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

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

Reviewed by Saam Barati.

.:

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

Source/JavaScriptCore:

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

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

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

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

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

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

switch (@generatorState) {
case Initial:

...
initial sequence.
...

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

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

return ...;

case Yield_0:

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

...

else if (@generatorResumeMode == Return)

...

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

case Yield_1:

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

...

else if (@generatorResumeMode == Return)

...

...
sentValue = @generatorValue;
...

...
}

}

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

  1. Store live frame registers to GeneratorFrame

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

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

  1. GeneratorFunction will evaluate parameters before generating Generator

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

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

yield b;

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

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

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

This is generator.
return {

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

...

}

}

}

  1. op_save seems similar to conditional jump

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

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

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

By constructing such a graph,

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

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

  • API/JSScriptRef.cpp:

(parseScript):

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

(JSC::createExecutableInternal):

  • builtins/GeneratorPrototype.js: Added.

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

  • bytecode/BytecodeBasicBlock.cpp:

(JSC::isBranch):

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

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

  • bytecode/BytecodeUseDef.h:

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

  • bytecode/CodeBlock.cpp:

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

  • bytecode/CodeBlock.h:

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

  • bytecode/EvalCodeCache.h:

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

  • bytecode/ExecutableInfo.h:

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

  • bytecode/PreciseJumpTargets.cpp:

(JSC::getJumpTargetsForBytecodeOffset):

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

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

  • bytecode/UnlinkedFunctionExecutable.cpp:

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

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

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

  • bytecompiler/BytecodeGenerator.h:

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

  • bytecompiler/NodesCodegen.cpp:

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

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGForAllKills.h:

(JSC::DFG::forAllKilledOperands):

  • dfg/DFGGraph.h:

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

  • dfg/DFGOSREntrypointCreationPhase.cpp:

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

  • dfg/DFGVariableEventStream.cpp:

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

  • ftl/FTLForOSREntryJITCode.cpp:

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

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

(JSC::FTL::prepareOSREntry):

  • ftl/FTLState.cpp:

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

  • heap/MarkedBlock.h:

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

  • interpreter/Interpreter.cpp:

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

  • jit/JIT.cpp:

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

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

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

  • jit/JITOperations.cpp:

(JSC::operationNewFunctionCommon):

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

(JSC::LLInt::frameRegisterCountFor):

  • llint/LLIntSlowPaths.cpp:

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

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

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

  • parser/Nodes.cpp:

(JSC::FunctionMetadataNode::FunctionMetadataNode):

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

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

  • parser/Parser.h:

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

  • parser/ParserModes.h:

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

  • parser/SourceCodeKey.h: Added.

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

  • parser/SyntaxChecker.h:

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

  • runtime/CodeCache.cpp:

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

  • runtime/CodeCache.h:

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

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

(JSC::SLOW_PATH_DECL):

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

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

  • runtime/Executable.cpp:

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

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

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

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

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

  • runtime/GeneratorFrame.h: Added.

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

  • runtime/GeneratorFunctionConstructor.cpp: Added.

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

  • runtime/GeneratorFunctionConstructor.h: Added.

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

  • runtime/GeneratorFunctionPrototype.cpp: Added.

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

  • runtime/GeneratorFunctionPrototype.h: Added.

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

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

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

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

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

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

(JSC::JSFunction::getOwnPropertySlot):

  • runtime/JSGeneratorFunction.cpp: Added.

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

  • runtime/JSGeneratorFunction.h: Added.

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

  • runtime/JSGlobalObject.cpp:

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

  • runtime/JSGlobalObject.h:

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

  • runtime/ModuleLoaderObject.cpp:

(JSC::moduleLoaderObjectParseModule):

  • runtime/VM.cpp:

(JSC::VM::VM):

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

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

  • tests/es6/generators_yield_star_instances_of_iterables.js:

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

  • tests/es6/generators_yield_star_iterator_closing.js:

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

  • tests/es6/generators_yield_star_iterator_closing_via_throw.js:

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

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

(shouldBe):
(test):

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

(shouldBe):
(g1):

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

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

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

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

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

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

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

(shouldBe):
(generatorFunctionConstructor):

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

