[ES6] Implement LLInt/Baseline Support for ES6 Generators and enable this feature
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Dec 2015 03:16:28 +0000 (03:16 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Dec 2015 03:16:28 +0000 (03:16 +0000)
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.

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

3. 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)
            {
                ...
            }
        }
    }

4. 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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192937 268f45cc-cd09-0410-ab3c-d52691b4dbfc

120 files changed:
ChangeLog
Source/JavaScriptCore/API/JSScriptRef.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/builtins/GeneratorPrototype.js [new file with mode: 0644]
Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/EvalCodeCache.h
Source/JavaScriptCore/bytecode/ExecutableInfo.h
Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGForAllKills.h
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp
Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp
Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.h
Source/JavaScriptCore/ftl/FTLOSREntry.cpp
Source/JavaScriptCore/ftl/FTLState.cpp
Source/JavaScriptCore/heap/MarkedBlock.h
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/Nodes.cpp
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserModes.h
Source/JavaScriptCore/parser/SourceCodeKey.h [new file with mode: 0644]
Source/JavaScriptCore/parser/SyntaxChecker.h
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/Completion.cpp
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/FunctionConstructor.cpp
Source/JavaScriptCore/runtime/FunctionConstructor.h
Source/JavaScriptCore/runtime/GeneratorFrame.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorFrame.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorPrototype.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorPrototype.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/GeneratorThisMode.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGeneratorFunction.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/tests/es6.yaml
Source/JavaScriptCore/tests/es6/generators_yield_star_generic_iterables.js
Source/JavaScriptCore/tests/es6/generators_yield_star_instances_of_iterables.js
Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing.js
Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing_via_throw.js
Source/JavaScriptCore/tests/stress/generator-arguments-from-function.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-arguments.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-class-methods-syntax.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-class-methods.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-eval-this.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-function-constructor.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-function-name.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-methods-with-non-generator.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-relations.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-return-before-first-call.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-return.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-this.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-throw-before-first-call.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-throw.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-with-new-target.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-with-super.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/generator-yield-star.js [new file with mode: 0644]
Source/WTF/ChangeLog
Source/WTF/wtf/FastBitVector.h
Source/WTF/wtf/FeatureDefines.h
Source/WebCore/ChangeLog
Source/WebCore/Configurations/FeatureDefines.xcconfig
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/Configurations/FeatureDefines.xcconfig
Source/WebKit2/ChangeLog
Source/WebKit2/Configurations/FeatureDefines.xcconfig
Source/cmake/OptionsWin.cmake
Source/cmake/WebKitFeatures.cmake
Tools/ChangeLog
Tools/Scripts/webkitperl/FeatureList.pm
WebKitLibraries/ChangeLog
WebKitLibraries/win/tools/vsprops/FeatureDefines.props
WebKitLibraries/win/tools/vsprops/FeatureDefinesCairo.props

index 3f364b8..49ed35a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2015-12-01  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [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:
+
 2015-12-01  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r192914.
index 3b7b76b..2f37423 100644 (file)
@@ -71,7 +71,7 @@ static bool parseScript(VM* vm, const SourceCode& source, ParserError& error)
 {
     return !!JSC::parse<JSC::ProgramNode>(
         vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
-        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, 
+        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
         error);
 }
 
index cae3cd2..7eeecfe 100644 (file)
@@ -576,6 +576,10 @@ set(JavaScriptCore_RUNTIME_SOURCES
     runtime/FunctionHasExecutedCache.cpp
     runtime/FunctionPrototype.cpp
     runtime/FunctionRareData.cpp
+    runtime/GeneratorFrame.cpp
+    runtime/GeneratorFunctionConstructor.cpp
+    runtime/GeneratorFunctionPrototype.cpp
+    runtime/GeneratorPrototype.cpp
     runtime/GetterSetter.cpp
     runtime/Identifier.cpp
     runtime/IndexingType.cpp
@@ -615,6 +619,7 @@ set(JavaScriptCore_RUNTIME_SOURCES
     runtime/JSDateMath.cpp
     runtime/JSEnvironmentRecord.cpp
     runtime/JSFunction.cpp
+    runtime/JSGeneratorFunction.cpp
     runtime/JSGlobalLexicalEnvironment.cpp
     runtime/JSGlobalObject.cpp
     runtime/JSGlobalObjectDebuggable.cpp
@@ -750,6 +755,7 @@ set(JavaScriptCore_OBJECT_LUT_SOURCES
     runtime/DateConstructor.cpp
     runtime/DatePrototype.cpp
     runtime/ErrorPrototype.cpp
+    runtime/GeneratorPrototype.cpp
     runtime/InspectorInstrumentationObject.cpp
     runtime/IntlCollatorConstructor.cpp
     runtime/IntlCollatorPrototype.cpp
@@ -1209,6 +1215,7 @@ set(JavaScriptCore_BUILTINS_SOURCES
     ${JAVASCRIPTCORE_DIR}/builtins/ArrayIteratorPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/ArrayPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/FunctionPrototype.js
+    ${JAVASCRIPTCORE_DIR}/builtins/GeneratorPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/GlobalObject.js
     ${JAVASCRIPTCORE_DIR}/builtins/InspectorInstrumentationObject.js
     ${JAVASCRIPTCORE_DIR}/builtins/InternalPromiseConstructor.js
index 84e0009..5bce494 100644 (file)
@@ -1,3 +1,508 @@
+2015-12-01  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [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.
+
+        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.
+
+        2. 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.
+
+        3. 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)
+                    {
+                        ...
+                    }
+                }
+            }
+
+        4. 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):
+
 2015-12-01  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r192914.
index e177afc..18d64d0 100644 (file)
@@ -47,7 +47,7 @@ ENABLE_CANVAS_PROXY = ;
 ENABLE_CHANNEL_MESSAGING = ENABLE_CHANNEL_MESSAGING;
 ENABLE_ES6_ARROWFUNCTION_SYNTAX = ENABLE_ES6_ARROWFUNCTION_SYNTAX;
 ENABLE_ES6_CLASS_SYNTAX = ENABLE_ES6_CLASS_SYNTAX;
-ENABLE_ES6_GENERATORS = ;
+ENABLE_ES6_GENERATORS = ENABLE_ES6_GENERATORS;
 ENABLE_ES6_MODULES = ;
 ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX = ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX;
 ENABLE_CONTENT_FILTERING = ENABLE_CONTENT_FILTERING;
index 3758a36..768ebaa 100644 (file)
@@ -84,6 +84,7 @@ JavaScriptCore_BUILTINS_SOURCES = \
     $(JavaScriptCore)/builtins/ArrayIteratorPrototype.js \
     $(JavaScriptCore)/builtins/ArrayPrototype.js \
     $(JavaScriptCore)/builtins/FunctionPrototype.js \
+    $(JavaScriptCore)/builtins/GeneratorPrototype.js \
     $(JavaScriptCore)/builtins/GlobalObject.js \
     $(JavaScriptCore)/builtins/InspectorInstrumentationObject.js \
     $(JavaScriptCore)/builtins/InternalPromiseConstructor.js \
@@ -119,6 +120,7 @@ OBJECT_LUT_HEADERS = \
     DateConstructor.lut.h \
     DatePrototype.lut.h \
     ErrorPrototype.lut.h \
+    GeneratorPrototype.lut.h \
     InspectorInstrumentationObject.lut.h \
     IntlCollatorConstructor.lut.h \
     IntlCollatorPrototype.lut.h \
index 9a206a0..62d21d2 100644 (file)
     <ClCompile Include="..\runtime\FunctionHasExecutedCache.cpp" />
     <ClCompile Include="..\runtime\FunctionPrototype.cpp" />
     <ClCompile Include="..\runtime\FunctionRareData.cpp" />
+    <ClCompile Include="..\runtime\GeneratorFrame.cpp" />
+    <ClCompile Include="..\runtime\GeneratorFunctionConstructor.cpp" />
+    <ClCompile Include="..\runtime\GeneratorFunctionPrototype.cpp" />
+    <ClCompile Include="..\runtime\GeneratorPrototype.cpp" />
     <ClCompile Include="..\runtime\GetterSetter.cpp" />
     <ClCompile Include="..\runtime\Identifier.cpp" />
     <ClCompile Include="..\runtime\IndexingType.cpp" />
     <ClCompile Include="..\runtime\JSDataViewPrototype.cpp" />
     <ClCompile Include="..\runtime\JSDateMath.cpp" />
     <ClCompile Include="..\runtime\JSFunction.cpp" />
+    <ClCompile Include="..\runtime\JSGeneratorFunction.cpp" />
     <ClCompile Include="..\runtime\JSGlobalObject.cpp" />
     <ClCompile Include="..\runtime\JSGlobalObjectFunctions.cpp" />
     <ClCompile Include="..\runtime\JSGlobalLexicalEnvironment.cpp" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\DateConstructor.lut.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\DatePrototype.lut.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ErrorPrototype.lut.h" />
+    <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\GeneratorPrototype.lut.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\HeaderDetection.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InjectedScriptSource.h" />
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorBackendDispatchers.h" />
     <ClInclude Include="..\parser\ParserTokens.h" />
     <ClInclude Include="..\parser\ResultType.h" />
     <ClInclude Include="..\parser\SourceCode.h" />
+    <ClInclude Include="..\parser\SourceCodeKey.h" />
     <ClInclude Include="..\parser\SourceProvider.h" />
     <ClInclude Include="..\parser\SourceProviderCache.h" />
     <ClInclude Include="..\parser\SourceProviderCacheItem.h" />
     <ClInclude Include="..\runtime\FunctionHasExecutedCache.h" />
     <ClInclude Include="..\runtime\FunctionPrototype.h" />
     <ClInclude Include="..\runtime\FunctionRareData.h" />
+    <ClInclude Include="..\runtime\GeneratorFrame.h" />
+    <ClInclude Include="..\runtime\GeneratorFunctionConstructor.h" />
+    <ClInclude Include="..\runtime\GeneratorFunctionPrototype.h" />
+    <ClInclude Include="..\runtime\GeneratorPrototype.h" />
+    <ClInclude Include="..\runtime\GeneratorThisMode.h" />
     <ClInclude Include="..\runtime\GenericArguments.h" />
     <ClInclude Include="..\runtime\GenericArgumentsInlines.h" />
     <ClInclude Include="..\runtime\GenericOffset.h" />
     <ClInclude Include="..\runtime\JSFloat32Array.h" />
     <ClInclude Include="..\runtime\JSFloat64Array.h" />
     <ClInclude Include="..\runtime\JSFunction.h" />
+    <ClInclude Include="..\runtime\JSGeneratorFunction.h" />
     <ClInclude Include="..\runtime\JSGenericTypedArrayView.h" />
     <ClInclude Include="..\runtime\JSGenericTypedArrayViewConstructor.h" />
     <ClInclude Include="..\runtime\JSGenericTypedArrayViewConstructorInlines.h" />
index 951c3c5..b900af0 100644 (file)
     <ClCompile Include="..\runtime\FunctionRareData.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
+    <ClCompile Include="..\runtime\GeneratorFrame.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
+    <ClCompile Include="..\runtime\GeneratorFunctionConstructor.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
+    <ClCompile Include="..\runtime\GeneratorFunctionPrototype.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
+    <ClCompile Include="..\runtime\GeneratorPrototype.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
     <ClCompile Include="..\runtime\GetterSetter.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
     <ClCompile Include="..\runtime\JSFunction.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
+    <ClCompile Include="..\runtime\JSGeneratorFunction.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
     <ClCompile Include="..\runtime\JSGlobalObject.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
     <ClInclude Include="..\parser\SourceCode.h">
       <Filter>parser</Filter>
     </ClInclude>
+    <ClInclude Include="..\parser\SourceCodeKey.h">
+      <Filter>parser</Filter>
+    </ClInclude>
     <ClInclude Include="..\parser\SourceProvider.h">
       <Filter>parser</Filter>
     </ClInclude>
     <ClInclude Include="..\runtime\FunctionRareData.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\GeneratorFrame.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
+    <ClInclude Include="..\runtime\GeneratorFunctionConstructor.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
+    <ClInclude Include="..\runtime\GeneratorFunctionPrototype.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
+    <ClInclude Include="..\runtime\GeneratorPrototype.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
+    <ClInclude Include="..\runtime\GeneratorThisMode.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\GetPutInfo.h">
       <Filter>runtime</Filter>
     </ClInclude>
     <ClInclude Include="..\runtime\JSFunction.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\JSGeneratorFunction.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\JSGlobalObject.h">
       <Filter>runtime</Filter>
     </ClInclude>
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ErrorPrototype.lut.h">
       <Filter>Derived Sources</Filter>
     </ClInclude>
+    <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\GeneratorPrototype.lut.h">
+      <Filter>Derived Sources</Filter>
+    </ClInclude>
     <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\HeaderDetection.h">
       <Filter>Derived Sources</Filter>
     </ClInclude>
index 68b9502..339b340 100644 (file)
                709FB86B1AE335C60039D069 /* WeakSetPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709FB8651AE335C60039D069 /* WeakSetPrototype.cpp */; };
                709FB86C1AE335C60039D069 /* WeakSetPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 709FB8661AE335C60039D069 /* WeakSetPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70B0A9D11A9B66460001306A /* RuntimeFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B0A9D01A9B66200001306A /* RuntimeFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B791911C024A13002481E2 /* SourceCodeKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B7918E1C0244C9002481E2 /* SourceCodeKey.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B791921C024A23002481E2 /* GeneratorFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70B791831C024432002481E2 /* GeneratorFrame.cpp */; };
+               70B791931C024A28002481E2 /* GeneratorFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B791841C024432002481E2 /* GeneratorFrame.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B791941C024A28002481E2 /* GeneratorFunctionConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70B791851C024432002481E2 /* GeneratorFunctionConstructor.cpp */; };
+               70B791951C024A28002481E2 /* GeneratorFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B791861C024432002481E2 /* GeneratorFunctionConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B791961C024A28002481E2 /* GeneratorFunctionPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70B791871C024432002481E2 /* GeneratorFunctionPrototype.cpp */; };
+               70B791971C024A29002481E2 /* GeneratorFunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B791881C024432002481E2 /* GeneratorFunctionPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B791981C024A29002481E2 /* GeneratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70B791891C024432002481E2 /* GeneratorPrototype.cpp */; };
+               70B791991C024A29002481E2 /* GeneratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B7918A1C024432002481E2 /* GeneratorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B7919A1C024A29002481E2 /* GeneratorThisMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B7918B1C024432002481E2 /* GeneratorThisMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B7919B1C024A46002481E2 /* JSGeneratorFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70B7918C1C024462002481E2 /* JSGeneratorFunction.cpp */; };
+               70B7919C1C024A49002481E2 /* JSGeneratorFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B7918D1C024462002481E2 /* JSGeneratorFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               70B7919D1C024A56002481E2 /* GeneratorPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B791901C0246CE002481E2 /* GeneratorPrototype.lut.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70DC3E091B2DF2C700054299 /* IteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70DC3E071B2DF2C700054299 /* IteratorPrototype.cpp */; };
                70DC3E0A1B2DF2C700054299 /* IteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 70DC3E081B2DF2C700054299 /* IteratorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70DE9A091BE7D69E005D89D9 /* LLIntAssembly.h in Headers */ = {isa = PBXBuildFile; fileRef = 70DE9A081BE7D670005D89D9 /* LLIntAssembly.h */; };
                709FB8651AE335C60039D069 /* WeakSetPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakSetPrototype.cpp; sourceTree = "<group>"; };
                709FB8661AE335C60039D069 /* WeakSetPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakSetPrototype.h; sourceTree = "<group>"; };
                70B0A9D01A9B66200001306A /* RuntimeFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeFlags.h; sourceTree = "<group>"; };
+               70B791831C024432002481E2 /* GeneratorFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GeneratorFrame.cpp; sourceTree = "<group>"; };
+               70B791841C024432002481E2 /* GeneratorFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratorFrame.h; sourceTree = "<group>"; };
+               70B791851C024432002481E2 /* GeneratorFunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GeneratorFunctionConstructor.cpp; sourceTree = "<group>"; };
+               70B791861C024432002481E2 /* GeneratorFunctionConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratorFunctionConstructor.h; sourceTree = "<group>"; };
+               70B791871C024432002481E2 /* GeneratorFunctionPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GeneratorFunctionPrototype.cpp; sourceTree = "<group>"; };
+               70B791881C024432002481E2 /* GeneratorFunctionPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratorFunctionPrototype.h; sourceTree = "<group>"; };
+               70B791891C024432002481E2 /* GeneratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GeneratorPrototype.cpp; sourceTree = "<group>"; };
+               70B7918A1C024432002481E2 /* GeneratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratorPrototype.h; sourceTree = "<group>"; };
+               70B7918B1C024432002481E2 /* GeneratorThisMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratorThisMode.h; sourceTree = "<group>"; };
+               70B7918C1C024462002481E2 /* JSGeneratorFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGeneratorFunction.cpp; sourceTree = "<group>"; };
+               70B7918D1C024462002481E2 /* JSGeneratorFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGeneratorFunction.h; sourceTree = "<group>"; };
+               70B7918E1C0244C9002481E2 /* SourceCodeKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceCodeKey.h; sourceTree = "<group>"; };
+               70B7918F1C0244EC002481E2 /* GeneratorPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = GeneratorPrototype.js; sourceTree = "<group>"; };
+               70B791901C0246CE002481E2 /* GeneratorPrototype.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratorPrototype.lut.h; sourceTree = "<group>"; };
                70DC3E071B2DF2C700054299 /* IteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IteratorPrototype.cpp; sourceTree = "<group>"; };
                70DC3E081B2DF2C700054299 /* IteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IteratorPrototype.h; sourceTree = "<group>"; };
                70DE9A081BE7D670005D89D9 /* LLIntAssembly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntAssembly.h; sourceTree = "<group>"; };
                                996B73081BD9FA2C00331B84 /* DateConstructor.lut.h */,
                                BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */,
                                996B73091BD9FA2C00331B84 /* ErrorPrototype.lut.h */,
+                               70B791901C0246CE002481E2 /* GeneratorPrototype.lut.h */,
                                6514F21818B3E1670098FF8B /* InitBytecodes.asm */,
                                A513E5C6185F9436007E95AD /* InjectedScriptSource.h */,
                                A5EA710D19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h */,
                                869EBCB60E8C6D4A008722CC /* ResultType.h */,
                                0F8F2B9D17306C8B007DBDA5 /* SourceCode.cpp */,
                                65E866EE0DD59AFA00A2B2A1 /* SourceCode.h */,
+                               70B7918E1C0244C9002481E2 /* SourceCodeKey.h */,
                                0F493AF816D0CAD10084508B /* SourceProvider.cpp */,
                                65E866ED0DD59AFA00A2B2A1 /* SourceProvider.h */,
                                E49DC15512EF277200184A1F /* SourceProviderCache.cpp */,
                                F692A85D0255597D01FF60F7 /* FunctionPrototype.h */,
                                62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */,
                                62D2D38E1ADF103F000206C1 /* FunctionRareData.h */,
+                               70B791831C024432002481E2 /* GeneratorFrame.cpp */,
+                               70B791841C024432002481E2 /* GeneratorFrame.h */,
+                               70B791851C024432002481E2 /* GeneratorFunctionConstructor.cpp */,
+                               70B791861C024432002481E2 /* GeneratorFunctionConstructor.h */,
+                               70B791871C024432002481E2 /* GeneratorFunctionPrototype.cpp */,
+                               70B791881C024432002481E2 /* GeneratorFunctionPrototype.h */,
+                               70B791891C024432002481E2 /* GeneratorPrototype.cpp */,
+                               70B7918A1C024432002481E2 /* GeneratorPrototype.h */,
+                               70B7918B1C024432002481E2 /* GeneratorThisMode.h */,
                                0FE050111AA9091100D33B33 /* GenericArguments.h */,
                                0FE050121AA9091100D33B33 /* GenericArgumentsInlines.h */,
                                0FE050131AA9091100D33B33 /* GenericOffset.h */,
                                F692A85E0255597D01FF60F7 /* JSFunction.cpp */,
                                F692A85F0255597D01FF60F7 /* JSFunction.h */,
                                A72028B91797603D0098028C /* JSFunctionInlines.h */,
+                               70B7918C1C024462002481E2 /* JSGeneratorFunction.cpp */,
+                               70B7918D1C024462002481E2 /* JSGeneratorFunction.h */,
                                0F2B66C317B6B5AB00A7AE3F /* JSGenericTypedArrayView.h */,
                                0F2B66C417B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h */,
                                0F2B66C517B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h */,
                                A75EE9B018AAB7E200AAD043 /* BuiltinNames.h */,
                                41DEA1311B9F3154006D65DD /* BuiltinUtils.h */,
                                A7A979C418BE8D9E002C3733 /* FunctionPrototype.js */,
+                               70B7918F1C0244EC002481E2 /* GeneratorPrototype.js */,
                                7CF9BC5A1B65D9A3009DB1EF /* GlobalObject.js */,
                                E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */,
                                E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */,
                                A737810E1799EA2E00817533 /* DFGNaturalLoops.h in Headers */,
                                86ECA3EA132DEF1C002B2AD7 /* DFGNode.h in Headers */,
                                0FFB921B16D02F010055A5DB /* DFGNodeAllocator.h in Headers */,
+                               70B791931C024A28002481E2 /* GeneratorFrame.h in Headers */,
                                0FA581BB150E953000B9A2D9 /* DFGNodeFlags.h in Headers */,
                                0F300B7818AB051100A6D72E /* DFGNodeOrigin.h in Headers */,
                                0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */,
                                0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */,
                                0F79085619A290B200F6310C /* DFGStructureRegistrationPhase.h in Headers */,
                                0F2FCCFF18A60070001A27F8 /* DFGThreadData.h in Headers */,
+                               70B791991C024A29002481E2 /* GeneratorPrototype.h in Headers */,
                                0FC097A2146B28CC00CF2442 /* DFGThunks.h in Headers */,
                                0FD8A32817D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.h in Headers */,
                                0FD8A32A17D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h in Headers */,
                                A50E4B6218809DD50068A46D /* InspectorRuntimeAgent.h in Headers */,
                                A593CF831840377100BFCE27 /* InspectorValues.h in Headers */,
                                969A07990ED1D3AE00F1F681 /* Instruction.h in Headers */,
+                               70B791911C024A13002481E2 /* SourceCodeKey.h in Headers */,
                                A7A8AF3B17ADB5F3005AB174 /* Int16Array.h in Headers */,
                                A7A8AF3C17ADB5F3005AB174 /* Int32Array.h in Headers */,
                                A7A8AF3A17ADB5F3005AB174 /* Int8Array.h in Headers */,
                                70113D4C1A8DB093003848C4 /* IteratorOperations.h in Headers */,
                                70DC3E0A1B2DF2C700054299 /* IteratorPrototype.h in Headers */,
                                BC18C4130E16F5CD00B34460 /* JavaScript.h in Headers */,
+                               70B791971C024A29002481E2 /* GeneratorFunctionPrototype.h in Headers */,
                                A503FA1A188E0FB000110F14 /* JavaScriptCallFrame.h in Headers */,
                                BC18C4140E16F5CD00B34460 /* JavaScriptCore.h in Headers */,
                                BC18C4150E16F5CD00B34460 /* JavaScriptCorePrefix.h in Headers */,
                                1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */,
                                0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */,
                                70ECA6061AFDBEA200449739 /* JSTemplateRegistryKey.h in Headers */,
