Title: [200038] trunk/Source/_javascript_Core
Revision
200038
Author
sbar...@apple.com
Date
2016-04-25 12:08:53 -0700 (Mon, 25 Apr 2016)

Log Message

We don't have to parse a function's parameters every time if the function is in the source provider cache
https://bugs.webkit.org/show_bug.cgi?id=156943

Reviewed by Filip Pizlo.

This patch makes a few changes to make parsing inner functions
faster.

First, we were always parsing an inner function's parameter
list using the templatized TreeBuiler. This means if our parent scope
was building an AST, we ended up building AST nodes for the inner
function's parameter list even though these nodes would go unused.
This patch fixes that to *always* build an inner function's parameter
list using the SyntaxChecker. (Note that this is consistent now with
always building an inner function's body with a SyntaxChecker.)

Second, we were always parsing an inner function's parameter list
even if we had that function saved in the source provider cache.
I've fixed that bug and made it so that we skip over the parsing
of a function's parameter list when it's in the source provider
cache. We could probably enhance this in the future to skip
over the entirety of a function starting at the "function"
keyword or any other start of the function (depending on
the function type: arrow function, method, etc).

This patch also renames a few fields. First, I fixed a typo
from "tocken" => "token" for a few field names. Secondly,
I renamed a field that was called 'bodyStartColumn' to
'parametersStartColumn' because the field really held the
parameter list's start column.

I'm benchmarking this as a 1.5-2% octane/jquery speedup
on a 15" MBP.

* parser/ASTBuilder.h:
(JSC::ASTBuilder::createFunctionExpr):
(JSC::ASTBuilder::createMethodDefinition):
(JSC::ASTBuilder::createArrowFunctionExpr):
(JSC::ASTBuilder::createGetterOrSetterProperty):
(JSC::ASTBuilder::createFuncDeclStatement):
* parser/Lexer.cpp:
(JSC::Lexer<T>::lex):
* parser/Lexer.h:
(JSC::Lexer::currentPosition):
(JSC::Lexer::positionBeforeLastNewline):
(JSC::Lexer::lastTokenLocation):
(JSC::Lexer::setLastLineNumber):
(JSC::Lexer::lastLineNumber):
(JSC::Lexer::prevTerminator):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
(JSC::Parser<LexerType>::parseFunctionBody):
(JSC::stringForFunctionMode):
(JSC::Parser<LexerType>::parseFunctionParameters):
(JSC::Parser<LexerType>::parseFunctionInfo):
* parser/Parser.h:
(JSC::Scope::usedVariablesContains):
(JSC::Scope::forEachUsedVariable):
(JSC::Scope::useVariable):
(JSC::Scope::copyCapturedVariablesToVector):
(JSC::Scope::fillParametersForSourceProviderCache):
(JSC::Scope::restoreFromSourceProviderCache):
* parser/ParserFunctionInfo.h:
* parser/SourceProviderCacheItem.h:
(JSC::SourceProviderCacheItem::endFunctionToken):
(JSC::SourceProviderCacheItem::usedVariables):
(JSC::SourceProviderCacheItem::SourceProviderCacheItem):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (200037 => 200038)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-25 19:08:53 UTC (rev 200038)
@@ -1,3 +1,74 @@
+2016-04-25  Saam barati  <sbar...@apple.com>
+
+        We don't have to parse a function's parameters every time if the function is in the source provider cache
+        https://bugs.webkit.org/show_bug.cgi?id=156943
+
+        Reviewed by Filip Pizlo.
+
+        This patch makes a few changes to make parsing inner functions
+        faster.
+
+        First, we were always parsing an inner function's parameter
+        list using the templatized TreeBuiler. This means if our parent scope
+        was building an AST, we ended up building AST nodes for the inner
+        function's parameter list even though these nodes would go unused.
+        This patch fixes that to *always* build an inner function's parameter
+        list using the SyntaxChecker. (Note that this is consistent now with
+        always building an inner function's body with a SyntaxChecker.)
+
+        Second, we were always parsing an inner function's parameter list
+        even if we had that function saved in the source provider cache.
+        I've fixed that bug and made it so that we skip over the parsing 
+        of a function's parameter list when it's in the source provider
+        cache. We could probably enhance this in the future to skip
+        over the entirety of a function starting at the "function"
+        keyword or any other start of the function (depending on
+        the function type: arrow function, method, etc).
+
+        This patch also renames a few fields. First, I fixed a typo
+        from "tocken" => "token" for a few field names. Secondly,
+        I renamed a field that was called 'bodyStartColumn' to 
+        'parametersStartColumn' because the field really held the
+        parameter list's start column.
+
+        I'm benchmarking this as a 1.5-2% octane/jquery speedup
+        on a 15" MBP.
+
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createFunctionExpr):
+        (JSC::ASTBuilder::createMethodDefinition):
+        (JSC::ASTBuilder::createArrowFunctionExpr):
+        (JSC::ASTBuilder::createGetterOrSetterProperty):
+        (JSC::ASTBuilder::createFuncDeclStatement):
+        * parser/Lexer.cpp:
+        (JSC::Lexer<T>::lex):
+        * parser/Lexer.h:
+        (JSC::Lexer::currentPosition):
+        (JSC::Lexer::positionBeforeLastNewline):
+        (JSC::Lexer::lastTokenLocation):
+        (JSC::Lexer::setLastLineNumber):
+        (JSC::Lexer::lastLineNumber):
+        (JSC::Lexer::prevTerminator):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseInner):
+        (JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
+        (JSC::Parser<LexerType>::parseFunctionBody):
+        (JSC::stringForFunctionMode):
+        (JSC::Parser<LexerType>::parseFunctionParameters):
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        * parser/Parser.h:
+        (JSC::Scope::usedVariablesContains):
+        (JSC::Scope::forEachUsedVariable):
+        (JSC::Scope::useVariable):
+        (JSC::Scope::copyCapturedVariablesToVector):
+        (JSC::Scope::fillParametersForSourceProviderCache):
+        (JSC::Scope::restoreFromSourceProviderCache):
+        * parser/ParserFunctionInfo.h:
+        * parser/SourceProviderCacheItem.h:
+        (JSC::SourceProviderCacheItem::endFunctionToken):
+        (JSC::SourceProviderCacheItem::usedVariables):
+        (JSC::SourceProviderCacheItem::SourceProviderCacheItem):
+
 2016-04-25  Mark Lam  <mark....@apple.com>
 
         Renaming SpecInt32, SpecInt52, MachineInt to SpecInt32Only, SpecInt52Only, AnyInt.

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2016-04-25 19:08:53 UTC (rev 200038)
@@ -375,7 +375,7 @@
     ExpressionNode* createFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
         FuncExprNode* result = new (m_parserArena) FuncExprNode(location, *functionInfo.name, functionInfo.body,
-            m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn));
+            m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn));
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
         return result;
     }
