Ignore:
Timestamp:
Jul 15, 2015, 2:41:08 PM (10 years ago)
Author:
[email protected]
Message:

[ES6] implement block scoping to enable 'let'
https://bugs.webkit.org/show_bug.cgi?id=142944

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

(JSC::BuiltinExecutables::createExecutableInternal):

  • bytecode/BytecodeList.json:

This patch adds a new opcode and removes op_pop_scope:
1) op_get_parent_scope returns the parent scope but doesn't
implicitly write that scope into the scope register. op_pop_scope
is now reduced to op_get_parent_scope followed by op_mov.

  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::stronglyVisitStrongReferences):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::addStringSwitchJumpTable):
(JSC::CodeBlock::stringSwitchJumpTable):
(JSC::CodeBlock::symbolTable):
(JSC::CodeBlock::evalCodeCache):
(JSC::CodeBlock::setConstantRegisters):
(JSC::CodeBlock::replaceConstant):
op_put_to_scope for LocalClosureVar now takes as an argument
the constant index for the Symbol Table it will be putting into.
This argument is only used to communicate from the BytecodeGenerator
to CodeBlock linking time and it is not present in the linked bytecode.

op_put_to_scope for non LocalClosureVar takes, at the same index, an
argument that represents the local scope depth which it uses for
JSScope::abstractResolve to know how many scopes it needs to skip.
Again, this is not in the linked code.
op_get_from_scope and op_resolve_scope also take as an argument
the local scope depth to use in JSScope::abstractResolve. Again,
this is not used in the linked code.

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::tryGet):
(JSC::EvalCodeCache::getSlow):
(JSC::EvalCodeCache::clear):
(JSC::EvalCodeCache::isCacheable):
When direct eval is called and passed a scope that
corresponds to a lexical scope, we can't safely cache
that code because we won't be able to guarantee
that the cached code is always executed in the same scope.
Consider this example:
function foo() {

let x = 20;
eval("x;");
if (b) {

let x = 30;
if (b) {

let y = 40;
eval("x;")

}

}

}

We can't reuse resolution depth when linking get_from_scope in evals.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::parameterCount):

  • bytecode/UnlinkedCodeBlock.h:

Unlinked functions now know the variables that were under TDZ in their parent
scope.

(JSC::UnlinkedCodeBlock::symbolTable):
(JSC::UnlinkedCodeBlock::setSymbolTable):
(JSC::UnlinkedCodeBlock::setSymbolTableConstantIndex):
(JSC::UnlinkedCodeBlock::symbolTableConstantIndex):
(JSC::UnlinkedCodeBlock::vm):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::~BytecodeGenerator):
(JSC::BytecodeGenerator::newRegister):
(JSC::BytecodeGenerator::reclaimFreeRegisters):
(JSC::BytecodeGenerator::newBlockScopeVariable):
(JSC::BytecodeGenerator::newTemporary):
(JSC::BytecodeGenerator::emitProfileType):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC::BytecodeGenerator::pushLexicalScope):
(JSC::BytecodeGenerator::popLexicalScope):
(JSC::BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration):
(JSC::BytecodeGenerator::variable):
(JSC::BytecodeGenerator::variablePerSymbolTable):
(JSC::BytecodeGenerator::variableForLocalEntry):
(JSC::BytecodeGenerator::createVariable):
(JSC::BytecodeGenerator::emitResolveScope):
(JSC::BytecodeGenerator::emitGetFromScope):
(JSC::BytecodeGenerator::emitPutToScope):
(JSC::BytecodeGenerator::initializeVariable):
(JSC::BytecodeGenerator::emitTDZCheck):
(JSC::BytecodeGenerator::needsTDZCheck):
(JSC::BytecodeGenerator::emitTDZCheckIfNecessary):
(JSC::BytecodeGenerator::liftTDZCheckIfPossible):
(JSC::BytecodeGenerator::getVariablesUnderTDZ):
(JSC::BytecodeGenerator::emitNewObject):
(JSC::BytecodeGenerator::emitPushWithScope):
(JSC::BytecodeGenerator::emitGetParentScope):
(JSC::BytecodeGenerator::emitPopScope):
(JSC::BytecodeGenerator::emitDebugHook):
(JSC::BytecodeGenerator::pushFinallyContext):
(JSC::BytecodeGenerator::pushIteratorCloseContext):
(JSC::BytecodeGenerator::emitComplexPopScopes):
(JSC::BytecodeGenerator::emitPopScopes):
(JSC::BytecodeGenerator::popTryAndEmitCatch):
(JSC::BytecodeGenerator::calculateTargetScopeDepthForExceptionHandler):
(JSC::BytecodeGenerator::currentScopeDepth):
(JSC::BytecodeGenerator::emitThrowReferenceError):
(JSC::BytecodeGenerator::emitPushCatchScope):
(JSC::BytecodeGenerator::beginSwitch):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
(JSC::BytecodeGenerator::emitEnumeration):

  • bytecompiler/BytecodeGenerator.h:

(JSC::Variable::Variable):
(JSC::Variable::isResolved):
(JSC::Variable::symbolTableConstantIndex):
(JSC::Variable::ident):
(JSC::BytecodeGenerator::ignoredResult):
(JSC::BytecodeGenerator::tempDestination):
(JSC::BytecodeGenerator::lastOpcodeID):
(JSC::BytecodeGenerator::makeFunction):
(JSC::BytecodeGenerator::symbolTable):
(JSC::BytecodeGenerator::shouldOptimizeLocals): Deleted.
(JSC::BytecodeGenerator::canOptimizeNonLocals): Deleted.
The heart of the changes in this patch are in the bytecode generator.
The bytecode generator now keeps a stack of tuples of
{symbol table, scope register, flag indicating catch or with scope, symbol table index in constant pool}
that models the runtime scope stack. This symbol table stack is used
in resolving local variables.