+                               70B7919C1C024A49002481E2 /* JSGeneratorFunction.h in Headers */,
                                BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */,
                                0F2B66FB17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h in Headers */,
                                0F2B66FD17B6B5AB00A7AE3F /* JSTypedArrayPrototypes.h in Headers */,
                                FE187A021BFBE5610038BBCA /* JITMulGenerator.h in Headers */,
                                86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */,
                                0F431738146BAC69007E3890 /* ListableHandler.h in Headers */,
+                               70B791951C024A28002481E2 /* GeneratorFunctionConstructor.h in Headers */,
                                A7E2EA6B0FB460CF00601F06 /* LiteralParser.h in Headers */,
                                FE3913551B794F8A00EDAF71 /* LiveObjectData.h in Headers */,
                                FE3913561B794F8F00EDAF71 /* LiveObjectList.h in Headers */,
                                A55D93A6185012A800400DED /* ScriptFunctionCall.h in Headers */,
                                A54CF2FA184EAEDA00237F19 /* ScriptObject.h in Headers */,
                                A54CF2F6184EAB2400237F19 /* ScriptValue.h in Headers */,
+                               70B7919D1C024A56002481E2 /* GeneratorPrototype.lut.h in Headers */,
                                A7299DA617D12858005F5FF9 /* SetConstructor.h in Headers */,
                                A790DD6E182F499700588807 /* SetIteratorPrototype.h in Headers */,
                                A7299DA217D12848005F5FF9 /* SetPrototype.h in Headers */,
                                BC18C46A0E16F5CD00B34460 /* StringPrototype.h in Headers */,
                                0FB3878E1BFBC44D00E3AB1E /* AirBlockWorklist.h in Headers */,
                                142E313B134FF0A600AFADB5 /* Strong.h in Headers */,
+                               70B7919A1C024A29002481E2 /* GeneratorThisMode.h in Headers */,
                                145722861437E140005FDE26 /* StrongInlines.h in Headers */,
                                BCDE3AB80E6C82F5001453A7 /* Structure.h in Headers */,
                                7E4EE7090EBB7963005934AA /* StructureChain.h in Headers */,
                                A1B9E23D1B4E0D6700BC7FED /* IntlCollatorPrototype.cpp in Sources */,
                                A1587D6D1B4DC14100D69849 /* IntlDateTimeFormat.cpp in Sources */,
                                A1587D6F1B4DC14100D69849 /* IntlDateTimeFormatConstructor.cpp in Sources */,
+                               70B7919B1C024A46002481E2 /* JSGeneratorFunction.cpp in Sources */,
                                A1587D711B4DC14100D69849 /* IntlDateTimeFormatPrototype.cpp in Sources */,
                                A1D792FC1B43864B004516F5 /* IntlNumberFormat.cpp in Sources */,
                                A1D792FE1B43864B004516F5 /* IntlNumberFormatConstructor.cpp in Sources */,
                                0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */,
                                0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */,
                                FE4238901BE18C3C00514737 /* JITSubGenerator.cpp in Sources */,
+                               70B791941C024A28002481E2 /* GeneratorFunctionConstructor.cpp in Sources */,
                                0F5EF91E16878F7A003E5C25 /* JITThunks.cpp in Sources */,
                                0FC712E217CD8791008CC93C /* JITToDFGDeferredCompilationCallback.cpp in Sources */,
                                140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */,
                                142D6F0813539A2800B02E86 /* MarkedBlock.cpp in Sources */,
                                14D2F3DA139F4BE200491031 /* MarkedSpace.cpp in Sources */,
                                142D6F1113539A4100B02E86 /* MarkStack.cpp in Sources */,
+                               70B791981C024A29002481E2 /* GeneratorPrototype.cpp in Sources */,
                                4340A4841A9051AF00D73CCA /* MathCommon.cpp in Sources */,
                                0F37308C1C0BD29100052BFA /* B3PhiChildren.cpp in Sources */,
                                14469DDF107EC7E700650446 /* MathObject.cpp in Sources */,
                                0FF42745158EBE91004CB9FF /* udis86_syn-att.c in Sources */,
                                0FF42746158EBE91004CB9FF /* udis86_syn-intel.c in Sources */,
                                0FF42747158EBE91004CB9FF /* udis86_syn.c in Sources */,
+                               70B791961C024A28002481E2 /* GeneratorFunctionPrototype.cpp in Sources */,
                                0FF42732158EBD58004CB9FF /* UDis86Disassembler.cpp in Sources */,
                                A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */,
                                14142E551B7973C000F4BF4B /* UnlinkedFunctionExecutable.cpp in Sources */,
                                79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */,
                                0F6C73501AC9F99F00BE1682 /* VariableWriteFireDetail.cpp in Sources */,
                                0FE0502C1AA9095600D33B33 /* VarOffset.cpp in Sources */,
+                               70B791921C024A23002481E2 /* GeneratorFrame.cpp in Sources */,
                                0F20C2591A8013AB00DA3229 /* VirtualRegister.cpp in Sources */,
                                E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */,
                                FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */,
index 816b4a5..a9e69be 100644 (file)
@@ -82,7 +82,7 @@ UnlinkedFunctionExecutable* createExecutableInternal(VM& vm, const SourceCode& s
     RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr;
     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
         &vm, source, Identifier(), builtinMode,
-        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error,
+        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error,
         &positionBeforeLastNewline, constructorKind);
 
     if (!program) {
@@ -115,7 +115,7 @@ UnlinkedFunctionExecutable* createExecutableInternal(VM& vm, const SourceCode& s
     }
     metadata->overrideName(name);
     VariableEnvironment dummyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, dummyTDZVariables, WTF::move(sourceOverride));
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, GeneratorThisMode::NonEmpty, dummyTDZVariables, WTF::move(sourceOverride));
     functionExecutable->setNameValue(vm, jsString(&vm, name.string()));
     return functionExecutable;
 }
diff --git a/Source/JavaScriptCore/builtins/GeneratorPrototype.js b/Source/JavaScriptCore/builtins/GeneratorPrototype.js
new file mode 100644 (file)
index 0000000..a3bbc35
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// 25.3.3.3 GeneratorResume ( generator, value )
+// 25.3.3.4 GeneratorResumeAbrupt(generator, abruptCompletion)
+function generatorResume(generator, sentValue, resumeMode)
+{
+    "use strict";
+
+    // GeneratorState.
+    const Completed = -1;
+    const Executing = -2;
+
+    // ResumeMode.
+    const NormalMode = 0;
+    const ReturnMode = 1;
+    const ThrowMode = 2;
+
+    let state = generator.@generatorState;
+    let done = false;
+    let value = undefined;
+
+    if (typeof state !== 'number')
+        throw new @TypeError("|this| should be a generator");
+
+    if (state === Executing)
+        throw new @TypeError("Generator is executing");
+
+    if (state === Completed) {
+        if (resumeMode === ThrowMode)
+            throw sentValue;
+
+        done = true;
+        if (resumeMode === ReturnMode)
+            value = sentValue;
+    } else {
+        try {
+            generator.@generatorState = Executing;
+            value = generator.@generatorNext.@call(generator.@generatorThis, generator, state, sentValue, resumeMode);
+            if (generator.@generatorState === Executing) {
+                generator.@generatorState = Completed;
+                done = true;
+            }
+        } catch (error) {
+            generator.@generatorState = Completed;
+            throw error;
+        }
+    }
+    return { done, value };
+}
+
+function next(value)
+{
+    "use strict";
+
+    return @generatorResume(this, value, /* NormalMode */ 0);
+}
+
+function return(value)
+{
+    "use strict";
+
+    return @generatorResume(this, value, /* ReturnMode */ 1);
+}
+
+function throw(exception)
+{
+    "use strict";
+
+    return @generatorResume(this, exception, /* ThrowMode */ 2);
+}
index 54dfd16..596064c 100644 (file)
@@ -59,6 +59,7 @@ static bool isBranch(OpcodeID opcodeID)
     case op_switch_char:
     case op_switch_string:
     case op_check_has_instance:
+    case op_save:
         return true;
     default:
         return false;
index f6c89a9..43d7012 100644 (file)
@@ -90,6 +90,8 @@
             { "name" : "op_switch_string", "length" : 4 },
             { "name" : "op_new_func", "length" : 4 },
             { "name" : "op_new_func_exp", "length" : 4 },
+            { "name" : "op_new_generator_func", "length" : 4 },
+            { "name" : "op_new_generator_func_exp", "length" : 4 },
             { "name" : "op_new_arrow_func_exp", "length" : 5 },
             { "name" : "op_call", "length" : 9 },
             { "name" : "op_tail_call", "length" : 9 },
             { "name" : "op_load_arrowfunction_this", "length" : 2 },
             { "name" : "op_assert", "length" : 3 },
             { "name" : "op_copy_rest", "length": 4 },
-            { "name" : "op_get_rest_length", "length": 3 }
+            { "name" : "op_get_rest_length", "length": 3 },
+            { "name" : "op_save", "length" : 4 },
+            { "name" : "op_resume", "length" : 3 }
         ]
     },
     {
index c77abea..7228b03 100644 (file)
@@ -98,7 +98,7 @@ static BytecodeBasicBlock* findBasicBlockForBytecodeOffset(Vector<std::unique_pt
 // Simplified interface to bytecode use/def, which determines defs first and then uses, and includes
 // exception handlers in the uses.
 template<typename UseFunctor, typename DefFunctor>
-static void stepOverInstruction(CodeBlock* codeBlock, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def)
+static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def)
 {
     // This abstractly execute the instruction in reverse. Instructions logically first use operands and
     // then define operands. This logical ordering is necessary for operations that use and def the same
@@ -116,19 +116,19 @@ static void stepOverInstruction(CodeBlock* codeBlock, Vector<std::unique_ptr<Byt
     // first add it to the out set (the use), and then we'd remove it (the def).
     
     computeDefsForBytecodeOffset(
-        codeBlock, bytecodeOffset,
+        codeBlock, block, bytecodeOffset,
         [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) {
             if (isValidRegisterForLiveness(codeBlock, operand))
                 def(VirtualRegister(operand).toLocal());
         });
 
     computeUsesForBytecodeOffset(
-        codeBlock, bytecodeOffset,
+        codeBlock, block, bytecodeOffset,
         [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) {
             if (isValidRegisterForLiveness(codeBlock, operand))
                 use(VirtualRegister(operand).toLocal());
         });
-        
+
     // If we have an exception handler, we want the live-in variables of the 
     // exception handler block to be included in the live-in of this particular bytecode.
     if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset)) {
@@ -138,10 +138,10 @@ static void stepOverInstruction(CodeBlock* codeBlock, Vector<std::unique_ptr<Byt
     }
 }
 
-static void stepOverInstruction(CodeBlock* codeBlock, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& out)
+static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& out)
 {
     stepOverInstruction(
-        codeBlock, basicBlocks, bytecodeOffset,
+        codeBlock, block, basicBlocks, bytecodeOffset,
         [&] (unsigned bitIndex) {
             // This is the use functor, so we set the bit.
             out.set(bitIndex);
@@ -164,7 +164,7 @@ static void computeLocalLivenessForBytecodeOffset(CodeBlock* codeBlock, Bytecode
         if (targetOffset > bytecodeOffset)
             break;
         
-        stepOverInstruction(codeBlock, basicBlocks, bytecodeOffset, out);
+        stepOverInstruction(codeBlock, block, basicBlocks, bytecodeOffset, out);
     }
 
     result.set(out);
@@ -180,7 +180,7 @@ static void computeLocalLivenessForBlock(CodeBlock* codeBlock, BytecodeBasicBloc
 void BytecodeLivenessAnalysis::runLivenessFixpoint()
 {
     UnlinkedCodeBlock* unlinkedCodeBlock = m_codeBlock->unlinkedCodeBlock();
-    unsigned numberOfVariables = unlinkedCodeBlock->m_numCalleeRegisters;
+    unsigned numberOfVariables = unlinkedCodeBlock->m_numCalleeLocals;
 
     for (unsigned i = 0; i < m_basicBlocks.size(); i++) {
         BytecodeBasicBlock* block = m_basicBlocks[i].get();
@@ -248,7 +248,7 @@ void BytecodeLivenessAnalysis::computeFullLiveness(FullBytecodeLiveness& result)
         
         for (unsigned i = block->bytecodeOffsets().size(); i--;) {
             unsigned bytecodeOffset = block->bytecodeOffsets()[i];
-            stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, out);
+            stepOverInstruction(m_codeBlock, block, m_basicBlocks, bytecodeOffset, out);
             result.m_map[bytecodeOffset] = out;
         }
     }
@@ -271,7 +271,7 @@ void BytecodeLivenessAnalysis::computeKills(BytecodeKills& result)
         for (unsigned i = block->bytecodeOffsets().size(); i--;) {
             unsigned bytecodeOffset = block->bytecodeOffsets()[i];
             stepOverInstruction(
-                m_codeBlock, m_basicBlocks, bytecodeOffset,
+                m_codeBlock, block, m_basicBlocks, bytecodeOffset,
                 [&] (unsigned index) {
                     // This is for uses.
                     if (out.get(index))
index cbb8948..fe026fa 100644 (file)
@@ -32,7 +32,7 @@ namespace JSC {
 
 template<typename Functor>
 void computeUsesForBytecodeOffset(
-    CodeBlock* codeBlock, unsigned bytecodeOffset, const Functor& functor)
+    CodeBlock* codeBlock, BytecodeBasicBlock* block, unsigned bytecodeOffset, const Functor& functor)
 {
     Interpreter* interpreter = codeBlock->vm()->interpreter;
     Instruction* instructionsBegin = codeBlock->instructions().begin();
@@ -71,7 +71,8 @@ void computeUsesForBytecodeOffset(
     case op_jeq_null:
     case op_jneq_null:
     case op_dec:
-    case op_inc: {
+    case op_inc:
+    case op_resume: {
         functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
         return;
     }
@@ -125,6 +126,7 @@ void computeUsesForBytecodeOffset(
     case op_get_property_enumerator:
     case op_get_enumerable_length:
     case op_new_func_exp:
+    case op_new_generator_func_exp:
     case op_new_arrow_func_exp:
     case op_to_index_string:
     case op_create_lexical_environment:
@@ -153,6 +155,7 @@ void computeUsesForBytecodeOffset(
     case op_del_by_id:
     case op_unsigned:
     case op_new_func:
+    case op_new_generator_func:
     case op_get_parent_scope:
     case op_create_scoped_arguments:
     case op_get_from_arguments: {
@@ -234,6 +237,22 @@ void computeUsesForBytecodeOffset(
             functor(codeBlock, instruction, opcodeID, lastArg + i);
         return;
     }
+    case op_save: {
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        unsigned mergePointBytecodeOffset = bytecodeOffset + instruction[3].u.operand;
+        BytecodeBasicBlock* mergePointBlock = nullptr;
+        for (BytecodeBasicBlock* successor : block->successors()) {
+            if (successor->leaderBytecodeOffset() == mergePointBytecodeOffset) {
+                mergePointBlock = successor;
+                break;
+            }
+        }
+        ASSERT(mergePointBlock);
+        mergePointBlock->in().forEachSetBit([&](unsigned local) {
+            functor(codeBlock, instruction, opcodeID, virtualRegisterForLocal(local).offset());
+        });
+        return;
+    }
     default:
         RELEASE_ASSERT_NOT_REACHED();
         break;
@@ -241,7 +260,7 @@ void computeUsesForBytecodeOffset(
 }
 
 template<typename Functor>
-void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, const Functor& functor)
+void computeDefsForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* block, unsigned bytecodeOffset, const Functor& functor)
 {
     Interpreter* interpreter = codeBlock->vm()->interpreter;
     Instruction* instructionsBegin = codeBlock->instructions().begin();
@@ -256,6 +275,7 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_profile_did_call:
     case op_throw:
     case op_throw_static_error:
+    case op_save:
     case op_assert:
     case op_debug:
     case op_ret:
@@ -316,6 +336,8 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_new_regexp:
     case op_new_func:
     case op_new_func_exp:
+    case op_new_generator_func:
+    case op_new_generator_func_exp:
     case op_new_arrow_func_exp:
     case op_call_varargs:
     case op_tail_call_varargs:
@@ -392,7 +414,15 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
         for (unsigned i = codeBlock->m_numVars; i--;)
             functor(codeBlock, instruction, opcodeID, virtualRegisterForLocal(i).offset());
         return;
-    } }
+    }
+    case op_resume: {
+        RELEASE_ASSERT(block->successors().size() == 1);
+        block->successors()[0]->in().forEachSetBit([&](unsigned local) {
+            functor(codeBlock, instruction, opcodeID, virtualRegisterForLocal(local).offset());
+        });
+        return;
+    }
+    }
 }
 
 } // namespace JSC
index 9e1386e..0ab781c 100644 (file)
@@ -585,7 +585,7 @@ void CodeBlock::dumpBytecode(PrintStream& out)
         ": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
         static_cast<unsigned long>(instructions().size()),
         static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
-        m_numParameters, m_numCalleeRegisters, m_numVars);
+        m_numParameters, m_numCalleeLocals, m_numVars);
     if (needsActivation() && codeType() == FunctionCode)
         out.printf("; lexical environment in r%d", activationRegister().offset());
     out.printf("\n");
@@ -680,6 +680,18 @@ void CodeBlock::dumpBytecode(PrintStream& out)
         } while (i < m_rareData->m_stringSwitchJumpTables.size());
     }
 
+    if (m_rareData && !m_rareData->m_liveCalleeLocalsAtYield.isEmpty()) {
+        out.printf("\nLive Callee Locals:\n");
+        unsigned i = 0;
+        do {
+            const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[i];
+            out.printf("  live%1u = ", i);
+            liveness.dump(out);
+            out.printf("\n");
+            ++i;
+        } while (i < m_rareData->m_liveCalleeLocalsAtYield.size());
+    }
+
     out.printf("\n");
 }
 
@@ -1303,6 +1315,14 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
             break;
         }
+        case op_new_generator_func: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int f0 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "new_generator_func");
+            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+            break;
+        }
         case op_new_arrow_func_exp: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
@@ -1320,6 +1340,14 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
             break;
         }
+        case op_new_generator_func_exp: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int f0 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "new_generator_func_exp");
+            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+            break;
+        }
         case op_call: {
             printCallOp(out, exec, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos);
             break;
@@ -1508,6 +1536,27 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %d", debugHookName(debugHookID), hasBreakpointFlag);
             break;
         }
+        case op_save: {
+            int generator = (++it)->u.operand;
+            unsigned liveCalleeLocalsIndex = (++it)->u.unsignedValue;
+            int offset = (++it)->u.operand;
+            const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex];
+            printLocationAndOp(out, exec, location, it, "save");
+            out.printf("%s, ", registerName(generator).data());
+            liveness.dump(out);
+            out.printf("(@live%1u), %d(->%d)", liveCalleeLocalsIndex, offset, location + offset);
+            break;
+        }
+        case op_resume: {
+            int generator = (++it)->u.operand;
+            unsigned liveCalleeLocalsIndex = (++it)->u.unsignedValue;
+            const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex];
+            printLocationAndOp(out, exec, location, it, "resume");
+            out.printf("%s, ", registerName(generator).data());
+            liveness.dump(out);
+            out.printf("(@live%1u)", liveCalleeLocalsIndex);
+            break;
+        }
         case op_assert: {
             int condition = (++it)->u.operand;
             int line = (++it)->u.operand;
@@ -1672,7 +1721,7 @@ CodeBlock::CodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, CodeBlock
     : JSCell(*vm, structure)
     , m_globalObject(other.m_globalObject)
     , m_heap(other.m_heap)
-    , m_numCalleeRegisters(other.m_numCalleeRegisters)
+    , m_numCalleeLocals(other.m_numCalleeLocals)
     , m_numVars(other.m_numVars)
     , m_isConstructor(other.m_isConstructor)
     , m_shouldAlwaysBeInlined(true)
@@ -1729,6 +1778,7 @@ void CodeBlock::finishCreation(VM& vm, CopyParsedBlockTag, CodeBlock& other)
         m_rareData->m_constantBuffers = other.m_rareData->m_constantBuffers;
         m_rareData->m_switchJumpTables = other.m_rareData->m_switchJumpTables;
         m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
+        m_rareData->m_liveCalleeLocalsAtYield = other.m_rareData->m_liveCalleeLocalsAtYield;
     }
     
     m_heap->m_codeBlocks.add(this);
@@ -1739,7 +1789,7 @@ CodeBlock::CodeBlock(VM* vm, Structure* structure, ScriptExecutable* ownerExecut
     : JSCell(*vm, structure)
     , m_globalObject(scope->globalObject()->vm(), this, scope->globalObject())
     , m_heap(&m_globalObject->vm().heap)
-    , m_numCalleeRegisters(unlinkedCodeBlock->m_numCalleeRegisters)
+    , m_numCalleeLocals(unlinkedCodeBlock->m_numCalleeLocals)
     , m_numVars(unlinkedCodeBlock->m_numVars)
     , m_isConstructor(unlinkedCodeBlock->isConstructor())
     , m_shouldAlwaysBeInlined(true)
@@ -1909,6 +1959,9 @@ void CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
     // Bookkeep the strongly referenced module environments.
     HashSet<JSModuleEnvironment*> stronglyReferencedModuleEnvironments;
 
+    // Bookkeep the merge point bytecode offsets.
+    Vector<size_t> mergePointBytecodeOffsets;
+
     RefCountedArray<Instruction> instructions(instructionCount);
 
     for (unsigned i = 0; !instructionReader.atEnd(); ) {
@@ -2197,6 +2250,15 @@ void CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
             break;
         }
 
+        case op_save: {
+            unsigned liveCalleeLocalsIndex = pc[2].u.index;
+            int offset = pc[3].u.operand;
+            if (liveCalleeLocalsIndex >= mergePointBytecodeOffsets.size())
+                mergePointBytecodeOffsets.resize(liveCalleeLocalsIndex + 1);
+            mergePointBytecodeOffsets[liveCalleeLocalsIndex] = i + offset;
+            break;
+        }
+
         default:
             break;
         }
@@ -2208,6 +2270,20 @@ void CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
 
     m_instructions = WTF::move(instructions);
 
+    // Perform bytecode liveness analysis to determine which locals are live and should be resumed when executing op_resume.
+    if (unlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode) {
+        if (size_t count = mergePointBytecodeOffsets.size()) {
+            createRareDataIfNecessary();
+            BytecodeLivenessAnalysis liveness(this);
+            m_rareData->m_liveCalleeLocalsAtYield.grow(count);
+            size_t liveCalleeLocalsIndex = 0;
+            for (size_t bytecodeOffset : mergePointBytecodeOffsets) {
+                m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex] = liveness.getLivenessInfoAtBytecodeOffset(bytecodeOffset);
+                ++liveCalleeLocalsIndex;
+            }
+        }
+    }
+
     // Set optimization thresholds only after m_instructions is initialized, since these
     // rely on the instruction count (and are in theory permitted to also inspect the
     // instruction stream to more accurate assess the cost of tier-up).
@@ -2231,7 +2307,7 @@ CodeBlock::CodeBlock(VM* vm, Structure* structure, WebAssemblyExecutable* ownerE
     : JSCell(*vm, structure)
     , m_globalObject(globalObject->vm(), this, globalObject)
     , m_heap(&m_globalObject->vm().heap)
-    , m_numCalleeRegisters(0)
+    , m_numCalleeLocals(0)
     , m_numVars(0)
     , m_isConstructor(false)
     , m_shouldAlwaysBeInlined(false)
@@ -3058,6 +3134,7 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
         if (m_rareData) {
             m_rareData->m_switchJumpTables.shrinkToFit();
             m_rareData->m_stringSwitchJumpTables.shrinkToFit();
+            m_rareData->m_liveCalleeLocalsAtYield.shrinkToFit();
         }
     } // else don't shrink these, because we would have already pointed pointers into these tables.
 }