@@ -383,7 +383,7 @@
     ExpressionNode* createMethodDefinition(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
         MethodDefinitionNode* result = new (m_parserArena) MethodDefinitionNode(location, *functionInfo.name, functionInfo.body,
-            m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn));
+            m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn));
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
         return result;
     }
@@ -403,7 +403,7 @@
     ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
         usesArrowFunction();
-        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.body->isArrowFunctionBodyExpression() ? functionInfo.endOffset - 1 : functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.body->isArrowFunctionBodyExpression() ? functionInfo.endOffset - 1 : functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn);
         ArrowFuncExprNode* result = new (m_parserArena) ArrowFuncExprNode(location, *functionInfo.name, functionInfo.body, source);
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
         return result;
@@ -416,7 +416,7 @@
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
         functionInfo.body->setEcmaName(*name);
         functionInfo.body->setInferredName(*name);
-        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn);
         MethodDefinitionNode* methodDef = new (m_parserArena) MethodDefinitionNode(location, m_vm->propertyNames->nullIdentifier, functionInfo.body, source);
         return new (m_parserArena) PropertyNode(*name, methodDef, type, PropertyNode::Unknown, SuperBinding::Needed, isClassProperty);
     }
@@ -426,7 +426,7 @@
     {
         ASSERT(name);
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
-        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn);
         MethodDefinitionNode* methodDef = new (m_parserArena) MethodDefinitionNode(location, m_vm->propertyNames->nullIdentifier, functionInfo.body, source);
         return new (m_parserArena) PropertyNode(name, methodDef, type, PropertyNode::Unknown, SuperBinding::Needed, isClassProperty);
     }