(shouldBe):
(ok):

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

(shouldThrow):

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

(shouldBe):
(generatorFunction):

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

(shouldBe):
(shouldBeIteratorResult):

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

(shouldBe):
(shouldBeIteratorResult):

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

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

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

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

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

(shouldBe):
(shouldBeIteratorResult):

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

(shouldBe):
(gen):

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

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

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

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

Source/WebCore:

  • Configurations/FeatureDefines.xcconfig:

Source/WebKit/mac:

  • Configurations/FeatureDefines.xcconfig:

Source/WebKit2:

  • Configurations/FeatureDefines.xcconfig:

Source/WTF:

  • wtf/FastBitVector.h:

(WTF::FastBitVector::forEachSetBit):

  • wtf/FeatureDefines.h:

Tools:

  • Scripts/webkitperl/FeatureList.pm:

WebKitLibraries:

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

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r192935 r192937  
    586586        static_cast<unsigned long>(instructions().size()),
    587587        static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
    588         m_numParameters, m_numCalleeRegisters, m_numVars);
     588        m_numParameters, m_numCalleeLocals, m_numVars);
    589589    if (needsActivation() && codeType() == FunctionCode)
    590590        out.printf("; lexical environment in r%d", activationRegister().offset());
     
    681681    }
    682682
     683    if (m_rareData && !m_rareData->m_liveCalleeLocalsAtYield.isEmpty()) {
     684        out.printf("\nLive Callee Locals:\n");
     685        unsigned i = 0;
     686        do {
     687            const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[i];
     688            out.printf("  live%1u = ", i);
     689            liveness.dump(out);
     690            out.printf("\n");
     691            ++i;
     692        } while (i < m_rareData->m_liveCalleeLocalsAtYield.size());
     693    }
     694
    683695    out.printf("\n");
    684696}
     
    13041316            break;
    13051317        }
     1318        case op_new_generator_func: {
     1319            int r0 = (++it)->u.operand;
     1320            int r1 = (++it)->u.operand;
     1321            int f0 = (++it)->u.operand;
     1322            printLocationAndOp(out, exec, location, it, "new_generator_func");
     1323            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
     1324            break;
     1325        }
    13061326        case op_new_arrow_func_exp: {
    13071327            int r0 = (++it)->u.operand;
     
    13181338            int f0 = (++it)->u.operand;
    13191339            printLocationAndOp(out, exec, location, it, "new_func_exp");
     1340            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
     1341            break;
     1342        }
     1343        case op_new_generator_func_exp: {
     1344            int r0 = (++it)->u.operand;
     1345            int r1 = (++it)->u.operand;
     1346            int f0 = (++it)->u.operand;
     1347            printLocationAndOp(out, exec, location, it, "new_generator_func_exp");
    13201348            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
    13211349            break;
     
    15091537            break;
    15101538        }
     1539        case op_save: {
     1540            int generator = (++it)->u.operand;
     1541            unsigned liveCalleeLocalsIndex = (++it)->u.unsignedValue;
     1542            int offset = (++it)->u.operand;
     1543            const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex];
     1544            printLocationAndOp(out, exec, location, it, "save");
     1545            out.printf("%s, ", registerName(generator).data());
     1546            liveness.dump(out);
     1547            out.printf("(@live%1u), %d(->%d)", liveCalleeLocalsIndex, offset, location + offset);
     1548            break;
     1549        }
     1550        case op_resume: {
     1551            int generator = (++it)->u.operand;
     1552            unsigned liveCalleeLocalsIndex = (++it)->u.unsignedValue;
     1553            const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex];
     1554            printLocationAndOp(out, exec, location, it, "resume");
     1555            out.printf("%s, ", registerName(generator).data());
     1556            liveness.dump(out);
     1557            out.printf("(@live%1u)", liveCalleeLocalsIndex);
     1558            break;
     1559        }
    15111560        case op_assert: {
    15121561            int condition = (++it)->u.operand;
     
    16731722    , m_globalObject(other.m_globalObject)
    16741723    , m_heap(other.m_heap)
    1675     , m_numCalleeRegisters(other.m_numCalleeRegisters)
     1724    , m_numCalleeLocals(other.m_numCalleeLocals)
    16761725    , m_numVars(other.m_numVars)
    16771726    , m_isConstructor(other.m_isConstructor)
     
    17301779        m_rareData->m_switchJumpTables = other.m_rareData->m_switchJumpTables;
    17311780        m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
     1781        m_rareData->m_liveCalleeLocalsAtYield = other.m_rareData->m_liveCalleeLocalsAtYield;
    17321782    }
    17331783   
     
    17401790    , m_globalObject(scope->globalObject()->vm(), this, scope->globalObject())
    17411791    , m_heap(&m_globalObject->vm().heap)
    1742     , m_numCalleeRegisters(unlinkedCodeBlock->m_numCalleeRegisters)
     1792    , m_numCalleeLocals(unlinkedCodeBlock->m_numCalleeLocals)
    17431793    , m_numVars(unlinkedCodeBlock->m_numVars)
    17441794    , m_isConstructor(unlinkedCodeBlock->isConstructor())
     
    19101960    HashSet<JSModuleEnvironment*> stronglyReferencedModuleEnvironments;
    19111961
     1962    // Bookkeep the merge point bytecode offsets.
     1963    Vector<size_t> mergePointBytecodeOffsets;
     1964
    19121965    RefCountedArray<Instruction> instructions(instructionCount);
    19131966
     
    21982251        }
    21992252
     2253        case op_save: {
     2254            unsigned liveCalleeLocalsIndex = pc[2].u.index;
     2255            int offset = pc[3].u.operand;
     2256            if (liveCalleeLocalsIndex >= mergePointBytecodeOffsets.size())
     2257                mergePointBytecodeOffsets.resize(liveCalleeLocalsIndex + 1);
     2258            mergePointBytecodeOffsets[liveCalleeLocalsIndex] = i + offset;
     2259            break;
     2260        }
     2261
    22002262        default:
    22012263            break;
     
    22082270
    22092271    m_instructions = WTF::move(instructions);
     2272
     2273    // Perform bytecode liveness analysis to determine which locals are live and should be resumed when executing op_resume.
     2274    if (unlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode) {
     2275        if (size_t count = mergePointBytecodeOffsets.size()) {
     2276            createRareDataIfNecessary();
     2277            BytecodeLivenessAnalysis liveness(this);
     2278            m_rareData->m_liveCalleeLocalsAtYield.grow(count);
     2279            size_t liveCalleeLocalsIndex = 0;
     2280            for (size_t bytecodeOffset : mergePointBytecodeOffsets) {
     2281                m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex] = liveness.getLivenessInfoAtBytecodeOffset(bytecodeOffset);
     2282                ++liveCalleeLocalsIndex;
     2283            }
     2284        }
     2285    }
    22102286
    22112287    // Set optimization thresholds only after m_instructions is initialized, since these
     
    22322308    , m_globalObject(globalObject->vm(), this, globalObject)
    22332309    , m_heap(&m_globalObject->vm().heap)
    2234     , m_numCalleeRegisters(0)
     2310    , m_numCalleeLocals(0)
    22352311    , m_numVars(0)
    22362312    , m_isConstructor(false)
     
    30593135            m_rareData->m_switchJumpTables.shrinkToFit();
    30603136            m_rareData->m_stringSwitchJumpTables.shrinkToFit();
     3137            m_rareData->m_liveCalleeLocalsAtYield.shrinkToFit();
    30613138        }
    30623139    } // else don't shrink these, because we would have already pointed pointers into these tables.
     
    40304107    FastBitVector liveAtHead = liveness.getLivenessInfoAtBytecodeOffset(0);
    40314108   
    4032     if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeRegisters)) {
     4109    if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeLocals)) {
    40334110        beginValidationDidFail();
    40344111        dataLog("    Wrong number of bits in result!\n");
     
    40384115    }
    40394116   
    4040     for (unsigned i = m_numCalleeRegisters; i--;) {
     4117    for (unsigned i = m_numCalleeLocals; i--;) {
    40414118        VirtualRegister reg = virtualRegisterForLocal(i);
    40424119       
Note: See TracChangeset for help on using the changeset viewer.