Changeset 198927 in webkit


Ignore:
Timestamp:
Mar 31, 2016 4:01:29 PM (8 years ago)
Author:
sbarati@apple.com
Message:

parsing arrow function expressions slows down the parser by 8% lets recoup some loss
https://bugs.webkit.org/show_bug.cgi?id=155988

Reviewed by Benjamin Poulain.

Source/JavaScriptCore:

We used to eagerly check if we're parsing an arrow function.
We did this inside parseAssignmentExpression(), and it was
very costly. The reason it was costly is that arrow functions
might start with an identifier. This means anytime we saw an
identifier we would have to do a lookahead, and then most likely
backtrack because more often than not, we wouldn't see "=>"
as the next token.

In this patch I implement a new approach. We just parse
the lhs of an assignment expression eagerly without doing any
lookahead. Retroactively, if we see that we might have started
with an arrow function, and we don't have a valid lhs or the
next token is a "=>", we try to parse as an arrow function.

Here are a few examples motivating why this is valid:

x => x
In this example:

  • "x" is a valid arrow function starting point.
  • "x" also happens to be a valid lhs
  • because we see "=>" as the next token, we parse as an arrow function and succeed.

(x) => x
In this example:

  • "(" is a valid arrow function starting point.
  • "(x)" also happens to be a valid lhs
  • because we see "=>" as the next token, we parse as an arrow function and succeed.

({x = 30}) => x;
In this example:

  • "(" is a valid arrow function starting point.
  • "({x = 30})" is NOT a valid lhs. Because of this, we try to parse it as an arrow function and succeed.

There is one interesting implementation detail where we might
parse something that is both a valid LHS but happens
to actually be the arrow function parameters. The valid LHS
parsing might declare such variables as "uses" which would cause
weird capture analysis. This patch also introduces a mechanism
to backtrack on used variable analysis.

This is a 3.5%-4.5% octane code load speedup.

  • parser/Lexer.h:

(JSC::Lexer::sawError):
(JSC::Lexer::setSawError):
(JSC::Lexer::getErrorMessage):
(JSC::Lexer::setErrorMessage):
(JSC::Lexer::sourceURL):
(JSC::Lexer::sourceMappingURL):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::isArrowFunctionParameters):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parsePrimaryExpression):

  • parser/Parser.h:

(JSC::Scope::Scope):
(JSC::Scope::startSwitch):
(JSC::Scope::declareParameter):
(JSC::Scope::usedVariablesContains):
(JSC::Scope::useVariable):
(JSC::Scope::pushUsedVariableSet):
(JSC::Scope::currentUsedVariablesSize):
(JSC::Scope::revertToPreviousUsedVariables):
(JSC::Scope::setNeedsFullActivation):
(JSC::Scope::needsFullActivation):
(JSC::Scope::isArrowFunctionBoundary):
(JSC::Scope::setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded):
(JSC::Scope::collectFreeVariables):
(JSC::Scope::fillParametersForSourceProviderCache):
(JSC::Scope::restoreFromSourceProviderCache):
(JSC::Scope::setIsModule):

LayoutTests:

  • js/parser-syntax-check-expected.txt:
  • js/script-tests/parser-syntax-check.js:

(catch):

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r198926 r198927  
     12016-03-31  Saam barati  <sbarati@apple.com>
     2
     3        parsing arrow function expressions slows down the parser by 8% lets recoup some loss
     4        https://bugs.webkit.org/show_bug.cgi?id=155988
     5
     6        Reviewed by Benjamin Poulain.
     7
     8        * js/parser-syntax-check-expected.txt:
     9        * js/script-tests/parser-syntax-check.js:
     10        (catch):
     11
    1122016-03-31  Per Arne Vollan  <peavo@outlook.com>
    213
  • trunk/LayoutTests/js/parser-syntax-check-expected.txt

    r198233 r198927  
    10411041PASS Invalid: "function foo(...if) { }"
    10421042PASS Invalid: "function f() { function foo(...if) { } }"
     1043Arrow function
     1044PASS Valid:   "var x = (x) => x;"
     1045PASS Valid:   "function f() { var x = (x) => x; }"
     1046PASS Valid:   "var x = (x, y, z) => x;"
     1047PASS Valid:   "function f() { var x = (x, y, z) => x; }"
     1048PASS Valid:   "var x = ({x}, [y], z) => x;"
     1049PASS Valid:   "function f() { var x = ({x}, [y], z) => x; }"
     1050PASS Valid:   "var x = ({x = 30}, [y], z) => x;"
     1051PASS Valid:   "function f() { var x = ({x = 30}, [y], z) => x; }"
     1052PASS Valid:   "var x = (x = 20) => x;"
     1053PASS Valid:   "function f() { var x = (x = 20) => x; }"
     1054PASS Valid:   "var x = ([x] = 20, y) => x;"
     1055PASS Valid:   "function f() { var x = ([x] = 20, y) => x; }"
     1056PASS Valid:   "var x = ([x = 20] = 20) => x;"
     1057PASS Valid:   "function f() { var x = ([x = 20] = 20) => x; }"
     1058PASS Valid:   "var x = foo => x;"
     1059PASS Valid:   "function f() { var x = foo => x; }"
     1060PASS Valid:   "var x = foo => x => x => x => x;"
     1061PASS Valid:   "function f() { var x = foo => x => x => x => x; }"
     1062PASS Valid:   "var x = foo => x => (x = 20) => (x = 20) => x;"
     1063PASS Valid:   "function f() { var x = foo => x => (x = 20) => (x = 20) => x; }"
     1064PASS Valid:   "var x = foo => x => x => x => {x};"
     1065PASS Valid:   "function f() { var x = foo => x => x => x => {x}; }"
     1066PASS Valid:   "var x = ([x = 25]) => x => x => ({x} = {});"
     1067PASS Valid:   "function f() { var x = ([x = 25]) => x => x => ({x} = {}); }"
     1068PASS Invalid: "var x = foo => x => x => {x} => x;"
     1069PASS Invalid: "function f() { var x = foo => x => x => {x} => x; }"
     1070PASS Invalid: "var x = {x} = 20 => x;"
     1071PASS Invalid: "function f() { var x = {x} = 20 => x; }"
     1072PASS Invalid: "var x = [x] = 20 => x;"
     1073PASS Invalid: "function f() { var x = [x] = 20 => x; }"
     1074PASS Invalid: "var x = [x = 25] = 20 => x;"
     1075PASS Invalid: "function f() { var x = [x = 25] = 20 => x; }"
     1076PASS Invalid: "var x = ([x = 25]) =>;"
     1077PASS Invalid: "function f() { var x = ([x = 25]) =>; }"
     1078PASS Invalid: "var x = ([x = 25]) => x =>;"
     1079PASS Invalid: "function f() { var x = ([x = 25]) => x =>; }"
     1080PASS Invalid: "var x = ([x = 25]) => x => x =>;"
     1081PASS Invalid: "function f() { var x = ([x = 25]) => x => x =>; }"
     1082PASS Invalid: "var x = ([x = 25]) => x => x => {;"
     1083PASS Invalid: "function f() { var x = ([x = 25]) => x => x => {; }"
     1084PASS Invalid: "var x ==> x;"
     1085PASS Invalid: "function f() { var x ==> x; }"
     1086PASS Invalid: "var x = x ==> x;"
     1087PASS Invalid: "function f() { var x = x ==> x; }"
     1088PASS Valid:   "foo((x) => x)" with ReferenceError
     1089PASS Valid:   "function f() { foo((x) => x) }"
     1090PASS Valid:   "foo((x, y, z) => x)" with ReferenceError
     1091PASS Valid:   "function f() { foo((x, y, z) => x) }"
     1092PASS Valid:   "foo(({x}, [y], z) => x)" with ReferenceError
     1093PASS Valid:   "function f() { foo(({x}, [y], z) => x) }"
     1094PASS Valid:   "foo(({x = 30}, [y], z) => x)" with ReferenceError
     1095PASS Valid:   "function f() { foo(({x = 30}, [y], z) => x) }"
     1096PASS Valid:   "foo((x = 20) => x)" with ReferenceError
     1097PASS Valid:   "function f() { foo((x = 20) => x) }"
     1098PASS Valid:   "foo(([x] = 20, y) => x)" with ReferenceError
     1099PASS Valid:   "function f() { foo(([x] = 20, y) => x) }"
     1100PASS Valid:   "foo(([x = 20] = 20) => x)" with ReferenceError
     1101PASS Valid:   "function f() { foo(([x = 20] = 20) => x) }"
     1102PASS Valid:   "foo(foo => x)" with ReferenceError
     1103PASS Valid:   "function f() { foo(foo => x) }"
     1104PASS Valid:   "foo(foo => x => x => x => x)" with ReferenceError
     1105PASS Valid:   "function f() { foo(foo => x => x => x => x) }"
     1106PASS Valid:   "foo(foo => x => (x = 20) => (x = 20) => x)" with ReferenceError
     1107PASS Valid:   "function f() { foo(foo => x => (x = 20) => (x = 20) => x) }"
     1108PASS Valid:   "foo(foo => x => x => x => {x})" with ReferenceError
     1109PASS Valid:   "function f() { foo(foo => x => x => x => {x}) }"
     1110PASS Valid:   "foo(([x = 25]) => x => x => ({x} = {}))" with ReferenceError
     1111PASS Valid:   "function f() { foo(([x = 25]) => x => x => ({x} = {})) }"
     1112PASS Invalid: "foo(foo => x => x => {x} => x)"
     1113PASS Invalid: "function f() { foo(foo => x => x => {x} => x) }"
     1114PASS Invalid: "foo({x} = 20 => x)"
     1115PASS Invalid: "function f() { foo({x} = 20 => x) }"
     1116PASS Invalid: "foo([x] = 20 => x)"
     1117PASS Invalid: "function f() { foo([x] = 20 => x) }"
     1118PASS Invalid: "foo([x = 25] = 20 => x)"
     1119PASS Invalid: "function f() { foo([x = 25] = 20 => x) }"
     1120PASS Invalid: "foo(([x = 25]) =>)"
     1121PASS Invalid: "function f() { foo(([x = 25]) =>) }"
     1122PASS Invalid: "foo(([x = 25]) => x =>)"
     1123PASS Invalid: "function f() { foo(([x = 25]) => x =>) }"
     1124PASS Invalid: "foo(([x = 25]) => x => x =>)"
     1125PASS Invalid: "function f() { foo(([x = 25]) => x => x =>) }"
     1126PASS Invalid: "foo(([x = 25]) => x => x => {)"
     1127PASS Invalid: "function f() { foo(([x = 25]) => x => x => {) }"
     1128PASS Invalid: "foo(x ==> x)"
     1129PASS Invalid: "function f() { foo(x ==> x) }"
     1130PASS Invalid: "foo(x = x ==> x)"
     1131PASS Invalid: "function f() { foo(x = x ==> x) }"
    10431132PASS e.line is 1
    10441133PASS foo is 'PASS'
  • trunk/LayoutTests/js/script-tests/parser-syntax-check.js

    r198233 r198927  
    619619invalid("function foo(...if) { }");
    620620
     621debug("Arrow function");
     622valid("var x = (x) => x;");
     623valid("var x = (x, y, z) => x;");
     624valid("var x = ({x}, [y], z) => x;");
     625valid("var x = ({x = 30}, [y], z) => x;");
     626valid("var x = (x = 20) => x;");
     627valid("var x = ([x] = 20, y) => x;");
     628valid("var x = ([x = 20] = 20) => x;");
     629valid("var x = foo => x;");
     630valid("var x = foo => x => x => x => x;");
     631valid("var x = foo => x => (x = 20) => (x = 20) => x;");
     632valid("var x = foo => x => x => x => {x};");
     633valid("var x = ([x = 25]) => x => x => ({x} = {});");
     634invalid("var x = foo => x => x => {x} => x;");
     635invalid("var x = {x} = 20 => x;");
     636invalid("var x = [x] = 20 => x;");
     637invalid("var x = [x = 25] = 20 => x;");
     638invalid("var x = ([x = 25]) =>;");
     639invalid("var x = ([x = 25]) => x =>;");
     640invalid("var x = ([x = 25]) => x => x =>;");
     641invalid("var x = ([x = 25]) => x => x => {;");
     642invalid("var x ==> x;");
     643invalid("var x = x ==> x;");
     644valid("foo((x) => x)");
     645valid("foo((x, y, z) => x)");
     646valid("foo(({x}, [y], z) => x)");
     647valid("foo(({x = 30}, [y], z) => x)");
     648valid("foo((x = 20) => x)");
     649valid("foo(([x] = 20, y) => x)");
     650valid("foo(([x = 20] = 20) => x)");
     651valid("foo(foo => x)");
     652valid("foo(foo => x => x => x => x)");
     653valid("foo(foo => x => (x = 20) => (x = 20) => x)");
     654valid("foo(foo => x => x => x => {x})");
     655valid("foo(([x = 25]) => x => x => ({x} = {}))");
     656invalid("foo(foo => x => x => {x} => x)");
     657invalid("foo({x} = 20 => x)");
     658invalid("foo([x] = 20 => x)");
     659invalid("foo([x = 25] = 20 => x)");
     660invalid("foo(([x = 25]) =>)");
     661invalid("foo(([x = 25]) => x =>)");
     662invalid("foo(([x = 25]) => x => x =>)");
     663invalid("foo(([x = 25]) => x => x => {)");
     664invalid("foo(x ==> x)");
     665invalid("foo(x = x ==> x)");
    621666
    622667
  • trunk/Source/JavaScriptCore/ChangeLog

    r198919 r198927  
     12016-03-31  Saam barati  <sbarati@apple.com>
     2
     3        parsing arrow function expressions slows down the parser by 8% lets recoup some loss
     4        https://bugs.webkit.org/show_bug.cgi?id=155988
     5
     6        Reviewed by Benjamin Poulain.
     7
     8        We used to eagerly check if we're parsing an arrow function.
     9        We did this inside parseAssignmentExpression(), and it was
     10        very costly. The reason it was costly is that arrow functions
     11        might start with an identifier. This means anytime we saw an
     12        identifier we would have to do a lookahead, and then most likely
     13        backtrack because more often than not, we wouldn't see "=>"
     14        as the next token.
     15
     16        In this patch I implement a new approach. We just parse
     17        the lhs of an assignment expression eagerly without doing any
     18        lookahead. Retroactively, if we see that we might have started
     19        with an arrow function, and we don't have a valid lhs or the
     20        next token is a "=>", we try to parse as an arrow function.
     21
     22        Here are a few examples motivating why this is valid:
     23
     24        `x => x`
     25        In this example:
     26        - "x" is a valid arrow function starting point.
     27        - "x" also happens to be a valid lhs
     28        - because we see "=>" as the next token, we parse as an arrow function and succeed.
     29
     30        `(x) => x`
     31        In this example:
     32        - "(" is a valid arrow function starting point.
     33        - "(x)" also happens to be a valid lhs
     34        - because we see "=>" as the next token, we parse as an arrow function and succeed.
     35
     36        `({x = 30}) => x;`
     37        In this example:
     38        - "(" is a valid arrow function starting point.
     39        - "({x = 30})" is NOT a valid lhs. Because of this, we try to parse it as an arrow function and succeed.
     40
     41        There is one interesting implementation detail where we might
     42        parse something that is both a valid LHS but happens
     43        to actually be the arrow function parameters. The valid LHS
     44        parsing might declare such variables as "uses" which would cause
     45        weird capture analysis. This patch also introduces a mechanism
     46        to backtrack on used variable analysis.
     47
     48        This is a 3.5%-4.5% octane code load speedup.
     49
     50        * parser/Lexer.h:
     51        (JSC::Lexer::sawError):
     52        (JSC::Lexer::setSawError):
     53        (JSC::Lexer::getErrorMessage):
     54        (JSC::Lexer::setErrorMessage):
     55        (JSC::Lexer::sourceURL):
     56        (JSC::Lexer::sourceMappingURL):
     57        * parser/Parser.cpp:
     58        (JSC::Parser<LexerType>::isArrowFunctionParameters):
     59        (JSC::Parser<LexerType>::parseAssignmentExpression):
     60        (JSC::Parser<LexerType>::parsePrimaryExpression):
     61        * parser/Parser.h:
     62        (JSC::Scope::Scope):
     63        (JSC::Scope::startSwitch):
     64        (JSC::Scope::declareParameter):
     65        (JSC::Scope::usedVariablesContains):
     66        (JSC::Scope::useVariable):
     67        (JSC::Scope::pushUsedVariableSet):
     68        (JSC::Scope::currentUsedVariablesSize):
     69        (JSC::Scope::revertToPreviousUsedVariables):
     70        (JSC::Scope::setNeedsFullActivation):
     71        (JSC::Scope::needsFullActivation):
     72        (JSC::Scope::isArrowFunctionBoundary):
     73        (JSC::Scope::setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded):
     74        (JSC::Scope::collectFreeVariables):
     75        (JSC::Scope::fillParametersForSourceProviderCache):
     76        (JSC::Scope::restoreFromSourceProviderCache):
     77        (JSC::Scope::setIsModule):
     78
    1792016-03-31  Yusuke Suzuki  <utatane.tea@gmail.com>
    280
  • trunk/Source/JavaScriptCore/parser/Lexer.h

    r194017 r198927  
    8686    // Functions for use after parsing.
    8787    bool sawError() const { return m_error; }
     88    void setSawError(bool sawError) { m_error = sawError; }
    8889    String getErrorMessage() const { return m_lexErrorMessage; }
     90    void setErrorMessage(const String& errorMessage) { m_lexErrorMessage = errorMessage; }
    8991    String sourceURL() const { return m_sourceURLDirective; }
    9092    String sourceMappingURL() const { return m_sourceMappingURLDirective; }
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r198472 r198927  
    6161#define semanticFailIfFalse(cond, ...) do { if (!(cond)) internalFailWithMessage(false, __VA_ARGS__); } while (0)
    6262#define regexFail(failure) do { setErrorMessage(failure); return 0; } while (0)
    63 #define restoreSavePointAndFail(savePoint, message) do { restoreSavePointWithError(savePoint, message); return 0; } while (0)
    6463#define failDueToUnexpectedToken() do {\
    6564        logError(true);\
     
    360359bool Parser<LexerType>::isArrowFunctionParameters()
    361360{
    362     bool isArrowFunction = false;
    363 
    364     if (match(EOFTOK))
    365         return false;
    366    
    367361    bool isOpenParen = match(OPENPAREN);
    368362    bool isIdent = match(IDENT);
     
    371365        return false;
    372366
     367    bool isArrowFunction = false;
    373368    SavePoint saveArrowFunctionPoint = createSavePoint();
    374369       
     
    29912986    int initialNonLHSCount = m_parserState.nonLHSCount;
    29922987    bool maybeAssignmentPattern = match(OPENBRACE) || match(OPENBRACKET);
     2988#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
     2989    bool wasOpenParen = match(OPENPAREN);
     2990    bool isValidArrowFunctionStart = match(OPENPAREN) || match(IDENT);
    29932991    SavePoint savePoint = createSavePoint();
     2992    size_t usedVariablesSize;
     2993    if (wasOpenParen) {
     2994        usedVariablesSize = currentScope()->currentUsedVariablesSize();
     2995        currentScope()->pushUsedVariableSet();
     2996    }
     2997#endif
    29942998
    29952999#if ENABLE(ES6_GENERATORS)
     
    29983002#endif
    29993003
     3004    TreeExpression lhs = parseConditionalExpression(context);
     3005
    30003006#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
    3001     if (isArrowFunctionParameters())
    3002         return parseArrowFunctionExpression(context);
     3007    if (isValidArrowFunctionStart && !match(EOFTOK)) {
     3008        bool isArrowFunctionToken = match(ARROWFUNCTION);
     3009        if (!lhs || isArrowFunctionToken) {
     3010            SavePoint errorRestorationSavePoint = createSavePointForError();
     3011            String oldErrorMessage = m_errorMessage;
     3012            String oldLexerErrorMessage = m_lexer->getErrorMessage();
     3013            bool hasLexerError = m_lexer->sawError();
     3014            restoreSavePoint(savePoint);
     3015            if (isArrowFunctionParameters()) {
     3016                if (wasOpenParen)
     3017                    currentScope()->revertToPreviousUsedVariables(usedVariablesSize);
     3018                return parseArrowFunctionExpression(context);
     3019            }
     3020            restoreSavePointWithError(errorRestorationSavePoint, oldErrorMessage);
     3021            m_lexer->setErrorMessage(oldLexerErrorMessage);
     3022            m_lexer->setSawError(hasLexerError);
     3023            if (isArrowFunctionToken)
     3024                failDueToUnexpectedToken();
     3025        }
     3026    }
     3027
    30033028#endif
    3004    
    3005     TreeExpression lhs = parseConditionalExpression(context);
    30063029
    30073030    if (!lhs && (!maybeAssignmentPattern || !classifier.indicatesPossiblePattern()))
     
    30103033    if (maybeAssignmentPattern && (!lhs || (context.isObjectOrArrayLiteral(lhs) && match(EQUAL)))) {
    30113034        String expressionError = m_errorMessage;
     3035        String oldLexerErrorMessage = m_lexer->getErrorMessage();
     3036        bool hasLexerError = m_lexer->sawError();
    30123037        SavePoint expressionErrorLocation = createSavePointForError();
    30133038        restoreSavePoint(savePoint);
    30143039        auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
    3015         if (classifier.indicatesPossiblePattern() && (!pattern || !match(EQUAL)))
    3016             restoreSavePointAndFail(expressionErrorLocation, expressionError);
     3040        if (classifier.indicatesPossiblePattern() && (!pattern || !match(EQUAL))) {
     3041            restoreSavePointWithError(expressionErrorLocation, expressionError);
     3042            m_lexer->setErrorMessage(oldLexerErrorMessage);
     3043            m_lexer->setSawError(hasLexerError);
     3044            return 0;
     3045        }
    30173046        failIfFalse(pattern, "Cannot parse assignment pattern");
    30183047        consumeOrFail(EQUAL, "Expected '=' following assignment pattern");
     
    36673696        JSTokenLocation location(tokenLocation());
    36683697        next();
     3698        if (UNLIKELY(match(ARROWFUNCTION)))
     3699            return 0;
    36693700        currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident);
    36703701        m_parserState.lastIdentifier = ident;
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r198375 r198927  
    4242#include <wtf/RefPtr.h>
    4343#include <wtf/SmallPtrSet.h>
    44 
    45 namespace JSC {
    46 struct Scope;
    47 }
    48 
    49 namespace WTF {
    50 template <> struct VectorTraits<JSC::Scope> : VectorTraitsBase</* is pod */ false, void> {
    51     static const bool canMoveWithMemcpy = true;
    52 };
    53 }
    5444
    5545namespace JSC {
     
    192182        , m_innerArrowFunctionFeatures(0)
    193183    {
     184        m_usedVariables.append(UniquedStringImplPtrSet());
     185    }
     186
     187    Scope(Scope&& other)
     188        : m_vm(other.m_vm)
     189        , m_shadowsArguments(other.m_shadowsArguments)
     190        , m_usesEval(other.m_usesEval)
     191        , m_needsFullActivation(other.m_needsFullActivation)
     192        , m_hasDirectSuper(other.m_hasDirectSuper)
     193        , m_needsSuperBinding(other.m_needsSuperBinding)
     194        , m_allowsVarDeclarations(other.m_allowsVarDeclarations)
     195        , m_allowsLexicalDeclarations(other.m_allowsLexicalDeclarations)
     196        , m_strictMode(other.m_strictMode)
     197        , m_isFunction(other.m_isFunction)
     198        , m_isGenerator(other.m_isGenerator)
     199        , m_isGeneratorBoundary(other.m_isGeneratorBoundary)
     200        , m_isArrowFunction(other.m_isArrowFunction)
     201        , m_isArrowFunctionBoundary(other.m_isArrowFunctionBoundary)
     202        , m_isLexicalScope(other.m_isLexicalScope)
     203        , m_isFunctionBoundary(other.m_isFunctionBoundary)
     204        , m_isValidStrictMode(other.m_isValidStrictMode)
     205        , m_hasArguments(other.m_hasArguments)
     206        , m_isEvalContext(other.m_isEvalContext)
     207        , m_constructorKind(other.m_constructorKind)
     208        , m_expectedSuperBinding(other.m_expectedSuperBinding)
     209        , m_loopDepth(other.m_loopDepth)
     210        , m_switchDepth(other.m_switchDepth)
     211        , m_innerArrowFunctionFeatures(other.m_innerArrowFunctionFeatures)
     212        , m_labels(WTFMove(other.m_labels))
     213        , m_declaredParameters(WTFMove(other.m_declaredParameters))
     214        , m_declaredVariables(WTFMove(other.m_declaredVariables))
     215        , m_lexicalVariables(WTFMove(other.m_lexicalVariables))
     216        , m_usedVariables(WTFMove(other.m_usedVariables))
     217        , m_closedVariableCandidates(WTFMove(other.m_closedVariableCandidates))
     218        , m_writtenVariables(WTFMove(other.m_writtenVariables))
     219        , m_moduleScopeData(WTFMove(other.m_moduleScopeData))
     220        , m_functionDeclarations(WTFMove(other.m_functionDeclarations))
     221    {
    194222    }
    195223
     
    463491    }
    464492   
    465     bool usedVariablesContains(UniquedStringImpl* impl) const { return m_usedVariables.contains(impl); }
     493    bool usedVariablesContains(UniquedStringImpl* impl) const
     494    {
     495        for (const UniquedStringImplPtrSet& set : m_usedVariables) {
     496            if (set.contains(impl))
     497                return true;
     498        }
     499        return false;
     500    }
    466501    void useVariable(const Identifier* ident, bool isEval)
    467502    {
     503        useVariable(ident->impl(), isEval);
     504    }
     505    void useVariable(UniquedStringImpl* impl, bool isEval)
     506    {
    468507        m_usesEval |= isEval;
    469         m_usedVariables.add(ident->impl());
    470     }
     508        m_usedVariables.last().add(impl);
     509    }
     510
     511    void pushUsedVariableSet() { m_usedVariables.append(UniquedStringImplPtrSet()); }
     512    size_t currentUsedVariablesSize() { return m_usedVariables.size(); }
     513
     514    void revertToPreviousUsedVariables(size_t size) { m_usedVariables.resize(size); }
    471515
    472516    void setNeedsFullActivation() { m_needsFullActivation = true; }
     
    505549            setInnerArrowFunctionUsesEval();
    506550       
    507         if (m_usedVariables.contains(m_vm->propertyNames->arguments.impl()))
     551        if (usedVariablesContains(m_vm->propertyNames->arguments.impl()))
    508552            setInnerArrowFunctionUsesArguments();
    509553    }
     
    515559
    516560        {
    517             for (UniquedStringImpl* impl : nestedScope->m_usedVariables) {
    518                 if (nestedScope->m_declaredVariables.contains(impl) || nestedScope->m_lexicalVariables.contains(impl))
    519                     continue;
    520 
    521                 // "arguments" reference should be resolved at function boudary.
    522                 if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl() && !nestedScope->isArrowFunctionBoundary())
    523                     continue;
    524 
    525                 m_usedVariables.add(impl);
    526                 // We don't want a declared variable that is used in an inner scope to be thought of as captured if
    527                 // that inner scope is both a lexical scope and not a function. Only inner functions and "catch"
    528                 // statements can cause variables to be captured.
    529                 if (shouldTrackClosedVariables && (nestedScope->m_isFunctionBoundary || !nestedScope->m_isLexicalScope))
    530                     m_closedVariableCandidates.add(impl);
     561            UniquedStringImplPtrSet& destinationSet = m_usedVariables.last();
     562            for (const UniquedStringImplPtrSet& usedVariablesSet : nestedScope->m_usedVariables) {
     563                for (UniquedStringImpl* impl : usedVariablesSet) {
     564                    if (nestedScope->m_declaredVariables.contains(impl) || nestedScope->m_lexicalVariables.contains(impl))
     565                        continue;
     566
     567                    // "arguments" reference should be resolved at function boudary.
     568                    if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl() && !nestedScope->isArrowFunctionBoundary())
     569                        continue;
     570
     571                    destinationSet.add(impl);
     572                    // We don't want a declared variable that is used in an inner scope to be thought of as captured if
     573                    // that inner scope is both a lexical scope and not a function. Only inner functions and "catch"
     574                    // statements can cause variables to be captured.
     575                    if (shouldTrackClosedVariables && (nestedScope->m_isFunctionBoundary || !nestedScope->m_isLexicalScope))
     576                        m_closedVariableCandidates.add(impl);
     577                }
    531578            }
    532579        }
     
    603650        parameters.innerArrowFunctionFeatures = m_innerArrowFunctionFeatures;
    604651        copyCapturedVariablesToVector(m_writtenVariables, parameters.writtenVariables);
    605         copyCapturedVariablesToVector(m_usedVariables, parameters.usedVariables);
     652        for (const UniquedStringImplPtrSet& set : m_usedVariables)
     653            copyCapturedVariablesToVector(set, parameters.usedVariables);
    606654    }
    607655
     
    613661        m_innerArrowFunctionFeatures = info->innerArrowFunctionFeatures;
    614662        m_needsFullActivation = info->needsFullActivation;
     663        UniquedStringImplPtrSet& destSet = m_usedVariables.last();
    615664        for (unsigned i = 0; i < info->usedVariablesCount; ++i)
    616             m_usedVariables.add(info->usedVariables()[i]);
     665            destSet.add(info->usedVariables()[i]);
    617666        for (unsigned i = 0; i < info->writtenVariablesCount; ++i)
    618667            m_writtenVariables.add(info->writtenVariables()[i]);
     
    658707    }
    659708
    660     // All the fields in Scope must be able to use memcpy as their
    661     // move operation. If you add a field that violates this, make sure
    662     // to remove this comment and update WTF::VectorTraits<JSC::Scope>.
    663709    const VM* m_vm;
    664710    bool m_shadowsArguments;
     
    691737    VariableEnvironment m_declaredVariables;
    692738    VariableEnvironment m_lexicalVariables;
    693     UniquedStringImplPtrSet m_usedVariables;
     739    Vector<UniquedStringImplPtrSet, 6> m_usedVariables;
    694740    IdentifierSet m_closedVariableCandidates;
    695741    UniquedStringImplPtrSet m_writtenVariables;
Note: See TracChangeset for help on using the changeset viewer.