@@ -4029,7 +4106,7 @@ void CodeBlock::validate()
     
     FastBitVector liveAtHead = liveness.getLivenessInfoAtBytecodeOffset(0);
     
-    if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeRegisters)) {
+    if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeLocals)) {
         beginValidationDidFail();
         dataLog("    Wrong number of bits in result!\n");
         dataLog("    Result: ", liveAtHead, "\n");
@@ -4037,7 +4114,7 @@ void CodeBlock::validate()
         endValidationDidFail();
     }
     
-    for (unsigned i = m_numCalleeRegisters; i--;) {
+    for (unsigned i = m_numCalleeLocals; i--;) {
         VirtualRegister reg = virtualRegisterForLocal(i);
         
         if (liveAtHead.get(i)) {
index c1df187..3cbe75c 100644 (file)
@@ -69,6 +69,7 @@
 #include "VirtualRegister.h"
 #include "Watchpoint.h"
 #include <wtf/Bag.h>
+#include <wtf/FastBitVector.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/RefCountedArray.h>
 #include <wtf/RefPtr.h>
@@ -141,6 +142,8 @@ public:
     int numParameters() const { return m_numParameters; }
     void setNumParameters(int newValue);
 
+    int numCalleeLocals() const { return m_numCalleeLocals; }
+
     int* addressOfNumParameters() { return &m_numParameters; }
     static ptrdiff_t offsetOfNumParameters() { return OBJECT_OFFSETOF(CodeBlock, m_numParameters); }
 
@@ -654,6 +657,18 @@ public:
     StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
     StringJumpTable& stringSwitchJumpTable(int tableIndex) { RELEASE_ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
 
+    // Live callee registers at yield points.
+    const FastBitVector& liveCalleeLocalsAtYield(unsigned index) const
+    {
+        RELEASE_ASSERT(m_rareData);
+        return m_rareData->m_liveCalleeLocalsAtYield[index];
+    }
+    FastBitVector& liveCalleeLocalsAtYield(unsigned index)
+    {
+        RELEASE_ASSERT(m_rareData);
+        return m_rareData->m_liveCalleeLocalsAtYield[index];
+    }
+
     EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; }
 
     enum ShrinkMode {
@@ -855,7 +870,7 @@ public:
     // FIXME: Make these remaining members private.
 
     int m_numLocalRegistersForCalleeSaves;
-    int m_numCalleeRegisters;
+    int m_numCalleeLocals;
     int m_numVars;
     bool m_isConstructor : 1;
     
@@ -900,6 +915,8 @@ public:
         Vector<SimpleJumpTable> m_switchJumpTables;
         Vector<StringJumpTable> m_stringSwitchJumpTables;
 
+        Vector<FastBitVector> m_liveCalleeLocalsAtYield;
+
         EvalCodeCache m_evalCodeCache;
     };
 
index 62521fc..83703cf 100644 (file)
@@ -34,6 +34,7 @@
 #include "JSScope.h"
 #include "Options.h"
 #include "SourceCode.h"
+#include "SourceCodeKey.h"
 #include <wtf/HashMap.h>
 #include <wtf/RefPtr.h>
 #include <wtf/text/StringHash.h>
@@ -44,23 +45,29 @@ namespace JSC {
 
     class EvalCodeCache {
     public:
-        EvalExecutable* tryGet(bool inStrictContext, const String& evalSource, JSScope* scope)
+        EvalExecutable* tryGet(bool inStrictContext, const SourceCode& evalSource, ThisTDZMode thisTDZMode, JSScope* scope)
         {
-            if (isCacheable(inStrictContext, evalSource, scope))
-                return m_cacheMap.get(evalSource.impl()).get();
-            return 0;
+            if (isCacheable(inStrictContext, evalSource, scope)) {
+                ASSERT(!inStrictContext);
+                SourceCodeKey sourceCodeKey(evalSource, String(), SourceCodeKey::EvalType, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, thisTDZMode);
+                return m_cacheMap.get(sourceCodeKey).get();
+            }
+            return nullptr;
         }
         
-        EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const String& evalSource, JSScope* scope)
+        EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const SourceCode& evalSource, JSScope* scope)
         {
             VariableEnvironment variablesUnderTDZ;
             JSScope::collectVariablesUnderTDZ(scope, variablesUnderTDZ);
-            EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext, thisTDZMode, &variablesUnderTDZ);
+            EvalExecutable* evalExecutable = EvalExecutable::create(exec, evalSource, inStrictContext, thisTDZMode, &variablesUnderTDZ);
             if (!evalExecutable)
-                return 0;
+                return nullptr;
 
-            if (isCacheable(inStrictContext, evalSource, scope) && m_cacheMap.size() < maxCacheEntries)
-                m_cacheMap.set(evalSource.impl(), WriteBarrier<EvalExecutable>(exec->vm(), owner, evalExecutable));
+            if (isCacheable(inStrictContext, evalSource, scope) && m_cacheMap.size() < maxCacheEntries) {
+                ASSERT(!inStrictContext);
+                SourceCodeKey sourceCodeKey(evalSource, String(), SourceCodeKey::EvalType, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, thisTDZMode);
+                m_cacheMap.set(sourceCodeKey, WriteBarrier<EvalExecutable>(exec->vm(), owner, evalExecutable));
+            }
             
             return evalExecutable;
         }
@@ -80,17 +87,17 @@ namespace JSC {
             return scope->isGlobalLexicalEnvironment() || scope->isFunctionNameScopeObject() || scope->isVarScope();
         }
 
-        ALWAYS_INLINE bool isCacheable(bool inStrictContext, const String& evalSource, JSScope* scope)
+        ALWAYS_INLINE bool isCacheable(bool inStrictContext, const SourceCode& evalSource, JSScope* scope)
         {
             // If eval() is called and it has access to a lexical scope, we can't soundly cache it.
             // If the eval() only has access to the "var" scope, then we can cache it.
             return !inStrictContext 
-                && evalSource.length() < Options::maximumEvalCacheableSourceLength() 
+                && static_cast<size_t>(evalSource.length()) < Options::maximumEvalCacheableSourceLength()
                 && isCacheableScope(scope);
         }
         static const int maxCacheEntries = 64;
 
-        typedef HashMap<RefPtr<StringImpl>, WriteBarrier<EvalExecutable>> EvalCacheMap;
+        typedef HashMap<SourceCodeKey, WriteBarrier<EvalExecutable>, SourceCodeKeyHash, SourceCodeKeyHashTraits> EvalCacheMap;
         EvalCacheMap m_cacheMap;
     };
 
index 92144f8..2602be7 100644 (file)
 #ifndef ExecutableInfo_h
 #define ExecutableInfo_h
 
+#include "GeneratorThisMode.h"
 #include "ParserModes.h"
 
 namespace JSC {
 
+// FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
+// https://bugs.webkit.org/show_bug.cgi?id=151547
 struct ExecutableInfo {
-    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, bool isArrowFunction)
+    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, GeneratorThisMode generatorThisMode, SuperBinding superBinding, SourceParseMode parseMode)
         : m_needsActivation(needsActivation)
         , m_usesEval(usesEval)
         , m_isStrictMode(isStrictMode)
         , m_isConstructor(isConstructor)
         , m_isBuiltinFunction(isBuiltinFunction)
+        , m_generatorThisMode(static_cast<unsigned>(generatorThisMode))
         , m_constructorKind(static_cast<unsigned>(constructorKind))
-        , m_isArrowFunction(isArrowFunction)
+        , m_superBinding(static_cast<unsigned>(superBinding))
+        , m_parseMode(parseMode)
     {
         ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
+        ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
+        ASSERT(m_generatorThisMode == static_cast<unsigned>(generatorThisMode));
     }
 
     bool needsActivation() const { return m_needsActivation; }
@@ -48,8 +55,10 @@ struct ExecutableInfo {
     bool isStrictMode() const { return m_isStrictMode; }
     bool isConstructor() const { return m_isConstructor; }
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
+    GeneratorThisMode generatorThisMode() const { return static_cast<GeneratorThisMode>(m_generatorThisMode); }
     ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
-    bool isArrowFunction() const { return m_isArrowFunction; }
+    SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
+    SourceParseMode parseMode() const { return m_parseMode; }
 
 private:
     unsigned m_needsActivation : 1;
@@ -57,8 +66,10 @@ private:
     unsigned m_isStrictMode : 1;
     unsigned m_isConstructor : 1;
     unsigned m_isBuiltinFunction : 1;
+    unsigned m_generatorThisMode : 1;
     unsigned m_constructorKind : 2;
-    unsigned m_isArrowFunction : 1;
+    unsigned m_superBinding : 1;
+    SourceParseMode m_parseMode;
 };
 
 } // namespace JSC
index d60fdf7..2bbf313 100644 (file)
@@ -54,6 +54,7 @@ static void getJumpTargetsForBytecodeOffset(CodeBlock* codeBlock, Interpreter* i
     case op_jnlesseq:
     case op_jngreater:
     case op_jngreatereq:
+    case op_save: // The jump of op_save is purely for calculating liveness.
         out.append(bytecodeOffset + current[3].u.operand);
         break;
     case op_switch_imm:
index c114b9b..87e8233 100644 (file)
@@ -54,7 +54,7 @@ const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock
 UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info)
     : Base(*vm, structure)
     , m_numVars(0)
-    , m_numCalleeRegisters(0)
+    , m_numCalleeLocals(0)
     , m_numParameters(0)
     , m_vm(vm)
     , m_globalObjectRegister(VirtualRegister())
@@ -65,10 +65,12 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code
     , m_hasCapturedVariables(false)
     , m_isBuiltinFunction(info.isBuiltinFunction())
     , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
-    , m_isArrowFunction(info.isArrowFunction())
+    , m_generatorThisMode(static_cast<unsigned>(info.generatorThisMode()))
+    , m_superBinding(static_cast<unsigned>(info.superBinding()))
     , m_firstLine(0)
     , m_lineCount(0)
     , m_endColumn(UINT_MAX)
+    , m_parseMode(info.parseMode())
     , m_features(0)
     , m_codeType(codeType)
     , m_arrayProfileCount(0)
index fa514c1..bca2c04 100644 (file)
@@ -31,6 +31,7 @@
 #include "CodeType.h"
 #include "ConstructAbility.h"
 #include "ExpressionRangeInfo.h"
+#include "GeneratorThisMode.h"
 #include "HandlerInfo.h"
 #include "Identifier.h"
 #include "JSCell.h"
@@ -41,6 +42,7 @@
 #include "UnlinkedFunctionExecutable.h"
 #include "VariableEnvironment.h"
 #include "VirtualRegister.h"
+#include <wtf/FastBitVector.h>
 #include <wtf/RefCountedArray.h>
 #include <wtf/Vector.h>
 
@@ -116,7 +118,7 @@ public:
     bool isConstructor() const { return m_isConstructor; }
     bool isStrictMode() const { return m_isStrictMode; }
     bool usesEval() const { return m_usesEval; }
-    bool isArrowFunction() const { return m_isArrowFunction; }
+    SourceParseMode parseMode() const { return m_parseMode; }
 
     bool needsFullScopeChain() const { return m_needsFullScopeChain; }
 
@@ -202,6 +204,8 @@ public:
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
 
     ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+    GeneratorThisMode generatorThisMode() const { return static_cast<GeneratorThisMode>(m_generatorThisMode); }
+    SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
 
     void shrinkToFit()
     {
@@ -232,7 +236,7 @@ public:
 
     int m_numVars;
     int m_numCapturedVars;
-    int m_numCalleeRegisters;
+    int m_numCalleeLocals;
 
     // Jump Tables
 
@@ -387,12 +391,14 @@ private:
     unsigned m_hasCapturedVariables : 1;
     unsigned m_isBuiltinFunction : 1;
     unsigned m_constructorKind : 2;
-    unsigned m_isArrowFunction : 1;
+    unsigned m_generatorThisMode : 1;
+    unsigned m_superBinding : 1;
 
     unsigned m_firstLine;
     unsigned m_lineCount;
     unsigned m_endColumn;
 
+    SourceParseMode m_parseMode;
     CodeFeatures m_features;
     CodeType m_codeType;
 
index 6da1859..3f49488 100644 (file)
@@ -50,13 +50,13 @@ const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutab
 static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source,
     CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode,
-    UnlinkedFunctionKind functionKind, ParserError& error, bool isArrowFunction)
+    UnlinkedFunctionKind functionKind, ParserError& error, SourceParseMode parseMode)
 {
     JSParserBuiltinMode builtinMode = executable->isBuiltinFunction() ? JSParserBuiltinMode::Builtin : JSParserBuiltinMode::NotBuiltin;
     JSParserStrictMode strictMode = executable->isInStrictContext() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
     ASSERT(isFunctionParseMode(executable->parseMode()));
     std::unique_ptr<FunctionNode> function = parse<FunctionNode>(
-        &vm, source, executable->name(), builtinMode, strictMode, executable->parseMode(), error, nullptr);
+        &vm, source, executable->name(), builtinMode, strictMode, executable->parseMode(), executable->superBinding(), error, nullptr);
 
     if (!function) {
         ASSERT(error.isValid());
@@ -67,7 +67,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     executable->recordParse(function->features(), function->hasCapturedVariables());
     
     UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode,
-        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), isArrowFunction));
+        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), executable->generatorThisMode(), executable->superBinding(), parseMode));
     auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode, executable->parentScopeTDZVariables()));
     error = generator->generate();
     if (error.isValid())
@@ -75,7 +75,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     return result;
 }
 
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables)
     : Base(*vm, structure)
     , m_name(node->ident())
     , m_inferredName(node->inferredName())
@@ -99,7 +99,8 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_constructAbility(static_cast<unsigned>(constructAbility))
     , m_constructorKind(static_cast<unsigned>(node->constructorKind()))
     , m_functionMode(node->functionMode())
-    , m_isArrowFunction(node->isArrowFunction())
+    , m_generatorThisMode(static_cast<unsigned>(generatorThisMode))
+    , m_superBinding(static_cast<unsigned>(node->superBinding()))
 {
     ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
     m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
@@ -180,7 +181,7 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
 
 UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
     VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, 
-    DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, bool isArrowFunction)
+    DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, SourceParseMode parseMode)
 {
     switch (specializationKind) {
     case CodeForCall:
@@ -196,7 +197,7 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
     UnlinkedFunctionCodeBlock* result = generateUnlinkedFunctionCodeBlock(
         vm, this, source, specializationKind, debuggerMode, profilerMode, 
         isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, 
-        error, isArrowFunction);
+        error, parseMode);
     
     if (error.isValid())
         return nullptr;
index d8e8229..c8bba0a 100644 (file)
@@ -31,6 +31,7 @@
 #include "CodeType.h"
 #include "ConstructAbility.h"
 #include "ExpressionRangeInfo.h"
+#include "GeneratorThisMode.h"
 #include "HandlerInfo.h"
 #include "Identifier.h"
 #include "JSCell.h"
@@ -65,10 +66,10 @@ public:
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
+    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
     {
         UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
-            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, parentScopeTDZVariables);
+            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, generatorThisMode, parentScopeTDZVariables);
         instance->finishCreation(*vm);
         return instance;
     }
@@ -82,6 +83,8 @@ public:
     bool isInStrictContext() const { return m_isInStrictContext; }
     FunctionMode functionMode() const { return static_cast<FunctionMode>(m_functionMode); }
     ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+    GeneratorThisMode generatorThisMode() const { return static_cast<GeneratorThisMode>(m_generatorThisMode); }
+    SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
 
     unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; }
     unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; }
@@ -95,7 +98,7 @@ public:
 
     UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
         VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, 
-        ParserError&, bool);
+        ParserError&, SourceParseMode);
 
     static UnlinkedFunctionExecutable* fromGlobalCode(
         const Identifier&, ExecState&, const SourceCode&, JSObject*& exception, 
@@ -125,10 +128,9 @@ public:
     ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
     bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
     const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
-    bool isArrowFunction() const { return m_isArrowFunction; }
 
 private:
-    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, VariableEnvironment&);
+    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, GeneratorThisMode, VariableEnvironment&);
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
 
@@ -158,7 +160,8 @@ private:
     unsigned m_constructAbility: 1;
     unsigned m_constructorKind : 2;
     unsigned m_functionMode : 1; // FunctionMode
-    unsigned m_isArrowFunction : 1;
+    unsigned m_generatorThisMode : 1;
+    unsigned m_superBinding : 1;
 
 protected:
     void finishCreation(VM& vm)
index 41a64c9..445d3d5 100644 (file)
 #include "BytecodeGenerator.h"
 
 #include "BuiltinExecutables.h"
+#include "BytecodeLivenessAnalysis.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
+#include "JSGeneratorFunction.h"
 #include "JSLexicalEnvironment.h"
 #include "JSTemplateRegistryKey.h"
 #include "LowLevelInterpreter.h"
@@ -227,9 +229,33 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
         }
     }
 
+    SourceParseMode parseMode = codeBlock->parseMode();
     bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain();
     bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
     bool needsArguments = functionNode->usesArguments() || codeBlock->usesEval();
+
+    // Generator never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
+    if (parseMode == SourceParseMode::GeneratorBodyMode)
+        needsArguments = false;
+
+    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode && needsArguments) {
+        // Generator does not provide "arguments". Instead, wrapping GeneratorFunction provides "arguments".
+        // This is because arguments of a generator should be evaluated before starting it.
+        // To workaround it, we evaluate these arguments as arguments of a wrapping generator function, and reference it from a generator.
+        //
+        //    function *gen(a, b = hello())
+        //    {
+        //        return {
+        //            @generatorNext: function (@generator, @generatorState, @generatorValue, @generatorResumeMode)
+        //            {
+        //                arguments;  // This `arguments` should reference to the gen's arguments.
+        //                ...
+        //            }
+        //        }
+        //    }
+        shouldCaptureSomeOfTheThings = true;
+    }
+
     if (shouldCaptureAllOfTheThings)
         functionNode->varDeclarations().markAllVariablesAsCaptured();
     
@@ -254,14 +280,33 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     allocateAndEmitScope();
     
     m_calleeRegister.setIndex(JSStack::Callee);
-    
+
+    initializeParameters(parameters);
+
+    // Before emitting a scope creation, emit a generator prologue that contains jump based on a generator's state.
+    if (parseMode == SourceParseMode::GeneratorBodyMode) {
+        m_generatorRegister = &m_parameters[1];
+        if (generatorThisMode() == GeneratorThisMode::Empty)
+            emitMoveEmptyValue(&m_thisRegister);
+
+        // Jump with switch_imm based on @generatorState. We don't take the coroutine styled generator implementation.
+        // When calling `next()`, we would like to enter the same prologue instead of jumping based on the saved instruction pointer.
+        // It's suitale for inlining, because it just inlines one `next` function implementation.
+
+        beginGenerator(generatorStateRegister());
+
+        // Initial state.
+        emitGeneratorStateLabel();
+    }
+
     if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode())) {
+        ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
         bool isDynamicScope = functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode());
         bool isFunctionNameCaptured = captures(functionNode->ident().impl());
         bool markAsCaptured = isDynamicScope || isFunctionNameCaptured;
         emitPushFunctionNameScope(functionNode->ident(), &m_calleeRegister, markAsCaptured);
     }
-    
+
     if (shouldCaptureSomeOfTheThings) {
         m_lexicalEnvironmentRegister = addVar();
         // We can allocate the "var" environment if we don't have default parameter expressions. If we have
@@ -271,19 +316,6 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             initializeVarLexicalEnvironment(symbolTableConstantIndex);
     }
 
-    // Make sure the code block knows about all of our parameters, and make sure that parameters
-    // needing destructuring are noted.
-    m_parameters.grow(parameters.size() + 1); // reserve space for "this"
-    m_thisRegister.setIndex(initializeNextParameter()->index()); // this
-    for (unsigned i = 0; i < parameters.size(); ++i) {
-        auto pattern = parameters.at(i).first;
-        if (pattern->isRestParameter()) {
-            RELEASE_ASSERT(!m_restParameter);
-            m_restParameter = static_cast<RestParameterNode*>(pattern);
-        } else
-            initializeNextParameter();
-    }
-    
     // Figure out some interesting facts about our arguments.
     bool capturesAnyArgumentByName = false;
     if (functionNode->hasCapturedVariables()) {
@@ -476,7 +508,36 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     }
 
     m_newTargetRegister = addVar();
-    if (!codeBlock->isArrowFunction()) {
+    switch (parseMode) {
+    case SourceParseMode::ArrowFunctionMode: {
+        if (functionNode->usesThis() || codeBlock->usesEval())
+            emitLoadArrowFunctionThis(&m_thisRegister);
+        break;
+    }
+
+    case SourceParseMode::GeneratorWrapperFunctionMode: {
+        m_generatorRegister = addVar();
+
+        // FIXME: Emit to_this only when Generator uses it.
+        // https://bugs.webkit.org/show_bug.cgi?id=151586
+        m_codeBlock->addPropertyAccessInstruction(instructions().size());
+        emitOpcode(op_to_this);
+        instructions().append(kill(&m_thisRegister));
+        instructions().append(0);
+        instructions().append(0);
+
+        emitMove(m_generatorRegister, &m_calleeRegister);
+        emitCreateThis(m_generatorRegister);
+        break;
+    }
+
+    case SourceParseMode::GeneratorBodyMode: {
+        // |this| is already filled correctly before here.
+        emitLoad(m_newTargetRegister, jsUndefined());
+        break;
+    }
+
+    default: {
         if (isConstructor()) {
             emitMove(m_newTargetRegister, &m_thisRegister);
             if (constructorKind() == ConstructorKind::Derived)
@@ -492,9 +553,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             instructions().append(0);
             instructions().append(0);
         }
-    } else {
-        if (functionNode->usesThis() || codeBlock->usesEval())
-            emitLoadArrowFunctionThis(&m_thisRegister);
+        break;
+    }
     }
 
     // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
@@ -799,6 +859,22 @@ RegisterID* BytecodeGenerator::initializeNextParameter()
     return &parameter;
 }
 
+void BytecodeGenerator::initializeParameters(FunctionParameters& parameters)
+{
+    // Make sure the code block knows about all of our parameters, and make sure that parameters
+    // needing destructuring are noted.
+    m_parameters.grow(parameters.size() + 1); // reserve space for "this"
+    m_thisRegister.setIndex(initializeNextParameter()->index()); // this
+    for (unsigned i = 0; i < parameters.size(); ++i) {
+        auto pattern = parameters.at(i).first;
+        if (pattern->isRestParameter()) {
+            RELEASE_ASSERT(!m_restParameter);
+            m_restParameter = static_cast<RestParameterNode*>(pattern);
+        } else
+            initializeNextParameter();
+    }
+}
+
 void BytecodeGenerator::initializeVarLexicalEnvironment(int symbolTableConstantIndex)
 {
     RELEASE_ASSERT(m_lexicalEnvironmentRegister);
@@ -826,17 +902,17 @@ UniquedStringImpl* BytecodeGenerator::visibleNameForParameter(DestructuringPatte
 
 RegisterID* BytecodeGenerator::newRegister()
 {
-    m_calleeRegisters.append(virtualRegisterForLocal(m_calleeRegisters.size()));
-    int numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size());
-    numCalleeRegisters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeRegisters);
-    m_codeBlock->m_numCalleeRegisters = numCalleeRegisters;
-    return &m_calleeRegisters.last();
+    m_calleeLocals.append(virtualRegisterForLocal(m_calleeLocals.size()));
+    int numCalleeLocals = max<int>(m_codeBlock->m_numCalleeLocals, m_calleeLocals.size());
+    numCalleeLocals = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeLocals);
+    m_codeBlock->m_numCalleeLocals = numCalleeLocals;
+    return &m_calleeLocals.last();
 }
 
 void BytecodeGenerator::reclaimFreeRegisters()
 {
-    while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount())
-        m_calleeRegisters.removeLast();
+    while (m_calleeLocals.size() && !m_calleeLocals.last().refCount())
+        m_calleeLocals.removeLast();
 }
 
 RegisterID* BytecodeGenerator::newBlockScopeVariable()
