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)
{