@@ -436,7 +436,7 @@
     {
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
         const Identifier& ident = parserArena.identifierArena().makeNumericIdentifier(vm, name);
-        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+        SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn);
         MethodDefinitionNode* methodDef = new (m_parserArena) MethodDefinitionNode(location, vm->propertyNames->nullIdentifier, functionInfo.body, source);
         return new (m_parserArena) PropertyNode(ident, methodDef, type, PropertyNode::Unknown, SuperBinding::Needed, isClassProperty);
     }
@@ -491,7 +491,7 @@
     StatementNode* createFuncDeclStatement(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
         FuncDeclNode* decl = new (m_parserArena) FuncDeclNode(location, *functionInfo.name, functionInfo.body,
-            m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn));
+            m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn));
         if (*functionInfo.name == m_vm->propertyNames->arguments)
             usesArguments();
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);

Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/Lexer.cpp	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp	2016-04-25 19:08:53 UTC (rev 200038)
@@ -1770,7 +1770,7 @@
 {
     JSTokenData* tokenData = &tokenRecord->m_data;
     JSTokenLocation* tokenLocation = &tokenRecord->m_location;
-    m_lastTockenLocation = JSTokenLocation(tokenRecord->m_location);
+    m_lastTokenLocation = JSTokenLocation(tokenRecord->m_location);
     
     ASSERT(!m_error);
     ASSERT(m_buffer8.isEmpty());
@@ -2002,6 +2002,9 @@
         break;
     case CharacterOpenParen:
         token = OPENPAREN;
+        tokenData->line = lineNumber();
+        tokenData->offset = currentOffset();
+        tokenData->lineStartOffset = currentLineStartOffset();
         shift();
         break;
     case CharacterCloseParen:

Modified: trunk/Source/_javascript_Core/parser/Lexer.h (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/Lexer.h	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/Lexer.h	2016-04-25 19:08:53 UTC (rev 200038)
@@ -73,7 +73,7 @@
         return JSTextPosition(m_lineNumber, currentOffset(), currentLineStartOffset());
     }
     JSTextPosition positionBeforeLastNewline() const { return m_positionBeforeLastNewline; }
-    JSTokenLocation lastTokenLocation() const { return m_lastTockenLocation; }
+    JSTokenLocation lastTokenLocation() const { return m_lastTokenLocation; }
     void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
     int lastLineNumber() const { return m_lastLineNumber; }
     bool prevTerminator() const { return m_terminator; }
@@ -202,7 +202,7 @@
     const T* m_codeStartPlusOffset;
     const T* m_lineStart;
     JSTextPosition m_positionBeforeLastNewline;
-    JSTokenLocation m_lastTockenLocation;
+    JSTokenLocation m_lastTokenLocation;
     bool m_isReparsingFunction;
     bool m_atLineStart;
     bool m_error;

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2016-04-25 19:08:53 UTC (rev 200038)
@@ -253,10 +253,9 @@
     if (m_lexer->isReparsingFunction()) {
         ParserFunctionInfo<ASTBuilder> functionInfo;
         if (parseMode == SourceParseMode::GeneratorBodyMode)
-            functionInfo.parameters = createGeneratorParameters(context);
+            m_parameters = createGeneratorParameters(context);
         else
-            parseFunctionParameters(context, parseMode, functionInfo);
-        m_parameters = functionInfo.parameters;
+            m_parameters = parseFunctionParameters(context, parseMode, functionInfo);
 
         if (parseMode == SourceParseMode::ArrowFunctionMode && !hasError()) {
             // The only way we could have an error wile reparsing is if we run out of stack space.
@@ -497,7 +496,7 @@
 
     ParserFunctionInfo<TreeBuilder> info;
     info.name = &m_vm->propertyNames->nullIdentifier;
-    info.parameters = createGeneratorParameters(context);
+    createGeneratorParameters(context);
     info.startOffset = parametersStart;
     info.startLine = tokenLine();
     info.parameterCount = 4; // generator, state, value, resume mode
@@ -513,7 +512,7 @@
 
     info.endLine = tokenLine();
     info.endOffset = m_token.m_data.offset;
-    info.bodyStartColumn = startColumn;
+    info.parametersStartColumn = startColumn;
 
     auto functionExpr = context.createFunctionExpr(startLocation, info);
     auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
@@ -1767,7 +1766,7 @@
 
 template <typename LexerType>
 template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(
-    TreeBuilder& context, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart, 
+    TreeBuilder& context, SyntaxChecker& syntaxChecker, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart, 
     ConstructorKind constructorKind, SuperBinding superBinding, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
 {
     bool isArrowFunctionBodyExpression = bodyType == ArrowFunctionBodyExpression;
@@ -1781,7 +1780,6 @@
 
     DepthManager statementDepth(&m_statementDepth);
     m_statementDepth = 0;
-    SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
     if (bodyType == ArrowFunctionBodyExpression)
         failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(syntaxChecker), "Cannot parse body of this arrow function");
     else
@@ -1817,13 +1815,10 @@
     return nullptr;
 }
 
-template <typename LexerType> template <class TreeBuilder> int Parser<LexerType>::parseFunctionParameters(TreeBuilder& context, SourceParseMode mode, ParserFunctionInfo<TreeBuilder>& functionInfo)
+template <typename LexerType> template <class TreeBuilder, class FunctionInfoType> typename TreeBuilder::FormalParameterList Parser<LexerType>::parseFunctionParameters(TreeBuilder& context, SourceParseMode mode, FunctionInfoType& functionInfo)
 {
     RELEASE_ASSERT(mode != SourceParseMode::ProgramMode && mode != SourceParseMode::ModuleAnalyzeMode && mode != SourceParseMode::ModuleEvaluateMode);
-    int parametersStart = m_token.m_location.startOffset;
     TreeFormalParameterList parameterList = context.createFormalParameterList();
-    functionInfo.parameters = parameterList;
-    functionInfo.startOffset = parametersStart;
     SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Parameters);
     
     if (mode == SourceParseMode::ArrowFunctionMode) {
@@ -1848,7 +1843,7 @@
             }
         }
 
-        return parametersStart;
+        return parameterList;
     }
 
     if (!consume(OPENPAREN)) {
@@ -1879,7 +1874,7 @@
         consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration");
     }
 
-    return parametersStart;
+    return parameterList;
 }
 
 template <typename LexerType>