@@ -1915,7 +1991,7 @@ void BytecodeGenerator::createVariable(
         varOffset = VarOffset(symbolTable->takeNextScopeOffset(locker));
     else {
         ASSERT(varKind == VarKind::Stack);
-        varOffset = VarOffset(virtualRegisterForLocal(m_calleeRegisters.size()));
+        varOffset = VarOffset(virtualRegisterForLocal(m_calleeLocals.size()));
     }
     SymbolTableEntry newEntry(varOffset, 0);
     symbolTable->add(locker, property.impl(), newEntry);
@@ -2312,12 +2388,12 @@ RegisterID* BytecodeGenerator::emitAssert(RegisterID* condition, int line)
 RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst)
 {
     size_t begin = instructions().size();
-    m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3);
+    m_staticPropertyAnalyzer.createThis(dst->index(), begin + 3);
 
     m_codeBlock->addPropertyAccessInstruction(instructions().size());
     emitOpcode(op_create_this); 
-    instructions().append(m_thisRegister.index()); 
-    instructions().append(m_thisRegister.index()); 
+    instructions().append(dst->index());
+    instructions().append(dst->index());
     instructions().append(0);
     instructions().append(0);
     return dst;
@@ -2481,20 +2557,6 @@ RegisterID* BytecodeGenerator::emitNewArrayWithSize(RegisterID* dst, RegisterID*
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionMetadataNode* function)
-{
-    return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(function)));
-}
-
-RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index)
-{
-    emitOpcode(op_new_func);
-    instructions().append(dst->index());
-    instructions().append(scopeRegister()->index());
-    instructions().append(index);
-    return dst;
-}
-
 RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
 {
     emitOpcode(op_new_regexp);
@@ -2503,13 +2565,25 @@ RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
     return dst;
 }
 
-void BytecodeGenerator::emitNewFunctionCommon(RegisterID* dst, BaseFuncExprNode* func, OpcodeID opcodeID)
+void BytecodeGenerator::emitNewFunctionExpressionCommon(RegisterID* dst, BaseFuncExprNode* func)
 {
-
-    ASSERT(opcodeID == op_new_func_exp || opcodeID == op_new_arrow_func_exp);
-    
     FunctionMetadataNode* function = func->metadata();
     unsigned index = m_codeBlock->addFunctionExpr(makeFunction(function));
+
+    OpcodeID opcodeID = op_new_func_exp;
+    switch (function->parseMode()) {
+    case SourceParseMode::GeneratorWrapperFunctionMode: {
+        opcodeID = op_new_generator_func_exp;
+        break;
+    }
+    case SourceParseMode::ArrowFunctionMode: {
+        opcodeID = op_new_arrow_func_exp;
+        break;
+    }
+    default: {
+        break;
+    }
+    }
     
     emitOpcode(opcodeID);
     instructions().append(dst->index());
@@ -2522,17 +2596,18 @@ void BytecodeGenerator::emitNewFunctionCommon(RegisterID* dst, BaseFuncExprNode*
 
 RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func)
 {
-    emitNewFunctionCommon(dst, func, op_new_func_exp);
+    emitNewFunctionExpressionCommon(dst, func);
     return dst;
 }
 
 RegisterID* BytecodeGenerator::emitNewArrowFunctionExpression(RegisterID* dst, ArrowFuncExprNode* func)
 {
+    ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode);
     bool isClassConstructor = m_codeBlock->isConstructor() && constructorKind() != ConstructorKind::None;
-    if (isClassConstructor)
+    if (isClassConstructor || generatorThisMode() == GeneratorThisMode::Empty)
         emitTDZCheck(thisRegister());
     
-    emitNewFunctionCommon(dst, func, op_new_arrow_func_exp);
+    emitNewFunctionExpressionCommon(dst, func);
     return dst;
 }
 
@@ -2550,6 +2625,19 @@ RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, Constr
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionMetadataNode* function)
+{
+    unsigned index = m_codeBlock->addFunctionDecl(makeFunction(function));
+    if (function->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
+        emitOpcode(op_new_generator_func);
+    else
+        emitOpcode(op_new_func);
+    instructions().append(dst->index());
+    instructions().append(scopeRegister()->index());
+    instructions().append(index);
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
 {
     return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd);
@@ -3773,6 +3861,24 @@ RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* ite
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitIteratorNextWithValue(RegisterID* dst, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node)
+{
+    {
+        RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next);
+        CallArguments nextArguments(*this, nullptr, 1);
+        emitMove(nextArguments.thisRegister(), iterator);
+        emitMove(nextArguments.argumentRegister(0), value);
+        emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd());
+    }
+    {
+        RefPtr<Label> typeIsObject = newLabel();
+        emitJumpIfTrue(emitIsObject(newTemporary(), dst), typeIsObject.get());
+        emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object."));
+        emitLabel(typeIsObject.get());
+    }
+    return dst;
+}
+
 void BytecodeGenerator::emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node)
 {
     RefPtr<Label> done = newLabel();
@@ -3868,4 +3974,228 @@ void BytecodeGenerator::emitRequireObjectCoercible(RegisterID* value, const Stri
     emitLabel(target.get());
 }
 
+void BytecodeGenerator::emitYieldPoint(RegisterID* argument)
+{
+    RefPtr<Label> mergePoint = newLabel();
+    size_t yieldPointIndex = m_generatorResumeLabels.size();
+    emitGeneratorStateChange(yieldPointIndex);
+    // First yield point is used for initial sequence.
+    unsigned liveCalleeLocalsIndex = yieldPointIndex - 1;
+    emitSave(mergePoint.get(), liveCalleeLocalsIndex);
+    emitReturn(argument);
+    emitResume(mergePoint.get(), liveCalleeLocalsIndex);
+}
+
+void BytecodeGenerator::emitSave(Label* mergePoint, unsigned liveCalleeLocalsIndex)
+{
+    size_t begin = instructions().size();
+    emitOpcode(op_save);
+    instructions().append(m_generatorRegister->index());
+    instructions().append(liveCalleeLocalsIndex);
+    instructions().append(mergePoint->bind(begin, instructions().size()));
+}
+
+void BytecodeGenerator::emitResume(Label* mergePoint, unsigned liveCalleeLocalsIndex)
+{
+    emitGeneratorStateLabel();
+    emitOpcode(op_resume);
+    instructions().append(m_generatorRegister->index());
+    instructions().append(liveCalleeLocalsIndex);
+    emitLabel(mergePoint);
+}
+
+RegisterID* BytecodeGenerator::emitYield(RegisterID* argument)
+{
+    emitYieldPoint(argument);
+
+    RefPtr<Label> normalLabel = newLabel();
+    RefPtr<RegisterID> condition = newTemporary();
+    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+    emitJumpIfTrue(condition.get(), normalLabel.get());
+
+    RefPtr<Label> throwLabel = newLabel();
+    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
+    emitJumpIfTrue(condition.get(), throwLabel.get());
+    // Return.
+    {
+        RefPtr<RegisterID> returnRegister = generatorValueRegister();
+        if (isInFinallyBlock()) {
+            returnRegister = emitMove(newTemporary(), returnRegister.get());
+            emitPopScopes(scopeRegister(), 0);
+        }
+        emitReturn(returnRegister.get());
+    }
+
+    // Throw.
+    emitLabel(throwLabel.get());
+    emitThrow(generatorValueRegister());
+
+    // Normal.
+    emitLabel(normalLabel.get());
+    return generatorValueRegister();
+}
+
+RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, ThrowableExpressionData* node)
+{
+    RefPtr<RegisterID> value = newTemporary();
+    {
+        RefPtr<RegisterID> iterator = emitGetById(newTemporary(), argument, propertyNames().iteratorSymbol);
+        {
+            CallArguments args(*this, nullptr);
+            emitMove(args.thisRegister(), argument);
+            emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd());
+        }
+
+        RefPtr<Label> loopDone = newLabel();
+        {
+            RefPtr<Label> nextElement = newLabel();
+            emitLoad(value.get(), jsUndefined());
+
+            emitJump(nextElement.get());
+
+            RefPtr<Label> loopStart = newLabel();
+            emitLabel(loopStart.get());
+            emitLoopHint();
+
+            {
+                emitYieldPoint(value.get());
+
+                RefPtr<Label> normalLabel = newLabel();
+                RefPtr<Label> returnLabel = newLabel();
+                {
+                    RefPtr<RegisterID> condition = newTemporary();
+                    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+                    emitJumpIfTrue(condition.get(), normalLabel.get());
+
+                    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode))));
+                    emitJumpIfTrue(condition.get(), returnLabel.get());
+
+                    // Fallthrough to ThrowMode.
+                }
+
+                RefPtr<Label> returnSequence = newLabel();
+                RefPtr<Label> returnWithIteratorResult = newLabel();
+                RefPtr<RegisterID> returnIteratorResult = newTemporary();
+                // Throw.
+                {
+                    RefPtr<Label> throwMethodFound = newLabel();
+                    RefPtr<RegisterID> throwMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().throwKeyword);
+                    emitJumpIfFalse(emitIsUndefined(newTemporary(), throwMethod.get()), throwMethodFound.get());
+
+                    emitIteratorClose(iterator.get(), node);
+                    emitThrowTypeError(ASCIILiteral("Delegated generator does not have a 'throw' method."));
+
+                    emitLabel(throwMethodFound.get());
+                    CallArguments throwArguments(*this, nullptr, 1);
+                    emitMove(throwArguments.thisRegister(), iterator.get());
+                    emitMove(throwArguments.argumentRegister(0), generatorValueRegister());
+                    emitCall(returnIteratorResult.get(), throwMethod.get(), NoExpectedFunction, throwArguments, node->divot(), node->divotStart(), node->divotEnd());
+                    emitJump(returnWithIteratorResult.get());
+                }
+
+                // Return.
+                emitLabel(returnLabel.get());
+                {
+                    RefPtr<Label> returnMethodFound = newLabel();
+                    RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
+                    emitJumpIfFalse(emitIsUndefined(newTemporary(), returnMethod.get()), returnMethodFound.get());
+
+                    emitMove(value.get(), generatorValueRegister());
+                    emitJump(returnSequence.get());
+
+                    emitLabel(returnMethodFound.get());
+                    CallArguments returnArguments(*this, nullptr, 1);
+                    emitMove(returnArguments.thisRegister(), iterator.get());
+                    emitMove(returnArguments.argumentRegister(0), generatorValueRegister());
+                    emitCall(returnIteratorResult.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd());
+
+                    // Fallthrough to returnWithIteratorResult.
+                }
+
+                emitLabel(returnWithIteratorResult.get());
+                {
+                    RefPtr<Label> returnIteratorResultIsObject = newLabel();
+                    emitJumpIfTrue(emitIsObject(newTemporary(), returnIteratorResult.get()), returnIteratorResultIsObject.get());
+                    emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object."));
+
+                    emitLabel(returnIteratorResultIsObject.get());
+                    RefPtr<Label> returnFromGenerator = newLabel();
+                    emitJumpIfTrue(emitGetById(newTemporary(), returnIteratorResult.get(), propertyNames().done), returnFromGenerator.get());
+
+                    emitGetById(value.get(), returnIteratorResult.get(), propertyNames().value);
+                    emitJump(loopStart.get());
+
+                    emitLabel(returnFromGenerator.get());
+                    emitGetById(value.get(), returnIteratorResult.get(), propertyNames().value);
+
+                    // Fallthrough to returnSequence.
+                }
+
+                emitLabel(returnSequence.get());
+                {
+                    if (isInFinallyBlock())
+                        emitPopScopes(scopeRegister(), 0);
+                    emitReturn(value.get());
+                }
+
+                // Normal.
+                emitLabel(normalLabel.get());
+                emitMove(value.get(), generatorValueRegister());
+            }
+
+            emitLabel(nextElement.get());
+            {
+                emitIteratorNextWithValue(value.get(), iterator.get(), value.get(), node);
+                emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get());
+                emitGetById(value.get(), value.get(), propertyNames().value);
+                emitJump(loopStart.get());
+            }
+        }
+        emitLabel(loopDone.get());
+    }
+
+    emitGetById(value.get(), value.get(), propertyNames().value);
+    return value.get();
+}
+
+
+void BytecodeGenerator::emitGeneratorStateChange(int32_t state)
+{
+    RegisterID* completedState = emitLoad(nullptr, jsNumber(state));
+    emitPutById(generatorRegister(), propertyNames().generatorStatePrivateName, completedState);
+}
+
+void BytecodeGenerator::emitGeneratorStateLabel()
+{
+    RefPtr<Label> label = newLabel();
+    m_generatorResumeLabels.append(label.get());
+    emitLabel(label.get());
+}
+
+void BytecodeGenerator::beginGenerator(RegisterID* state)
+{
+    beginSwitch(state, SwitchInfo::SwitchImmediate);
+}
+
+void BytecodeGenerator::endGenerator(Label* defaultLabel)
+{
+    SwitchInfo switchInfo = m_switchContextStack.last();
+    m_switchContextStack.removeLast();
+
+    instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfSwitchJumpTables();
+    instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
+
+    UnlinkedSimpleJumpTable& jumpTable = m_codeBlock->addSwitchJumpTable();
+    int32_t switchAddress = switchInfo.bytecodeOffset;
+    jumpTable.min = 0;
+    jumpTable.branchOffsets.resize(m_generatorResumeLabels.size() + 1);
+    jumpTable.branchOffsets.fill(0);
+    for (uint32_t i = 0; i < m_generatorResumeLabels.size(); ++i) {
+        // We're emitting this after the clause labels should have been fixed, so
+        // the labels should not be "forward" references
+        ASSERT(!m_generatorResumeLabels[i]->isForward());
+        jumpTable.add(i, m_generatorResumeLabels[i]->bind(switchAddress, switchAddress + 3));
+    }
+}
+
 } // namespace JSC
index 6ab390e..0ea49a4 100644 (file)
@@ -32,6 +32,7 @@
 #define BytecodeGenerator_h
 
 #include "CodeBlock.h"
+#include "GeneratorThisMode.h"
 #include <wtf/HashTraits.h>
 #include "Instruction.h"
 #include "Label.h"
@@ -280,6 +281,8 @@ namespace JSC {
 
         bool isConstructor() const { return m_codeBlock->isConstructor(); }
         ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); }
+        GeneratorThisMode generatorThisMode() const { return m_codeBlock->generatorThisMode(); }
+        SuperBinding superBinding() const { return m_codeBlock->superBinding(); }
 
         ParserError generate();
 
@@ -297,6 +300,8 @@ namespace JSC {
 
         RegisterID* scopeRegister() { return m_scopeRegister; }
 
+        RegisterID* generatorRegister() { return m_generatorRegister; }
+
         // Returns the next available temporary register. Registers returned by
         // newTemporary require a modified form of reference counting: any
         // register with a refcount of 0 is considered "available", meaning that
@@ -500,10 +505,8 @@ namespace JSC {
         RegisterID* emitNewArrayWithSize(RegisterID* dst, RegisterID* length);
 
         RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*);
-        RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index);
         RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
         RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name);
-        void emitNewFunctionCommon(RegisterID*, BaseFuncExprNode*, OpcodeID);
         RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
         RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
 
@@ -598,6 +601,7 @@ namespace JSC {
         void emitRequireObjectCoercible(RegisterID* value, const String& error);
 
         RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node);
+        RegisterID* emitIteratorNextWithValue(RegisterID* dst, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node);
         void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node);
 
         RegisterID* emitRestParameter(RegisterID* result, unsigned numParametersToSkip);
@@ -646,12 +650,28 @@ namespace JSC {
         void beginSwitch(RegisterID*, SwitchInfo::SwitchType);
         void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range);
 
+        void emitYieldPoint(RegisterID*);
+        void emitSave(Label* mergePoint, unsigned liveCalleeLocalsIndex);
+        void emitResume(Label* mergePoint, unsigned liveCalleeLocalsIndex);
+
+        void emitGeneratorStateLabel();
+        void emitGeneratorStateChange(int32_t state);
+        RegisterID* emitYield(RegisterID* argument);
+        RegisterID* emitDelegateYield(RegisterID* argument, ThrowableExpressionData*);
+        void beginGenerator(RegisterID*);
+        void endGenerator(Label* defaultLabel);
+        RegisterID* generatorStateRegister() { return &m_parameters[2]; }
+        RegisterID* generatorValueRegister() { return &m_parameters[3]; }
+        RegisterID* generatorResumeModeRegister() { return &m_parameters[4]; }
+
         CodeType codeType() const { return m_codeType; }
 
         bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
         bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; }
         
         bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
+
+        SourceParseMode parseMode() const { return m_codeBlock->parseMode(); }
         
         bool isBuiltinFunction() const { return m_isBuiltinFunction; }
 
@@ -669,6 +689,7 @@ namespace JSC {
         void emitPopScope(RegisterID* dst, RegisterID* scope);
         RegisterID* emitGetParentScope(RegisterID* dst, RegisterID* scope);
         void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, bool isCaptured);
+        void emitNewFunctionExpressionCommon(RegisterID*, BaseFuncExprNode*);
 
     public:
         void pushLexicalScope(VariableEnvironmentNode*, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult = nullptr);
@@ -732,7 +753,7 @@ namespace JSC {
         RegisterID& registerFor(VirtualRegister reg)
         {
             if (reg.isLocal())
-                return m_calleeRegisters[reg.toLocal()];
+                return m_calleeLocals[reg.toLocal()];
 
             if (reg.offset() == JSStack::Callee)
                 return m_calleeRegister;
@@ -754,12 +775,22 @@ namespace JSC {
             VariableEnvironment variablesUnderTDZ;
             getVariablesUnderTDZ(variablesUnderTDZ);
 
+            // FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
+            // https://bugs.webkit.org/show_bug.cgi?id=151547
             SourceParseMode parseMode = metadata->parseMode();
             ConstructAbility constructAbility = ConstructAbility::CanConstruct;
-            if (parseMode == SourceParseMode::GetterMode || parseMode == SourceParseMode::SetterMode || parseMode == SourceParseMode::ArrowFunctionMode || (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() == ConstructorKind::None))
+            if (parseMode == SourceParseMode::GetterMode || parseMode == SourceParseMode::SetterMode || parseMode == SourceParseMode::ArrowFunctionMode)
                 constructAbility = ConstructAbility::CannotConstruct;
+            else if (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() == ConstructorKind::None)
+                constructAbility = ConstructAbility::CannotConstruct;
+            else if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode && metadata->superBinding() == SuperBinding::Needed)
+                constructAbility = ConstructAbility::CannotConstruct;
+
+            GeneratorThisMode generatorThisMode = GeneratorThisMode::NonEmpty;
+            if (parseMode == SourceParseMode::GeneratorBodyMode && isConstructor())
+                generatorThisMode = GeneratorThisMode::Empty;
 
-            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, variablesUnderTDZ);
+            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, generatorThisMode, variablesUnderTDZ);
         }
 
         void getVariablesUnderTDZ(VariableEnvironment&);
@@ -767,6 +798,7 @@ namespace JSC {
         RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
         RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 
+        void initializeParameters(FunctionParameters&);
         void initializeVarLexicalEnvironment(int symbolTableConstantIndex);
         void initializeDefaultParameterValuesAndSetupFunctionScopeStack(FunctionParameters&, FunctionNode*, SymbolTable*, int symbolTableConstantIndex, const std::function<bool (UniquedStringImpl*)>& captures);
 
@@ -806,6 +838,7 @@ namespace JSC {
         RegisterID* m_topMostScope { nullptr };
         RegisterID* m_argumentsRegister { nullptr };
         RegisterID* m_lexicalEnvironmentRegister { nullptr };
+        RegisterID* m_generatorRegister { nullptr };
         RegisterID* m_emptyValueRegister { nullptr };
         RegisterID* m_globalObjectRegister { nullptr };
         RegisterID* m_newTargetRegister { nullptr };
@@ -813,7 +846,7 @@ namespace JSC {
 
         SegmentedVector<RegisterID*, 16> m_localRegistersForCalleeSaveRegisters;
         SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
-        SegmentedVector<RegisterID, 32> m_calleeRegisters;
+        SegmentedVector<RegisterID, 32> m_calleeLocals;
         SegmentedVector<RegisterID, 32> m_parameters;
         SegmentedVector<Label, 32> m_labels;
         LabelScopeStore m_labelScopes;
@@ -829,6 +862,7 @@ namespace JSC {
         Vector<SwitchInfo> m_switchContextStack;
         Vector<std::unique_ptr<ForInContext>> m_forInContextStack;
         Vector<TryContext> m_tryContextStack;
+        Vector<RefPtr<Label>> m_generatorResumeLabels;
         enum FunctionVariableType : uint8_t { NormalFunctionVariable, GlobalFunctionVariable };
         Vector<std::pair<FunctionMetadataNode*, FunctionVariableType>> m_functionsToInitialize;
         bool m_needToInitializeArguments { false };
index 6eee442..99561bc 100644 (file)
@@ -34,6 +34,7 @@
 #include "Debugger.h"
 #include "JIT.h"
 #include "JSFunction.h"
+#include "JSGeneratorFunction.h"
 #include "JSGlobalObject.h"
 #include "JSONObject.h"
 #include "LabelScope.h"
@@ -145,7 +146,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived)
+    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.generatorThisMode() == GeneratorThisMode::Empty)
         generator.emitTDZCheck(generator.thisRegister());
 
     if (dst == generator.ignoredResult())
@@ -170,12 +171,16 @@ RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
 }
 
-static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
+static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator)
 {
     RegisterID callee;
     callee.setIndex(JSStack::Callee);
+    return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName);
+}
 
-    RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName);
+static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
+{
+    RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
     return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto);
 }
 
@@ -2584,6 +2589,7 @@ void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
         dst = 0;
 
     RefPtr<RegisterID> returnRegister = m_value ? generator.emitNodeInTailPosition(dst, m_value) : generator.emitLoad(dst, jsUndefined());
+
     generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, divotStart(), divotEnd());
     if (generator.isInFinallyBlock()) {
         returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get());
@@ -2966,26 +2972,95 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 
     generator.emitProfileControlFlow(startStartOffset());
     generator.emitDebugHook(DidEnterCallFrame, startLine(), startStartOffset(), startLineStartOffset());
-    emitStatementsBytecode(generator, generator.ignoredResult());
 