Also, the bytecode generator handles pushing and popping of lexical scopes.
This is relatively straight forward:
Captured 'let' variables end up in the JSLexicalEnvironment scope and non-captured
variables end up on the stack. Some trickiness is involved in generating
code for 'for' loops that have captured variables (I'm talking about variables in the loop
header, not the loop body). Each iteration of the for loop ends up with
its own JSLexicalEnvironment. Static code must be generated in such a way
to create this runtime behavior. This is done by emitting instructions to
push and pop a lexical scope at the end of each loop and copying values
from the previous loop's scope into the new scope. This code must also
ensure that each loop iteration's scope refers to the same underlying
SymbolTable so that no scope is accidentally mistaken as being a singleton scope.

When the debugger is enabled, all lexically defined variables will end up in the
JSLexicalEnvironment.

  • bytecompiler/NodesCodegen.cpp:

(JSC::ResolveNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::DeleteResolveNode::emitBytecode):
(JSC::TypeOfResolveNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::BlockNode::emitBytecode):
(JSC::ExprStatementNode::emitBytecode):
(JSC::DeclarationStatement::emitBytecode):
(JSC::EmptyVarExpression::emitBytecode):
(JSC::EmptyLetExpression::emitBytecode):
(JSC::ForNode::emitBytecode):
(JSC::ForInNode::emitMultiLoopBytecode):
(JSC::ForOfNode::emitBytecode):
(JSC::SwitchNode::emitBytecode):
(JSC::BindingNode::bindValue):
(JSC::VarStatementNode::emitBytecode): Deleted.

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::evaluate):

  • debugger/DebuggerScope.cpp:

(JSC::DebuggerScope::getOwnPropertySlot):
(JSC::DebuggerScope::put):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGNode.h:

(JSC::DFG::Node::castConstant):
(JSC::DFG::Node::initializationValueForActivation):
(JSC::DFG::Node::containsMovHint):

  • dfg/DFGObjectAllocationSinkingPhase.cpp:

CreateActivation nodes now have a second OpInfo that tracks the
initial value that needs to be placed in the activation. This initial value
is also used in allocation sinking to create proper bottom values for all
scope variables.

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCreateActivation):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • ftl/FTLIntrinsicRepository.h:
  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::DFG::LowerDFGToLLVM::compileCreateActivation):
(JSC::FTL::DFG::LowerDFGToLLVM::compileMaterializeCreateActivation):

  • ftl/FTLOperations.cpp:

(JSC::FTL::operationMaterializeObjectInOSR):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::execute):

  • jit/CCallHelpers.h:

(JSC::CCallHelpers::setupArgumentsWithExecState):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITInlines.h:

(JSC::JIT::callOperation):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_push_with_scope):
(JSC::JIT::compileOpStrictEq):
(JSC::JIT::emit_op_catch):
(JSC::JIT::emit_op_create_lexical_environment):
(JSC::JIT::emit_op_get_parent_scope):
(JSC::JIT::emit_op_switch_imm):
(JSC::JIT::emit_op_enter):
(JSC::JIT::emit_op_get_scope):
(JSC::JIT::emit_op_pop_scope): Deleted.

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_push_with_scope):
(JSC::JIT::emit_op_to_number):
(JSC::JIT::emit_op_catch):
(JSC::JIT::emit_op_create_lexical_environment):
(JSC::JIT::emit_op_get_parent_scope):
(JSC::JIT::emit_op_switch_imm):
(JSC::JIT::emit_op_enter):
(JSC::JIT::emit_op_get_scope):
(JSC::JIT::emit_op_pop_scope): Deleted.

  • jit/JITOperations.cpp:

(JSC::canAccessArgumentIndexQuickly):

  • jit/JITOperations.h:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createSourceElements):
(JSC::ASTBuilder::funcDeclarations):
(JSC::ASTBuilder::features):
(JSC::ASTBuilder::numConstants):
(JSC::ASTBuilder::createConditionalExpr):
(JSC::ASTBuilder::createAssignResolve):
(JSC::ASTBuilder::createClassDeclStatement):
(JSC::ASTBuilder::createBlockStatement):
(JSC::ASTBuilder::createIfStatement):
(JSC::ASTBuilder::createForLoop):
(JSC::ASTBuilder::createForInLoop):
(JSC::ASTBuilder::createForOfLoop):
(JSC::ASTBuilder::isBindingNode):
(JSC::ASTBuilder::createEmptyStatement):
(JSC::ASTBuilder::createDeclarationStatement):
(JSC::ASTBuilder::createVarStatement):
(JSC::ASTBuilder::createLetStatement):
(JSC::ASTBuilder::createEmptyVarExpression):
(JSC::ASTBuilder::createEmptyLetExpression):
(JSC::ASTBuilder::createReturnStatement):
(JSC::ASTBuilder::createTryStatement):
(JSC::ASTBuilder::createSwitchStatement):
(JSC::ASTBuilder::appendStatement):
(JSC::ASTBuilder::createCommaExpr):
(JSC::ASTBuilder::appendObjectPatternEntry):
(JSC::ASTBuilder::createBindingLocation):
(JSC::ASTBuilder::setEndOffset):
(JSC::ASTBuilder::Scope::Scope):
(JSC::ASTBuilder::makeAssignNode):
(JSC::ASTBuilder::varDeclarations): Deleted.
(JSC::ASTBuilder::addVar): Deleted.

  • parser/Keywords.table:
  • parser/NodeConstructors.h:

(JSC::ReadModifyResolveNode::ReadModifyResolveNode):
(JSC::AssignResolveNode::AssignResolveNode):
(JSC::ExprStatementNode::ExprStatementNode):
(JSC::DeclarationStatement::DeclarationStatement):
(JSC::EmptyVarExpression::EmptyVarExpression):
(JSC::EmptyLetExpression::EmptyLetExpression):
(JSC::IfElseNode::IfElseNode):
(JSC::WhileNode::WhileNode):
(JSC::ForNode::ForNode):
(JSC::CaseBlockNode::CaseBlockNode):
(JSC::SwitchNode::SwitchNode):
(JSC::ConstDeclNode::ConstDeclNode):
(JSC::BlockNode::BlockNode):
(JSC::EnumerationNode::EnumerationNode):
(JSC::ForInNode::ForInNode):
(JSC::ForOfNode::ForOfNode):
(JSC::ObjectPatternNode::create):
(JSC::BindingNode::create):
(JSC::BindingNode::BindingNode):
(JSC::VarStatementNode::VarStatementNode): Deleted.

  • parser/Nodes.cpp:

(JSC::ScopeNode::ScopeNode):
(JSC::ScopeNode::singleStatement):
(JSC::ProgramNode::ProgramNode):
(JSC::EvalNode::EvalNode):
(JSC::FunctionNode::FunctionNode):
(JSC::FunctionNode::finishParsing):
(JSC::VariableEnvironmentNode::VariableEnvironmentNode):

  • parser/Nodes.h:

(JSC::VariableEnvironmentNode::VariableEnvironmentNode):
(JSC::VariableEnvironmentNode::lexicalVariables):
(JSC::ScopeNode::usesThis):
(JSC::ScopeNode::needsActivationForMoreThanVariables):
(JSC::ScopeNode::needsActivation):
(JSC::ScopeNode::hasCapturedVariables):
(JSC::ScopeNode::captures):
(JSC::ScopeNode::varDeclarations):
(JSC::ScopeNode::functionStack):
(JSC::ScopeNode::neededConstants):
(JSC::ProgramNode::startColumn):
(JSC::ProgramNode::endColumn):
(JSC::EvalNode::startColumn):
(JSC::EvalNode::endColumn):
(JSC::BindingNode::boundProperty):
(JSC::BindingNode::divotStart):
(JSC::BindingNode::divotEnd):
(JSC::ScopeNode::capturedVariableCount): Deleted.
(JSC::ScopeNode::capturedVariables): Deleted.
(JSC::ScopeNode::varStack): Deleted.
There is a new class called 'VariableEnvironmentNode' that has the
necessary fields to model a lexical scope. Multiple AST nodes now
also inherit from VariableEnvironmentNode.

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::didFinishParsing):
(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseVariableDeclaration):
(JSC::Parser<LexerType>::parseWhileStatement):
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseConstDeclarationList):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseBreakStatement):
(JSC::Parser<LexerType>::parseContinueStatement):
(JSC::Parser<LexerType>::parseSwitchStatement):
(JSC::Parser<LexerType>::parseTryStatement):
(JSC::Parser<LexerType>::parseBlockStatement):
(JSC::Parser<LexerType>::parseStatement):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseClassDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseExpressionOrLabelStatement):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseVarDeclaration): Deleted.
(JSC::Parser<LexerType>::parseVarDeclarationList): Deleted.

  • parser/Parser.h:

(JSC::Scope::Scope):
(JSC::Scope::setIsFunction):
(JSC::Scope::isFunction):
(JSC::Scope::isFunctionBoundary):
(JSC::Scope::setIsLexicalScope):
(JSC::Scope::isLexicalScope):
(JSC::Scope::declaredVariables):
(JSC::Scope::finalizeLexicalEnvironment):
(JSC::Scope::computeLexicallyCapturedVariablesAndPurgeCandidates):
(JSC::Scope::declareCallee):
(JSC::Scope::declareVariable):
(JSC::Scope::declareLexicalVariable):
(JSC::Scope::hasDeclaredVariable):
(JSC::Scope::hasLexicallyDeclaredVariable):
(JSC::Scope::hasDeclaredParameter):
(JSC::Scope::declareWrite):
(JSC::Scope::preventAllVariableDeclarations):
(JSC::Scope::preventVarDeclarations):
(JSC::Scope::allowsVarDeclarations):
(JSC::Scope::allowsLexicalDeclarations):
(JSC::Scope::declareParameter):
(JSC::Scope::declareBoundParameter):
(JSC::Scope::useVariable):
(JSC::Scope::setNeedsFullActivation):
(JSC::Scope::needsFullActivation):
(JSC::Scope::hasDirectSuper):
(JSC::Scope::setNeedsSuperBinding):
(JSC::Scope::collectFreeVariables):
(JSC::Scope::getCapturedVars):
(JSC::Scope::copyCapturedVariablesToVector):
(JSC::Parser::AutoCleanupLexicalScope::AutoCleanupLexicalScope):
(JSC::Parser::AutoCleanupLexicalScope::~AutoCleanupLexicalScope):
(JSC::Parser::AutoCleanupLexicalScope::setIsValid):
(JSC::Parser::AutoCleanupLexicalScope::isValid):
(JSC::Parser::AutoCleanupLexicalScope::setPopped):
(JSC::Parser::AutoCleanupLexicalScope::scope):
(JSC::Parser::currentScope):
(JSC::Parser::pushScope):
(JSC::Parser::popScopeInternal):
(JSC::Parser::popScope):
(JSC::Parser::declareVariable):
(JSC::Parser::hasDeclaredVariable):
(JSC::Parser::hasDeclaredParameter):
(JSC::Parser::declareWrite):
(JSC::Parser::findCachedFunctionInfo):
(JSC::Parser::isFunctionBodyNode):
(JSC::Parser::continueIsValid):
(JSC::Parser::pushLabel):
(JSC::Parser::popLabel):
(JSC::Parser::getLabel):
(JSC::Parser::isLETMaskedAsIDENT):
(JSC::Parser<LexerType>::parse):
(JSC::Scope::preventNewDecls): Deleted.
(JSC::Scope::allowsNewDecls): Deleted.
(JSC::Scope::getCapturedVariables): Deleted.
There are basic parser changes that now allow for the 'let'
keyword. The trickiest change is how we will still treat 'let'
as an identifier for sloppy-mode code sometimes. For example,
"var let = ..." is allowed but "let let" or "const let" is not.

