@@ -1150,14 +1150,17 @@ public class JavaScriptLifter: Lifter {
1150
1150
1151
1151
case . beginWhileLoopBody:
1152
1152
let COND = handleEndSingleExpressionContext ( result: input ( 0 ) , with: & w)
1153
+ w. pushLabelStack ( LabelType . loopblock)
1153
1154
w. emitBlock ( " while ( \( COND) ) { " )
1154
1155
w. enterNewBlock ( )
1155
1156
1156
1157
case . endWhileLoop:
1157
1158
w. leaveCurrentBlock ( )
1158
1159
w. emit ( " } " )
1160
+ w. popLabelStack ( LabelType . loopblock)
1159
1161
1160
1162
case . beginDoWhileLoopBody:
1163
+ w. pushLabelStack ( LabelType . loopblock)
1161
1164
w. emit ( " do { " )
1162
1165
w. enterNewBlock ( )
1163
1166
@@ -1168,6 +1171,7 @@ public class JavaScriptLifter: Lifter {
1168
1171
case . endDoWhileLoop:
1169
1172
let COND = handleEndSingleExpressionContext ( result: input ( 0 ) , with: & w)
1170
1173
w. emitBlock ( " } while ( \( COND) ) " )
1174
+ w. popLabelStack ( LabelType . loopblock)
1171
1175
1172
1176
case . beginForLoopInitializer:
1173
1177
// While we could inline into the loop header, we probably don't want to do that as it will often lead
@@ -1243,6 +1247,7 @@ public class JavaScriptLifter: Lifter {
1243
1247
let INITIALIZER = header. initializer
1244
1248
var CONDITION = header. condition
1245
1249
var AFTERTHOUGHT = handleEndSingleExpressionContext ( with: & w)
1250
+ w. pushLabelStack ( LabelType . loopblock)
1246
1251
1247
1252
if !INITIALIZER. contains ( " \n " ) && !CONDITION. contains ( " \n " ) && !AFTERTHOUGHT. contains ( " \n " ) {
1248
1253
if !CONDITION. isEmpty { CONDITION = " " + CONDITION }
@@ -1262,22 +1267,26 @@ public class JavaScriptLifter: Lifter {
1262
1267
case . endForLoop:
1263
1268
w. leaveCurrentBlock ( )
1264
1269
w. emit ( " } " )
1270
+ w. popLabelStack ( LabelType . loopblock)
1265
1271
1266
1272
case . beginForInLoop:
1267
1273
let LET = w. declarationKeyword ( for: instr. innerOutput)
1268
1274
let V = w. declare ( instr. innerOutput)
1269
1275
let OBJ = input ( 0 )
1276
+ w. pushLabelStack ( LabelType . loopblock)
1270
1277
w. emit ( " for ( \( LET) \( V) in \( OBJ) ) { " )
1271
1278
w. enterNewBlock ( )
1272
1279
1273
1280
case . endForInLoop:
1274
1281
w. leaveCurrentBlock ( )
1275
1282
w. emit ( " } " )
1283
+ w. popLabelStack ( LabelType . loopblock)
1276
1284
1277
1285
case . beginForOfLoop:
1278
1286
let V = w. declare ( instr. innerOutput)
1279
1287
let LET = w. declarationKeyword ( for: instr. innerOutput)
1280
1288
let OBJ = input ( 0 )
1289
+ w. pushLabelStack ( LabelType . loopblock)
1281
1290
w. emit ( " for ( \( LET) \( V) of \( OBJ) ) { " )
1282
1291
w. enterNewBlock ( )
1283
1292
@@ -1286,12 +1295,14 @@ public class JavaScriptLifter: Lifter {
1286
1295
let PATTERN = liftArrayDestructPattern ( indices: op. indices, outputs: outputs, hasRestElement: op. hasRestElement)
1287
1296
let LET = w. varKeyword
1288
1297
let OBJ = input ( 0 )
1298
+ w. pushLabelStack ( LabelType . loopblock)
1289
1299
w. emit ( " for ( \( LET) [ \( PATTERN) ] of \( OBJ) ) { " )
1290
1300
w. enterNewBlock ( )
1291
1301
1292
1302
case . endForOfLoop:
1293
1303
w. leaveCurrentBlock ( )
1294
1304
w. emit ( " } " )
1305
+ w. popLabelStack ( LabelType . loopblock)
1295
1306
1296
1307
case . beginRepeatLoop( let op) :
1297
1308
let LET = w. varKeyword
@@ -1302,12 +1313,14 @@ public class JavaScriptLifter: Lifter {
1302
1313
I = " i "
1303
1314
}
1304
1315
let ITERATIONS = op. iterations
1316
+ w. pushLabelStack ( LabelType . loopblock)
1305
1317
w. emit ( " for ( \( LET) \( I) = 0; \( I) < \( ITERATIONS) ; \( I) ++) { " )
1306
1318
w. enterNewBlock ( )
1307
1319
1308
1320
case . endRepeatLoop:
1309
1321
w. leaveCurrentBlock ( )
1310
1322
w. emit ( " } " )
1323
+ w. popLabelStack ( LabelType . loopblock)
1311
1324
1312
1325
case . loopBreak( _) ,
1313
1326
. switchBreak:
@@ -1372,6 +1385,9 @@ public class JavaScriptLifter: Lifter {
1372
1385
let VALUE = input ( 0 )
1373
1386
w. emit ( " fuzzilli('FUZZILLI_PRINT', \( VALUE) ); " )
1374
1387
1388
+ case . loopNestedContinue( let op) :
1389
+ w. liftContinueLabel ( LabelType . loopblock, expDepth: op. depth)
1390
+
1375
1391
case . createWasmGlobal( let op) :
1376
1392
let V = w. declare ( instr. output)
1377
1393
let LET = w. varKeyword
@@ -1640,6 +1656,7 @@ public class JavaScriptLifter: Lifter {
1640
1656
w. emitComment ( footer)
1641
1657
}
1642
1658
1659
+ assert ( w. labelStackDepth ( LabelType . loopblock) == 0 )
1643
1660
return w. code
1644
1661
}
1645
1662
@@ -1846,6 +1863,11 @@ public class JavaScriptLifter: Lifter {
1846
1863
return writer. code
1847
1864
}
1848
1865
1866
+ // Used for nestBreak series operations to record location information during append code, where temporary data structures such as temporaryOutputBufferStack may not necessarily be empty
1867
+ var codeLength : Int {
1868
+ return writer. code. count
1869
+ }
1870
+
1849
1871
// Maps each FuzzIL variable to its JavaScript expression.
1850
1872
// The expression for a FuzzIL variable can generally either be
1851
1873
// * an identifier like "v42" if the FuzzIL variable is mapped to a JavaScript variable OR
@@ -1861,6 +1883,11 @@ public class JavaScriptLifter: Lifter {
1861
1883
// See `reassign()` for more details about reassignment inlining.
1862
1884
private var inlinedReassignments = VariableMap < Expression > ( )
1863
1885
1886
+ // Trace nested code block to break/continue a label
1887
+ private var labelStack : [ LabelType : [ LabelPin ] ] = [
1888
+ LabelType . loopblock: [ ]
1889
+ ]
1890
+
1864
1891
init ( analyzer: DefUseAnalyzer , version: ECMAScriptVersion , stripComments: Bool = false , includeLineNumbers: Bool = false , indent: Int = 4 ) {
1865
1892
self . writer = ScriptWriter ( stripComments: stripComments, includeLineNumbers: includeLineNumbers, indent: indent)
1866
1893
self . analyzer = analyzer
@@ -2236,6 +2263,66 @@ public class JavaScriptLifter: Lifter {
2236
2263
return analyzer. numUses ( of: v) <= 1
2237
2264
}
2238
2265
}
2266
+
2267
+ /// Records a new label pin at the current code position.
2268
+ mutating func pushLabelStack( _ labelStackType: LabelType ) {
2269
+ labelStack [ labelStackType, default: [ ] ] . append (
2270
+ LabelPin (
2271
+ beginPos: codeLength,
2272
+ hasLabel: false ,
2273
+ indention: writer. getCurrentIndention ( )
2274
+ )
2275
+ )
2276
+ }
2277
+
2278
+ /// Removes the most recently recorded label pin.
2279
+ mutating func popLabelStack( _ labelStackType: LabelType ) {
2280
+ _ = labelStack [ labelStackType, default: [ ] ] . popLast ( )
2281
+ }
2282
+
2283
+ /// Checks whether a label has already been inserted at the specified index.
2284
+ private mutating func labelExists( _ labelStack: inout [ LabelPin ] , at index: Int ) -> Bool {
2285
+ return labelStack [ index] . hasLabel
2286
+ }
2287
+
2288
+ /// Updates the label stack when a label is inserted into the code.
2289
+ ///
2290
+ /// This method:
2291
+ /// - Marks the label at the specified index as inserted.
2292
+ /// - Inserts the label content at the given code position.
2293
+ /// - Shifts the positions of subsequent labels accordingly.
2294
+ private mutating func insertLabel( _ type: LabelType , _ index: Int , _ labelContent: String ) {
2295
+ var stack = labelStack [ type] !
2296
+ let insertPos = stack [ index] . beginPos
2297
+ let indention = stack [ index] . indention
2298
+
2299
+ writer. insert ( insertPos, labelContent, indention)
2300
+
2301
+ stack [ index] . hasLabel = true
2302
+ let delta = labelContent. count
2303
+
2304
+ for i in index+ 1 ..< stack. count {
2305
+ stack [ i] . beginPos += delta
2306
+ }
2307
+
2308
+ labelStack [ type] = stack
2309
+ }
2310
+
2311
+ mutating func liftContinueLabel( _ type: LabelType , expDepth: Int ) {
2312
+ let stack = labelStack [ type] !
2313
+ let d = expDepth % stack. count
2314
+ let labelName = " label \( d) : "
2315
+
2316
+ if !stack[ d] . hasLabel {
2317
+ insertLabel ( type, d, labelName)
2318
+ }
2319
+
2320
+ emit ( " continue label \( d) ; " )
2321
+ }
2322
+
2323
+ mutating func labelStackDepth( _ type: LabelType ) -> Int {
2324
+ return labelStack [ type] !. count
2325
+ }
2239
2326
}
2240
2327
2241
2328
// Helper class for formatting object literals.
@@ -2268,4 +2355,15 @@ public class JavaScriptLifter: Lifter {
2268
2355
fields [ fields. count - 1 ] += body + " } "
2269
2356
}
2270
2357
}
2358
+
2359
+ // Every possible position of label
2360
+ struct LabelPin {
2361
+ var beginPos : Int
2362
+ var hasLabel : Bool
2363
+ var indention : String
2364
+ }
2365
+
2366
+ enum LabelType {
2367
+ case loopblock
2368
+ }
2271
2369
}
0 commit comments