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
NestedBreak
as discussed in #479. I’ve refined the implementation based on a clearer understanding of JavaScript’sLabelStatement
constraints 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
switchBreak
andloopBreak
are 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
xxxNestedBreak
operation 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
、loopNestedBreak
six JSOperations;LabelStack
to trace the nested code block of these six code blocks. The element inLabelStack
isLabelPin
, which has two fields:beginPos
andhasLabel
.beginPos
is the index of the starting point of the js code block, andhasLabel
indicates whetherbeginPos
has 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 whenbreakNested
orcontinueNested
appears. Therefore, the core operation ofLabelStack
isinsertLabel
, which has three operations: ①Insert label Identifier string into js code; ②mark that a label has been inserted here; ③Move thebeginPos
of all LabelPins forward by the given size offset.;ifNestedBreak
,blockNestedBreak
, andtryNestedBreak
when implementing them in jsoperation. Therefore, three new contexts have been added to the context.