[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 3f364b848cf01ac28a70a41519272f3dab4370d9..49ed35aeb2b9ebc68e3649d2a76f727111bbf04b 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 3b7b76bf3a444c921be973c576c19f692e8d232d..2f374230097b5082583f84427b9257937d309307 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 cae3cd2d6e402abc7e5d15d72bc041a3a9c7c40c..7eeecfe4093297096cc398c52dfb386ef0d64bb0 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 84e00095944839c9ae81c3557464c3d72c811ccf..5bce4942d69540820f4800cbc068aff109da6daf 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 e177afcb55454254230c57129eed7568d57f411d..18d64d0352a4da643cab71b77a5d19b66ef49c5f 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 3758a36364d97c3583c916f3f3d985a4877f92c6..768ebaa629772f6ded798a7e6d7f81dee0eb6e83 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 9a206a07c2b5529edbab03d9faf0f4de8648c4a8..62d21d29296ac03c0b1f4642ba17eb68c0f514cc 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 951c3c5c147895a7e5272712d6d188543a322aa4..b900af03e9e655b9a845e4eaaa1d1d71d8ab4595 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 68b95022d1567e5b1fe5103c8b44978d95d19fcf..339b3404a8b69e669cba2cbe97a108edf9c5a25f 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 816b4a5d30b520b5d1dfeaeab2f9394c68bdc0a3..a9e69bea6eeae578b92d989e1e89191a334899ef 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 54dfd168ca600ebef13580432c77e25ad444ad0c..596064c406824978089c4643f1c3dfbd0534b99f 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 f6c89a9d4ad2f6378587347016513b14730e5372..43d70124196dd362cc644f93a21f9f81e87bb35c 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 c77abeaa29209e329913cd94cfad751519bd99f1..7228b033366c7a67b510488dfe45f3dd3cfa4315 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 cbb89486e14c05f28474cfd2abda74e910ca28db..fe026faaf9ecb9224ae3daa0ca6255a5f9afaec3 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 9e1386e3d32d61dba9f819cec97a70023c9b8f3f..0ab781ce75c7f7a07806b00fcb12576bf9556369 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 c1df187c1220d2f7f0324a2d25f9b83c052d82ec..3cbe75c497810193880c3a5b1b995930500aa990 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 62521fc6528c5a2e7d4eaf43858c06cee7c7aedd..83703cfa922cc6271285f5938e2a820f8bedb070 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 92144f89fbd450fe820500c2a0969b50b102a15d..2602be7c4fbece9dea50218fe14b5651fb47b8bd 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 d60fdf7d3cf360e3ec1698779abe6b9eb906d514..2bbf3134456a9ae52a61928bc4ae07135ea61e3c 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 c114b9b57d144d165ea41dad8f2a68ee8fa8b576..87e8233f1fe3a8bec40230d298b09e6dff9a3896 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 fa514c156a7cb7cef74a9f1000165b861f0f83cf..bca2c04aca4382921756958baa68db30e8f135c0 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 6da1859b3ad2d1c65d8a53ff1137e1e47e9d59b6..3f494885af49c28e26f497d675f64a16c9b9af96 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 d8e8229390e577cb480fb0e9293f41ba42d9c1f8..c8bba0ac32be437ffb5df3e3f9e05b0478a5361b 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 41a64c9a50af381772387fde665ec4123972e80d..445d3d5cd4c064657e61228830865f9fcf2ae087 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 6ab390ebaa1607bc121d989685e12a147dbacb73..0ea49a42c6a8839d5330152282fe6bb3f22fd714 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 6eee44233d0959b8d09d5139e073bbffe9de1d75..99561bc7ed588b6f80d0e9c1c666543d163a6ede 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 439e620034b7fcdc81503a5916e1b447f6c062ab..a2020a44a020d284f569b7fd675500745394e161 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 51ac55d4ca5f9ed498ab8897c96ed259333d6287..f5f4cb52380edbb3c9f8971032110a088cfd1290 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 428870b1c2a258715cd7153b8e799beae92c4e5f..1911cfeed64190396c8ae65f3a7ec4978a766fa9 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 e6c4235ec4ca6817cd37e699834786089f2b6efa..5e5a1504c24d06404f786b1722e2f6150f8fab63 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 be8e2a79149f5a2e3144ad464a35c654fc599e0c..6392f14a9804cfb692e84bc390120d0bab7dbde2 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 29f05e51d461fdf6e014383199c918f6415e8cea..3080dc34509c733324b8143d2a954f08edaf13fb 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 44af8f95791aaa78e6e81dfa649c86a15ea34481..9ae973f40d12c16b809c0c8ca1e36ebaa8ee3697 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 ac71714f93f55af2618c7e420a71b66de2117666..601b46094064ac613a98fa9c229386fa6eadf051 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 0307e0ed05c5a2561cc4ef82b5aa2e5ffcf8c0eb..55d829a2a66b626091584a73e11dba03c256ea28 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 d5b1492ae7f53de6ca65519c572eb61eeb39e30e..546971ce8f538b9e335cfffb284733bd96154e2b 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 c54751cd720fffc11e15d35256b06375c0b6e8ac..75ed8cf7bc4ced619876fd76df0f0bae59ec06b8 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 2d6f02c2b1f8907f3dfa7f89403ae08630d31a2a..ab05e807f619727421b108e397f5a833e1fb4704 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 6850f7aa51e1888e2e4839be145efd244fd88346..2b46e8255dbd63c2bd67596c6b02513c5c44fe68 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 f60ae57afde38de616b6a89b826ef8491534a3f5..1f3115a59cc94660a1c3fe8da984720553c20b6d 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 d873a1ddd657a28968a0e51f90636d1de2fcf816..cad93469c1bcbd2b57dcb52023abe9f723f74445 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 9638f145c9d5575f1c952e275f594a76b32a4b88..2542550229da41e1add46b0b0258e8e4995b9b6d 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 a6c3d27e280a0447922869d782cfe2a55ab780c3..f5918b72170ac5de47c2bed363796530e0195401 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 765f197950e323f0566e72c73b4eed63e3b208c5..351a4c8d442f2d6c68c4a92c32f16ec602da8287 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 e244829fdd1e2f1506a35d10a4eb81fcbe32c531..271324b18453d72dc8b76180ba0304ab45659597 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 5ad5b3fcd739d5639490cdacafeca6c1475b9429..567cb58c125697bcde617ecec0c8b078695e9777 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 ce985ca45de99e8da5a57f8b93a3064ca6f1d324..a90dc1c1cc2796dd104bf71e3e97093ce9272fe9 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 ea376393b6467b5ad63e632c9f6d3d939338ce50..5b6dc49385da78358c279bc0800bf89a0a6579c4 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 5ca34664fdf164aa39e1f614d3eebd0de05189ea..8e9a252ead1fee9159fafe153b7c7961d87a2c1f 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 2b958b6ec65e3a95a016e1a14af6d1ff414b3a61..c3be82c6e93f6b9f67b5a2cdcd79766ea9bfba83 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());
@@ -457,6 +471,45 @@ template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseModuleSo
     return sourceElements;
 }
 