-    StatementNode* singleStatement = this->singleStatement();
-    ReturnNode* returnNode = 0;
+    switch (generator.parseMode()) {
+    case SourceParseMode::GeneratorWrapperFunctionMode: {
+        StatementNode* singleStatement = this->singleStatement();
+        ASSERT(singleStatement->isExprStatement());
+        ExprStatementNode* exprStatement = static_cast<ExprStatementNode*>(singleStatement);
+        ExpressionNode* expr = exprStatement->expr();
+        ASSERT(expr->isFuncExprNode());
+        FuncExprNode* funcExpr = static_cast<FuncExprNode*>(expr);
+
+        RefPtr<RegisterID> next = generator.newTemporary();
+        generator.emitNode(next.get(), funcExpr);
+
+        if (generator.superBinding() == SuperBinding::Needed) {
+            RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
+            emitPutHomeObject(generator, next.get(), homeObject.get());
+        }
 
-    // Check for a return statement at the end of a function composed of a single block.
-    if (singleStatement && singleStatement->isBlock()) {
-        StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
-        if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
-            returnNode = static_cast<ReturnNode*>(lastStatementInBlock);
-    }
+        // FIXME: Currently, we just create an object and store generator related fields as its properties for ease.
+        // But to make it efficient, we will introduce JSGenerator class, add opcode new_generator and use its C++ fields instead of these private properties.
+        // https://bugs.webkit.org/show_bug.cgi?id=151545
+
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorNextPrivateName, next.get(), PropertyNode::KnownDirect);
+
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorThisPrivateName, generator.thisRegister(), PropertyNode::KnownDirect);
+
+        RegisterID* initialState = generator.emitLoad(nullptr, jsNumber(0));
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorStatePrivateName, initialState, PropertyNode::KnownDirect);
+
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorFramePrivateName, generator.emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
 
-    // If there is no return we must automatically insert one.
-    if (!returnNode) {
-        RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
-        generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code.
         ASSERT(startOffset() >= lineStartOffset());
         generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
-        generator.emitReturn(r0);
-        return;
+        generator.emitReturn(generator.generatorRegister());
+        break;
+    }
+
+    case SourceParseMode::GeneratorBodyMode: {
+        RefPtr<Label> generatorBodyLabel = generator.newLabel();
+        {
+            RefPtr<RegisterID> condition = generator.newTemporary();
+            generator.emitEqualityOp(op_stricteq, condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+            generator.emitJumpIfTrue(condition.get(), generatorBodyLabel.get());
+
+            RefPtr<Label> throwLabel = generator.newLabel();
+            generator.emitEqualityOp(op_stricteq, condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
+            generator.emitJumpIfTrue(condition.get(), throwLabel.get());
+
+            generator.emitReturn(generator.generatorValueRegister());
+
+            generator.emitLabel(throwLabel.get());
+            generator.emitThrow(generator.generatorValueRegister());
+        }
+
+        generator.emitLabel(generatorBodyLabel.get());
+
+        emitStatementsBytecode(generator, generator.ignoredResult());
+
+        RefPtr<Label> done = generator.newLabel();
+        generator.emitLabel(done.get());
+        generator.emitReturn(generator.emitLoad(nullptr, jsUndefined()));
+        generator.endGenerator(done.get());
+        break;
+    }
+
+    default: {
+        emitStatementsBytecode(generator, generator.ignoredResult());
+
+        StatementNode* singleStatement = this->singleStatement();
+        ReturnNode* returnNode = 0;
+
+        // Check for a return statement at the end of a function composed of a single block.
+        if (singleStatement && singleStatement->isBlock()) {
+            StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
+            if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
+                returnNode = static_cast<ReturnNode*>(lastStatementInBlock);
+        }
+
+        // If there is no return we must automatically insert one.
+        if (!returnNode) {
+            RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
+            generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code.
+            ASSERT(startOffset() >= lineStartOffset());
+            generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
+            generator.emitReturn(r0);
+            return;
+        }
+        break;
+    }
     }
 }
 
@@ -3013,11 +3088,24 @@ RegisterID* ArrowFuncExprNode::emitBytecode(BytecodeGenerator& generator, Regist
 
 RegisterID* YieldExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    // FIXME: This is just a stub. When completing ES6 Generators, we need to implement it.
-    generator.emitThrowTypeError(ASCIILiteral("Not implemented yet."));
+    if (!delegate()) {
+        RefPtr<RegisterID> arg = nullptr;
+        if (argument()) {
+            arg = generator.newTemporary();
+            generator.emitNode(arg.get(), argument());
+        } else
+            arg = generator.emitLoad(nullptr, jsUndefined());
+        RefPtr<RegisterID> value = generator.emitYield(arg.get());
+        if (dst == generator.ignoredResult())
+            return nullptr;
+        return generator.emitMove(generator.finalDestination(dst), value.get());
+    }
+    RefPtr<RegisterID> arg = generator.newTemporary();
+    generator.emitNode(arg.get(), argument());
+    RefPtr<RegisterID> value = generator.emitDelegateYield(arg.get(), this);
     if (dst == generator.ignoredResult())
-        return 0;
-    return generator.emitLoad(dst, jsUndefined());
+        return nullptr;
+    return generator.emitMove(generator.finalDestination(dst), value.get());
 }
 
 // ------------------------------ ClassDeclNode ---------------------------------
index 439e620..a2020a4 100644 (file)
@@ -145,7 +145,7 @@ public:
         , m_constantNaN(graph.freeze(jsNumber(PNaN)))
         , m_constantOne(graph.freeze(jsNumber(1)))
         , m_numArguments(m_codeBlock->numParameters())
-        , m_numLocals(m_codeBlock->m_numCalleeRegisters)
+        , m_numLocals(m_codeBlock->m_numCalleeLocals)
         , m_parameterSlots(0)
         , m_numPassedVarArgs(0)
         , m_inlineStackTop(0)
@@ -1413,7 +1413,7 @@ void ByteCodeParser::inlineCall(Node* callTargetNode, int resultOperand, CallVar
     
     ensureLocals(
         VirtualRegister(inlineCallFrameStart).toLocal() + 1 +
-        JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters);
+        JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeLocals);
     
     size_t argumentPositionStart = m_graph.m_argumentPositions.size();
 
@@ -2927,7 +2927,7 @@ void ByteCodeParser::handleGetById(
     
     // Start with a register offset that corresponds to the last in-use register.
     int registerOffset = virtualRegisterForLocal(
-        m_inlineStackTop->m_profiledBlock->m_numCalleeRegisters - 1).offset();
+        m_inlineStackTop->m_profiledBlock->m_numCalleeLocals - 1).offset();
     registerOffset -= numberOfParameters;
     registerOffset -= JSStack::CallFrameHeaderSize;
     
@@ -3096,7 +3096,7 @@ void ByteCodeParser::handlePutById(
     
         // Start with a register offset that corresponds to the last in-use register.
         int registerOffset = virtualRegisterForLocal(
-            m_inlineStackTop->m_profiledBlock->m_numCalleeRegisters - 1).offset();
+            m_inlineStackTop->m_profiledBlock->m_numCalleeLocals - 1).offset();
         registerOffset -= numberOfParameters;
         registerOffset -= JSStack::CallFrameHeaderSize;
     
index 51ac55d..f5f4cb5 100644 (file)
@@ -76,7 +76,7 @@ void forAllKilledOperands(Graph& graph, Node* nodeBefore, Node* nodeAfter, const
         const FastBitVector& liveBefore = fullLiveness.getLiveness(before.bytecodeIndex);
         const FastBitVector& liveAfter = fullLiveness.getLiveness(after.bytecodeIndex);
         
-        for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
+        for (unsigned relativeLocal = codeBlock->m_numCalleeLocals; relativeLocal--;) {
             if (liveBefore.get(relativeLocal) && !liveAfter.get(relativeLocal))
                 functor(virtualRegisterForLocal(relativeLocal) + stackOffset);
         }
index 428870b..1911cfe 100644 (file)
@@ -738,7 +738,7 @@ public:
             CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame);
             FullBytecodeLiveness& fullLiveness = livenessFor(codeBlock);
             const FastBitVector& liveness = fullLiveness.getLiveness(codeOriginPtr->bytecodeIndex);
-            for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
+            for (unsigned relativeLocal = codeBlock->m_numCalleeLocals; relativeLocal--;) {
                 VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal);
                 
                 // Don't report if our callee already reported.
index e6c4235..5e5a150 100644 (file)
@@ -93,8 +93,8 @@ public:
         // We'd really like to use an unset origin, but ThreadedCPS won't allow that.
         NodeOrigin origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), false);
         
-        Vector<Node*> locals(baseline->m_numCalleeRegisters);
-        for (int local = 0; local < baseline->m_numCalleeRegisters; ++local) {
+        Vector<Node*> locals(baseline->m_numCalleeLocals);
+        for (int local = 0; local < baseline->m_numCalleeLocals; ++local) {
             Node* previousHead = target->variablesAtHead.local(local);
             if (!previousHead)
                 continue;
@@ -124,7 +124,7 @@ public:
             m_graph.m_arguments[argument] = node;
         }
 
-        for (int local = 0; local < baseline->m_numCalleeRegisters; ++local) {
+        for (int local = 0; local < baseline->m_numCalleeLocals; ++local) {
             Node* previousHead = target->variablesAtHead.local(local);
             if (!previousHead)
                 continue;
index be8e2a7..6392f14 100644 (file)
@@ -123,9 +123,9 @@ void VariableEventStream::reconstruct(
     
     unsigned numVariables;
     if (codeOrigin.inlineCallFrame)
-        numVariables = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters + VirtualRegister(codeOrigin.inlineCallFrame->stackOffset).toLocal() + 1;
+        numVariables = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeLocals + VirtualRegister(codeOrigin.inlineCallFrame->stackOffset).toLocal() + 1;
     else
-        numVariables = baselineCodeBlock->m_numCalleeRegisters;
+        numVariables = baselineCodeBlock->m_numCalleeLocals;
     
     // Crazy special case: if we're at index == 0 then this must be an argument check
     // failure, in which case all variables are already set up. The recoveries should
index 29f05e5..3080dc3 100644 (file)
@@ -45,9 +45,9 @@ ForOSREntryJITCode* ForOSREntryJITCode::ftlForOSREntry()
     return this;
 }
 
-void ForOSREntryJITCode::initializeEntryBuffer(VM& vm, unsigned numCalleeRegisters)
+void ForOSREntryJITCode::initializeEntryBuffer(VM& vm, unsigned numCalleeLocals)
 {
-    m_entryBuffer = vm.scratchBufferForSize(numCalleeRegisters * sizeof(EncodedJSValue));
+    m_entryBuffer = vm.scratchBufferForSize(numCalleeLocals * sizeof(EncodedJSValue));
 }
 
 } } // namespace JSC::FTL
index 44af8f9..9ae973f 100644 (file)
@@ -46,7 +46,7 @@ public:
     ForOSREntryJITCode();
     ~ForOSREntryJITCode();
     
-    void initializeEntryBuffer(VM&, unsigned numCalleeRegisters);
+    void initializeEntryBuffer(VM&, unsigned numCalleeLocals);
     ScratchBuffer* entryBuffer() const { return m_entryBuffer; }
     
     void setBytecodeIndex(unsigned value) { m_bytecodeIndex = value; }
index ac71714..601b460 100644 (file)
@@ -83,7 +83,7 @@ void* prepareOSREntry(
     }
     
     RELEASE_ASSERT(
-        static_cast<int>(values.numberOfLocals()) == baseline->m_numCalleeRegisters);
+        static_cast<int>(values.numberOfLocals()) == baseline->m_numCalleeLocals);
     
     EncodedJSValue* scratch = static_cast<EncodedJSValue*>(
         entryCode->entryBuffer()->dataBuffer());
index 0307e0e..55d829a 100644 (file)
@@ -56,7 +56,7 @@ State::State(Graph& graph)
     }
     case FTLForOSREntryMode: {
         RefPtr<ForOSREntryJITCode> code = adoptRef(new ForOSREntryJITCode());
-        code->initializeEntryBuffer(graph.m_vm, graph.m_profiledBlock->m_numCalleeRegisters);
+        code->initializeEntryBuffer(graph.m_vm, graph.m_profiledBlock->m_numCalleeLocals);
         code->setBytecodeIndex(graph.m_plan.osrEntryBytecodeIndex);
         jitCode = code;
         break;
index d5b1492..546971c 100644 (file)
@@ -155,6 +155,7 @@ namespace JSC {
         bool testAndSetMarked(const void*);
         bool isLive(const JSCell*);
         bool isLiveCell(const void*);
+        bool isAtom(const void*);
         bool isMarkedOrNewlyAllocated(const JSCell*);
         void setMarked(const void*);
         void clearMarked(const void*);
@@ -388,7 +389,7 @@ namespace JSC {
         return false;
     }
 
-    inline bool MarkedBlock::isLiveCell(const void* p)
+    inline bool MarkedBlock::isAtom(const void* p)
     {
         ASSERT(MarkedBlock::isAtomAligned(p));
         size_t atomNumber = this->atomNumber(p);
@@ -399,7 +400,13 @@ namespace JSC {
             return false;
         if (atomNumber >= m_endAtom) // Filters pointers into invalid cells out of the range.
             return false;
+        return true;
+    }
 
+    inline bool MarkedBlock::isLiveCell(const void* p)
+    {
+        if (!isAtom(p))
+            return false;
         return isLive(static_cast<const JSCell*>(p));
     }
 
index c54751c..75ed8cf 100644 (file)
@@ -153,7 +153,16 @@ JSValue eval(CallFrame* callFrame)
     CallFrame* callerFrame = callFrame->callerFrame();
     CodeBlock* callerCodeBlock = callerFrame->codeBlock();
     JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
-    EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain);
+    UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock();
+
+    ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded;
+    if (callerUnlinkedCodeBlock->constructorKind() == ConstructorKind::Derived)
+        thisTDZMode = ThisTDZMode::AlwaysCheck;
+    if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode && callerUnlinkedCodeBlock->generatorThisMode() == GeneratorThisMode::Empty)
+        thisTDZMode = ThisTDZMode::AlwaysCheck;
+
+    SourceCode sourceCode(makeSource(programSource));
+    EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), sourceCode, thisTDZMode, callerScopeChain);
 
     if (!eval) {
         if (!callerCodeBlock->isStrictMode()) {
@@ -171,8 +180,7 @@ JSValue eval(CallFrame* callFrame)
         // If the literal parser bailed, it should not have thrown exceptions.
         ASSERT(!callFrame->vm().exception());
 
-        ThisTDZMode thisTDZMode = callerCodeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
-        eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, programSource, callerScopeChain);
+        eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, sourceCode, callerScopeChain);
         if (!eval)
             return jsUndefined();
     }
@@ -410,7 +418,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
     }
     dataLogF("-----------------------------------------------------------------------------\n");
 
-    end = it - codeBlock->m_numCalleeRegisters + codeBlock->m_numVars;
+    end = it - codeBlock->m_numCalleeLocals + codeBlock->m_numVars;
     if (it != end) {
         do {
             JSValue v = (*it).jsValue();
index 2d6f02c..ab05e80 100644 (file)
@@ -215,6 +215,8 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_get_rest_length)
         DEFINE_OP(op_check_tdz)
         DEFINE_OP(op_assert)
+        DEFINE_OP(op_save)
+        DEFINE_OP(op_resume)
         DEFINE_OP(op_debug)
         DEFINE_OP(op_del_by_id)
         DEFINE_OP(op_div)
@@ -261,6 +263,8 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_new_array_buffer)
         DEFINE_OP(op_new_func)
         DEFINE_OP(op_new_func_exp)
+        DEFINE_OP(op_new_generator_func)
+        DEFINE_OP(op_new_generator_func_exp)
         DEFINE_OP(op_new_arrow_func_exp) 
         DEFINE_OP(op_new_object)
         DEFINE_OP(op_new_regexp)
@@ -764,9 +768,9 @@ void JIT::privateCompileExceptionHandlers()
 
 unsigned JIT::frameRegisterCountFor(CodeBlock* codeBlock)
 {
-    ASSERT(static_cast<unsigned>(codeBlock->m_numCalleeRegisters) == WTF::roundUpToMultipleOf(stackAlignmentRegisters(), static_cast<unsigned>(codeBlock->m_numCalleeRegisters)));
+    ASSERT(static_cast<unsigned>(codeBlock->m_numCalleeLocals) == WTF::roundUpToMultipleOf(stackAlignmentRegisters(), static_cast<unsigned>(codeBlock->m_numCalleeLocals)));
 
-    return roundLocalRegisterCountForFramePointerOffset(codeBlock->m_numCalleeRegisters + maxFrameExtentForSlowPathCallInRegisters);
+    return roundLocalRegisterCountForFramePointerOffset(codeBlock->m_numCalleeLocals + maxFrameExtentForSlowPathCallInRegisters);
 }
 
 int JIT::stackPointerOffsetFor(CodeBlock* codeBlock)
index 6850f7a..2b46e82 100755 (executable)
@@ -494,6 +494,8 @@ namespace JSC {
         void emit_op_get_rest_length(Instruction*);
         void emit_op_check_tdz(Instruction*);
         void emit_op_assert(Instruction*);
+        void emit_op_save(Instruction*);
+        void emit_op_resume(Instruction*);
         void emit_op_debug(Instruction*);
         void emit_op_del_by_id(Instruction*);
         void emit_op_div(Instruction*);
@@ -542,6 +544,8 @@ namespace JSC {
         void emit_op_new_array_buffer(Instruction*);
         void emit_op_new_func(Instruction*);
         void emit_op_new_func_exp(Instruction*);
+        void emit_op_new_generator_func(Instruction*);
+        void emit_op_new_generator_func_exp(Instruction*);
         void emit_op_new_arrow_func_exp(Instruction*);
         void emit_op_new_object(Instruction*);
         void emit_op_new_regexp(Instruction*);
@@ -661,6 +665,7 @@ namespace JSC {
         void emitRightShift(Instruction*, bool isUnsigned);
         void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned);
 
+        void emitNewFuncCommon(Instruction*);
         void emitNewFuncExprCommon(Instruction*);
         void emitVarInjectionCheck(bool needsVarInjectionChecks);
         void emitResolveClosure(int dst, int scope, bool needsVarInjectionChecks, unsigned depth);
index f60ae57..1f3115a 100755 (executable)
@@ -967,7 +967,7 @@ void JIT::emit_op_new_regexp(Instruction* currentInstruction)
     callOperation(operationNewRegexp, currentInstruction[1].u.operand, m_codeBlock->regexp(currentInstruction[2].u.operand));
 }
 
-void JIT::emit_op_new_func(Instruction* currentInstruction)
+void JIT::emitNewFuncCommon(Instruction* currentInstruction)
 {
     Jump lazyJump;
     int dst = currentInstruction[1].u.operand;
@@ -978,14 +978,26 @@ void JIT::emit_op_new_func(Instruction* currentInstruction)
     emitLoadPayload(currentInstruction[2].u.operand, regT0);
 #endif
     FunctionExecutable* funcExec = m_codeBlock->functionDecl(currentInstruction[3].u.operand);
-    callOperation(operationNewFunction, dst, regT0, funcExec);
+
+    OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
+    if (opcodeID == op_new_func)
+        callOperation(operationNewFunction, dst, regT0, funcExec);
+    else {
+        ASSERT(opcodeID == op_new_generator_func);
+        callOperation(operationNewGeneratorFunction, dst, regT0, funcExec);
+    }
 }
 
-void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
+void JIT::emit_op_new_func(Instruction* currentInstruction)
 {
-    emitNewFuncExprCommon(currentInstruction);
+    emitNewFuncCommon(currentInstruction);
 }
-    
+
+void JIT::emit_op_new_generator_func(Instruction* currentInstruction)
+{
+    emitNewFuncCommon(currentInstruction);
+}
+
 void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
 {
     OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
@@ -1018,11 +1030,27 @@ void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
 #else 
         callOperation(operationNewArrowFunction, dst, regT0, function, regT3, regT2);
 #endif
-    else
-        callOperation(operationNewFunction, dst, regT0, function);
+    else {
+        if (opcodeID == op_new_func_exp)
+            callOperation(operationNewFunction, dst, regT0, function);
+        else {
+            ASSERT(opcodeID == op_new_generator_func_exp);
+            callOperation(operationNewGeneratorFunction, dst, regT0, function);
+        }
+    }
     done.link(this);
 }
-    
+
+void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
+{
+    emitNewFuncExprCommon(currentInstruction);
+}
+
+void JIT::emit_op_new_generator_func_exp(Instruction* currentInstruction)
+{
+    emitNewFuncExprCommon(currentInstruction);
+}
+
 void JIT::emit_op_new_arrow_func_exp(Instruction* currentInstruction)
 {
     emitNewFuncExprCommon(currentInstruction);
@@ -1434,6 +1462,18 @@ void JIT::emit_op_get_rest_length(Instruction* currentInstruction)
 #endif
 }
 
+void JIT::emit_op_save(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_save);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_resume(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_resume);
+    slowPathCall.call();
+}
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index d873a1d..cad9346 100644 (file)
@@ -45,6 +45,7 @@
 #include "JITToDFGDeferredCompilationCallback.h"
 #include "JSArrowFunction.h"
 #include "JSCInlines.h"
+#include "JSGeneratorFunction.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSLexicalEnvironment.h"
 #include "JSPropertyNameEnumerator.h"
@@ -987,23 +988,42 @@ EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState* exec
     return JSValue::encode(constructArrayWithSizeQuirk(exec, profile, exec->lexicalGlobalObject(), sizeValue));
 }
 
-EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
+}
+
+template<typename FunctionType>
+static EncodedJSValue operationNewFunctionCommon(ExecState* exec, JSScope* scope, JSCell* functionExecutable, bool isInvalidated)
 {
     ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-    return JSValue::encode(JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
+    if (isInvalidated)
+        return JSValue::encode(FunctionType::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
+    return JSValue::encode(FunctionType::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
+}
+
+extern "C" {
+
+EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
+{
+    return operationNewFunctionCommon<JSFunction>(exec, scope, functionExecutable, false);
 }
 
 EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
 {
-    ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-    return JSValue::encode(JSFunction::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
+    return operationNewFunctionCommon<JSFunction>(exec, scope, functionExecutable, true);
+}
+
+EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
+{
+    return operationNewFunctionCommon<JSGeneratorFunction>(exec, scope, functionExecutable, false);
+}
+
+EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
+{
+    return operationNewFunctionCommon<JSGeneratorFunction>(exec, scope, functionExecutable, true);
 }
 
-EncodedJSValue static operationNewFunctionCommon(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue, bool isInvalidated)
+EncodedJSValue static operationNewArrowFunctionCommon(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue, bool isInvalidated)
 {
     ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
     FunctionExecutable* executable = static_cast<FunctionExecutable*>(functionExecutable);
@@ -1019,12 +1039,12 @@ EncodedJSValue static operationNewFunctionCommon(ExecState* exec, JSScope* scope
     
 EncodedJSValue JIT_OPERATION operationNewArrowFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue)
 {
-    return operationNewFunctionCommon(exec, scope, functionExecutable, thisValue, true);
+    return operationNewArrowFunctionCommon(exec, scope, functionExecutable, thisValue, true);
 }
     
 EncodedJSValue JIT_OPERATION operationNewArrowFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue)
 {
-    return operationNewFunctionCommon(exec, scope, functionExecutable, thisValue, false);
+    return operationNewArrowFunctionCommon(exec, scope, functionExecutable, thisValue, false);
 }
 
 JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure)
index 9638f14..2542550 100644 (file)
@@ -301,6 +301,8 @@ EncodedJSValue JIT_OPERATION operationNewArrayBufferWithProfile(ExecState*, Arra
 EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState*, ArrayAllocationProfile*, EncodedJSValue size) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewArrowFunction(ExecState*, JSScope*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewArrowFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
index a6c3d27..f5918b7 100644 (file)
@@ -134,9 +134,9 @@ void setEntrypoint(VM& vm, CodeBlock* codeBlock)
 
 unsigned frameRegisterCountFor(CodeBlock* codeBlock)
 {
-    ASSERT(static_cast<unsigned>(codeBlock->m_numCalleeRegisters) == WTF::roundUpToMultipleOf(stackAlignmentRegisters(), static_cast<unsigned>(codeBlock->m_numCalleeRegisters)));
+    ASSERT(static_cast<unsigned>(codeBlock->m_numCalleeLocals) == WTF::roundUpToMultipleOf(stackAlignmentRegisters(), static_cast<unsigned>(codeBlock->m_numCalleeLocals)));
 
-    return roundLocalRegisterCountForFramePointerOffset(codeBlock->m_numCalleeRegisters + maxFrameExtentForSlowPathCallInRegisters);
+    return roundLocalRegisterCountForFramePointerOffset(codeBlock->m_numCalleeLocals + maxFrameExtentForSlowPathCallInRegisters);
 }
 
 } } // namespace JSC::LLInt
index 765f197..351a4c8 100644 (file)
@@ -43,6 +43,7 @@
 #include "JSLexicalEnvironment.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
+#include "JSGeneratorFunction.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSStackInlines.h"
 #include "JSString.h"
@@ -224,9 +225,9 @@ static void traceFunctionPrologue(ExecState* exec, const char* comment, CodeSpec
     JSFunction* callee = jsCast<JSFunction*>(exec->callee());
     FunctionExecutable* executable = callee->jsExecutable();
     CodeBlock* codeBlock = executable->codeBlockFor(kind);
-    dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n",
+    dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeLocals = %u, caller = %p.\n",
             codeBlock, exec, comment, callee, executable,
-            codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeRegisters,
+            codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeLocals,
             exec->callerFrame());
 }
 
@@ -458,7 +459,7 @@ LLINT_SLOW_PATH_DECL(stack_check)
 #if LLINT_SLOW_PATH_TRACING
     dataLogF("Checking stack height with exec = %p.\n", exec);
     dataLogF("CodeBlock = %p.\n", exec->codeBlock());
-    dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeRegisters);
+    dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeLocals);
     dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars);
 
 #if ENABLE(JIT)
