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.cpp

    r186379 r186860  
    265265        m_statementDepth--;
    266266    ScopeRef scope = currentScope();
     267    scope->setIsLexicalScope();
     268
    267269    SourceElements* sourceElements = parseSourceElements(context, CheckForStrictMode, StandardFunctionParseType);
    268270    if (!sourceElements || !consume(EOFTOK)) {
     
    276278    bool modifiedParameter = false;
    277279    bool modifiedArguments = false;
    278     scope->getCapturedVariables(capturedVariables, modifiedParameter, modifiedArguments);
     280    scope->getCapturedVars(capturedVariables, modifiedParameter, modifiedArguments);
     281    VariableEnvironment& varDeclarations = scope->declaredVariables();
     282    for (auto& entry : capturedVariables)
     283        varDeclarations.markVariableAsCaptured(entry);
    279284   
    280285    CodeFeatures features = context.features();
     
    291296        IdentifierSet usedVariables;
    292297        scope->getUsedVariables(usedVariables);
     298        // FIXME: This needs to be changed if we want to allow builtins to use lexical declarations.
    293299        for (const auto& variable : usedVariables) {
    294300            Identifier identifier = Identifier::fromUid(m_vm, variable.get());
     
    307313        if (!capturedVariables.isEmpty()) {
    308314            for (const auto& capturedVariable : capturedVariables) {
    309                 Identifier identifier = Identifier::fromUid(m_vm, capturedVariable.get());
    310                 if (scope->hasDeclaredVariable(identifier))
     315                if (scope->hasDeclaredVariable(capturedVariable))
    311316                    continue;
    312317
    313                 if (scope->hasDeclaredParameter(identifier))
     318                if (scope->hasDeclaredParameter(capturedVariable))
    314319                    continue;
    315320
     
    318323        }
    319324    }
    320     didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
    321         context.numConstants(), capturedVariables, WTF::move(closedVariables));
     325    didFinishParsing(sourceElements, context.funcDeclarations(), varDeclarations, features, context.numConstants(), WTF::move(closedVariables));
    322326
    323327    return parseError;
     
    325329
    326330template <typename LexerType>
    327 void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::VarStack& varStack,
    328     DeclarationStacks::FunctionStack& funcStack, CodeFeatures features, int numConstants, IdentifierSet& capturedVars, const Vector<RefPtr<UniquedStringImpl>>&& closedVariables)
     331void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::FunctionStack& funcStack,
     332    VariableEnvironment& varDeclarations, CodeFeatures features, int numConstants, const Vector<RefPtr<UniquedStringImpl>>&& closedVariables)
    329333{
    330334    m_sourceElements = sourceElements;
    331     m_varDeclarations.swap(varStack);
    332335    m_funcDeclarations.swap(funcStack);
    333     m_capturedVariables.swap(capturedVars);
     336    m_varDeclarations.swap(varDeclarations);
    334337    m_closedVariables = closedVariables;
    335338    m_features = features;
     
    408411    // The grammar is documented here:
    409412    // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-statements
     413    DepthManager statementDepth(&m_statementDepth);
     414    m_statementDepth++;
    410415    TreeStatement result = 0;
     416    bool shouldSetEndOffset = true;
    411417    switch (m_token.m_type) {
    412418    case CONSTTOKEN:
    413419        result = parseConstDeclaration(context);
    414420        break;
     421    case LET: {
     422        bool shouldParseVariableDeclaration = true;
     423        if (!strictMode()) {
     424            SavePoint savePoint = createSavePoint();
     425            next();
     426            if (!match(IDENT) && !match(OPENBRACE) && !match(OPENBRACKET))
     427                shouldParseVariableDeclaration = false;
     428            restoreSavePoint(savePoint);
     429        }
     430        if (shouldParseVariableDeclaration)
     431            result = parseVariableDeclaration(context, DeclarationType::LexicalDeclaration);
     432        else
     433            result = parseExpressionOrLabelStatement(context); // Treat this as an IDENT. This is how ::parseStatement() handles IDENT.
     434
     435        break;
     436    }
    415437#if ENABLE(ES6_CLASS_SYNTAX)
    416438    case CLASSTOKEN:
     
    419441#endif
    420442    default:
    421         // FIXME: This needs to consider 'let' in bug:
    422         // https://bugs.webkit.org/show_bug.cgi?id=142944
     443        m_statementDepth--; // parseStatement() increments the depth.
    423444        result = parseStatement(context, directive, directiveLiteralLength);
    424         break;
    425     }
     445        shouldSetEndOffset = false;
     446        break;
     447    }
     448
     449    if (result && shouldSetEndOffset)
     450        context.setEndOffset(result, m_lastTokenEndPosition.offset);
    426451
    427452    return result;
     
    429454
    430455template <typename LexerType>
    431 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVarDeclaration(TreeBuilder& context)
    432 {
    433     ASSERT(match(VAR));
     456template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDeclaration(TreeBuilder& context, DeclarationType declarationType)
     457{
     458    ASSERT(match(VAR) || match(LET));
    434459    JSTokenLocation location(tokenLocation());
    435460    int start = tokenLine();
     
    439464    TreeExpression scratch2 = 0;
    440465    JSTextPosition scratch3;
    441     TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext);
     466    TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType);
    442467    propagateError();
    443468    failIfFalse(autoSemiColon(), "Expected ';' after var declaration");
    444469   
    445     return context.createVarStatement(location, varDecls, start, end);
     470    if (declarationType == DeclarationType::VarDeclaration)
     471        return context.createVarStatement(location, variableDecls, start, end);
     472    ASSERT(declarationType == DeclarationType::LexicalDeclaration);
     473    return context.createLetStatement(location, variableDecls, start, end);
    446474}
    447475
     
    508536
    509537template <typename LexerType>
    510 template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext)
    511 {
     538template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext, DeclarationType declarationType)
     539{
     540    ASSERT(declarationType == DeclarationType::LexicalDeclaration || declarationType == DeclarationType::VarDeclaration);
    512541    TreeExpression head = 0;
    513542    TreeExpression tail = 0;
     
    522551        declarations++;
    523552        bool hasInitializer = false;
    524         if (match(IDENT)) {
     553        if (match(IDENT) || isLETMaskedAsIDENT()) {
     554            failIfTrue(isLETMaskedAsIDENT() && declarationType == DeclarationType::LexicalDeclaration, "Can't use 'let' as an identifier name for a LexicalDeclaration");
    525555            JSTextPosition varStart = tokenStartPosition();
    526556            JSTokenLocation varStartLocation(tokenLocation());
     
    531561            next();
    532562            hasInitializer = match(EQUAL);
    533             failIfFalseIfStrict(declareVariable(name), "Cannot declare a variable named ", name->impl(), " in strict mode");
    534             context.addVar(name, (hasInitializer || (!m_allowsIn && (match(INTOKEN) || isofToken()))) ? DeclarationStacks::HasInitializer : 0);
     563            if (!declareVariable(name, declarationType)) {
     564                if (declarationType == DeclarationType::LexicalDeclaration)
     565                    internalFailWithMessage(false, "Cannot declare a lexical variable twice: '", name->impl(), "'");
     566                else if (strictMode())
     567                    internalFailWithMessage(false, "Cannot declare a variable named ", name->impl(), " in strict mode");
     568            }
    535569            if (hasInitializer) {
    536570                JSTextPosition varDivot = tokenStartPosition() + 1;
     
    542576                failIfFalse(initializer, "Expected expression as the intializer for the variable '", name->impl(), "'");
    543577               
    544                 node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition());
    545             } else
    546                 node = context.createEmptyVarExpression(varStartLocation, *name);
     578                node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition(), AssignmentContext::DeclarationStatement);
     579            } else {
     580                if (declarationType == DeclarationType::VarDeclaration)
     581                    node = context.createEmptyVarExpression(varStartLocation, *name);
     582                else
     583                    node = context.createEmptyLetExpression(varStartLocation, *name);
     584            }
    547585        } else {
    548586            lastIdent = 0;
    549             auto pattern = parseDestructuringPattern(context, DestructureToVariables);
     587            auto pattern = parseDestructuringPattern(context, declarationType == DeclarationType::VarDeclaration ? DestructureToVariables : DestructureToLexicalVariables, AssignmentContext::DeclarationStatement);
    550588            failIfFalse(pattern, "Cannot parse this destructuring pattern");
    551589            hasInitializer = match(EQUAL);
     
    569607    } while (match(COMMA));
    570608    if (lastIdent)
    571         lastPattern = createBindingPattern(context, DestructureToVariables, *lastIdent, 0, lastIdentToken);
     609        lastPattern = context.createBindingLocation(lastIdentToken.m_location, *lastIdent, lastIdentToken.m_startPosition, lastIdentToken.m_endPosition, AssignmentContext::DeclarationStatement);
     610
    572611    return head;
    573612}
    574613
    575614template <typename LexerType>
    576 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token)
     615template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext)
    577616{
    578617    ASSERT(!name.isNull());
     
    581620    if (depth) {
    582621        if (kind == DestructureToVariables)
    583             failIfFalseIfStrict(declareVariable(&name), "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
    584         if (kind == DestructureToParameters) {
     622            failIfFalseIfStrict(declareVariable(&name), "Cannot deconstruct to a variable named '", name.impl(), "' in strict mode");
     623        else if (kind == DestructureToLexicalVariables)
     624            semanticFailIfFalse(declareVariable(&name, DeclarationType::LexicalDeclaration), "Cannot declare a lexical variable twice: '", name.impl(), "'");
     625        else if (kind == DestructureToParameters) {
    585626            auto bindingResult = declareBoundParameter(&name);
    586627            if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
     
    600641            }
    601642        }
    602         if (kind != DestructureToExpressions)
    603             context.addVar(&name, DeclarationStacks::HasInitializer);
    604643
    605644    } else {
    606         if (kind == DestructureToVariables) {
     645        if (kind == DestructureToVariables)
    607646            failIfFalseIfStrict(declareVariable(&name), "Cannot declare a variable named '", name.impl(), "' in strict mode");
    608             context.addVar(&name, DeclarationStacks::HasInitializer);
    609         }
    610        
    611         if (kind == DestructureToParameters) {
     647        else if (kind == DestructureToLexicalVariables)
     648            semanticFailIfFalse(declareVariable(&name, DeclarationType::LexicalDeclaration), "Cannot declare a lexical variable twice: '", name.impl(), "'");
     649        else if (kind == DestructureToParameters) {
    612650            bool declarationResult = declareParameter(&name);
    613651            if (!declarationResult && strictMode()) {
     
    622660        }
    623661    }
    624     return context.createBindingLocation(token.m_location, name, token.m_startPosition, token.m_endPosition);
     662    return context.createBindingLocation(token.m_location, name, token.m_startPosition, token.m_endPosition, bindingContext);
    625663}
    626664
     
    662700
    663701template <typename LexerType>
    664 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context)
    665 {
    666     return parseDestructuringPattern(context, DestructureToExpressions);
    667 }
    668 
    669 template <typename LexerType>
    670 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, int depth)
     702template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context, AssignmentContext bindingContext)
     703{
     704    return parseDestructuringPattern(context, DestructureToExpressions, bindingContext);
     705}
     706
     707template <typename LexerType>
     708template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, AssignmentContext bindingContext, int depth)
    671709{
    672710    failIfStackOverflow();
     
    694732                JSTokenLocation location = m_token.m_location;
    695733                next();
    696                 auto innerPattern = parseDestructuringPattern(context, kind, depth + 1);
     734                auto innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
    697735                if (kind == DestructureToExpressions && !innerPattern)
    698736                    return 0;
     
    707745
    708746            JSTokenLocation location = m_token.m_location;
    709             auto innerPattern = parseDestructuringPattern(context, kind, depth + 1);
     747            auto innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
    710748            if (kind == DestructureToExpressions && !innerPattern)
    711749                return 0;
     
    736774            TreeDestructuringPattern innerPattern = 0;
    737775            JSTokenLocation location = m_token.m_location;
    738             if (match(IDENT)) {
     776            if (match(IDENT) || isLETMaskedAsIDENT()) {
     777                failIfTrue(isLETMaskedAsIDENT() && kind == DestructureToLexicalVariables, "Can't use 'let' as an identifier name for a LexicalDeclaration");
    739778                propertyName = *m_token.m_data.ident;
    740779                JSToken identifierToken = m_token;
    741780                next();
    742781                if (consume(COLON))
    743                     innerPattern = parseDestructuringPattern(context, kind, depth + 1);
     782                    innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
    744783                else
    745                     innerPattern = createBindingPattern(context, kind, propertyName, depth, identifierToken);
     784                    innerPattern = createBindingPattern(context, kind, propertyName, depth, identifierToken, bindingContext);
    746785            } else {
    747786                JSTokenType tokenType = m_token.m_type;
     
    774813                    failWithMessage("Expected a ':' prior to a named destructuring property");
    775814                }
    776                 innerPattern = parseDestructuringPattern(context, kind, depth + 1);
     815                innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
    777816            }
    778817            if (kind == DestructureToExpressions && !innerPattern)
     
    792831
    793832    default: {
    794         if (!match(IDENT)) {
     833        if (!match(IDENT) && !isLETMaskedAsIDENT()) {
    795834            if (kind == DestructureToExpressions)
    796835                return 0;
     
    798837            failWithMessage("Expected a parameter pattern or a ')' in parameter list");
    799838        }
    800         pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token);
     839        failIfTrue(isLETMaskedAsIDENT() && kind == DestructureToLexicalVariables, "Can't use 'let' as an identifier name for a LexicalDeclaration");
     840        pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext);
    801841        next();
    802842        break;
     
    826866        JSTokenLocation location(tokenLocation());
    827867        next();
    828         matchOrFail(IDENT, "Expected an identifier name in const declaration");
     868        failIfFalse(match(IDENT), "Expected an identifier name in const declaration");
    829869        const Identifier* name = m_token.m_data.ident;
    830870        next();
    831871        bool hasInitializer = match(EQUAL);
    832         declareVariable(name);
    833         context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
    834 
     872        // FIXME: This should be LexicalVariable when we support proper ES6 const semantics.
     873        declareVariable(name, DeclarationType::VarDeclaration, true);
    835874        TreeExpression initializer = 0;
    836875        if (hasInitializer) {
     
    860899    TreeExpression decls = 0;
    861900    TreeDestructuringPattern pattern = 0;
    862     if (match(VAR)) {
     901    bool isVarDeclaraton = match(VAR);
     902    bool isLetDeclaration = match(LET);
     903
     904    VariableEnvironment dummySet;
     905    VariableEnvironment* lexicalVariables = nullptr;
     906    AutoCleanupLexicalScope lexicalScope;
     907
     908    auto gatherLexicalVariablesIfNecessary = [&] {
     909        if (isLetDeclaration) {
     910            ScopeRef scope = lexicalScope.scope();
     911            lexicalVariables = &scope->finalizeLexicalEnvironment();
     912        } else
     913            lexicalVariables = &dummySet;
     914    };
     915
     916    auto popLexicalScopeIfNecessary = [&] {
     917        if (isLetDeclaration)
     918            popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
     919    };
     920
     921    if (isVarDeclaraton || isLetDeclaration) {
    863922        /*
    864          for (var IDENT in expression) statement
    865          for (var varDeclarationList; expressionOpt; expressionOpt)
     923         for (var/let IDENT in expression) statement
     924         for (var/let varDeclarationList; expressionOpt; expressionOpt)
    866925         */
     926        if (isLetDeclaration) {
     927            ScopeRef newScope = pushScope();
     928            newScope->setIsLexicalScope();
     929            newScope->preventVarDeclarations();
     930            lexicalScope.setIsValid(newScope, this);
     931        }
     932
    867933        TreeDestructuringPattern forInTarget = 0;
    868934        TreeExpression forInInitializer = 0;
     
    870936        JSTextPosition initStart;
    871937        JSTextPosition initEnd;
    872         decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext);
     938        decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, isVarDeclaraton ? DeclarationType::VarDeclaration : DeclarationType::LexicalDeclaration);
    873939        m_allowsIn = true;
    874940        propagateError();
     
    906972        endLoop();
    907973        failIfFalse(statement, "Expected statement as body of for-", isOfEnumeration ? "of" : "in", " statement");
     974        gatherLexicalVariablesIfNecessary();
     975        TreeStatement result;
    908976        if (isOfEnumeration)
    909             return context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine);
    910         return context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine);
     977            result = context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
     978        else
     979            result = context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
     980        popLexicalScopeIfNecessary();
     981        return result;
    911982    }
    912983   
     
    915986            SavePoint savePoint = createSavePoint();
    916987            declsStart = tokenStartPosition();
    917             pattern = tryParseDestructuringPatternExpression(context);
     988            pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::DeclarationStatement);
    918989            declsEnd = lastTokenEndPosition();
    919990            if (pattern && (match(INTOKEN) || (match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of)))
     
    9541025        endLoop();
    9551026        failIfFalse(statement, "Expected a statement as the body of a for loop");
    956         return context.createForLoop(location, decls, condition, increment, statement, startLine, endLine);
    957     }
    958    
    959     // For-in loop
     1027        gatherLexicalVariablesIfNecessary();
     1028        TreeStatement result = context.createForLoop(location, decls, condition, increment, statement, startLine, endLine, *lexicalVariables);
     1029        popLexicalScopeIfNecessary();
     1030        return result;
     1031    }
     1032   
     1033    // For-in and For-of loop
    9601034enumerationLoop:
    9611035    failIfFalse(nonLHSCount == m_nonLHSCount, "Expected a reference on the left hand side of an enumeration statement");
     
    9771051    endLoop();
    9781052    failIfFalse(statement, "Expected a statement as the body of a for-", isOfEnumeration ? "of" : "in", "loop");
     1053    gatherLexicalVariablesIfNecessary();
     1054    TreeStatement result;
    9791055    if (pattern) {
    9801056        ASSERT(!decls);
    9811057        if (isOfEnumeration)
    982             return context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
    983         return context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
     1058            result = context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1059        else
     1060            result = context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1061
     1062        popLexicalScopeIfNecessary();
     1063        return result;
    9841064    }
    9851065    if (isOfEnumeration)
    986         return context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
    987     return context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
     1066        result = context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1067    else
     1068        result = context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1069    popLexicalScopeIfNecessary();
     1070    return result;
    9881071}
    9891072
     
    10011084        return context.createBreakStatement(location, &m_vm->propertyNames->nullIdentifier, start, end);
    10021085    }
    1003     matchOrFail(IDENT, "Expected an identifier as the target for a break statement");
     1086    failIfFalse(match(IDENT) || isLETMaskedAsIDENT(), "Expected an identifier as the target for a break statement");
    10041087    const Identifier* ident = m_token.m_data.ident;
    10051088    semanticFailIfFalse(getLabel(ident), "Cannot use the undeclared label '", ident->impl(), "'");
     
    10231106        return context.createContinueStatement(location, &m_vm->propertyNames->nullIdentifier, start, end);
    10241107    }
    1025     matchOrFail(IDENT, "Expected an identifier as the target for a continue statement");
     1108    failIfFalse(match(IDENT) || isLETMaskedAsIDENT(), "Expected an identifier as the target for a continue statement");
    10261109    const Identifier* ident = m_token.m_data.ident;
    10271110    ScopeLabelInfo* label = getLabel(ident);
     
    11171200    handleProductionOrFail(CLOSEPAREN, ")", "end", "subject of a 'switch'");
    11181201    handleProductionOrFail(OPENBRACE, "{", "start", "body of a 'switch'");
     1202    AutoPopScopeRef lexicalScope(this, pushScope());
     1203    lexicalScope->setIsLexicalScope();
     1204    lexicalScope->preventVarDeclarations();
    11191205    startSwitch();
    11201206    TreeClauseList firstClauses = parseSwitchClauses(context);
     
    11291215    handleProductionOrFail(CLOSEBRACE, "}", "end", "body of a 'switch'");
    11301216   
    1131     return context.createSwitchStatement(location, expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
    1132    
     1217    TreeStatement result = context.createSwitchStatement(location, expr, firstClauses, defaultClause, secondClauses, startLine, endLine, lexicalScope->finalizeLexicalEnvironment());
     1218    popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
     1219    return result;
    11331220}
    11341221
     
    12021289       
    12031290        handleProductionOrFail(OPENPAREN, "(", "start", "'catch' target");
    1204         if (!match(IDENT)) {
     1291        if (!(match(IDENT) || isLETMaskedAsIDENT())) {
    12051292            semanticFailureDueToKeyword("catch variable name");
    12061293            failWithMessage("Expected identifier name as catch target");
     
    12101297        AutoPopScopeRef catchScope(this, pushScope());
    12111298        failIfFalseIfStrict(declareVariable(ident), "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
    1212         catchScope->preventNewDecls();
     1299        catchScope->preventAllVariableDeclarations();
    12131300        handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
    12141301        matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
    12151302        catchBlock = parseBlockStatement(context);
    12161303        failIfFalse(catchBlock, "Unable to parse 'catch' block");
    1217         failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo), "Parse error");
     1304        popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
    12181305    }
    12191306   
     
    12461333{
    12471334    ASSERT(match(OPENBRACE));
     1335
     1336    // We should treat the first block statement of the function (the body of the function) as the lexical
     1337    // scope of the function itself, and not the lexical scope of a 'block' statement within the function.
     1338    AutoCleanupLexicalScope lexicalScope;
     1339    bool shouldPushLexicalScope = m_statementDepth > 0;
     1340    if (shouldPushLexicalScope) {
     1341        ScopeRef newScope = pushScope();
     1342        newScope->setIsLexicalScope();
     1343        newScope->preventVarDeclarations();
     1344        lexicalScope.setIsValid(newScope, this);
     1345    }
    12481346    JSTokenLocation location(tokenLocation());
    12491347    int startOffset = m_token.m_data.offset;
    12501348    int start = tokenLine();
     1349    VariableEnvironment emptyEnvironment;
    12511350    next();
    12521351    if (match(CLOSEBRACE)) {
    12531352        int endOffset = m_token.m_data.offset;
    12541353        next();
    1255         TreeStatement result = context.createBlockStatement(location, 0, start, m_lastTokenEndPosition.line);
     1354        TreeStatement result = context.createBlockStatement(location, 0, start, m_lastTokenEndPosition.line, shouldPushLexicalScope ? currentScope()->finalizeLexicalEnvironment() : emptyEnvironment);
    12561355        context.setStartOffset(result, startOffset);
    12571356        context.setEndOffset(result, endOffset);
     1357        if (shouldPushLexicalScope)
     1358            popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
    12581359        return result;
    12591360    }
     
    12631364    int endOffset = m_token.m_data.offset;
    12641365    next();
    1265     TreeStatement result = context.createBlockStatement(location, subtree, start, m_lastTokenEndPosition.line);
     1366    TreeStatement result = context.createBlockStatement(location, subtree, start, m_lastTokenEndPosition.line, shouldPushLexicalScope ? currentScope()->finalizeLexicalEnvironment() : emptyEnvironment);
    12661367    context.setStartOffset(result, startOffset);
    12671368    context.setEndOffset(result, endOffset);
     1369    if (shouldPushLexicalScope)
     1370        popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
     1371
    12681372    return result;
    12691373}
     
    12861390        break;
    12871391    case VAR:
    1288         result = parseVarDeclaration(context);
     1392        result = parseVariableDeclaration(context, DeclarationType::VarDeclaration);
    12891393        break;
    12901394    case FUNCTION:
     
    14931597    switch (parseType) {
    14941598    case StandardFunctionParseType: {
    1495         if (match(IDENT)) {
     1599        if (match(IDENT) || isLETMaskedAsIDENT()) {
    14961600            info.name = m_token.m_data.ident;
    14971601            m_lastFunctionName = info.name;
     
    15811685       
    15821686        functionScope->restoreFromSourceProviderCache(cachedInfo);
    1583         failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error");
     1687        popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
    15841688       
    15851689        m_token = cachedInfo->endFunctionToken();
     
    16891793    }
    16901794   
    1691     failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error");
     1795    popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
    16921796   
    16931797#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
     
    17371841    TreeClassExpression classExpr = parseClass(context, FunctionNeedsName, info);
    17381842    failIfFalse(classExpr, "Failed to parse class");
     1843    // FIXME: This should be like `let`, not `var`.
    17391844    declareVariable(info.className);
    1740 
    1741     // FIXME: This should be like `let`, not `var`.
    1742     context.addVar(info.className, DeclarationStacks::HasInitializer);
    17431845
    17441846    JSTextPosition classEnd = lastTokenEndPosition();
     
    18671969    }
    18681970
    1869     failIfFalse(popScope(classScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error");
     1971    popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
    18701972    consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
    18711973
     
    19212023            labels.append(LabelInfo(ident, start, end));
    19222024        }
    1923     } while (match(IDENT));
     2025    } while (match(IDENT) || isLETMaskedAsIDENT());
    19242026    bool isLoop = false;
    19252027    switch (m_token.m_type) {
     
    19342036    }
    19352037    const Identifier* unused = 0;
     2038    ScopeRef labelScope = currentScope();
    19362039    if (!m_syntaxAlreadyValidated) {
    19372040        for (size_t i = 0; i < labels.size(); i++)
     
    19412044    if (!m_syntaxAlreadyValidated) {
    19422045        for (size_t i = 0; i < labels.size(); i++)
    1943             popLabel();
     2046            popLabel(labelScope);
    19442047    }
    19452048    failIfFalse(statement, "Cannot parse statement");
     
    21032206    if (match(OPENBRACE) || match(OPENBRACKET)) {
    21042207        SavePoint savePoint = createSavePoint();
    2105         auto pattern = tryParseDestructuringPatternExpression(context);
     2208        auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
    21062209        if (pattern && consume(EQUAL)) {
    21072210            auto rhs = parseAssignmentExpression(context);
     
    23682471    const Identifier* stringPropertyName = 0;
    23692472    double numericPropertyName = 0;
    2370     if (m_token.m_type == IDENT || m_token.m_type == STRING) {
     2473    if (m_token.m_type == IDENT || m_token.m_type == STRING || isLETMaskedAsIDENT()) {
    23712474        stringPropertyName = m_token.m_data.ident;
    23722475        semanticFailIfTrue(superBinding == SuperBinding::Needed && *stringPropertyName == m_vm->propertyNames->prototype,
     
    26842787    }
    26852788    case IDENT: {
     2789    identifierExpression:
    26862790        JSTextPosition start = tokenStartPosition();
    26872791        const Identifier* ident = m_token.m_data.ident;
     
    27492853        return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings);
    27502854#endif
     2855    case LET:
     2856        if (!strictMode())
     2857            goto identifierExpression;
     2858        FALLTHROUGH;
    27512859    default:
    27522860        failDueToUnexpectedToken();
Note: See TracChangeset for help on using the changeset viewer.