Ignore:
Timestamp:
Dec 1, 2015, 7:16:28 PM (10 years ago)
Author:
Yusuke Suzuki
Message:

[ES6] Implement LLInt/Baseline Support for ES6 Generators and enable this feature
https://bugs.webkit.org/show_bug.cgi?id=150792

Reviewed by Saam Barati.

.:

  • Source/cmake/OptionsWin.cmake:
  • Source/cmake/WebKitFeatures.cmake:

Source/JavaScriptCore:

This patch implements basic functionality of ES6 Generators in LLInt and Baseline tiers.
While the implementation has some inefficient part, the implementation covers edge cases.
Later, we will make this efficient.

https://bugs.webkit.org/show_bug.cgi?id=151545
https://bugs.webkit.org/show_bug.cgi?id=151546
https://bugs.webkit.org/show_bug.cgi?id=151547
https://bugs.webkit.org/show_bug.cgi?id=151552
https://bugs.webkit.org/show_bug.cgi?id=151560
https://bugs.webkit.org/show_bug.cgi?id=151586

To encourage DFG / FTL later, we take the following design.

  1. Use switch_imm to jump to the save/resume points.

Instead of saving / restoring instruction pointer to resume from it, we use switch_imm to jump to the resume point.
This limits one entry point to a given generator function. This design makes inlining easy.
The generated code becomes the following.

function @generatorNext(@generator, @generatorState, @generatorValue, @generatorResumeMode)
{

switch (@generatorState) {
case Initial:

...
initial sequence.
...

op_save(Yield_0); op_save contains *virtual* jump to Yield_0.

CFG shows a jump edge to Yield_0 point, but it won't be actually used.

return ...;

case Yield_0:

op_resume();
if (@generatorResumeMode == Throw)

...

else if (@generatorResumeMode == Return)

...

...
sentValue is a value sent from a caller by generator.next(sentValue).
sentValue = @generatorValue;
...
op_save(Yield_1);
return ...;

case Yield_1:

op_resume();
if (@generatorResumeMode == Throw)

...

else if (@generatorResumeMode == Return)

...

...
sentValue = @generatorValue;
...

...
}

}

Resume sequence should not be emitted per yield.
This should be done in https://bugs.webkit.org/show_bug.cgi?id=151552.

  1. Store live frame registers to GeneratorFrame

To save and resume generator's state, we save all the live registers in GeneratorFrame.
And when resuming, we refill registers with saved ones.
Since saved register contains scope register, |this| etc., the environment including the scope chain will be recovered automatically.
While saving and resuming callee registers, we don't save parameter registers.
These registers will be used to control generator's resume behavior.

We perform BytecodeLivenessAnalysis in CodeBlock to determine actually *def*ined registers at that resume point.

  1. GeneratorFunction will evaluate parameters before generating Generator

Generator's parameter should be evaluated before entering Generator's body. For example,

function hello() { ... }
function *gen(a, b = hello())
{

yield b;

}
let g = gen(20); Now, hello should be called.

To enable this, we evaluate parameters in GeneratorFunction, and after that, we create a Generator and return it.
This can be explained by the following pseudo code.

function *gen(a, b = hello())
{

This is generator.
return {

@generatorNext: function (@generator, @generatorState, @generatorValue, @generatorResumeMode)
{

...

}

}

}

  1. op_save seems similar to conditional jump

We won't jump to elsewhere from op_save actually. But we add a *virtual* jump edge (flow) from op_save to the point so called *merge point*.
We construct the CFG as follows,

(global generator switch) -> (initial sequence) -> (op_save) ----+-> (merge point) -> (next sequence)*

| | |
| v |
| (op_ret) |
| |
+------------------------------------------->(op_resume)--+

By constructing such a graph,

  1. Since we have a flow from (op_save) to (merge point), at merge point, we can *use* locals that are defined before (op_save)
  2. op_save should claim that it does not define anything. And claim that it *use*s locals that are used in (merge point).
  3. at op_resume, we see *use*d locals at merge point and define all of them.

