Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hi Saelo,
This PR implements
NestedBreakas discussed in #479. I’ve refined the implementation based on a clearer understanding of JavaScript’sLabelStatementconstraints and Fuzzilli’s context architecture.Below is the definition of LabelStatement in ECMA:
And here is the full list of Statement types:
In fact, not all of these statements can be used in combination with a labelStatement. Below is a summary of those that cannot be used:
1. DeclarationStatement
Therefore, all declaration statements can be ignored. This is merely a historical quirk and has no practical significance.
2. DebuggerStatement
Only one scenario exists:
label: debugger, which is also not worth supporting.3. ExpressionStatement
ExpressionStatement :
[lookahead ≠ { '{' , 'function' , 'class' , 'let' , 'async function' }] Expression ;
A LabelStatement must be followed by exactly one Statement, so in practice the only valid form here is something like
label: break label;, which we can also ignore.4. ReturnStatement
Because return can only appear within function bodies, it cannot be used with a label.
After filtering out the above cases, here are the valid statements that can be used with a label, which roughly match your earlier examples:
It’s clear that all valid statement types are recursive structures, which means our previously designed loopLabelStack can be reused.
Here are some discussions on implementation details:
Fuzzilli does not abstract base grammar categories like Statement or Expression, so there’s no way to manipulate all statements in a uniform way.
Given the list of valid Statements above, the break operation cannot be implemented in the way you advised (i.e., support the nested break in every JS context). A label must anchor the entry point of a code block; otherwise, a break cannot determine its target.
Fuzzilli’s context system is designed in a top-down manner, which means there is no unified solution for handling the same operation appearing in different contexts. For example, the already implemented
switchBreakandloopBreakare both justbreak;in JavaScript, but due to the underlying architecture based onisSubSet(of: originContext)in ProgramBuilder.swift, they must be implemented separately.Therefore, I’ve chosen to follow the existing design approach and implement a dedicated
xxxNestedBreakoperation for each context, rather than introducing a genericnestedBreak.I also reorganized the supporting label stack to enable reuse across different Statements and contexts. The main implementation process is as follows:
switchNestedBreak、blockNestedBreak、ifNestedBreak、withNestedBreak、tryNestedBreak、loopNestedBreaksix JSOperations;LabelStackto trace the nested code block of these six code blocks. The element inLabelStackisLabelPin, which has two fields:beginPosandhasLabel.beginPosis the index of the starting point of the js code block, andhasLabelindicates whetherbeginPoshas generated a label (with a small probability of generating N lines of break or continue in the same block). Because there is no need to mark every code entry with a label Identifier, which will expand the code size, it is only inserted whenbreakNestedorcontinueNestedappears. Therefore, the core operation ofLabelStackisinsertLabel, which has three operations: ①Insert label Identifier string into js code; ②mark that a label has been inserted here; ③Move thebeginPosof all LabelPins forward by the given size offset.;ifNestedBreak,blockNestedBreak, andtryNestedBreakwhen implementing them in jsoperation. Therefore, three new contexts have been added to the context.