+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)
 {
@@ -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:
@@ -1713,6 +1767,37 @@ template <typename LexerType> template <class TreeBuilder> int Parser<LexerType>
     return parametersStart;
 }
 
+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)
 {
@@ -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 9d94e07a807b8ee720314760d951574de8f4998f..262ff963fa40fd8d8900bee80f6cc4c3f0edc435 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 49585cbc62b4c33efdf7c49ea29bd715528be885..486d8fc0dacc25c1d3b115b40002751862698c29 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 547e44fc9ebf91d65ad26493364db3250f7c306f..2c7728527e943cd682a515e9b43d2f50db2b8d53 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 f13b25e4c9b262c525e0f56ec0f69cdc7cbedf0e..494520dbdf428c8640db5e223f00e21f2fecffe9 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 48c8cfef84649d8f09c2fb0b9488111e16936bd7..9b8c150de20b8533b1fda3daa895d06cdc895738 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 495f235878665c43057881d8d1bd848426a99bda..473d5a41cbf719379677fae24459255c780b1b5d 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 490636f204c9f64c4cfc88e0e97c76f735550fee..af0a8486d1209ea6848bd2507a7c37e5bd0c9fd2 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 226185c4c7ea7cc6fc7f3cc4f1f37e60eb72f17a..f00d8705d4e67fe4d4059bde168ee88f57df72e7 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 a632c48e030b41b33b33dba16a31cf6135b4f50f..02f395c42bc12ee021834a82f81f0fc979bcda58 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 8365292d57bc9dec03e56417d7a40d320ec7ca60..42060067229aa40ab47e9b40529621fe82edb34d 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 9fc9be7a14f6c0febc2397126b60fd7b0c340a04..75b3091cf81c7296fe2fafe9a9676536299782fc 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 dbe42fa5fe26304e86ee2013b100cabb221c429c..5d7ef3766ac0d69b35546af7e791ce949bb42d6c 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 22ecb57b93f69bfc9f8b1b306fb4c42a0a67d2e3..d11fb2a374d619150c9d6c42629ba91cc1205f52 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 5b2edfbd6d5371bb01e02db03e64eb4690fad10b..baddbbca4a82852a56915d0582df7ffdf9ffd8cc 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 bc08f9692b0ed3fab9f9bbe73f8fcc2cfe7d7a64..6dde6602784bf8d183d7b9568bdfa8338496fe7e 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 8e1629c5bbea67949483ad3cc781893b84d85104..0325324985a038e697814c98079bcdd43eb76729 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 800a7869e54b75d5c8d28a50d97a1e0b77b5063a..37b8afc77e2d09e95513befb58ee7ddfc06c54a9 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 5135f40d10d6f002264db862bbca9df4fde978f7..ecababc9fff604f37f1957dbee28ed864a4360c9 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 ced3194089006bf3e178193ca629e8e68d2b81e6..5577a89a490fd0c2f43b527a1bfa79f298e0b8ee 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 af3413323c564c93305112602ee0d40380689ab9..c952d3253013bc42280354a749f0f5d71e711892 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 a8b9b53cccfae1a5b5a66c13bd23e8cae527aaa4..9a82132a60fc0e791972c04318d07b9e26004a33 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 b4c74539326c8972b74a761ff4d8f29b2a5ae829..8167da52df6fd1ea8fc15444a3b64eb86e63c792 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 6f682f5a16cab9e8b5d269ade42e83aeb8b03d4f..32d317c0b80adb95294343f9ac88ff8ea84dfacf 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 44a065a96a1c9de7e26c36206c1cb364704a04d4..1f47d328bbc7f5cda1f9248e956afba54293829b 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-arguments.js b/Source/JavaScriptCore/tests/stress/generator-arguments.js
new file mode 100644 (file)
index 0000000..b26478f
--- /dev/null
@@ -0,0 +1,107 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+(function () {
+    function *g1(a, b, c)
+    {
+        yield arguments;
+        yield arguments;
+    }
+
+    var g = g1(0, 1, 2);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+
+    function *g2(a, b, c)
+    {
+        yield arguments;
+        yield arguments;
+        a = yield a;
+        yield arguments;
+        b = yield b;
+        yield arguments;
+        c = yield c;
+        yield arguments;
+    }
+    var g = g2(0, 1, 2);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 0);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":42,"1":1,"2":2}`);
+    shouldBe(g.next().value, 1);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":42,"1":42,"2":2}`);
+    shouldBe(g.next().value, 2);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":42,"1":42,"2":42}`);
+}());
+
+(function () {
+    function *g1(a, b, c)
+    {
+        "use strict";
+        yield arguments;
+        yield arguments;
+    }
+
+    var g = g1(0, 1, 2);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+
+    function *g2(a, b, c)
+    {
+        "use strict";
+        yield arguments;
+        yield arguments;
+        a = yield a;
+        yield arguments;
+        b = yield b;
+        yield arguments;
+        c = yield c;
+        yield arguments;
+    }
+    var g = g2(0, 1, 2);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 0);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 1);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 2);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+}());
+
+(function () {
+    "use strict";
+    function *g1(a, b, c)
+    {
+        yield arguments;
+        yield arguments;
+    }
+
+    var g = g1(0, 1, 2);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+
+    function *g2(a, b, c)
+    {
+        yield arguments;
+        yield arguments;
+        a = yield a;
+        yield arguments;
+        b = yield b;
+        yield arguments;
+        c = yield c;
+        yield arguments;
+    }
+    var g = g2(0, 1, 2);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 0);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 1);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+    shouldBe(g.next().value, 2);
+    shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-class-methods-syntax.js b/Source/JavaScriptCore/tests/stress/generator-class-methods-syntax.js
new file mode 100644 (file)
index 0000000..2465ceb
--- /dev/null
@@ -0,0 +1,48 @@
+function testSyntax(script) {
+    try {
+        eval(script);
+    } catch (error) {
+        if (error instanceof SyntaxError)
+            throw new Error("Bad error: " + String(error));
+    }
+}
+
+function testSyntaxError(script, message) {
+    var error = null;
+    try {
+        eval(script);
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("Expected syntax error not thrown");
+
+    if (String(error) !== message)
+        throw new Error("Bad error: " + String(error));
+}
+
+testSyntaxError(`
+class Cocoa {
+    *constructor()
+    {
+    }
+}
+`, `SyntaxError: Cannot declare a generator named 'constructor'.`);
+
+testSyntax(`
+class Cocoa {
+    *ok()
+    {
+        yield 42;
+    }
+}
+`);
+
+testSyntax(`
+class Cocoa {
+    static *ok()
+    {
+        yield 42;
+    }
+}
+`);
diff --git a/Source/JavaScriptCore/tests/stress/generator-class-methods.js b/Source/JavaScriptCore/tests/stress/generator-class-methods.js
new file mode 100644 (file)
index 0000000..21f5a54
--- /dev/null
@@ -0,0 +1,62 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+class A {
+    *gen()
+    {
+        yield this;
+        yield this;
+        return 42;
+    }
+
+    static *staticGen()
+    {
+        yield this;
+        yield this;
+        return 42;
+    }
+}
+{
+    let a = new A();
+    let g = a.gen();
+    shouldBe(g.next().value, a);
+    shou