We can do the above things in use-def analysis because use-def analysis is backward analysis.
And after analyzing use-def chains, in op_save / op_resume, we only save / resume live registers at the head of merge point.

  • API/JSScriptRef.cpp:

(parseScript):

  • CMakeLists.txt:
  • Configurations/FeatureDefines.xcconfig:
  • DerivedSources.make:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • builtins/BuiltinExecutables.cpp:

(JSC::createExecutableInternal):

  • builtins/GeneratorPrototype.js: Added.

(generatorResume):
(next):
(return):
(throw):

  • bytecode/BytecodeBasicBlock.cpp:

(JSC::isBranch):

  • bytecode/BytecodeList.json:
  • bytecode/BytecodeLivenessAnalysis.cpp:

(JSC::stepOverInstruction):
(JSC::computeLocalLivenessForBytecodeOffset):
(JSC::BytecodeLivenessAnalysis::runLivenessFixpoint):
(JSC::BytecodeLivenessAnalysis::computeFullLiveness):
(JSC::BytecodeLivenessAnalysis::computeKills):

  • bytecode/BytecodeUseDef.h:

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

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::shrinkToFit):
(JSC::CodeBlock::validate):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::numCalleeLocals):
(JSC::CodeBlock::liveCalleeLocalsAtYield):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::tryGet):
(JSC::EvalCodeCache::getSlow):
(JSC::EvalCodeCache::isCacheable):

  • bytecode/ExecutableInfo.h:

(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::generatorThisMode):
(JSC::ExecutableInfo::superBinding):
(JSC::ExecutableInfo::parseMode):
(JSC::ExecutableInfo::isArrowFunction): Deleted.

  • bytecode/PreciseJumpTargets.cpp:

(JSC::getJumpTargetsForBytecodeOffset):

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::parseMode):
(JSC::UnlinkedCodeBlock::generatorThisMode):
(JSC::UnlinkedCodeBlock::superBinding):
(JSC::UnlinkedCodeBlock::isArrowFunction): Deleted.

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::generateUnlinkedFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):

  • bytecode/UnlinkedFunctionExecutable.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeParameters):
(JSC::BytecodeGenerator::newRegister):
(JSC::BytecodeGenerator::reclaimFreeRegisters):
(JSC::BytecodeGenerator::createVariable):
(JSC::BytecodeGenerator::emitCreateThis):
(JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
(JSC::BytecodeGenerator::emitNewFunctionExpression):
(JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
(JSC::BytecodeGenerator::emitNewFunction):
(JSC::BytecodeGenerator::emitIteratorNextWithValue):
(JSC::BytecodeGenerator::emitYieldPoint):
(JSC::BytecodeGenerator::emitSave):
(JSC::BytecodeGenerator::emitResume):
(JSC::BytecodeGenerator::emitYield):
(JSC::BytecodeGenerator::emitDelegateYield):
(JSC::BytecodeGenerator::emitGeneratorStateChange):
(JSC::BytecodeGenerator::emitGeneratorStateLabel):
(JSC::BytecodeGenerator::beginGenerator):
(JSC::BytecodeGenerator::endGenerator):
(JSC::BytecodeGenerator::emitNewFunctionInternal): Deleted.
(JSC::BytecodeGenerator::emitNewFunctionCommon): Deleted.

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::generatorThisMode):
(JSC::BytecodeGenerator::superBinding):
(JSC::BytecodeGenerator::generatorRegister):
(JSC::BytecodeGenerator::generatorStateRegister):
(JSC::BytecodeGenerator::generatorValueRegister):
(JSC::BytecodeGenerator::generatorResumeModeRegister):
(JSC::BytecodeGenerator::parseMode):
(JSC::BytecodeGenerator::registerFor):
(JSC::BytecodeGenerator::makeFunction):

  • bytecompiler/NodesCodegen.cpp:

(JSC::ThisNode::emitBytecode):
(JSC::emitHomeObjectForCallee):
(JSC::emitSuperBaseForCallee):
(JSC::ReturnNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):
(JSC::YieldExprNode::emitBytecode):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::inlineCall):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::handlePutById):

  • dfg/DFGForAllKills.h:

(JSC::DFG::forAllKilledOperands):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::forAllLocalsLiveInBytecode):

  • dfg/DFGOSREntrypointCreationPhase.cpp:

(JSC::DFG::OSREntrypointCreationPhase::run):

  • dfg/DFGVariableEventStream.cpp:

(JSC::DFG::VariableEventStream::reconstruct):

  • ftl/FTLForOSREntryJITCode.cpp:

(JSC::FTL::ForOSREntryJITCode::initializeEntryBuffer):

  • ftl/FTLForOSREntryJITCode.h:
  • ftl/FTLOSREntry.cpp:

(JSC::FTL::prepareOSREntry):

  • ftl/FTLState.cpp:

(JSC::FTL::State::State):

  • heap/MarkedBlock.h:

(JSC::MarkedBlock::isAtom):
(JSC::MarkedBlock::isLiveCell):

  • interpreter/Interpreter.cpp:

(JSC::eval):
(JSC::Interpreter::dumpRegisters):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::frameRegisterCountFor):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emitNewFuncCommon):
(JSC::JIT::emit_op_new_func):
(JSC::JIT::emit_op_new_generator_func):
(JSC::JIT::emitNewFuncExprCommon):
(JSC::JIT::emit_op_new_func_exp):
(JSC::JIT::emit_op_new_generator_func_exp):
(JSC::JIT::emit_op_save):
(JSC::JIT::emit_op_resume):

  • jit/JITOperations.cpp:

(JSC::operationNewFunctionCommon):

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

(JSC::LLInt::frameRegisterCountFor):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::traceFunctionPrologue):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):

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

(JSC::ASTBuilder::createYield):
(JSC::ASTBuilder::createFunctionMetadata):
(JSC::ASTBuilder::propagateArgumentsUse):

  • parser/Nodes.cpp:

(JSC::FunctionMetadataNode::FunctionMetadataNode):

  • parser/Nodes.h:
  • parser/Parser.cpp:

(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
(JSC::Parser<LexerType>::parseFunctionBody):
(JSC::stringForFunctionMode):
(JSC::Parser<LexerType>::createGeneratorParameters):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseYieldExpression):
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parseFunctionExpression):

  • parser/Parser.h:

(JSC::Scope::Scope):
(JSC::Scope::setSourceParseMode):
(JSC::Scope::hasArguments):
(JSC::Scope::collectFreeVariables):
(JSC::Scope::setIsFunction):
(JSC::Scope::setIsGeneratorFunction):
(JSC::Scope::setIsGenerator):
(JSC::parse):

  • parser/ParserModes.h:

(JSC::isFunctionParseMode):
(JSC::isModuleParseMode):
(JSC::isProgramParseMode):

  • parser/SourceCodeKey.h: Added.

(JSC::SourceCodeKey::SourceCodeKey):
(JSC::SourceCodeKey::isHashTableDeletedValue):
(JSC::SourceCodeKey::hash):
(JSC::SourceCodeKey::length):
(JSC::SourceCodeKey::isNull):
(JSC::SourceCodeKey::string):
(JSC::SourceCodeKey::operator==):
(JSC::SourceCodeKeyHash::hash):
(JSC::SourceCodeKeyHash::equal):
(JSC::SourceCodeKeyHashTraits::isEmptyValue):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createYield):
(JSC::SyntaxChecker::createFunctionMetadata):
(JSC::SyntaxChecker::operatorStackPop):

  • runtime/CodeCache.cpp:

(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):

  • runtime/CodeCache.h:

(JSC::SourceCodeKey::SourceCodeKey): Deleted.
(JSC::SourceCodeKey::isHashTableDeletedValue): Deleted.
(JSC::SourceCodeKey::hash): Deleted.
(JSC::SourceCodeKey::length): Deleted.
(JSC::SourceCodeKey::isNull): Deleted.
(JSC::SourceCodeKey::string): Deleted.
(JSC::SourceCodeKey::operator==): Deleted.
(JSC::SourceCodeKeyHash::hash): Deleted.
(JSC::SourceCodeKeyHash::equal): Deleted.
(JSC::SourceCodeKeyHashTraits::isEmptyValue): Deleted.

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

(JSC::SLOW_PATH_DECL):

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

(JSC::checkSyntax):
(JSC::checkModuleSyntax):

  • runtime/Executable.cpp:

(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ProgramExecutable::checkSyntax):

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

(JSC::constructFunction):
(JSC::constructFunctionSkippingEvalEnabledCheck):

  • runtime/FunctionConstructor.h:
  • runtime/GeneratorFrame.cpp: Added.

(JSC::GeneratorFrame::GeneratorFrame):
(JSC::GeneratorFrame::finishCreation):
(JSC::GeneratorFrame::createStructure):
(JSC::GeneratorFrame::create):
(JSC::GeneratorFrame::save):
(JSC::GeneratorFrame::resume):
(JSC::GeneratorFrame::visitChildren):

  • runtime/GeneratorFrame.h: Added.

(JSC::GeneratorFrame::locals):
(JSC::GeneratorFrame::localAt):
(JSC::GeneratorFrame::offsetOfLocals):
(JSC::GeneratorFrame::allocationSizeForLocals):

  • runtime/GeneratorFunctionConstructor.cpp: Added.

(JSC::GeneratorFunctionConstructor::GeneratorFunctionConstructor):
(JSC::GeneratorFunctionConstructor::finishCreation):
(JSC::callGeneratorFunctionConstructor):
(JSC::constructGeneratorFunctionConstructor):
(JSC::GeneratorFunctionConstructor::getCallData):
(JSC::GeneratorFunctionConstructor::getConstructData):

  • runtime/GeneratorFunctionConstructor.h: Added.

(JSC::GeneratorFunctionConstructor::create):
(JSC::GeneratorFunctionConstructor::createStructure):

  • runtime/GeneratorFunctionPrototype.cpp: Added.

(JSC::GeneratorFunctionPrototype::GeneratorFunctionPrototype):
(JSC::GeneratorFunctionPrototype::finishCreation):

  • runtime/GeneratorFunctionPrototype.h: Added.

(JSC::GeneratorFunctionPrototype::create):
(JSC::GeneratorFunctionPrototype::createStructure):

  • runtime/GeneratorPrototype.cpp: Copied from Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp.

(JSC::GeneratorPrototype::finishCreation):
(JSC::GeneratorPrototype::getOwnPropertySlot):

  • runtime/GeneratorPrototype.h: Copied from Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp.

(JSC::GeneratorPrototype::create):
(JSC::GeneratorPrototype::createStructure):
(JSC::GeneratorPrototype::GeneratorPrototype):

  • runtime/GeneratorThisMode.h: Added.
  • runtime/JSFunction.cpp:

(JSC::JSFunction::getOwnPropertySlot):

  • runtime/JSGeneratorFunction.cpp: Added.

(JSC::JSGeneratorFunction::JSGeneratorFunction):
(JSC::JSGeneratorFunction::createImpl):
(JSC::JSGeneratorFunction::create):
(JSC::JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint):

  • runtime/JSGeneratorFunction.h: Added.

(JSC::JSGeneratorFunction::allocationSize):
(JSC::JSGeneratorFunction::createStructure):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::generatorFunctionPrototype):
(JSC::JSGlobalObject::generatorPrototype):
(JSC::JSGlobalObject::generatorFunctionStructure):

  • runtime/ModuleLoaderObject.cpp:

(JSC::moduleLoaderObjectParseModule):

  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:
  • tests/es6.yaml:
  • tests/es6/generators_yield_star_generic_iterables.js:

(iterator.next):
(iterable.Symbol.iterator):
(createIterableObject):

  • tests/es6/generators_yield_star_instances_of_iterables.js:

(iterator.next):
(iterable.Symbol.iterator):
(createIterableObject):

  • tests/es6/generators_yield_star_iterator_closing.js:

(iterator.next):
(iterable.Symbol.iterator):
(createIterableObject):

  • tests/es6/generators_yield_star_iterator_closing_via_throw.js:

(iterator.next):
(iterable.Symbol.iterator):
(createIterableObject):

  • tests/stress/generator-arguments-from-function.js: Added.

(shouldBe):
(test):

  • tests/stress/generator-arguments.js: Added.

(shouldBe):
(g1):

  • tests/stress/generator-class-methods-syntax.js: Added.

(testSyntax):
(testSyntaxError):
(testSyntaxError.Cocoa):
(testSyntax.Cocoa.prototype.ok):
(testSyntax.Cocoa):
(testSyntax.Cocoa.ok):

  • tests/stress/generator-class-methods.js: Added.

(shouldBe):
(prototype.gen):
(staticGen):
(shouldBe.g.next):

  • tests/stress/generator-eval-this.js: Added.

(shouldBe):
(shouldThrow):
(B):
(A):
(C.prototype.generator):
(C):
(TypeError):

  • tests/stress/generator-function-constructor.js: Added.

(shouldBe):
(generatorFunctionConstructor):

  • tests/stress/generator-function-name.js: Added.

(shouldBe):
(ok):

  • tests/stress/generator-methods-with-non-generator.js: Added.

(shouldThrow):

  • tests/stress/generator-relations.js: Added.

(shouldBe):
(generatorFunction):

  • tests/stress/generator-return-before-first-call.js: Added.

(shouldBe):
(shouldBeIteratorResult):

  • tests/stress/generator-return.js: Added.

(shouldBe):
(shouldBeIteratorResult):

  • tests/stress/generator-this.js: Added.

(shouldBe):
(shouldThrow):
(gen):
(shouldBe.g.next):

  • tests/stress/generator-throw-before-first-call.js: Added.

(unreachable):
(gen):
(catch):

  • tests/stress/generator-throw.js: Added.

(shouldBe):
(shouldBeIteratorResult):

  • tests/stress/generator-with-new-target.js: Added.

(shouldBe):
(gen):

  • tests/stress/generator-with-super.js: Added.

(shouldThrow):
(test):
(B.prototype.gen):
(B):
(A.prototype.gen):
(A):

  • tests/stress/generator-yield-star.js: Added.

(shouldBe):
(shouldThrow):
(prototype.call):
(Arrays):
(Arrays.prototype.Symbol.iterator):
(Iterator.prototype.next):
(Iterator.prototype.string_appeared_here):
(Iterator.prototype.Symbol.iterator):
(Iterator):
(gen):

Source/WebCore:

  • Configurations/FeatureDefines.xcconfig:

Source/WebKit/mac:

  • Configurations/FeatureDefines.xcconfig:

Source/WebKit2:

  • Configurations/FeatureDefines.xcconfig:

Source/WTF:

  • wtf/FastBitVector.h:

(WTF::FastBitVector::forEachSetBit):

  • wtf/FeatureDefines.h:

Tools:

  • Scripts/webkitperl/FeatureList.pm:

WebKitLibraries:

  • win/tools/vsprops/FeatureDefines.props:
  • win/tools/vsprops/FeatureDefinesCairo.props:
File:
1 edited

