+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-11-23 Carlos Garcia Campos <cgarcia@igalia.com>
Unreviewed. Update OptionsGTK.cmake and NEWS for 2.11.2 release.
{
return !!JSC::parse<JSC::ProgramNode>(
vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
- JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode,
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
error);
}
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
runtime/JSDateMath.cpp
runtime/JSEnvironmentRecord.cpp
runtime/JSFunction.cpp
+ runtime/JSGeneratorFunction.cpp
runtime/JSGlobalLexicalEnvironment.cpp
runtime/JSGlobalObject.cpp
runtime/JSGlobalObjectDebuggable.cpp
runtime/DateConstructor.cpp
runtime/DatePrototype.cpp
runtime/ErrorPrototype.cpp
+ runtime/GeneratorPrototype.cpp
runtime/InspectorInstrumentationObject.cpp
runtime/IntlCollatorConstructor.cpp
runtime/IntlCollatorPrototype.cpp
${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
+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 Filip Pizlo <fpizlo@apple.com>
Remove repetitive cruft from FTL OSR exit code in LowerDFGToLLVM
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;
$(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 \
DateConstructor.lut.h \
DatePrototype.lut.h \
ErrorPrototype.lut.h \
+ GeneratorPrototype.lut.h \
InspectorInstrumentationObject.lut.h \
IntlCollatorConstructor.lut.h \
IntlCollatorPrototype.lut.h \
<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" />
<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>
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 */,
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) {
}
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;
}
--- /dev/null
+/*
+ * 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);
+}
case op_switch_char:
case op_switch_string:
case op_check_has_instance:
+ case op_save:
return true;
default:
return false;
{ "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 }
]
},
{
// 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
// 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)) {
}
}
-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);
if (targetOffset > bytecodeOffset)
break;
- stepOverInstruction(codeBlock, basicBlocks, bytecodeOffset, out);
+ stepOverInstruction(codeBlock, block, basicBlocks, bytecodeOffset, out);
}
result.set(out);
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();
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;
}
}
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))
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();
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;
}
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:
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: {
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;
}
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();
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:
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:
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
": %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");
} 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");
}
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;
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;
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;
: 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)
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);
: 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)
// 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(); ) {
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;
}
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).
: 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)
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.
}
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");
endValidationDidFail();
}
- for (unsigned i = m_numCalleeRegisters; i--;) {
+ for (unsigned i = m_numCalleeLocals; i--;) {
VirtualRegister reg = virtualRegisterForLocal(i);
if (liveAtHead.get(i)) {
#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>
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); }
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 {
// FIXME: Make these remaining members private.
int m_numLocalRegistersForCalleeSaves;
- int m_numCalleeRegisters;
+ int m_numCalleeLocals;
int m_numVars;
bool m_isConstructor : 1;
Vector<SimpleJumpTable> m_switchJumpTables;
Vector<StringJumpTable> m_stringSwitchJumpTables;
+ Vector<FastBitVector> m_liveCalleeLocalsAtYield;
+
EvalCodeCache m_evalCodeCache;
};
#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>
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;
}
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;
};
#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; }
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;
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
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:
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())
, 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)
#include "CodeType.h"
#include "ConstructAbility.h"
#include "ExpressionRangeInfo.h"
+#include "GeneratorThisMode.h"
#include "HandlerInfo.h"
#include "Identifier.h"
#include "JSCell.h"
#include "UnlinkedFunctionExecutable.h"
#include "VariableEnvironment.h"
#include "VirtualRegister.h"
+#include <wtf/FastBitVector.h>
#include <wtf/RefCountedArray.h>
#include <wtf/Vector.h>
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; }
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()
{
int m_numVars;
int m_numCapturedVars;
- int m_numCalleeRegisters;
+ int m_numCalleeLocals;
// Jump Tables
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;
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());
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())
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())
, 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);
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:
UnlinkedFunctionCodeBlock* result = generateUnlinkedFunctionCodeBlock(
vm, this, source, specializationKind, debuggerMode, profilerMode,
isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction,
- error, isArrowFunction);
+ error, parseMode);
if (error.isValid())
return nullptr;
#include "CodeType.h"
#include "ConstructAbility.h"
#include "ExpressionRangeInfo.h"
+#include "GeneratorThisMode.h"
#include "HandlerInfo.h"
#include "Identifier.h"
#include "JSCell.h"
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;
}
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; }
UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode,
- ParserError&, bool);
+ ParserError&, SourceParseMode);
static UnlinkedFunctionExecutable* fromGlobalCode(
const Identifier&, ExecState&, const SourceCode&, JSObject*& exception,
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;
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)
#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"
}
}
+ 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();
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
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()) {
}
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)
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
return ¶meter;
}
+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);
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()
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);
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;
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);
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());
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;
}
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);
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();
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
#define BytecodeGenerator_h
#include "CodeBlock.h"
+#include "GeneratorThisMode.h"
#include <wtf/HashTraits.h>
#include "Instruction.h"
#include "Label.h"
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();
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
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*);
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);
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; }
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);
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;
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&);
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);
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 };
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;
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 };
#include "Debugger.h"
#include "JIT.h"
#include "JSFunction.h"
+#include "JSGeneratorFunction.h"
#include "JSGlobalObject.h"
#include "JSONObject.h"
#include "LabelScope.h"
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())
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);
}
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());
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;
+ }
}
}
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 ---------------------------------
, 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)
ensureLocals(
VirtualRegister(inlineCallFrameStart).toLocal() + 1 +
- JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters);
+ JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeLocals);
size_t argumentPositionStart = m_graph.m_argumentPositions.size();
// 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;
// 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;
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);
}
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.
// 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;
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;
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
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
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; }
}
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());
}
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;
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*);
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);
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));
}
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()) {
// 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();
}
}
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();
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)
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)
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)
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*);
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*);
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);
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;
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);
#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);
#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)
#include "JITToDFGDeferredCompilationCallback.h"
#include "JSArrowFunction.h"
#include "JSCInlines.h"
+#include "JSGeneratorFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSLexicalEnvironment.h"
#include "JSPropertyNameEnumerator.h"
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);
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)
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;
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
#include "JSLexicalEnvironment.h"
#include "JSCInlines.h"
#include "JSCJSValue.h"
+#include "JSGeneratorFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSStackInlines.h"
#include "JSString.h"
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());
}
#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)
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();
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();
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);
end
macro getFrameRegisterSizeForCodeBlock(codeBlock, size)
- loadi CodeBlock::m_numCalleeRegisters[codeBlock], size
+ loadi CodeBlock::m_numCalleeLocals[codeBlock], size
lshiftp 3, size
addp maxFrameExtentForSlowPathCall, size
end
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)
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)
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)
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,
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)
{
node->setStartOffset(offset);
}
+
+
+ void propagateArgumentsUse() { usesArguments(); }
private:
struct Scope {
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)
, 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));
}
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);
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)
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;
};
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);
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)
, m_lastFunctionName(nullptr)
, m_sourceElements(0)
, m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
+ , m_superBinding(superBinding)
, m_defaultConstructorKind(defaultConstructorKind)
, m_thisTDZMode(thisTDZMode)
{
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()) {
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;
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;
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());
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)
{
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);
}
}
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)
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:
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)
{
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);
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;
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");
}
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");
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'");
}
ExpressionErrorClassifier classifier(this);
#if ENABLE(ES6_GENERATORS)
- if (match(YIELD))
+ if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))
return parseYieldExpression(context);
#endif
failIfTrue(m_functionParsePhase == FunctionParsePhase::Parameters, "Cannot use yield expression within parameters");
JSTokenLocation location(tokenLocation());
+ JSTextPosition divotStart = tokenStartPosition();
ASSERT(match(YIELD));
SavePoint savePoint = createSavePoint();
next();
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>
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);
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);
, m_isLexicalScope(false)
, m_isFunctionBoundary(false)
, m_isValidStrictMode(true)
+ , m_hasArguments(false)
, m_loopDepth(0)
, m_switchDepth(0)
{
, 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)
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:
bool isFunctionBoundary() const { return m_isFunctionBoundary; }
bool isGenerator() const { return m_isGenerator; }
+ bool hasArguments() const { return m_hasArguments; }
+
void setIsLexicalScope()
{
m_isLexicalScope = true;
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.
{
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()
bool m_isLexicalScope : 1;
bool m_isFunctionBoundary : 1;
bool m_isValidStrictMode : 1;
+ bool m_hasArguments : 1;
int m_loopDepth;
int m_switchDepth;
public:
Parser(
- VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode,
+ VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode, SuperBinding,
ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded);
~Parser();
}
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 };
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);
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>&);
RefPtr<SourceProviderCache> m_functionCache;
SourceElements* m_sourceElements;
bool m_parsingBuiltin;
+ SuperBinding m_superBinding;
ConstructorKind m_defaultConstructorKind;
ThisTDZMode m_thisTDZMode;
VariableEnvironment m_varDeclarations;
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)
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();
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();
enum class SourceParseMode {
NormalFunctionMode,
- GeneratorMode,
+ GeneratorBodyMode,
+ GeneratorWrapperFunctionMode,
GetterMode,
SetterMode,
MethodMode,
{
switch (parseMode) {
case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::GeneratorWrapperFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
case SourceParseMode::MethodMode:
return true;
case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::GeneratorWrapperFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
case SourceParseMode::MethodMode:
return true;
case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::GeneratorWrapperFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
case SourceParseMode::MethodMode:
--- /dev/null
+/*
+ * 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
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; }
int endOffset(int) { return 0; }
void setStartOffset(int, int) { }
+ void propagateArgumentsUse() { }
+
private:
int m_topBinaryExpr;
int m_topUnaryToken;
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;
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());
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()));
#include "CodeSpecializationKind.h"
#include "ParserModes.h"
#include "SourceCode.h"
+#include "SourceCodeKey.h"
#include "Strong.h"
#include "VariableEnvironment.h"
#include <wtf/CurrentTime.h>
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()
{
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 {
#include "Error.h"
#include "ErrorHandlingScope.h"
#include "ExceptionFuzz.h"
+#include "GeneratorFrame.h"
#include "GetterSetter.h"
#include "HostCallReturnValue.h"
#include "Interpreter.h"
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();
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);
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)
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;
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(),
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());
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(); }
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;
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(); }
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)
}
// 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));
}
// 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
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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
#include "CallFrame.h"
#include "ExceptionHelpers.h"
#include "FunctionPrototype.h"
+#include "GeneratorPrototype.h"
#include "GetterSetter.h"
#include "JSArray.h"
#include "JSBoundFunction.h"
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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#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"
#include "JSDollarVM.h"
#include "JSDollarVMPrototype.h"
#include "JSFunction.h"
+#include "JSGeneratorFunction.h"
#include "JSGenericTypedArrayViewConstructorInlines.h"
#include "JSGenericTypedArrayViewInlines.h"
#include "JSGenericTypedArrayViewPrototypeInlines.h"
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
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);
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));
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);
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);
class FunctionCodeBlock;
class FunctionExecutable;
class FunctionPrototype;
+class GeneratorPrototype;
+class GeneratorFunctionPrototype;
class GetterSetter;
class GlobalCodeBlock;
class InputCursor;
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;
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;
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(); }
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(); }
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));
#include "FTLThunks.h"
#include "FunctionConstructor.h"
#include "GCActivityCallback.h"
+#include "GeneratorFrame.h"
#include "GetterSetter.h"
#include "Heap.h"
#include "HeapIterationScope.h"
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()));
Strong<Structure> inferredTypeStructure;
Strong<Structure> inferredTypeTableStructure;
Strong<Structure> functionRareDataStructure;
+ Strong<Structure> generatorFrameStructure;
Strong<Structure> exceptionStructure;
Strong<Structure> promiseDeferredStructure;
Strong<Structure> internalPromiseDeferredStructure;
- 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
+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() {
+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() {
+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 = '';
+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;
--- /dev/null
+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);
--- /dev/null
+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}`);
+}());
--- /dev/null
+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;
+ }
+}
+`);
--- /dev/null
+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);
+ shouldBe(g.next().value, a);
+ shouldBe(g.next().value, 42);
+ shouldBe(g.next().done, true);
+}
+{
+ let a = new A();
+ shouldThrow(() => {
+ let g = new a.gen();
+ }, `TypeError: function is not a constructor (evaluating 'new a.gen()')`);
+}
+
+{
+ let g = A.staticGen();
+ shouldBe(g.next().value, A);
+ shouldBe(g.next().value, A);
+ shouldBe(g.next().value, 42);
+ shouldBe(g.next().done, true);
+}
+{
+ &nb