@@ -1041,6 +1042,18 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func)
     LLINT_RETURN(JSFunction::create(vm, codeBlock->functionDecl(pc[3].u.operand), scope));
 }
 
+LLINT_SLOW_PATH_DECL(slow_path_new_generator_func)
+{
+    LLINT_BEGIN();
+    CodeBlock* codeBlock = exec->codeBlock();
+    ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation());
+    JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+#if LLINT_SLOW_PATH_TRACING
+    dataLogF("Creating function!\n");
+#endif
+    LLINT_RETURN(JSGeneratorFunction::create(vm, codeBlock->functionDecl(pc[3].u.operand), scope));
+}
+
 LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
 {
     LLINT_BEGIN();
@@ -1052,6 +1065,17 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
     LLINT_RETURN(JSFunction::create(vm, executable, scope));
 }
 
+LLINT_SLOW_PATH_DECL(slow_path_new_generator_func_exp)
+{
+    LLINT_BEGIN();
+
+    CodeBlock* codeBlock = exec->codeBlock();
+    JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+    FunctionExecutable* executable = codeBlock->functionExpr(pc[3].u.operand);
+
+    LLINT_RETURN(JSGeneratorFunction::create(vm, executable, scope));
+}
+
 LLINT_SLOW_PATH_DECL(slow_path_new_arrow_func_exp)
 {
     LLINT_BEGIN();
index e244829..271324b 100644 (file)
@@ -99,6 +99,8 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_char);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_string);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func_exp);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_arrow_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct);
index 5ad5b3f..567cb58 100644 (file)
@@ -697,7 +697,7 @@ macro vmEntryRecord(entryFramePointer, resultReg)
 end
 
 macro getFrameRegisterSizeForCodeBlock(codeBlock, size)
-    loadi CodeBlock::m_numCalleeRegisters[codeBlock], size
+    loadi CodeBlock::m_numCalleeLocals[codeBlock], size
     lshiftp 3, size
     addp maxFrameExtentForSlowPathCall, size
 end
@@ -1227,6 +1227,12 @@ _llint_op_new_func:
     dispatch(4)
 
 
+_llint_op_new_generator_func:
+    traceExecution()
+    callSlowPath(_llint_slow_path_new_generator_func)
+    dispatch(4)
+
+
 _llint_op_new_array:
     traceExecution()
     callSlowPath(_llint_slow_path_new_array)
@@ -1458,6 +1464,11 @@ _llint_op_new_func_exp:
     callSlowPath(_llint_slow_path_new_func_exp)
     dispatch(4)
 
+_llint_op_new_generator_func_exp:
+    traceExecution()
+    callSlowPath(_llint_slow_path_new_generator_func_exp)
+    dispatch(4)
+
 _llint_op_new_arrow_func_exp:
     traceExecution()
     callSlowPath(_llint_slow_path_new_arrow_func_exp)
@@ -1573,6 +1584,18 @@ _llint_op_assert:
     dispatch(3)
 
 
+_llint_op_save:
+    traceExecution()
+    callSlowPath(_slow_path_save)
+    dispatch(4)
+
+
+_llint_op_resume:
+    traceExecution()
+    callSlowPath(_slow_path_resume)
+    dispatch(3)
+
+
 _llint_op_create_lexical_environment:
     traceExecution()
     callSlowPath(_slow_path_create_lexical_environment)
index ce985ca..a90dc1c 100644 (file)
@@ -341,9 +341,11 @@ public:
         return new (m_parserArena) YieldExprNode(location, nullptr, /* delegate */ false);
     }
 
-    YieldExprNode* createYield(const JSTokenLocation& location, ExpressionNode* argument, bool delegate)
+    YieldExprNode* createYield(const JSTokenLocation& location, ExpressionNode* argument, bool delegate, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
     {
-        return new (m_parserArena) YieldExprNode(location, argument, delegate);
+        YieldExprNode* node = new (m_parserArena) YieldExprNode(location, argument, delegate);
+        setExceptionLocation(node, start, divot, end);
+        return node;
     }
 
     ClassExprNode* createClassExpr(const JSTokenLocation& location, const Identifier& name, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
@@ -364,12 +366,12 @@ public:
         const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, 
         unsigned startColumn, unsigned endColumn, int functionKeywordStart, 
         int functionNameStart, int parametersStart, bool inStrictContext, 
-        ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode, bool isArrowFunction, bool isArrowFunctionBodyExpression)
+        ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
     {
         return new (m_parserArena) FunctionMetadataNode(
             m_parserArena, startLocation, endLocation, startColumn, endColumn, 
             functionKeywordStart, functionNameStart, parametersStart, 
-            inStrictContext, constructorKind, parameterCount, mode, isArrowFunction, isArrowFunctionBodyExpression);
+            inStrictContext, constructorKind, superBinding, parameterCount, mode, isArrowFunctionBodyExpression);
     }
 
     ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
@@ -891,6 +893,9 @@ public:
     {
         node->setStartOffset(offset);
     }
+
+
+    void propagateArgumentsUse() { usesArguments(); }
     
 private:
     struct Scope {
index ea37639..5b6dc49 100644 (file)
@@ -151,7 +151,7 @@ FunctionMetadataNode::FunctionMetadataNode(
     ParserArena&, const JSTokenLocation& startLocation, 
     const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn, 
     int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext, 
-    ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode, bool isArrowFunction, bool isArrowFunctionBodyExpression)
+    ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
         : Node(endLocation)
         , m_startColumn(startColumn)
         , m_endColumn(endColumn)
@@ -162,10 +162,11 @@ FunctionMetadataNode::FunctionMetadataNode(
         , m_parameterCount(parameterCount)
         , m_parseMode(mode)
         , m_isInStrictContext(isInStrictContext)
+        , m_superBinding(static_cast<unsigned>(superBinding))
         , m_constructorKind(static_cast<unsigned>(constructorKind))
-        , m_isArrowFunction(isArrowFunction)
         , m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression)
 {
+    ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
     ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
 }
 
index 5ca3466..8e9a252 100644 (file)
@@ -1817,7 +1817,7 @@ namespace JSC {
             ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, 
             unsigned startColumn, unsigned endColumn, int functionKeywordStart, 
             int functionNameStart, int parametersStart, bool isInStrictContext, 
-            ConstructorKind, unsigned, SourceParseMode, bool isArrowFunction, bool isArrowFunctionBodyExpression);
+            ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool isArrowFunctionBodyExpression);
 
         void finishParsing(const SourceCode&, const Identifier&, FunctionMode);
         
@@ -1842,8 +1842,8 @@ namespace JSC {
 
         int startStartOffset() const { return m_startStartOffset; }
         bool isInStrictContext() const { return m_isInStrictContext; }
+        SuperBinding superBinding() { return static_cast<SuperBinding>(m_superBinding); }
         ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
-        bool isArrowFunction() const { return m_isArrowFunction; }
         bool isArrowFunctionBodyExpression() const { return m_isArrowFunctionBodyExpression; }
 
         void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset)
@@ -1869,8 +1869,8 @@ namespace JSC {
         int m_lastLine;
         SourceParseMode m_parseMode;
         unsigned m_isInStrictContext : 1;
+        unsigned m_superBinding : 1;
         unsigned m_constructorKind : 2;
-        unsigned m_isArrowFunction : 1;
         unsigned m_isArrowFunctionBodyExpression : 1;
     };
 
@@ -1932,7 +1932,7 @@ namespace JSC {
         virtual bool isArrowFuncExprNode() const override { return true; }
     };
 
-    class YieldExprNode final : public ExpressionNode {
+    class YieldExprNode final : public ExpressionNode, public ThrowableExpressionData {
     public:
         YieldExprNode(const JSTokenLocation&, ExpressionNode* argument, bool delegate);
 
index 2b958b6..c3be82c 100644 (file)
@@ -194,7 +194,7 @@ void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B
 template <typename LexerType>
 Parser<LexerType>::Parser(
     VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode, 
-    JSParserStrictMode strictMode, SourceParseMode parseMode, 
+    JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding,
     ConstructorKind defaultConstructorKind, ThisTDZMode thisTDZMode)
     : m_vm(vm)
     , m_source(&source)
@@ -210,6 +210,7 @@ Parser<LexerType>::Parser(
     , m_lastFunctionName(nullptr)
     , m_sourceElements(0)
     , m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
+    , m_superBinding(superBinding)
     , m_defaultConstructorKind(defaultConstructorKind)
     , m_thisTDZMode(thisTDZMode)
 {
@@ -249,7 +250,10 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     bool isArrowFunctionBodyExpression = false;
     if (m_lexer->isReparsingFunction()) {
         ParserFunctionInfo<ASTBuilder> functionInfo;
-        parseFunctionParameters(context, parseMode, functionInfo);
+        if (parseMode == SourceParseMode::GeneratorBodyMode)
+            functionInfo.parameters = createGeneratorParameters(context);
+        else
+            parseFunctionParameters(context, parseMode, functionInfo);
         m_parameters = functionInfo.parameters;
 
         if (parseMode == SourceParseMode::ArrowFunctionMode && !hasError()) {
@@ -273,8 +277,12 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
             sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
         else if (isModuleParseMode(parseMode))
             sourceElements = parseModuleSourceElements(context, parseMode);
-        else
-            sourceElements = parseSourceElements(context, CheckForStrictMode);
+        else {
+            if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
+                sourceElements = parseGeneratorFunctionSourceElements(context, CheckForStrictMode);
+            else
+                sourceElements = parseSourceElements(context, CheckForStrictMode);
+        }
     }
 
     bool validEnding;
@@ -301,7 +309,14 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     VariableEnvironment& varDeclarations = scope->declaredVariables();
     for (auto& entry : capturedVariables)
         varDeclarations.markVariableAsCaptured(entry);
-    
+
+    IdentifierSet usedVariables;
+    scope->getUsedVariables(usedVariables);
+    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode) {
+        if (usedVariables.contains(m_vm->propertyNames->arguments.impl()))
+            context.propagateArgumentsUse();
+    }
+
     CodeFeatures features = context.features();
     if (scope->strictMode())
         features |= StrictModeFeature;
@@ -311,10 +326,9 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
         features |= ModifiedParameterFeature;
     if (modifiedArguments)
         features |= ModifiedArgumentsFeature;
+
     Vector<RefPtr<UniquedStringImpl>> closedVariables;
     if (m_parsingBuiltin) {
-        IdentifierSet usedVariables;
-        scope->getUsedVariables(usedVariables);
         // FIXME: This needs to be changed if we want to allow builtins to use lexical declarations.
         for (const auto& variable : usedVariables) {
             Identifier identifier = Identifier::fromUid(m_vm, variable.get());
@@ -458,6 +472,45 @@ template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseModuleSo
 }
 
 template <typename LexerType>
+template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, SourceElementsMode mode)
+{
+    auto sourceElements = context.createSourceElements();
+
+    unsigned functionKeywordStart = tokenStart();
+    JSTokenLocation startLocation(tokenLocation());
+    JSTextPosition start = tokenStartPosition();
+    unsigned startColumn = tokenColumn();
+    int functionNameStart = m_token.m_location.startOffset;
+    int parametersStart = m_token.m_location.startOffset;
+
+    ParserFunctionInfo<TreeBuilder> info;
+    info.name = &m_vm->propertyNames->nullIdentifier;
+    info.parameters = createGeneratorParameters(context);
+    info.startOffset = parametersStart;
+    info.startLine = tokenLine();
+    info.parameterCount = 4; // generator, state, value, resume mode
+
+    {
+        AutoPopScopeRef generatorBodyScope(this, pushScope());
+        generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+        SyntaxChecker generatorFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
+        failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
+        popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
+    }
+    info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false);
+
+    info.endLine = tokenLine();
+    info.endOffset = m_token.m_data.offset;
+    info.bodyStartColumn = startColumn;
+
+    auto functionExpr = context.createFunctionExpr(startLocation, info);
+    auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
+    context.appendStatement(sourceElements, statement);
+
+    return sourceElements;
+}
+
+template <typename LexerType>
 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
 {
     // The grammar is documented here:
@@ -1600,15 +1653,14 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeB
 template <typename LexerType>
 template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(
     TreeBuilder& context, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart, 
-    ConstructorKind constructorKind, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
+    ConstructorKind constructorKind, SuperBinding superBinding, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
 {
-    bool isArrowFunction = FunctionBodyType::StandardFunctionBodyBlock != bodyType;
     bool isArrowFunctionBodyExpression = bodyType == ArrowFunctionBodyExpression;
     if (!isArrowFunctionBodyExpression) {
         next();
         if (match(CLOSEBRACE)) {
             unsigned endColumn = tokenColumn();
-            return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction, isArrowFunctionBodyExpression);
+            return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
         }
     }
 
@@ -1620,7 +1672,7 @@ template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBo
     else
         failIfFalse(parseSourceElements(syntaxChecker, CheckForStrictMode), bodyType == StandardFunctionBodyBlock ? "Cannot parse body of this function" : "Cannot parse body of this arrow function");
     unsigned endColumn = tokenColumn();
-    return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction, isArrowFunctionBodyExpression);
+    return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
 }
 
 static const char* stringForFunctionMode(SourceParseMode mode)
@@ -1634,8 +1686,10 @@ static const char* stringForFunctionMode(SourceParseMode mode)
         return "function";
     case SourceParseMode::MethodMode:
         return "method";
-    case SourceParseMode::GeneratorMode:
+    case SourceParseMode::GeneratorBodyMode:
         return "generator";
+    case SourceParseMode::GeneratorWrapperFunctionMode:
+        return "generator function";
     case SourceParseMode::ArrowFunctionMode:
         return "arrow function";
     case SourceParseMode::ProgramMode:
@@ -1714,6 +1768,37 @@ template <typename LexerType> template <class TreeBuilder> int Parser<LexerType>
 }
 
 template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::FormalParameterList Parser<LexerType>::createGeneratorParameters(TreeBuilder& context)
+{
+    auto parameters = context.createFormalParameterList();
+
+    JSTokenLocation location(tokenLocation());
+    JSTextPosition position = tokenStartPosition();
+
+    // @generator
+    declareParameter(&m_vm->propertyNames->generatorPrivateName);
+    auto generator = context.createBindingLocation(location, m_vm->propertyNames->generatorPrivateName, position, position, AssignmentContext::DeclarationStatement);
+    context.appendParameter(parameters, generator, 0);
+
+    // @generatorState
+    declareParameter(&m_vm->propertyNames->generatorStatePrivateName);
+    auto generatorState = context.createBindingLocation(location, m_vm->propertyNames->generatorStatePrivateName, position, position, AssignmentContext::DeclarationStatement);
+    context.appendParameter(parameters, generatorState, 0);
+
+    // @generatorValue
+    declareParameter(&m_vm->propertyNames->generatorValuePrivateName);
+    auto generatorValue = context.createBindingLocation(location, m_vm->propertyNames->generatorValuePrivateName, position, position, AssignmentContext::DeclarationStatement);
+    context.appendParameter(parameters, generatorValue, 0);
+
+    // @generatorResumeMode
+    declareParameter(&m_vm->propertyNames->generatorResumeModePrivateName);
+    auto generatorResumeMode = context.createBindingLocation(location, m_vm->propertyNames->generatorResumeModePrivateName, position, position, AssignmentContext::DeclarationStatement);
+    context.appendParameter(parameters, generatorResumeMode, 0);
+
+    return parameters;
+}
+
+template <typename LexerType>
 template <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)
 {
     RELEASE_ASSERT(isFunctionParseMode(mode));
@@ -1824,12 +1909,10 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             endLocation.startOffset - endLocation.lineStartOffset;
         unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
         
-        bool isArrowFunction = mode == SourceParseMode::ArrowFunctionMode;
-        
         functionInfo.body = context.createFunctionMetadata(
             startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn, 
             functionKeywordStart, functionNameStart, parametersStart, 
-            cachedInfo->strictMode, constructorKind, cachedInfo->parameterCount, mode, isArrowFunction,  functionBodyType == ArrowFunctionBodyExpression);
+            cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression);
         
         functionScope->restoreFromSourceProviderCache(cachedInfo);
         popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
@@ -1843,7 +1926,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         m_lexer->setLineNumber(m_token.m_location.line);
         functionInfo.endOffset = cachedInfo->endFunctionOffset;
 
-        if (isArrowFunction)
+        if (mode == SourceParseMode::ArrowFunctionMode)
             functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
         else
             functionBodyType = StandardFunctionBodyBlock;
@@ -1865,14 +1948,33 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     
     m_lastFunctionName = lastFunctionName;
     ParserState oldState = saveState();
-    
-    functionInfo.body = parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, functionBodyType, functionInfo.parameterCount, mode);
+
+    auto performParsingFunctionBody = [&] {
+        return parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
+    };
+
+    if (mode == SourceParseMode::GeneratorWrapperFunctionMode) {
+        AutoPopScopeRef generatorBodyScope(this, pushScope());
+        generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+        functionInfo.body = performParsingFunctionBody();
+
+        // When a generator has a "use strict" directive, a generator function wrapping it should be strict mode.
+        if  (generatorBodyScope->strictMode())
+            functionScope->setStrictMode();
+
+        semanticFailIfTrue(generatorBodyScope->hasDirectSuper(), "Cannot call super() outside of a class constructor");
+        if (generatorBodyScope->needsSuperBinding())
+            semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
+
+        popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
+    } else
+        functionInfo.body = performParsingFunctionBody();
     
     restoreState(oldState);
     failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
     context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
     if (functionScope->strictMode() && functionInfo.name) {
-        RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorMode);
+        RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode);
         semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
         semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
     }
@@ -1940,7 +2042,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDecla
     SourceParseMode parseMode = SourceParseMode::NormalFunctionMode;
 #if ENABLE(ES6_GENERATORS)
     if (consume(TIMES))
-        parseMode = SourceParseMode::GeneratorMode;
+        parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
 #endif
     failIfFalse((parseFunctionInfo(context, FunctionNeedsName, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
     failIfFalse(functionInfo.name, "Function statements must have a name");
@@ -2091,7 +2193,7 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
             SourceParseMode parseMode = SourceParseMode::MethodMode;
             if (isGenerator) {
                 isConstructor = false;
-                parseMode = SourceParseMode::GeneratorMode;
+                parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
                 semanticFailIfTrue(*ident == m_vm->propertyNames->prototype, "Cannot declare a generator named 'prototype'");
                 semanticFailIfTrue(*ident == m_vm->propertyNames->constructor, "Cannot declare a generator named 'constructor'");
             }
@@ -2757,7 +2859,7 @@ template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmen
     SavePoint savePoint = createSavePoint();
 
 #if ENABLE(ES6_GENERATORS)
-    if (match(YIELD))
+    if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))
         return parseYieldExpression(context);
 #endif
 
@@ -2862,6 +2964,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseYieldExpress
     failIfTrue(m_functionParsePhase == FunctionParsePhase::Parameters, "Cannot use yield expression within parameters");
 
     JSTokenLocation location(tokenLocation());
+    JSTextPosition divotStart = tokenStartPosition();
     ASSERT(match(YIELD));
     SavePoint savePoint = createSavePoint();
     next();
@@ -2869,13 +2972,14 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseYieldExpress
         return context.createYield(location);
 
     bool delegate = consume(TIMES);
+    JSTextPosition argumentStart = tokenStartPosition();
     TreeExpression argument = parseAssignmentExpression(context);
     if (!argument) {
         restoreSavePoint(savePoint);
         next();
         return context.createYield(location);
     }
-    return context.createYield(location, argument, delegate);
+    return context.createYield(location, argument, delegate, divotStart, argumentStart, lastTokenEndPosition());
 }
 
 template <typename LexerType>
@@ -3067,7 +3171,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMeth
     JSTokenLocation methodLocation(tokenLocation());
     unsigned methodStart = tokenStart();
     ParserFunctionInfo<TreeBuilder> methodInfo;
-    SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorMode : SourceParseMode::MethodMode;
+    SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorWrapperFunctionMode : SourceParseMode::MethodMode;
     failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
     methodInfo.name = methodName;
     return context.createFunctionExpr(methodLocation, methodInfo);
@@ -3320,7 +3424,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseFunctionExpr
     SourceParseMode parseMode = SourceParseMode::NormalFunctionMode;
 #if ENABLE(ES6_GENERATORS)
     if (consume(TIMES))
-        parseMode = SourceParseMode::GeneratorMode;
+        parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
 #endif
     failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Expression)), "Cannot parse function expression");
     return context.createFunctionExpr(location, functionInfo);