Legend:

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

    r192935 r192937  
    195195Parser<LexerType>::Parser(
    196196    VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode,
    197     JSParserStrictMode strictMode, SourceParseMode parseMode,
     197    JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding,
    198198    ConstructorKind defaultConstructorKind, ThisTDZMode thisTDZMode)
    199199    : m_vm(vm)
     
    211211    , m_sourceElements(0)
    212212    , m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
     213    , m_superBinding(superBinding)
    213214    , m_defaultConstructorKind(defaultConstructorKind)
    214215    , m_thisTDZMode(thisTDZMode)
     
    250251    if (m_lexer->isReparsingFunction()) {
    251252        ParserFunctionInfo<ASTBuilder> functionInfo;
    252         parseFunctionParameters(context, parseMode, functionInfo);
     253        if (parseMode == SourceParseMode::GeneratorBodyMode)
     254            functionInfo.parameters = createGeneratorParameters(context);
     255        else
     256            parseFunctionParameters(context, parseMode, functionInfo);
    253257        m_parameters = functionInfo.parameters;
    254258
     
    274278        else if (isModuleParseMode(parseMode))
    275279            sourceElements = parseModuleSourceElements(context, parseMode);
    276         else
    277             sourceElements = parseSourceElements(context, CheckForStrictMode);
     280        else {
     281            if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
     282                sourceElements = parseGeneratorFunctionSourceElements(context, CheckForStrictMode);
     283            else
     284                sourceElements = parseSourceElements(context, CheckForStrictMode);
     285        }
    278286    }
    279287
     
    302310    for (auto& entry : capturedVariables)
    303311        varDeclarations.markVariableAsCaptured(entry);
    304    
     312
     313    IdentifierSet usedVariables;
     314    scope->getUsedVariables(usedVariables);
     315    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode) {
     316        if (usedVariables.contains(m_vm->propertyNames->arguments.impl()))
     317            context.propagateArgumentsUse();
     318    }
     319
    305320    CodeFeatures features = context.features();
    306321    if (scope->strictMode())
     
    312327    if (modifiedArguments)
    313328        features |= ModifiedArgumentsFeature;
     329
    314330    Vector<RefPtr<UniquedStringImpl>> closedVariables;
    315331    if (m_parsingBuiltin) {
    316         IdentifierSet usedVariables;
    317         scope->getUsedVariables(usedVariables);
    318332        // FIXME: This needs to be changed if we want to allow builtins to use lexical declarations.
    319333        for (const auto& variable : usedVariables) {
     
    454468        semanticFail("Exported binding '", uid.get(), "' needs to refer to a top-level declared variable");
    455469    }
     470
     471    return sourceElements;
     472}
     473
     474template <typename LexerType>
     475template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, SourceElementsMode mode)
     476{
     477    auto sourceElements = context.createSourceElements();
     478
     479    unsigned functionKeywordStart = tokenStart();
     480    JSTokenLocation startLocation(tokenLocation());
     481    JSTextPosition start = tokenStartPosition();
     482    unsigned startColumn = tokenColumn();
     483    int functionNameStart = m_token.m_location.startOffset;
     484    int parametersStart = m_token.m_location.startOffset;
     485
     486    ParserFunctionInfo<TreeBuilder> info;
     487    info.name = &m_vm->propertyNames->nullIdentifier;
     488    info.parameters = createGeneratorParameters(context);
     489    info.startOffset = parametersStart;
     490    info.startLine = tokenLine();
     491    info.parameterCount = 4; // generator, state, value, resume mode
     492
     493    {
     494        AutoPopScopeRef generatorBodyScope(this, pushScope());
     495        generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
     496        SyntaxChecker generatorFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
     497        failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
     498        popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
     499    }
     500    info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false);
     501
     502    info.endLine = tokenLine();
     503    info.endOffset = m_token.m_data.offset;
     504    info.bodyStartColumn = startColumn;
     505
     506    auto functionExpr = context.createFunctionExpr(startLocation, info);
     507    auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
     508    context.appendStatement(sourceElements, statement);
    456509
    457510    return sourceElements;
     
    16011654template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(
    16021655    TreeBuilder& context, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart,
    1603     ConstructorKind constructorKind, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
    1604 {
    1605     bool isArrowFunction = FunctionBodyType::StandardFunctionBodyBlock != bodyType;
     1656    ConstructorKind constructorKind, SuperBinding superBinding, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
     1657{
    16061658    bool isArrowFunctionBodyExpression = bodyType == ArrowFunctionBodyExpression;
    16071659    if (!isArrowFunctionBodyExpression) {
     
    16091661        if (match(CLOSEBRACE)) {
    16101662            unsigned endColumn = tokenColumn();
    1611             return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction, isArrowFunctionBodyExpression);
     1663            return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
    16121664        }
    16131665    }
     
    16211673        failIfFalse(parseSourceElements(syntaxChecker, CheckForStrictMode), bodyType == StandardFunctionBodyBlock ? "Cannot parse body of this function" : "Cannot parse body of this arrow function");
    16221674    unsigned endColumn = tokenColumn();
    1623     return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction, isArrowFunctionBodyExpression);
     1675    return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
    16241676}
    16251677
     
    16351687    case SourceParseMode::MethodMode:
    16361688        return "method";
    1637     case SourceParseMode::GeneratorMode:
     1689    case SourceParseMode::GeneratorBodyMode:
    16381690        return "generator";
     1691    case SourceParseMode::GeneratorWrapperFunctionMode:
     1692        return "generator function";
    16391693    case SourceParseMode::ArrowFunctionMode:
    16401694        return "arrow function";
     
    17151769
    17161770template <typename LexerType>
     1771template <class TreeBuilder> typename TreeBuilder::FormalParameterList Parser<LexerType>::createGeneratorParameters(TreeBuilder& context)
     1772{
     1773    auto parameters = context.createFormalParameterList();
     1774
     1775    JSTokenLocation location(tokenLocation());
     1776    JSTextPosition position = tokenStartPosition();
     1777
     1778    // @generator
     1779    declareParameter(&m_vm->propertyNames->generatorPrivateName);
     1780    auto generator = context.createBindingLocation(location, m_vm->propertyNames->generatorPrivateName, position, position, AssignmentContext::DeclarationStatement);
     1781    context.appendParameter(parameters, generator, 0);
     1782
     1783    // @generatorState
     1784    declareParameter(&m_vm->propertyNames->generatorStatePrivateName);
     1785    auto generatorState = context.createBindingLocation(location, m_vm->propertyNames->generatorStatePrivateName, position, position, AssignmentContext::DeclarationStatement);
     1786    context.appendParameter(parameters, generatorState, 0);
     1787
     1788    // @generatorValue
     1789    declareParameter(&m_vm->propertyNames->generatorValuePrivateName);
     1790    auto generatorValue = context.createBindingLocation(location, m_vm->propertyNames->generatorValuePrivateName, position, position, AssignmentContext::DeclarationStatement);
     1791    context.appendParameter(parameters, generatorValue, 0);
     1792
     1793    // @generatorResumeMode
     1794    declareParameter(&m_vm->propertyNames->generatorResumeModePrivateName);
     1795    auto generatorResumeMode = context.createBindingLocation(location, m_vm->propertyNames->generatorResumeModePrivateName, position, position, AssignmentContext::DeclarationStatement);
     1796    context.appendParameter(parameters, generatorResumeMode, 0);
     1797
     1798    return parameters;
     1799}
     1800
     1801template <typename LexerType>
    17171802template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionDefinitionType functionDefinitionType)
    17181803{
     
    18251910        unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
    18261911       
    1827         bool isArrowFunction = mode == SourceParseMode::ArrowFunctionMode;
    1828        
    18291912        functionInfo.body = context.createFunctionMetadata(
    18301913            startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn,
    18311914            functionKeywordStart, functionNameStart, parametersStart,
    1832             cachedInfo->strictMode, constructorKind, cachedInfo->parameterCount, mode, isArrowFunction, functionBodyType == ArrowFunctionBodyExpression);
     1915            cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression);
    18331916       
    18341917        functionScope->restoreFromSourceProviderCache(cachedInfo);
     
    18441927        functionInfo.endOffset = cachedInfo->endFunctionOffset;
    18451928
    1846         if (isArrowFunction)
     1929        if (mode == SourceParseMode::ArrowFunctionMode)
    18471930            functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
    18481931        else
     
    18661949    m_lastFunctionName = lastFunctionName;
    18671950    ParserState oldState = saveState();
    1868    
    1869     functionInfo.body = parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, functionBodyType, functionInfo.parameterCount, mode);
     1951
     1952    auto performParsingFunctionBody = [&] {
     1953        return parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
     1954    };
     1955
     1956    if (mode == SourceParseMode::GeneratorWrapperFunctionMode) {
     1957        AutoPopScopeRef generatorBodyScope(this, pushScope());
     1958        generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
     1959        functionInfo.body = performParsingFunctionBody();
     1960
     1961        // When a generator has a "use strict" directive, a generator function wrapping it should be strict mode.
     1962        if  (generatorBodyScope->strictMode())
     1963            functionScope->setStrictMode();
     1964
     1965        semanticFailIfTrue(generatorBodyScope->hasDirectSuper(), "Cannot call super() outside of a class constructor");
     1966        if (generatorBodyScope->needsSuperBinding())
     1967            semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
     1968
     1969        popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
     1970    } else
     1971        functionInfo.body = performParsingFunctionBody();
    18701972   
    18711973    restoreState(oldState);
     
    18731975    context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
    18741976    if (functionScope->strictMode() && functionInfo.name) {
    1875         RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorMode);
     1977        RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode);
    18761978        semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
    18771979        semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
     
    19412043#if ENABLE(ES6_GENERATORS)
    19422044    if (consume(TIMES))
    1943         parseMode = SourceParseMode::GeneratorMode;
     2045        parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
    19442046#endif
    19452047    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
     
    20922194            if (isGenerator) {
    20932195                isConstructor = false;
    2094                 parseMode = SourceParseMode::GeneratorMode;
     2196                parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
    20952197                semanticFailIfTrue(*ident == m_vm->propertyNames->prototype, "Cannot declare a generator named 'prototype'");
    20962198                semanticFailIfTrue(*ident == m_vm->propertyNames->constructor, "Cannot declare a generator named 'constructor'");
     
    27582860
    27592861#if ENABLE(ES6_GENERATORS)
    2760     if (match(YIELD))
     2862    if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))
    27612863        return parseYieldExpression(context);
    27622864#endif
     
    28632965
    28642966    JSTokenLocation location(tokenLocation());
     2967    JSTextPosition divotStart = tokenStartPosition();
    28652968    ASSERT(match(YIELD));
    28662969    SavePoint savePoint = createSavePoint();
     
    28702973
    28712974    bool delegate = consume(TIMES);
     2975    JSTextPosition argumentStart = tokenStartPosition();
    28722976    TreeExpression argument = parseAssignmentExpression(context);
    28732977    if (!argument) {
     
    28762980        return context.createYield(location);
    28772981    }
    2878     return context.createYield(location, argument, delegate);
     2982    return context.createYield(location, argument, delegate, divotStart, argumentStart, lastTokenEndPosition());
    28792983}
    28802984
     
    30683172    unsigned methodStart = tokenStart();
    30693173    ParserFunctionInfo<TreeBuilder> methodInfo;
    3070     SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorMode : SourceParseMode::MethodMode;
     3174    SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorWrapperFunctionMode : SourceParseMode::MethodMode;
    30713175    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
    30723176    methodInfo.name = methodName;
     
    33213425#if ENABLE(ES6_GENERATORS)
    33223426    if (consume(TIMES))
    3323         parseMode = SourceParseMode::GeneratorMode;
     3427        parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
    33243428#endif
    33253429    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Expression)), "Cannot parse function expression");
Note: See TracChangeset for help on using the changeset viewer.