Skip to content

Commit 434d594

Browse files
committed
Refactor of for-in and for-of loops. Makes each type of loop a seperate instruction in FuzzIL
1 parent 5545802 commit 434d594

21 files changed

+465
-300
lines changed

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,19 +2488,31 @@ public class ProgramBuilder {
24882488
emit(EndForLoop())
24892489
}
24902490

2491-
public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> ()) {
2492-
let i = emit(BeginForInLoop(), withInputs: [obj]).innerOutput
2491+
public func buildPlainForInLoop(_ obj: Variable, _ body: (Variable) -> ()) {
2492+
let i = emit(BeginPlainForInLoop(), withInputs: [obj]).innerOutput
24932493
body(i)
24942494
emit(EndForInLoop())
24952495
}
24962496

2497-
public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> ()) {
2498-
let i = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput
2497+
public func buildForInLoopWithReassignment(_ obj: Variable, _ existingVar: Variable, _ body: () -> ()) {
2498+
emit(BeginForInLoopWithReassignment(), withInputs: [obj, existingVar])
2499+
body()
2500+
emit(EndForInLoop())
2501+
}
2502+
2503+
public func buildPlainForOfLoop(_ obj: Variable, _ body: (Variable) -> ()) {
2504+
let i = emit(BeginPlainForOfLoop(), withInputs: [obj]).innerOutput
24992505
body(i)
25002506
emit(EndForOfLoop())
25012507
}
25022508

2503-
public func buildForOfLoop(_ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, _ body: ([Variable]) -> ()) {
2509+
public func buildForOfLoopWithReassignment(_ obj: Variable, _ existingVar: Variable, _ body: () -> ()) {
2510+
emit(BeginForOfLoopWithReassignment(), withInputs: [obj, existingVar])
2511+
body()
2512+
emit(EndForOfLoop())
2513+
}
2514+
2515+
public func buildForOfLoopWithDestruct(_ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, _ body: ([Variable]) -> ()) {
25042516
let instr = emit(BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), withInputs: [obj])
25052517
body(Array(instr.innerOutputs))
25062518
emit(EndForOfLoop())

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,10 @@ public let codeGeneratorWeights = [
158158
"DoWhileLoopGenerator": 15,
159159
"SimpleForLoopGenerator": 10,
160160
"ComplexForLoopGenerator": 10,
161-
"ForInLoopGenerator": 10,
162-
"ForOfLoopGenerator": 10,
161+
"PlainForInLoopGenerator": 8,
162+
"ForInLoopWithReassignmentGenerator": 2,
163+
"PlainForOfLoopGenerator": 8,
164+
"ForOfLoopWithReassignmentGenerator": 2,
163165
"ForOfWithDestructLoopGenerator": 3,
164166
"RepeatLoopGenerator": 10,
165167
"SwitchCaseBreakGenerator": 5,

Sources/Fuzzilli/CodeGen/CodeGenerators.swift

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,14 +1366,29 @@ public let CodeGenerators: [CodeGenerator] = [
13661366
}
13671367
},
13681368

1369-
RecursiveCodeGenerator("ForInLoopGenerator", inputs: .preferred(.object())) { b, obj in
1370-
b.buildForInLoop(obj) { _ in
1369+
RecursiveCodeGenerator("PlainForInLoopGenerator", inputs: .preferred(.object())) { b, obj in
1370+
b.buildPlainForInLoop(obj) { _ in
13711371
b.buildRecursive()
13721372
}
13731373
},
13741374

1375-
RecursiveCodeGenerator("ForOfLoopGenerator", inputs: .preferred(.iterable)) { b, obj in
1376-
b.buildForOfLoop(obj) { _ in
1375+
RecursiveCodeGenerator("ForInLoopWithReassignmentGenerator", inputs: .preferred(.object())) { b, obj in
1376+
// use a pre-declared variable as the iterator variable (i.e., reassign it)
1377+
let existing = b.randomVariable()
1378+
b.buildForInLoopWithReassignment(obj, existing) {
1379+
b.buildRecursive()
1380+
}
1381+
},
1382+
1383+
RecursiveCodeGenerator("PlainForOfLoopGenerator", inputs: .preferred(.iterable)) { b, obj in
1384+
b.buildPlainForOfLoop(obj) { _ in
1385+
b.buildRecursive()
1386+
}
1387+
},
1388+
1389+
RecursiveCodeGenerator("ForOfLoopWithReassignmentGenerator", inputs: .preferred(.iterable)) { b, obj in
1390+
let existing = b.randomVariable()
1391+
b.buildForOfLoopWithReassignment(obj, existing) {
13771392
b.buildRecursive()
13781393
}
13791394
},
@@ -1390,7 +1405,7 @@ public let CodeGenerators: [CodeGenerator] = [
13901405
indices = [0]
13911406
}
13921407

1393-
b.buildForOfLoop(obj, selecting: indices, hasRestElement: probability(0.2)) { _ in
1408+
b.buildForOfLoopWithDestruct(obj, selecting: indices, hasRestElement: probability(0.2)) { _ in
13941409
b.buildRecursive()
13951410
}
13961411
},

Sources/Fuzzilli/Compiler/Compiler.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ public class JavaScriptCompiler {
423423
guard !variableDeclarator.hasValue else {
424424
throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop")
425425
}
426-
let loopVar = emit(BeginForInLoop(), withInputs: [obj]).innerOutput
426+
let loopVar = emit(BeginPlainForInLoop(), withInputs: [obj]).innerOutput
427427
try enterNewScope {
428428
map(variableDeclarator.name, to: loopVar)
429429
try compileBody(forInLoop.body)
@@ -435,7 +435,7 @@ public class JavaScriptCompiler {
435435
// TODO instead of throwing an error, we should create a global property with the identifier name
436436
throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-in loop.")
437437
}
438-
emit(BeginForInLoop(usesPredeclaredIterator: true), withInputs: [obj, loopVar])
438+
emit(BeginForInLoopWithReassignment(), withInputs: [obj, loopVar])
439439
try enterNewScope {
440440
try compileBody(forInLoop.body)
441441
}
@@ -451,7 +451,7 @@ public class JavaScriptCompiler {
451451
guard !variableDeclarator.hasValue else {
452452
throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop")
453453
}
454-
let loopVar = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput
454+
let loopVar = emit(BeginPlainForOfLoop(), withInputs: [obj]).innerOutput
455455
try enterNewScope {
456456
map(variableDeclarator.name, to: loopVar)
457457
try compileBody(forOfLoop.body)
@@ -463,7 +463,7 @@ public class JavaScriptCompiler {
463463
// TODO instead of throwing an error, we should create a global property with the identifier name
464464
throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-of loop.")
465465
}
466-
emit(BeginForOfLoop(usesPredeclaredIterator: true), withInputs: [obj, loopVar])
466+
emit(BeginForOfLoopWithReassignment(), withInputs: [obj, loopVar])
467467
try enterNewScope {
468468
try compileBody(forOfLoop.body)
469469
}

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -790,16 +790,16 @@ extension Instruction: ProtobufConvertible {
790790
$0.beginForLoopBody = Fuzzilli_Protobuf_BeginForLoopBody()
791791
case .endForLoop:
792792
$0.endForLoop = Fuzzilli_Protobuf_EndForLoop()
793-
case .beginForInLoop(let op):
794-
$0.beginForInLoop = Fuzzilli_Protobuf_BeginForInLoop.with { protobufOp in
795-
protobufOp.usesPredeclaredIterator = op.usesPredeclaredIterator
796-
}
793+
case .beginPlainForInLoop:
794+
$0.beginPlainForInLoop = Fuzzilli_Protobuf_BeginPlainForInLoop()
795+
case .beginForInLoopWithReassignment:
796+
$0.beginForInLoopWithReassignment = Fuzzilli_Protobuf_BeginForInLoopWithReassignment()
797797
case .endForInLoop:
798798
$0.endForInLoop = Fuzzilli_Protobuf_EndForInLoop()
799-
case .beginForOfLoop(let op):
800-
$0.beginForOfLoop = Fuzzilli_Protobuf_BeginForOfLoop.with { protobufOp in
801-
protobufOp.usesPredeclaredIterator = op.usesPredeclaredIterator
802-
}
799+
case .beginPlainForOfLoop:
800+
$0.beginPlainForOfLoop = Fuzzilli_Protobuf_BeginPlainForOfLoop()
801+
case .beginForOfLoopWithReassignment:
802+
$0.beginForOfLoopWithReassignment = Fuzzilli_Protobuf_BeginForOfLoopWithReassignment()
803803
case .beginForOfLoopWithDestruct(let op):
804804
$0.beginForOfLoopWithDestruct = Fuzzilli_Protobuf_BeginForOfLoopWithDestruct.with {
805805
$0.indices = op.indices.map({ Int32($0) })
@@ -1216,14 +1216,21 @@ extension Instruction: ProtobufConvertible {
12161216
op = BeginForLoopBody(numLoopVariables: inouts.count)
12171217
case .endForLoop:
12181218
op = EndForLoop()
1219-
case .beginForInLoop(let p):
1220-
op = BeginForInLoop(usesPredeclaredIterator: p.usesPredeclaredIterator)
1219+
case .beginPlainForInLoop:
1220+
op = BeginPlainForInLoop()
1221+
case .beginForInLoopWithReassignment:
1222+
op = BeginForInLoopWithReassignment()
12211223
case .endForInLoop:
12221224
op = EndForInLoop()
1223-
case .beginForOfLoop(let p):
1224-
op = BeginForOfLoop(usesPredeclaredIterator: p.usesPredeclaredIterator)
1225+
case .beginPlainForOfLoop:
1226+
op = BeginPlainForOfLoop()
1227+
case .beginForOfLoopWithReassignment:
1228+
op = BeginForOfLoopWithReassignment()
12251229
case .beginForOfLoopWithDestruct(let p):
1226-
op = BeginForOfLoopWithDestruct(indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p)
1230+
op = BeginForOfLoopWithDestruct(
1231+
indices: p.indices.map({ Int64($0) }),
1232+
hasRestElement: p.hasRestElement_p
1233+
)
12271234
case .endForOfLoop:
12281235
op = EndForOfLoop()
12291236
case .beginRepeatLoop(let p):

Sources/Fuzzilli/FuzzIL/JSTyper.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,10 @@ public struct JSTyper: Analyzer {
283283
case .endForLoop:
284284
state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges)
285285
case .beginWhileLoopBody,
286-
.beginForInLoop,
287-
.beginForOfLoop,
286+
.beginPlainForInLoop,
287+
.beginForInLoopWithReassignment,
288+
.beginPlainForOfLoop,
289+
.beginForOfLoopWithReassignment,
288290
.beginForOfLoopWithDestruct,
289291
.beginRepeatLoop,
290292
.beginCodeString:
@@ -793,19 +795,17 @@ public struct JSTyper: Analyzer {
793795
assert(inputTypes.count == instr.numInnerOutputs)
794796
zip(instr.innerOutputs, inputTypes).forEach({ set($0, $1) })
795797

796-
case .beginForInLoop:
797-
if instr.numInputs == 2 {
798-
set(instr.input(1), .string) // Iterator is declared beforehand
799-
} else {
800-
set(instr.innerOutput, .string) // Iterator is declared in the function header
801-
}
798+
case .beginPlainForInLoop:
799+
set(instr.innerOutput, .string)
802800

803-
case .beginForOfLoop:
804-
if instr.numInputs == 2 {
805-
set(instr.input(1), .anything)
806-
} else {
807-
set(instr.innerOutput, .anything)
808-
}
801+
case .beginForInLoopWithReassignment:
802+
set(instr.input(1), .string)
803+
804+
case .beginPlainForOfLoop:
805+
set(instr.innerOutput, .anything)
806+
807+
case .beginForOfLoopWithReassignment:
808+
set(instr.input(1), .anything)
809809

810810
case .beginForOfLoopWithDestruct:
811811
for v in instr.innerOutputs {

Sources/Fuzzilli/FuzzIL/JsOperations.swift

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,19 +1964,17 @@ final class EndForLoop: JsOperation {
19641964
}
19651965
}
19661966

1967-
final class BeginForInLoop: JsOperation {
1968-
override var opcode: Opcode { .beginForInLoop(self) }
1969-
1970-
let usesPredeclaredIterator: Bool
1967+
final class BeginPlainForInLoop: JsOperation {
1968+
override var opcode: Opcode { .beginPlainForInLoop(self) }
1969+
init() {
1970+
super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop])
1971+
}
1972+
}
19711973

1972-
init(usesPredeclaredIterator: Bool = false) {
1973-
self.usesPredeclaredIterator = usesPredeclaredIterator
1974-
super.init(
1975-
numInputs: usesPredeclaredIterator ? 2 : 1,
1976-
numInnerOutputs: usesPredeclaredIterator ? 0 : 1,
1977-
attributes: [.isBlockStart, .propagatesSurroundingContext],
1978-
contextOpened: [.javascript, .loop]
1979-
)
1974+
final class BeginForInLoopWithReassignment: JsOperation {
1975+
override var opcode: Opcode { .beginForInLoopWithReassignment(self) }
1976+
init() {
1977+
super.init(numInputs: 2, numInnerOutputs: 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop])
19801978
}
19811979
}
19821980

@@ -1988,20 +1986,17 @@ final class EndForInLoop: JsOperation {
19881986
}
19891987
}
19901988

1991-
final class BeginForOfLoop: JsOperation {
1992-
override var opcode: Opcode { .beginForOfLoop(self) }
1993-
1994-
1995-
let usesPredeclaredIterator: Bool
1989+
final class BeginPlainForOfLoop: JsOperation {
1990+
override var opcode: Opcode { .beginPlainForOfLoop(self) }
1991+
init() {
1992+
super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop])
1993+
}
1994+
}
19961995

1997-
init(usesPredeclaredIterator: Bool = false) {
1998-
self.usesPredeclaredIterator = usesPredeclaredIterator
1999-
super.init(
2000-
numInputs: usesPredeclaredIterator ? 2 : 1,
2001-
numInnerOutputs: usesPredeclaredIterator ? 0 : 1,
2002-
attributes: [.isBlockStart, .propagatesSurroundingContext],
2003-
contextOpened: [.javascript, .loop]
2004-
)
1996+
final class BeginForOfLoopWithReassignment: JsOperation {
1997+
override var opcode: Opcode { .beginForOfLoopWithReassignment(self) }
1998+
init() {
1999+
super.init(numInputs: 2, numInnerOutputs: 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop])
20052000
}
20062001
}
20072002

Sources/Fuzzilli/FuzzIL/Opcodes.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,11 @@ enum Opcode {
176176
case beginForLoopAfterthought(BeginForLoopAfterthought)
177177
case beginForLoopBody(BeginForLoopBody)
178178
case endForLoop(EndForLoop)
179-
case beginForInLoop(BeginForInLoop)
179+
case beginPlainForInLoop(BeginPlainForInLoop)
180+
case beginForInLoopWithReassignment(BeginForInLoopWithReassignment)
180181
case endForInLoop(EndForInLoop)
181-
case beginForOfLoop(BeginForOfLoop)
182+
case beginPlainForOfLoop(BeginPlainForOfLoop)
183+
case beginForOfLoopWithReassignment(BeginForOfLoopWithReassignment)
182184
case beginForOfLoopWithDestruct(BeginForOfLoopWithDestruct)
183185
case endForOfLoop(EndForOfLoop)
184186
case beginRepeatLoop(BeginRepeatLoop)

Sources/Fuzzilli/FuzzIL/Semantics.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ extension Operation {
5454
case .destructArrayAndReassign,
5555
.destructObjectAndReassign:
5656
return inputIdx != 0
57-
case .beginForInLoop(let op):
58-
return op.usesPredeclaredIterator && inputIdx == 1
59-
case .beginForOfLoop(let op):
60-
return op.usesPredeclaredIterator && inputIdx == 1
57+
case .beginForInLoopWithReassignment:
58+
return inputIdx == 1
59+
case .beginForOfLoopWithReassignment:
60+
return inputIdx == 1
6161
default:
6262
return false
6363
}
@@ -210,9 +210,11 @@ extension Operation {
210210
return endOp is BeginForLoopBody
211211
case .beginForLoopBody:
212212
return endOp is EndForLoop
213-
case .beginForInLoop:
213+
case .beginPlainForInLoop,
214+
.beginForInLoopWithReassignment:
214215
return endOp is EndForInLoop
215-
case .beginForOfLoop,
216+
case .beginPlainForOfLoop,
217+
.beginForOfLoopWithReassignment,
216218
.beginForOfLoopWithDestruct:
217219
return endOp is EndForOfLoop
218220
case .beginRepeatLoop:

Sources/Fuzzilli/Lifting/FuzzILLifter.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -666,24 +666,24 @@ public class FuzzILLifter: Lifter {
666666
w.decreaseIndentionLevel()
667667
w.emit("EndForLoop")
668668

669-
case .beginForInLoop:
670-
if instr.numInputs == 2 {
671-
w.emit("BeginForInLoop \(input(0)) -> \(input(1))") // Iterator is declared beforehand
672-
} else {
673-
w.emit("BeginForInLoop \(input(0)) -> \(innerOutput())") // Iterator is declared in the function header
674-
}
669+
case .beginPlainForInLoop:
670+
w.emit("BeginPlainForInLoop \(input(0)) -> \(innerOutput())")
671+
w.increaseIndentionLevel()
672+
673+
case .beginForInLoopWithReassignment:
674+
w.emit("BeginForInLoopWithReassignment \(input(0)) -> \(input(1))")
675675
w.increaseIndentionLevel()
676676

677677
case .endForInLoop:
678678
w.decreaseIndentionLevel()
679679
w.emit("EndForInLoop")
680680

681-
case .beginForOfLoop:
682-
if instr.numInputs == 2 {
683-
w.emit("BeginForOfLoop \(input(0)) -> \(input(1))")
684-
} else {
685-
w.emit("BeginForOfLoop \(input(0)) -> \(innerOutput())")
686-
}
681+
case .beginPlainForOfLoop:
682+
w.emit("BeginPlainForOfLoop \(input(0)) -> \(innerOutput())")
683+
w.increaseIndentionLevel()
684+
685+
case .beginForOfLoopWithReassignment:
686+
w.emit("BeginForOfLoopWithReassignment \(input(0)) -> \(input(1))")
687687
w.increaseIndentionLevel()
688688

689689
case .beginForOfLoopWithDestruct(let op):

0 commit comments

Comments
 (0)