[ES6] Implement LLInt/Baseline Support for ES6 Generators and enable this feature
https://bugs.webkit.org/show_bug.cgi?id=150792
Reviewed by Saam Barati.
.:
* Source/cmake/OptionsWin.cmake:
* Source/cmake/WebKitFeatures.cmake:
Source/JavaScriptCore:
This patch implements basic functionality of ES6 Generators in LLInt and Baseline tiers.
While the implementation has some inefficient part, the implementation covers edge cases.
Later, we will make this efficient.
https://bugs.webkit.org/show_bug.cgi?id=151545
https://bugs.webkit.org/show_bug.cgi?id=151546
https://bugs.webkit.org/show_bug.cgi?id=151547
https://bugs.webkit.org/show_bug.cgi?id=151552
https://bugs.webkit.org/show_bug.cgi?id=151560
https://bugs.webkit.org/show_bug.cgi?id=151586
To encourage DFG / FTL later, we take the following design.
1. Use switch_imm to jump to the save/resume points.
Instead of saving / restoring instruction pointer to resume from it, we use switch_imm to jump to the resume point.
This limits one entry point to a given generator function. This design makes inlining easy.
The generated code becomes the following.
function @generatorNext(@generator, @generatorState, @generatorValue, @generatorResumeMode)
{
switch (@generatorState) {
case Initial:
...
initial sequence.
...
op_save(Yield_0); // op_save contains *virtual* jump to Yield_0.
// CFG shows a jump edge to Yield_0 point, but it won't be actually used.
return ...;
case Yield_0:
op_resume();
if (@generatorResumeMode == Throw)
...
else if (@generatorResumeMode == Return)
...
...
// sentValue is a value sent from a caller by `generator.next(sentValue)`.
sentValue = @generatorValue;
...
op_save(Yield_1);
return ...;
case Yield_1:
op_resume();
if (@generatorResumeMode == Throw)
...
else if (@generatorResumeMode == Return)
...
...
sentValue = @generatorValue;
...
...
}
}
Resume sequence should not be emitted per yield.
This should be done in https://bugs.webkit.org/show_bug.cgi?id=151552.
2. Store live frame registers to GeneratorFrame
To save and resume generator's state, we save all the live registers in GeneratorFrame.
And when resuming, we refill registers with saved ones.
Since saved register contains scope register, |this| etc., the environment including the scope chain will be recovered automatically.
While saving and resuming callee registers, we don't save parameter registers.
These registers will be used to control generator's resume behavior.
We perform BytecodeLivenessAnalysis in CodeBlock to determine actually *def*ined registers at that resume point.
3. GeneratorFunction will evaluate parameters before generating Generator
Generator's parameter should be evaluated before entering Generator's body. For example,
function hello() { ... }
function *gen(a, b = hello())
{
yield b;
}
let g = gen(20); // Now, hello should be called.
To enable this, we evaluate parameters in GeneratorFunction, and after that, we create a Generator and return it.
This can be explained by the following pseudo code.
function *gen(a, b = hello())
{
// This is generator.
return {
@generatorNext: function (@generator, @generatorState, @generatorValue, @generatorResumeMode)
{
...
}
}
}
4. op_save seems similar to conditional jump
We won't jump to elsewhere from op_save actually. But we add a *virtual* jump edge (flow) from op_save to the point so called *merge point*.
We construct the CFG as follows,
(global generator switch) -> (initial sequence) -> (op_save) ----+-> (merge point) -> (next sequence)*
| | |
| v |
| (op_ret) |
| |
+------------------------------------------->(op_resume)--+
By constructing such a graph,
1. Since we have a flow from (op_save) to (merge point), at merge point, we can *use* locals that are defined before (op_save)
2. op_save should claim that it does not define anything. And claim that it *use*s locals that are used in (merge point).
3. at op_resume, we see *use*d locals at merge point and define all of them.
We can do the above things in use-def analysis because use-def analysis is backward analysis.
And after analyzing use-def chains, in op_save / op_resume, we only save / resume live registers at the head of merge point.
* API/JSScriptRef.cpp:
(parseScript):
* CMakeLists.txt:
* Configurations/FeatureDefines.xcconfig:
* DerivedSources.make:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* builtins/BuiltinExecutables.cpp:
(JSC::createExecutableInternal):
* builtins/GeneratorPrototype.js: Added.
(generatorResume):
(next):
(return):
(throw):
* bytecode/BytecodeBasicBlock.cpp:
(JSC::isBranch):
* bytecode/BytecodeList.json:
* bytecode/BytecodeLivenessAnalysis.cpp:
(JSC::stepOverInstruction):
(JSC::computeLocalLivenessForBytecodeOffset):
(JSC::BytecodeLivenessAnalysis::runLivenessFixpoint):
(JSC::BytecodeLivenessAnalysis::computeFullLiveness):
(JSC::BytecodeLivenessAnalysis::computeKills):
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::shrinkToFit):
(JSC::CodeBlock::validate):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::numCalleeLocals):
(JSC::CodeBlock::liveCalleeLocalsAtYield):
* bytecode/EvalCodeCache.h:
(JSC::EvalCodeCache::tryGet):
(JSC::EvalCodeCache::getSlow):
(JSC::EvalCodeCache::isCacheable):
* bytecode/ExecutableInfo.h:
(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::generatorThisMode):
(JSC::ExecutableInfo::superBinding):
(JSC::ExecutableInfo::parseMode):
(JSC::ExecutableInfo::isArrowFunction): Deleted.
* bytecode/PreciseJumpTargets.cpp:
(JSC::getJumpTargetsForBytecodeOffset):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::parseMode):
(JSC::UnlinkedCodeBlock::generatorThisMode):
(JSC::UnlinkedCodeBlock::superBinding):
(JSC::UnlinkedCodeBlock::isArrowFunction): Deleted.
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::generateUnlinkedFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
* bytecode/UnlinkedFunctionExecutable.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeParameters):
(JSC::BytecodeGenerator::newRegister):
(JSC::BytecodeGenerator::reclaimFreeRegisters):
(JSC::BytecodeGenerator::createVariable):
(JSC::BytecodeGenerator::emitCreateThis):
(JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
(JSC::BytecodeGenerator::emitNewFunctionExpression):
(JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
(JSC::BytecodeGenerator::emitNewFunction):
(JSC::BytecodeGenerator::emitIteratorNextWithValue):
(JSC::BytecodeGenerator::emitYieldPoint):
(JSC::BytecodeGenerator::emitSave):
(JSC::BytecodeGenerator::emitResume):
(JSC::BytecodeGenerator::emitYield):
(JSC::BytecodeGenerator::emitDelegateYield):
(JSC::BytecodeGenerator::emitGeneratorStateChange):
(JSC::BytecodeGenerator::emitGeneratorStateLabel):
(JSC::BytecodeGenerator::beginGenerator):
(JSC::BytecodeGenerator::endGenerator):
(JSC::BytecodeGenerator::emitNewFunctionInternal): Deleted.
(JSC::BytecodeGenerator::emitNewFunctionCommon): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::generatorThisMode):
(JSC::BytecodeGenerator::superBinding):
(JSC::BytecodeGenerator::generatorRegister):
(JSC::BytecodeGenerator::generatorStateRegister):
(JSC::BytecodeGenerator::generatorValueRegister):
(JSC::BytecodeGenerator::generatorResumeModeRegister):
(JSC::BytecodeGenerator::parseMode):
(JSC::BytecodeGenerator::registerFor):
(JSC::BytecodeGenerator::makeFunction):
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::emitHomeObjectForCallee):
(JSC::emitSuperBaseForCallee):
(JSC::ReturnNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):
(JSC::YieldExprNode::emitBytecode):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::inlineCall):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::handlePutById):
* dfg/DFGForAllKills.h:
(JSC::DFG::forAllKilledOperands):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::forAllLocalsLiveInBytecode):
* dfg/DFGOSREntrypointCreationPhase.cpp:
(JSC::DFG::OSREntrypointCreationPhase::run):
* dfg/DFGVariableEventStream.cpp:
(JSC::DFG::VariableEventStream::reconstruct):
* ftl/FTLForOSREntryJITCode.cpp:
(JSC::FTL::ForOSREntryJITCode::initializeEntryBuffer):
* ftl/FTLForOSREntryJITCode.h:
* ftl/FTLOSREntry.cpp:
(JSC::FTL::prepareOSREntry):
* ftl/FTLState.cpp:
(JSC::FTL::State::State):
* heap/MarkedBlock.h:
(JSC::MarkedBlock::isAtom):
(JSC::MarkedBlock::isLiveCell):
* interpreter/Interpreter.cpp:
(JSC::eval):
(JSC::Interpreter::dumpRegisters):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::frameRegisterCountFor):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emitNewFuncCommon):
(JSC::JIT::emit_op_new_func):
(JSC::JIT::emit_op_new_generator_func):
(JSC::JIT::emitNewFuncExprCommon):
(JSC::JIT::emit_op_new_func_exp):
(JSC::JIT::emit_op_new_generator_func_exp):
(JSC::JIT::emit_op_save):
(JSC::JIT::emit_op_resume):
* jit/JITOperations.cpp:
(JSC::operationNewFunctionCommon):
* jit/JITOperations.h:
* llint/LLIntEntrypoint.cpp:
(JSC::LLInt::frameRegisterCountFor):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::traceFunctionPrologue):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createYield):
(JSC::ASTBuilder::createFunctionMetadata):
(JSC::ASTBuilder::propagateArgumentsUse):
* parser/Nodes.cpp:
(JSC::FunctionMetadataNode::FunctionMetadataNode):
* parser/Nodes.h:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
(JSC::Parser<LexerType>::parseFunctionBody):
(JSC::stringForFunctionMode):
(JSC::Parser<LexerType>::createGeneratorParameters):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseYieldExpression):
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parseFunctionExpression):
* parser/Parser.h:
(JSC::Scope::Scope):
(JSC::Scope::setSourceParseMode):
(JSC::Scope::hasArguments):
(JSC::Scope::collectFreeVariables):
(JSC::Scope::setIsFunction):
(JSC::Scope::setIsGeneratorFunction):
(JSC::Scope::setIsGenerator):
(JSC::parse):
* parser/ParserModes.h:
(JSC::isFunctionParseMode):
(JSC::isModuleParseMode):
(JSC::isProgramParseMode):
* parser/SourceCodeKey.h: Added.
(JSC::SourceCodeKey::SourceCodeKey):
(JSC::SourceCodeKey::isHashTableDeletedValue):
(JSC::SourceCodeKey::hash):
(JSC::SourceCodeKey::length):
(JSC::SourceCodeKey::isNull):
(JSC::SourceCodeKey::string):
(JSC::SourceCodeKey::operator==):
(JSC::SourceCodeKeyHash::hash):
(JSC::SourceCodeKeyHash::equal):
(JSC::SourceCodeKeyHashTraits::isEmptyValue):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createYield):
(JSC::SyntaxChecker::createFunctionMetadata):
(JSC::SyntaxChecker::operatorStackPop):
* runtime/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):
* runtime/CodeCache.h:
(JSC::SourceCodeKey::SourceCodeKey): Deleted.
(JSC::SourceCodeKey::isHashTableDeletedValue): Deleted.
(JSC::SourceCodeKey::hash): Deleted.
(JSC::SourceCodeKey::length): Deleted.
(JSC::SourceCodeKey::isNull): Deleted.
(JSC::SourceCodeKey::string): Deleted.
(JSC::SourceCodeKey::operator==): Deleted.
(JSC::SourceCodeKeyHash::hash): Deleted.
(JSC::SourceCodeKeyHash::equal): Deleted.
(JSC::SourceCodeKeyHashTraits::isEmptyValue): Deleted.
* runtime/CommonIdentifiers.h:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/Completion.cpp:
(JSC::checkSyntax):
(JSC::checkModuleSyntax):
* runtime/Executable.cpp:
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ProgramExecutable::checkSyntax):
* runtime/Executable.h:
* runtime/FunctionConstructor.cpp:
(JSC::constructFunction):
(JSC::constructFunctionSkippingEvalEnabledCheck):
* runtime/FunctionConstructor.h:
* runtime/GeneratorFrame.cpp: Added.
(JSC::GeneratorFrame::GeneratorFrame):
(JSC::GeneratorFrame::finishCreation):
(JSC::GeneratorFrame::createStructure):
(JSC::GeneratorFrame::create):
(JSC::GeneratorFrame::save):
(JSC::GeneratorFrame::resume):
(JSC::GeneratorFrame::visitChildren):
* runtime/GeneratorFrame.h: Added.
(JSC::GeneratorFrame::locals):
(JSC::GeneratorFrame::localAt):
(JSC::GeneratorFrame::offsetOfLocals):
(JSC::GeneratorFrame::allocationSizeForLocals):
* runtime/GeneratorFunctionConstructor.cpp: Added.
(JSC::GeneratorFunctionConstructor::GeneratorFunctionConstructor):
(JSC::GeneratorFunctionConstructor::finishCreation):
(JSC::callGeneratorFunctionConstructor):
(JSC::constructGeneratorFunctionConstructor):
(JSC::GeneratorFunctionConstructor::getCallData):
(JSC::GeneratorFunctionConstructor::getConstructData):
* runtime/GeneratorFunctionConstructor.h: Added.
(JSC::GeneratorFunctionConstructor::create):
(JSC::GeneratorFunctionConstructor::createStructure):
* runtime/GeneratorFunctionPrototype.cpp: Added.
(JSC::GeneratorFunctionPrototype::GeneratorFunctionPrototype):
(JSC::GeneratorFunctionPrototype::finishCreation):
* runtime/GeneratorFunctionPrototype.h: Added.
(JSC::GeneratorFunctionPrototype::create):
(JSC::GeneratorFunctionPrototype::createStructure):
* runtime/GeneratorPrototype.cpp: Copied from Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp.
(JSC::GeneratorPrototype::finishCreation):
(JSC::GeneratorPrototype::getOwnPropertySlot):
* runtime/GeneratorPrototype.h: Copied from Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp.
(JSC::GeneratorPrototype::create):
(JSC::GeneratorPrototype::createStructure):
(JSC::GeneratorPrototype::GeneratorPrototype):
* runtime/GeneratorThisMode.h: Added.
* runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertySlot):
* runtime/JSGeneratorFunction.cpp: Added.
(JSC::JSGeneratorFunction::JSGeneratorFunction):
(JSC::JSGeneratorFunction::createImpl):
(JSC::JSGeneratorFunction::create):
(JSC::JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint):
* runtime/JSGeneratorFunction.h: Added.
(JSC::JSGeneratorFunction::allocationSize):
(JSC::JSGeneratorFunction::createStructure):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::generatorFunctionPrototype):
(JSC::JSGlobalObject::generatorPrototype):
(JSC::JSGlobalObject::generatorFunctionStructure):
* runtime/ModuleLoaderObject.cpp:
(JSC::moduleLoaderObjectParseModule):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
* tests/es6.yaml:
* tests/es6/generators_yield_star_generic_iterables.js:
(iterator.next):
(iterable.Symbol.iterator):
(__createIterableObject):
* tests/es6/generators_yield_star_instances_of_iterables.js:
(iterator.next):
(iterable.Symbol.iterator):
(__createIterableObject):
* tests/es6/generators_yield_star_iterator_closing.js:
(iterator.next):
(iterable.Symbol.iterator):
(__createIterableObject):
* tests/es6/generators_yield_star_iterator_closing_via_throw.js:
(iterator.next):
(iterable.Symbol.iterator):
(__createIterableObject):
* tests/stress/generator-arguments-from-function.js: Added.
(shouldBe):
(test):
* tests/stress/generator-arguments.js: Added.
(shouldBe):
(g1):
* tests/stress/generator-class-methods-syntax.js: Added.
(testSyntax):
(testSyntaxError):
(testSyntaxError.Cocoa):
(testSyntax.Cocoa.prototype.ok):
(testSyntax.Cocoa):
(testSyntax.Cocoa.ok):
* tests/stress/generator-class-methods.js: Added.
(shouldBe):
(prototype.gen):
(staticGen):
(shouldBe.g.next):
* tests/stress/generator-eval-this.js: Added.
(shouldBe):
(shouldThrow):
(B):
(A):
(C.prototype.generator):
(C):
(TypeError):
* tests/stress/generator-function-constructor.js: Added.
(shouldBe):
(generatorFunctionConstructor):
* tests/stress/generator-function-name.js: Added.
(shouldBe):
(ok):
* tests/stress/generator-methods-with-non-generator.js: Added.
(shouldThrow):
* tests/stress/generator-relations.js: Added.
(shouldBe):
(generatorFunction):
* tests/stress/generator-return-before-first-call.js: Added.
(shouldBe):
(shouldBeIteratorResult):
* tests/stress/generator-return.js: Added.
(shouldBe):
(shouldBeIteratorResult):
* tests/stress/generator-this.js: Added.
(shouldBe):
(shouldThrow):
(gen):
(shouldBe.g.next):
* tests/stress/generator-throw-before-first-call.js: Added.
(unreachable):
(gen):
(catch):
* tests/stress/generator-throw.js: Added.
(shouldBe):
(shouldBeIteratorResult):
* tests/stress/generator-with-new-target.js: Added.
(shouldBe):
(gen):
* tests/stress/generator-with-super.js: Added.
(shouldThrow):
(test):
(B.prototype.gen):
(B):
(A.prototype.gen):
(A):
* tests/stress/generator-yield-star.js: Added.
(shouldBe):
(shouldThrow):
(prototype.call):
(Arrays):
(Arrays.prototype.Symbol.iterator):
(Iterator.prototype.next):
(Iterator.prototype.string_appeared_here):
(Iterator.prototype.Symbol.iterator):
(Iterator):
(gen):
Source/WebCore:
* Configurations/FeatureDefines.xcconfig:
Source/WebKit/mac:
* Configurations/FeatureDefines.xcconfig:
Source/WebKit2:
* Configurations/FeatureDefines.xcconfig:
Source/WTF:
* wtf/FastBitVector.h:
(WTF::FastBitVector::forEachSetBit):
* wtf/FeatureDefines.h:
Tools:
* Scripts/webkitperl/FeatureList.pm:
WebKitLibraries:
* win/tools/vsprops/FeatureDefines.props:
* win/tools/vsprops/FeatureDefinesCairo.props:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@192937 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/ChangeLog b/ChangeLog
index 3f364b8..49ed35a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2015-12-01 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [ES6] Implement LLInt/Baseline Support for ES6 Generators and enable this feature
+ https://bugs.webkit.org/show_bug.cgi?id=150792
+
+ Reviewed by Saam Barati.
+
+ * Source/cmake/OptionsWin.cmake:
+ * Source/cmake/WebKitFeatures.cmake:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Source/JavaScriptCore/API/JSScriptRef.cpp b/Source/JavaScriptCore/API/JSScriptRef.cpp
index 3b7b76b..2f37423 100644
--- a/Source/JavaScriptCore/API/JSScriptRef.cpp
+++ b/Source/JavaScriptCore/API/JSScriptRef.cpp
@@ -71,7 +71,7 @@
{
return !!JSC::parse<JSC::ProgramNode>(
vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
- JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode,
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
error);
}
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index cae3cd2..7eeecfe 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -576,6 +576,10 @@
runtime/FunctionHasExecutedCache.cpp
runtime/FunctionPrototype.cpp
runtime/FunctionRareData.cpp
+ runtime/GeneratorFrame.cpp
+ runtime/GeneratorFunctionConstructor.cpp
+ runtime/GeneratorFunctionPrototype.cpp
+ runtime/GeneratorPrototype.cpp
runtime/GetterSetter.cpp
runtime/Identifier.cpp
runtime/IndexingType.cpp
@@ -615,6 +619,7 @@
runtime/JSDateMath.cpp
runtime/JSEnvironmentRecord.cpp
runtime/JSFunction.cpp
+ runtime/JSGeneratorFunction.cpp
runtime/JSGlobalLexicalEnvironment.cpp
runtime/JSGlobalObject.cpp
runtime/JSGlobalObjectDebuggable.cpp
@@ -750,6 +755,7 @@
runtime/DateConstructor.cpp
runtime/DatePrototype.cpp
runtime/ErrorPrototype.cpp
+ runtime/GeneratorPrototype.cpp
runtime/InspectorInstrumentationObject.cpp
runtime/IntlCollatorConstructor.cpp
runtime/IntlCollatorPrototype.cpp
@@ -1209,6 +1215,7 @@
${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
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 84e0009..5bce494 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,508 @@
+2015-12-01 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [ES6] Implement LLInt/Baseline Support for ES6 Generators and enable this feature
+ https://bugs.webkit.org/show_bug.cgi?id=150792
+
+ Reviewed by Saam Barati.
+
+ This patch implements basic functionality of ES6 Generators in LLInt and Baseline tiers.
+ While the implementation has some inefficient part, the implementation covers edge cases.
+ Later, we will make this efficient.
+
+ https://bugs.webkit.org/show_bug.cgi?id=151545
+ https://bugs.webkit.org/show_bug.cgi?id=151546
+ https://bugs.webkit.org/show_bug.cgi?id=151547
+ https://bugs.webkit.org/show_bug.cgi?id=151552
+ https://bugs.webkit.org/show_bug.cgi?id=151560
+ https://bugs.webkit.org/show_bug.cgi?id=151586
+
+ To encourage DFG / FTL later, we take the following design.
+
+ 1. Use switch_imm to jump to the save/resume points.
+
+ Instead of saving / restoring instruction pointer to resume from it, we use switch_imm to jump to the resume point.
+ This limits one entry point to a given generator function. This design makes inlining easy.
+ The generated code becomes the following.
+
+ function @generatorNext(@generator, @generatorState, @generatorValue, @generatorResumeMode)
+ {
+ switch (@generatorState) {
+ case Initial:
+ ...
+ initial sequence.
+ ...
+
+
+ op_save(Yield_0); // op_save contains *virtual* jump to Yield_0.
+ // CFG shows a jump edge to Yield_0 point, but it won't be actually used.
+ return ...;
+
+ case Yield_0:
+ op_resume();
+ if (@generatorResumeMode == Throw)
+ ...
+ else if (@generatorResumeMode == Return)
+ ...
+ ...
+ // sentValue is a value sent from a caller by `generator.next(sentValue)`.
+ sentValue = @generatorValue;
+ ...
+ op_save(Yield_1);
+ return ...;
+
+ case Yield_1:
+ op_resume();
+ if (@generatorResumeMode == Throw)
+ ...
+ else if (@generatorResumeMode == Return)
+ ...
+ ...
+ sentValue = @generatorValue;
+ ...
+
+ ...
+ }
+ }
+
+ Resume sequence should not be emitted per yield.
+ This should be done in https://bugs.webkit.org/show_bug.cgi?id=151552.
+
+ 2. Store live frame registers to GeneratorFrame
+
+ To save and resume generator's state, we save all the live registers in GeneratorFrame.
+ And when resuming, we refill registers with saved ones.
+ Since saved register contains scope register, |this| etc., the environment including the scope chain will be recovered automatically.
+ While saving and resuming callee registers, we don't save parameter registers.
+ These registers will be used to control generator's resume behavior.
+
+ We perform BytecodeLivenessAnalysis in CodeBlock to determine actually *def*ined registers at that resume point.
+
+ 3. GeneratorFunction will evaluate parameters before generating Generator
+
+ Generator's parameter should be evaluated before entering Generator's body. For example,
+
+ function hello() { ... }
+ function *gen(a, b = hello())
+ {
+ yield b;
+ }
+ let g = gen(20); // Now, hello should be called.
+
+ To enable this, we evaluate parameters in GeneratorFunction, and after that, we create a Generator and return it.
+ This can be explained by the following pseudo code.
+
+ function *gen(a, b = hello())
+ {
+ // This is generator.
+ return {
+ @generatorNext: function (@generator, @generatorState, @generatorValue, @generatorResumeMode)
+ {
+ ...
+ }
+ }
+ }
+
+ 4. op_save seems similar to conditional jump
+
+ We won't jump to elsewhere from op_save actually. But we add a *virtual* jump edge (flow) from op_save to the point so called *merge point*.
+ We construct the CFG as follows,
+
+ (global generator switch) -> (initial sequence) -> (op_save) ----+-> (merge point) -> (next sequence)*
+ | | |
+ | v |
+ | (op_ret) |
+ | |
+ +------------------------------------------->(op_resume)--+
+
+ By constructing such a graph,
+
+ 1. Since we have a flow from (op_save) to (merge point), at merge point, we can *use* locals that are defined before (op_save)
+ 2. op_save should claim that it does not define anything. And claim that it *use*s locals that are used in (merge point).
+ 3. at op_resume, we see *use*d locals at merge point and define all of them.
+
+ We can do the above things in use-def analysis because use-def analysis is backward analysis.
+ And after analyzing use-def chains, in op_save / op_resume, we only save / resume live registers at the head of merge point.
+
+ * API/JSScriptRef.cpp:
+ (parseScript):
+ * CMakeLists.txt:
+ * Configurations/FeatureDefines.xcconfig:
+ * DerivedSources.make:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * builtins/BuiltinExecutables.cpp:
+ (JSC::createExecutableInternal):
+ * builtins/GeneratorPrototype.js: Added.
+ (generatorResume):
+ (next):
+ (return):
+ (throw):
+ * bytecode/BytecodeBasicBlock.cpp:
+ (JSC::isBranch):
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeLivenessAnalysis.cpp:
+ (JSC::stepOverInstruction):
+ (JSC::computeLocalLivenessForBytecodeOffset):
+ (JSC::BytecodeLivenessAnalysis::runLivenessFixpoint):
+ (JSC::BytecodeLivenessAnalysis::computeFullLiveness):
+ (JSC::BytecodeLivenessAnalysis::computeKills):
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ (JSC::CodeBlock::CodeBlock):
+ (JSC::CodeBlock::finishCreation):
+ (JSC::CodeBlock::shrinkToFit):
+ (JSC::CodeBlock::validate):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::numCalleeLocals):
+ (JSC::CodeBlock::liveCalleeLocalsAtYield):
+ * bytecode/EvalCodeCache.h:
+ (JSC::EvalCodeCache::tryGet):
+ (JSC::EvalCodeCache::getSlow):
+ (JSC::EvalCodeCache::isCacheable):
+ * bytecode/ExecutableInfo.h:
+ (JSC::ExecutableInfo::ExecutableInfo):
+ (JSC::ExecutableInfo::generatorThisMode):
+ (JSC::ExecutableInfo::superBinding):
+ (JSC::ExecutableInfo::parseMode):
+ (JSC::ExecutableInfo::isArrowFunction): Deleted.
+ * bytecode/PreciseJumpTargets.cpp:
+ (JSC::getJumpTargetsForBytecodeOffset):
+ * bytecode/UnlinkedCodeBlock.cpp:
+ (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
+ * bytecode/UnlinkedCodeBlock.h:
+ (JSC::UnlinkedCodeBlock::parseMode):
+ (JSC::UnlinkedCodeBlock::generatorThisMode):
+ (JSC::UnlinkedCodeBlock::superBinding):
+ (JSC::UnlinkedCodeBlock::isArrowFunction): Deleted.
+ * bytecode/UnlinkedFunctionExecutable.cpp:
+ (JSC::generateUnlinkedFunctionCodeBlock):
+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+ (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
+ * bytecode/UnlinkedFunctionExecutable.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ (JSC::BytecodeGenerator::initializeParameters):
+ (JSC::BytecodeGenerator::newRegister):
+ (JSC::BytecodeGenerator::reclaimFreeRegisters):
+ (JSC::BytecodeGenerator::createVariable):
+ (JSC::BytecodeGenerator::emitCreateThis):
+ (JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
+ (JSC::BytecodeGenerator::emitNewFunctionExpression):
+ (JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
+ (JSC::BytecodeGenerator::emitNewFunction):
+ (JSC::BytecodeGenerator::emitIteratorNextWithValue):
+ (JSC::BytecodeGenerator::emitYieldPoint):
+ (JSC::BytecodeGenerator::emitSave):
+ (JSC::BytecodeGenerator::emitResume):
+ (JSC::BytecodeGenerator::emitYield):
+ (JSC::BytecodeGenerator::emitDelegateYield):
+ (JSC::BytecodeGenerator::emitGeneratorStateChange):
+ (JSC::BytecodeGenerator::emitGeneratorStateLabel):
+ (JSC::BytecodeGenerator::beginGenerator):
+ (JSC::BytecodeGenerator::endGenerator):
+ (JSC::BytecodeGenerator::emitNewFunctionInternal): Deleted.
+ (JSC::BytecodeGenerator::emitNewFunctionCommon): Deleted.
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::BytecodeGenerator::generatorThisMode):
+ (JSC::BytecodeGenerator::superBinding):
+ (JSC::BytecodeGenerator::generatorRegister):
+ (JSC::BytecodeGenerator::generatorStateRegister):
+ (JSC::BytecodeGenerator::generatorValueRegister):
+ (JSC::BytecodeGenerator::generatorResumeModeRegister):
+ (JSC::BytecodeGenerator::parseMode):
+ (JSC::BytecodeGenerator::registerFor):
+ (JSC::BytecodeGenerator::makeFunction):
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ThisNode::emitBytecode):
+ (JSC::emitHomeObjectForCallee):
+ (JSC::emitSuperBaseForCallee):
+ (JSC::ReturnNode::emitBytecode):
+ (JSC::FunctionNode::emitBytecode):
+ (JSC::YieldExprNode::emitBytecode):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::inlineCall):
+ (JSC::DFG::ByteCodeParser::handleGetById):
+ (JSC::DFG::ByteCodeParser::handlePutById):
+ * dfg/DFGForAllKills.h:
+ (JSC::DFG::forAllKilledOperands):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::forAllLocalsLiveInBytecode):
+ * dfg/DFGOSREntrypointCreationPhase.cpp:
+ (JSC::DFG::OSREntrypointCreationPhase::run):
+ * dfg/DFGVariableEventStream.cpp:
+ (JSC::DFG::VariableEventStream::reconstruct):
+ * ftl/FTLForOSREntryJITCode.cpp:
+ (JSC::FTL::ForOSREntryJITCode::initializeEntryBuffer):
+ * ftl/FTLForOSREntryJITCode.h:
+ * ftl/FTLOSREntry.cpp:
+ (JSC::FTL::prepareOSREntry):
+ * ftl/FTLState.cpp:
+ (JSC::FTL::State::State):
+ * heap/MarkedBlock.h:
+ (JSC::MarkedBlock::isAtom):
+ (JSC::MarkedBlock::isLiveCell):
+ * interpreter/Interpreter.cpp:
+ (JSC::eval):
+ (JSC::Interpreter::dumpRegisters):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::frameRegisterCountFor):
+ * jit/JIT.h:
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emitNewFuncCommon):
+ (JSC::JIT::emit_op_new_func):
+ (JSC::JIT::emit_op_new_generator_func):
+ (JSC::JIT::emitNewFuncExprCommon):
+ (JSC::JIT::emit_op_new_func_exp):
+ (JSC::JIT::emit_op_new_generator_func_exp):
+ (JSC::JIT::emit_op_save):
+ (JSC::JIT::emit_op_resume):
+ * jit/JITOperations.cpp:
+ (JSC::operationNewFunctionCommon):
+ * jit/JITOperations.h:
+ * llint/LLIntEntrypoint.cpp:
+ (JSC::LLInt::frameRegisterCountFor):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::traceFunctionPrologue):
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LLIntSlowPaths.h:
+ * llint/LowLevelInterpreter.asm:
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createYield):
+ (JSC::ASTBuilder::createFunctionMetadata):
+ (JSC::ASTBuilder::propagateArgumentsUse):
+ * parser/Nodes.cpp:
+ (JSC::FunctionMetadataNode::FunctionMetadataNode):
+ * parser/Nodes.h:
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::Parser):
+ (JSC::Parser<LexerType>::parseInner):
+ (JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
+ (JSC::Parser<LexerType>::parseFunctionBody):
+ (JSC::stringForFunctionMode):
+ (JSC::Parser<LexerType>::createGeneratorParameters):
+ (JSC::Parser<LexerType>::parseFunctionInfo):
+ (JSC::Parser<LexerType>::parseFunctionDeclaration):
+ (JSC::Parser<LexerType>::parseClass):
+ (JSC::Parser<LexerType>::parseAssignmentExpression):
+ (JSC::Parser<LexerType>::parseYieldExpression):
+ (JSC::Parser<LexerType>::parsePropertyMethod):
+ (JSC::Parser<LexerType>::parseFunctionExpression):
+ * parser/Parser.h:
+ (JSC::Scope::Scope):
+ (JSC::Scope::setSourceParseMode):
+ (JSC::Scope::hasArguments):
+ (JSC::Scope::collectFreeVariables):
+ (JSC::Scope::setIsFunction):
+ (JSC::Scope::setIsGeneratorFunction):
+ (JSC::Scope::setIsGenerator):
+ (JSC::parse):
+ * parser/ParserModes.h:
+ (JSC::isFunctionParseMode):
+ (JSC::isModuleParseMode):
+ (JSC::isProgramParseMode):
+ * parser/SourceCodeKey.h: Added.
+ (JSC::SourceCodeKey::SourceCodeKey):
+ (JSC::SourceCodeKey::isHashTableDeletedValue):
+ (JSC::SourceCodeKey::hash):
+ (JSC::SourceCodeKey::length):
+ (JSC::SourceCodeKey::isNull):
+ (JSC::SourceCodeKey::string):
+ (JSC::SourceCodeKey::operator==):
+ (JSC::SourceCodeKeyHash::hash):
+ (JSC::SourceCodeKeyHash::equal):
+ (JSC::SourceCodeKeyHashTraits::isEmptyValue):
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createYield):
+ (JSC::SyntaxChecker::createFunctionMetadata):
+ (JSC::SyntaxChecker::operatorStackPop):
+ * runtime/CodeCache.cpp:
+ (JSC::CodeCache::getGlobalCodeBlock):
+ (JSC::CodeCache::getFunctionExecutableFromGlobalCode):
+ * runtime/CodeCache.h:
+ (JSC::SourceCodeKey::SourceCodeKey): Deleted.
+ (JSC::SourceCodeKey::isHashTableDeletedValue): Deleted.
+ (JSC::SourceCodeKey::hash): Deleted.
+ (JSC::SourceCodeKey::length): Deleted.
+ (JSC::SourceCodeKey::isNull): Deleted.
+ (JSC::SourceCodeKey::string): Deleted.
+ (JSC::SourceCodeKey::operator==): Deleted.
+ (JSC::SourceCodeKeyHash::hash): Deleted.
+ (JSC::SourceCodeKeyHash::equal): Deleted.
+ (JSC::SourceCodeKeyHashTraits::isEmptyValue): Deleted.
+ * runtime/CommonIdentifiers.h:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/CommonSlowPaths.h:
+ * runtime/Completion.cpp:
+ (JSC::checkSyntax):
+ (JSC::checkModuleSyntax):
+ * runtime/Executable.cpp:
+ (JSC::ScriptExecutable::newCodeBlockFor):
+ (JSC::ProgramExecutable::checkSyntax):
+ * runtime/Executable.h:
+ * runtime/FunctionConstructor.cpp:
+ (JSC::constructFunction):
+ (JSC::constructFunctionSkippingEvalEnabledCheck):
+ * runtime/FunctionConstructor.h:
+ * runtime/GeneratorFrame.cpp: Added.
+ (JSC::GeneratorFrame::GeneratorFrame):
+ (JSC::GeneratorFrame::finishCreation):
+ (JSC::GeneratorFrame::createStructure):
+ (JSC::GeneratorFrame::create):
+ (JSC::GeneratorFrame::save):
+ (JSC::GeneratorFrame::resume):
+ (JSC::GeneratorFrame::visitChildren):
+ * runtime/GeneratorFrame.h: Added.
+ (JSC::GeneratorFrame::locals):
+ (JSC::GeneratorFrame::localAt):
+ (JSC::GeneratorFrame::offsetOfLocals):
+ (JSC::GeneratorFrame::allocationSizeForLocals):
+ * runtime/GeneratorFunctionConstructor.cpp: Added.
+ (JSC::GeneratorFunctionConstructor::GeneratorFunctionConstructor):
+ (JSC::GeneratorFunctionConstructor::finishCreation):
+ (JSC::callGeneratorFunctionConstructor):
+ (JSC::constructGeneratorFunctionConstructor):
+ (JSC::GeneratorFunctionConstructor::getCallData):
+ (JSC::GeneratorFunctionConstructor::getConstructData):
+ * runtime/GeneratorFunctionConstructor.h: Added.
+ (JSC::GeneratorFunctionConstructor::create):
+ (JSC::GeneratorFunctionConstructor::createStructure):
+ * runtime/GeneratorFunctionPrototype.cpp: Added.
+ (JSC::GeneratorFunctionPrototype::GeneratorFunctionPrototype):
+ (JSC::GeneratorFunctionPrototype::finishCreation):
+ * runtime/GeneratorFunctionPrototype.h: Added.
+ (JSC::GeneratorFunctionPrototype::create):
+ (JSC::GeneratorFunctionPrototype::createStructure):
+ * runtime/GeneratorPrototype.cpp: Copied from Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp.
+ (JSC::GeneratorPrototype::finishCreation):
+ (JSC::GeneratorPrototype::getOwnPropertySlot):
+ * runtime/GeneratorPrototype.h: Copied from Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp.
+ (JSC::GeneratorPrototype::create):
+ (JSC::GeneratorPrototype::createStructure):
+ (JSC::GeneratorPrototype::GeneratorPrototype):
+ * runtime/GeneratorThisMode.h: Added.
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::getOwnPropertySlot):
+ * runtime/JSGeneratorFunction.cpp: Added.
+ (JSC::JSGeneratorFunction::JSGeneratorFunction):
+ (JSC::JSGeneratorFunction::createImpl):
+ (JSC::JSGeneratorFunction::create):
+ (JSC::JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint):
+ * runtime/JSGeneratorFunction.h: Added.
+ (JSC::JSGeneratorFunction::allocationSize):
+ (JSC::JSGeneratorFunction::createStructure):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ (JSC::JSGlobalObject::visitChildren):
+ * runtime/JSGlobalObject.h:
+ (JSC::JSGlobalObject::generatorFunctionPrototype):
+ (JSC::JSGlobalObject::generatorPrototype):
+ (JSC::JSGlobalObject::generatorFunctionStructure):
+ * runtime/ModuleLoaderObject.cpp:
+ (JSC::moduleLoaderObjectParseModule):
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+ * tests/es6.yaml:
+ * tests/es6/generators_yield_star_generic_iterables.js:
+ (iterator.next):
+ (iterable.Symbol.iterator):
+ (__createIterableObject):
+ * tests/es6/generators_yield_star_instances_of_iterables.js:
+ (iterator.next):
+ (iterable.Symbol.iterator):
+ (__createIterableObject):
+ * tests/es6/generators_yield_star_iterator_closing.js:
+ (iterator.next):
+ (iterable.Symbol.iterator):
+ (__createIterableObject):
+ * tests/es6/generators_yield_star_iterator_closing_via_throw.js:
+ (iterator.next):
+ (iterable.Symbol.iterator):
+ (__createIterableObject):
+ * tests/stress/generator-arguments-from-function.js: Added.
+ (shouldBe):
+ (test):
+ * tests/stress/generator-arguments.js: Added.
+ (shouldBe):
+ (g1):
+ * tests/stress/generator-class-methods-syntax.js: Added.
+ (testSyntax):
+ (testSyntaxError):
+ (testSyntaxError.Cocoa):
+ (testSyntax.Cocoa.prototype.ok):
+ (testSyntax.Cocoa):
+ (testSyntax.Cocoa.ok):
+ * tests/stress/generator-class-methods.js: Added.
+ (shouldBe):
+ (prototype.gen):
+ (staticGen):
+ (shouldBe.g.next):
+ * tests/stress/generator-eval-this.js: Added.
+ (shouldBe):
+ (shouldThrow):
+ (B):
+ (A):
+ (C.prototype.generator):
+ (C):
+ (TypeError):
+ * tests/stress/generator-function-constructor.js: Added.
+ (shouldBe):
+ (generatorFunctionConstructor):
+ * tests/stress/generator-function-name.js: Added.
+ (shouldBe):
+ (ok):
+ * tests/stress/generator-methods-with-non-generator.js: Added.
+ (shouldThrow):
+ * tests/stress/generator-relations.js: Added.
+ (shouldBe):
+ (generatorFunction):
+ * tests/stress/generator-return-before-first-call.js: Added.
+ (shouldBe):
+ (shouldBeIteratorResult):
+ * tests/stress/generator-return.js: Added.
+ (shouldBe):
+ (shouldBeIteratorResult):
+ * tests/stress/generator-this.js: Added.
+ (shouldBe):
+ (shouldThrow):
+ (gen):
+ (shouldBe.g.next):
+ * tests/stress/generator-throw-before-first-call.js: Added.
+ (unreachable):
+ (gen):
+ (catch):
+ * tests/stress/generator-throw.js: Added.
+ (shouldBe):
+ (shouldBeIteratorResult):
+ * tests/stress/generator-with-new-target.js: Added.
+ (shouldBe):
+ (gen):
+ * tests/stress/generator-with-super.js: Added.
+ (shouldThrow):
+ (test):
+ (B.prototype.gen):
+ (B):
+ (A.prototype.gen):
+ (A):
+ * tests/stress/generator-yield-star.js: Added.
+ (shouldBe):
+ (shouldThrow):
+ (prototype.call):
+ (Arrays):
+ (Arrays.prototype.Symbol.iterator):
+ (Iterator.prototype.next):
+ (Iterator.prototype.string_appeared_here):
+ (Iterator.prototype.Symbol.iterator):
+ (Iterator):
+ (gen):
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
index e177afc..18d64d0 100644
--- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
+++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
@@ -47,7 +47,7 @@
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;
diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make
index 3758a36..768ebaa 100644
--- a/Source/JavaScriptCore/DerivedSources.make
+++ b/Source/JavaScriptCore/DerivedSources.make
@@ -84,6 +84,7 @@
$(JavaScriptCore)/builtins/ArrayIteratorPrototype.js \
$(JavaScriptCore)/builtins/ArrayPrototype.js \
$(JavaScriptCore)/builtins/FunctionPrototype.js \
+ $(JavaScriptCore)/builtins/GeneratorPrototype.js \
$(JavaScriptCore)/builtins/GlobalObject.js \
$(JavaScriptCore)/builtins/InspectorInstrumentationObject.js \
$(JavaScriptCore)/builtins/InternalPromiseConstructor.js \
@@ -119,6 +120,7 @@
DateConstructor.lut.h \
DatePrototype.lut.h \
ErrorPrototype.lut.h \
+ GeneratorPrototype.lut.h \
InspectorInstrumentationObject.lut.h \
IntlCollatorConstructor.lut.h \
IntlCollatorPrototype.lut.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 9a206a0..62d21d2 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -758,6 +758,10 @@
<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" />
@@ -797,6 +801,7 @@
<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" />
@@ -947,6 +952,7 @@
<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" />
@@ -1521,6 +1527,7 @@
<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" />
@@ -1607,6 +1614,11 @@
<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" />
@@ -1666,6 +1678,7 @@
<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" />
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
index 951c3c5..b900af0 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
@@ -669,6 +669,18 @@
<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>
@@ -750,6 +762,9 @@
<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>
@@ -2624,6 +2639,9 @@
<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>
@@ -2825,6 +2843,21 @@
<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>
@@ -2930,6 +2963,9 @@
<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>
@@ -3294,6 +3330,9 @@
<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>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 68b9502..339b340 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -1208,6 +1208,19 @@
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 */; };
@@ -3287,6 +3300,20 @@
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>"; };
@@ -5116,6 +5143,7 @@
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 */,
@@ -5244,6 +5272,7 @@
869EBCB60E8C6D4A008722CC /* ResultType.h */,
0F8F2B9D17306C8B007DBDA5 /* SourceCode.cpp */,
65E866EE0DD59AFA00A2B2A1 /* SourceCode.h */,
+ 70B7918E1C0244C9002481E2 /* SourceCodeKey.h */,
0F493AF816D0CAD10084508B /* SourceProvider.cpp */,
65E866ED0DD59AFA00A2B2A1 /* SourceProvider.h */,
E49DC15512EF277200184A1F /* SourceProviderCache.cpp */,
@@ -5373,6 +5402,15 @@
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 */,
@@ -5472,6 +5510,8 @@
F692A85E0255597D01FF60F7 /* JSFunction.cpp */,
F692A85F0255597D01FF60F7 /* JSFunction.h */,
A72028B91797603D0098028C /* JSFunctionInlines.h */,
+ 70B7918C1C024462002481E2 /* JSGeneratorFunction.cpp */,
+ 70B7918D1C024462002481E2 /* JSGeneratorFunction.h */,
0F2B66C317B6B5AB00A7AE3F /* JSGenericTypedArrayView.h */,
0F2B66C417B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h */,
0F2B66C517B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h */,
@@ -6586,6 +6626,7 @@
A75EE9B018AAB7E200AAD043 /* BuiltinNames.h */,
41DEA1311B9F3154006D65DD /* BuiltinUtils.h */,
A7A979C418BE8D9E002C3733 /* FunctionPrototype.js */,
+ 70B7918F1C0244EC002481E2 /* GeneratorPrototype.js */,
7CF9BC5A1B65D9A3009DB1EF /* GlobalObject.js */,
E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */,
E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */,
@@ -7002,6 +7043,7 @@
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 */,
@@ -7052,6 +7094,7 @@
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 */,
@@ -7273,6 +7316,7 @@
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 */,
@@ -7300,6 +7344,7 @@
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 */,
@@ -7443,6 +7488,7 @@
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 */,
@@ -7479,6 +7525,7 @@
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 */,
@@ -7652,6 +7699,7 @@
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 */,
@@ -7684,6 +7732,7 @@
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 */,
@@ -8705,6 +8754,7 @@
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 */,
@@ -8731,6 +8781,7 @@
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 */,
@@ -8868,6 +8919,7 @@
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 */,
@@ -9016,6 +9068,7 @@
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 */,
@@ -9024,6 +9077,7 @@
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 */,
diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
index 816b4a5..a9e69be 100644
--- a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
+++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
@@ -82,7 +82,7 @@
RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr;
std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
&vm, source, Identifier(), builtinMode,
- JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error,
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error,
&positionBeforeLastNewline, constructorKind);
if (!program) {
@@ -115,7 +115,7 @@
}
metadata->overrideName(name);
VariableEnvironment dummyTDZVariables;
- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, dummyTDZVariables, WTF::move(sourceOverride));
+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, GeneratorThisMode::NonEmpty, dummyTDZVariables, WTF::move(sourceOverride));
functionExecutable->setNameValue(vm, jsString(&vm, name.string()));
return functionExecutable;
}
diff --git a/Source/JavaScriptCore/builtins/GeneratorPrototype.js b/Source/JavaScriptCore/builtins/GeneratorPrototype.js
new file mode 100644
index 0000000..a3bbc35
--- /dev/null
+++ b/Source/JavaScriptCore/builtins/GeneratorPrototype.js
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// 25.3.3.3 GeneratorResume ( generator, value )
+// 25.3.3.4 GeneratorResumeAbrupt(generator, abruptCompletion)
+function generatorResume(generator, sentValue, resumeMode)
+{
+ "use strict";
+
+ // GeneratorState.
+ const Completed = -1;
+ const Executing = -2;
+
+ // ResumeMode.
+ const NormalMode = 0;
+ const ReturnMode = 1;
+ const ThrowMode = 2;
+
+ let state = generator.@generatorState;
+ let done = false;
+ let value = undefined;
+
+ if (typeof state !== 'number')
+ throw new @TypeError("|this| should be a generator");
+
+ if (state === Executing)
+ throw new @TypeError("Generator is executing");
+
+ if (state === Completed) {
+ if (resumeMode === ThrowMode)
+ throw sentValue;
+
+ done = true;
+ if (resumeMode === ReturnMode)
+ value = sentValue;
+ } else {
+ try {
+ generator.@generatorState = Executing;
+ value = generator.@generatorNext.@call(generator.@generatorThis, generator, state, sentValue, resumeMode);
+ if (generator.@generatorState === Executing) {
+ generator.@generatorState = Completed;
+ done = true;
+ }
+ } catch (error) {
+ generator.@generatorState = Completed;
+ throw error;
+ }
+ }
+ return { done, value };
+}
+
+function next(value)
+{
+ "use strict";
+
+ return @generatorResume(this, value, /* NormalMode */ 0);
+}
+
+function return(value)
+{
+ "use strict";
+
+ return @generatorResume(this, value, /* ReturnMode */ 1);
+}
+
+function throw(exception)
+{
+ "use strict";
+
+ return @generatorResume(this, exception, /* ThrowMode */ 2);
+}
diff --git a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
index 54dfd16..596064c 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp
@@ -59,6 +59,7 @@
case op_switch_char:
case op_switch_string:
case op_check_has_instance:
+ case op_save:
return true;
default:
return false;
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json
index f6c89a9..43d7012 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.json
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json
@@ -90,6 +90,8 @@
{ "name" : "op_switch_string", "length" : 4 },
{ "name" : "op_new_func", "length" : 4 },
{ "name" : "op_new_func_exp", "length" : 4 },
+ { "name" : "op_new_generator_func", "length" : 4 },
+ { "name" : "op_new_generator_func_exp", "length" : 4 },
{ "name" : "op_new_arrow_func_exp", "length" : 5 },
{ "name" : "op_call", "length" : 9 },
{ "name" : "op_tail_call", "length" : 9 },
@@ -130,7 +132,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 }
]
},
{
diff --git a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
index c77abea..7228b03 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
@@ -98,7 +98,7 @@
// Simplified interface to bytecode use/def, which determines defs first and then uses, and includes
// exception handlers in the uses.
template<typename UseFunctor, typename DefFunctor>
-static void stepOverInstruction(CodeBlock* codeBlock, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def)
+static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def)
{
// This abstractly execute the instruction in reverse. Instructions logically first use operands and
// then define operands. This logical ordering is necessary for operations that use and def the same
@@ -116,19 +116,19 @@
// first add it to the out set (the use), and then we'd remove it (the def).
computeDefsForBytecodeOffset(
- codeBlock, bytecodeOffset,
+ codeBlock, block, bytecodeOffset,
[&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) {
if (isValidRegisterForLiveness(codeBlock, operand))
def(VirtualRegister(operand).toLocal());
});
computeUsesForBytecodeOffset(
- codeBlock, bytecodeOffset,
+ codeBlock, block, bytecodeOffset,
[&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) {
if (isValidRegisterForLiveness(codeBlock, operand))
use(VirtualRegister(operand).toLocal());
});
-
+
// If we have an exception handler, we want the live-in variables of the
// exception handler block to be included in the live-in of this particular bytecode.
if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset)) {
@@ -138,10 +138,10 @@
}
}
-static void stepOverInstruction(CodeBlock* codeBlock, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& out)
+static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& out)
{
stepOverInstruction(
- codeBlock, basicBlocks, bytecodeOffset,
+ codeBlock, block, basicBlocks, bytecodeOffset,
[&] (unsigned bitIndex) {
// This is the use functor, so we set the bit.
out.set(bitIndex);
@@ -164,7 +164,7 @@
if (targetOffset > bytecodeOffset)
break;
- stepOverInstruction(codeBlock, basicBlocks, bytecodeOffset, out);
+ stepOverInstruction(codeBlock, block, basicBlocks, bytecodeOffset, out);
}
result.set(out);
@@ -180,7 +180,7 @@
void BytecodeLivenessAnalysis::runLivenessFixpoint()
{
UnlinkedCodeBlock* unlinkedCodeBlock = m_codeBlock->unlinkedCodeBlock();
- unsigned numberOfVariables = unlinkedCodeBlock->m_numCalleeRegisters;
+ unsigned numberOfVariables = unlinkedCodeBlock->m_numCalleeLocals;
for (unsigned i = 0; i < m_basicBlocks.size(); i++) {
BytecodeBasicBlock* block = m_basicBlocks[i].get();
@@ -248,7 +248,7 @@
for (unsigned i = block->bytecodeOffsets().size(); i--;) {
unsigned bytecodeOffset = block->bytecodeOffsets()[i];
- stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, out);
+ stepOverInstruction(m_codeBlock, block, m_basicBlocks, bytecodeOffset, out);
result.m_map[bytecodeOffset] = out;
}
}
@@ -271,7 +271,7 @@
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))
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index cbb8948..fe026fa 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -32,7 +32,7 @@
template<typename Functor>
void computeUsesForBytecodeOffset(
- CodeBlock* codeBlock, unsigned bytecodeOffset, const Functor& functor)
+ CodeBlock* codeBlock, BytecodeBasicBlock* block, unsigned bytecodeOffset, const Functor& functor)
{
Interpreter* interpreter = codeBlock->vm()->interpreter;
Instruction* instructionsBegin = codeBlock->instructions().begin();
@@ -71,7 +71,8 @@
case op_jeq_null:
case op_jneq_null:
case op_dec:
- case op_inc: {
+ case op_inc:
+ case op_resume: {
functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
return;
}
@@ -125,6 +126,7 @@
case op_get_property_enumerator:
case op_get_enumerable_length:
case op_new_func_exp:
+ case op_new_generator_func_exp:
case op_new_arrow_func_exp:
case op_to_index_string:
case op_create_lexical_environment:
@@ -153,6 +155,7 @@
case op_del_by_id:
case op_unsigned:
case op_new_func:
+ case op_new_generator_func:
case op_get_parent_scope:
case op_create_scoped_arguments:
case op_get_from_arguments: {
@@ -234,6 +237,22 @@
functor(codeBlock, instruction, opcodeID, lastArg + i);
return;
}
+ case op_save: {
+ functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+ unsigned mergePointBytecodeOffset = bytecodeOffset + instruction[3].u.operand;
+ BytecodeBasicBlock* mergePointBlock = nullptr;
+ for (BytecodeBasicBlock* successor : block->successors()) {
+ if (successor->leaderBytecodeOffset() == mergePointBytecodeOffset) {
+ mergePointBlock = successor;
+ break;
+ }
+ }
+ ASSERT(mergePointBlock);
+ mergePointBlock->in().forEachSetBit([&](unsigned local) {
+ functor(codeBlock, instruction, opcodeID, virtualRegisterForLocal(local).offset());
+ });
+ return;
+ }
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -241,7 +260,7 @@
}
template<typename Functor>
-void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, const Functor& functor)
+void computeDefsForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* block, unsigned bytecodeOffset, const Functor& functor)
{
Interpreter* interpreter = codeBlock->vm()->interpreter;
Instruction* instructionsBegin = codeBlock->instructions().begin();
@@ -256,6 +275,7 @@
case op_profile_did_call:
case op_throw:
case op_throw_static_error:
+ case op_save:
case op_assert:
case op_debug:
case op_ret:
@@ -316,6 +336,8 @@
case op_new_regexp:
case op_new_func:
case op_new_func_exp:
+ case op_new_generator_func:
+ case op_new_generator_func_exp:
case op_new_arrow_func_exp:
case op_call_varargs:
case op_tail_call_varargs:
@@ -392,7 +414,15 @@
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
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 9e1386e..0ab781c 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -585,7 +585,7 @@
": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
static_cast<unsigned long>(instructions().size()),
static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
- m_numParameters, m_numCalleeRegisters, m_numVars);
+ m_numParameters, m_numCalleeLocals, m_numVars);
if (needsActivation() && codeType() == FunctionCode)
out.printf("; lexical environment in r%d", activationRegister().offset());
out.printf("\n");
@@ -680,6 +680,18 @@
} while (i < m_rareData->m_stringSwitchJumpTables.size());
}
+ if (m_rareData && !m_rareData->m_liveCalleeLocalsAtYield.isEmpty()) {
+ out.printf("\nLive Callee Locals:\n");
+ unsigned i = 0;
+ do {
+ const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[i];
+ out.printf(" live%1u = ", i);
+ liveness.dump(out);
+ out.printf("\n");
+ ++i;
+ } while (i < m_rareData->m_liveCalleeLocalsAtYield.size());
+ }
+
out.printf("\n");
}
@@ -1303,6 +1315,14 @@
out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
break;
}
+ case op_new_generator_func: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int f0 = (++it)->u.operand;
+ printLocationAndOp(out, exec, location, it, "new_generator_func");
+ out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+ break;
+ }
case op_new_arrow_func_exp: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
@@ -1320,6 +1340,14 @@
out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
break;
}
+ case op_new_generator_func_exp: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int f0 = (++it)->u.operand;
+ printLocationAndOp(out, exec, location, it, "new_generator_func_exp");
+ out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+ break;
+ }
case op_call: {
printCallOp(out, exec, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos);
break;
@@ -1508,6 +1536,27 @@
out.printf("%s, %d", debugHookName(debugHookID), hasBreakpointFlag);
break;
}
+ case op_save: {
+ int generator = (++it)->u.operand;
+ unsigned liveCalleeLocalsIndex = (++it)->u.unsignedValue;
+ int offset = (++it)->u.operand;
+ const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex];
+ printLocationAndOp(out, exec, location, it, "save");
+ out.printf("%s, ", registerName(generator).data());
+ liveness.dump(out);
+ out.printf("(@live%1u), %d(->%d)", liveCalleeLocalsIndex, offset, location + offset);
+ break;
+ }
+ case op_resume: {
+ int generator = (++it)->u.operand;
+ unsigned liveCalleeLocalsIndex = (++it)->u.unsignedValue;
+ const FastBitVector& liveness = m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex];
+ printLocationAndOp(out, exec, location, it, "resume");
+ out.printf("%s, ", registerName(generator).data());
+ liveness.dump(out);
+ out.printf("(@live%1u)", liveCalleeLocalsIndex);
+ break;
+ }
case op_assert: {
int condition = (++it)->u.operand;
int line = (++it)->u.operand;
@@ -1672,7 +1721,7 @@
: JSCell(*vm, structure)
, m_globalObject(other.m_globalObject)
, m_heap(other.m_heap)
- , m_numCalleeRegisters(other.m_numCalleeRegisters)
+ , m_numCalleeLocals(other.m_numCalleeLocals)
, m_numVars(other.m_numVars)
, m_isConstructor(other.m_isConstructor)
, m_shouldAlwaysBeInlined(true)
@@ -1729,6 +1778,7 @@
m_rareData->m_constantBuffers = other.m_rareData->m_constantBuffers;
m_rareData->m_switchJumpTables = other.m_rareData->m_switchJumpTables;
m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
+ m_rareData->m_liveCalleeLocalsAtYield = other.m_rareData->m_liveCalleeLocalsAtYield;
}
m_heap->m_codeBlocks.add(this);
@@ -1739,7 +1789,7 @@
: JSCell(*vm, structure)
, m_globalObject(scope->globalObject()->vm(), this, scope->globalObject())
, m_heap(&m_globalObject->vm().heap)
- , m_numCalleeRegisters(unlinkedCodeBlock->m_numCalleeRegisters)
+ , m_numCalleeLocals(unlinkedCodeBlock->m_numCalleeLocals)
, m_numVars(unlinkedCodeBlock->m_numVars)
, m_isConstructor(unlinkedCodeBlock->isConstructor())
, m_shouldAlwaysBeInlined(true)
@@ -1909,6 +1959,9 @@
// Bookkeep the strongly referenced module environments.
HashSet<JSModuleEnvironment*> stronglyReferencedModuleEnvironments;
+ // Bookkeep the merge point bytecode offsets.
+ Vector<size_t> mergePointBytecodeOffsets;
+
RefCountedArray<Instruction> instructions(instructionCount);
for (unsigned i = 0; !instructionReader.atEnd(); ) {
@@ -2197,6 +2250,15 @@
break;
}
+ case op_save: {
+ unsigned liveCalleeLocalsIndex = pc[2].u.index;
+ int offset = pc[3].u.operand;
+ if (liveCalleeLocalsIndex >= mergePointBytecodeOffsets.size())
+ mergePointBytecodeOffsets.resize(liveCalleeLocalsIndex + 1);
+ mergePointBytecodeOffsets[liveCalleeLocalsIndex] = i + offset;
+ break;
+ }
+
default:
break;
}
@@ -2208,6 +2270,20 @@
m_instructions = WTF::move(instructions);
+ // Perform bytecode liveness analysis to determine which locals are live and should be resumed when executing op_resume.
+ if (unlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode) {
+ if (size_t count = mergePointBytecodeOffsets.size()) {
+ createRareDataIfNecessary();
+ BytecodeLivenessAnalysis liveness(this);
+ m_rareData->m_liveCalleeLocalsAtYield.grow(count);
+ size_t liveCalleeLocalsIndex = 0;
+ for (size_t bytecodeOffset : mergePointBytecodeOffsets) {
+ m_rareData->m_liveCalleeLocalsAtYield[liveCalleeLocalsIndex] = liveness.getLivenessInfoAtBytecodeOffset(bytecodeOffset);
+ ++liveCalleeLocalsIndex;
+ }
+ }
+ }
+
// Set optimization thresholds only after m_instructions is initialized, since these
// rely on the instruction count (and are in theory permitted to also inspect the
// instruction stream to more accurate assess the cost of tier-up).
@@ -2231,7 +2307,7 @@
: JSCell(*vm, structure)
, m_globalObject(globalObject->vm(), this, globalObject)
, m_heap(&m_globalObject->vm().heap)
- , m_numCalleeRegisters(0)
+ , m_numCalleeLocals(0)
, m_numVars(0)
, m_isConstructor(false)
, m_shouldAlwaysBeInlined(false)
@@ -3058,6 +3134,7 @@
if (m_rareData) {
m_rareData->m_switchJumpTables.shrinkToFit();
m_rareData->m_stringSwitchJumpTables.shrinkToFit();
+ m_rareData->m_liveCalleeLocalsAtYield.shrinkToFit();
}
} // else don't shrink these, because we would have already pointed pointers into these tables.
}
@@ -4029,7 +4106,7 @@
FastBitVector liveAtHead = liveness.getLivenessInfoAtBytecodeOffset(0);
- if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeRegisters)) {
+ if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeLocals)) {
beginValidationDidFail();
dataLog(" Wrong number of bits in result!\n");
dataLog(" Result: ", liveAtHead, "\n");
@@ -4037,7 +4114,7 @@
endValidationDidFail();
}
- for (unsigned i = m_numCalleeRegisters; i--;) {
+ for (unsigned i = m_numCalleeLocals; i--;) {
VirtualRegister reg = virtualRegisterForLocal(i);
if (liveAtHead.get(i)) {
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index c1df187..3cbe75c 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -69,6 +69,7 @@
#include "VirtualRegister.h"
#include "Watchpoint.h"
#include <wtf/Bag.h>
+#include <wtf/FastBitVector.h>
#include <wtf/FastMalloc.h>
#include <wtf/RefCountedArray.h>
#include <wtf/RefPtr.h>
@@ -141,6 +142,8 @@
int numParameters() const { return m_numParameters; }
void setNumParameters(int newValue);
+ int numCalleeLocals() const { return m_numCalleeLocals; }
+
int* addressOfNumParameters() { return &m_numParameters; }
static ptrdiff_t offsetOfNumParameters() { return OBJECT_OFFSETOF(CodeBlock, m_numParameters); }
@@ -654,6 +657,18 @@
StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
StringJumpTable& stringSwitchJumpTable(int tableIndex) { RELEASE_ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
+ // Live callee registers at yield points.
+ const FastBitVector& liveCalleeLocalsAtYield(unsigned index) const
+ {
+ RELEASE_ASSERT(m_rareData);
+ return m_rareData->m_liveCalleeLocalsAtYield[index];
+ }
+ FastBitVector& liveCalleeLocalsAtYield(unsigned index)
+ {
+ RELEASE_ASSERT(m_rareData);
+ return m_rareData->m_liveCalleeLocalsAtYield[index];
+ }
+
EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; }
enum ShrinkMode {
@@ -855,7 +870,7 @@
// FIXME: Make these remaining members private.
int m_numLocalRegistersForCalleeSaves;
- int m_numCalleeRegisters;
+ int m_numCalleeLocals;
int m_numVars;
bool m_isConstructor : 1;
@@ -900,6 +915,8 @@
Vector<SimpleJumpTable> m_switchJumpTables;
Vector<StringJumpTable> m_stringSwitchJumpTables;
+ Vector<FastBitVector> m_liveCalleeLocalsAtYield;
+
EvalCodeCache m_evalCodeCache;
};
diff --git a/Source/JavaScriptCore/bytecode/EvalCodeCache.h b/Source/JavaScriptCore/bytecode/EvalCodeCache.h
index 62521fc..83703cf 100644
--- a/Source/JavaScriptCore/bytecode/EvalCodeCache.h
+++ b/Source/JavaScriptCore/bytecode/EvalCodeCache.h
@@ -34,6 +34,7 @@
#include "JSScope.h"
#include "Options.h"
#include "SourceCode.h"
+#include "SourceCodeKey.h"
#include <wtf/HashMap.h>
#include <wtf/RefPtr.h>
#include <wtf/text/StringHash.h>
@@ -44,23 +45,29 @@
class EvalCodeCache {
public:
- EvalExecutable* tryGet(bool inStrictContext, const String& evalSource, JSScope* scope)
+ EvalExecutable* tryGet(bool inStrictContext, const SourceCode& evalSource, ThisTDZMode thisTDZMode, JSScope* scope)
{
- if (isCacheable(inStrictContext, evalSource, scope))
- return m_cacheMap.get(evalSource.impl()).get();
- return 0;
+ if (isCacheable(inStrictContext, evalSource, scope)) {
+ ASSERT(!inStrictContext);
+ SourceCodeKey sourceCodeKey(evalSource, String(), SourceCodeKey::EvalType, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, thisTDZMode);
+ return m_cacheMap.get(sourceCodeKey).get();
+ }
+ return nullptr;
}
- EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const String& evalSource, JSScope* scope)
+ EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const SourceCode& evalSource, JSScope* scope)
{
VariableEnvironment variablesUnderTDZ;
JSScope::collectVariablesUnderTDZ(scope, variablesUnderTDZ);
- EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext, thisTDZMode, &variablesUnderTDZ);
+ EvalExecutable* evalExecutable = EvalExecutable::create(exec, evalSource, inStrictContext, thisTDZMode, &variablesUnderTDZ);
if (!evalExecutable)
- return 0;
+ return nullptr;
- if (isCacheable(inStrictContext, evalSource, scope) && m_cacheMap.size() < maxCacheEntries)
- m_cacheMap.set(evalSource.impl(), WriteBarrier<EvalExecutable>(exec->vm(), owner, evalExecutable));
+ if (isCacheable(inStrictContext, evalSource, scope) && m_cacheMap.size() < maxCacheEntries) {
+ ASSERT(!inStrictContext);
+ SourceCodeKey sourceCodeKey(evalSource, String(), SourceCodeKey::EvalType, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, thisTDZMode);
+ m_cacheMap.set(sourceCodeKey, WriteBarrier<EvalExecutable>(exec->vm(), owner, evalExecutable));
+ }
return evalExecutable;
}
@@ -80,17 +87,17 @@
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;
};
diff --git a/Source/JavaScriptCore/bytecode/ExecutableInfo.h b/Source/JavaScriptCore/bytecode/ExecutableInfo.h
index 92144f8..2602be7 100644
--- a/Source/JavaScriptCore/bytecode/ExecutableInfo.h
+++ b/Source/JavaScriptCore/bytecode/ExecutableInfo.h
@@ -26,21 +26,28 @@
#ifndef ExecutableInfo_h
#define ExecutableInfo_h
+#include "GeneratorThisMode.h"
#include "ParserModes.h"
namespace JSC {
+// FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
+// https://bugs.webkit.org/show_bug.cgi?id=151547
struct ExecutableInfo {
- ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, bool isArrowFunction)
+ ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, GeneratorThisMode generatorThisMode, SuperBinding superBinding, SourceParseMode parseMode)
: m_needsActivation(needsActivation)
, m_usesEval(usesEval)
, m_isStrictMode(isStrictMode)
, m_isConstructor(isConstructor)
, m_isBuiltinFunction(isBuiltinFunction)
+ , m_generatorThisMode(static_cast<unsigned>(generatorThisMode))
, m_constructorKind(static_cast<unsigned>(constructorKind))
- , m_isArrowFunction(isArrowFunction)
+ , m_superBinding(static_cast<unsigned>(superBinding))
+ , m_parseMode(parseMode)
{
ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
+ ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
+ ASSERT(m_generatorThisMode == static_cast<unsigned>(generatorThisMode));
}
bool needsActivation() const { return m_needsActivation; }
@@ -48,8 +55,10 @@
bool isStrictMode() const { return m_isStrictMode; }
bool isConstructor() const { return m_isConstructor; }
bool isBuiltinFunction() const { return m_isBuiltinFunction; }
+ GeneratorThisMode generatorThisMode() const { return static_cast<GeneratorThisMode>(m_generatorThisMode); }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
- bool isArrowFunction() const { return m_isArrowFunction; }
+ SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
+ SourceParseMode parseMode() const { return m_parseMode; }
private:
unsigned m_needsActivation : 1;
@@ -57,8 +66,10 @@
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
diff --git a/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp b/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
index d60fdf7..2bbf313 100644
--- a/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
+++ b/Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp
@@ -54,6 +54,7 @@
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:
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index c114b9b..87e8233 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -54,7 +54,7 @@
UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info)
: Base(*vm, structure)
, m_numVars(0)
- , m_numCalleeRegisters(0)
+ , m_numCalleeLocals(0)
, m_numParameters(0)
, m_vm(vm)
, m_globalObjectRegister(VirtualRegister())
@@ -65,10 +65,12 @@
, 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)
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
index fa514c1..bca2c04 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
@@ -31,6 +31,7 @@
#include "CodeType.h"
#include "ConstructAbility.h"
#include "ExpressionRangeInfo.h"
+#include "GeneratorThisMode.h"
#include "HandlerInfo.h"
#include "Identifier.h"
#include "JSCell.h"
@@ -41,6 +42,7 @@
#include "UnlinkedFunctionExecutable.h"
#include "VariableEnvironment.h"
#include "VirtualRegister.h"
+#include <wtf/FastBitVector.h>
#include <wtf/RefCountedArray.h>
#include <wtf/Vector.h>
@@ -116,7 +118,7 @@
bool isConstructor() const { return m_isConstructor; }
bool isStrictMode() const { return m_isStrictMode; }
bool usesEval() const { return m_usesEval; }
- bool isArrowFunction() const { return m_isArrowFunction; }
+ SourceParseMode parseMode() const { return m_parseMode; }
bool needsFullScopeChain() const { return m_needsFullScopeChain; }
@@ -202,6 +204,8 @@
bool isBuiltinFunction() const { return m_isBuiltinFunction; }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+ GeneratorThisMode generatorThisMode() const { return static_cast<GeneratorThisMode>(m_generatorThisMode); }
+ SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
void shrinkToFit()
{
@@ -232,7 +236,7 @@
int m_numVars;
int m_numCapturedVars;
- int m_numCalleeRegisters;
+ int m_numCalleeLocals;
// Jump Tables
@@ -387,12 +391,14 @@
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;
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
index 6da1859..3f49488 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
@@ -50,13 +50,13 @@
static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source,
CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode,
- UnlinkedFunctionKind functionKind, ParserError& error, bool isArrowFunction)
+ UnlinkedFunctionKind functionKind, ParserError& error, SourceParseMode parseMode)
{
JSParserBuiltinMode builtinMode = executable->isBuiltinFunction() ? JSParserBuiltinMode::Builtin : JSParserBuiltinMode::NotBuiltin;
JSParserStrictMode strictMode = executable->isInStrictContext() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
ASSERT(isFunctionParseMode(executable->parseMode()));
std::unique_ptr<FunctionNode> function = parse<FunctionNode>(
- &vm, source, executable->name(), builtinMode, strictMode, executable->parseMode(), error, nullptr);
+ &vm, source, executable->name(), builtinMode, strictMode, executable->parseMode(), executable->superBinding(), error, nullptr);
if (!function) {
ASSERT(error.isValid());
@@ -67,7 +67,7 @@
executable->recordParse(function->features(), function->hasCapturedVariables());
UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode,
- ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), isArrowFunction));
+ ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), executable->generatorThisMode(), executable->superBinding(), parseMode));
auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode, executable->parentScopeTDZVariables()));
error = generator->generate();
if (error.isValid())
@@ -75,7 +75,7 @@
return result;
}
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables)
: Base(*vm, structure)
, m_name(node->ident())
, m_inferredName(node->inferredName())
@@ -99,7 +99,8 @@
, m_constructAbility(static_cast<unsigned>(constructAbility))
, m_constructorKind(static_cast<unsigned>(node->constructorKind()))
, m_functionMode(node->functionMode())
- , m_isArrowFunction(node->isArrowFunction())
+ , m_generatorThisMode(static_cast<unsigned>(generatorThisMode))
+ , m_superBinding(static_cast<unsigned>(node->superBinding()))
{
ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
@@ -180,7 +181,7 @@
UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind,
- DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, bool isArrowFunction)
+ DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, SourceParseMode parseMode)
{
switch (specializationKind) {
case CodeForCall:
@@ -196,7 +197,7 @@
UnlinkedFunctionCodeBlock* result = generateUnlinkedFunctionCodeBlock(
vm, this, source, specializationKind, debuggerMode, profilerMode,
isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction,
- error, isArrowFunction);
+ error, parseMode);
if (error.isValid())
return nullptr;
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
index d8e8229..c8bba0a 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
@@ -31,6 +31,7 @@
#include "CodeType.h"
#include "ConstructAbility.h"
#include "ExpressionRangeInfo.h"
+#include "GeneratorThisMode.h"
#include "HandlerInfo.h"
#include "Identifier.h"
#include "JSCell.h"
@@ -65,10 +66,10 @@
typedef JSCell Base;
static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
+ static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
{
UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
- UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, parentScopeTDZVariables);
+ UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, generatorThisMode, parentScopeTDZVariables);
instance->finishCreation(*vm);
return instance;
}
@@ -82,6 +83,8 @@
bool isInStrictContext() const { return m_isInStrictContext; }
FunctionMode functionMode() const { return static_cast<FunctionMode>(m_functionMode); }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+ GeneratorThisMode generatorThisMode() const { return static_cast<GeneratorThisMode>(m_generatorThisMode); }
+ SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; }
unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; }
@@ -95,7 +98,7 @@
UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode,
- ParserError&, bool);
+ ParserError&, SourceParseMode);
static UnlinkedFunctionExecutable* fromGlobalCode(
const Identifier&, ExecState&, const SourceCode&, JSObject*& exception,
@@ -125,10 +128,9 @@
ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
- bool isArrowFunction() const { return m_isArrowFunction; }
private:
- UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, VariableEnvironment&);
+ UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, GeneratorThisMode, VariableEnvironment&);
WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
@@ -158,7 +160,8 @@
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)
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 41a64c9..445d3d5 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -32,8 +32,10 @@
#include "BytecodeGenerator.h"
#include "BuiltinExecutables.h"
+#include "BytecodeLivenessAnalysis.h"
#include "Interpreter.h"
#include "JSFunction.h"
+#include "JSGeneratorFunction.h"
#include "JSLexicalEnvironment.h"
#include "JSTemplateRegistryKey.h"
#include "LowLevelInterpreter.h"
@@ -227,9 +229,33 @@
}
}
+ SourceParseMode parseMode = codeBlock->parseMode();
bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain();
bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
bool needsArguments = functionNode->usesArguments() || codeBlock->usesEval();
+
+ // Generator never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
+ if (parseMode == SourceParseMode::GeneratorBodyMode)
+ needsArguments = false;
+
+ if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode && needsArguments) {
+ // Generator does not provide "arguments". Instead, wrapping GeneratorFunction provides "arguments".
+ // This is because arguments of a generator should be evaluated before starting it.
+ // To workaround it, we evaluate these arguments as arguments of a wrapping generator function, and reference it from a generator.
+ //
+ // function *gen(a, b = hello())
+ // {
+ // return {
+ // @generatorNext: function (@generator, @generatorState, @generatorValue, @generatorResumeMode)
+ // {
+ // arguments; // This `arguments` should reference to the gen's arguments.
+ // ...
+ // }
+ // }
+ // }
+ shouldCaptureSomeOfTheThings = true;
+ }
+
if (shouldCaptureAllOfTheThings)
functionNode->varDeclarations().markAllVariablesAsCaptured();
@@ -254,14 +280,33 @@
allocateAndEmitScope();
m_calleeRegister.setIndex(JSStack::Callee);
-
+
+ initializeParameters(parameters);
+
+ // Before emitting a scope creation, emit a generator prologue that contains jump based on a generator's state.
+ if (parseMode == SourceParseMode::GeneratorBodyMode) {
+ m_generatorRegister = &m_parameters[1];
+ if (generatorThisMode() == GeneratorThisMode::Empty)
+ emitMoveEmptyValue(&m_thisRegister);
+
+ // Jump with switch_imm based on @generatorState. We don't take the coroutine styled generator implementation.
+ // When calling `next()`, we would like to enter the same prologue instead of jumping based on the saved instruction pointer.
+ // It's suitale for inlining, because it just inlines one `next` function implementation.
+
+ beginGenerator(generatorStateRegister());
+
+ // Initial state.
+ emitGeneratorStateLabel();
+ }
+
if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode())) {
+ ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
bool isDynamicScope = functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode());
bool isFunctionNameCaptured = captures(functionNode->ident().impl());
bool markAsCaptured = isDynamicScope || isFunctionNameCaptured;
emitPushFunctionNameScope(functionNode->ident(), &m_calleeRegister, markAsCaptured);
}
-
+
if (shouldCaptureSomeOfTheThings) {
m_lexicalEnvironmentRegister = addVar();
// We can allocate the "var" environment if we don't have default parameter expressions. If we have
@@ -271,19 +316,6 @@
initializeVarLexicalEnvironment(symbolTableConstantIndex);
}
- // Make sure the code block knows about all of our parameters, and make sure that parameters
- // needing destructuring are noted.
- m_parameters.grow(parameters.size() + 1); // reserve space for "this"
- m_thisRegister.setIndex(initializeNextParameter()->index()); // this
- for (unsigned i = 0; i < parameters.size(); ++i) {
- auto pattern = parameters.at(i).first;
- if (pattern->isRestParameter()) {
- RELEASE_ASSERT(!m_restParameter);
- m_restParameter = static_cast<RestParameterNode*>(pattern);
- } else
- initializeNextParameter();
- }
-
// Figure out some interesting facts about our arguments.
bool capturesAnyArgumentByName = false;
if (functionNode->hasCapturedVariables()) {
@@ -476,7 +508,36 @@
}
m_newTargetRegister = addVar();
- if (!codeBlock->isArrowFunction()) {
+ switch (parseMode) {
+ case SourceParseMode::ArrowFunctionMode: {
+ if (functionNode->usesThis() || codeBlock->usesEval())
+ emitLoadArrowFunctionThis(&m_thisRegister);
+ break;
+ }
+
+ case SourceParseMode::GeneratorWrapperFunctionMode: {
+ m_generatorRegister = addVar();
+
+ // FIXME: Emit to_this only when Generator uses it.
+ // https://bugs.webkit.org/show_bug.cgi?id=151586
+ m_codeBlock->addPropertyAccessInstruction(instructions().size());
+ emitOpcode(op_to_this);
+ instructions().append(kill(&m_thisRegister));
+ instructions().append(0);
+ instructions().append(0);
+
+ emitMove(m_generatorRegister, &m_calleeRegister);
+ emitCreateThis(m_generatorRegister);
+ break;
+ }
+
+ case SourceParseMode::GeneratorBodyMode: {
+ // |this| is already filled correctly before here.
+ emitLoad(m_newTargetRegister, jsUndefined());
+ break;
+ }
+
+ default: {
if (isConstructor()) {
emitMove(m_newTargetRegister, &m_thisRegister);
if (constructorKind() == ConstructorKind::Derived)
@@ -492,9 +553,8 @@
instructions().append(0);
instructions().append(0);
}
- } else {
- if (functionNode->usesThis() || codeBlock->usesEval())
- emitLoadArrowFunctionThis(&m_thisRegister);
+ break;
+ }
}
// All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
@@ -799,6 +859,22 @@
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);
@@ -826,17 +902,17 @@
RegisterID* BytecodeGenerator::newRegister()
{
- m_calleeRegisters.append(virtualRegisterForLocal(m_calleeRegisters.size()));
- int numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size());
- numCalleeRegisters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeRegisters);
- m_codeBlock->m_numCalleeRegisters = numCalleeRegisters;
- return &m_calleeRegisters.last();
+ m_calleeLocals.append(virtualRegisterForLocal(m_calleeLocals.size()));
+ int numCalleeLocals = max<int>(m_codeBlock->m_numCalleeLocals, m_calleeLocals.size());
+ numCalleeLocals = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeLocals);
+ m_codeBlock->m_numCalleeLocals = numCalleeLocals;
+ return &m_calleeLocals.last();
}
void BytecodeGenerator::reclaimFreeRegisters()
{
- while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount())
- m_calleeRegisters.removeLast();
+ while (m_calleeLocals.size() && !m_calleeLocals.last().refCount())
+ m_calleeLocals.removeLast();
}
RegisterID* BytecodeGenerator::newBlockScopeVariable()
@@ -1915,7 +1991,7 @@
varOffset = VarOffset(symbolTable->takeNextScopeOffset(locker));
else {
ASSERT(varKind == VarKind::Stack);
- varOffset = VarOffset(virtualRegisterForLocal(m_calleeRegisters.size()));
+ varOffset = VarOffset(virtualRegisterForLocal(m_calleeLocals.size()));
}
SymbolTableEntry newEntry(varOffset, 0);
symbolTable->add(locker, property.impl(), newEntry);
@@ -2312,12 +2388,12 @@
RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst)
{
size_t begin = instructions().size();
- m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3);
+ m_staticPropertyAnalyzer.createThis(dst->index(), begin + 3);
m_codeBlock->addPropertyAccessInstruction(instructions().size());
emitOpcode(op_create_this);
- instructions().append(m_thisRegister.index());
- instructions().append(m_thisRegister.index());
+ instructions().append(dst->index());
+ instructions().append(dst->index());
instructions().append(0);
instructions().append(0);
return dst;
@@ -2481,20 +2557,6 @@
return dst;
}
-RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionMetadataNode* function)
-{
- return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(function)));
-}
-
-RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index)
-{
- emitOpcode(op_new_func);
- instructions().append(dst->index());
- instructions().append(scopeRegister()->index());
- instructions().append(index);
- return dst;
-}
-
RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
{
emitOpcode(op_new_regexp);
@@ -2503,13 +2565,25 @@
return dst;
}
-void BytecodeGenerator::emitNewFunctionCommon(RegisterID* dst, BaseFuncExprNode* func, OpcodeID opcodeID)
+void BytecodeGenerator::emitNewFunctionExpressionCommon(RegisterID* dst, BaseFuncExprNode* func)
{
-
- ASSERT(opcodeID == op_new_func_exp || opcodeID == op_new_arrow_func_exp);
-
FunctionMetadataNode* function = func->metadata();
unsigned index = m_codeBlock->addFunctionExpr(makeFunction(function));
+
+ OpcodeID opcodeID = op_new_func_exp;
+ switch (function->parseMode()) {
+ case SourceParseMode::GeneratorWrapperFunctionMode: {
+ opcodeID = op_new_generator_func_exp;
+ break;
+ }
+ case SourceParseMode::ArrowFunctionMode: {
+ opcodeID = op_new_arrow_func_exp;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
emitOpcode(opcodeID);
instructions().append(dst->index());
@@ -2522,17 +2596,18 @@
RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func)
{
- emitNewFunctionCommon(dst, func, op_new_func_exp);
+ emitNewFunctionExpressionCommon(dst, func);
return dst;
}
RegisterID* BytecodeGenerator::emitNewArrowFunctionExpression(RegisterID* dst, ArrowFuncExprNode* func)
{
+ ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode);
bool isClassConstructor = m_codeBlock->isConstructor() && constructorKind() != ConstructorKind::None;
- if (isClassConstructor)
+ if (isClassConstructor || generatorThisMode() == GeneratorThisMode::Empty)
emitTDZCheck(thisRegister());
- emitNewFunctionCommon(dst, func, op_new_arrow_func_exp);
+ emitNewFunctionExpressionCommon(dst, func);
return dst;
}
@@ -2550,6 +2625,19 @@
return dst;
}
+RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionMetadataNode* function)
+{
+ unsigned index = m_codeBlock->addFunctionDecl(makeFunction(function));
+ if (function->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
+ emitOpcode(op_new_generator_func);
+ else
+ emitOpcode(op_new_func);
+ instructions().append(dst->index());
+ instructions().append(scopeRegister()->index());
+ instructions().append(index);
+ return dst;
+}
+
RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
{
return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd);
@@ -3773,6 +3861,24 @@
return dst;
}
+RegisterID* BytecodeGenerator::emitIteratorNextWithValue(RegisterID* dst, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node)
+{
+ {
+ RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next);
+ CallArguments nextArguments(*this, nullptr, 1);
+ emitMove(nextArguments.thisRegister(), iterator);
+ emitMove(nextArguments.argumentRegister(0), value);
+ emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd());
+ }
+ {
+ RefPtr<Label> typeIsObject = newLabel();
+ emitJumpIfTrue(emitIsObject(newTemporary(), dst), typeIsObject.get());
+ emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object."));
+ emitLabel(typeIsObject.get());
+ }
+ return dst;
+}
+
void BytecodeGenerator::emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node)
{
RefPtr<Label> done = newLabel();
@@ -3868,4 +3974,228 @@
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
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 6ab390e..0ea49a4 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -32,6 +32,7 @@
#define BytecodeGenerator_h
#include "CodeBlock.h"
+#include "GeneratorThisMode.h"
#include <wtf/HashTraits.h>
#include "Instruction.h"
#include "Label.h"
@@ -280,6 +281,8 @@
bool isConstructor() const { return m_codeBlock->isConstructor(); }
ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); }
+ GeneratorThisMode generatorThisMode() const { return m_codeBlock->generatorThisMode(); }
+ SuperBinding superBinding() const { return m_codeBlock->superBinding(); }
ParserError generate();
@@ -297,6 +300,8 @@
RegisterID* scopeRegister() { return m_scopeRegister; }
+ RegisterID* generatorRegister() { return m_generatorRegister; }
+
// Returns the next available temporary register. Registers returned by
// newTemporary require a modified form of reference counting: any
// register with a refcount of 0 is considered "available", meaning that
@@ -500,10 +505,8 @@
RegisterID* emitNewArrayWithSize(RegisterID* dst, RegisterID* length);
RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*);
- RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index);
RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name);
- void emitNewFunctionCommon(RegisterID*, BaseFuncExprNode*, OpcodeID);
RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
@@ -598,6 +601,7 @@
void emitRequireObjectCoercible(RegisterID* value, const String& error);
RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node);
+ RegisterID* emitIteratorNextWithValue(RegisterID* dst, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node);
void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node);
RegisterID* emitRestParameter(RegisterID* result, unsigned numParametersToSkip);
@@ -646,12 +650,28 @@
void beginSwitch(RegisterID*, SwitchInfo::SwitchType);
void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range);
+ void emitYieldPoint(RegisterID*);
+ void emitSave(Label* mergePoint, unsigned liveCalleeLocalsIndex);
+ void emitResume(Label* mergePoint, unsigned liveCalleeLocalsIndex);
+
+ void emitGeneratorStateLabel();
+ void emitGeneratorStateChange(int32_t state);
+ RegisterID* emitYield(RegisterID* argument);
+ RegisterID* emitDelegateYield(RegisterID* argument, ThrowableExpressionData*);
+ void beginGenerator(RegisterID*);
+ void endGenerator(Label* defaultLabel);
+ RegisterID* generatorStateRegister() { return &m_parameters[2]; }
+ RegisterID* generatorValueRegister() { return &m_parameters[3]; }
+ RegisterID* generatorResumeModeRegister() { return &m_parameters[4]; }
+
CodeType codeType() const { return m_codeType; }
bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; }
bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
+
+ SourceParseMode parseMode() const { return m_codeBlock->parseMode(); }
bool isBuiltinFunction() const { return m_isBuiltinFunction; }
@@ -669,6 +689,7 @@
void emitPopScope(RegisterID* dst, RegisterID* scope);
RegisterID* emitGetParentScope(RegisterID* dst, RegisterID* scope);
void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, bool isCaptured);
+ void emitNewFunctionExpressionCommon(RegisterID*, BaseFuncExprNode*);
public:
void pushLexicalScope(VariableEnvironmentNode*, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult = nullptr);
@@ -732,7 +753,7 @@
RegisterID& registerFor(VirtualRegister reg)
{
if (reg.isLocal())
- return m_calleeRegisters[reg.toLocal()];
+ return m_calleeLocals[reg.toLocal()];
if (reg.offset() == JSStack::Callee)
return m_calleeRegister;
@@ -754,12 +775,22 @@
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;
- return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, variablesUnderTDZ);
+ 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, generatorThisMode, variablesUnderTDZ);
}
void getVariablesUnderTDZ(VariableEnvironment&);
@@ -767,6 +798,7 @@
RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+ void initializeParameters(FunctionParameters&);
void initializeVarLexicalEnvironment(int symbolTableConstantIndex);
void initializeDefaultParameterValuesAndSetupFunctionScopeStack(FunctionParameters&, FunctionNode*, SymbolTable*, int symbolTableConstantIndex, const std::function<bool (UniquedStringImpl*)>& captures);
@@ -806,6 +838,7 @@
RegisterID* m_topMostScope { nullptr };
RegisterID* m_argumentsRegister { nullptr };
RegisterID* m_lexicalEnvironmentRegister { nullptr };
+ RegisterID* m_generatorRegister { nullptr };
RegisterID* m_emptyValueRegister { nullptr };
RegisterID* m_globalObjectRegister { nullptr };
RegisterID* m_newTargetRegister { nullptr };
@@ -813,7 +846,7 @@
SegmentedVector<RegisterID*, 16> m_localRegistersForCalleeSaveRegisters;
SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
- SegmentedVector<RegisterID, 32> m_calleeRegisters;
+ SegmentedVector<RegisterID, 32> m_calleeLocals;
SegmentedVector<RegisterID, 32> m_parameters;
SegmentedVector<Label, 32> m_labels;
LabelScopeStore m_labelScopes;
@@ -829,6 +862,7 @@
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 };
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 6eee442..99561bc 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -34,6 +34,7 @@
#include "Debugger.h"
#include "JIT.h"
#include "JSFunction.h"
+#include "JSGeneratorFunction.h"
#include "JSGlobalObject.h"
#include "JSONObject.h"
#include "LabelScope.h"
@@ -145,7 +146,7 @@
RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived)
+ if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.generatorThisMode() == GeneratorThisMode::Empty)
generator.emitTDZCheck(generator.thisRegister());
if (dst == generator.ignoredResult())
@@ -170,12 +171,16 @@
return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
}
-static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
+static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator)
{
RegisterID callee;
callee.setIndex(JSStack::Callee);
+ return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName);
+}
- RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName);
+static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
+{
+ RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto);
}
@@ -2584,6 +2589,7 @@
dst = 0;
RefPtr<RegisterID> returnRegister = m_value ? generator.emitNodeInTailPosition(dst, m_value) : generator.emitLoad(dst, jsUndefined());
+
generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, divotStart(), divotEnd());
if (generator.isInFinallyBlock()) {
returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get());
@@ -2966,26 +2972,95 @@
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);
- // 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);
- }
+ RefPtr<RegisterID> next = generator.newTemporary();
+ generator.emitNode(next.get(), funcExpr);
- // 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.
+ if (generator.superBinding() == SuperBinding::Needed) {
+ RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
+ emitPutHomeObject(generator, next.get(), homeObject.get());
+ }
+
+ // 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);
+
ASSERT(startOffset() >= lineStartOffset());
generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
- generator.emitReturn(r0);
- return;
+ generator.emitReturn(generator.generatorRegister());
+ break;
+ }
+
+ case SourceParseMode::GeneratorBodyMode: {
+ RefPtr<Label> generatorBodyLabel = generator.newLabel();
+ {
+ RefPtr<RegisterID> condition = generator.newTemporary();
+ generator.emitEqualityOp(op_stricteq, condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+ generator.emitJumpIfTrue(condition.get(), generatorBodyLabel.get());
+
+ RefPtr<Label> throwLabel = generator.newLabel();
+ generator.emitEqualityOp(op_stricteq, condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
+ generator.emitJumpIfTrue(condition.get(), throwLabel.get());
+
+ generator.emitReturn(generator.generatorValueRegister());
+
+ generator.emitLabel(throwLabel.get());
+ generator.emitThrow(generator.generatorValueRegister());
+ }
+
+ generator.emitLabel(generatorBodyLabel.get());
+
+ emitStatementsBytecode(generator, generator.ignoredResult());
+
+ RefPtr<Label> done = generator.newLabel();
+ generator.emitLabel(done.get());
+ generator.emitReturn(generator.emitLoad(nullptr, jsUndefined()));
+ generator.endGenerator(done.get());
+ break;
+ }
+
+ default: {
+ emitStatementsBytecode(generator, generator.ignoredResult());
+
+ StatementNode* singleStatement = this->singleStatement();
+ ReturnNode* returnNode = 0;
+
+ // Check for a return statement at the end of a function composed of a single block.
+ if (singleStatement && singleStatement->isBlock()) {
+ StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement();
+ if (lastStatementInBlock && lastStatementInBlock->isReturnNode())
+ returnNode = static_cast<ReturnNode*>(lastStatementInBlock);
+ }
+
+ // If there is no return we must automatically insert one.
+ if (!returnNode) {
+ RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
+ generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code.
+ ASSERT(startOffset() >= lineStartOffset());
+ generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
+ generator.emitReturn(r0);
+ return;
+ }
+ break;
+ }
}
}
@@ -3013,11 +3088,24 @@
RegisterID* 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 ---------------------------------
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 439e620..a2020a4 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -145,7 +145,7 @@
, m_constantNaN(graph.freeze(jsNumber(PNaN)))
, m_constantOne(graph.freeze(jsNumber(1)))
, m_numArguments(m_codeBlock->numParameters())
- , m_numLocals(m_codeBlock->m_numCalleeRegisters)
+ , m_numLocals(m_codeBlock->m_numCalleeLocals)
, m_parameterSlots(0)
, m_numPassedVarArgs(0)
, m_inlineStackTop(0)
@@ -1413,7 +1413,7 @@
ensureLocals(
VirtualRegister(inlineCallFrameStart).toLocal() + 1 +
- JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters);
+ JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeLocals);
size_t argumentPositionStart = m_graph.m_argumentPositions.size();
@@ -2927,7 +2927,7 @@
// Start with a register offset that corresponds to the last in-use register.
int registerOffset = virtualRegisterForLocal(
- m_inlineStackTop->m_profiledBlock->m_numCalleeRegisters - 1).offset();
+ m_inlineStackTop->m_profiledBlock->m_numCalleeLocals - 1).offset();
registerOffset -= numberOfParameters;
registerOffset -= JSStack::CallFrameHeaderSize;
@@ -3096,7 +3096,7 @@
// 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;
diff --git a/Source/JavaScriptCore/dfg/DFGForAllKills.h b/Source/JavaScriptCore/dfg/DFGForAllKills.h
index 51ac55d..f5f4cb5 100644
--- a/Source/JavaScriptCore/dfg/DFGForAllKills.h
+++ b/Source/JavaScriptCore/dfg/DFGForAllKills.h
@@ -76,7 +76,7 @@
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);
}
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 428870b..1911cfe 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -738,7 +738,7 @@
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.
diff --git a/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp b/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp
index e6c4235..5e5a150 100644
--- a/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp
@@ -93,8 +93,8 @@
// We'd really like to use an unset origin, but ThreadedCPS won't allow that.
NodeOrigin origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), false);
- Vector<Node*> locals(baseline->m_numCalleeRegisters);
- for (int local = 0; local < baseline->m_numCalleeRegisters; ++local) {
+ Vector<Node*> locals(baseline->m_numCalleeLocals);
+ for (int local = 0; local < baseline->m_numCalleeLocals; ++local) {
Node* previousHead = target->variablesAtHead.local(local);
if (!previousHead)
continue;
@@ -124,7 +124,7 @@
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;
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
index be8e2a7..6392f14 100644
--- a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
+++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
@@ -123,9 +123,9 @@
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
diff --git a/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp b/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp
index 29f05e5..3080dc3 100644
--- a/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp
+++ b/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.cpp
@@ -45,9 +45,9 @@
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
diff --git a/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.h b/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.h
index 44af8f9..9ae973f 100644
--- a/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.h
+++ b/Source/JavaScriptCore/ftl/FTLForOSREntryJITCode.h
@@ -46,7 +46,7 @@
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; }
diff --git a/Source/JavaScriptCore/ftl/FTLOSREntry.cpp b/Source/JavaScriptCore/ftl/FTLOSREntry.cpp
index ac71714..601b460 100644
--- a/Source/JavaScriptCore/ftl/FTLOSREntry.cpp
+++ b/Source/JavaScriptCore/ftl/FTLOSREntry.cpp
@@ -83,7 +83,7 @@
}
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());
diff --git a/Source/JavaScriptCore/ftl/FTLState.cpp b/Source/JavaScriptCore/ftl/FTLState.cpp
index 0307e0e..55d829a 100644
--- a/Source/JavaScriptCore/ftl/FTLState.cpp
+++ b/Source/JavaScriptCore/ftl/FTLState.cpp
@@ -56,7 +56,7 @@
}
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;
diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h
index d5b1492a..546971c 100644
--- a/Source/JavaScriptCore/heap/MarkedBlock.h
+++ b/Source/JavaScriptCore/heap/MarkedBlock.h
@@ -155,6 +155,7 @@
bool testAndSetMarked(const void*);
bool isLive(const JSCell*);
bool isLiveCell(const void*);
+ bool isAtom(const void*);
bool isMarkedOrNewlyAllocated(const JSCell*);
void setMarked(const void*);
void clearMarked(const void*);
@@ -388,7 +389,7 @@
return false;
}
- inline bool MarkedBlock::isLiveCell(const void* p)
+ inline bool MarkedBlock::isAtom(const void* p)
{
ASSERT(MarkedBlock::isAtomAligned(p));
size_t atomNumber = this->atomNumber(p);
@@ -399,7 +400,13 @@
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));
}
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index c54751c..75ed8cf 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -153,7 +153,16 @@
CallFrame* callerFrame = callFrame->callerFrame();
CodeBlock* callerCodeBlock = callerFrame->codeBlock();
JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
- EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain);
+ UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock();
+
+ ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded;
+ if (callerUnlinkedCodeBlock->constructorKind() == ConstructorKind::Derived)
+ thisTDZMode = ThisTDZMode::AlwaysCheck;
+ if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode && callerUnlinkedCodeBlock->generatorThisMode() == GeneratorThisMode::Empty)
+ thisTDZMode = ThisTDZMode::AlwaysCheck;
+
+ SourceCode sourceCode(makeSource(programSource));
+ EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), sourceCode, thisTDZMode, callerScopeChain);
if (!eval) {
if (!callerCodeBlock->isStrictMode()) {
@@ -171,8 +180,7 @@
// If the literal parser bailed, it should not have thrown exceptions.
ASSERT(!callFrame->vm().exception());
- ThisTDZMode thisTDZMode = callerCodeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
- eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, programSource, callerScopeChain);
+ eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, sourceCode, callerScopeChain);
if (!eval)
return jsUndefined();
}
@@ -410,7 +418,7 @@
}
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();
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 2d6f02c..ab05e80 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -215,6 +215,8 @@
DEFINE_OP(op_get_rest_length)
DEFINE_OP(op_check_tdz)
DEFINE_OP(op_assert)
+ DEFINE_OP(op_save)
+ DEFINE_OP(op_resume)
DEFINE_OP(op_debug)
DEFINE_OP(op_del_by_id)
DEFINE_OP(op_div)
@@ -261,6 +263,8 @@
DEFINE_OP(op_new_array_buffer)
DEFINE_OP(op_new_func)
DEFINE_OP(op_new_func_exp)
+ DEFINE_OP(op_new_generator_func)
+ DEFINE_OP(op_new_generator_func_exp)
DEFINE_OP(op_new_arrow_func_exp)
DEFINE_OP(op_new_object)
DEFINE_OP(op_new_regexp)
@@ -764,9 +768,9 @@
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)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 6850f7a..2b46e82 100755
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -494,6 +494,8 @@
void emit_op_get_rest_length(Instruction*);
void emit_op_check_tdz(Instruction*);
void emit_op_assert(Instruction*);
+ void emit_op_save(Instruction*);
+ void emit_op_resume(Instruction*);
void emit_op_debug(Instruction*);
void emit_op_del_by_id(Instruction*);
void emit_op_div(Instruction*);
@@ -542,6 +544,8 @@
void emit_op_new_array_buffer(Instruction*);
void emit_op_new_func(Instruction*);
void emit_op_new_func_exp(Instruction*);
+ void emit_op_new_generator_func(Instruction*);
+ void emit_op_new_generator_func_exp(Instruction*);
void emit_op_new_arrow_func_exp(Instruction*);
void emit_op_new_object(Instruction*);
void emit_op_new_regexp(Instruction*);
@@ -661,6 +665,7 @@
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);
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index f60ae57..1f3115a 100755
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -967,7 +967,7 @@
callOperation(operationNewRegexp, currentInstruction[1].u.operand, m_codeBlock->regexp(currentInstruction[2].u.operand));
}
-void JIT::emit_op_new_func(Instruction* currentInstruction)
+void JIT::emitNewFuncCommon(Instruction* currentInstruction)
{
Jump lazyJump;
int dst = currentInstruction[1].u.operand;
@@ -978,14 +978,26 @@
emitLoadPayload(currentInstruction[2].u.operand, regT0);
#endif
FunctionExecutable* funcExec = m_codeBlock->functionDecl(currentInstruction[3].u.operand);
- callOperation(operationNewFunction, dst, regT0, funcExec);
+
+ OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
+ if (opcodeID == op_new_func)
+ callOperation(operationNewFunction, dst, regT0, funcExec);
+ else {
+ ASSERT(opcodeID == op_new_generator_func);
+ callOperation(operationNewGeneratorFunction, dst, regT0, funcExec);
+ }
}
-void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
+void JIT::emit_op_new_func(Instruction* currentInstruction)
{
- emitNewFuncExprCommon(currentInstruction);
+ emitNewFuncCommon(currentInstruction);
}
-
+
+void JIT::emit_op_new_generator_func(Instruction* currentInstruction)
+{
+ emitNewFuncCommon(currentInstruction);
+}
+
void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
{
OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
@@ -1018,11 +1030,27 @@
#else
callOperation(operationNewArrowFunction, dst, regT0, function, regT3, regT2);
#endif
- else
- callOperation(operationNewFunction, dst, regT0, function);
+ else {
+ if (opcodeID == op_new_func_exp)
+ callOperation(operationNewFunction, dst, regT0, function);
+ else {
+ ASSERT(opcodeID == op_new_generator_func_exp);
+ callOperation(operationNewGeneratorFunction, dst, regT0, function);
+ }
+ }
done.link(this);
}
-
+
+void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
+{
+ emitNewFuncExprCommon(currentInstruction);
+}
+
+void JIT::emit_op_new_generator_func_exp(Instruction* currentInstruction)
+{
+ emitNewFuncExprCommon(currentInstruction);
+}
+
void JIT::emit_op_new_arrow_func_exp(Instruction* currentInstruction)
{
emitNewFuncExprCommon(currentInstruction);
@@ -1434,6 +1462,18 @@
#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)
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index d873a1d..cad9346 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -45,6 +45,7 @@
#include "JITToDFGDeferredCompilationCallback.h"
#include "JSArrowFunction.h"
#include "JSCInlines.h"
+#include "JSGeneratorFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSLexicalEnvironment.h"
#include "JSPropertyNameEnumerator.h"
@@ -987,23 +988,42 @@
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 static operationNewFunctionCommon(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue, bool isInvalidated)
+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 operationNewArrowFunctionCommon(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue, bool isInvalidated)
{
ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
FunctionExecutable* executable = static_cast<FunctionExecutable*>(functionExecutable);
@@ -1019,12 +1039,12 @@
EncodedJSValue 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)
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 9638f14..2542550 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -301,6 +301,8 @@
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;
diff --git a/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp b/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
index a6c3d27..f5918b7 100644
--- a/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
+++ b/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
@@ -134,9 +134,9 @@
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
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index 765f197..351a4c8 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -43,6 +43,7 @@
#include "JSLexicalEnvironment.h"
#include "JSCInlines.h"
#include "JSCJSValue.h"
+#include "JSGeneratorFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSStackInlines.h"
#include "JSString.h"
@@ -224,9 +225,9 @@
JSFunction* callee = jsCast<JSFunction*>(exec->callee());
FunctionExecutable* executable = callee->jsExecutable();
CodeBlock* codeBlock = executable->codeBlockFor(kind);
- dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n",
+ dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeLocals = %u, caller = %p.\n",
codeBlock, exec, comment, callee, executable,
- codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeRegisters,
+ codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeLocals,
exec->callerFrame());
}
@@ -458,7 +459,7 @@
#if LLINT_SLOW_PATH_TRACING
dataLogF("Checking stack height with exec = %p.\n", exec);
dataLogF("CodeBlock = %p.\n", exec->codeBlock());
- dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeRegisters);
+ dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeLocals);
dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars);
#if ENABLE(JIT)
@@ -1041,6 +1042,18 @@
LLINT_RETURN(JSFunction::create(vm, codeBlock->functionDecl(pc[3].u.operand), scope));
}
+LLINT_SLOW_PATH_DECL(slow_path_new_generator_func)
+{
+ LLINT_BEGIN();
+ CodeBlock* codeBlock = exec->codeBlock();
+ ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation());
+ JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+#if LLINT_SLOW_PATH_TRACING
+ dataLogF("Creating function!\n");
+#endif
+ LLINT_RETURN(JSGeneratorFunction::create(vm, codeBlock->functionDecl(pc[3].u.operand), scope));
+}
+
LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
{
LLINT_BEGIN();
@@ -1052,6 +1065,17 @@
LLINT_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();
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
index e244829..271324b 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
@@ -99,6 +99,8 @@
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);
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 5ad5b3f..567cb58 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -697,7 +697,7 @@
end
macro getFrameRegisterSizeForCodeBlock(codeBlock, size)
- loadi CodeBlock::m_numCalleeRegisters[codeBlock], size
+ loadi CodeBlock::m_numCalleeLocals[codeBlock], size
lshiftp 3, size
addp maxFrameExtentForSlowPathCall, size
end
@@ -1227,6 +1227,12 @@
dispatch(4)
+_llint_op_new_generator_func:
+ traceExecution()
+ callSlowPath(_llint_slow_path_new_generator_func)
+ dispatch(4)
+
+
_llint_op_new_array:
traceExecution()
callSlowPath(_llint_slow_path_new_array)
@@ -1458,6 +1464,11 @@
callSlowPath(_llint_slow_path_new_func_exp)
dispatch(4)
+_llint_op_new_generator_func_exp:
+ traceExecution()
+ callSlowPath(_llint_slow_path_new_generator_func_exp)
+ dispatch(4)
+
_llint_op_new_arrow_func_exp:
traceExecution()
callSlowPath(_llint_slow_path_new_arrow_func_exp)
@@ -1573,6 +1584,18 @@
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)
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
index ce985ca..a90dc1c 100644
--- a/Source/JavaScriptCore/parser/ASTBuilder.h
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -341,9 +341,11 @@
return new (m_parserArena) YieldExprNode(location, nullptr, /* delegate */ false);
}
- YieldExprNode* createYield(const JSTokenLocation& location, ExpressionNode* argument, bool delegate)
+ YieldExprNode* createYield(const JSTokenLocation& location, ExpressionNode* argument, bool delegate, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
{
- return new (m_parserArena) YieldExprNode(location, argument, delegate);
+ YieldExprNode* node = new (m_parserArena) YieldExprNode(location, argument, delegate);
+ setExceptionLocation(node, start, divot, end);
+ return node;
}
ClassExprNode* createClassExpr(const JSTokenLocation& location, const Identifier& name, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
@@ -364,12 +366,12 @@
const JSTokenLocation& startLocation, const JSTokenLocation& endLocation,
unsigned startColumn, unsigned endColumn, int functionKeywordStart,
int functionNameStart, int parametersStart, bool inStrictContext,
- ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode, bool isArrowFunction, bool isArrowFunctionBodyExpression)
+ ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
{
return new (m_parserArena) FunctionMetadataNode(
m_parserArena, startLocation, endLocation, startColumn, endColumn,
functionKeywordStart, functionNameStart, parametersStart,
- inStrictContext, constructorKind, parameterCount, mode, isArrowFunction, isArrowFunctionBodyExpression);
+ inStrictContext, constructorKind, superBinding, parameterCount, mode, isArrowFunctionBodyExpression);
}
ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
@@ -891,6 +893,9 @@
{
node->setStartOffset(offset);
}
+
+
+ void propagateArgumentsUse() { usesArguments(); }
private:
struct Scope {
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
index ea37639..5b6dc49 100644
--- a/Source/JavaScriptCore/parser/Nodes.cpp
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -151,7 +151,7 @@
ParserArena&, const JSTokenLocation& startLocation,
const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn,
int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext,
- ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode, bool isArrowFunction, bool isArrowFunctionBodyExpression)
+ ConstructorKind constructorKind, SuperBinding superBinding, unsigned parameterCount, SourceParseMode mode, bool isArrowFunctionBodyExpression)
: Node(endLocation)
, m_startColumn(startColumn)
, m_endColumn(endColumn)
@@ -162,10 +162,11 @@
, 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));
}
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 5ca3466..8e9a252 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -1817,7 +1817,7 @@
ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end,
unsigned startColumn, unsigned endColumn, int functionKeywordStart,
int functionNameStart, int parametersStart, bool isInStrictContext,
- ConstructorKind, unsigned, SourceParseMode, bool isArrowFunction, bool isArrowFunctionBodyExpression);
+ ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool isArrowFunctionBodyExpression);
void finishParsing(const SourceCode&, const Identifier&, FunctionMode);
@@ -1842,8 +1842,8 @@
int startStartOffset() const { return m_startStartOffset; }
bool isInStrictContext() const { return m_isInStrictContext; }
+ SuperBinding superBinding() { return static_cast<SuperBinding>(m_superBinding); }
ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
- bool isArrowFunction() const { return m_isArrowFunction; }
bool isArrowFunctionBodyExpression() const { return m_isArrowFunctionBodyExpression; }
void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset)
@@ -1869,8 +1869,8 @@
int m_lastLine;
SourceParseMode m_parseMode;
unsigned m_isInStrictContext : 1;
+ unsigned m_superBinding : 1;
unsigned m_constructorKind : 2;
- unsigned m_isArrowFunction : 1;
unsigned m_isArrowFunctionBodyExpression : 1;
};
@@ -1932,7 +1932,7 @@
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);
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index 2b958b6ec6..c3be82c 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -194,7 +194,7 @@
template <typename LexerType>
Parser<LexerType>::Parser(
VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode,
- JSParserStrictMode strictMode, SourceParseMode parseMode,
+ JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding,
ConstructorKind defaultConstructorKind, ThisTDZMode thisTDZMode)
: m_vm(vm)
, m_source(&source)
@@ -210,6 +210,7 @@
, m_lastFunctionName(nullptr)
, m_sourceElements(0)
, m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
+ , m_superBinding(superBinding)
, m_defaultConstructorKind(defaultConstructorKind)
, m_thisTDZMode(thisTDZMode)
{
@@ -249,7 +250,10 @@
bool isArrowFunctionBodyExpression = false;
if (m_lexer->isReparsingFunction()) {
ParserFunctionInfo<ASTBuilder> functionInfo;
- parseFunctionParameters(context, parseMode, functionInfo);
+ if (parseMode == SourceParseMode::GeneratorBodyMode)
+ functionInfo.parameters = createGeneratorParameters(context);
+ else
+ parseFunctionParameters(context, parseMode, functionInfo);
m_parameters = functionInfo.parameters;
if (parseMode == SourceParseMode::ArrowFunctionMode && !hasError()) {
@@ -273,8 +277,12 @@
sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
else if (isModuleParseMode(parseMode))
sourceElements = parseModuleSourceElements(context, parseMode);
- else
- sourceElements = parseSourceElements(context, CheckForStrictMode);
+ else {
+ if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
+ sourceElements = parseGeneratorFunctionSourceElements(context, CheckForStrictMode);
+ else
+ sourceElements = parseSourceElements(context, CheckForStrictMode);
+ }
}
bool validEnding;
@@ -301,7 +309,14 @@
VariableEnvironment& varDeclarations = scope->declaredVariables();
for (auto& entry : capturedVariables)
varDeclarations.markVariableAsCaptured(entry);
-
+
+ IdentifierSet usedVariables;
+ scope->getUsedVariables(usedVariables);
+ if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode) {
+ if (usedVariables.contains(m_vm->propertyNames->arguments.impl()))
+ context.propagateArgumentsUse();
+ }
+
CodeFeatures features = context.features();
if (scope->strictMode())
features |= StrictModeFeature;
@@ -311,10 +326,9 @@
features |= ModifiedParameterFeature;
if (modifiedArguments)
features |= ModifiedArgumentsFeature;
+
Vector<RefPtr<UniquedStringImpl>> closedVariables;
if (m_parsingBuiltin) {
- IdentifierSet usedVariables;
- scope->getUsedVariables(usedVariables);
// FIXME: This needs to be changed if we want to allow builtins to use lexical declarations.
for (const auto& variable : usedVariables) {
Identifier identifier = Identifier::fromUid(m_vm, variable.get());
@@ -458,6 +472,45 @@
}
template <typename LexerType>
+template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, SourceElementsMode mode)
+{
+ auto sourceElements = context.createSourceElements();
+
+ unsigned functionKeywordStart = tokenStart();
+ JSTokenLocation startLocation(tokenLocation());
+ JSTextPosition start = tokenStartPosition();
+ unsigned startColumn = tokenColumn();
+ int functionNameStart = m_token.m_location.startOffset;
+ int parametersStart = m_token.m_location.startOffset;
+
+ ParserFunctionInfo<TreeBuilder> info;
+ info.name = &m_vm->propertyNames->nullIdentifier;
+ info.parameters = createGeneratorParameters(context);
+ info.startOffset = parametersStart;
+ info.startLine = tokenLine();
+ info.parameterCount = 4; // generator, state, value, resume mode
+
+ {
+ AutoPopScopeRef generatorBodyScope(this, pushScope());
+ generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+ SyntaxChecker generatorFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
+ failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
+ popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
+ }
+ info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false);
+
+ info.endLine = tokenLine();
+ info.endOffset = m_token.m_data.offset;
+ info.bodyStartColumn = startColumn;
+
+ auto functionExpr = context.createFunctionExpr(startLocation, info);
+ auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
+ context.appendStatement(sourceElements, statement);
+
+ return sourceElements;
+}
+
+template <typename LexerType>
template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
{
// The grammar is documented here:
@@ -1600,15 +1653,14 @@
template <typename LexerType>
template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(
TreeBuilder& context, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart,
- ConstructorKind constructorKind, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
+ ConstructorKind constructorKind, SuperBinding superBinding, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
{
- bool isArrowFunction = FunctionBodyType::StandardFunctionBodyBlock != bodyType;
bool isArrowFunctionBodyExpression = bodyType == ArrowFunctionBodyExpression;
if (!isArrowFunctionBodyExpression) {
next();
if (match(CLOSEBRACE)) {
unsigned endColumn = tokenColumn();
- return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction, isArrowFunctionBodyExpression);
+ return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
}
}
@@ -1620,7 +1672,7 @@
else
failIfFalse(parseSourceElements(syntaxChecker, CheckForStrictMode), bodyType == StandardFunctionBodyBlock ? "Cannot parse body of this function" : "Cannot parse body of this arrow function");
unsigned endColumn = tokenColumn();
- return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction, isArrowFunctionBodyExpression);
+ return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, superBinding, parameterCount, parseMode, isArrowFunctionBodyExpression);
}
static const char* stringForFunctionMode(SourceParseMode mode)
@@ -1634,8 +1686,10 @@
return "function";
case SourceParseMode::MethodMode:
return "method";
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
return "generator";
+ case SourceParseMode::GeneratorWrapperFunctionMode:
+ return "generator function";
case SourceParseMode::ArrowFunctionMode:
return "arrow function";
case SourceParseMode::ProgramMode:
@@ -1714,6 +1768,37 @@
}
template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::FormalParameterList Parser<LexerType>::createGeneratorParameters(TreeBuilder& context)
+{
+ auto parameters = context.createFormalParameterList();
+
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition position = tokenStartPosition();
+
+ // @generator
+ declareParameter(&m_vm->propertyNames->generatorPrivateName);
+ auto generator = context.createBindingLocation(location, m_vm->propertyNames->generatorPrivateName, position, position, AssignmentContext::DeclarationStatement);
+ context.appendParameter(parameters, generator, 0);
+
+ // @generatorState
+ declareParameter(&m_vm->propertyNames->generatorStatePrivateName);
+ auto generatorState = context.createBindingLocation(location, m_vm->propertyNames->generatorStatePrivateName, position, position, AssignmentContext::DeclarationStatement);
+ context.appendParameter(parameters, generatorState, 0);
+
+ // @generatorValue
+ declareParameter(&m_vm->propertyNames->generatorValuePrivateName);
+ auto generatorValue = context.createBindingLocation(location, m_vm->propertyNames->generatorValuePrivateName, position, position, AssignmentContext::DeclarationStatement);
+ context.appendParameter(parameters, generatorValue, 0);
+
+ // @generatorResumeMode
+ declareParameter(&m_vm->propertyNames->generatorResumeModePrivateName);
+ auto generatorResumeMode = context.createBindingLocation(location, m_vm->propertyNames->generatorResumeModePrivateName, position, position, AssignmentContext::DeclarationStatement);
+ context.appendParameter(parameters, generatorResumeMode, 0);
+
+ return parameters;
+}
+
+template <typename LexerType>
template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionDefinitionType functionDefinitionType)
{
RELEASE_ASSERT(isFunctionParseMode(mode));
@@ -1824,12 +1909,10 @@
endLocation.startOffset - endLocation.lineStartOffset;
unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
- bool isArrowFunction = mode == SourceParseMode::ArrowFunctionMode;
-
functionInfo.body = context.createFunctionMetadata(
startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn,
functionKeywordStart, functionNameStart, parametersStart,
- cachedInfo->strictMode, constructorKind, cachedInfo->parameterCount, mode, isArrowFunction, functionBodyType == ArrowFunctionBodyExpression);
+ cachedInfo->strictMode, constructorKind, expectedSuperBinding, cachedInfo->parameterCount, mode, functionBodyType == ArrowFunctionBodyExpression);
functionScope->restoreFromSourceProviderCache(cachedInfo);
popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
@@ -1843,7 +1926,7 @@
m_lexer->setLineNumber(m_token.m_location.line);
functionInfo.endOffset = cachedInfo->endFunctionOffset;
- if (isArrowFunction)
+ if (mode == SourceParseMode::ArrowFunctionMode)
functionBodyType = cachedInfo->isBodyArrowExpression ? ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
else
functionBodyType = StandardFunctionBodyBlock;
@@ -1865,14 +1948,33 @@
m_lastFunctionName = lastFunctionName;
ParserState oldState = saveState();
-
- functionInfo.body = parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, functionBodyType, functionInfo.parameterCount, mode);
+
+ auto performParsingFunctionBody = [&] {
+ return parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
+ };
+
+ if (mode == SourceParseMode::GeneratorWrapperFunctionMode) {
+ AutoPopScopeRef generatorBodyScope(this, pushScope());
+ generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+ functionInfo.body = performParsingFunctionBody();
+
+ // When a generator has a "use strict" directive, a generator function wrapping it should be strict mode.
+ if (generatorBodyScope->strictMode())
+ functionScope->setStrictMode();
+
+ semanticFailIfTrue(generatorBodyScope->hasDirectSuper(), "Cannot call super() outside of a class constructor");
+ if (generatorBodyScope->needsSuperBinding())
+ semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
+
+ popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
+ } else
+ functionInfo.body = performParsingFunctionBody();
restoreState(oldState);
failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
if (functionScope->strictMode() && functionInfo.name) {
- RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorMode);
+ RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode);
semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
}
@@ -1940,7 +2042,7 @@
SourceParseMode parseMode = SourceParseMode::NormalFunctionMode;
#if ENABLE(ES6_GENERATORS)
if (consume(TIMES))
- parseMode = SourceParseMode::GeneratorMode;
+ parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
#endif
failIfFalse((parseFunctionInfo(context, FunctionNeedsName, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
failIfFalse(functionInfo.name, "Function statements must have a name");
@@ -2091,7 +2193,7 @@
SourceParseMode parseMode = SourceParseMode::MethodMode;
if (isGenerator) {
isConstructor = false;
- parseMode = SourceParseMode::GeneratorMode;
+ parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
semanticFailIfTrue(*ident == m_vm->propertyNames->prototype, "Cannot declare a generator named 'prototype'");
semanticFailIfTrue(*ident == m_vm->propertyNames->constructor, "Cannot declare a generator named 'constructor'");
}
@@ -2757,7 +2859,7 @@
SavePoint savePoint = createSavePoint();
#if ENABLE(ES6_GENERATORS)
- if (match(YIELD))
+ if (match(YIELD) && !isYIELDMaskedAsIDENT(currentScope()->isGenerator()))
return parseYieldExpression(context);
#endif
@@ -2862,6 +2964,7 @@
failIfTrue(m_functionParsePhase == FunctionParsePhase::Parameters, "Cannot use yield expression within parameters");
JSTokenLocation location(tokenLocation());
+ JSTextPosition divotStart = tokenStartPosition();
ASSERT(match(YIELD));
SavePoint savePoint = createSavePoint();
next();
@@ -2869,13 +2972,14 @@
return context.createYield(location);
bool delegate = consume(TIMES);
+ JSTextPosition argumentStart = tokenStartPosition();
TreeExpression argument = parseAssignmentExpression(context);
if (!argument) {
restoreSavePoint(savePoint);
next();
return context.createYield(location);
}
- return context.createYield(location, argument, delegate);
+ return context.createYield(location, argument, delegate, divotStart, argumentStart, lastTokenEndPosition());
}
template <typename LexerType>
@@ -3067,7 +3171,7 @@
JSTokenLocation methodLocation(tokenLocation());
unsigned methodStart = tokenStart();
ParserFunctionInfo<TreeBuilder> methodInfo;
- SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorMode : SourceParseMode::MethodMode;
+ SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorWrapperFunctionMode : SourceParseMode::MethodMode;
failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
methodInfo.name = methodName;
return context.createFunctionExpr(methodLocation, methodInfo);
@@ -3320,7 +3424,7 @@
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);
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index 9d94e07..262ff96 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -172,6 +172,7 @@
, m_isLexicalScope(false)
, m_isFunctionBoundary(false)
, m_isValidStrictMode(true)
+ , m_hasArguments(false)
, m_loopDepth(0)
, m_switchDepth(0)
{
@@ -192,6 +193,7 @@
, m_isLexicalScope(rhs.m_isLexicalScope)
, m_isFunctionBoundary(rhs.m_isFunctionBoundary)
, m_isValidStrictMode(rhs.m_isValidStrictMode)
+ , m_hasArguments(rhs.m_hasArguments)
, m_loopDepth(rhs.m_loopDepth)
, m_switchDepth(rhs.m_switchDepth)
, m_moduleScopeData(rhs.m_moduleScopeData)
@@ -242,10 +244,14 @@
void setSourceParseMode(SourceParseMode mode)
{
switch (mode) {
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
setIsGenerator();
break;
+ case SourceParseMode::GeneratorWrapperFunctionMode:
+ setIsGeneratorFunction();
+ break;
+
case SourceParseMode::NormalFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
@@ -268,6 +274,8 @@
bool isFunctionBoundary() const { return m_isFunctionBoundary; }
bool isGenerator() const { return m_isGenerator; }
+ bool hasArguments() const { return m_hasArguments; }
+
void setIsLexicalScope()
{
m_isLexicalScope = true;
@@ -450,16 +458,20 @@
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;
- m_usedVariables.add(*ptr);
+
+ // "arguments" reference should be resolved at function boudary.
+ if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl())
+ continue;
+
+ m_usedVariables.add(impl);
// We don't want a declared variable that is used in an inner scope to be thought of as captured if
// that inner scope is both a lexical scope and not a function. Only inner functions and "catch"
// statements can cause variables to be captured.
if (shouldTrackClosedVariables && (nestedScope->m_isFunctionBoundary || !nestedScope->m_isLexicalScope))
- m_closedVariableCandidates.add(*ptr);
+ m_closedVariableCandidates.add(impl);
}
}
// Propagate closed variable candidates downwards within the same function.
@@ -550,14 +562,22 @@
{
m_isFunction = true;
m_isFunctionBoundary = true;
+ m_hasArguments = true;
setIsLexicalScope();
m_isGenerator = false;
}
+ void setIsGeneratorFunction()
+ {
+ setIsFunction();
+ m_isGenerator = true;
+ }
+
void setIsGenerator()
{
setIsFunction();
m_isGenerator = true;
+ m_hasArguments = false;
}
void setIsModule()
@@ -579,6 +599,7 @@
bool m_isLexicalScope : 1;
bool m_isFunctionBoundary : 1;
bool m_isValidStrictMode : 1;
+ bool m_hasArguments : 1;
int m_loopDepth;
int m_switchDepth;
@@ -627,7 +648,7 @@
public:
Parser(
- VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode,
+ VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode, SuperBinding,
ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded);
~Parser();
@@ -1157,6 +1178,7 @@
}
template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
+ template <class TreeBuilder> TreeSourceElements parseGeneratorFunctionSourceElements(TreeBuilder&, SourceElementsMode);
template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
enum class ExportType { Exported, NotExported };
@@ -1199,7 +1221,7 @@
template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator);
template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded);
- template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionBodyType, unsigned, SourceParseMode);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, SuperBinding, FunctionBodyType, unsigned, SourceParseMode);
template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, unsigned&);
enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, ExportType, bool& forLoopConstDoesNotHaveInitializer);
@@ -1224,6 +1246,7 @@
template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType);
template <class TreeBuilder> NEVER_INLINE int parseFunctionParameters(TreeBuilder&, SourceParseMode, ParserFunctionInfo<TreeBuilder>&);
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::FormalParameterList createGeneratorParameters(TreeBuilder&);
template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
@@ -1349,6 +1372,7 @@
RefPtr<SourceProviderCache> m_functionCache;
SourceElements* m_sourceElements;
bool m_parsingBuiltin;
+ SuperBinding m_superBinding;
ConstructorKind m_defaultConstructorKind;
ThisTDZMode m_thisTDZMode;
VariableEnvironment m_varDeclarations;
@@ -1472,7 +1496,7 @@
std::unique_ptr<ParsedNode> parse(
VM* vm, const SourceCode& source,
const Identifier& name, JSParserBuiltinMode builtinMode,
- JSParserStrictMode strictMode, SourceParseMode parseMode,
+ JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding,
ParserError& error, JSTextPosition* positionBeforeLastNewline = nullptr,
ConstructorKind defaultConstructorKind = ConstructorKind::None,
ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded)
@@ -1481,7 +1505,7 @@
ASSERT(!source.provider()->source().isNull());
if (source.provider()->source().is8Bit()) {
- Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, parseMode, defaultConstructorKind, thisTDZMode);
+ Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, thisTDZMode);
std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
if (positionBeforeLastNewline)
*positionBeforeLastNewline = parser.positionBeforeLastNewline();
@@ -1494,7 +1518,7 @@
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();
diff --git a/Source/JavaScriptCore/parser/ParserModes.h b/Source/JavaScriptCore/parser/ParserModes.h
index 49585cb..486d8fc 100644
--- a/Source/JavaScriptCore/parser/ParserModes.h
+++ b/Source/JavaScriptCore/parser/ParserModes.h
@@ -46,7 +46,8 @@
enum class SourceParseMode {
NormalFunctionMode,
- GeneratorMode,
+ GeneratorBodyMode,
+ GeneratorWrapperFunctionMode,
GetterMode,
SetterMode,
MethodMode,
@@ -60,7 +61,8 @@
{
switch (parseMode) {
case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::GeneratorWrapperFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
case SourceParseMode::MethodMode:
@@ -84,7 +86,8 @@
return true;
case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::GeneratorWrapperFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
case SourceParseMode::MethodMode:
@@ -103,7 +106,8 @@
return true;
case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GeneratorMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::GeneratorWrapperFunctionMode:
case SourceParseMode::GetterMode:
case SourceParseMode::SetterMode:
case SourceParseMode::MethodMode:
diff --git a/Source/JavaScriptCore/parser/SourceCodeKey.h b/Source/JavaScriptCore/parser/SourceCodeKey.h
new file mode 100644
index 0000000..8d49a7e
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceCodeKey.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceCodeKey_h
+#define SourceCodeKey_h
+
+#include "ParserModes.h"
+#include "SourceCode.h"
+#include <wtf/HashTraits.h>
+
+namespace JSC {
+
+class SourceCodeKey {
+public:
+ enum CodeType { EvalType, ProgramType, FunctionType, ModuleType };
+
+ SourceCodeKey()
+ {
+ }
+
+ SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded)
+ : m_sourceCode(sourceCode)
+ , m_name(name)
+ , m_flags((static_cast<unsigned>(codeType) << 3) | (static_cast<unsigned>(builtinMode) << 2) | (static_cast<unsigned>(strictMode) << 1) | static_cast<unsigned>(thisTDZMode))
+ , m_hash(string().impl()->hash())
+ {
+ }
+
+ SourceCodeKey(WTF::HashTableDeletedValueType)
+ : m_sourceCode(WTF::HashTableDeletedValue)
+ {
+ }
+
+ bool isHashTableDeletedValue() const { return m_sourceCode.isHashTableDeletedValue(); }
+
+ unsigned hash() const { return m_hash; }
+
+ size_t length() const { return m_sourceCode.length(); }
+
+ bool isNull() const { return m_sourceCode.isNull(); }
+
+ // To save memory, we compute our string on demand. It's expected that source
+ // providers cache their strings to make this efficient.
+ String string() const { return m_sourceCode.toString(); }
+
+ bool operator==(const SourceCodeKey& other) const
+ {
+ return m_hash == other.m_hash
+ && length() == other.length()
+ && m_flags == other.m_flags
+ && m_name == other.m_name
+ && string() == other.string();
+ }
+
+private:
+ SourceCode m_sourceCode;
+ String m_name;
+ unsigned m_flags;
+ unsigned m_hash;
+};
+
+struct SourceCodeKeyHash {
+ static unsigned hash(const SourceCodeKey& key) { return key.hash(); }
+ static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+struct SourceCodeKeyHashTraits : SimpleClassHashTraits<SourceCodeKey> {
+ static const bool hasIsEmptyValueFunction = true;
+ static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); }
+};
+
+}
+
+#endif // SourceCodeKey_h
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
index 547e44f..2c77285 100644
--- a/Source/JavaScriptCore/parser/SyntaxChecker.h
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -180,10 +180,10 @@
ExpressionType createEmptyVarExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
ExpressionType createEmptyLetExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
ExpressionType createYield(const JSTokenLocation&) { return YieldExpr; }
- ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool) { return YieldExpr; }
+ ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool, int, int, int) { return YieldExpr; }
ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
- int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, unsigned, SourceParseMode, bool, bool) { return FunctionBodyResult; }
+ int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool) { return FunctionBodyResult; }
ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
void setFunctionNameStart(int, int) { }
int createArguments() { return ArgumentsResult; }
@@ -389,6 +389,8 @@
int endOffset(int) { return 0; }
void setStartOffset(int, int) { }
+ void propagateArgumentsUse() { }
+
private:
int m_topBinaryExpr;
int m_topUnaryToken;
diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp
index f13b25e..494520d 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.cpp
+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp
@@ -103,7 +103,7 @@
typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
std::unique_ptr<RootNode> rootNode = parse<RootNode>(
&vm, source, Identifier(), builtinMode, strictMode,
- CacheTypes<UnlinkedCodeBlockType>::parseMode, error, nullptr, ConstructorKind::None, thisTDZMode);
+ CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, thisTDZMode);
if (!rootNode)
return nullptr;
@@ -160,7 +160,7 @@
JSTextPosition positionBeforeLastNewline;
std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
&vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
- JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode,
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
error, &positionBeforeLastNewline);
if (!program) {
RELEASE_ASSERT(error.isValid());
@@ -188,7 +188,7 @@
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()));
diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h
index 48c8cfe..9b8c150 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.h
+++ b/Source/JavaScriptCore/runtime/CodeCache.h
@@ -29,6 +29,7 @@
#include "CodeSpecializationKind.h"
#include "ParserModes.h"
#include "SourceCode.h"
+#include "SourceCodeKey.h"
#include "Strong.h"
#include "VariableEnvironment.h"
#include <wtf/CurrentTime.h>
@@ -56,71 +57,6 @@
class 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()
{
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
index 495f235..473d5a4 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -39,6 +39,7 @@
macro(Error) \
macro(EvalError) \
macro(Function) \
+ macro(GeneratorFunction) \
macro(Infinity) \
macro(Intl) \
macro(JSON) \
@@ -330,6 +331,13 @@
macro(Uint32Array) \
macro(Float32Array) \
macro(Float64Array) \
+ macro(generator) \
+ macro(generatorNext) \
+ macro(generatorState) \
+ macro(generatorFrame) \
+ macro(generatorValue) \
+ macro(generatorThis) \
+ macro(generatorResumeMode) \
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index 490636f..af0a848 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -34,6 +34,7 @@
#include "Error.h"
#include "ErrorHandlingScope.h"
#include "ExceptionFuzz.h"
+#include "GeneratorFrame.h"
#include "GetterSetter.h"
#include "HostCallReturnValue.h"
#include "Interpreter.h"
@@ -222,11 +223,6 @@
{
BEGIN();
JSFunction* constructor = jsCast<JSFunction*>(OP(2).jsValue().asCell());
-
-#if !ASSERT_DISABLED
- ConstructData constructData;
- ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
-#endif
auto& cacheWriteBarrier = pc[4].u.jsCell;
if (!cacheWriteBarrier)
@@ -644,6 +640,38 @@
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();
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index 226185c..f00d870 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -290,6 +290,8 @@
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);
diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp
index a632c48..02f395c 100644
--- a/Source/JavaScriptCore/runtime/Completion.cpp
+++ b/Source/JavaScriptCore/runtime/Completion.cpp
@@ -63,7 +63,7 @@
RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
return !!parse<ProgramNode>(
&vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
- JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error);
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
}
bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& error)
@@ -73,7 +73,7 @@
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;
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index 8365292..4206006 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -299,7 +299,7 @@
UnlinkedFunctionCodeBlock* unlinkedCodeBlock =
executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
*vm, executable->m_source, kind, debuggerMode, profilerMode, error,
- executable->isArrowFunction());
+ executable->parseMode());
recordParse(
executable->m_unlinkedExecutable->features(),
executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(),
@@ -556,7 +556,7 @@
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());
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index 9fc9be7..75b3091 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -448,7 +448,7 @@
DECLARE_INFO;
- ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+ ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode); }
unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
@@ -501,7 +501,7 @@
DECLARE_INFO;
- ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+ ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode); }
private:
friend class ExecutableBase;
@@ -542,7 +542,7 @@
DECLARE_INFO;
- ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+ ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode); }
UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
@@ -650,12 +650,13 @@
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)
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
index dbe42fa..5d7ef37 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -79,28 +79,30 @@
}
// ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position, FunctionConstructionMode functionConstructionMode)
{
if (!globalObject->evalEnabled())
return exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
- return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position);
+ return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position, -1, functionConstructionMode);
}
JSObject* constructFunctionSkippingEvalEnabledCheck(
ExecState* exec, JSGlobalObject* globalObject, const ArgList& args,
const Identifier& functionName, const String& sourceURL,
- const TextPosition& position, int overrideLineNumber)
+ const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode)
{
// How we stringify functions is sometimes important for web compatibility.
// See https://bugs.webkit.org/show_bug.cgi?id=24350.
String program;
if (args.isEmpty())
- program = makeString("{function ", functionName.string(), "() {\n\n}}");
+ program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n\n}}");
else if (args.size() == 1)
- program = makeString("{function ", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
+ program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
else {
StringBuilder builder;
builder.appendLiteral("{function ");
+ if (functionConstructionMode == FunctionConstructionMode::Generator)
+ builder.append('*');
builder.append(functionName.string());
builder.append('(');
builder.append(args.at(0).toString(exec)->view(exec));
@@ -126,9 +128,9 @@
}
// 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
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h
index 22ecb57..d11fb2a 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.h
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h
@@ -56,12 +56,17 @@
static CallType getCallData(JSCell*, CallData&);
};
-JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&);
-JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&);
+enum class FunctionConstructionMode {
+ Function,
+ Generator,
+};
+
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&, FunctionConstructionMode = FunctionConstructionMode::Function);
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, FunctionConstructionMode = FunctionConstructionMode::Function);
JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(
ExecState*, JSGlobalObject*, const ArgList&, const Identifier&,
- const String&, const WTF::TextPosition&, int overrideLineNumber = -1);
+ const String&, const WTF::TextPosition&, int overrideLineNumber = -1, FunctionConstructionMode = FunctionConstructionMode::Function);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFrame.cpp b/Source/JavaScriptCore/runtime/GeneratorFrame.cpp
new file mode 100644
index 0000000..ef6ea7a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFrame.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorFrame.h"
+
+#include "CodeBlock.h"
+#include "HeapIterationScope.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo GeneratorFrame::s_info = { "GeneratorFrame", nullptr, nullptr, CREATE_METHOD_TABLE(GeneratorFrame) };
+
+GeneratorFrame::GeneratorFrame(VM& vm, size_t numberOfCalleeLocals)
+ : Base(vm, vm.generatorFrameStructure.get())
+ , m_numberOfCalleeLocals(numberOfCalleeLocals)
+{
+}
+
+void GeneratorFrame::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ for (size_t i = 0; i < m_numberOfCalleeLocals; ++i)
+ localAt(i).clear();
+}
+
+Structure* GeneratorFrame::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+GeneratorFrame* GeneratorFrame::create(VM& vm, size_t numberOfLocals)
+{
+ GeneratorFrame* result =
+ new (
+ NotNull,
+ allocateCell<GeneratorFrame>(vm.heap, allocationSizeForLocals(numberOfLocals)))
+ GeneratorFrame(vm, numberOfLocals);
+ result->finishCreation(vm);
+ return result;
+}
+
+void GeneratorFrame::save(ExecState* exec, const FastBitVector& liveCalleeLocals)
+{
+ // Only save callee locals.
+ // Every time a generator is called (or resumed), parameters should be replaced.
+ ASSERT(liveCalleeLocals.numBits() <= m_numberOfCalleeLocals);
+ liveCalleeLocals.forEachSetBit([&](size_t index) {
+ localAt(index).set(exec->vm(), this, exec->uncheckedR(virtualRegisterForLocal(index)).jsValue());
+ });
+}
+
+void GeneratorFrame::resume(ExecState* exec, const FastBitVector& liveCalleeLocals)
+{
+ // Only resume callee locals.
+ // Every time a generator is called (or resumed), parameters should be replaced.
+ liveCalleeLocals.forEachSetBit([&](size_t index) {
+ exec->uncheckedR(virtualRegisterForLocal(index)) = localAt(index).get();
+ localAt(index).clear();
+ });
+}
+
+void GeneratorFrame::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ GeneratorFrame* thisObject = jsCast<GeneratorFrame*>(cell);
+ Base::visitChildren(thisObject, visitor);
+ // Since only true cell pointers are stored as a cell, we can safely mark them.
+ visitor.appendValues(thisObject->locals(), thisObject->m_numberOfCalleeLocals);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFrame.h b/Source/JavaScriptCore/runtime/GeneratorFrame.h
new file mode 100644
index 0000000..3d545b1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFrame.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorFrame_h
+#define GeneratorFrame_h
+
+#include "JSCell.h"
+#include <wtf/FastBitVector.h>
+
+namespace JSC {
+
+class GeneratorFrame : public JSCell {
+ friend class JIT;
+#if ENABLE(DFG_JIT)
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+#endif
+ friend class VM;
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ DECLARE_EXPORT_INFO;
+
+ static GeneratorFrame* create(VM&, size_t numberOfCalleeLocals);
+
+ WriteBarrierBase<Unknown>* locals()
+ {
+ return bitwise_cast<WriteBarrierBase<Unknown>*>(bitwise_cast<char*>(this) + offsetOfLocals());
+ }
+
+ WriteBarrierBase<Unknown>& localAt(size_t index)
+ {
+ ASSERT(index < m_numberOfCalleeLocals);
+ return locals()[index];
+ }
+
+ static size_t offsetOfLocals()
+ {
+ return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(GeneratorFrame));
+ }
+
+ static size_t allocationSizeForLocals(unsigned numberOfLocals)
+ {
+ return offsetOfLocals() + numberOfLocals * sizeof(WriteBarrier<Unknown>);
+ }
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ void save(ExecState*, const FastBitVector& liveCalleeLocals);
+ void resume(ExecState*, const FastBitVector& liveCalleeLocals);
+
+private:
+ GeneratorFrame(VM&, size_t numberOfCalleeLocals);
+
+ size_t m_numberOfCalleeLocals;
+
+ friend class LLIntOffsetsExtractor;
+
+ void finishCreation(VM&);
+
+protected:
+ static void visitChildren(JSCell*, SlotVisitor&);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFrame_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp
new file mode 100644
index 0000000..28f5893
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorFunctionConstructor.h"
+
+#include "FunctionConstructor.h"
+#include "GeneratorFunctionPrototype.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GeneratorFunctionConstructor);
+
+const ClassInfo GeneratorFunctionConstructor::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(GeneratorFunctionConstructor) };
+
+GeneratorFunctionConstructor::GeneratorFunctionConstructor(VM& vm, Structure* structure)
+ : InternalFunction(vm, structure)
+{
+}
+
+void GeneratorFunctionConstructor::finishCreation(VM& vm, GeneratorFunctionPrototype* generatorFunctionPrototype)
+{
+ Base::finishCreation(vm, "GeneratorFunction");
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, generatorFunctionPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // Number of arguments for constructor
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL callGeneratorFunctionConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Generator));
+}
+
+static EncodedJSValue JSC_HOST_CALL constructGeneratorFunctionConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Generator));
+}
+
+CallType GeneratorFunctionConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callGeneratorFunctionConstructor;
+ return CallTypeHost;
+}
+
+ConstructType GeneratorFunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructGeneratorFunctionConstructor;
+ return ConstructTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h
new file mode 100644
index 0000000..c86c87b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorFunctionConstructor_h
+#define GeneratorFunctionConstructor_h
+
+#include "InternalFunction.h"
+
+namespace WTF {
+class TextPosition;
+}
+
+namespace JSC {
+
+class GeneratorFunctionPrototype;
+
+class GeneratorFunctionConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+
+ static GeneratorFunctionConstructor* create(VM& vm, Structure* structure, GeneratorFunctionPrototype* generatorFunctionPrototype)
+ {
+ GeneratorFunctionConstructor* constructor = new (NotNull, allocateCell<GeneratorFunctionConstructor>(vm.heap)) GeneratorFunctionConstructor(vm, structure);
+ constructor->finishCreation(vm, generatorFunctionPrototype);
+ return constructor;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+private:
+ GeneratorFunctionConstructor(VM&, Structure*);
+ void finishCreation(VM&, GeneratorFunctionPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFunctionConstructor_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp
new file mode 100644
index 0000000..33fe8f2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorFunctionPrototype.h"
+
+#include "BuiltinExecutables.h"
+#include "BuiltinNames.h"
+#include "Error.h"
+#include "JSArray.h"
+#include "JSCInlines.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "Lexer.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GeneratorFunctionPrototype);
+
+const ClassInfo GeneratorFunctionPrototype::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(GeneratorFunctionPrototype) };
+
+GeneratorFunctionPrototype::GeneratorFunctionPrototype(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
+{
+}
+
+void GeneratorFunctionPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h
new file mode 100644
index 0000000..d0a0349
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorFunctionPrototype_h
+#define GeneratorFunctionPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class GeneratorFunctionPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ static GeneratorFunctionPrototype* create(VM& vm, Structure* structure)
+ {
+ GeneratorFunctionPrototype* prototype = new (NotNull, allocateCell<GeneratorFunctionPrototype>(vm.heap)) GeneratorFunctionPrototype(vm, structure);
+ prototype->finishCreation(vm);
+ return prototype;
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&);
+
+private:
+ GeneratorFunctionPrototype(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFunctionPrototype_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp b/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp
new file mode 100644
index 0000000..af467b3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GeneratorPrototype.h"
+
+#include "JSCBuiltins.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "StructureInlines.h"
+
+#include "GeneratorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo GeneratorPrototype::s_info = { "Generator", &Base::s_info, &generatorPrototypeTable, CREATE_METHOD_TABLE(GeneratorPrototype) };
+
+/* Source for GeneratorPrototype.lut.h
+@begin generatorPrototypeTable
+ next JSBuiltin DontEnum|Function 1
+ return JSBuiltin DontEnum|Function 1
+ throw JSBuiltin DontEnum|Function 1
+@end
+*/
+
+void GeneratorPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Generator"), DontEnum | ReadOnly);
+ vm.prototypeMap.addPrototype(this);
+}
+
+bool GeneratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<Base>(exec, generatorPrototypeTable, jsCast<GeneratorPrototype*>(object), propertyName, slot);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorPrototype.h b/Source/JavaScriptCore/runtime/GeneratorPrototype.h
new file mode 100644
index 0000000..f10c44d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorPrototype.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorPrototype_h
+#define GeneratorPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class GeneratorPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static GeneratorPrototype* create(VM& vm, JSGlobalObject*, Structure* structure)
+ {
+ GeneratorPrototype* prototype = new (NotNull, allocateCell<GeneratorPrototype>(vm.heap)) GeneratorPrototype(vm, structure);
+ prototype->finishCreation(vm);
+ return prototype;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+private:
+ GeneratorPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+ void finishCreation(VM&);
+};
+
+}
+
+#endif // !defined(GeneratorPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/GeneratorThisMode.h b/Source/JavaScriptCore/runtime/GeneratorThisMode.h
new file mode 100644
index 0000000..4c03e7b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorThisMode.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratorThisMode_h
+#define GeneratorThisMode_h
+
+namespace JSC {
+
+// http://ecma-international.org/ecma-262/6.0/#sec-functionallocate
+// http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
+// When the function is a GeneratorFunction, its [[ConstructorKind]] is always "derived".
+// This means that OrdinaryCallBindThis in section 9.2.2 is never executed for GeneratorFunction.
+// So, when we execute the following,
+//
+// function *gen()
+// {
+// yield this
+// }
+//
+// {
+// let g = gen();
+// // |this| should be global.
+// g.next();
+// }
+//
+// {
+// let g = new gen();
+// // |this| in gen should be TDZ (and it won't be filled).
+// g.next();
+// }
+//
+// The following flag manages this state. When GeneratorFunction is called as a constructor, it returns a Generator that function has GeneratorThisMode::Empty flag.
+// In this case, when accessing |this|, a TDZ reference error occurs.
+enum class GeneratorThisMode : unsigned {
+ Empty,
+ NonEmpty
+};
+
+}
+
+#endif // GeneratorThisMode_h
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 5b2edfb..baddbbc 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -32,6 +32,7 @@
#include "CallFrame.h"
#include "ExceptionHelpers.h"
#include "FunctionPrototype.h"
+#include "GeneratorPrototype.h"
#include "GetterSetter.h"
#include "JSArray.h"
#include "JSBoundFunction.h"
@@ -348,7 +349,12 @@
unsigned attributes;
PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
if (!isValidOffset(offset)) {
- JSObject* prototype = constructEmptyObject(exec);
+ JSObject* prototype = nullptr;
+ if (thisObject->jsExecutable()->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
+ prototype = constructEmptyObject(exec, thisObject->globalObject()->generatorPrototype());
+ else
+ prototype = constructEmptyObject(exec);
+
prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes);
diff --git a/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp b/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp
new file mode 100644
index 0000000..34cbce0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSGeneratorFunction.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSCJSValue.h"
+#include "JSFunction.h"
+#include "JSFunctionInlines.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSGeneratorFunction::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSGeneratorFunction) };
+
+JSGeneratorFunction::JSGeneratorFunction(VM& vm, FunctionExecutable* executable, JSScope* scope)
+ : Base(vm, executable, scope, scope->globalObject()->generatorFunctionStructure())
+{
+}
+
+JSGeneratorFunction* JSGeneratorFunction::createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ JSGeneratorFunction* generatorFunction = new (NotNull, allocateCell<JSGeneratorFunction>(vm.heap)) JSGeneratorFunction(vm, executable, scope);
+ ASSERT(generatorFunction->structure()->globalObject());
+ generatorFunction->finishCreation(vm);
+ return generatorFunction;
+}
+
+JSGeneratorFunction* JSGeneratorFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ JSGeneratorFunction* generatorFunction = createImpl(vm, executable, scope);
+ executable->singletonFunction()->notifyWrite(vm, generatorFunction, "Allocating a generator function");
+ return generatorFunction;
+}
+
+JSGeneratorFunction* JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ return createImpl(vm, executable, scope);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGeneratorFunction.h b/Source/JavaScriptCore/runtime/JSGeneratorFunction.h
new file mode 100644
index 0000000..ff1072a5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGeneratorFunction.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSGeneratorFunction_h
+#define JSGeneratorFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+class LLIntDesiredOffsets;
+
+class JSGeneratorFunction : public JSFunction {
+ friend class JIT;
+#if ENABLE(DFG_JIT)
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+#endif
+ friend class VM;
+public:
+ typedef JSFunction Base;
+
+ enum class GeneratorResumeMode : int32_t {
+ NormalMode = 0,
+ ReturnMode = 1,
+ ThrowMode = 2
+ };
+
+ const static unsigned StructureFlags = Base::StructureFlags;
+
+ DECLARE_EXPORT_INFO;
+
+ static JSGeneratorFunction* create(VM&, FunctionExecutable*, JSScope*);
+ static JSGeneratorFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
+
+ static size_t allocationSize(size_t inlineCapacity)
+ {
+ ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+ return sizeof(JSGeneratorFunction);
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+ }
+
+private:
+ JSGeneratorFunction(VM&, FunctionExecutable*, JSScope*);
+
+ static JSGeneratorFunction* createImpl(VM&, FunctionExecutable*, JSScope*);
+
+ friend class LLIntOffsetsExtractor;
+};
+
+} // namespace JSC
+
+#endif // JSGeneratorFunction_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index bc08f96..6dde660 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -50,6 +50,9 @@
#include "ErrorPrototype.h"
#include "FunctionConstructor.h"
#include "FunctionPrototype.h"
+#include "GeneratorFunctionConstructor.h"
+#include "GeneratorFunctionPrototype.h"
+#include "GeneratorPrototype.h"
#include "GetterSetter.h"
#include "HeapIterationScope.h"
#include "InspectorInstrumentationObject.h"
@@ -72,6 +75,7 @@
#include "JSDollarVM.h"
#include "JSDollarVMPrototype.h"
#include "JSFunction.h"
+#include "JSGeneratorFunction.h"
#include "JSGenericTypedArrayViewConstructorInlines.h"
#include "JSGenericTypedArrayViewInlines.h"
#include "JSGenericTypedArrayViewPrototypeInlines.h"
@@ -384,6 +388,7 @@
FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE)
m_propertyNameIteratorStructure.set(vm, this, JSPropertyNameIterator::createStructure(vm, this, m_iteratorPrototype.get()));
+ m_generatorPrototype.set(vm, this, GeneratorPrototype::create(vm, this, GeneratorPrototype::createStructure(vm, this, m_iteratorPrototype.get())));
#undef CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE
@@ -420,6 +425,14 @@
m_syntaxErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("SyntaxError")));
m_typeErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("TypeError")));
m_URIErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("URIError")));
+
+ m_generatorFunctionPrototype.set(vm, this, GeneratorFunctionPrototype::create(vm, GeneratorFunctionPrototype::createStructure(vm, this, m_functionPrototype.get())));
+ GeneratorFunctionConstructor* generatorFunctionConstructor = GeneratorFunctionConstructor::create(vm, GeneratorFunctionConstructor::createStructure(vm, this, functionConstructor), m_generatorFunctionPrototype.get());
+ m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, generatorFunctionConstructor, DontEnum);
+ m_generatorFunctionStructure.set(vm, this, JSGeneratorFunction::createStructure(vm, this, m_generatorFunctionPrototype.get()));
+
+ m_generatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_generatorFunctionPrototype.get(), DontEnum);
+ m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->prototype, m_generatorPrototype.get(), DontEnum);
m_objectPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, objectConstructor, DontEnum);
m_functionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, functionConstructor, DontEnum);
@@ -553,6 +566,7 @@
GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseResolveThenableJobPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsPromiseResolveThenableJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
GlobalPropertyInfo(vm.propertyNames->builtinNames().InspectorInstrumentationPrivateName(), InspectorInstrumentationObject::create(vm, this, InspectorInstrumentationObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum | DontDelete | ReadOnly),
GlobalPropertyInfo(vm.propertyNames->MapPrivateName, mapConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().generatorResumePrivateName(), JSFunction::createBuiltinFunction(vm, generatorPrototypeGeneratorResumeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
};
addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
@@ -820,6 +834,8 @@
visitor.append(&thisObject->m_arrayPrototype);
visitor.append(&thisObject->m_errorPrototype);
visitor.append(&thisObject->m_iteratorPrototype);
+ visitor.append(&thisObject->m_generatorFunctionPrototype);
+ visitor.append(&thisObject->m_generatorPrototype);
visitor.append(&thisObject->m_debuggerScopeStructure);
visitor.append(&thisObject->m_withScopeStructure);
@@ -852,6 +868,7 @@
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);
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 8e1629c..0325324 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -63,6 +63,8 @@
class FunctionCodeBlock;
class FunctionExecutable;
class FunctionPrototype;
+class GeneratorPrototype;
+class GeneratorFunctionPrototype;
class GetterSetter;
class GlobalCodeBlock;
class InputCursor;
@@ -229,6 +231,8 @@
WriteBarrier<ArrayPrototype> m_arrayPrototype;
WriteBarrier<RegExpPrototype> m_regExpPrototype;
WriteBarrier<IteratorPrototype> m_iteratorPrototype;
+ WriteBarrier<GeneratorFunctionPrototype> m_generatorFunctionPrototype;
+ WriteBarrier<GeneratorPrototype> m_generatorPrototype;
WriteBarrier<Structure> m_debuggerScopeStructure;
WriteBarrier<Structure> m_withScopeStructure;
@@ -262,6 +266,7 @@
PropertyOffset m_functionNameOffset;
WriteBarrier<Structure> m_privateNameStructure;
WriteBarrier<Structure> m_regExpStructure;
+ WriteBarrier<Structure> m_generatorFunctionStructure;
WriteBarrier<Structure> m_consoleStructure;
WriteBarrier<Structure> m_dollarVMStructure;
WriteBarrier<Structure> m_internalFunctionStructure;
@@ -453,6 +458,8 @@
RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
IteratorPrototype* iteratorPrototype() const { return m_iteratorPrototype.get(); }
+ GeneratorFunctionPrototype* generatorFunctionPrototype() const { return m_generatorFunctionPrototype.get(); }
+ GeneratorPrototype* generatorPrototype() const { return m_generatorPrototype.get(); }
Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(); }
Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
@@ -506,6 +513,7 @@
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(); }
diff --git a/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp b/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
index 800a786..37b8afc 100644
--- a/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
+++ b/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
@@ -281,7 +281,7 @@
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));
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp
index 5135f40..ecababc 100644
--- a/Source/JavaScriptCore/runtime/VM.cpp
+++ b/Source/JavaScriptCore/runtime/VM.cpp
@@ -45,6 +45,7 @@
#include "FTLThunks.h"
#include "FunctionConstructor.h"
#include "GCActivityCallback.h"
+#include "GeneratorFrame.h"
#include "GetterSetter.h"
#include "Heap.h"
#include "HeapIterationScope.h"
@@ -244,6 +245,7 @@
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()));
diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h
index ced3194..5577a89 100644
--- a/Source/JavaScriptCore/runtime/VM.h
+++ b/Source/JavaScriptCore/runtime/VM.h
@@ -304,6 +304,7 @@
Strong<Structure> inferredTypeStructure;
Strong<Structure> inferredTypeTableStructure;
Strong<Structure> functionRareDataStructure;
+ Strong<Structure> generatorFrameStructure;
Strong<Structure> exceptionStructure;
Strong<Structure> promiseDeferredStructure;
Strong<Structure> internalPromiseDeferredStructure;
diff --git a/Source/JavaScriptCore/tests/es6.yaml b/Source/JavaScriptCore/tests/es6.yaml
index af34133..c952d32 100644
--- a/Source/JavaScriptCore/tests/es6.yaml
+++ b/Source/JavaScriptCore/tests/es6.yaml
@@ -727,7 +727,7 @@
- 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
@@ -735,7 +735,7 @@
- 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
@@ -761,7 +761,7 @@
- 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
@@ -771,7 +771,7 @@
- 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
@@ -811,55 +811,55 @@
- 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
@@ -1113,7 +1113,7 @@
- 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
diff --git a/Source/JavaScriptCore/tests/es6/generators_yield_star_generic_iterables.js b/Source/JavaScriptCore/tests/es6/generators_yield_star_generic_iterables.js
index a8b9b53..9a82132 100644
--- a/Source/JavaScriptCore/tests/es6/generators_yield_star_generic_iterables.js
+++ b/Source/JavaScriptCore/tests/es6/generators_yield_star_generic_iterables.js
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+ return {};
+}
+arr.length++;
+var iterator = {
+ next: function() {
+ return { value: arr.shift(), done: arr.length <= 0 };
+ },
+ 'return': methods['return'],
+ 'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
function test() {
var iterator = (function * generator() {
diff --git a/Source/JavaScriptCore/tests/es6/generators_yield_star_instances_of_iterables.js b/Source/JavaScriptCore/tests/es6/generators_yield_star_instances_of_iterables.js
index b4c7453..8167da5 100644
--- a/Source/JavaScriptCore/tests/es6/generators_yield_star_instances_of_iterables.js
+++ b/Source/JavaScriptCore/tests/es6/generators_yield_star_instances_of_iterables.js
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+ return {};
+}
+arr.length++;
+var iterator = {
+ next: function() {
+ return { value: arr.shift(), done: arr.length <= 0 };
+ },
+ 'return': methods['return'],
+ 'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
function test() {
var iterator = (function * generator() {
diff --git a/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing.js b/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing.js
index 6f682f5..32d317c 100644
--- a/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing.js
+++ b/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing.js
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+ return {};
+}
+arr.length++;
+var iterator = {
+ next: function() {
+ return { value: arr.shift(), done: arr.length <= 0 };
+ },
+ 'return': methods['return'],
+ 'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
function test() {
var closed = '';
diff --git a/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing_via_throw.js b/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing_via_throw.js
index 44a065a..1f47d32 100644
--- a/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing_via_throw.js
+++ b/Source/JavaScriptCore/tests/es6/generators_yield_star_iterator_closing_via_throw.js
@@ -1,3 +1,24 @@
+if (typeof global === 'undefined') {
+var global = this;
+}
+function __createIterableObject(arr, methods) {
+methods = methods || {};
+if (typeof Symbol !== 'function' || !Symbol.iterator) {
+ return {};
+}
+arr.length++;
+var iterator = {
+ next: function() {
+ return { value: arr.shift(), done: arr.length <= 0 };
+ },
+ 'return': methods['return'],
+ 'throw': methods['throw']
+};
+var iterable = {};
+iterable[Symbol.iterator] = function(){ return iterator; }
+return iterable;
+}
+
function test() {
var closed = false;
diff --git a/Source/JavaScriptCore/tests/stress/generator-arguments-from-function.js b/Source/JavaScriptCore/tests/stress/generator-arguments-from-function.js
new file mode 100644
index 0000000..7ca5879
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-arguments-from-function.js
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+function *gen(a, b, c)
+{
+ function test()
+ {
+ return arguments;
+ }
+
+ return test;
+}
+
+let g = gen(1, 2, 3);
+let {value: func} = g.next();
+shouldBe(func().length, 0);
diff --git a/Source/JavaScriptCore/tests/stress/generator-arguments.js b/Source/JavaScriptCore/tests/stress/generator-arguments.js
new file mode 100644
index 0000000..b26478f
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-arguments.js
@@ -0,0 +1,107 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+(function () {
+ function *g1(a, b, c)
+ {
+ yield arguments;
+ yield arguments;
+ }
+
+ var g = g1(0, 1, 2);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+
+ function *g2(a, b, c)
+ {
+ yield arguments;
+ yield arguments;
+ a = yield a;
+ yield arguments;
+ b = yield b;
+ yield arguments;
+ c = yield c;
+ yield arguments;
+ }
+ var g = g2(0, 1, 2);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 0);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":42,"1":1,"2":2}`);
+ shouldBe(g.next().value, 1);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":42,"1":42,"2":2}`);
+ shouldBe(g.next().value, 2);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":42,"1":42,"2":42}`);
+}());
+
+(function () {
+ function *g1(a, b, c)
+ {
+ "use strict";
+ yield arguments;
+ yield arguments;
+ }
+
+ var g = g1(0, 1, 2);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+
+ function *g2(a, b, c)
+ {
+ "use strict";
+ yield arguments;
+ yield arguments;
+ a = yield a;
+ yield arguments;
+ b = yield b;
+ yield arguments;
+ c = yield c;
+ yield arguments;
+ }
+ var g = g2(0, 1, 2);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 0);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 1);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 2);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+}());
+
+(function () {
+ "use strict";
+ function *g1(a, b, c)
+ {
+ yield arguments;
+ yield arguments;
+ }
+
+ var g = g1(0, 1, 2);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+
+ function *g2(a, b, c)
+ {
+ yield arguments;
+ yield arguments;
+ a = yield a;
+ yield arguments;
+ b = yield b;
+ yield arguments;
+ c = yield c;
+ yield arguments;
+ }
+ var g = g2(0, 1, 2);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(JSON.stringify(g.next().value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 0);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 1);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+ shouldBe(g.next().value, 2);
+ shouldBe(JSON.stringify(g.next(42).value), `{"0":0,"1":1,"2":2}`);
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-class-methods-syntax.js b/Source/JavaScriptCore/tests/stress/generator-class-methods-syntax.js
new file mode 100644
index 0000000..2465ceb
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-class-methods-syntax.js
@@ -0,0 +1,48 @@
+function testSyntax(script) {
+ try {
+ eval(script);
+ } catch (error) {
+ if (error instanceof SyntaxError)
+ throw new Error("Bad error: " + String(error));
+ }
+}
+
+function testSyntaxError(script, message) {
+ var error = null;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+ if (!error)
+ throw new Error("Expected syntax error not thrown");
+
+ if (String(error) !== message)
+ throw new Error("Bad error: " + String(error));
+}
+
+testSyntaxError(`
+class Cocoa {
+ *constructor()
+ {
+ }
+}
+`, `SyntaxError: Cannot declare a generator named 'constructor'.`);
+
+testSyntax(`
+class Cocoa {
+ *ok()
+ {
+ yield 42;
+ }
+}
+`);
+
+testSyntax(`
+class Cocoa {
+ static *ok()
+ {
+ yield 42;
+ }
+}
+`);
diff --git a/Source/JavaScriptCore/tests/stress/generator-class-methods.js b/Source/JavaScriptCore/tests/stress/generator-class-methods.js
new file mode 100644
index 0000000..21f5a54
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-class-methods.js
@@ -0,0 +1,62 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+class A {
+ *gen()
+ {
+ yield this;
+ yield this;
+ return 42;
+ }
+
+ static *staticGen()
+ {
+ yield this;
+ yield this;
+ return 42;
+ }
+}
+{
+ let a = new A();
+ let g = a.gen();
+ shouldBe(g.next().value, a);
+ 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);
+}
+{
+ shouldThrow(() => {
+ let g = new A.staticGen();
+ }, `TypeError: function is not a constructor (evaluating 'new A.staticGen()')`);
+}
diff --git a/Source/JavaScriptCore/tests/stress/generator-eval-this.js b/Source/JavaScriptCore/tests/stress/generator-eval-this.js
new file mode 100644
index 0000000..c9bd78d
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-eval-this.js
@@ -0,0 +1,65 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + 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)}`);
+}
+
+function *gen() {
+ yield eval("this");
+}
+
+var g = new gen();
+shouldThrow(() => {
+ g.next().value;
+}, `ReferenceError: Cannot access uninitialized variable.`);
+
+class B { }
+
+(function() {
+ eval('this');
+ eval('this');
+}());
+
+class A extends B {
+ constructor()
+ {
+ return eval('this');
+ }
+}
+
+shouldThrow(() => {
+ new A();
+}, `ReferenceError: Cannot access uninitialized variable.`);
+
+class C {
+ *generator()
+ {
+ yield eval('this');
+ }
+}
+
+shouldThrow(() => {
+ let c = new C();
+ let g = new c.generator();
+ g.next();
+}, `TypeError: function is not a constructor (evaluating 'new c.generator()')`);
+
+(function () {
+ let c = new C();
+ let g = c.generator();
+ shouldBe(g.next().value, c);
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-function-constructor.js b/Source/JavaScriptCore/tests/stress/generator-function-constructor.js
new file mode 100644
index 0000000..2696ae5
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-function-constructor.js
@@ -0,0 +1,9 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+var global = (new Function("return this"))();
+shouldBe(typeof global.GeneratorFunction, 'undefined');
+var generatorFunctionConstructor = (function *() { }).constructor;
+shouldBe(generatorFunctionConstructor.__proto__, Function);
+shouldBe(generatorFunctionConstructor.prototype.constructor, generatorFunctionConstructor);
diff --git a/Source/JavaScriptCore/tests/stress/generator-function-name.js b/Source/JavaScriptCore/tests/stress/generator-function-name.js
new file mode 100644
index 0000000..6f7736c
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-function-name.js
@@ -0,0 +1,12 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+var ok = function *generator()
+{
+ yield generator;
+};
+
+var g = ok();
+shouldBe(g.next().value, ok);
diff --git a/Source/JavaScriptCore/tests/stress/generator-methods-with-non-generator.js b/Source/JavaScriptCore/tests/stress/generator-methods-with-non-generator.js
new file mode 100644
index 0000000..4561d93
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-methods-with-non-generator.js
@@ -0,0 +1,31 @@
+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)}`);
+}
+
+function *gen() {
+}
+var g = gen();
+
+shouldThrow(() => {
+ g.next.call({});
+}, `TypeError: |this| should be a generator`);
+
+
+shouldThrow(() => {
+ g.throw.call({});
+}, `TypeError: |this| should be a generator`);
+
+shouldThrow(() => {
+ g.return.call({});
+}, `TypeError: |this| should be a generator`);
diff --git a/Source/JavaScriptCore/tests/stress/generator-relations.js b/Source/JavaScriptCore/tests/stress/generator-relations.js
new file mode 100644
index 0000000..efa4dc8
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-relations.js
@@ -0,0 +1,30 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function *generatorFunction() {
+}
+let generator = generatorFunction();
+
+shouldBe(generator instanceof generatorFunction, true);
+shouldBe(typeof generator.__proto__, 'object');
+shouldBe(generator.__proto__, generatorFunction.prototype);
+
+let GeneratorPrototype = generator.__proto__.__proto__;
+
+let GeneratorFunctionPrototype = generatorFunction.__proto__;
+let GeneratorFunction = generatorFunction.__proto__.constructor;
+shouldBe(GeneratorFunction.prototype, GeneratorFunctionPrototype);
+shouldBe(generatorFunction instanceof GeneratorFunction, true);
+shouldBe(GeneratorFunction.__proto__, Function);
+shouldBe(GeneratorFunctionPrototype.__proto__, Function.prototype);
+
+shouldBe(GeneratorFunctionPrototype.prototype, GeneratorPrototype);
+shouldBe(GeneratorPrototype.constructor, GeneratorFunctionPrototype);
+
+let arrayIterator = [][Symbol.iterator]();
+let ArrayIteratorPrototype = arrayIterator.__proto__;
+let IteratorPrototype = ArrayIteratorPrototype.__proto__;
+
+shouldBe(IteratorPrototype, GeneratorPrototype.__proto__);
diff --git a/Source/JavaScriptCore/tests/stress/generator-return-before-first-call.js b/Source/JavaScriptCore/tests/stress/generator-return-before-first-call.js
new file mode 100644
index 0000000..ce6debc
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-return-before-first-call.js
@@ -0,0 +1,23 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function shouldBeIteratorResult(actual, { value, done })
+{
+ shouldBe(actual.value, value);
+ shouldBe(actual.done, done);
+}
+
+function unreachable()
+{
+ throw new Error("NG");
+}
+
+function *gen()
+{
+ unreachable();
+}
+
+var g = gen();
+shouldBeIteratorResult(g.return("Hello"), { value: "Hello", done: true });
diff --git a/Source/JavaScriptCore/tests/stress/generator-return.js b/Source/JavaScriptCore/tests/stress/generator-return.js
new file mode 100644
index 0000000..7f569a0
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-return.js
@@ -0,0 +1,133 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+function shouldBeIteratorResult(actual, { value, done })
+{
+ shouldBe(actual.value, value);
+ shouldBe(actual.done, done);
+}
+
+function unreachable()
+{
+ throw new Error('unreachable');
+}
+
+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)}`);
+}
+
+(function () {
+ function *gen() {
+ yield yield 20;
+ yield 42;
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(0), { value: 20, done: false });
+ shouldBeIteratorResult(g.return(20), { value: 20, done: true });
+ shouldBeIteratorResult(g.return(20), { value: 20, done: true });
+ shouldBeIteratorResult(g.next(42), { value: undefined, done: true });
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ shouldBeIteratorResult(g.next(42), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ }
+}());
+
+(function () {
+ function *gen() {
+ return 42;
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: 42, done: true });
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ }
+}());
+
+(function () {
+ function *gen() {
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ }
+}());
+
+(function () {
+ function *gen() {
+ try {
+ yield 42;
+ } finally {
+ return 400;
+ }
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: 42, done: false });
+ shouldBeIteratorResult(g.return(0), { value: 400, done: true });
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ }
+}());
+
+
+(function () {
+ function *gen() {
+ try {
+ yield 42;
+ } finally {
+ throw new Error("thrown");
+ }
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: 42, done: false });
+ shouldThrow(() => g.return(0), `Error: thrown`);
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ }
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-this.js b/Source/JavaScriptCore/tests/stress/generator-this.js
new file mode 100644
index 0000000..880af6e
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-this.js
@@ -0,0 +1,67 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + 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)}`);
+}
+
+
+var global = new Function('return this')();
+
+(function () {
+ function *gen() {
+ yield this;
+ }
+
+ {
+ let g = gen();
+ shouldBe(g.next().value, global);
+ }
+ {
+ let g = new gen();
+ shouldThrow(() => {
+ g.next();
+ }, `ReferenceError: Cannot access uninitialized variable.`);
+ }
+ {
+ let thisObject = {};
+ let g = gen.call(thisObject);
+ shouldBe(g.next().value, thisObject);
+ }
+}());
+
+(function () {
+ function *gen() {
+ "use strict";
+ yield this;
+ }
+
+ {
+ let g = gen();
+ shouldBe(g.next().value, undefined);
+ }
+ {
+ let g = new gen();
+ shouldThrow(() => {
+ g.next();
+ }, `ReferenceError: Cannot access uninitialized variable.`);
+ }
+ {
+ let thisObject = {};
+ let g = gen.call(thisObject);
+ shouldBe(g.next().value, thisObject);
+ }
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-throw-before-first-call.js b/Source/JavaScriptCore/tests/stress/generator-throw-before-first-call.js
new file mode 100644
index 0000000..e46cb4f
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-throw-before-first-call.js
@@ -0,0 +1,20 @@
+function unreachable()
+{
+ throw new Error("NG");
+}
+
+function *gen()
+{
+ unreachable();
+}
+
+var g = gen();
+var error = new Error("OK");
+var thrown = null;
+try {
+ g.throw(error);
+} catch (e) {
+ thrown = e;
+}
+if (thrown !== error)
+ unreachable();
diff --git a/Source/JavaScriptCore/tests/stress/generator-throw.js b/Source/JavaScriptCore/tests/stress/generator-throw.js
new file mode 100644
index 0000000..ce2269f
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-throw.js
@@ -0,0 +1,132 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+function shouldBeIteratorResult(actual, { value, done })
+{
+ shouldBe(actual.value, value);
+ shouldBe(actual.done, done);
+}
+
+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 CallSite {
+ constructor()
+ {
+ this.count = 0;
+ }
+
+ call()
+ {
+ return this.count++;
+ }
+}
+
+(function () {
+ function *gen() {
+ yield yield 20;
+ yield 42;
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(0), { value: 20, done: false });
+ shouldThrow(() => g.throw(20), `20`);
+ shouldThrow(() => g.throw(20), `20`);
+ shouldBeIteratorResult(g.next(42), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ }
+ {
+ let g = gen();
+ shouldThrow(() => g.throw(42), `42`);
+ shouldBeIteratorResult(g.next(42), { value: undefined, done: true });
+ shouldBeIteratorResult(g.return(42), { value: 42, done: true });
+ shouldThrow(() => g.throw(42), `42`);
+ }
+}());
+
+(function () {
+ function *gen() {
+ return 42;
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: 42, done: true });
+ shouldThrow(() => g.throw(0), `0`);
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldThrow(() => g.throw(42), `42`);
+ }
+}());
+
+(function () {
+ function *gen() {
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldThrow(() => g.throw(0), `0`);
+ }
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.return(0), { value: 0, done: true });
+ shouldBeIteratorResult(g.next(), { value: undefined, done: true });
+ shouldThrow(() => g.throw(42), `42`);
+ }
+}());
+
+(function () {
+ let site = new CallSite();
+ function *gen() {
+ try {
+ yield 42;
+ } catch (e) {
+ shouldBe(e, 0);
+ site.call();
+ }
+ return 42;
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: 42, done: false });
+ shouldBeIteratorResult(g.throw(0), { value: 42, done: true });
+ shouldBe(site.count, 1);
+ }
+}());
+
+(function () {
+ function *gen() {
+ try {
+ yield 42;
+ } finally {
+ return 42;
+ }
+ }
+
+ {
+ let g = gen();
+ shouldBeIteratorResult(g.next(), { value: 42, done: false });
+ shouldBeIteratorResult(g.throw(0), { value: 42, done: true });
+ shouldThrow(() => g.throw(0), `0`);
+ }
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-with-new-target.js b/Source/JavaScriptCore/tests/stress/generator-with-new-target.js
new file mode 100644
index 0000000..0d3b2df
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-with-new-target.js
@@ -0,0 +1,15 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function *gen()
+{
+ yield new.target;
+}
+
+var g = gen();
+shouldBe(g.next().value, undefined);
+
+var g2 = new gen();
+shouldBe(g.next().value, undefined);
diff --git a/Source/JavaScriptCore/tests/stress/generator-with-super.js b/Source/JavaScriptCore/tests/stress/generator-with-super.js
new file mode 100644
index 0000000..9e53c79
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-with-super.js
@@ -0,0 +1,82 @@
+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)}`);
+}
+
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+(function () {
+ function test() {
+ return eval('super');
+ }
+
+ shouldThrow(() => test(), `SyntaxError: super is only valid inside functions.`);
+}());
+
+(function () {
+ class B {
+ gen() {
+ return 42;
+ }
+ }
+
+ class A extends B {
+ *gen() {
+ return eval('super.gen()');
+ }
+ }
+
+ let a = new A();
+ shouldThrow(() => {
+ a.gen().next();
+ }, `SyntaxError: super is only valid inside functions.`);
+}());
+
+(function () {
+ class B {
+ gen() {
+ return 42;
+ }
+ }
+
+ class A extends B {
+ *gen() {
+ yield super.gen();
+ }
+ }
+
+ let a = new A();
+ shouldBe(a.gen().next().value, 42);
+}());
+
+(function () {
+ class B {
+ gen() {
+ return 42;
+ }
+ }
+
+ class A extends B {
+ *gen() {
+ yield super.gen();
+ }
+ }
+
+ let a = new A();
+ shouldThrow(() => {
+ new a.gen();
+ }, `TypeError: function is not a constructor (evaluating 'new a.gen()')`);
+}());
diff --git a/Source/JavaScriptCore/tests/stress/generator-yield-star.js b/Source/JavaScriptCore/tests/stress/generator-yield-star.js
new file mode 100644
index 0000000..45abefa
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/generator-yield-star.js
@@ -0,0 +1,326 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + 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 CallSite {
+ constructor()
+ {
+ this.count = 0;
+ }
+
+ call()
+ {
+ return this.count++;
+ }
+}
+
+(function () {
+ class Arrays {
+ constructor()
+ {
+ this.first = [ 0, 1, 2, 3 ];
+ this.second = [ 4, 5, 6, 7 ];
+ }
+
+ *[Symbol.iterator]()
+ {
+ yield * this.first;
+ yield * this.second;
+ }
+ }
+
+ var arrays = new Arrays;
+ let i = 0;
+ for (let value of arrays)
+ shouldBe(i++, value);
+}());
+
+(function () {
+ // throw should be propagated.
+ let c1 = new CallSite;
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ 'throw'(value) {
+ shouldBe(value, 42);
+ c1.call();
+ throw new Error("OK");
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ yield * iter;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldThrow(() => {
+ g.throw(42);
+ }, `Error: OK`);
+ shouldThrow(() => {
+ g.throw(44);
+ }, `44`);
+ shouldBe(c1.count, 1);
+}());
+
+(function () {
+ // No `throw` method.
+ let c1 = new CallSite;
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ 'return'(value)
+ {
+ shouldBe(value, undefined);
+ c1.call();
+ return { value, done: true };
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ yield * iter;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldThrow(() => {
+ g.throw(42);
+ }, `TypeError: Delegated generator does not have a 'throw' method.`);
+ shouldThrow(() => {
+ g.throw(44);
+ }, `44`);
+ shouldBe(c1.count, 1);
+}());
+
+(function () {
+ // No `throw` method, `return` returns an incorrect result.
+ let c1 = new CallSite;
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ 'return'(value)
+ {
+ shouldBe(value, undefined);
+ c1.call();
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ yield * iter;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldThrow(() => {
+ g.throw(42);
+ }, `TypeError: Iterator result interface is not an object.`);
+ shouldThrow(() => {
+ g.throw(44);
+ }, `44`);
+ shouldBe(c1.count, 1);
+}());
+
+(function () {
+ // No `throw` method, No `return` method.
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ yield * iter;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldThrow(() => {
+ g.throw(42);
+ }, `TypeError: Delegated generator does not have a 'throw' method.`);
+ shouldThrow(() => {
+ g.throw(44);
+ }, `44`);
+}());
+
+
+(function () {
+ // `throw` does not throw. Not returns a object.
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ 'throw'(value)
+ {
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ yield * iter;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldThrow(() => {
+ g.throw(42);
+ }, `TypeError: Iterator result interface is not an object.`);
+ shouldThrow(() => {
+ g.throw(44);
+ }, `44`);
+}());
+
+(function () {
+ // `throw` does not throw. If returned iterator result is marked as done, it becomes `return`.
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ 'throw'(value)
+ {
+ return { value, done: true };
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ yield * iter;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldBe(g.throw(42).value, 42);
+ shouldThrow(() => {
+ g.throw(44);
+ }, `44`);
+}());
+
+(function () {
+ // `return` returns done: false.
+ class Iterator {
+ next(value)
+ {
+ return { value, done: false };
+ }
+
+ 'return'(value)
+ {
+ return { value, done: false };
+ }
+
+ [Symbol.iterator]()
+ {
+ return this;
+ }
+ }
+
+ function *gen()
+ {
+ let iter = new Iterator();
+ let result = yield * iter;
+ yield result;
+ yield 42;
+ }
+
+ let g = gen();
+ shouldBe(g.next(0).value, undefined);
+ shouldBe(g.next(1).value, 1);
+ shouldBe(g.next(2).value, 2);
+ shouldBe(g.return(42).value, 42);
+ shouldBe(g.return(42).done, false);
+}());
+
+(function () {
+ function *gen()
+ {
+ let result = yield * [ 0, 1, 2 ];
+ yield result;
+ }
+
+ let g = gen();
+ shouldBe(g.next().value, 0);
+ shouldBe(g.next().value, 1);
+ shouldBe(g.next().value, 2);
+ shouldBe(g.next().value, undefined);
+}());
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index 659d887..b1e0b07 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,14 @@
+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.
+
+ * wtf/FastBitVector.h:
+ (WTF::FastBitVector::forEachSetBit):
+ * wtf/FeatureDefines.h:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Source/WTF/wtf/FastBitVector.h b/Source/WTF/wtf/FastBitVector.h
index 9f188bc..98fff5c 100644
--- a/Source/WTF/wtf/FastBitVector.h
+++ b/Source/WTF/wtf/FastBitVector.h
@@ -181,7 +181,7 @@
}
template<typename Functor>
- void forEachSetBit(const Functor& functor)
+ void forEachSetBit(const Functor& functor) const
{
unsigned n = arrayLength();
for (unsigned i = 0; i < n; ++i) {
@@ -195,7 +195,7 @@
}
}
}
-
+
WTF_EXPORT_PRIVATE void dump(PrintStream&) const;
private:
diff --git a/Source/WTF/wtf/FeatureDefines.h b/Source/WTF/wtf/FeatureDefines.h
index 421941f..f46e119 100644
--- a/Source/WTF/wtf/FeatureDefines.h
+++ b/Source/WTF/wtf/FeatureDefines.h
@@ -364,7 +364,7 @@
#endif
#if !defined(ENABLE_ES6_CLASS_SYNTAX)
-#define ENABLE_ES6_GENERATORS 0
+#define ENABLE_ES6_GENERATORS 1
#endif
#if !defined(ENABLE_ES6_MODULES)
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 43ecddd..41b8c40 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,12 @@
+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.
+
+ * Configurations/FeatureDefines.xcconfig:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Source/WebCore/Configurations/FeatureDefines.xcconfig b/Source/WebCore/Configurations/FeatureDefines.xcconfig
index e177afc..18d64d0 100644
--- a/Source/WebCore/Configurations/FeatureDefines.xcconfig
+++ b/Source/WebCore/Configurations/FeatureDefines.xcconfig
@@ -47,7 +47,7 @@
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;
diff --git a/Source/WebKit/mac/ChangeLog b/Source/WebKit/mac/ChangeLog
index 3837ad0..f98bd3e 100644
--- a/Source/WebKit/mac/ChangeLog
+++ b/Source/WebKit/mac/ChangeLog
@@ -1,3 +1,12 @@
+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.
+
+ * Configurations/FeatureDefines.xcconfig:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Source/WebKit/mac/Configurations/FeatureDefines.xcconfig b/Source/WebKit/mac/Configurations/FeatureDefines.xcconfig
index e177afc..18d64d0 100644
--- a/Source/WebKit/mac/Configurations/FeatureDefines.xcconfig
+++ b/Source/WebKit/mac/Configurations/FeatureDefines.xcconfig
@@ -47,7 +47,7 @@
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;
diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog
index c68231a..3e1c2ef7 100644
--- a/Source/WebKit2/ChangeLog
+++ b/Source/WebKit2/ChangeLog
@@ -1,3 +1,12 @@
+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.
+
+ * Configurations/FeatureDefines.xcconfig:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Source/WebKit2/Configurations/FeatureDefines.xcconfig b/Source/WebKit2/Configurations/FeatureDefines.xcconfig
index e177afc..18d64d0 100644
--- a/Source/WebKit2/Configurations/FeatureDefines.xcconfig
+++ b/Source/WebKit2/Configurations/FeatureDefines.xcconfig
@@ -47,7 +47,7 @@
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;
diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake
index 9cd8465..02cc798 100644
--- a/Source/cmake/OptionsWin.cmake
+++ b/Source/cmake/OptionsWin.cmake
@@ -34,7 +34,7 @@
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DIRECTORY_UPLOAD PUBLIC OFF)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DOM4_EVENTS_CONSTRUCTOR PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DRAG_SUPPORT PUBLIC ON)
-WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ES6_GENERATORS PUBLIC OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ES6_GENERATORS PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ES6_MODULES PUBLIC OFF)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FILE_SYSTEM PUBLIC OFF)
diff --git a/Source/cmake/WebKitFeatures.cmake b/Source/cmake/WebKitFeatures.cmake
index d96224d..00edbc0 100644
--- a/Source/cmake/WebKitFeatures.cmake
+++ b/Source/cmake/WebKitFeatures.cmake
@@ -77,7 +77,7 @@
WEBKIT_OPTION_DEFINE(ENABLE_ENCRYPTED_MEDIA_V2 "Support EME v2" PRIVATE OFF)
WEBKIT_OPTION_DEFINE(ENABLE_ES6_ARROWFUNCTION_SYNTAX "Toggle ES6 arrow function syntax support" PRIVATE ON)
WEBKIT_OPTION_DEFINE(ENABLE_ES6_CLASS_SYNTAX "Toggle ES6 class syntax support" PRIVATE ON)
- WEBKIT_OPTION_DEFINE(ENABLE_ES6_GENERATORS "Toggle ES6 generators support" PRIVATE OFF)
+ WEBKIT_OPTION_DEFINE(ENABLE_ES6_GENERATORS "Toggle ES6 generators support" PRIVATE ON)
WEBKIT_OPTION_DEFINE(ENABLE_ES6_MODULES "Toggle ES6 modules support" PRIVATE OFF)
WEBKIT_OPTION_DEFINE(ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX "Toggle ES6 template literal syntax support" PRIVATE ON)
WEBKIT_OPTION_DEFINE(ENABLE_FILTERS_LEVEL_2 "Toggle Filters Module Level 2" PRIVATE OFF)
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index bdf16f2..554a893 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,12 @@
+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.
+
+ * Scripts/webkitperl/FeatureList.pm:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/Tools/Scripts/webkitperl/FeatureList.pm b/Tools/Scripts/webkitperl/FeatureList.pm
index cdeb525..4621881 100644
--- a/Tools/Scripts/webkitperl/FeatureList.pm
+++ b/Tools/Scripts/webkitperl/FeatureList.pm
@@ -185,7 +185,7 @@
define => "ENABLE_ES6_CLASS_SYNTAX", default => 1, value => \$classSyntax },
{ option => "generators", desc => "Toggle ES6 generators support",
- define => "ENABLE_ES6_GENERATORS", default => 0, value => \$generatorsSupport },
+ define => "ENABLE_ES6_GENERATORS", default => 1, value => \$generatorsSupport },
{ option => "modules", desc => "Toggle ES6 modules support",
define => "ENABLE_ES6_MODULES", default => 0, value => \$modulesSupport },
diff --git a/WebKitLibraries/ChangeLog b/WebKitLibraries/ChangeLog
index cf4e6f8..3f1f9b9 100644
--- a/WebKitLibraries/ChangeLog
+++ b/WebKitLibraries/ChangeLog
@@ -1,3 +1,13 @@
+2015-12-01 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [ES6] Implement LLInt/Baseline Support for ES6 Generators and enable this feature
+ https://bugs.webkit.org/show_bug.cgi?id=150792
+
+ Reviewed by Saam Barati.
+
+ * win/tools/vsprops/FeatureDefines.props:
+ * win/tools/vsprops/FeatureDefinesCairo.props:
+
2015-12-01 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r192914.
diff --git a/WebKitLibraries/win/tools/vsprops/FeatureDefines.props b/WebKitLibraries/win/tools/vsprops/FeatureDefines.props
index 0d74a8f..b07dc50 100644
--- a/WebKitLibraries/win/tools/vsprops/FeatureDefines.props
+++ b/WebKitLibraries/win/tools/vsprops/FeatureDefines.props
@@ -32,7 +32,7 @@
<ENABLE_DIRECTORY_UPLOAD />
<ENABLE_DOM4_EVENTS_CONSTRUCTOR>ENABLE_DOM4_EVENTS_CONSTRUCTOR</ENABLE_DOM4_EVENTS_CONSTRUCTOR>
<ENABLE_ENCRYPTED_MEDIA_V2>ENABLE_ENCRYPTED_MEDIA_V2</ENABLE_ENCRYPTED_MEDIA_V2>
- <ENABLE_ES6_GENERATORS />
+ <ENABLE_ES6_GENERATORS>ENABLE_ES6_GENERATORS</ENABLE_ES6_GENERATORS>
<ENABLE_ES6_MODULES />
<ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX>ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX</ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX>
<ENABLE_FILE_SYSTEM />
diff --git a/WebKitLibraries/win/tools/vsprops/FeatureDefinesCairo.props b/WebKitLibraries/win/tools/vsprops/FeatureDefinesCairo.props
index 91ee80f..f5b08ff 100644
--- a/WebKitLibraries/win/tools/vsprops/FeatureDefinesCairo.props
+++ b/WebKitLibraries/win/tools/vsprops/FeatureDefinesCairo.props
@@ -32,7 +32,7 @@
<ENABLE_DIRECTORY_UPLOAD />
<ENABLE_DOM4_EVENTS_CONSTRUCTOR>ENABLE_DOM4_EVENTS_CONSTRUCTOR</ENABLE_DOM4_EVENTS_CONSTRUCTOR>
<ENABLE_ENCRYPTED_MEDIA_V2 />
- <ENABLE_ES6_GENERATORS />
+ <ENABLE_ES6_GENERATORS>ENABLE_ES6_GENERATORS</ENABLE_ES6_GENERATORS>
<ENABLE_ES6_MODULES />
<ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX>ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX</ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX>
<ENABLE_FILE_SYSTEM />