The most significant change to the parser made for this patch
is appropriating the Scope struct to also also model a lexical
scope. Changes were made in how we track captured variables to
account for this. In general, I think some of this code could
benefit from a slight refactoring to make things cleaner.

  • parser/ParserTokens.h:
  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createNewExpr):
(JSC::SyntaxChecker::createConditionalExpr):
(JSC::SyntaxChecker::createAssignResolve):
(JSC::SyntaxChecker::createEmptyVarExpression):
(JSC::SyntaxChecker::createEmptyLetExpression):
(JSC::SyntaxChecker::createClassExpr):
(JSC::SyntaxChecker::createClassDeclStatement):
(JSC::SyntaxChecker::createBlockStatement):
(JSC::SyntaxChecker::createExprStatement):
(JSC::SyntaxChecker::createIfStatement):
(JSC::SyntaxChecker::createForLoop):
(JSC::SyntaxChecker::createForInLoop):
(JSC::SyntaxChecker::createForOfLoop):
(JSC::SyntaxChecker::createEmptyStatement):
(JSC::SyntaxChecker::createVarStatement):
(JSC::SyntaxChecker::createLetStatement):
(JSC::SyntaxChecker::createReturnStatement):
(JSC::SyntaxChecker::createBreakStatement):
(JSC::SyntaxChecker::createContinueStatement):
(JSC::SyntaxChecker::createTryStatement):
(JSC::SyntaxChecker::createSwitchStatement):
(JSC::SyntaxChecker::createWhileStatement):
(JSC::SyntaxChecker::createWithStatement):
(JSC::SyntaxChecker::createDoWhileStatement):
(JSC::SyntaxChecker::createGetterOrSetterProperty):
(JSC::SyntaxChecker::appendStatement):
(JSC::SyntaxChecker::combineCommaNodes):
(JSC::SyntaxChecker::evalCount):
(JSC::SyntaxChecker::appendBinaryExpressionInfo):
(JSC::SyntaxChecker::operatorStackPop):
(JSC::SyntaxChecker::addVar): Deleted.

  • parser/VariableEnvironment.cpp: Added.

(JSC::VariableEnvironment::markVariableAsCapturedIfDefined):
(JSC::VariableEnvironment::markVariableAsCaptured):
(JSC::VariableEnvironment::markAllVariablesAsCaptured):
(JSC::VariableEnvironment::hasCapturedVariables):
(JSC::VariableEnvironment::captures):
(JSC::VariableEnvironment::swap):

  • parser/VariableEnvironment.h: Added.

(JSC::VariableEnvironmentEntry::isCaptured):
(JSC::VariableEnvironmentEntry::isConstant):
(JSC::VariableEnvironmentEntry::isVar):
(JSC::VariableEnvironmentEntry::isLet):
(JSC::VariableEnvironmentEntry::setIsCaptured):
(JSC::VariableEnvironmentEntry::setIsConstant):
(JSC::VariableEnvironmentEntry::setIsVar):
(JSC::VariableEnvironmentEntry::setIsLet):
(JSC::VariableEnvironmentEntry::clearIsVar):
(JSC::VariableEnvironment::begin):
(JSC::VariableEnvironment::end):
(JSC::VariableEnvironment::add):
(JSC::VariableEnvironment::size):
(JSC::VariableEnvironment::contains):
(JSC::VariableEnvironment::remove):
VariableEnvironment is a new class that keeps track
of the static environment in the parser and the bytecode generator.
VariableEnvironment behaves like SymbolTable but for the bytecode generator.
It keeps track of variable types, i.e, if a variable is a "var", "let", "const"
and whether or not its captured.

  • runtime/CodeCache.cpp:

(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):

  • runtime/CodeCache.h:

(JSC::CodeCache::clear):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.h:
  • runtime/ExceptionHelpers.cpp:

(JSC::createErrorForInvalidGlobalAssignment):
(JSC::createTDZError):
(JSC::throwOutOfMemoryError):

  • runtime/ExceptionHelpers.h:
  • runtime/Executable.cpp:

(JSC::EvalExecutable::create):
(JSC::ProgramExecutable::initializeGlobalProperties):

  • runtime/Executable.h:
  • runtime/JSCJSValue.h:

(JSC::jsUndefined):
(JSC::jsTDZValue):
(JSC::jsBoolean):

  • runtime/JSEnvironmentRecord.h:

(JSC::JSEnvironmentRecord::finishCreationUninitialized):
(JSC::JSEnvironmentRecord::finishCreation):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::createProgramCodeBlock):
(JSC::JSGlobalObject::createEvalCodeBlock):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::weakRandomInteger):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncEval):

  • runtime/JSLexicalEnvironment.cpp:

(JSC::JSLexicalEnvironment::symbolTableGet):

  • runtime/JSLexicalEnvironment.h:

(JSC::JSLexicalEnvironment::create):

  • runtime/JSScope.cpp:

(JSC::JSScope::resolve):
(JSC::JSScope::abstractResolve):
(JSC::JSScope::collectVariablesUnderTDZ):
(JSC::JSScope::isLexicalScope):
(JSC::resolveModeName):

  • runtime/JSScope.h:
  • runtime/PropertySlot.h:

(JSC::PropertySlot::setValue):

  • runtime/SymbolTable.cpp:

(JSC::SymbolTable::SymbolTable):
(JSC::SymbolTable::cloneScopePart):

  • runtime/SymbolTable.h:

SymbolTable now uses an extra bit to know if it corresponds
to a "let"-like environment or not.

  • runtime/WriteBarrier.h:

(JSC::WriteBarrierBase<Unknown>::get):
(JSC::WriteBarrierBase<Unknown>::clear):
(JSC::WriteBarrierBase<Unknown>::setUndefined):
(JSC::WriteBarrierBase<Unknown>::setStartingValue):
(JSC::WriteBarrierBase<Unknown>::isNumber):
(JSC::WriteBarrierBase<Unknown>::isObject):
(JSC::WriteBarrierBase<Unknown>::isNull):

  • tests/stress/activation-sink-default-value-tdz-error.js: Added.

(shouldThrowTDZ):
(bar):
(foo.cap):

  • tests/stress/activation-sink-osrexit-default-value-tdz-error.js: Added.

(shouldThrowTDZ):
(bar):

  • tests/stress/lexical-let-and-with-statement.js: Added.

(truth):
(assert):
(.):

  • tests/stress/lexical-let-exception-handling.js: Added.

(truth):
(assert):
(.):

  • tests/stress/lexical-let-global-not-captured-variables.js: Added.

(truth):
(assert):
(foo):
(.let.capY):

  • tests/stress/lexical-let-loop-semantics.js: Added.

(truth):
(assert):
(shouldThrowTDZ):
(.):

  • tests/stress/lexical-let-not-strict-mode.js: Added.

(truth):
(assert):
(shouldThrowTDZ):
(.):

  • tests/stress/lexical-let-semantics.js: Added.

(truth):
(assert):
(let.globalFunction):
(let.retGlobalNumberCaptured):
(let.setGlobalNumberCaptured):
(.):

  • tests/stress/lexical-let-tdz.js: Added.

(truth):
(assert):
(shouldThrowTDZ):
(.):

LayoutTests:

  • js/dom/reserved-words-as-property-expected.txt:
  • js/keywords-and-reserved_words-expected.txt:
  • js/let-syntax-expected.txt: Added.
  • js/let-syntax.html: Added.
  • js/reserved-words-strict-expected.txt:
  • js/script-tests/keywords-and-reserved_words.js:
  • js/script-tests/let-syntax.js: Added.

(truth):
(assert):
(hasSyntaxError):
(shouldHaveSyntaxError):
(shouldNotHaveSyntaxError):
(shouldHaveSyntaxErrorStrictOnly):

  • js/script-tests/reserved-words-strict.js:
  • js/script-tests/statement-list-item-syntax-errors.js:

(testSyntax):
(runTests):

  • js/statement-list-item-syntax-errors-expected.txt:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r186379 r186860  
    3737#include "SourceProviderCache.h"
    3838#include "SourceProviderCacheItem.h"
     39#include "VariableEnvironment.h"
    3940#include <wtf/Forward.h>
    4041#include <wtf/Noncopyable.h>
     
    9899enum DestructuringKind {
    99100    DestructureToVariables,
     101    DestructureToLexicalVariables,
    100102    DestructureToParameters,
    101103    DestructureToExpressions
     
    118120        , m_hasDirectSuper(false)
    119121        , m_needsSuperBinding(false)
    120         , m_allowsNewDecls(true)
     122        , m_allowsVarDeclarations(true)
     123        , m_allowsLexicalDeclarations(true)
    121124        , m_strictMode(strictMode)
    122125        , m_isFunction(isFunction)
     126        , m_isLexicalScope(false)
    123127        , m_isFunctionBoundary(false)
    124128        , m_isValidStrictMode(true)
     
    135139        , m_hasDirectSuper(rhs.m_hasDirectSuper)
    136140        , m_needsSuperBinding(rhs.m_needsSuperBinding)
    137         , m_allowsNewDecls(rhs.m_allowsNewDecls)
     141        , m_allowsVarDeclarations(rhs.m_allowsVarDeclarations)
     142        , m_allowsLexicalDeclarations(rhs.m_allowsLexicalDeclarations)
    138143        , m_strictMode(rhs.m_strictMode)
    139144        , m_isFunction(rhs.m_isFunction)
     145        , m_isLexicalScope(rhs.m_isLexicalScope)
    140146        , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
    141147        , m_isValidStrictMode(rhs.m_isValidStrictMode)
     
    190196        m_isFunction = true;
    191197        m_isFunctionBoundary = true;
    192     }
    193     bool isFunction() { return m_isFunction; }
    194     bool isFunctionBoundary() { return m_isFunctionBoundary; }
     198        setIsLexicalScope();
     199    }
     200
     201    bool isFunction() const { return m_isFunction; }
     202    bool isFunctionBoundary() const { return m_isFunctionBoundary; }
     203
     204    void setIsLexicalScope()
     205    {
     206        m_isLexicalScope = true;
     207        m_allowsLexicalDeclarations = true;
     208    }
     209    bool isLexicalScope() { return m_isLexicalScope; }
     210
     211    VariableEnvironment& declaredVariables() { return m_declaredVariables; }
     212    VariableEnvironment& finalizeLexicalEnvironment()
     213    {
     214        if (m_usesEval || m_needsFullActivation)
     215            m_lexicalVariables.markAllVariablesAsCaptured();
     216        else
     217            computeLexicallyCapturedVariablesAndPurgeCandidates();
     218
     219        return m_lexicalVariables;
     220    }
     221
     222    void computeLexicallyCapturedVariablesAndPurgeCandidates()
     223    {
     224        // Because variables may be defined at any time in the range of a lexical scope, we must
     225        // track lexical variables that might be captured. Then, when we're preparing to pop the top
     226        // lexical scope off the stack, we should find which variables are truly captured, and which
     227        // variable still may be captured in a parent scope.
     228        if (m_lexicalVariables.size() && m_closedVariableCandidates.size()) {
     229            auto end = m_closedVariableCandidates.end();
     230            for (auto iter = m_closedVariableCandidates.begin(); iter != end; ++iter)
     231                m_lexicalVariables.markVariableAsCapturedIfDefined(iter->get());
     232        }
     233
     234        // We can now purge values from the captured candidates because they're captured in this scope.
     235        {
     236            for (auto entry : m_lexicalVariables) {
     237                if (entry.value.isCaptured())
     238                    m_closedVariableCandidates.remove(entry.key);
     239            }
     240        }
     241    }
    195242
    196243    void declareCallee(const Identifier* ident)
    197244    {
    198         m_declaredVariables.add(ident->impl());
    199     }
    200 
    201     bool declareVariable(const Identifier* ident)
    202     {
     245        auto addResult = m_declaredVariables.add(ident->impl());
     246        // We want to track if callee is captured, but we don't want to act like it's a 'var'
     247        // because that would cause the BytecodeGenerator to emit bad code.
     248        addResult.iterator->value.clearIsVar();
     249    }
     250
     251    bool declareVariable(const Identifier* ident, bool isConstant = false)
     252    {
     253        ASSERT(m_allowsVarDeclarations);
    203254        bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident;
    204255        m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
    205         m_declaredVariables.add(ident->impl());
     256        auto addResult = m_declaredVariables.add(ident->impl());
     257        addResult.iterator->value.setIsVar();
     258        if (isConstant)
     259            addResult.iterator->value.setIsConstant();
     260
    206261        return isValidStrictMode;
    207262    }
    208263
     264    bool declareLexicalVariable(const Identifier* ident)
     265    {
     266        ASSERT(m_allowsLexicalDeclarations);
     267        bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident;
     268        m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
     269        auto addResult = m_lexicalVariables.add(ident->impl());
     270        addResult.iterator->value.setIsLet();
     271        bool successfulDeclaration = addResult.isNewEntry && isValidStrictMode;
     272        return successfulDeclaration;
     273    }
     274
    209275    bool hasDeclaredVariable(const Identifier& ident)
    210276    {
    211         return m_declaredVariables.contains(ident.impl());
    212     }
    213    
    214     bool hasDeclaredParameter(const Identifier& ident)
    215     {
    216         return m_declaredParameters.contains(ident.impl()) || m_declaredVariables.contains(ident.impl());
     277        return hasDeclaredVariable(ident.impl());
     278    }
     279
     280    bool hasDeclaredVariable(const RefPtr<UniquedStringImpl>& ident)
     281    {
     282        return m_declaredVariables.contains(ident.get());
     283    }
     284
     285    bool hasLexicallyDeclaredVariable(const RefPtr<UniquedStringImpl>& ident) const
     286    {
     287        return m_lexicalVariables.contains(ident.get());
     288    }
     289   
     290    ALWAYS_INLINE bool hasDeclaredParameter(const Identifier& ident)
     291    {
     292        return hasDeclaredParameter(ident.impl());
     293    }
     294
     295    bool hasDeclaredParameter(const RefPtr<UniquedStringImpl>& ident)
     296    {
     297        return m_declaredParameters.contains(ident) || m_declaredVariables.contains(ident.get());
    217298    }
    218299   
     
    223304    }
    224305
    225     void preventNewDecls() { m_allowsNewDecls = false; }
    226     bool allowsNewDecls() const { return m_allowsNewDecls; }
     306    void preventAllVariableDeclarations()
     307    {
     308        m_allowsVarDeclarations = false;
     309        m_allowsLexicalDeclarations = false;
     310    }
     311    void preventVarDeclarations() { m_allowsVarDeclarations = false; }
     312    bool allowsVarDeclarations() const { return m_allowsVarDeclarations; }
     313    bool allowsLexicalDeclarations() const { return m_allowsLexicalDeclarations; }
    227314
    228315    bool declareParameter(const Identifier* ident)
    229316    {
     317        ASSERT(m_allowsVarDeclarations);
    230318        bool isArguments = m_vm->propertyNames->arguments == *ident;
    231         bool isValidStrictMode = m_declaredVariables.add(ident->impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
     319        auto addResult = m_declaredVariables.add(ident->impl());
     320        addResult.iterator->value.clearIsVar();
     321        bool isValidStrictMode = addResult.isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
    232322        m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
    233323        m_declaredParameters.add(ident->impl());
     
    246336    {
    247337        bool isArguments = m_vm->propertyNames->arguments == *ident;
    248         bool newEntry = m_declaredVariables.add(ident->impl()).isNewEntry;
    249         bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments;
     338        auto addResult = m_declaredVariables.add(ident->impl());
     339        addResult.iterator->value.setIsVar(); // Treat destructuring parameters as "var"s.
     340        bool isValidStrictMode = addResult.isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
    250341        m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
    251342   
    252343        if (isArguments)
    253344            m_shadowsArguments = true;
    254         if (!newEntry)
     345        if (!addResult.isNewEntry)
    255346            return BindingFailed;
    256347        return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;
     
    269360
    270361    void setNeedsFullActivation() { m_needsFullActivation = true; }
     362    bool needsFullActivation() const { return m_needsFullActivation; }
    271363
    272364#if ENABLE(ES6_CLASS_SYNTAX)
     
    284376    void setNeedsSuperBinding() { m_needsSuperBinding = true; }
    285377
    286     bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
     378    void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
    287379    {
    288380        if (nestedScope->m_usesEval)
    289381            m_usesEval = true;
    290         IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
    291         for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
    292             if (nestedScope->m_declaredVariables.contains(*ptr))
    293                 continue;
    294             m_usedVariables.add(*ptr);
    295             if (shouldTrackClosedVariables)
    296                 m_closedVariables.add(*ptr);
    297         }
     382
     383        {
     384            IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
     385            for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
     386                if (nestedScope->m_declaredVariables.contains(*ptr) || nestedScope->m_lexicalVariables.contains(*ptr))
     387                    continue;
     388                m_usedVariables.add(*ptr);
     389                // We don't want a declared variable that is used in an inner scope to be thought of as captured if
     390                // that inner scope is both a lexical scope and not a function. Only inner functions and "catch"
     391                // statements can cause variables to be captured.
     392                if (shouldTrackClosedVariables && (nestedScope->m_isFunctionBoundary || !nestedScope->m_isLexicalScope))
     393                    m_closedVariableCandidates.add(*ptr);
     394            }
     395        }
     396        // Propagate closed variable candidates downwards within the same function.
     397        // Cross function captures will be realized via m_usedVariables propagation.
     398        if (shouldTrackClosedVariables && !nestedScope->m_isFunctionBoundary && nestedScope->m_closedVariableCandidates.size()) {
     399            IdentifierSet::iterator end = nestedScope->m_closedVariableCandidates.end();
     400            IdentifierSet::iterator begin = nestedScope->m_closedVariableCandidates.begin();
     401            m_closedVariableCandidates.add(begin, end);
     402        }
     403
    298404        if (nestedScope->m_writtenVariables.size()) {
    299405            IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
    300406            for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
    301                 if (nestedScope->m_declaredVariables.contains(*ptr))
     407                if (nestedScope->m_declaredVariables.contains(*ptr) || nestedScope->m_lexicalVariables.contains(*ptr))
    302408                    continue;
    303409                m_writtenVariables.add(*ptr);
    304410            }
    305411        }
    306 
    307         return true;
    308     }
    309 
    310     void getCapturedVariables(IdentifierSet& capturedVariables, bool& modifiedParameter, bool& modifiedArguments)
     412    }
     413   
     414    void getCapturedVars(IdentifierSet& capturedVariables, bool& modifiedParameter, bool& modifiedArguments)
    311415    {
    312416        if (m_needsFullActivation || m_usesEval) {
    313417            modifiedParameter = true;
    314             capturedVariables = m_declaredVariables;
     418            for (auto& entry : m_declaredVariables)
     419                capturedVariables.add(entry.key);
    315420            return;
    316421        }
    317         for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
     422        for (IdentifierSet::iterator ptr = m_closedVariableCandidates.begin(); ptr != m_closedVariableCandidates.end(); ++ptr) {
    318423            if (!m_declaredVariables.contains(*ptr))
    319424                continue;
     
    344449        IdentifierSet::iterator end = capturedVariables.end();
    345450        for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
    346             if (m_declaredVariables.contains(*it))
     451            if (m_declaredVariables.contains(*it) || m_lexicalVariables.contains(*it))
    347452                continue;
    348453            vector.append(*it);
     
    379484    bool m_hasDirectSuper : 1;
    380485    bool m_needsSuperBinding : 1;
    381     bool m_allowsNewDecls : 1;
     486    bool m_allowsVarDeclarations : 1;
     487    bool m_allowsLexicalDeclarations : 1;
    382488    bool m_strictMode : 1;
    383489    bool m_isFunction : 1;
     490    bool m_isLexicalScope : 1;
    384491    bool m_isFunctionBoundary : 1;
    385492    bool m_isValidStrictMode : 1;
     
    390497    std::unique_ptr<LabelStack> m_labels;
    391498    IdentifierSet m_declaredParameters;
    392     IdentifierSet m_declaredVariables;
     499    VariableEnvironment m_declaredVariables;
     500    VariableEnvironment m_lexicalVariables;
    393501    IdentifierSet m_usedVariables;
    394     IdentifierSet m_closedVariables;
     502    IdentifierSet m_closedVariableCandidates;
    395503    IdentifierSet m_writtenVariables;
    396504};
     
    480588    };
    481589
     590    struct AutoCleanupLexicalScope {
     591        // We can allocate this object on the stack without actually knowing beforehand if we're
     592        // going to create a new lexical scope. If we decide to create a new lexical scope, we
     593        // can pass the scope into this obejct and it will take care of the cleanup for us if the parse fails.
     594        // This is helpful if we may fail from syntax errors after creating a lexical scope conditionally.
     595        AutoCleanupLexicalScope()
     596            : m_scope(nullptr, UINT_MAX)
     597            , m_parser(nullptr)
     598        {
     599        }
     600
     601        ~AutoCleanupLexicalScope()
     602        {
     603            // This should only ever be called if we fail from a syntax error. Otherwise
     604            // it's the intention that a user of this class pops this scope manually on a
     605            // successful parse.
     606            if (isValid())
     607                m_parser->popScope(*this, false);
     608        }
     609
     610        void setIsValid(ScopeRef& scope, Parser* parser)
     611        {
     612            RELEASE_ASSERT(scope->isLexicalScope());
     613            m_scope = scope;
     614            m_parser = parser;
     615        }
     616
     617        bool isValid() const { return !!m_parser; }
     618
     619        void setPopped()
     620        {
     621            m_parser = nullptr;
     622        }
     623
     624        ScopeRef& scope() { return m_scope; }
     625
     626    private:
     627        ScopeRef m_scope;
     628        Parser* m_parser;
     629    };
     630
    482631    ScopeRef currentScope()
    483632    {
     
    497646    }
    498647   
    499     bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
     648    void popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
    500649    {
    501650        ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
    502651        ASSERT(m_scopeStack.size() > 1);
    503         bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
     652        m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
     653        if (!m_scopeStack.last().isFunctionBoundary() && m_scopeStack.last().needsFullActivation())
     654            m_scopeStack[m_scopeStack.size() - 2].setNeedsFullActivation();
    504655        m_scopeStack.removeLast();
    505         return result;
    506     }
    507    
    508     bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
    509     {
    510         return popScopeInternal(scope, shouldTrackClosedVariables);
    511     }
    512    
    513     bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
     656    }
     657   
     658    ALWAYS_INLINE void popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
     659    {
     660        popScopeInternal(scope, shouldTrackClosedVariables);
     661    }
     662   
     663    ALWAYS_INLINE void popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
    514664    {
    515665        scope.setPopped();
    516         return popScopeInternal(scope, shouldTrackClosedVariables);
    517     }
    518    
    519     bool declareVariable(const Identifier* ident)
     666        popScopeInternal(scope, shouldTrackClosedVariables);
     667    }
     668
     669    ALWAYS_INLINE void popScope(AutoCleanupLexicalScope& cleanupScope, bool shouldTrackClosedVariables)
     670    {
     671        RELEASE_ASSERT(cleanupScope.isValid());
     672        ScopeRef& scope = cleanupScope.scope();
     673        cleanupScope.setPopped();
     674        popScopeInternal(scope, shouldTrackClosedVariables);
     675    }
     676   
     677    enum class DeclarationType { VarDeclaration, LexicalDeclaration };
     678    bool declareVariable(const Identifier* ident, typename Parser::DeclarationType type = DeclarationType::VarDeclaration, bool isConstant = false)
    520679    {
    521680        unsigned i = m_scopeStack.size() - 1;
    522681        ASSERT(i < m_scopeStack.size());
    523         while (!m_scopeStack[i].allowsNewDecls()) {
     682
     683        if (type == DeclarationType::VarDeclaration) {
     684            while (!m_scopeStack[i].allowsVarDeclarations()) {
     685                i--;
     686                ASSERT(i < m_scopeStack.size());
     687            }
     688
     689            return m_scopeStack[i].declareVariable(ident, isConstant);
     690        }
     691
     692        ASSERT(type == DeclarationType::LexicalDeclaration);
     693
     694        // Lexical variables declared at a top level scope that shadow arguments or vars are not allowed.
     695        if (m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident)))
     696            return false;
     697
     698        while (!m_scopeStack[i].allowsLexicalDeclarations()) {
    524699            i--;
    525700            ASSERT(i < m_scopeStack.size());
    526701        }
    527         return m_scopeStack[i].declareVariable(ident);
     702
     703        return m_scopeStack[i].declareLexicalVariable(ident);
    528704    }
    529705   
     
    532708        unsigned i = m_scopeStack.size() - 1;
    533709        ASSERT(i < m_scopeStack.size());
    534         while (!m_scopeStack[i].allowsNewDecls()) {
     710        while (!m_scopeStack[i].allowsVarDeclarations()) {
    535711            i--;
    536712            ASSERT(i < m_scopeStack.size());
     
    538714        return m_scopeStack[i].hasDeclaredVariable(ident);
    539715    }
    540    
     716
    541717    NEVER_INLINE bool hasDeclaredParameter(const Identifier& ident)
    542718    {
    543719        unsigned i = m_scopeStack.size() - 1;
    544720        ASSERT(i < m_scopeStack.size());
    545         while (!m_scopeStack[i].allowsNewDecls()) {
     721        while (!m_scopeStack[i].allowsVarDeclarations()) {
    546722            i--;
    547723            ASSERT(i < m_scopeStack.size());
     
    555731            m_scopeStack.last().declareWrite(ident);
    556732    }
    557    
     733
    558734    ScopeStack m_scopeStack;
    559735   
     
    566742    String parseInner();
    567743
    568     void didFinishParsing(SourceElements*, DeclarationStacks::VarStack&,
    569         DeclarationStacks::FunctionStack&, CodeFeatures, int, IdentifierSet&, const Vector<RefPtr<UniquedStringImpl>>&&);
     744    void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&, VariableEnvironment&, CodeFeatures, int, const Vector<RefPtr<UniquedStringImpl>>&&);
    570745
    571746    // Used to determine type of error to report.
     
    754929    }
    755930    void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
    756     void popLabel() { currentScope()->popLabel(); }
     931    void popLabel(ScopeRef scope) { scope->popLabel(); }
    757932    ScopeLabelInfo* getLabel(const Identifier* label)
    758933    {
     
    765940        }
    766941        return result;
     942    }
     943
     944    ALWAYS_INLINE bool isLETMaskedAsIDENT()
     945    {
     946        return match(LET) && !strictMode();
    767947    }
    768948
     
    774954#endif
    775955    template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
    776     template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
     956    template <class TreeBuilder> TreeStatement parseVariableDeclaration(TreeBuilder&, DeclarationType);
    777957    template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
    778958    template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
     
    811991    template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
    812992    enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
    813     template <class TreeBuilder> TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext);
     993    template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType);
    814994    template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
    815995
     
    819999#endif
    8201000
    821     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken);
    822     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, int depth = 0);
    823     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&);
     1001    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken, AssignmentContext);
     1002    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, AssignmentContext = AssignmentContext::DeclarationStatement, int depth = 0);
     1003    template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&, AssignmentContext);
    8241004    template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&);
    8251005
     
    9471127    ConstructorKind m_defaultConstructorKind;
    9481128    ThisTDZMode m_thisTDZMode;
    949     DeclarationStacks::VarStack m_varDeclarations;
     1129    VariableEnvironment m_varDeclarations;
    9501130    DeclarationStacks::FunctionStack m_funcDeclarations;
    951     IdentifierSet m_capturedVariables;
    9521131    Vector<RefPtr<UniquedStringImpl>> m_closedVariables;
    9531132    CodeFeatures m_features;
     
    10211200                                    m_varDeclarations,
    10221201                                    m_funcDeclarations,
    1023                                     m_capturedVariables,
     1202                                    currentScope()->finalizeLexicalEnvironment(),
    10241203                                    *m_source,
    10251204                                    m_features,
Note: See TracChangeset for help on using the changeset viewer.