@@ -1925,17 +1920,93 @@
     int functionNameStart = m_token.m_location.startOffset;
     const Identifier* lastFunctionName = m_parserState.lastFunctionName;
     m_parserState.lastFunctionName = nullptr;
-    int parametersStart;
+    int parametersStart = -1;
     JSTokenLocation startLocation;
-    int startColumn;
+    int startColumn = -1;
     FunctionBodyType functionBodyType;
 
+    auto loadCachedFunction = [&] () -> bool {
+        ASSERT(parametersStart != -1);
+        ASSERT(startColumn != -1);
+
+        // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
+        if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(parametersStart) : 0) {
+            // If we're in a strict context, the cached function info must say it was strict too.
+            ASSERT(!strictMode() || cachedInfo->strictMode);
+            JSTokenLocation endLocation;
+
+            ConstructorKind constructorKind = static_cast<ConstructorKind>(cachedInfo->constructorKind);
+            SuperBinding expectedSuperBinding = static_cast<SuperBinding>(cachedInfo->expectedSuperBinding);
+            functionScope->setConstructorKind(constructorKind);
+            functionScope->setExpectedSuperBinding(expectedSuperBinding);
+
+            endLocation.line = cachedInfo->lastTokenLine;
+            endLocation.startOffset = cachedInfo->lastTokenStartOffset;
+            endLocation.lineStartOffset = cachedInfo->lastTokenLineStartOffset;
+            ASSERT(endLocation.startOffset >= endLocation.lineStartOffset);
+
+            bool endColumnIsOnStartLine = endLocation.line == functionInfo.startLine;
+            unsigned currentLineStartOffset = m_lexer->currentLineStartOffset();
+            unsigned bodyEndColumn = endColumnIsOnStartLine ? endLocation.startOffset - currentLineStartOffset : endLocation.startOffset - endLocation.lineStartOffset;
+
+            ASSERT(endLocation.startOffset >= endLocation.lineStartOffset);
+            
+            FunctionBodyType functionBodyType;
+            if (mode == SourceParseMode::ArrowFunctionMode)
+                functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
+            else
+                functionBodyType = StandardFunctionBodyBlock;
+            
+            functionInfo.body = context.createFunctionMetadata(
+                startLocation, endLocation, startColumn, bodyEndColumn, 
+                functionKeywordStart, functionNameStart, parametersStart, 
+                cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression);
+            functionInfo.endOffset = cachedInfo->endFunctionOffset;
+            functionInfo.parameterCount = cachedInfo->parameterCount;
+
+            functionScope->restoreFromSourceProviderCache(cachedInfo);
+            popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
+            
+            m_token = cachedInfo->endFunctionToken();
+
+            if (endColumnIsOnStartLine)
+                m_token.m_location.lineStartOffset = currentLineStartOffset;
+
+            m_lexer->setOffset(m_token.m_location.endOffset, m_token.m_location.lineStartOffset);
+            m_lexer->setLineNumber(m_token.m_location.line);
+
+            switch (functionBodyType) {
+            case ArrowFunctionBodyExpression:
+                next();
+                context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
+                break;
+            case ArrowFunctionBodyBlock:
+            case StandardFunctionBodyBlock:
+                context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
+                next();
+                break;
+            }
+            functionInfo.endLine = m_lastTokenEndPosition.line;
+            return true;
+        }
+
+        return false;
+    };
+
+    SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
+
     if (mode == SourceParseMode::ArrowFunctionMode) {
         startLocation = tokenLocation();
         functionInfo.startLine = tokenLine();
         startColumn = tokenColumn();
 
-        parametersStart = parseFunctionParameters(context, mode, functionInfo);
+        parametersStart = m_token.m_location.startOffset;
+        functionInfo.startOffset = parametersStart;
+        functionInfo.parametersStartColumn = startColumn;
+
+        if (loadCachedFunction())
+            return true;
+        parseFunctionParameters(syntaxChecker, mode, functionInfo);
         propagateError();
 
         matchOrFail(ARROWFUNCTION, "Expected a '=>' after arrow function parameter declaration");
@@ -1986,8 +2057,14 @@
         startLocation = tokenLocation();
         functionInfo.startLine = tokenLine();
         startColumn = tokenColumn();
+        functionInfo.parametersStartColumn = startColumn;
 
-        parametersStart = parseFunctionParameters(context, mode, functionInfo);
+        parametersStart = m_token.m_location.startOffset;
+        functionInfo.startOffset = parametersStart;
+
+        if (loadCachedFunction())
+            return true;
+        parseFunctionParameters(syntaxChecker, mode, functionInfo);
         propagateError();
         
         matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body");
@@ -2006,67 +2083,30 @@
     functionScope->setConstructorKind(constructorKind);
     functionScope->setExpectedSuperBinding(expectedSuperBinding);
 
-    functionInfo.bodyStartColumn = startColumn;
-    
-    // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
-    if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(functionInfo.startOffset) : 0) {
-        // If we're in a strict context, the cached function info must say it was strict too.
-        ASSERT(!strictMode() || cachedInfo->strictMode);
-        JSTokenLocation endLocation;
-
-        endLocation.line = cachedInfo->lastTockenLine;
-        endLocation.startOffset = cachedInfo->lastTockenStartOffset;
-        endLocation.lineStartOffset = cachedInfo->lastTockenLineStartOffset;
-
-        bool endColumnIsOnStartLine = (endLocation.line == functionInfo.startLine);
-        ASSERT(endLocation.startOffset >= endLocation.lineStartOffset);
-        unsigned bodyEndColumn = endColumnIsOnStartLine ?
-            endLocation.startOffset - m_token.m_data.lineStartOffset :
-            endLocation.startOffset - endLocation.lineStartOffset;
-        unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
-        
-        functionInfo.body = context.createFunctionMetadata(
-            startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn, 
-            functionKeywordStart, functionNameStart, parametersStart, 
-            cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression);
-        
-        functionScope->restoreFromSourceProviderCache(cachedInfo);
-        popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
-        
-        m_token = cachedInfo->endFunctionToken();
-        
-        if (endColumnIsOnStartLine)
-            m_token.m_location.lineStartOffset = currentLineStartOffset;
-
-        m_lexer->setOffset(m_token.m_location.endOffset, m_token.m_location.lineStartOffset);
-        m_lexer->setLineNumber(m_token.m_location.line);
-        functionInfo.endOffset = cachedInfo->endFunctionOffset;
-
-        if (mode == SourceParseMode::ArrowFunctionMode)
-            functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
-        else
-            functionBodyType = StandardFunctionBodyBlock;
-        
-        switch (functionBodyType) {
-        case ArrowFunctionBodyExpression:
-            next();
-            context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
-            break;
-        case ArrowFunctionBodyBlock:
-        case StandardFunctionBodyBlock:
-            context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
-            next();
-            break;
-        }
-        functionInfo.endLine = m_lastTokenEndPosition.line;
-        return true;
-    }
-    
     m_parserState.lastFunctionName = lastFunctionName;
     ParserState oldState = internalSaveParserState();
 
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156962
+    // This loop collects the set of capture candidates that aren't
+    // part of the set of this function's declared parameters. We will
+    // figure out which parameters are captured for this function when
+    // we actually generate code for it. For now, we just propagate to
+    // our parent scopes which variables we might have closed over that
+    // belong to them. This is necessary for correctness when using
+    // the source provider cache because we can't close over a variable
+    // that we don't claim to close over. The source provider cache must
+    // know this information to properly cache this function.
+    // This might work itself out nicer if we declared a different
+    // Scope struct for the parameters (because they are indeed implemented
+    // as their own scope).
+    UniquedStringImplPtrSet nonLocalCapturesFromParameterExpressions;
+    functionScope->forEachUsedVariable([&] (UniquedStringImpl* impl) {
+        if (!functionScope->hasDeclaredParameter(impl))
+            nonLocalCapturesFromParameterExpressions.add(impl);
+    });
+
     auto performParsingFunctionBody = [&] {
-        return parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
+        return parseFunctionBody(context, syntaxChecker, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
     };
 
     if (mode == SourceParseMode::GeneratorWrapperFunctionMode) {
@@ -2134,16 +2174,18 @@
         SourceProviderCacheItemCreationParameters parameters;
         parameters.endFunctionOffset = functionInfo.endOffset;
         parameters.functionNameStart = functionNameStart;
-        parameters.lastTockenLine = location.line;
-        parameters.lastTockenStartOffset = location.startOffset;
-        parameters.lastTockenEndOffset = location.endOffset;
-        parameters.lastTockenLineStartOffset = location.lineStartOffset;
+        parameters.lastTokenLine = location.line;
+        parameters.lastTokenStartOffset = location.startOffset;
+        parameters.lastTokenEndOffset = location.endOffset;
+        parameters.lastTokenLineStartOffset = location.lineStartOffset;
         parameters.parameterCount = functionInfo.parameterCount;
+        parameters.constructorKind = constructorKind;
+        parameters.expectedSuperBinding = expectedSuperBinding;
         if (functionBodyType == ArrowFunctionBodyExpression) {
             parameters.isBodyArrowExpression = true;
             parameters.tokenType = m_token.m_type;
         }
-        functionScope->fillParametersForSourceProviderCache(parameters);
+        functionScope->fillParametersForSourceProviderCache(parameters, nonLocalCapturesFromParameterExpressions);
         newInfo = SourceProviderCacheItem::create(parameters);
     }
     
@@ -2153,7 +2195,7 @@
         matchOrFail(CLOSEBRACE, "Expected a closing '}' after a ", stringForFunctionMode(mode), " body");
         next();
     }