index 9d94e07..262ff96 100644 (file)
@@ -172,6 +172,7 @@ struct Scope {
         , m_isLexicalScope(false)
         , m_isFunctionBoundary(false)
         , m_isValidStrictMode(true)
+        , m_hasArguments(false)
         , m_loopDepth(0)
         , m_switchDepth(0)
     {
@@ -192,6 +193,7 @@ struct Scope {
         , m_isLexicalScope(rhs.m_isLexicalScope)
         , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
         , m_isValidStrictMode(rhs.m_isValidStrictMode)
+        , m_hasArguments(rhs.m_hasArguments)
         , m_loopDepth(rhs.m_loopDepth)
         , m_switchDepth(rhs.m_switchDepth)
         , m_moduleScopeData(rhs.m_moduleScopeData)
@@ -242,10 +244,14 @@ struct Scope {
     void setSourceParseMode(SourceParseMode mode)
     {
         switch (mode) {
-        case SourceParseMode::GeneratorMode:
+        case SourceParseMode::GeneratorBodyMode:
             setIsGenerator();
             break;
 
+        case SourceParseMode::GeneratorWrapperFunctionMode:
+            setIsGeneratorFunction();
+            break;
+
         case SourceParseMode::NormalFunctionMode:
         case SourceParseMode::GetterMode:
         case SourceParseMode::SetterMode:
@@ -268,6 +274,8 @@ struct Scope {
     bool isFunctionBoundary() const { return m_isFunctionBoundary; }
     bool isGenerator() const { return m_isGenerator; }
 
+    bool hasArguments() const { return m_hasArguments; }
+
     void setIsLexicalScope() 
     { 
         m_isLexicalScope = true;
@@ -450,16 +458,20 @@ struct Scope {
             m_usesEval = true;
 
         {
-            IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
-            for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
-                if (nestedScope->m_declaredVariables.contains(*ptr) || nestedScope->m_lexicalVariables.contains(*ptr))
+            for (const RefPtr<UniquedStringImpl>& impl : nestedScope->m_usedVariables) {
+                if (nestedScope->m_declaredVariables.contains(impl) || nestedScope->m_lexicalVariables.contains(impl))
+                    continue;
+
+                // "arguments" reference should be resolved at function boudary.
+                if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl())
                     continue;
-                m_usedVariables.add(*ptr);
+
+                m_usedVariables.add(impl);
                 // We don't want a declared variable that is used in an inner scope to be thought of as captured if
                 // that inner scope is both a lexical scope and not a function. Only inner functions and "catch" 
                 // statements can cause variables to be captured.
                 if (shouldTrackClosedVariables && (nestedScope->m_isFunctionBoundary || !nestedScope->m_isLexicalScope))
-                    m_closedVariableCandidates.add(*ptr);
+                    m_closedVariableCandidates.add(impl);
             }
         }
         // Propagate closed variable candidates downwards within the same function.
@@ -550,14 +562,22 @@ private:
     {
         m_isFunction = true;
         m_isFunctionBoundary = true;
+        m_hasArguments = true;
         setIsLexicalScope();
         m_isGenerator = false;
     }
 
+    void setIsGeneratorFunction()
+    {
+        setIsFunction();
+        m_isGenerator = true;
+    }
+
     void setIsGenerator()
     {
         setIsFunction();
         m_isGenerator = true;
+        m_hasArguments = false;
     }
 
     void setIsModule()
@@ -579,6 +599,7 @@ private:
     bool m_isLexicalScope : 1;
     bool m_isFunctionBoundary : 1;
     bool m_isValidStrictMode : 1;
+    bool m_hasArguments : 1;
     int m_loopDepth;
     int m_switchDepth;
 
@@ -627,7 +648,7 @@ class Parser {
 
 public:
     Parser(
-        VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode,
+        VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode, SuperBinding,
         ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded);
     ~Parser();
 
@@ -1157,6 +1178,7 @@ private:
     }
 
     template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
+    template <class TreeBuilder> TreeSourceElements parseGeneratorFunctionSourceElements(TreeBuilder&, SourceElementsMode);
     template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
     template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
     enum class ExportType { Exported, NotExported };
@@ -1199,7 +1221,7 @@ private:
     template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
     template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator);
     template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded);
-    template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionBodyType, unsigned, SourceParseMode);
+    template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, SuperBinding, FunctionBodyType, unsigned, SourceParseMode);
     template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, unsigned&);
     enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
     template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, ExportType, bool& forLoopConstDoesNotHaveInitializer);
@@ -1224,6 +1246,7 @@ private:
     template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType);
     
     template <class TreeBuilder> NEVER_INLINE int parseFunctionParameters(TreeBuilder&, SourceParseMode, ParserFunctionInfo<TreeBuilder>&);
+    template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::FormalParameterList createGeneratorParameters(TreeBuilder&);
 
     template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
 
@@ -1349,6 +1372,7 @@ private:
     RefPtr<SourceProviderCache> m_functionCache;
     SourceElements* m_sourceElements;
     bool m_parsingBuiltin;
+    SuperBinding m_superBinding;
     ConstructorKind m_defaultConstructorKind;
     ThisTDZMode m_thisTDZMode;
     VariableEnvironment m_varDeclarations;
@@ -1472,7 +1496,7 @@ template <class ParsedNode>
 std::unique_ptr<ParsedNode> parse(
     VM* vm, const SourceCode& source,
     const Identifier& name, JSParserBuiltinMode builtinMode,
-    JSParserStrictMode strictMode, SourceParseMode parseMode,
+    JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding,
     ParserError& error, JSTextPosition* positionBeforeLastNewline = nullptr,
     ConstructorKind defaultConstructorKind = ConstructorKind::None,
     ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded)
@@ -1481,7 +1505,7 @@ std::unique_ptr<ParsedNode> parse(
 
     ASSERT(!source.provider()->source().isNull());
     if (source.provider()->source().is8Bit()) {
-        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, parseMode, defaultConstructorKind, thisTDZMode);
+        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, thisTDZMode);
         std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
         if (positionBeforeLastNewline)
             *positionBeforeLastNewline = parser.positionBeforeLastNewline();
@@ -1494,7 +1518,7 @@ std::unique_ptr<ParsedNode> parse(
         return result;
     }
     ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string");
-    Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, parseMode, defaultConstructorKind, thisTDZMode);
+    Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, thisTDZMode);
     std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
     if (positionBeforeLastNewline)
         *positionBeforeLastNewline = parser.positionBeforeLastNewline();
index 49585cb..486d8fc 100644 (file)
@@ -46,7 +46,8 @@ enum FunctionMode { FunctionExpression, FunctionDeclaration };
 
 enum class SourceParseMode {
     NormalFunctionMode,
-    GeneratorMode,
+    GeneratorBodyMode,
+    GeneratorWrapperFunctionMode,
     GetterMode,
     SetterMode,
     MethodMode,
@@ -60,7 +61,8 @@ inline bool isFunctionParseMode(SourceParseMode parseMode)
 {
     switch (parseMode) {
     case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
     case SourceParseMode::GetterMode:
     case SourceParseMode::SetterMode:
     case SourceParseMode::MethodMode:
@@ -84,7 +86,8 @@ inline bool isModuleParseMode(SourceParseMode parseMode)
         return true;
 
     case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
     case SourceParseMode::GetterMode:
     case SourceParseMode::SetterMode:
     case SourceParseMode::MethodMode:
@@ -103,7 +106,8 @@ inline bool isProgramParseMode(SourceParseMode parseMode)
         return true;
 
     case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
     case SourceParseMode::GetterMode:
     case SourceParseMode::SetterMode:
     case SourceParseMode::MethodMode:
diff --git a/Source/JavaScriptCore/parser/SourceCodeKey.h b/Source/JavaScriptCore/parser/SourceCodeKey.h
new file mode 100644 (file)
index 0000000..8d49a7e
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceCodeKey_h
+#define SourceCodeKey_h
+
+#include "ParserModes.h"
+#include "SourceCode.h"
+#include <wtf/HashTraits.h>
+
+namespace JSC {
+
+class SourceCodeKey {
+public:
+    enum CodeType { EvalType, ProgramType, FunctionType, ModuleType };
+
+    SourceCodeKey()
+    {
+    }
+
+    SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded)
+        : m_sourceCode(sourceCode)
+        , m_name(name)
+        , m_flags((static_cast<unsigned>(codeType) << 3) | (static_cast<unsigned>(builtinMode) << 2) | (static_cast<unsigned>(strictMode) << 1) | static_cast<unsigned>(thisTDZMode))
+        , m_hash(string().impl()->hash())
+    {
+    }
+
+    SourceCodeKey(WTF::HashTableDeletedValueType)
+        : m_sourceCode(WTF::HashTableDeletedValue)
+    {
+    }
+
+    bool isHashTableDeletedValue() const { return m_sourceCode.isHashTableDeletedValue(); }
+
+    unsigned hash() const { return m_hash; }
+
+    size_t length() const { return m_sourceCode.length(); }
+
+    bool isNull() const { return m_sourceCode.isNull(); }
+
+    // To save memory, we compute our string on demand. It's expected that source
+    // providers cache their strings to make this efficient.
+    String string() const { return m_sourceCode.toString(); }
+
+    bool operator==(const SourceCodeKey& other) const
+    {
+        return m_hash == other.m_hash
+            && length() == other.length()
+            && m_flags == other.m_flags
+            && m_name == other.m_name
+            && string() == other.string();
+    }
+
+private:
+    SourceCode m_sourceCode;
+    String m_name;
+    unsigned m_flags;
+    unsigned m_hash;
+};
+
+struct SourceCodeKeyHash {
+    static unsigned hash(const SourceCodeKey& key) { return key.hash(); }
+    static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+struct SourceCodeKeyHashTraits : SimpleClassHashTraits<SourceCodeKey> {
+    static const bool hasIsEmptyValueFunction = true;
+    static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); }
+};
+
+}
+
+#endif // SourceCodeKey_h
index 547e44f..2c77285 100644 (file)
@@ -180,10 +180,10 @@ public:
     ExpressionType createEmptyVarExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
     ExpressionType createEmptyLetExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
     ExpressionType createYield(const JSTokenLocation&) { return YieldExpr; }
-    ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool) { return YieldExpr; }
+    ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool, int, int, int) { return YieldExpr; }
     ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
     ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
-    int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, unsigned, SourceParseMode, bool, bool) { return FunctionBodyResult; }
+    int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool) { return FunctionBodyResult; }
     ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
     void setFunctionNameStart(int, int) { }
     int createArguments() { return ArgumentsResult; }
@@ -389,6 +389,8 @@ public:
     int endOffset(int) { return 0; }
     void setStartOffset(int, int) { }
 
+    void propagateArgumentsUse() { }
+
 private:
     int m_topBinaryExpr;
     int m_topUnaryToken;
index f13b25e..494520d 100644 (file)
@@ -103,7 +103,7 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(
         &vm, source, Identifier(), builtinMode, strictMode,
-        CacheTypes<UnlinkedCodeBlockType>::parseMode, error, nullptr, ConstructorKind::None, thisTDZMode);
+        CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, thisTDZMode);
     if (!rootNode)
         return nullptr;
 
@@ -160,7 +160,7 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
     JSTextPosition positionBeforeLastNewline;
     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
-        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode,
+        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
         error, &positionBeforeLastNewline);
     if (!program) {
         RELEASE_ASSERT(error.isValid());
@@ -188,7 +188,7 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
     metadata->setEndPosition(positionBeforeLastNewline);
     // The Function constructor only has access to global variables, so no variables will be under TDZ.
     VariableEnvironment emptyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, GeneratorThisMode::NonEmpty, emptyTDZVariables);
     functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
 
     m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age()));
index 48c8cfe..9b8c150 100644 (file)
@@ -29,6 +29,7 @@
 #include "CodeSpecializationKind.h"
 #include "ParserModes.h"
 #include "SourceCode.h"
+#include "SourceCodeKey.h"
 #include "Strong.h"
 #include "VariableEnvironment.h"
 #include <wtf/CurrentTime.h>
@@ -56,71 +57,6 @@ class VM;
 class SourceCode;
 class SourceProvider;
 
-class SourceCodeKey {
-public:
-    enum CodeType { EvalType, ProgramType, FunctionType, ModuleType };
-
-    SourceCodeKey()
-    {
-    }
-
-    SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserBuiltinMode builtinMode,
-        JSParserStrictMode strictMode, ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded)
-        : m_sourceCode(sourceCode)
-        , m_name(name)
-        , m_flags(
-            (static_cast<unsigned>(codeType) << 3)
-            | (static_cast<unsigned>(builtinMode) << 2)
-            | (static_cast<unsigned>(strictMode) << 1)
-            | static_cast<unsigned>(thisTDZMode))
-        , m_hash(string().impl()->hash())
-    {
-    }
-
-    SourceCodeKey(WTF::HashTableDeletedValueType)
-        : m_sourceCode(WTF::HashTableDeletedValue)
-    {
-    }
-
-    bool isHashTableDeletedValue() const { return m_sourceCode.isHashTableDeletedValue(); }
-
-    unsigned hash() const { return m_hash; }
-
-    size_t length() const { return m_sourceCode.length(); }
-
-    bool isNull() const { return m_sourceCode.isNull(); }
-
-    // To save memory, we compute our string on demand. It's expected that source
-    // providers cache their strings to make this efficient.
-    String string() const { return m_sourceCode.toString(); }
-
-    bool operator==(const SourceCodeKey& other) const
-    {
-        return m_hash == other.m_hash
-            && length() == other.length()
-            && m_flags == other.m_flags
-            && m_name == other.m_name
-            && string() == other.string();
-    }
-
-private:
-    SourceCode m_sourceCode;
-    String m_name;
-    unsigned m_flags;
-    unsigned m_hash;
-};
-
-struct SourceCodeKeyHash {
-    static unsigned hash(const SourceCodeKey& key) { return key.hash(); }
-    static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; }
-    static const bool safeToCompareToEmptyOrDeleted = false;
-};
-
-struct SourceCodeKeyHashTraits : SimpleClassHashTraits<SourceCodeKey> {
-    static const bool hasIsEmptyValueFunction = true;
-    static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); }
-};
-
 struct SourceCodeValue {
     SourceCodeValue()
     {
index 495f235..473d5a4 100644 (file)
@@ -39,6 +39,7 @@
     macro(Error) \
     macro(EvalError) \
     macro(Function) \
+    macro(GeneratorFunction) \
     macro(Infinity) \
     macro(Intl) \
     macro(JSON) \
     macro(Uint32Array) \
     macro(Float32Array) \
     macro(Float64Array) \
+    macro(generator) \
+    macro(generatorNext) \
+    macro(generatorState) \
+    macro(generatorFrame) \
+    macro(generatorValue) \
+    macro(generatorThis) \
+    macro(generatorResumeMode) \
 
 
 namespace JSC {
index 490636f..af0a848 100644 (file)
@@ -34,6 +34,7 @@
 #include "Error.h"
 #include "ErrorHandlingScope.h"
 #include "ExceptionFuzz.h"
+#include "GeneratorFrame.h"
 #include "GetterSetter.h"
 #include "HostCallReturnValue.h"
 #include "Interpreter.h"
@@ -222,11 +223,6 @@ SLOW_PATH_DECL(slow_path_create_this)
 {
     BEGIN();
     JSFunction* constructor = jsCast<JSFunction*>(OP(2).jsValue().asCell());
-    
-#if !ASSERT_DISABLED
-    ConstructData constructData;
-    ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
-#endif
 
     auto& cacheWriteBarrier = pc[4].u.jsCell;
     if (!cacheWriteBarrier)
@@ -644,6 +640,38 @@ SLOW_PATH_DECL(slow_path_assert)
     END();
 }
 
+SLOW_PATH_DECL(slow_path_save)
+{
+    // Only save variables and temporary registers. The scope registers are included in them.
+    // But parameters are not included. Because the generator implementation replaces the values of parameters on each generator.next() call.
+    BEGIN();
+    JSValue generator = OP(1).jsValue();
+    GeneratorFrame* frame = nullptr;
+    JSValue value = generator.get(exec, exec->propertyNames().generatorFramePrivateName);
+    if (!value.isNull())
+        frame = jsCast<GeneratorFrame*>(value);
+    else {
+        // FIXME: Once JSGenerator specialized object is introduced, this GeneratorFrame should be embeded into it to avoid allocations.
+        // https://bugs.webkit.org/show_bug.cgi?id=151545
+        frame = GeneratorFrame::create(exec->vm(),  exec->codeBlock()->numCalleeLocals());
+        PutPropertySlot slot(generator, true, PutPropertySlot::PutById);
+        asObject(generator)->methodTable(exec->vm())->put(asObject(generator), exec, exec->propertyNames().generatorFramePrivateName, frame, slot);
+    }
+    unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue;
+    frame->save(exec, exec->codeBlock()->liveCalleeLocalsAtYield(liveCalleeLocalsIndex));
+    END();
+}
+
+SLOW_PATH_DECL(slow_path_resume)
+{
+    BEGIN();
+    JSValue generator = OP(1).jsValue();
+    GeneratorFrame* frame = jsCast<GeneratorFrame*>(generator.get(exec, exec->propertyNames().generatorFramePrivateName));
+    unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue;
+    frame->resume(exec, exec->codeBlock()->liveCalleeLocalsAtYield(liveCalleeLocalsIndex));
+    END();
+}
+
 SLOW_PATH_DECL(slow_path_create_lexical_environment)
 {
     BEGIN();
index 226185c..f00d870 100644 (file)
@@ -290,6 +290,8 @@ SLOW_PATH_HIDDEN_DECL(slow_path_next_generic_enumerator_pname);
 SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
 SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log);
 SLOW_PATH_HIDDEN_DECL(slow_path_assert);
+SLOW_PATH_HIDDEN_DECL(slow_path_save);
+SLOW_PATH_HIDDEN_DECL(slow_path_resume);
 SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment);
 SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
index a632c48..02f395c 100644 (file)
@@ -63,7 +63,7 @@ bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error)
     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
     return !!parse<ProgramNode>(
         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
-        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error);
+        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
 }
 
 bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& error)
@@ -73,7 +73,7 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e
     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
-        JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, error);
+        JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
     if (!moduleProgramNode)
         return false;
 
index 8365292..4206006 100644 (file)
@@ -299,7 +299,7 @@ CodeBlock* ScriptExecutable::newCodeBlockFor(
     UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 
         executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
             *vm, executable->m_source, kind, debuggerMode, profilerMode, error, 
-            executable->isArrowFunction());
+            executable->parseMode());
     recordParse(
         executable->m_unlinkedExecutable->features(), 
         executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(), 
@@ -556,7 +556,7 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
     std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>(
         vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin, 
-        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error);
+        JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
     if (programNode)
         return 0;
     ASSERT(error.isValid());
index 9fc9be7..75b3091 100644 (file)
@@ -448,7 +448,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode); }
 
     unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
@@ -501,7 +501,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode); }
 
 private:
     friend class ExecutableBase;
@@ -542,7 +542,7 @@ public:
 
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode); }
     UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
 
     SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
@@ -650,12 +650,13 @@ public:
     FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
-    bool isArrowFunction() const { return m_unlinkedExecutable->isArrowFunction(); }
     bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
     const Identifier& name() { return m_unlinkedExecutable->name(); }
     const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
     JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); }
     size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
+    SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
+    bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
 
     static void visitChildren(JSCell*, SlotVisitor&);
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
index dbe42fa..5d7ef37 100644 (file)
@@ -79,28 +79,30 @@ CallType FunctionConstructor::getCallData(JSCell*, CallData& callData)
 }
 
 // ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position, FunctionConstructionMode functionConstructionMode)
 {
     if (!globalObject->evalEnabled())
         return exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
-    return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position);
+    return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position, -1, functionConstructionMode);
 }
 
 JSObject* constructFunctionSkippingEvalEnabledCheck(
     ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, 
     const Identifier& functionName, const String& sourceURL, 
-    const TextPosition& position, int overrideLineNumber)
+    const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode)
 {
     // How we stringify functions is sometimes important for web compatibility.
     // See https://bugs.webkit.org/show_bug.cgi?id=24350.
     String program;
     if (args.isEmpty())
-        program = makeString("{function ", functionName.string(), "() {\n\n}}");
+        program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n\n}}");
     else if (args.size() == 1)
-        program = makeString("{function ", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
+        program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
     else {
         StringBuilder builder;
         builder.appendLiteral("{function ");
+        if (functionConstructionMode == FunctionConstructionMode::Generator)
+            builder.append('*');
         builder.append(functionName.string());
         builder.append('(');
         builder.append(args.at(0).toString(exec)->view(exec));
@@ -126,9 +128,9 @@ JSObject* constructFunctionSkippingEvalEnabledCheck(
 }
 
 // ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, FunctionConstructionMode functionConstructionMode)
 {
-    return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition());
+    return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition(), functionConstructionMode);
 }
 
 } // namespace JSC
index 22ecb57..d11fb2a 100644 (file)
@@ -56,12 +56,17 @@ private:
     static CallType getCallData(JSCell*, CallData&);
 };
 
-JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&);
-JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&);
+enum class FunctionConstructionMode {
+    Function,
+    Generator,
+};
+
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&, FunctionConstructionMode = FunctionConstructionMode::Function);
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, FunctionConstructionMode = FunctionConstructionMode::Function);
 
 JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(
     ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, 
-    const String&, const WTF::TextPosition&, int overrideLineNumber = -1);
+    const String&, const WTF::TextPosition&, int overrideLineNumber = -1, FunctionConstructionMode = FunctionConstructionMode::Function);
 
 } // namespace JSC
 