-    
+
     if (newInfo)
         m_functionCache->add(functionInfo.startOffset, WTFMove(newInfo));
     

Modified: trunk/Source/_javascript_Core/parser/Parser.h (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/Parser.h	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2016-04-25 19:08:53 UTC (rev 200038)
@@ -50,6 +50,7 @@
 class VM;
 class ProgramNode;
 class SourceCode;
+class SyntaxChecker;
 
 // Macros to make the more common TreeBuilder types a little less verbose
 #define TreeStatement typename TreeBuilder::Statement
@@ -501,6 +502,14 @@
         }
         return false;
     }
+    template <typename Func>
+    void forEachUsedVariable(const Func& func)
+    {
+        for (const UniquedStringImplPtrSet& set : m_usedVariables) {
+            for (UniquedStringImpl* impl : set)
+                func(impl);
+        }
+    }
     void useVariable(const Identifier* ident, bool isEval)
     {
         useVariable(ident->impl(), isEval);
@@ -644,7 +653,7 @@
         }
     }
 
-    void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters)
+    void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters, const UniquedStringImplPtrSet& capturesFromParameterExpressions)
     {
         ASSERT(m_isFunction);
         parameters.usesEval = m_usesEval;
@@ -653,6 +662,18 @@
         parameters.innerArrowFunctionFeatures = m_innerArrowFunctionFeatures;
         for (const UniquedStringImplPtrSet& set : m_usedVariables)
             copyCapturedVariablesToVector(set, parameters.usedVariables);
+
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156962
+        // We add these unconditionally because we currently don't keep a separate
+        // declaration scope for a function's parameters and its var/let/const declarations.
+        // This is somewhat unfortunate and we should refactor to do this at some point
+        // because parameters logically form a parent scope to var/let/const variables.
+        // But because we don't do this, we must grab capture candidates from a parameter
+        // list before we parse the body of a function because the body's declarations
+        // might make us believe something isn't actually a capture candidate when it really
+        // is.
+        for (UniquedStringImpl* impl : capturesFromParameterExpressions)
+            parameters.usedVariables.append(impl);
     }
 
     void restoreFromSourceProviderCache(const SourceProviderCacheItem* info)