diff --git a/Source/JavaScriptCore/runtime/GeneratorFrame.cpp b/Source/JavaScriptCore/runtime/GeneratorFrame.cpp
new file mode 100644 (file)
index 0000000..ef6ea7a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorFrame.h"
+
+#include "CodeBlock.h"
+#include "HeapIterationScope.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo GeneratorFrame::s_info = { "GeneratorFrame", nullptr, nullptr, CREATE_METHOD_TABLE(GeneratorFrame) };
+
+GeneratorFrame::GeneratorFrame(VM& vm, size_t numberOfCalleeLocals)
+    : Base(vm, vm.generatorFrameStructure.get())
+    , m_numberOfCalleeLocals(numberOfCalleeLocals)
+{
+}
+
+void GeneratorFrame::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    for (size_t i = 0; i < m_numberOfCalleeLocals; ++i)
+        localAt(i).clear();
+}
+
+Structure* GeneratorFrame::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+GeneratorFrame* GeneratorFrame::create(VM& vm, size_t numberOfLocals)
+{
+    GeneratorFrame* result =
+        new (
+            NotNull,
+            allocateCell<GeneratorFrame>(vm.heap, allocationSizeForLocals(numberOfLocals)))
+        GeneratorFrame(vm, numberOfLocals);
+    result->finishCreation(vm);
+    return result;
+}
+
+void GeneratorFrame::save(ExecState* exec, const FastBitVector& liveCalleeLocals)
+{
+    // Only save callee locals.
+    // Every time a generator is called (or resumed), parameters should be replaced.
+    ASSERT(liveCalleeLocals.numBits() <= m_numberOfCalleeLocals);
+    liveCalleeLocals.forEachSetBit([&](size_t index) {
+        localAt(index).set(exec->vm(), this, exec->uncheckedR(virtualRegisterForLocal(index)).jsValue());
+    });
+}
+
+void GeneratorFrame::resume(ExecState* exec, const FastBitVector& liveCalleeLocals)
+{
+    // Only resume callee locals.
+    // Every time a generator is called (or resumed), parameters should be replaced.
+    liveCalleeLocals.forEachSetBit([&](size_t index) {
+        exec->uncheckedR(virtualRegisterForLocal(index)) = localAt(index).get();
+        localAt(index).clear();
+    });
+}
+
+void GeneratorFrame::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    GeneratorFrame* thisObject = jsCast<GeneratorFrame*>(cell);
+    Base::visitChildren(thisObject, visitor);
+    // Since only true cell pointers are stored as a cell, we can safely mark them.
+    visitor.appendValues(thisObject->locals(), thisObject->m_numberOfCalleeLocals);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFrame.h b/Source/JavaScriptCore/runtime/GeneratorFrame.h
new file mode 100644 (file)
index 0000000..3d545b1
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorFrame_h
+#define GeneratorFrame_h
+
+#include "JSCell.h"
+#include <wtf/FastBitVector.h>
+
+namespace JSC {
+
+class GeneratorFrame : public JSCell {
+    friend class JIT;
+#if ENABLE(DFG_JIT)
+    friend class DFG::SpeculativeJIT;
+    friend class DFG::JITCompiler;
+#endif
+    friend class VM;
+public:
+    typedef JSCell Base;
+    static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+    DECLARE_EXPORT_INFO;
+
+    static GeneratorFrame* create(VM&, size_t numberOfCalleeLocals);
+
+    WriteBarrierBase<Unknown>* locals()
+    {
+        return bitwise_cast<WriteBarrierBase<Unknown>*>(bitwise_cast<char*>(this) + offsetOfLocals());
+    }
+
+    WriteBarrierBase<Unknown>& localAt(size_t index)
+    {
+        ASSERT(index < m_numberOfCalleeLocals);
+        return locals()[index];
+    }
+
+    static size_t offsetOfLocals()
+    {
+        return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(GeneratorFrame));
+    }
+
+    static size_t allocationSizeForLocals(unsigned numberOfLocals)
+    {
+        return offsetOfLocals() + numberOfLocals * sizeof(WriteBarrier<Unknown>);
+    }
+
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+    void save(ExecState*, const FastBitVector& liveCalleeLocals);
+    void resume(ExecState*, const FastBitVector& liveCalleeLocals);
+
+private:
+    GeneratorFrame(VM&, size_t numberOfCalleeLocals);
+
+    size_t m_numberOfCalleeLocals;
+
+    friend class LLIntOffsetsExtractor;
+
+    void finishCreation(VM&);
+
+protected:
+    static void visitChildren(JSCell*, SlotVisitor&);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFrame_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp
new file mode 100644 (file)
index 0000000..28f5893
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorFunctionConstructor.h"
+
+#include "FunctionConstructor.h"
+#include "GeneratorFunctionPrototype.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GeneratorFunctionConstructor);
+
+const ClassInfo GeneratorFunctionConstructor::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(GeneratorFunctionConstructor) };
+
+GeneratorFunctionConstructor::GeneratorFunctionConstructor(VM& vm, Structure* structure)
+    : InternalFunction(vm, structure)
+{
+}
+
+void GeneratorFunctionConstructor::finishCreation(VM& vm, GeneratorFunctionPrototype* generatorFunctionPrototype)
+{
+    Base::finishCreation(vm, "GeneratorFunction");
+    putDirectWithoutTransition(vm, vm.propertyNames->prototype, generatorFunctionPrototype, DontEnum | DontDelete | ReadOnly);
+
+    // Number of arguments for constructor
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL callGeneratorFunctionConstructor(ExecState* exec)
+{
+    ArgList args(exec);
+    return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Generator));
+}
+
+static EncodedJSValue JSC_HOST_CALL constructGeneratorFunctionConstructor(ExecState* exec)
+{
+    ArgList args(exec);
+    return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Generator));
+}
+
+CallType GeneratorFunctionConstructor::getCallData(JSCell*, CallData& callData)
+{
+    callData.native.function = callGeneratorFunctionConstructor;
+    return CallTypeHost;
+}
+
+ConstructType GeneratorFunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+    constructData.native.function = constructGeneratorFunctionConstructor;
+    return ConstructTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h
new file mode 100644 (file)
index 0000000..c86c87b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorFunctionConstructor_h
+#define GeneratorFunctionConstructor_h
+
+#include "InternalFunction.h"
+
+namespace WTF {
+class TextPosition;
+}
+
+namespace JSC {
+
+class GeneratorFunctionPrototype;
+
+class GeneratorFunctionConstructor : public InternalFunction {
+public:
+    typedef InternalFunction Base;
+
+    static GeneratorFunctionConstructor* create(VM& vm, Structure* structure, GeneratorFunctionPrototype* generatorFunctionPrototype)
+    {
+        GeneratorFunctionConstructor* constructor = new (NotNull, allocateCell<GeneratorFunctionConstructor>(vm.heap)) GeneratorFunctionConstructor(vm, structure);
+        constructor->finishCreation(vm, generatorFunctionPrototype);
+        return constructor;
+    }
+
+    DECLARE_INFO;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+private:
+    GeneratorFunctionConstructor(VM&, Structure*);
+    void finishCreation(VM&, GeneratorFunctionPrototype*);
+    static ConstructType getConstructData(JSCell*, ConstructData&);
+    static CallType getCallData(JSCell*, CallData&);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFunctionConstructor_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp
new file mode 100644 (file)
index 0000000..33fe8f2
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorFunctionPrototype.h"
+
+#include "BuiltinExecutables.h"
+#include "BuiltinNames.h"
+#include "Error.h"
+#include "JSArray.h"
+#include "JSCInlines.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "Lexer.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GeneratorFunctionPrototype);
+
+const ClassInfo GeneratorFunctionPrototype::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(GeneratorFunctionPrototype) };
+
+GeneratorFunctionPrototype::GeneratorFunctionPrototype(VM& vm, Structure* structure)
+    : JSNonFinalObject(vm, structure)
+{
+}
+
+void GeneratorFunctionPrototype::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h
new file mode 100644 (file)
index 0000000..d0a0349
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorFunctionPrototype_h
+#define GeneratorFunctionPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class GeneratorFunctionPrototype : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+
+    static GeneratorFunctionPrototype* create(VM& vm, Structure* structure)
+    {
+        GeneratorFunctionPrototype* prototype = new (NotNull, allocateCell<GeneratorFunctionPrototype>(vm.heap)) GeneratorFunctionPrototype(vm, structure);
+        prototype->finishCreation(vm);
+        return prototype;
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+    DECLARE_INFO;
+
+protected:
+    void finishCreation(VM&);
+
+private:
+    GeneratorFunctionPrototype(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFunctionPrototype_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp b/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp
new file mode 100644 (file)
index 0000000..af467b3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorPrototype.h"
+
+#include "JSCBuiltins.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "StructureInlines.h"
+
+#include "GeneratorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo GeneratorPrototype::s_info = { "Generator", &Base::s_info, &generatorPrototypeTable, CREATE_METHOD_TABLE(GeneratorPrototype) };
+
+/* Source for GeneratorPrototype.lut.h
+@begin generatorPrototypeTable
+  next      JSBuiltin    DontEnum|Function 1
+  return    JSBuiltin    DontEnum|Function 1
+  throw     JSBuiltin    DontEnum|Function 1
+@end
+*/
+
+void GeneratorPrototype::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(info()));
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Generator"), DontEnum | ReadOnly);
+    vm.prototypeMap.addPrototype(this);
+}
+
+bool GeneratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+    return getStaticFunctionSlot<Base>(exec, generatorPrototypeTable, jsCast<GeneratorPrototype*>(object), propertyName, slot);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorPrototype.h b/Source/JavaScriptCore/runtime/GeneratorPrototype.h
new file mode 100644 (file)
index 0000000..f10c44d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorPrototype_h
+#define GeneratorPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class GeneratorPrototype : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+    static GeneratorPrototype* create(VM& vm, JSGlobalObject*, Structure* structure)
+    {
+        GeneratorPrototype* prototype = new (NotNull, allocateCell<GeneratorPrototype>(vm.heap)) GeneratorPrototype(vm, structure);
+        prototype->finishCreation(vm);
+        return prototype;
+    }
+
+    DECLARE_INFO;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+    static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+private:
+    GeneratorPrototype(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+    void finishCreation(VM&);
+};
+
+}
+
+#endif // !defined(GeneratorPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/GeneratorThisMode.h b/Source/JavaScriptCore/runtime/GeneratorThisMode.h
new file mode 100644 (file)
index 0000000..4c03e7b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorThisMode_h
+#define GeneratorThisMode_h
+
+namespace JSC {
+
+// http://ecma-international.org/ecma-262/6.0/#sec-functionallocate
+// http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
+// When the function is a GeneratorFunction, its [[ConstructorKind]] is always "derived".
+// This means that OrdinaryCallBindThis in section 9.2.2 is never executed for GeneratorFunction.
+// So, when we execute the following,
+//
+//     function *gen()
+//     {
+//        yield this
+//     }
+//
+//     {
+//         let g = gen();
+//         // |this| should be global.
+//         g.next();
+//     }
+//
+//     {
+//         let g = new gen();
+//         // |this| in gen should be TDZ (and it won't be filled).
+//         g.next();
+//     }
+//
+// The following flag manages this state. When GeneratorFunction is called as a constructor, it returns a Generator that function has GeneratorThisMode::Empty flag.
+// In this case, when accessing |this|, a TDZ reference error occurs.
+enum class GeneratorThisMode : unsigned {
+    Empty,
+    NonEmpty
+};
+
+}
+
+#endif // GeneratorThisMode_h
index 5b2edfb..baddbbc 100644 (file)
@@ -32,6 +32,7 @@
 #include "CallFrame.h"
 #include "ExceptionHelpers.h"
 #include "FunctionPrototype.h"
+#include "GeneratorPrototype.h"
 #include "GetterSetter.h"
 #include "JSArray.h"
 #include "JSBoundFunction.h"
@@ -348,7 +349,12 @@ bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyN
         unsigned attributes;
         PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
         if (!isValidOffset(offset)) {
-            JSObject* prototype = constructEmptyObject(exec);
+            JSObject* prototype = nullptr;
+            if (thisObject->jsExecutable()->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
+                prototype = constructEmptyObject(exec, thisObject->globalObject()->generatorPrototype());
+            else
+                prototype = constructEmptyObject(exec);
+
             prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
             thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
             offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes);
diff --git a/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp b/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp
new file mode 100644 (file)
index 0000000..34cbce0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSGeneratorFunction.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSCJSValue.h"
+#include "JSFunction.h"
+#include "JSFunctionInlines.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSGeneratorFunction::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSGeneratorFunction) };
+
+JSGeneratorFunction::JSGeneratorFunction(VM& vm, FunctionExecutable* executable, JSScope* scope)
+    : Base(vm, executable, scope, scope->globalObject()->generatorFunctionStructure())
+{
+}
+
+JSGeneratorFunction* JSGeneratorFunction::createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    JSGeneratorFunction* generatorFunction = new (NotNull, allocateCell<JSGeneratorFunction>(vm.heap)) JSGeneratorFunction(vm, executable, scope);
+    ASSERT(generatorFunction->structure()->globalObject());
+    generatorFunction->finishCreation(vm);
+    return generatorFunction;
+}
+
+JSGeneratorFunction* JSGeneratorFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    JSGeneratorFunction* generatorFunction = createImpl(vm, executable, scope);
+    executable->singletonFunction()->notifyWrite(vm, generatorFunction, "Allocating a generator function");
+    return generatorFunction;
+}
+
+JSGeneratorFunction* JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    return createImpl(vm, executable, scope);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGeneratorFunction.h b/Source/JavaScriptCore/runtime/JSGeneratorFunction.h
new file mode 100644 (file)
index 0000000..ff1072a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSGeneratorFunction_h
+#define JSGeneratorFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+class LLIntDesiredOffsets;
+
+class JSGeneratorFunction : public JSFunction {
+    friend class JIT;
+#if ENABLE(DFG_JIT)
+    friend class DFG::SpeculativeJIT;
+    friend class DFG::JITCompiler;
+#endif
+    friend class VM;
+public:
+    typedef JSFunction Base;
+
+    enum class GeneratorResumeMode : int32_t {
+        NormalMode = 0,
+        ReturnMode = 1,
+        ThrowMode = 2
+    };
+
+    const static unsigned StructureFlags = Base::StructureFlags;
+
+    DECLARE_EXPORT_INFO;
+
+    static JSGeneratorFunction* create(VM&, FunctionExecutable*, JSScope*);
+    static JSGeneratorFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
+
+    static size_t allocationSize(size_t inlineCapacity)
+    {
+        ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+        return sizeof(JSGeneratorFunction);
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        ASSERT(globalObject);
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+    }
+
+private:
+    JSGeneratorFunction(VM&, FunctionExecutable*, JSScope*);
+
+    static JSGeneratorFunction* createImpl(VM&, FunctionExecutable*, JSScope*);
+
+    friend class LLIntOffsetsExtractor;
+};
+
+} // namespace JSC
+
+#endif // JSGeneratorFunction_h
index bc08f96..6dde660 100644 (file)
@@ -50,6 +50,9 @@
 #include "ErrorPrototype.h"
 #include "FunctionConstructor.h"
 #include "FunctionPrototype.h"
+#include "GeneratorFunctionConstructor.h"
+#include "GeneratorFunctionPrototype.h"
+#include "GeneratorPrototype.h"
 #include "GetterSetter.h"
 #include "HeapIterationScope.h"
 #include "InspectorInstrumentationObject.h"
@@ -72,6 +75,7 @@
 #include "JSDollarVM.h"
 #include "JSDollarVMPrototype.h"
 #include "JSFunction.h"
+#include "JSGeneratorFunction.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
 #include "JSGenericTypedArrayViewInlines.h"
 #include "JSGenericTypedArrayViewPrototypeInlines.h"
@@ -384,6 +388,7 @@ m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, th
     
     FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE)
     m_propertyNameIteratorStructure.set(vm, this, JSPropertyNameIterator::createStructure(vm, this, m_iteratorPrototype.get()));
+    m_generatorPrototype.set(vm, this, GeneratorPrototype::create(vm, this, GeneratorPrototype::createStructure(vm, this, m_iteratorPrototype.get())));
     
 #undef CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE
 
@@ -420,6 +425,14 @@ m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->c
     m_syntaxErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("SyntaxError")));
     m_typeErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("TypeError")));
     m_URIErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("URIError")));
+
+    m_generatorFunctionPrototype.set(vm, this, GeneratorFunctionPrototype::create(vm, GeneratorFunctionPrototype::createStructure(vm, this, m_functionPrototype.get())));
+    GeneratorFunctionConstructor* generatorFunctionConstructor = GeneratorFunctionConstructor::create(vm, GeneratorFunctionConstructor::createStructure(vm, this, functionConstructor), m_generatorFunctionPrototype.get());
+    m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, generatorFunctionConstructor, DontEnum);
+    m_generatorFunctionStructure.set(vm, this, JSGeneratorFunction::createStructure(vm, this, m_generatorFunctionPrototype.get()));
+
+    m_generatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_generatorFunctionPrototype.get(), DontEnum);
+    m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->prototype, m_generatorPrototype.get(), DontEnum);
     
     m_objectPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, objectConstructor, DontEnum);
     m_functionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, functionConstructor, DontEnum);
@@ -553,6 +566,7 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
         GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseResolveThenableJobPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsPromiseResolveThenableJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().InspectorInstrumentationPrivateName(), InspectorInstrumentationObject::create(vm, this, InspectorInstrumentationObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->MapPrivateName, mapConstructor, DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().generatorResumePrivateName(), JSFunction::createBuiltinFunction(vm, generatorPrototypeGeneratorResumeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
     };
     addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
     
@@ -820,6 +834,8 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_arrayPrototype);
     visitor.append(&thisObject->m_errorPrototype);
     visitor.append(&thisObject->m_iteratorPrototype);
+    visitor.append(&thisObject->m_generatorFunctionPrototype);
+    visitor.append(&thisObject->m_generatorPrototype);
 
     visitor.append(&thisObject->m_debuggerScopeStructure);
     visitor.append(&thisObject->m_withScopeStructure);
@@ -852,6 +868,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_namedFunctionStructure);
     visitor.append(&thisObject->m_symbolObjectStructure);
     visitor.append(&thisObject->m_regExpStructure);
+    visitor.append(&thisObject->m_generatorFunctionStructure);
     visitor.append(&thisObject->m_regExpMatchesArrayStructure);
     visitor.append(&thisObject->m_moduleRecordStructure);
     visitor.append(&thisObject->m_moduleNamespaceObjectStructure);
index 8e1629c..0325324 100644 (file)
@@ -63,6 +63,8 @@ class EvalExecutable;
 class FunctionCodeBlock;
 class FunctionExecutable;
 class FunctionPrototype;
+class GeneratorPrototype;
+class GeneratorFunctionPrototype;
 class GetterSetter;
 class GlobalCodeBlock;
 class InputCursor;
@@ -229,6 +231,8 @@ protected:
     WriteBarrier<ArrayPrototype> m_arrayPrototype;
     WriteBarrier<RegExpPrototype> m_regExpPrototype;
     WriteBarrier<IteratorPrototype> m_iteratorPrototype;
+    WriteBarrier<GeneratorFunctionPrototype> m_generatorFunctionPrototype;
+    WriteBarrier<GeneratorPrototype> m_generatorPrototype;
 
     WriteBarrier<Structure> m_debuggerScopeStructure;
     WriteBarrier<Structure> m_withScopeStructure;
@@ -262,6 +266,7 @@ protected:
     PropertyOffset m_functionNameOffset;
     WriteBarrier<Structure> m_privateNameStructure;
     WriteBarrier<Structure> m_regExpStructure;
+    WriteBarrier<Structure> m_generatorFunctionStructure;
     WriteBarrier<Structure> m_consoleStructure;
     WriteBarrier<Structure> m_dollarVMStructure;
     WriteBarrier<Structure> m_internalFunctionStructure;
@@ -453,6 +458,8 @@ public:
     RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
     ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
     IteratorPrototype* iteratorPrototype() const { return m_iteratorPrototype.get(); }
+    GeneratorFunctionPrototype* generatorFunctionPrototype() const { return m_generatorFunctionPrototype.get(); }
+    GeneratorPrototype* generatorPrototype() const { return m_generatorPrototype.get(); }
 
     Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(); }
     Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
@@ -506,6 +513,7 @@ public:
     Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
     Structure* mapStructure() const { return m_mapStructure.get(); }
     Structure* regExpStructure() const { return m_regExpStructure.get(); }
+    Structure* generatorFunctionStructure() const { return m_generatorFunctionStructure.get(); }
     Structure* setStructure() const { return m_setStructure.get(); }
     Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
     Structure* symbolObjectStructure() const { return m_symbolObjectStructure.get(); }
index 800a786..37b8afc 100644 (file)
@@ -281,7 +281,7 @@ EncodedJSValue JSC_HOST_CALL moduleLoaderObjectParseModule(ExecState* exec)
     ParserError error;
     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
         &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
-        JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, error);
+        JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
 
     if (error.isValid()) {
         throwVMError(exec, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode));
index 5135f40..ecababc 100644 (file)
@@ -45,6 +45,7 @@
 #include "FTLThunks.h"
 #include "FunctionConstructor.h"
 #include "GCActivityCallback.h"
+#include "GeneratorFrame.h"
 #include "GetterSetter.h"
 #include "Heap.h"
 #include "HeapIterationScope.h"
@@ -244,6 +245,7 @@ VM::VM(VMType vmType, HeapType heapType)
     inferredTypeStructure.set(*this, InferredType::createStructure(*this, 0, jsNull()));
     inferredTypeTableStructure.set(*this, InferredTypeTable::createStructure(*this, 0, jsNull()));
     functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
+    generatorFrameStructure.set(*this, GeneratorFrame::createStructure(*this, 0, jsNull()));
     exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
     promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
     internalPromiseDeferredStructure.set(*this, JSInternalPromiseDeferred::createStructure(*this, 0, jsNull()));
index ced3194..5577a89 100644 (file)
@@ -304,6 +304,7 @@ public:
     Strong<Structure> inferredTypeStructure;
     Strong<Structure> inferredTypeTableStructure;
     Strong<Structure> functionRareDataStructure;
+    Strong<Structure> generatorFrameStructure;
     Strong<Structure> exceptionStructure;
     Strong<Structure> promiseDeferredStructure;
     Strong<Structure> internalPromiseDeferredStructure;
index af34133..c952d32 100644 (file)
 - path: es6/Array_is_subclassable_correct_prototype_chain.js
   cmd: runES6 :fail
 - path: es6/Array_static_methods_Array.from_generator_instances.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Array_static_methods_Array.from_generic_iterables.js
   cmd: runES6 :fail
 - path: es6/Array_static_methods_Array.from_instances_of_generic_iterables.js
 - path: es6/Array_static_methods_Array.from_iterator_closing.js
   cmd: runES6 :fail
 - path: es6/Array_static_methods_Array.from_map_function_generator_instances.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Array_static_methods_Array.from_map_function_generic_iterables.js
   cmd: runES6 :fail
 - path: es6/Array_static_methods_Array.from_map_function_instances_of_iterables.js
 - path: es6/destructuring_nested_rest.js
   cmd: runES6 :normal
 - path: es6/destructuring_with_generator_instances.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/destructuring_with_generic_iterables.js
   cmd: runES6 :fail
 - path: es6/destructuring_with_instances_of_generic_iterables.js
 - path: es6/for..of_loops_iterator_closing_throw.js
   cmd: runES6 :fail
 - path: es6/for..of_loops_with_generator_instances.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/for..of_loops_with_generic_iterables.js
   cmd: runES6 :fail
 - path: es6/for..of_loops_with_instances_of_generic_iterables.js
 - path: es6/function_name_property_variables_function.js
   cmd: runES6 :fail
 - path: es6/generators_%GeneratorPrototype%.constructor.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_%GeneratorPrototype%.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_%GeneratorPrototype%.return.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_%GeneratorPrototype%.throw.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_basic_functionality.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_cant_use_this_with_new.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_computed_shorthand_generators.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_computed_shorthand_generators_classes.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_correct_this_binding.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_generator_function_expressions.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_sending.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_shorthand_generator_methods.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_shorthand_generator_methods_classes.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_string-keyed_shorthand_generator_methods.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_arrays.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_astral_plane_strings.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_generator_instances.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_generic_iterables.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_instances_of_iterables.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_iterator_closing.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_iterator_closing_via_throw.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_on_non-iterables_is_a_runtime_error.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_sparse_arrays.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_star_strings.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/generators_yield_operator_precedence.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Map_iterator_closing.js
   cmd: runES6 :fail
 - path: es6/Map_Map[Symbol.species].js
 - path: es6/spread_..._operator_with_astral_plane_strings_in_function_calls.js
   cmd: runES6 :fail
 - path: es6/spread_..._operator_with_generator_instances_in_arrays.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/spread_..._operator_with_generator_instances_in_calls.js
   cmd: runES6 :fail
 - path: es6/spread_..._operator_with_generic_iterables_in_arrays.js
index a8b9b53..9a82132 100644 (file)
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+  return {};
+}
+arr.length++;
+var iterator = {
+  next: function() {
+    return { value: arr.shift(), done: arr.length <= 0 };
+  },
+  'return': methods['return'],
+  'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
 function test() {
 
 var iterator = (function * generator() {
index b4c7453..8167da5 100644 (file)
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+  return {};
+}
+arr.length++;
+var iterator = {
+  next: function() {
+    return { value: arr.shift(), done: arr.length <= 0 };
+  },
+  'return': methods['return'],
+  'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
 function test() {
 
 var iterator = (function * generator() {
index 6f682f5..32d317c 100644 (file)
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+  return {};
+}
+arr.length++;
+var iterator = {
+  next: function() {
+    return { value: arr.shift(), done: arr.length <= 0 };
+  },
+  'return': methods['return'],
+  'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
 function test() {
 
 var closed = '';
index 44a065a..1f47d32 100644 (file)
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+  return {};
+}
+arr.length++;
+var iterator = {
+  next: function() {
+    return { value: arr.shift(), done: arr.length <= 0 };
+  },
+  'return': methods['return'],
+  'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
 function test() {
 
 var closed = false;
diff --git a/Source/JavaScriptCore/tests/stress/generator-arguments-from-function.js b/Source/JavaScriptCore/tests/stress/generator-arguments-from-function.js
new file mode 100644 (file)
index 0000000..7ca5879
--- /dev/null
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+function *gen(a, b, c)
+{
+    function test()
+    {
+        return arguments;
+    }
+
+    return test;
+}
+
+let g = gen(1, 2, 3);
+let {value: func} = g.next();
+shouldBe(func().length, 0);
diff --git a/Source/JavaScriptCore/tests/stress/generator-argumen