@@ -1389,7 +1410,7 @@
     template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
     template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator);
     template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind, bool isClassProperty);
-    template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, SuperBinding, FunctionBodyType, unsigned, SourceParseMode);
+    template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, SyntaxChecker&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, SuperBinding, FunctionBodyType, unsigned, SourceParseMode);
     template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, unsigned&);
     enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
     template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, ExportType, bool& forLoopConstDoesNotHaveInitializer);
@@ -1415,7 +1436,7 @@
     
     ALWAYS_INLINE bool isArrowFunctionParameters();
     
-    template <class TreeBuilder> NEVER_INLINE int parseFunctionParameters(TreeBuilder&, SourceParseMode, ParserFunctionInfo<TreeBuilder>&);
+    template <class TreeBuilder, class FunctionInfoType> NEVER_INLINE typename TreeBuilder::FormalParameterList parseFunctionParameters(TreeBuilder&, SourceParseMode, FunctionInfoType&);
     template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::FormalParameterList createGeneratorParameters(TreeBuilder&);
 
     template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);

Modified: trunk/Source/_javascript_Core/parser/ParserFunctionInfo.h (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/ParserFunctionInfo.h	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/ParserFunctionInfo.h	2016-04-25 19:08:53 UTC (rev 200038)
@@ -31,14 +31,13 @@
 template <class TreeBuilder>
 struct ParserFunctionInfo {
     const Identifier* name = 0;
-    typename TreeBuilder::FormalParameterList parameters = 0;
     typename TreeBuilder::FunctionBody body = 0;
     unsigned parameterCount = 0;
     unsigned startOffset = 0;
     unsigned endOffset = 0;
     int startLine = 0;
     int endLine = 0;
-    unsigned bodyStartColumn = 0;
+    unsigned parametersStartColumn = 0;
 };
 
 template <class TreeBuilder>

Modified: trunk/Source/_javascript_Core/parser/SourceProviderCacheItem.h (200037 => 200038)


--- trunk/Source/_javascript_Core/parser/SourceProviderCacheItem.h	2016-04-25 18:38:56 UTC (rev 200037)
+++ trunk/Source/_javascript_Core/parser/SourceProviderCacheItem.h	2016-04-25 19:08:53 UTC (rev 200038)
@@ -35,10 +35,10 @@
 
 struct SourceProviderCacheItemCreationParameters {
     unsigned functionNameStart;
-    unsigned lastTockenLine;
-    unsigned lastTockenStartOffset;
-    unsigned lastTockenEndOffset;
-    unsigned lastTockenLineStartOffset;
+    unsigned lastTokenLine;
+    unsigned lastTokenStartOffset;
+    unsigned lastTokenEndOffset;
+    unsigned lastTokenLineStartOffset;
     unsigned endFunctionOffset;
     unsigned parameterCount;
     bool needsFullActivation;
@@ -48,6 +48,8 @@
     Vector<UniquedStringImpl*, 8> usedVariables;
     bool isBodyArrowExpression { false };
     JSTokenType tokenType { CLOSEBRACE };
+    ConstructorKind constructorKind;
+    SuperBinding expectedSuperBinding;
 };
 
 #if COMPILER(MSVC)
@@ -65,11 +67,11 @@
     {
         JSToken token;
         token.m_type = isBodyArrowExpression ? tokenType : CLOSEBRACE;
-        token.m_data.offset = lastTockenStartOffset;
-        token.m_location.startOffset = lastTockenStartOffset;
-        token.m_location.endOffset = lastTockenEndOffset;
-        token.m_location.line = lastTockenLine;
-        token.m_location.lineStartOffset = lastTockenLineStartOffset;
+        token.m_data.offset = lastTokenStartOffset;
+        token.m_location.startOffset = lastTokenStartOffset;
+        token.m_location.endOffset = lastTokenEndOffset;
+        token.m_location.line = lastTokenLine;
+        token.m_location.lineStartOffset = lastTokenLineStartOffset;
         // token.m_location.sourceOffset is initialized once by the client. So,
         // we do not need to set it here.
         return token;
@@ -77,26 +79,23 @@
 
     unsigned functionNameStart : 31;
     bool needsFullActivation : 1;
-
     unsigned endFunctionOffset : 31;
-    unsigned lastTockenLine : 31;
-    unsigned lastTockenStartOffset : 31;
-    unsigned lastTockenEndOffset: 31;
-    unsigned parameterCount;
-    
     bool usesEval : 1;
-
+    unsigned lastTokenLine : 31;
     bool strictMode : 1;
-    
+    unsigned lastTokenStartOffset : 31;
+    unsigned lastTokenEndOffset: 31;
+    unsigned constructorKind : 2; // ConstructorKind
+    unsigned parameterCount : 31;
+    unsigned expectedSuperBinding : 1; // SuperBinding
+    unsigned lastTokenLineStartOffset;
+    unsigned usedVariablesCount;
     InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures;
-
-    unsigned lastTockenLineStartOffset;
-    unsigned usedVariablesCount;
-
-    UniquedStringImpl** usedVariables() const { return const_cast<UniquedStringImpl**>(m_variables); }
     bool isBodyArrowExpression;
     JSTokenType tokenType;
 
+    UniquedStringImpl** usedVariables() const { return const_cast<UniquedStringImpl**>(m_variables); }
+
 private:
     SourceProviderCacheItem(const SourceProviderCacheItemCreationParameters&);
 
@@ -121,15 +120,17 @@
     : functionNameStart(parameters.functionNameStart)
     , needsFullActivation(parameters.needsFullActivation)
     , endFunctionOffset(parameters.endFunctionOffset)
-    , lastTockenLine(parameters.lastTockenLine)
-    , lastTockenStartOffset(parameters.lastTockenStartOffset)
-    , lastTockenEndOffset(parameters.lastTockenEndOffset)
-    , parameterCount(parameters.parameterCount)
     , usesEval(parameters.usesEval)
+    , lastTokenLine(parameters.lastTokenLine)
     , strictMode(parameters.strictMode)
+    , lastTokenStartOffset(parameters.lastTokenStartOffset)
+    , lastTokenEndOffset(parameters.lastTokenEndOffset)
+    , constructorKind(static_cast<unsigned>(parameters.constructorKind))
+    , parameterCount(parameters.parameterCount)
+    , expectedSuperBinding(static_cast<unsigned>(parameters.expectedSuperBinding))
+    , lastTokenLineStartOffset(parameters.lastTokenLineStartOffset)
+    , usedVariablesCount(parameters.usedVariables.size())
     , innerArrowFunctionFeatures(parameters.innerArrowFunctionFeatures)
-    , lastTockenLineStartOffset(parameters.lastTockenLineStartOffset)
-    , usedVariablesCount(parameters.usedVariables.size())
     , isBodyArrowExpression(parameters.isBodyArrowExpression)
     , tokenType(parameters.tokenType)
 {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to