[JSC] Generator should have internal fields
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Sep 2019 05:02:45 +0000 (05:02 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Sep 2019 05:02:45 +0000 (05:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201159

Reviewed by Keith Miller.

JSTests:

* stress/create-generator.js: Added.
(shouldBe):
(test.generator):
(test):
* stress/generator-construct-failure.js: Added.
(shouldThrow):
(TypeError):
* stress/generator-prototype-change.js: Added.
(shouldBe):
(gen):
* stress/generator-prototype-closure.js: Added.
(shouldBe):
(test.gen):
(test):
* stress/object-assign-fast-path.js:

Source/JavaScriptCore:

This patch makes generator's internal states InternalField instead of private properties.
Each generator function produces a generator with different [[Prototype]], which makes generators have different Structures.
As a result, Generator.prototype.next etc.'s implementation becomes megamorphic even if it is not necessary.

If we make these structures adaptively poly-proto, some generators get poly-proto structures while others are not, resulting
in megamorphic lookup in Generator.prototype.next. If we make all the generator's structure poly-proto, it makes Generator.prototype.next
lookup suboptimal for now.

In this patch, we start with a relatively simple solution. This patch introduces JSGenerator class, and it has internal fields for generator's internal
states. We extend promise-internal-field access bytecodes to access to these fields from bytecode so that Generator.prototype.next can access
these fields without using megamorphic get_by_id_direct.

And we attach JSGeneratorType to JSGenerator so that we can efficiently implement `@isGenerator()` check in bytecode.

We reserve the offset = 0 slot for the future poly-proto extension for JSGenerator. By reserving this slot, non-poly-proto JSGenerator and poly-proto
JSGenerator still can offer the way to access to the same Generator internal fields with the same offset while poly-proto JSGenerator can get offset = 0
inline-storage slot for PolyProto implementation.

This patch adds op_create_generator since it is distinct from op_create_promise once we add PolyProto support.
In the future when we introduce some kind of op_create_async_generator we will probably share only one bytecode for both generator and async generator.

This patch offers around 10% improvement in JetStream2/Basic. And this patch is the basis of optimization of JetStream2/async-fs which leverages async generators significantly.

This patch includes several design decisions.

    1. We add a new JSGenerator instead of leveraging JSFinalObject. The main reason is that we would like to have JSGeneratorType to quickly query `@isGenerator`.
    2. This patch currently does not include object-allocation-sinking support for JSGenerator, but it is trivial, and will be added. And this patch also does not include poly-proto
       support for JSGenerator. The main reason is simply because this patch is already large enough, and I do not want to make this patch larger and larger.
    3. We can support arbitrary sized inline-storage: Reserving 0-5 offsets for internal fields, and start putting all the other things to the subsequent internal fields. But for now,
       we are not taking this approach just because I'm not sure this is necessary. If we found such a pattern, we can easily extend the current one but for now, I would like to keep
       this patch simple.

* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* builtins/AsyncFunctionPrototype.js:
(globalPrivate.asyncFunctionResume):
* builtins/GeneratorPrototype.js:
(globalPrivate.generatorResume):
(next):
(return):
(throw):
* bytecode/BytecodeGeneratorification.cpp:
(JSC::BytecodeGeneratorification::run):
* bytecode/BytecodeIntrinsicRegistry.cpp:
(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
* bytecode/BytecodeIntrinsicRegistry.h:
* bytecode/BytecodeList.rb:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::finalizeLLIntInlineCaches):
* bytecode/SpeculatedType.cpp:
(JSC::speculationFromJSType):
* bytecode/SpeculatedType.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitPutGeneratorFields):
(JSC::BytecodeGenerator::emitCreateGenerator):
(JSC::BytecodeGenerator::emitNewGenerator):
(JSC::BytecodeGenerator::emitYield):
(JSC::BytecodeGenerator::emitDelegateYield):
(JSC::BytecodeGenerator::emitGeneratorStateChange):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitIsGenerator):
(JSC::BytecodeGenerator::generatorStateRegister):
(JSC::BytecodeGenerator::generatorValueRegister):
(JSC::BytecodeGenerator::generatorResumeModeRegister):
(JSC::BytecodeGenerator::generatorFrameRegister):
* bytecompiler/NodesCodegen.cpp:
(JSC::generatorInternalFieldIndex):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_getGeneratorInternalField):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_putGeneratorInternalField):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_isGenerator):
(JSC::FunctionNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGClobbersExitState.cpp:
(JSC::DFG::clobbersExitState):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupIsCellWithType):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToNewGenerator):
(JSC::DFG::Node::speculatedTypeForQuery):
(JSC::DFG::Node::hasStructure):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCreatePromise):
(JSC::DFG::SpeculativeJIT::compileCreateGenerator):
(JSC::DFG::SpeculativeJIT::compileNewGenerator):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStoreBarrierInsertionPhase.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileNewGenerator):
(JSC::FTL::DFG::LowerDFGToB3::compileCreatePromise):
(JSC::FTL::DFG::LowerDFGToB3::compileCreateGenerator):
(JSC::FTL::DFG::LowerDFGToB3::isCellWithType):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_internal_field):
(JSC::JIT::emit_op_put_internal_field):
* llint/LowLevelInterpreter.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/InternalFunction.cpp:
(JSC::InternalFunction::createSubclassStructureSlow):
* runtime/InternalFunction.h:
(JSC::InternalFunction::createSubclassStructure):
* runtime/JSGenerator.cpp: Added.
(JSC::JSGenerator::create):
(JSC::JSGenerator::createStructure):
(JSC::JSGenerator::JSGenerator):
(JSC::JSGenerator::finishCreation):
(JSC::JSGenerator::visitChildren):
* runtime/JSGenerator.h: Copied from Source/JavaScriptCore/runtime/JSGeneratorFunction.h.
* runtime/JSGeneratorFunction.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::generatorStructure const):
* runtime/JSType.cpp:
(WTF::printInternal):
* runtime/JSType.h:

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

60 files changed:
JSTests/ChangeLog
JSTests/stress/create-generator.js [new file with mode: 0644]
JSTests/stress/generator-construct-failure.js [new file with mode: 0644]
JSTests/stress/generator-prototype-change.js [new file with mode: 0644]
JSTests/stress/generator-prototype-closure.js [new file with mode: 0644]
JSTests/stress/object-assign-fast-path.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js
Source/JavaScriptCore/builtins/GeneratorPrototype.js
Source/JavaScriptCore/bytecode/BytecodeGeneratorification.cpp
Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
Source/JavaScriptCore/bytecode/BytecodeList.rb
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/InternalFunction.cpp
Source/JavaScriptCore/runtime/InternalFunction.h
Source/JavaScriptCore/runtime/JSGenerator.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGenerator.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGeneratorFunction.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSType.cpp
Source/JavaScriptCore/runtime/JSType.h

index 2db1dda4e1fca0dc72d8b9a26ff44dd3f47022e0..6f0d4a1b54447a8acd5595519089e91ccbb9121b 100644 (file)
@@ -1,3 +1,26 @@
+2019-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Generator should have internal fields
+        https://bugs.webkit.org/show_bug.cgi?id=201159
+
+        Reviewed by Keith Miller.
+
+        * stress/create-generator.js: Added.
+        (shouldBe):
+        (test.generator):
+        (test):
+        * stress/generator-construct-failure.js: Added.
+        (shouldThrow):
+        (TypeError):
+        * stress/generator-prototype-change.js: Added.
+        (shouldBe):
+        (gen):
+        * stress/generator-prototype-closure.js: Added.
+        (shouldBe):
+        (test.gen):
+        (test):
+        * stress/object-assign-fast-path.js:
+
 2019-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
 
         Follow-up after String.codePointAt optimization
diff --git a/JSTests/stress/create-generator.js b/JSTests/stress/create-generator.js
new file mode 100644 (file)
index 0000000..92d0305
--- /dev/null
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test() {
+    function* generator() {
+        return this;
+    }
+
+    var g = generator();
+    shouldBe(g.__proto__, generator.prototype);
+    return g;
+}
+
+for (var i = 0; i < 1e6; ++i) {
+    var g1 = test();
+    var g2 = test();
+    shouldBe(g1.__proto__ != g2.__proto__, true);
+}
diff --git a/JSTests/stress/generator-construct-failure.js b/JSTests/stress/generator-construct-failure.js
new file mode 100644 (file)
index 0000000..0e4a3c7
--- /dev/null
@@ -0,0 +1,24 @@
+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() { }
+
+shouldThrow(() => {
+    new gen()
+}, `TypeError: function is not a constructor (evaluating 'new gen()')`);
+
+shouldThrow(() => {
+    Reflect.construct(gen, [], {});
+}, `TypeError: Reflect.construct requires the first argument be a constructor`);
diff --git a/JSTests/stress/generator-prototype-change.js b/JSTests/stress/generator-prototype-change.js
new file mode 100644 (file)
index 0000000..9871172
--- /dev/null
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function* gen()
+{
+}
+var originalPrototype = gen.prototype;
+
+for (var i = 0; i < 1e6; ++i) {
+    var g = gen();
+    shouldBe(g.__proto__, gen.prototype);
+}
+gen.prototype = {};
+var g = gen();
+shouldBe(g.__proto__, gen.prototype);
+shouldBe(g.__proto__ !== originalPrototype, true);
diff --git a/JSTests/stress/generator-prototype-closure.js b/JSTests/stress/generator-prototype-closure.js
new file mode 100644 (file)
index 0000000..4b28ed6
--- /dev/null
@@ -0,0 +1,22 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function test() {
+    function* gen()
+    {
+    }
+    var originalPrototype = gen.prototype;
+
+    var g = gen();
+    shouldBe(g.__proto__, gen.prototype);
+    gen.prototype = {};
+    var g = gen();
+    shouldBe(g.__proto__, gen.prototype);
+    shouldBe(g.__proto__ !== originalPrototype, true);
+}
+noInline(test);
+
+for (var i = 0; i < 1e5; ++i)
+    test();
index 5c6d54760a87bfe9b46703658aefe31e0e5a436a..ecb90d56bcd50fc3f55c97c1229cb383b9a28e3d 100644 (file)
@@ -128,14 +128,18 @@ function checkProperty(object, name, value, attributes = { writable: true, enume
     shouldBe(okCalled, 1);
 }
 {
-    let builtin = createBuiltin(`(function (obj) {
-        return @getByIdDirectPrivate(obj, "generatorState");
+    let builtinPut = createBuiltin(`(function (obj, value) {
+        @putByIdDirectPrivate(obj, "next", value);
     })`);
-    function* hello() { }
-    let generator = hello();
-    shouldBe(typeof builtin(generator), "number");
-    let result = Object.assign({}, generator);
-    shouldBe(typeof builtin(result), "undefined");
+    let builtinGet = createBuiltin(`(function (obj) {
+        return @getByIdDirectPrivate(obj, "next");
+    })`);
+    var object = {};
+    var value = 42;
+    builtinPut(object, value);
+    shouldBe(typeof builtinGet(object), "number");
+    let result = Object.assign({}, object);
+    shouldBe(typeof builtinGet(result), "undefined");
 }
 {
     let object = {};
index 8bfadca4f87efa197ded5f8032e485e4093bcb4d..e12172efb64d85c7ec47e81e25fecf474e32a4a4 100644 (file)
@@ -1,3 +1,166 @@
+2019-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Generator should have internal fields
+        https://bugs.webkit.org/show_bug.cgi?id=201159
+
+        Reviewed by Keith Miller.
+
+        This patch makes generator's internal states InternalField instead of private properties.
+        Each generator function produces a generator with different [[Prototype]], which makes generators have different Structures.
+        As a result, Generator.prototype.next etc.'s implementation becomes megamorphic even if it is not necessary.
+
+        If we make these structures adaptively poly-proto, some generators get poly-proto structures while others are not, resulting
+        in megamorphic lookup in Generator.prototype.next. If we make all the generator's structure poly-proto, it makes Generator.prototype.next
+        lookup suboptimal for now.
+
+        In this patch, we start with a relatively simple solution. This patch introduces JSGenerator class, and it has internal fields for generator's internal
+        states. We extend promise-internal-field access bytecodes to access to these fields from bytecode so that Generator.prototype.next can access
+        these fields without using megamorphic get_by_id_direct.
+
+        And we attach JSGeneratorType to JSGenerator so that we can efficiently implement `@isGenerator()` check in bytecode.
+
+        We reserve the offset = 0 slot for the future poly-proto extension for JSGenerator. By reserving this slot, non-poly-proto JSGenerator and poly-proto
+        JSGenerator still can offer the way to access to the same Generator internal fields with the same offset while poly-proto JSGenerator can get offset = 0
+        inline-storage slot for PolyProto implementation.
+
+        This patch adds op_create_generator since it is distinct from op_create_promise once we add PolyProto support.
+        In the future when we introduce some kind of op_create_async_generator we will probably share only one bytecode for both generator and async generator.
+
+        This patch offers around 10% improvement in JetStream2/Basic. And this patch is the basis of optimization of JetStream2/async-fs which leverages async generators significantly.
+
+        This patch includes several design decisions.
+
+            1. We add a new JSGenerator instead of leveraging JSFinalObject. The main reason is that we would like to have JSGeneratorType to quickly query `@isGenerator`.
+            2. This patch currently does not include object-allocation-sinking support for JSGenerator, but it is trivial, and will be added. And this patch also does not include poly-proto
+               support for JSGenerator. The main reason is simply because this patch is already large enough, and I do not want to make this patch larger and larger.
+            3. We can support arbitrary sized inline-storage: Reserving 0-5 offsets for internal fields, and start putting all the other things to the subsequent internal fields. But for now,
+               we are not taking this approach just because I'm not sure this is necessary. If we found such a pattern, we can easily extend the current one but for now, I would like to keep
+               this patch simple.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * builtins/AsyncFunctionPrototype.js:
+        (globalPrivate.asyncFunctionResume):
+        * builtins/GeneratorPrototype.js:
+        (globalPrivate.generatorResume):
+        (next):
+        (return):
+        (throw):
+        * bytecode/BytecodeGeneratorification.cpp:
+        (JSC::BytecodeGeneratorification::run):
+        * bytecode/BytecodeIntrinsicRegistry.cpp:
+        (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
+        * bytecode/BytecodeIntrinsicRegistry.h:
+        * bytecode/BytecodeList.rb:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        (JSC::CodeBlock::finalizeLLIntInlineCaches):
+        * bytecode/SpeculatedType.cpp:
+        (JSC::speculationFromJSType):
+        * bytecode/SpeculatedType.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::emitPutGeneratorFields):
+        (JSC::BytecodeGenerator::emitCreateGenerator):
+        (JSC::BytecodeGenerator::emitNewGenerator):
+        (JSC::BytecodeGenerator::emitYield):
+        (JSC::BytecodeGenerator::emitDelegateYield):
+        (JSC::BytecodeGenerator::emitGeneratorStateChange):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitIsGenerator):
+        (JSC::BytecodeGenerator::generatorStateRegister):
+        (JSC::BytecodeGenerator::generatorValueRegister):
+        (JSC::BytecodeGenerator::generatorResumeModeRegister):
+        (JSC::BytecodeGenerator::generatorFrameRegister):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::generatorInternalFieldIndex):
+        (JSC::BytecodeIntrinsicNode::emit_intrinsic_getGeneratorInternalField):
+        (JSC::BytecodeIntrinsicNode::emit_intrinsic_putGeneratorInternalField):
+        (JSC::BytecodeIntrinsicNode::emit_intrinsic_isGenerator):
+        (JSC::FunctionNode::emitBytecode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGClobbersExitState.cpp:
+        (JSC::DFG::clobbersExitState):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupIsCellWithType):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToNewGenerator):
+        (JSC::DFG::Node::speculatedTypeForQuery):
+        (JSC::DFG::Node::hasStructure):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCreatePromise):
+        (JSC::DFG::SpeculativeJIT::compileCreateGenerator):
+        (JSC::DFG::SpeculativeJIT::compileNewGenerator):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStoreBarrierInsertionPhase.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewGenerator):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCreatePromise):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCreateGenerator):
+        (JSC::FTL::DFG::LowerDFGToB3::isCellWithType):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_internal_field):
+        (JSC::JIT::emit_op_put_internal_field):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        * runtime/InternalFunction.cpp:
+        (JSC::InternalFunction::createSubclassStructureSlow):
+        * runtime/InternalFunction.h:
+        (JSC::InternalFunction::createSubclassStructure):
+        * runtime/JSGenerator.cpp: Added.
+        (JSC::JSGenerator::create):
+        (JSC::JSGenerator::createStructure):
+        (JSC::JSGenerator::JSGenerator):
+        (JSC::JSGenerator::finishCreation):
+        (JSC::JSGenerator::visitChildren):
+        * runtime/JSGenerator.h: Copied from Source/JavaScriptCore/runtime/JSGeneratorFunction.h.
+        * runtime/JSGeneratorFunction.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::generatorStructure const):
+        * runtime/JSType.cpp:
+        (WTF::printInternal):
+        * runtime/JSType.h:
+
 2019-09-17  Keith Miller  <keith_miller@apple.com>
 
         Move comment explaining our Options to OptionsList.h
index 62edca9b8fa0b26c3058bcffecda275eaf25cc7f..fb40b0e10a15ac7266624b202d1264ab469ffb6c 100644 (file)
                E3400EC122A1CC7B009DED54 /* FunctionExecutableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3400EC022A1CC78009DED54 /* FunctionExecutableInlines.h */; };
                E34E657520668EAA00FB81AC /* ParseHash.h in Headers */ = {isa = PBXBuildFile; fileRef = E34E657320668E8D00FB81AC /* ParseHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E34EDBF71DB5FFC900DC87A5 /* FrameTracers.h in Headers */ = {isa = PBXBuildFile; fileRef = E34EDBF61DB5FFC100DC87A5 /* FrameTracers.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E34F930E2322D882002B8DB4 /* JSGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = E34F930C2322D881002B8DB4 /* JSGenerator.h */; };
                E350708A1DC49BBF0089BCD6 /* DOMJITSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = E35070891DC49BB60089BCD6 /* DOMJITSignature.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E354622B1B6065D100545386 /* ConstructAbility.h in Headers */ = {isa = PBXBuildFile; fileRef = E354622A1B6065D100545386 /* ConstructAbility.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3555B8A1DAE03A500F36921 /* DOMJITCallDOMGetterSnippet.h in Headers */ = {isa = PBXBuildFile; fileRef = E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterSnippet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E34E657320668E8D00FB81AC /* ParseHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseHash.h; sourceTree = "<group>"; };
                E34E657420668E8E00FB81AC /* ParseHash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHash.cpp; sourceTree = "<group>"; };
                E34EDBF61DB5FFC100DC87A5 /* FrameTracers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameTracers.h; sourceTree = "<group>"; };
+               E34F930B2322D881002B8DB4 /* JSGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGenerator.cpp; sourceTree = "<group>"; };
+               E34F930C2322D881002B8DB4 /* JSGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenerator.h; sourceTree = "<group>"; };
                E35070891DC49BB60089BCD6 /* DOMJITSignature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITSignature.h; sourceTree = "<group>"; };
                E354622A1B6065D100545386 /* ConstructAbility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstructAbility.h; sourceTree = "<group>"; };
                E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterSnippet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITCallDOMGetterSnippet.h; sourceTree = "<group>"; };
                                F692A85E0255597D01FF60F7 /* JSFunction.cpp */,
                                F692A85F0255597D01FF60F7 /* JSFunction.h */,
                                A72028B91797603D0098028C /* JSFunctionInlines.h */,
+                               E34F930B2322D881002B8DB4 /* JSGenerator.cpp */,
+                               E34F930C2322D881002B8DB4 /* JSGenerator.h */,
                                70B7918C1C024462002481E2 /* JSGeneratorFunction.cpp */,
                                70B7918D1C024462002481E2 /* JSGeneratorFunction.h */,
                                0F2B66C317B6B5AB00A7AE3F /* JSGenericTypedArrayView.h */,
                                0F2B66F017B6B5AB00A7AE3F /* JSFloat64Array.h in Headers */,
                                BC18C41F0E16F5CD00B34460 /* JSFunction.h in Headers */,
                                A72028BA1797603D0098028C /* JSFunctionInlines.h in Headers */,
+                               E34F930E2322D882002B8DB4 /* JSGenerator.h in Headers */,
                                70B7919C1C024A49002481E2 /* JSGeneratorFunction.h in Headers */,
                                0F2B66F117B6B5AB00A7AE3F /* JSGenericTypedArrayView.h in Headers */,
                                0F2B66F217B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h in Headers */,
index 6a331d1de0963fc6a6b28f3a0e386ba9ec6bee54..43ea530c2513485e747d5415352728787c8285c6 100644 (file)
@@ -824,6 +824,7 @@ runtime/JSDateMath.cpp
 runtime/JSDestructibleObjectHeapCellType.cpp
 runtime/JSFixedArray.cpp
 runtime/JSFunction.cpp
+runtime/JSGenerator.cpp
 runtime/JSGeneratorFunction.cpp
 runtime/JSGlobalLexicalEnvironment.cpp
 runtime/JSGlobalObject.cpp
index 5214bd6f3a1b4e2e5f1e95aa1c9911899b89500f..968cf1e7346192f1d458c3798ec37c8d1bc91d02 100644 (file)
@@ -31,22 +31,22 @@ function asyncFunctionResume(generator, promise, sentValue, resumeMode)
 
     @assert(@isPromise(promise));
 
-    var state = @getByIdDirectPrivate(generator, "generatorState");
+    var state = @getGeneratorInternalField(generator, @generatorFieldState);
     var value = @undefined;
 
     if (state === @GeneratorStateCompleted || (resumeMode !== @GeneratorResumeModeNormal && resumeMode !== @GeneratorResumeModeThrow))
         @throwTypeError("Async function illegally resumed");
 
     try {
-        @putByIdDirectPrivate(generator, "generatorState", @GeneratorStateExecuting);
-        value = @getByIdDirectPrivate(generator, "generatorNext").@call(@getByIdDirectPrivate(generator, "generatorThis"), generator, state, sentValue, resumeMode, @getByIdDirectPrivate(generator, "generatorFrame"));
-        if (@getByIdDirectPrivate(generator, "generatorState") === @GeneratorStateExecuting) {
-            @putByIdDirectPrivate(generator, "generatorState", @GeneratorStateCompleted);
+        @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateExecuting);
+        value = @getGeneratorInternalField(generator, @generatorFieldNext).@call(@getGeneratorInternalField(generator, @generatorFieldThis), generator, state, sentValue, resumeMode, @getGeneratorInternalField(generator, @generatorFieldFrame));
+        if (@getGeneratorInternalField(generator, @generatorFieldState) === @GeneratorStateExecuting) {
+            @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
             @resolvePromiseWithFirstResolvingFunctionCallCheck(promise, value);
             return promise;
         }
     } catch (error) {
-        @putByIdDirectPrivate(generator, "generatorState", @GeneratorStateCompleted);
+        @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
         @rejectPromiseWithFirstResolvingFunctionCallCheck(promise, error);
         return promise;
     }
index b2801df882b8a8bc6e15e6e14a9f296cd1c6925d..8393ea28ae8997692cfeb6ee254baf795271c08d 100644 (file)
@@ -34,14 +34,14 @@ function generatorResume(generator, state, generatorThis, sentValue, value, resu
     var done = state === @GeneratorStateCompleted;
     if (!done) {
         try {
-            @putByIdDirectPrivate(generator, "generatorState", @GeneratorStateExecuting);
-            value = @getByIdDirectPrivate(generator, "generatorNext").@call(generatorThis, generator, state, sentValue, resumeMode, @getByIdDirectPrivate(generator, "generatorFrame"));
-            if (@getByIdDirectPrivate(generator, "generatorState") === @GeneratorStateExecuting) {
-                @putByIdDirectPrivate(generator, "generatorState", @GeneratorStateCompleted);
+            @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateExecuting);
+            value = @getGeneratorInternalField(generator, @generatorFieldNext).@call(generatorThis, generator, state, sentValue, resumeMode, @getGeneratorInternalField(generator, @generatorFieldFrame));
+            if (@getGeneratorInternalField(generator, @generatorFieldState) === @GeneratorStateExecuting) {
+                @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
                 done = true;
             }
         } catch (error) {
-            @putByIdDirectPrivate(generator, "generatorState", @GeneratorStateCompleted);
+            @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
             throw error;
         }
     }
@@ -52,43 +52,43 @@ function next(value)
 {
     "use strict";
 
-    var state = @getByIdDirectPrivate(this, "generatorState");
-    if (typeof state !== "number")
+    if (!@isGenerator(this))
         @throwTypeError("|this| should be a generator");
 
+    var state = @getGeneratorInternalField(this, @generatorFieldState);
     if (state === @GeneratorStateExecuting)
         @throwTypeError("Generator is executing");
 
-    return @generatorResume(this, state, @getByIdDirectPrivate(this, "generatorThis"), value, @undefined, @GeneratorResumeModeNormal);
+    return @generatorResume(this, state, @getGeneratorInternalField(this, @generatorFieldThis), value, @undefined, @GeneratorResumeModeNormal);
 }
 
 function return(value)
 {
     "use strict";
 
-    var state = @getByIdDirectPrivate(this, "generatorState");
-    if (typeof state !== "number")
+    if (!@isGenerator(this))
         @throwTypeError("|this| should be a generator");
 
+    var state = @getGeneratorInternalField(this, @generatorFieldState);
     if (state === @GeneratorStateExecuting)
         @throwTypeError("Generator is executing");
 
-    return @generatorResume(this, state, @getByIdDirectPrivate(this, "generatorThis"), value, value, @GeneratorResumeModeReturn);
+    return @generatorResume(this, state, @getGeneratorInternalField(this, @generatorFieldThis), value, value, @GeneratorResumeModeReturn);
 }
 
 function throw(exception)
 {
     "use strict";
 
-    var state = @getByIdDirectPrivate(this, "generatorState");
-    if (typeof state !== "number")
+    if (!@isGenerator(this))
         @throwTypeError("|this| should be a generator");
 
+    var state = @getGeneratorInternalField(this, @generatorFieldState);
     if (state === @GeneratorStateExecuting)
         @throwTypeError("Generator is executing");
 
     if (state === @GeneratorStateCompleted)
         throw exception;
 
-    return @generatorResume(this, state, @getByIdDirectPrivate(this, "generatorThis"), exception, @undefined, @GeneratorResumeModeThrow);
+    return @generatorResume(this, state, @getGeneratorInternalField(this, @generatorFieldThis), exception, @undefined, @GeneratorResumeModeThrow);
 }
index 9544bcb4c8869b34586f166c874cbb081503efdf..286051cc95ea4d8fda66fb0997bb593ede7e32a6 100644 (file)
@@ -36,7 +36,7 @@
 #include "InterpreterInlines.h"
 #include "JSCInlines.h"
 #include "JSCJSValueInlines.h"
-#include "JSGeneratorFunction.h"
+#include "JSGenerator.h"
 #include "Label.h"
 #include "StrongInlines.h"
 #include "UnlinkedCodeBlock.h"
@@ -223,7 +223,7 @@ void BytecodeGeneratorification::run()
     {
         auto nextToEnterPoint = enterPoint().next();
         unsigned switchTableIndex = m_codeBlock->numberOfSwitchJumpTables();
-        VirtualRegister state = virtualRegisterForArgument(static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::State));
+        VirtualRegister state = virtualRegisterForArgument(static_cast<int32_t>(JSGenerator::GeneratorArgument::State));
         auto& jumpTable = m_codeBlock->addSwitchJumpTable();
         jumpTable.min = 0;
         jumpTable.branchOffsets.resize(m_yields.size() + 1);
@@ -238,7 +238,7 @@ void BytecodeGeneratorification::run()
     }
 
     for (const YieldData& data : m_yields) {
-        VirtualRegister scope = virtualRegisterForArgument(static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::Frame));
+        VirtualRegister scope = virtualRegisterForArgument(static_cast<int32_t>(JSGenerator::GeneratorArgument::Frame));
 
         auto instruction = m_instructions.at(data.point);
         // Emit save sequence.
index 198443d531fc6c79e7ea15538b2301febff45f6d..06fc5819212b31b0559eeff6119d75aa510c9725 100644 (file)
@@ -33,7 +33,7 @@
 #include "IterationKind.h"
 #include "JSAsyncGeneratorFunction.h"
 #include "JSCInlines.h"
-#include "JSGeneratorFunction.h"
+#include "JSGenerator.h"
 #include "JSGlobalObject.h"
 #include "JSModuleLoader.h"
 #include "JSPromise.h"
@@ -72,13 +72,19 @@ BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry(VM& vm)
     m_promiseStateMask.set(m_vm, jsNumber(JSPromise::stateMask));
     m_promiseFlagsIsHandled.set(m_vm, jsNumber(JSPromise::isHandledFlag));
     m_promiseFlagsIsFirstResolvingFunctionCalled.set(m_vm, jsNumber(JSPromise::isFirstResolvingFunctionCalledFlag));
+    // FIXME: Clean up JSInternalObjectImpl field registry.
+    // https://bugs.webkit.org/show_bug.cgi?id=201894
     m_promiseFieldFlags.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Field::Flags)));
     m_promiseFieldReactionsOrResult.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Field::ReactionsOrResult)));
-    m_GeneratorResumeModeNormal.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)));
-    m_GeneratorResumeModeThrow.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode)));
-    m_GeneratorResumeModeReturn.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode)));
-    m_GeneratorStateCompleted.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorState::Completed)));
-    m_GeneratorStateExecuting.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorState::Executing)));
+    m_generatorFieldState.set(m_vm, jsNumber(static_cast<unsigned>(JSGenerator::Field::State)));
+    m_generatorFieldNext.set(m_vm, jsNumber(static_cast<unsigned>(JSGenerator::Field::Next)));
+    m_generatorFieldThis.set(m_vm, jsNumber(static_cast<unsigned>(JSGenerator::Field::This)));
+    m_generatorFieldFrame.set(m_vm, jsNumber(static_cast<unsigned>(JSGenerator::Field::Frame)));
+    m_GeneratorResumeModeNormal.set(m_vm, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode)));
+    m_GeneratorResumeModeThrow.set(m_vm, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ThrowMode)));
+    m_GeneratorResumeModeReturn.set(m_vm, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ReturnMode)));
+    m_GeneratorStateCompleted.set(m_vm, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorState::Completed)));
+    m_GeneratorStateExecuting.set(m_vm, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorState::Executing)));
     m_AsyncGeneratorStateCompleted.set(m_vm, jsNumber(static_cast<int32_t>(JSAsyncGeneratorFunction::AsyncGeneratorState::Completed)));
     m_AsyncGeneratorStateExecuting.set(m_vm, jsNumber(static_cast<int32_t>(JSAsyncGeneratorFunction::AsyncGeneratorState::Executing)));
     m_AsyncGeneratorStateSuspendedStart.set(m_vm, jsNumber(static_cast<int32_t>(JSAsyncGeneratorFunction::AsyncGeneratorState::SuspendedStart)));
index d5f6c3b05eeb89659acd987b16f20c9436bba750..280b7f906d65e50ffb7675e11ea2e293b7d57ea9 100644 (file)
@@ -42,11 +42,13 @@ class RegisterID;
     macro(getByIdDirect) \
     macro(getByIdDirectPrivate) \
     macro(getPromiseInternalField) \
+    macro(getGeneratorInternalField) \
     macro(idWithProfile) \
     macro(isObject) \
     macro(isJSArray) \
     macro(isProxyObject) \
     macro(isDerivedArray) \
+    macro(isGenerator) \
     macro(isPromise) \
     macro(isRegExpObject) \
     macro(isMap) \
@@ -61,6 +63,7 @@ class RegisterID;
     macro(putByIdDirectPrivate) \
     macro(putByValDirect) \
     macro(putPromiseInternalField) \
+    macro(putGeneratorInternalField) \
     macro(toNumber) \
     macro(toString) \
     macro(toObject) \
@@ -98,6 +101,10 @@ class RegisterID;
     macro(promiseFlagsIsFirstResolvingFunctionCalled) \
     macro(promiseFieldFlags) \
     macro(promiseFieldReactionsOrResult) \
+    macro(generatorFieldState) \
+    macro(generatorFieldNext) \
+    macro(generatorFieldThis) \
+    macro(generatorFieldFrame) \
     macro(GeneratorResumeModeNormal) \
     macro(GeneratorResumeModeThrow) \
     macro(GeneratorResumeModeReturn) \
index 3b3998ab50cd620309bac6d67fd6918ff4a01a75..1ba41f106b7a1151255712f6a3d933770f2d73f1 100644 (file)
@@ -134,6 +134,20 @@ op :new_promise,
         isInternalPromise: bool,
     }
 
+op :create_generator,
+    args: {
+        dst: VirtualRegister,
+        callee: VirtualRegister,
+    },
+    metadata: {
+        cachedCallee: WriteBarrier[JSCell]
+    }
+
+op :new_generator,
+    args: {
+        dst: VirtualRegister,
+    }
+
 op :get_argument,
     args: {
         dst: VirtualRegister,
index be0859640fb107de8b782bcfa5081bc7d1c79bc2..4079249965d5618e93f986724724ecc3732015c7 100644 (file)
@@ -80,6 +80,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins
     case op_jmp:
     case op_new_object:
     case op_new_promise:
+    case op_new_generator:
     case op_enter:
     case op_argument_count:
     case op_catch:
@@ -194,6 +195,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins
     USES(OpNewArrayWithSize, length)
     USES(OpCreateThis, callee)
     USES(OpCreatePromise, callee)
+    USES(OpCreateGenerator, callee)
     USES(OpDelById, base)
     USES(OpNewFunc, scope)
     USES(OpNewAsyncGeneratorFunc, scope)
@@ -385,6 +387,7 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins
     DEFS(OpToPrimitive, dst)
     DEFS(OpCreateThis, dst)
     DEFS(OpCreatePromise, dst)
+    DEFS(OpCreateGenerator, dst)
     DEFS(OpNewArray, dst)
     DEFS(OpNewArrayWithSpread, dst)
     DEFS(OpSpread, dst)
@@ -465,6 +468,7 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins
     DEFS(OpMov, dst)
     DEFS(OpNewObject, dst)
     DEFS(OpNewPromise, dst)
+    DEFS(OpNewGenerator, dst)
     DEFS(OpToThis, srcDst)
     DEFS(OpGetScope, dst)
     DEFS(OpCreateDirectArguments, dst)
index 1382f69cb586e70d4719690fdc3c9572ae9148e2..5b4ab151d6e92db3bb6b1064b982d609b30d8c2f 100644 (file)
@@ -568,6 +568,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         LINK(OpPutById)
         LINK(OpCreateThis)
         LINK(OpCreatePromise)
+        LINK(OpCreateGenerator)
 
         LINK(OpAdd)
         LINK(OpMul)
@@ -1274,6 +1275,9 @@ void CodeBlock::finalizeLLIntInlineCaches()
         m_metadata->forEach<OpCreatePromise>([&] (auto& metadata) {
             handleCreateBytecode(metadata, "op_create_promise"_s);
         });
+        m_metadata->forEach<OpCreateGenerator>([&] (auto& metadata) {
+            handleCreateBytecode(metadata, "op_create_generator"_s);
+        });
 
         m_metadata->forEach<OpResolveScope>([&] (auto& metadata) {
             // Right now this isn't strictly necessary. Any symbol tables that this will refer to
index 42b626c05ee1f5184606ea6da940ff19aa230278..6d4e22032b1dde04ebc2fb6bb5d901eba9e309ee 100644 (file)
@@ -579,7 +579,7 @@ TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType type)
     return NotTypedArray;
 }
 
-SpeculatedType speculationFromJSType(JSType type)
+Optional<SpeculatedType> speculationFromJSType(JSType type)
 {
     switch (type) {
     case StringType:
@@ -609,9 +609,8 @@ SpeculatedType speculationFromJSType(JSType type)
     case DataViewType:
         return SpecDataViewObject;
     default:
-        ASSERT_NOT_REACHED();
+        return WTF::nullopt;
     }
-    return SpecNone;
 }
 
 SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType type)
index b929bc24341ce1b36e89c8b14377eb07d138ede0..b1153b47d2fd3a59ee3fcffb0f3bbf39b015195b 100644 (file)
@@ -497,7 +497,7 @@ JS_EXPORT_PRIVATE SpeculatedType speculationFromValue(JSValue);
 // If it's an anyInt(), it'll return speculated types from the Int52 lattice.
 // Otherwise, it'll return types from the JSValue lattice.
 JS_EXPORT_PRIVATE SpeculatedType int52AwareSpeculationFromValue(JSValue);
-SpeculatedType speculationFromJSType(JSType);
+Optional<SpeculatedType> speculationFromJSType(JSType);
 
 SpeculatedType speculationFromTypedArrayType(TypedArrayType); // only valid for typed views.
 TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType);
index 6883545630e3ebecfc52004c500fb2b724ca42c1..fb47b5e3ba6d79688ffb61d3f5d2caa5d05a2856 100644 (file)
@@ -683,7 +683,17 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
 
     switch (parseMode) {
     case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GeneratorWrapperMethodMode:
+    case SourceParseMode::GeneratorWrapperMethodMode: {
+        m_generatorRegister = addVar();
+
+        // FIXME: Emit to_this only when Generator uses it.
+        // https://bugs.webkit.org/show_bug.cgi?id=151586
+        emitToThis();
+
+        emitCreateGenerator(m_generatorRegister, &m_calleeRegister);
+        break;
+    }
+
     case SourceParseMode::AsyncGeneratorWrapperMethodMode:
     case SourceParseMode::AsyncGeneratorWrapperFunctionMode: {
         m_generatorRegister = addVar();
@@ -711,7 +721,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             emitToThis();
         }
 
-        emitNewObject(m_generatorRegister);
+        emitNewGenerator(m_generatorRegister);
         emitNewPromise(promiseRegister(), m_isBuiltinFunction);
         break;
     }
@@ -866,7 +876,10 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             // Generatorification inserts lexical environment creation if necessary. Otherwise, we convert it to op_mov frame, `undefined`.
             OpCreateGeneratorFrameEnvironment::emit(this, generatorFrameRegister(), scopeRegister(), VirtualRegister { symbolTableConstantIndex }, addConstantValue(jsUndefined()));
         }
-        emitPutById(generatorRegister(), propertyNames().builtinNames().generatorFramePrivateName(), generatorFrameRegister());
+        if (parseMode == SourceParseMode::AsyncGeneratorBodyMode)
+            emitPutById(generatorRegister(), propertyNames().builtinNames().generatorFramePrivateName(), generatorFrameRegister());
+        else
+            emitPutInternalField(generatorRegister(), static_cast<unsigned>(JSGenerator::Field::Frame), generatorFrameRegister());
     }
 
     bool shouldInitializeBlockScopedFunctions = false; // We generate top-level function declarations in ::generate().
@@ -2698,20 +2711,12 @@ void BytecodeGenerator::emitPutSetterByVal(RegisterID* base, RegisterID* propert
 
 void BytecodeGenerator::emitPutGeneratorFields(RegisterID* nextFunction)
 {
-    // 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
-
-    emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().generatorNextPrivateName(), nextFunction, PropertyNode::KnownDirect);
+    emitPutInternalField(m_generatorRegister, static_cast<unsigned>(JSGenerator::Field::Next), nextFunction);
 
     // We do not store 'this' in arrow function within constructor,
     // because it might be not initialized, if super is called later.
     if (!(isDerivedConstructorContext() && m_codeBlock->parseMode() == SourceParseMode::AsyncArrowFunctionMode))
-        emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().generatorThisPrivateName(), &m_thisRegister, PropertyNode::KnownDirect);
-
-    emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().generatorStatePrivateName(), emitLoad(nullptr, jsNumber(0)), PropertyNode::KnownDirect);
-
-    emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().generatorFramePrivateName(), emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
+        emitPutInternalField(m_generatorRegister, static_cast<unsigned>(JSGenerator::Field::This), &m_thisRegister);
 }
 
 void BytecodeGenerator::emitPutAsyncGeneratorFields(RegisterID* nextFunction)
@@ -2858,6 +2863,18 @@ RegisterID* BytecodeGenerator::emitNewPromise(RegisterID* dst, bool isInternalPr
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitCreateGenerator(RegisterID* dst, RegisterID* newTarget)
+{
+    OpCreateGenerator::emit(this, dst, newTarget);
+    return dst;
+}
+
+RegisterID* BytecodeGenerator::emitNewGenerator(RegisterID* dst)
+{
+    OpNewGenerator::emit(this, dst);
+    return dst;
+}
+
 void BytecodeGenerator::emitTDZCheck(RegisterID* target)
 {
     OpCheckTdz::emit(this, target);
@@ -4544,11 +4561,11 @@ RegisterID* BytecodeGenerator::emitYield(RegisterID* argument, JSAsyncGeneratorF
 
     Ref<Label> normalLabel = newLabel();
     RefPtr<RegisterID> condition = newTemporary();
-    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode))));
     emitJumpIfTrue(condition.get(), normalLabel.get());
 
     Ref<Label> throwLabel = newLabel();
-    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
+    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ThrowMode))));
     emitJumpIfTrue(condition.get(), throwLabel.get());
     // Return.
     {
@@ -4656,10 +4673,10 @@ RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, Throwable
                 Ref<Label> returnLabel = newLabel();
                 {
                     RefPtr<RegisterID> condition = newTemporary();
-                    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+                    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode))));
                     emitJumpIfTrue(condition.get(), normalLabel.get());
 
-                    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode))));
+                    emitEqualityOp<OpStricteq>(condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ReturnMode))));
                     emitJumpIfTrue(condition.get(), returnLabel.get());
 
                     // Fallthrough to ThrowMode.
@@ -4761,7 +4778,10 @@ RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, Throwable
 void BytecodeGenerator::emitGeneratorStateChange(int32_t state)
 {
     RegisterID* completedState = emitLoad(nullptr, jsNumber(state));
-    emitPutById(generatorRegister(), propertyNames().builtinNames().generatorStatePrivateName(), completedState);
+    if (m_codeBlock->parseMode() == SourceParseMode::AsyncGeneratorBodyMode)
+        emitPutById(generatorRegister(), propertyNames().builtinNames().generatorStatePrivateName(), completedState);
+    else
+        emitPutInternalField(generatorRegister(), static_cast<unsigned>(JSGenerator::Field::State), completedState);
 }
 
 bool BytecodeGenerator::emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label& jumpTarget)
index 4f36a735410adfaec46f5395b3feee2fcb905a81..2694b226ab95c2d870ccc0fac421df116145c73e 100644 (file)
@@ -35,7 +35,7 @@
 #include "Interpreter.h"
 #include "JSAsyncGeneratorFunction.h"
 #include "JSBigInt.h"
-#include "JSGeneratorFunction.h"
+#include "JSGenerator.h"
 #include "JSTemplateObjectDescriptor.h"
 #include "Label.h"
 #include "LabelScope.h"
@@ -724,12 +724,14 @@ namespace JSC {
 
         RegisterID* emitCreateThis(RegisterID* dst);
         RegisterID* emitCreatePromise(RegisterID* dst, RegisterID* newTarget, bool isInternalPromise);
+        RegisterID* emitCreateGenerator(RegisterID* dst, RegisterID* newTarget);
         void emitTDZCheck(RegisterID* target);
         bool needsTDZCheck(const Variable&);
         void emitTDZCheckIfNecessary(const Variable&, RegisterID* target, RegisterID* scope);
         void liftTDZCheckIfPossible(const Variable&);
         RegisterID* emitNewObject(RegisterID* dst);
         RegisterID* emitNewPromise(RegisterID* dst, bool isInternalPromise);
+        RegisterID* emitNewGenerator(RegisterID* dst);
         RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length, IndexingType recommendedIndexingType); // stops at first elision
         RegisterID* emitNewArrayBuffer(RegisterID* dst, JSImmutableButterfly*, IndexingType recommendedIndexingType);
         // FIXME: new_array_with_spread should use an array allocation profile and take a recommendedIndexingType
@@ -866,6 +868,7 @@ namespace JSC {
         RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index);
 
         RegisterID* emitIsCellWithType(RegisterID* dst, RegisterID* src, JSType);
+        RegisterID* emitIsGenerator(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSGeneratorType); }
         RegisterID* emitIsJSArray(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, ArrayType); }
         RegisterID* emitIsPromise(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSPromiseType); }
         RegisterID* emitIsProxyObject(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, ProxyObjectType); }
@@ -988,10 +991,10 @@ namespace JSC {
         void emitGeneratorStateChange(int32_t state);
         RegisterID* emitYield(RegisterID* argument, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason = JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Yield);
         RegisterID* emitDelegateYield(RegisterID* argument, ThrowableExpressionData*);
-        RegisterID* generatorStateRegister() { return &m_parameters[static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::State)]; }
-        RegisterID* generatorValueRegister() { return &m_parameters[static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::Value)]; }
-        RegisterID* generatorResumeModeRegister() { return &m_parameters[static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::ResumeMode)]; }
-        RegisterID* generatorFrameRegister() { return &m_parameters[static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::Frame)]; }
+        RegisterID* generatorStateRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::State)]; }
+        RegisterID* generatorValueRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::Value)]; }
+        RegisterID* generatorResumeModeRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::ResumeMode)]; }
+        RegisterID* generatorFrameRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::Frame)]; }
 
         CodeType codeType() const { return m_codeType; }
 
index 2c65f50a2b6e92e1aadfb412f8056f421d149cb4..652766abf9c5414843009ade68f798437244e683 100644 (file)
@@ -34,7 +34,7 @@
 #include "JIT.h"
 #include "JSCInlines.h"
 #include "JSFunction.h"
-#include "JSGeneratorFunction.h"
+#include "JSGenerator.h"
 #include "JSGlobalObject.h"
 #include "JSImmutableButterfly.h"
 #include "LabelScope.h"
@@ -1020,6 +1020,20 @@ static JSPromise::Field promiseInternalFieldIndex(BytecodeIntrinsicNode* node)
     return JSPromise::Field::Flags;
 }
 
+static JSGenerator::Field generatorInternalFieldIndex(BytecodeIntrinsicNode* node)
+{
+    if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldState)
+        return JSGenerator::Field::State;
+    if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldNext)
+        return JSGenerator::Field::Next;
+    if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldThis)
+        return JSGenerator::Field::This;
+    if (node->emitter() == &BytecodeIntrinsicNode::emit_intrinsic_generatorFieldFrame)
+        return JSGenerator::Field::Frame;
+    RELEASE_ASSERT_NOT_REACHED();
+    return JSGenerator::Field::State;
+}
+
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getPromiseInternalField(BytecodeGenerator& generator, RegisterID* dst)
 {
     ArgumentListNode* node = m_args->m_listNode;
@@ -1033,6 +1047,19 @@ RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getPromiseInternalField(Byteco
     return generator.emitGetInternalField(generator.finalDestination(dst), base.get(), index);
 }
 
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_getGeneratorInternalField(BytecodeGenerator& generator, RegisterID* dst)
+{
+    ArgumentListNode* node = m_args->m_listNode;
+    RefPtr<RegisterID> base = generator.emitNode(node);
+    node = node->m_next;
+    RELEASE_ASSERT(node->m_expr->isBytecodeIntrinsicNode());
+    unsigned index = static_cast<unsigned>(generatorInternalFieldIndex(static_cast<BytecodeIntrinsicNode*>(node->m_expr)));
+    ASSERT(index < JSGenerator::numberOfInternalFields);
+    ASSERT(!node->m_next);
+
+    return generator.emitGetInternalField(generator.finalDestination(dst), base.get(), index);
+}
+
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_argument(BytecodeGenerator& generator, RegisterID* dst)
 {
     ArgumentListNode* node = m_args->m_listNode;
@@ -1118,6 +1145,22 @@ RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putPromiseInternalField(Byteco
     return generator.move(dst, generator.emitPutInternalField(base.get(), index, value.get()));
 }
 
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putGeneratorInternalField(BytecodeGenerator& generator, RegisterID* dst)
+{
+    ArgumentListNode* node = m_args->m_listNode;
+    RefPtr<RegisterID> base = generator.emitNode(node);
+    node = node->m_next;
+    RELEASE_ASSERT(node->m_expr->isBytecodeIntrinsicNode());
+    unsigned index = static_cast<unsigned>(generatorInternalFieldIndex(static_cast<BytecodeIntrinsicNode*>(node->m_expr)));
+    ASSERT(index < JSGenerator::numberOfInternalFields);
+    node = node->m_next;
+    RefPtr<RegisterID> value = generator.emitNode(node);
+
+    ASSERT(!node->m_next);
+
+    return generator.move(dst, generator.emitPutInternalField(base.get(), index, value.get()));
+}
+
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_tailCallForwardArguments(BytecodeGenerator& generator, RegisterID* dst)
 {
     ArgumentListNode* node = m_args->m_listNode;
@@ -1231,6 +1274,15 @@ RegisterID* BytecodeIntrinsicNode::emit_intrinsic_idWithProfile(BytecodeGenerato
 
     return generator.move(dst, generator.emitIdWithProfile(idValue.get(), speculation));
 }
+
+RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isGenerator(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst)
+{
+    ArgumentListNode* node = m_args->m_listNode;
+    RefPtr<RegisterID> src = generator.emitNode(node);
+    ASSERT(!node->m_next);
+
+    return generator.move(dst, generator.emitIsGenerator(generator.tempDestination(dst), src.get()));
+}
     
 RegisterID* BytecodeIntrinsicNode::emit_intrinsic_isJSArray(JSC::BytecodeGenerator& generator, JSC::RegisterID* dst)
 {
@@ -3993,7 +4045,7 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
         generator.move(args.argumentRegister(argumentCount++), generator.generatorRegister());
         generator.move(args.argumentRegister(argumentCount++), generator.promiseRegister());
         generator.emitLoad(args.argumentRegister(argumentCount++), jsUndefined());
-        generator.emitLoad(args.argumentRegister(argumentCount++), jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)));
+        generator.emitLoad(args.argumentRegister(argumentCount++), jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode)));
         // JSTextPosition(int _line, int _offset, int _lineStartOffset)
         JSTextPosition divot(firstLine(), startOffset(), lineStartOffset());
 
@@ -4010,11 +4062,11 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
         Ref<Label> generatorBodyLabel = generator.newLabel();
         {
             RefPtr<RegisterID> condition = generator.newTemporary();
-            generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
+            generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::NormalMode))));
             generator.emitJumpIfTrue(condition.get(), generatorBodyLabel.get());
 
             Ref<Label> throwLabel = generator.newLabel();
-            generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
+            generator.emitEqualityOp<OpStricteq>(condition.get(), generator.generatorResumeModeRegister(), generator.emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGenerator::GeneratorResumeMode::ThrowMode))));
             generator.emitJumpIfTrue(condition.get(), throwLabel.get());
 
             generator.emitReturn(generator.generatorValueRegister());
index c2fe3aba959b0502f48f55a25515df294d7e9e0b..9b637fd7def51a618538ab04682b045d26a1ef7a 100644 (file)
@@ -37,6 +37,7 @@
 #include "GetterSetter.h"
 #include "HashMapImpl.h"
 #include "JITOperations.h"
+#include "JSGenerator.h"
 #include "JSImmutableButterfly.h"
 #include "JSInternalPromise.h"
 #include "JSInternalPromiseConstructor.h"
@@ -1564,18 +1565,27 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             }
             break;
 
-        case IsCellWithType:
-            if (!(child.m_type & ~node->speculatedTypeForQuery())) {
+        case IsCellWithType: {
+            Optional<SpeculatedType> filter = node->speculatedTypeForQuery();
+            if (!filter) {
+                if (!(child.m_type & SpecCell)) {
+                    setConstant(node, jsBoolean(false));
+                    constantWasSet = true;
+                }
+                break;
+            }
+            if (!(child.m_type & ~filter.value())) {
                 setConstant(node, jsBoolean(true));
                 constantWasSet = true;
                 break;
             }
-            if (!(child.m_type & node->speculatedTypeForQuery())) {
+            if (!(child.m_type & filter.value())) {
                 setConstant(node, jsBoolean(false));
                 constantWasSet = true;
                 break;
             }
             break;
+        }
 
         case IsTypedArrayView:
             if (!(child.m_type & ~SpecTypedArrayView)) {
@@ -2676,10 +2686,42 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
 
+    case CreateGenerator: {
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
+        if (JSValue base = forNode(node->child1()).m_value) {
+            if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) {
+                if (FunctionRareData* rareData = function->rareData()) {
+                    if (rareData->allocationProfileWatchpointSet().isStillValid()) {
+                        Structure* structure = rareData->internalFunctionAllocationStructure();
+                        if (structure
+                            && structure->classInfo() == JSGenerator::info()
+                            && structure->globalObject() == globalObject
+                            && rareData->allocationProfileWatchpointSet().isStillValid()) {
+                            m_graph.freeze(rareData);
+                            m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
+                            m_state.setFoundConstants(true);
+                            didFoldClobberWorld();
+                            setForNode(node, structure);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        clobberWorld();
+        setTypeForNode(node, SpecObjectOther);
+        break;
+    }
+
     case NewPromise:
         ASSERT(!!node->structure().get());
         setForNode(node, node->structure());
         break;
+
+    case NewGenerator:
+        ASSERT(!!node->structure().get());
+        setForNode(node, node->structure());
+        break;
         
     case NewObject:
         ASSERT(!!node->structure().get());
index b17cdf893b7855e69f3ebcadee4c7dc0a9c74380..f6a7d539364c87651cce1a10e209ed7d940f94ac 100644 (file)
@@ -4850,8 +4850,6 @@ void ByteCodeParser::parseBlock(unsigned limit)
                             m_graph.freeze(rareData);
                             m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
                             
-                            // The callee is still live up to this point.
-                            addToGraph(Phantom, callee);
                             Node* object = addToGraph(NewObject, OpInfo(m_graph.registerStructure(structure)));
                             if (structure->hasPolyProto()) {
                                 StorageAccessData* data = m_graph.m_storageAccessData.add();
@@ -4861,6 +4859,8 @@ void ByteCodeParser::parseBlock(unsigned limit)
                                 addToGraph(PutByOffset, OpInfo(data), object, object, weakJSConstant(prototype));
                             }
                             set(VirtualRegister(bytecode.m_dst), object);
+                            // The callee is still live up to this point.
+                            addToGraph(Phantom, callee);
                             alreadyEmitted = true;
                         }
                     }
@@ -4930,9 +4930,9 @@ void ByteCodeParser::parseBlock(unsigned limit)
                                 m_graph.freeze(rareData);
                                 m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
 
+                                set(VirtualRegister(bytecode.m_dst), addToGraph(NewPromise, OpInfo(m_graph.registerStructure(structure)), OpInfo(bytecode.m_isInternalPromise)));
                                 // The callee is still live up to this point.
                                 addToGraph(Phantom, callee);
-                                set(VirtualRegister(bytecode.m_dst), addToGraph(NewPromise, OpInfo(m_graph.registerStructure(structure)), OpInfo(bytecode.m_isInternalPromise)));
                                 alreadyEmitted = true;
                             }
                         }
@@ -4944,6 +4944,52 @@ void ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_create_promise);
         }
 
+        case op_create_generator: {
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
+            auto bytecode = currentInstruction->as<OpCreateGenerator>();
+            Node* callee = get(VirtualRegister(bytecode.m_callee));
+
+            bool alreadyEmitted = false;
+
+            JSFunction* function = callee->dynamicCastConstant<JSFunction*>(*m_vm);
+            if (!function) {
+                JSCell* cachedFunction = bytecode.metadata(codeBlock).m_cachedCallee.unvalidatedGet();
+                if (cachedFunction
+                    && cachedFunction != JSCell::seenMultipleCalleeObjects()
+                    && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) {
+                    ASSERT(cachedFunction->inherits<JSFunction>(*m_vm));
+
+                    FrozenValue* frozen = m_graph.freeze(cachedFunction);
+                    addToGraph(CheckCell, OpInfo(frozen), callee);
+
+                    function = static_cast<JSFunction*>(cachedFunction);
+                }
+            }
+
+            if (function) {
+                if (FunctionRareData* rareData = function->rareData()) {
+                    if (rareData->allocationProfileWatchpointSet().isStillValid()) {
+                        Structure* structure = rareData->internalFunctionAllocationStructure();
+                        if (structure
+                            && structure->classInfo() == JSGenerator::info()
+                            && structure->globalObject() == globalObject
+                            && rareData->allocationProfileWatchpointSet().isStillValid()) {
+                            m_graph.freeze(rareData);
+                            m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
+
+                            set(VirtualRegister(bytecode.m_dst), addToGraph(NewGenerator, OpInfo(m_graph.registerStructure(structure))));
+                            // The callee is still live up to this point.
+                            addToGraph(Phantom, callee);
+                            alreadyEmitted = true;
+                        }
+                    }
+                }
+            }
+            if (!alreadyEmitted)
+                set(VirtualRegister(bytecode.m_dst), addToGraph(CreateGenerator, callee));
+            NEXT_OPCODE(op_create_generator);
+        }
+
         case op_new_object: {
             auto bytecode = currentInstruction->as<OpNewObject>();
             set(bytecode.m_dst,
@@ -4958,6 +5004,13 @@ void ByteCodeParser::parseBlock(unsigned limit)
             set(bytecode.m_dst, addToGraph(NewPromise, OpInfo(m_graph.registerStructure(bytecode.m_isInternalPromise ? globalObject->internalPromiseStructure() : globalObject->promiseStructure())), OpInfo(bytecode.m_isInternalPromise)));
             NEXT_OPCODE(op_new_promise);
         }
+
+        case op_new_generator: {
+            auto bytecode = currentInstruction->as<OpNewGenerator>();
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
+            set(bytecode.m_dst, addToGraph(NewGenerator, OpInfo(m_graph.registerStructure(globalObject->generatorStructure()))));
+            NEXT_OPCODE(op_new_generator);
+        }
             
         case op_new_array: {
             auto bytecode = currentInstruction->as<OpNewArray>();
index c0ee98aea838d7256e6b754b54574bb8d6e9f9fa..71ec7f1628495eb2c840459517857102f1d8e40a 100644 (file)
@@ -117,6 +117,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const I
     case op_check_tdz:
     case op_create_this:
     case op_create_promise:
+    case op_create_generator:
     case op_bitnot:
     case op_bitand:
     case op_bitor:
@@ -212,6 +213,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const I
     case op_end:
     case op_new_object:
     case op_new_promise:
+    case op_new_generator:
     case op_new_array:
     case op_new_array_with_size:
     case op_new_array_buffer:
index 303f4793e3b645e848bc36dd269bd8f0cb654db4..9a8ad07b31a88bea6f9b4d7a9a92e1ddbf8ed547 100644 (file)
@@ -668,6 +668,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case NumberToStringWithRadix:
     case CreateThis:
     case CreatePromise:
+    case CreateGenerator:
     case InstanceOf:
     case StringValueOf:
     case ObjectKeys:
@@ -1566,6 +1567,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
 
     case NewObject:
     case NewPromise:
+    case NewGenerator:
     case NewRegexp:
     case NewSymbol:
     case NewStringObject:
index 370fd1dc2c5c1476c7b5a53cfdc2db7c1f4e01c4..d2f7ba478d8ec834cd2508d53bd9fa14d280090e 100644 (file)
@@ -58,6 +58,7 @@ bool clobbersExitState(Graph& graph, Node* node)
     case Arrayify:
     case NewObject:
     case NewPromise:
+    case NewGenerator:
     case NewRegexp:
     case NewSymbol:
     case NewStringObject:
index 99d875e66a6b70fbe52881e00117a708bea43bd0..f3f5cb60d88ac5c6452ddf15be4c45dfe108d9a7 100644 (file)
@@ -778,6 +778,30 @@ private:
                 break;
             }
 
+            case CreateGenerator: {
+                JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
+                if (JSValue base = m_state.forNode(node->child1()).m_value) {
+                    if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) {
+                        if (FunctionRareData* rareData = function->rareData()) {
+                            if (rareData->allocationProfileWatchpointSet().isStillValid()) {
+                                Structure* structure = rareData->internalFunctionAllocationStructure();
+                                if (structure
+                                    && structure->classInfo() == JSGenerator::info()
+                                    && structure->globalObject() == globalObject
+                                    && rareData->allocationProfileWatchpointSet().isStillValid()) {
+                                    m_graph.freeze(rareData);
+                                    m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
+                                    node->convertToNewGenerator(m_graph.registerStructure(structure));
+                                    changed = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+
             case ObjectCreate: {
                 if (JSValue base = m_state.forNode(node->child1()).m_value) {
                     JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
index 4072f917e45f4a0591a8aac6830f0d804a654766..c9733d0096d62ef2d5dec1783ec769bef2027567 100644 (file)
@@ -333,6 +333,7 @@ bool doesGC(Graph& graph, Node* node)
     case TryGetById:
     case CreateThis:
     case CreatePromise:
+    case CreateGenerator:
     case ObjectCreate:
     case ObjectKeys:
     case AllocatePropertyStorage:
@@ -341,6 +342,7 @@ bool doesGC(Graph& graph, Node* node)
     case ArrayifyToStructure:
     case NewObject:
     case NewPromise:
+    case NewGenerator:
     case NewArray:
     case NewArrayWithSpread:
     case Spread:
index ec040af8dd673da0a40747b1ae99d623c67ec412..d0643225acbfb44d6f01f1f47ff1ac597893e5e5 100644 (file)
@@ -1647,6 +1647,7 @@ private:
         case CheckCell:
         case CreateThis:
         case CreatePromise:
+        case CreateGenerator:
         case GetButterfly: {
             fixEdge<CellUse>(node->child1());
             break;
@@ -2404,6 +2405,7 @@ private:
         case ProfileControlFlow:
         case NewObject:
         case NewPromise:
+        case NewGenerator:
         case NewRegexp:
         case DeleteById:
         case DeleteByVal:
@@ -2574,61 +2576,64 @@ private:
 
     void fixupIsCellWithType(Node* node)
     {
-        switch (node->speculatedTypeForQuery()) {
-        case SpecString:
-            if (node->child1()->shouldSpeculateString()) {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Check, node->origin,
-                    Edge(node->child1().node(), StringUse));
-                m_graph.convertToConstant(node, jsBoolean(true));
-                observeUseKindOnNode<StringUse>(node);
-                return;
-            }
-            break;
+        Optional<SpeculatedType> filter = node->speculatedTypeForQuery();
+        if (filter) {
+            switch (filter.value()) {
+            case SpecString:
+                if (node->child1()->shouldSpeculateString()) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, Check, node->origin,
+                        Edge(node->child1().node(), StringUse));
+                    m_graph.convertToConstant(node, jsBoolean(true));
+                    observeUseKindOnNode<StringUse>(node);
+                    return;
+                }
+                break;
 
-        case SpecProxyObject:
-            if (node->child1()->shouldSpeculateProxyObject()) {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Check, node->origin,
-                    Edge(node->child1().node(), ProxyObjectUse));
-                m_graph.convertToConstant(node, jsBoolean(true));
-                observeUseKindOnNode<ProxyObjectUse>(node);
-                return;
-            }
-            break;
+            case SpecProxyObject:
+                if (node->child1()->shouldSpeculateProxyObject()) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, Check, node->origin,
+                        Edge(node->child1().node(), ProxyObjectUse));
+                    m_graph.convertToConstant(node, jsBoolean(true));
+                    observeUseKindOnNode<ProxyObjectUse>(node);
+                    return;
+                }
+                break;
 
-        case SpecRegExpObject:
-            if (node->child1()->shouldSpeculateRegExpObject()) {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Check, node->origin,
-                    Edge(node->child1().node(), RegExpObjectUse));
-                m_graph.convertToConstant(node, jsBoolean(true));
-                observeUseKindOnNode<RegExpObjectUse>(node);
-                return;
-            }
-            break;
+            case SpecRegExpObject:
+                if (node->child1()->shouldSpeculateRegExpObject()) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, Check, node->origin,
+                        Edge(node->child1().node(), RegExpObjectUse));
+                    m_graph.convertToConstant(node, jsBoolean(true));
+                    observeUseKindOnNode<RegExpObjectUse>(node);
+                    return;
+                }
+                break;
 
-        case SpecArray:
-            if (node->child1()->shouldSpeculateArray()) {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Check, node->origin,
-                    Edge(node->child1().node(), ArrayUse));
-                m_graph.convertToConstant(node, jsBoolean(true));
-                observeUseKindOnNode<ArrayUse>(node);
-                return;
-            }
-            break;
+            case SpecArray:
+                if (node->child1()->shouldSpeculateArray()) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, Check, node->origin,
+                        Edge(node->child1().node(), ArrayUse));
+                    m_graph.convertToConstant(node, jsBoolean(true));
+                    observeUseKindOnNode<ArrayUse>(node);
+                    return;
+                }
+                break;
 
-        case SpecDerivedArray:
-            if (node->child1()->shouldSpeculateDerivedArray()) {
-                m_insertionSet.insertNode(
-                    m_indexInBlock, SpecNone, Check, node->origin,
-                    Edge(node->child1().node(), DerivedArrayUse));
-                m_graph.convertToConstant(node, jsBoolean(true));
-                observeUseKindOnNode<DerivedArrayUse>(node);
-                return;
+            case SpecDerivedArray:
+                if (node->child1()->shouldSpeculateDerivedArray()) {
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, Check, node->origin,
+                        Edge(node->child1().node(), DerivedArrayUse));
+                    m_graph.convertToConstant(node, jsBoolean(true));
+                    observeUseKindOnNode<DerivedArrayUse>(node);
+                    return;
+                }
+                break;
             }
-            break;
         }
 
         if (node->child1()->shouldSpeculateCell()) {
index ab8ab4266009d16fcc0287491b23c45cd3107c30..a594cf0d96ba274ab418573bd3d7b6476ed3b199 100644 (file)
@@ -281,8 +281,8 @@ void Graph::dump(PrintStream& out, const char* prefixStr, Node* node, DumpContex
             }
         }
     }
-    if (node->hasSpeculatedTypeForQuery())
-        out.print(comma, SpeculationDump(node->speculatedTypeForQuery()));
+    if (node->hasQueriedType())
+        out.print(comma, node->queriedType());
     if (node->hasStorageAccessData()) {
         StorageAccessData& storageAccessData = node->storageAccessData();
         out.print(comma, "id", storageAccessData.identifierNumber, "{", identifiers()[storageAccessData.identifierNumber], "}");
index 676df6365b1505a59e78dd46bc247aa65ca276b9..2d5524a6bc98b02483fcaaeff6bf9505cad55a5a 100644 (file)
@@ -767,6 +767,15 @@ public:
         m_opInfo2 = internal;
     }
 
+    void convertToNewGenerator(RegisteredStructure structure)
+    {
+        ASSERT(m_op == CreateGenerator);
+        setOpAndDefaultFlags(NewGenerator);
+        children.reset();
+        m_opInfo = structure;
+        m_opInfo2 = OpInfoWrapper();
+    }
+
     void convertToNewArrayBuffer(FrozenValue* immutableButterfly);
     
     void convertToDirectCall(FrozenValue*);
@@ -1372,7 +1381,7 @@ public:
         return op() == IsCellWithType;
     }
 
-    SpeculatedType speculatedTypeForQuery()
+    Optional<SpeculatedType> speculatedTypeForQuery()
     {
         return speculationFromJSType(queriedType());
     }
@@ -1909,6 +1918,7 @@ public:
         case ArrayifyToStructure:
         case NewObject:
         case NewPromise:
+        case NewGenerator:
         case NewStringObject:
             return true;
         default:
index 2618520bce9473aab96082c3538ea5b1716736c3..1ebdfd13a95b55424bc61c33c964b5d752e4a432 100644 (file)
@@ -54,6 +54,7 @@ namespace JSC { namespace DFG {
     macro(ToThis, NodeResultJS) \
     macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
     macro(CreatePromise, NodeResultJS | NodeMustGenerate) \
+    macro(CreateGenerator, NodeResultJS | NodeMustGenerate) \
     macro(GetCallee, NodeResultJS) \
     macro(SetCallee, NodeMustGenerate) \
     macro(GetArgumentCountIncludingThis, NodeResultInt32) \
@@ -341,6 +342,7 @@ namespace JSC { namespace DFG {
     /* Allocations. */\
     macro(NewObject, NodeResultJS) \
     macro(NewPromise, NodeResultJS) \
+    macro(NewGenerator, NodeResultJS) \
     macro(NewArray, NodeResultJS | NodeHasVarArgs) \
     macro(NewArrayWithSpread, NodeResultJS | NodeHasVarArgs) \
     macro(NewArrayWithSize, NodeResultJS | NodeMustGenerate) \
index afa28220dcf302441441593e3573d89e3ad5033d..c315c26527c762b13c0e6e33c349c2bcb64449ab 100644 (file)
@@ -398,6 +398,16 @@ JSCell* JIT_OPERATION operationCreateInternalPromise(ExecState* exec, JSObject*
     RELEASE_AND_RETURN(scope, JSInternalPromise::create(vm, structure));
 }
 
+JSCell* JIT_OPERATION operationCreateGenerator(ExecState* exec, JSObject* constructor, JSGlobalObject* globalObject)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    Structure* structure = InternalFunction::createSubclassStructure(exec, nullptr, constructor, globalObject->generatorStructure());
+    RETURN_IF_EXCEPTION(scope, nullptr);
+    RELEASE_AND_RETURN(scope, JSGenerator::create(vm, structure));
+}
+
 JSCell* JIT_OPERATION operationCallObjectConstructor(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue encodedTarget)
 {
     VM& vm = exec->vm();
index b98e62175c66f36e364d58e9dc806ad052dc652b..744a50dbfef8275e29af72969c6864a3662c5702 100644 (file)
@@ -50,6 +50,7 @@ JSCell* JIT_OPERATION operationObjectCreateObject(ExecState*, JSObject*) WTF_INT
 JSCell* JIT_OPERATION operationCreateThis(ExecState*, JSObject* constructor, uint32_t inlineCapacity) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreatePromise(ExecState*, JSObject* constructor, JSGlobalObject*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreateInternalPromise(ExecState*, JSObject* constructor, JSGlobalObject*) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationCreateGenerator(ExecState*, JSObject* constructor, JSGlobalObject*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueMod(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
index 00ac55c6e669be4217cdd0a7050387d0e4305841..c3d921cd71a58364790a1ccea99448cef24f7f47 100644 (file)
@@ -1015,6 +1015,11 @@ private:
         case NewPromise:
             setPrediction(SpecPromiseObject);
             break;
+
+        case CreateGenerator:
+        case NewGenerator:
+            setPrediction(SpecObjectOther);
+            break;
             
         case ArraySlice:
         case NewArrayWithSpread:
index 6837e235b3062557718f5f132c04682cd8cec93b..7d8eee84dfa77cc47feb1950aee1d63bda785c16 100644 (file)
@@ -179,6 +179,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ToThis:
     case CreateThis:
     case CreatePromise:
+    case CreateGenerator:
     case ObjectCreate:
     case ObjectKeys:
     case GetCallee:
@@ -321,6 +322,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case ConstructForwardVarargs:
     case NewObject:
     case NewPromise:
+    case NewGenerator:
     case NewArray:
     case NewArrayWithSize:
     case NewArrayBuffer:
index 9b4246f750ffb71127c38a3cc21003dcaffd45ed..1cf76cef9e193fa3f54ac6e352c3f078153eb477 100644 (file)
@@ -12722,6 +12722,7 @@ void SpeculativeJIT::compileCreatePromise(Node* node)
     m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
     slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
     m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()), structureGPR);
+    slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, structureGPR));
     m_jit.move(TrustedImmPtr(node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info()), scratch1GPR);
     slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::classInfoOffset())));
     m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), scratch1GPR);
@@ -12742,6 +12743,51 @@ void SpeculativeJIT::compileCreatePromise(Node* node)
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileCreateGenerator(Node* node)
+{
+    JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic);
+
+    SpeculateCellOperand callee(this, node->child1());
+    GPRTemporary result(this);
+    GPRTemporary structure(this);
+    GPRTemporary scratch1(this);
+    GPRTemporary scratch2(this);
+
+    GPRReg calleeGPR = callee.gpr();
+    GPRReg resultGPR = result.gpr();
+    GPRReg structureGPR = structure.gpr();
+    GPRReg scratch1GPR = scratch1.gpr();
+    GPRReg scratch2GPR = scratch2.gpr();
+    // Rare data is only used to access the allocator & structure
+    // We can avoid using an additional GPR this way
+    GPRReg rareDataGPR = structureGPR;
+
+    MacroAssembler::JumpList slowCases;
+
+    slowCases.append(m_jit.branchIfNotFunction(calleeGPR));
+    m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
+    slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR));
+    m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()), structureGPR);
+    slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, structureGPR));
+    m_jit.move(TrustedImmPtr(JSGenerator::info()), scratch1GPR);
+    slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::classInfoOffset())));
+    m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), scratch1GPR);
+    slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::globalObjectOffset())));
+
+    auto butterfly = TrustedImmPtr(nullptr);
+    emitAllocateJSObjectWithKnownSize<JSGenerator>(resultGPR, structureGPR, butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSGenerator));
+    m_jit.storeTrustedValue(jsNull(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::PolyProto))));
+    m_jit.storeTrustedValue(jsNumber(static_cast<int32_t>(JSGenerator::GeneratorState::Init)), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::State))));
+    m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::Next))));
+    m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::This))));
+    m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::Frame))));
+    m_jit.mutatorFence(m_jit.vm());
+
+    addSlowPathGenerator(slowPathCall(slowCases, this, operationCreateGenerator, resultGPR, calleeGPR, TrustedImmPtr::weakPointer(m_jit.graph(), globalObject)));
+
+    cellResult(resultGPR, node);
+}
+
 void SpeculativeJIT::compileNewObject(Node* node)
 {
     GPRTemporary result(this);
@@ -12798,6 +12844,33 @@ void SpeculativeJIT::compileNewPromise(Node* node)
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileNewGenerator(Node* node)
+{
+    GPRTemporary result(this);
+    GPRTemporary scratch1(this);
+    GPRTemporary scratch2(this);
+
+    GPRReg resultGPR = result.gpr();
+    GPRReg scratch1GPR = scratch1.gpr();
+    GPRReg scratch2GPR = scratch2.gpr();
+
+    MacroAssembler::JumpList slowCases;
+
+    FrozenValue* structure = m_graph.freezeStrong(node->structure().get());
+    auto butterfly = TrustedImmPtr(nullptr);
+    emitAllocateJSObjectWithKnownSize<JSGenerator>(resultGPR, TrustedImmPtr(structure), butterfly, scratch1GPR, scratch2GPR, slowCases, sizeof(JSGenerator));
+    m_jit.storeTrustedValue(jsNull(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::PolyProto))));
+    m_jit.storeTrustedValue(jsNumber(static_cast<int32_t>(JSGenerator::GeneratorState::Init)), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::State))));
+    m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::Next))));
+    m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::This))));
+    m_jit.storeTrustedValue(jsUndefined(), CCallHelpers::Address(resultGPR, JSInternalFieldObjectImpl<>::offsetOfInternalField(static_cast<unsigned>(JSGenerator::Field::Frame))));
+    m_jit.mutatorFence(m_jit.vm());
+
+    addSlowPathGenerator(slowPathCall(slowCases, this, operationNewGenerator, resultGPR, TrustedImmPtr(structure)));
+
+    cellResult(resultGPR, node);
+}
+
 void SpeculativeJIT::compileToPrimitive(Node* node)
 {
     DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
index c8354a1225345f19a4f9bb8fcd1cb1662561e823..2d322d4e141d1c9e0dc313b4f1ad19b2282c5241 100644 (file)
@@ -1474,8 +1474,10 @@ public:
     void compileObjectCreate(Node*);
     void compileCreateThis(Node*);
     void compileCreatePromise(Node*);
+    void compileCreateGenerator(Node*);
     void compileNewObject(Node*);
     void compileNewPromise(Node*);
+    void compileNewGenerator(Node*);
     void compileToPrimitive(Node*);
     void compileLogShadowChickenPrologue(Node*);
     void compileLogShadowChickenTail(Node*);
index e9e92912da321dd7623c47dc44389e3b7ae69d9d..a6d46a545681708a9b4d86d099373693b1941a67 100644 (file)
@@ -3157,6 +3157,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case CreateGenerator: {
+        compileCreateGenerator(node);
+        break;
+    }
+
     case NewObject: {
         compileNewObject(node);
         break;
@@ -3167,6 +3172,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case NewGenerator: {
+        compileNewGenerator(node);
+        break;
+    }
+
     case GetCallee: {
         compileGetCallee(node);
         break;
index eec210e7965b2d6088731fa2eae6d80518382671..3733843b3c9cafcc02512a0e5e867b15d4b372eb 100644 (file)
@@ -3483,6 +3483,11 @@ void SpeculativeJIT::compile(Node* node)
         compileCreatePromise(node);
         break;
     }
+
+    case CreateGenerator: {
+        compileCreateGenerator(node);
+        break;
+    }
         
     case NewObject: {
         compileNewObject(node);
@@ -3494,6 +3499,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case NewGenerator: {
+        compileNewGenerator(node);
+        break;
+    }
+
     case GetCallee: {
         compileGetCallee(node);
         break;
index 5d20c9e491f9fa43d36489942bde466c72c95763..54917db3491e2d7a929b571cc73612bad1777584 100644 (file)
@@ -322,6 +322,7 @@ private:
             switch (m_node->op()) {
             case NewObject:
             case NewPromise:
+            case NewGenerator:
             case NewArray:
             case NewArrayWithSize:
             case NewArrayBuffer:
index 198947873079493f89a5e4353b8ce5e4b87cbb8e..ead259a014752e2c36926d8d16c358af164f0b39 100644 (file)
@@ -75,6 +75,7 @@ inline CapabilityLevel canCompile(Node* node)
     case GetButterfly:
     case NewObject:
     case NewPromise:
+    case NewGenerator:
     case NewStringObject:
     case NewSymbol:
     case NewArray:
@@ -380,6 +381,7 @@ inline CapabilityLevel canCompile(Node* node)
     case FilterInByIdStatus:
     case CreateThis:
     case CreatePromise:
+    case CreateGenerator:
     case DataViewGetInt:
     case DataViewGetFloat:
     case DataViewSet:
index 1e1dc7a4f6b08c9921019803699b3be4bad0ab78..8b9b58ae6c345e426c36adbfead6bb761bfd7d91 100644 (file)
@@ -78,6 +78,7 @@
 #include "JSAsyncFunction.h"
 #include "JSAsyncGeneratorFunction.h"
 #include "JSCInlines.h"
+#include "JSGenerator.h"
 #include "JSGeneratorFunction.h"
 #include "JSImmutableButterfly.h"
 #include "JSLexicalEnvironment.h"
@@ -1048,6 +1049,9 @@ private:
         case NewPromise:
             compileNewPromise();
             break;
+        case NewGenerator:
+            compileNewGenerator();
+            break;
         case NewStringObject:
             compileNewStringObject();
             break;
@@ -1066,6 +1070,9 @@ private:
         case CreatePromise:
             compileCreatePromise();
             break;
+        case CreateGenerator:
+            compileCreateGenerator();
+            break;
         case Spread:
             compileSpread();
             break;
@@ -5912,6 +5919,31 @@ private:
         setJSValue(m_out.phi(pointerType(), fastResult, slowResult));
     }
 
+    void compileNewGenerator()
+    {
+        LBasicBlock slowCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowCase);
+
+        LValue generator = allocateObject<JSGenerator>(m_node->structure(), m_out.intPtrZero, slowCase);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsNull())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::PolyProto)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsNumber(static_cast<int32_t>(JSGenerator::GeneratorState::Init)))), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::State)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsUndefined())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::Next)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsUndefined())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::This)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsUndefined())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::Frame)]);
+        mutatorFence();
+        ValueFromBlock fastResult = m_out.anchor(generator);
+        m_out.jump(continuation);
+
+        m_out.appendTo(slowCase, continuation);
+        ValueFromBlock slowResult = m_out.anchor(vmCall(pointerType(), m_out.operation(operationNewGenerator), m_callFrame, frozenPointer(m_graph.freezeStrong(m_node->structure().get()))));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(pointerType(), fastResult, slowResult));
+    }
+
     void compileNewStringObject()
     {
         RegisteredStructure structure = m_node->structure();
@@ -6279,6 +6311,7 @@ private:
         LBasicBlock derivedCase = m_out.newBlock();
         LBasicBlock isFunctionBlock = m_out.newBlock();
         LBasicBlock hasRareData = m_out.newBlock();
+        LBasicBlock hasStructure = m_out.newBlock();
         LBasicBlock checkGlobalObjectCase = m_out.newBlock();
         LBasicBlock fastAllocationCase = m_out.newBlock();
         LBasicBlock slowCase = m_out.newBlock();
@@ -6294,8 +6327,11 @@ private:
         LValue rareData = m_out.loadPtr(callee, m_heaps.JSFunction_rareData);
         m_out.branch(m_out.isZero64(rareData), rarely(slowCase), usually(hasRareData));
 
-        m_out.appendTo(hasRareData, fastAllocationCase);
+        m_out.appendTo(hasRareData, hasStructure);
         LValue structure = m_out.loadPtr(rareData, m_heaps.FunctionRareData_internalFunctionAllocationProfile_structure);
+        m_out.branch(m_out.isZero64(structure), rarely(slowCase), usually(hasStructure));
+
+        m_out.appendTo(hasStructure, checkGlobalObjectCase);
         m_out.branch(m_out.equal(m_out.loadPtr(structure, m_heaps.Structure_classInfo), m_out.constIntPtr(m_node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info())), usually(checkGlobalObjectCase), rarely(slowCase));
 
         m_out.appendTo(checkGlobalObjectCase, fastAllocationCase);
@@ -6324,6 +6360,57 @@ private:
         setJSValue(result);
     }
 
+    void compileCreateGenerator()
+    {
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+
+        LValue callee = lowCell(m_node->child1());
+
+        LBasicBlock isFunctionBlock = m_out.newBlock();
+        LBasicBlock hasRareData = m_out.newBlock();
+        LBasicBlock hasStructure = m_out.newBlock();
+        LBasicBlock checkGlobalObjectCase = m_out.newBlock();
+        LBasicBlock fastAllocationCase = m_out.newBlock();
+        LBasicBlock slowCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        m_out.branch(isFunction(callee, provenType(m_node->child1())), usually(isFunctionBlock), rarely(slowCase));
+
+        LBasicBlock lastNext = m_out.appendTo(isFunctionBlock, hasRareData);
+        LValue rareData = m_out.loadPtr(callee, m_heaps.JSFunction_rareData);
+        m_out.branch(m_out.isZero64(rareData), rarely(slowCase), usually(hasRareData));
+
+        m_out.appendTo(hasRareData, hasStructure);
+        LValue structure = m_out.loadPtr(rareData, m_heaps.FunctionRareData_internalFunctionAllocationProfile_structure);
+        m_out.branch(m_out.isZero64(structure), rarely(slowCase), usually(hasStructure));
+
+        m_out.appendTo(hasStructure, checkGlobalObjectCase);
+        m_out.branch(m_out.equal(m_out.loadPtr(structure, m_heaps.Structure_classInfo), m_out.constIntPtr(JSGenerator::info())), usually(checkGlobalObjectCase), rarely(slowCase));
+
+        m_out.appendTo(checkGlobalObjectCase, fastAllocationCase);
+        m_out.branch(m_out.equal(m_out.loadPtr(structure, m_heaps.Structure_globalObject), weakPointer(globalObject)), usually(fastAllocationCase), rarely(slowCase));
+
+        m_out.appendTo(fastAllocationCase, slowCase);
+        LValue generator = allocateObject<JSGenerator>(structure, m_out.intPtrZero, slowCase);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsNull())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::PolyProto)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsNumber(static_cast<int32_t>(JSGenerator::GeneratorState::Init)))), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::State)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsUndefined())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::Next)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsUndefined())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::This)]);
+        m_out.store64(m_out.constInt64(JSValue::encode(jsUndefined())), generator, m_heaps.JSInternalFieldObjectImpl_internalFields[static_cast<unsigned>(JSGenerator::Field::Frame)]);
+        mutatorFence();
+        ValueFromBlock fastResult = m_out.anchor(generator);
+        m_out.jump(continuation);
+
+        m_out.appendTo(slowCase, continuation);
+        ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, m_out.operation(operationCreateGenerator), m_callFrame, callee, weakPointer(globalObject)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        LValue result = m_out.phi(Int64, fastResult, slowResult);
+
+        setJSValue(result);
+    }
+
     void compileSpread()
     {
         if (m_node->child1()->op() == PhantomNewArrayBuffer) {
@@ -16101,10 +16188,12 @@ private:
         jsValueToStrictInt52(edge, lowJSValue(edge, ManualOperandSpeculation));
     }
 
-    LValue isCellWithType(LValue cell, JSType queriedType, SpeculatedType speculatedTypeForQuery, SpeculatedType type = SpecFullTop)
+    LValue isCellWithType(LValue cell, JSType queriedType, Optional<SpeculatedType> speculatedTypeForQuery, SpeculatedType type = SpecFullTop)
     {
-        if (LValue proven = isProvenValue(type & SpecCell, speculatedTypeForQuery))
-            return proven;
+        if (speculatedTypeForQuery) {
+            if (LValue proven = isProvenValue(type & SpecCell, speculatedTypeForQuery.value()))
+                return proven;
+        }
         return m_out.equal(
             m_out.load8ZeroExt32(cell, m_heaps.JSCell_typeInfoType),
             m_out.constInt32(queriedType));
index b167f1c26aafb03ed3a178ec160542b87fc94b6f..bbfcfe30fa360fdf53d837a7b97a542367e295af 100644 (file)
@@ -312,6 +312,8 @@ void JIT::privateCompileMainPass()
         DEFINE_SLOW_OP(create_rest)
         DEFINE_SLOW_OP(create_promise)
         DEFINE_SLOW_OP(new_promise)
+        DEFINE_SLOW_OP(create_generator)
+        DEFINE_SLOW_OP(new_generator)
         DEFINE_SLOW_OP(pow)
 
         DEFINE_OP(op_add)
@@ -580,6 +582,7 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_SLOW_OP(div)
         DEFINE_SLOWCASE_SLOW_OP(create_this)
         DEFINE_SLOWCASE_SLOW_OP(create_promise)
+        DEFINE_SLOWCASE_SLOW_OP(create_generator)
         DEFINE_SLOWCASE_SLOW_OP(to_this)
         DEFINE_SLOWCASE_SLOW_OP(to_primitive)
         DEFINE_SLOWCASE_SLOW_OP(to_number)
index 7af4ee326cf1e89e9a53f9a277bd5c4052630808..efa254cb2af01257ead60cd225897a61b7109146 100644 (file)
@@ -1394,6 +1394,14 @@ JSCell* JIT_OPERATION operationNewInternalPromise(ExecState* exec, Structure* st
     return JSInternalPromise::create(vm, structure);
 }
 
+JSCell* JIT_OPERATION operationNewGenerator(ExecState* exec, Structure* structure)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    return JSGenerator::create(vm, structure);
+}
+
 JSCell* JIT_OPERATION operationNewRegexp(ExecState* exec, JSCell* regexpPtr)
 {
     SuperSamplerScope superSamplerScope(false);
index 1c3c272cbba8dd3562d4d15cf0950e6c92428762..1b749b230f802d3fc42fcfa16046ba89f30c8c5b 100644 (file)
@@ -421,6 +421,7 @@ void JIT_OPERATION operationSetFunctionName(ExecState*, JSCell*, EncodedJSValue)
 JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewPromise(ExecState*, Structure*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewInternalPromise(ExecState*, Structure*) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationNewGenerator(ExecState*, Structure*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewRegexp(ExecState*, JSCell*) WTF_INTERNAL;
 UnusedPtr JIT_OPERATION operationHandleTraps(ExecState*) WTF_INTERNAL;
 void JIT_OPERATION operationThrow(ExecState*, EncodedJSValue) WTF_INTERNAL;
index 40758e7f30acc4d7282eb8535cb4d31bc8c0e742..369cb10b225c09a142afe623be93d5b04af80dac 100644 (file)
@@ -1243,7 +1243,6 @@ void JIT::emit_op_get_internal_field(const Instruction* currentInstruction)
     int dst = bytecode.m_dst.offset();
     int base = bytecode.m_base.offset();
     unsigned index = bytecode.m_index;
-    ASSERT(index < JSPromise::numberOfInternalFields);
 
     emitGetVirtualRegister(base, regT1);
     loadPtr(Address(regT1, JSInternalFieldObjectImpl<>::offsetOfInternalField(index)), regT0);
@@ -1258,7 +1257,6 @@ void JIT::emit_op_put_internal_field(const Instruction* currentInstruction)
     int base = bytecode.m_base.offset();
     int value = bytecode.m_value.offset();
     unsigned index = bytecode.m_index;
-    ASSERT(index < JSPromise::numberOfInternalFields);
 
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(value, regT1);
index d204b407c2de48e5dcb2ca131a4ab14e3d89b1cc..2576ef49e1183126cff8f1e35eeaedbfe046decd 100644 (file)
@@ -1495,6 +1495,7 @@ slowPathOp(create_rest)
 slowPathOp(create_scoped_arguments)
 slowPathOp(create_this)
 slowPathOp(create_promise)
+slowPathOp(create_generator)
 slowPathOp(define_accessor_property)
 slowPathOp(define_data_property)
 slowPathOp(enumerator_generic_pname)
@@ -1530,6 +1531,7 @@ slowPathOp(to_index_string)
 slowPathOp(typeof)
 slowPathOp(unreachable)
 slowPathOp(new_promise)
+slowPathOp(new_generator)
 
 macro llintSlowPathOp(opcodeName)
     llintOp(op_%opcodeName%, unused, macro (unused, unused, dispatch)
index 6586579823344499702bbbdc5d35cb27544e3cef..1123d179f639062315e542404a1e525b487e6f5f 100644 (file)
@@ -309,6 +309,36 @@ SLOW_PATH_DECL(slow_path_new_promise)
     RETURN(result);
 }
 
+SLOW_PATH_DECL(slow_path_create_generator)
+{
+    BEGIN();
+    auto bytecode = pc->as<OpCreateGenerator>();
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    JSObject* constructorAsObject = asObject(GET(bytecode.m_callee).jsValue());
+
+    Structure* structure = InternalFunction::createSubclassStructure(exec, nullptr, constructorAsObject, globalObject->generatorStructure());
+    CHECK_EXCEPTION();
+    JSGenerator* result = JSGenerator::create(vm, structure);
+
+    JSFunction* constructor = jsDynamicCast<JSFunction*>(vm, constructorAsObject);
+    if (constructor && constructor->canUseAllocationProfile()) {
+        WriteBarrier<JSCell>& cachedCallee = bytecode.metadata(exec).m_cachedCallee;
+        if (!cachedCallee)
+            cachedCallee.set(vm, exec->codeBlock(), constructor);
+        else if (cachedCallee.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cachedCallee.get() != constructor)
+            cachedCallee.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects());
+    }
+    RETURN(result);
+}
+
+SLOW_PATH_DECL(slow_path_new_generator)
+{
+    BEGIN();
+    auto bytecode = pc->as<OpNewGenerator>();
+    JSGenerator* result = JSGenerator::create(vm, exec->lexicalGlobalObject()->generatorStructure());
+    RETURN(result);
+}
+
 SLOW_PATH_DECL(slow_path_to_this)
 {
     BEGIN();
index 2fe75e6c36523efc9ba82a4616550dff7623a188..7f90b140b89790fe14c4307f1a20f74fd9d3fbb1 100644 (file)
@@ -384,6 +384,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_is_var_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope_for_hoisting_func_decl_in_eval);
 SLOW_PATH_HIDDEN_DECL(slow_path_create_promise);
+SLOW_PATH_HIDDEN_DECL(slow_path_create_generator);
 SLOW_PATH_HIDDEN_DECL(slow_path_create_rest);
 SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
 SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
@@ -393,6 +394,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_define_accessor_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_throw_static_error);
 SLOW_PATH_HIDDEN_DECL(slow_path_new_promise);
+SLOW_PATH_HIDDEN_DECL(slow_path_new_generator);
 SLOW_PATH_HIDDEN_DECL(slow_path_new_array_with_spread);
 SLOW_PATH_HIDDEN_DECL(slow_path_new_array_buffer);
 SLOW_PATH_HIDDEN_DECL(slow_path_spread);
index dd4a220800f18343170129f931be312ff37f13d2..238e54333eadccbef85b3eb60403d57b0bf389b1 100644 (file)
@@ -119,7 +119,6 @@ Structure* InternalFunction::createSubclassStructureSlow(ExecState* exec, JSValu
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    ASSERT(!newTarget || newTarget.isConstructor(vm));
 
     ASSERT(baseClass->hasMonoProto());
 
@@ -133,7 +132,7 @@ Structure* InternalFunction::createSubclassStructureSlow(ExecState* exec, JSValu
             return structure;
 
         // Note, Reflect.construct might cause the profile to churn but we don't care.
-        JSValue prototypeValue = newTarget.get(exec, vm.propertyNames->prototype);
+        JSValue prototypeValue = targetFunction->get(exec, vm.propertyNames->prototype);
         RETURN_IF_EXCEPTION(scope, nullptr);
         if (JSObject* prototype = jsDynamicCast<JSObject*>(vm, prototypeValue))
             return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, globalObject, prototype, baseClass);
index e53fb48dc2f7e86a236495f9ef04c33ab8110dc4..abf01ccb27b26ba7f63b4e3b98e269bb3696f820 100644 (file)
@@ -102,8 +102,6 @@ ALWAYS_INLINE Structure* InternalFunction::createSubclassStructure(ExecState* ex
 {
     // We allow newTarget == JSValue() because the API needs to be able to create classes without having a real JS frame.
     // Since we don't allow subclassing in the API we just treat newTarget == JSValue() as newTarget == exec->jsCallee()
-    ASSERT(!newTarget || newTarget.isConstructor(exec->vm()));
-
     if (newTarget && newTarget != baseCallee)
         return createSubclassStructureSlow(exec, newTarget, baseClass);
     return baseClass;
diff --git a/Source/JavaScriptCore/runtime/JSGenerator.cpp b/Source/JavaScriptCore/runtime/JSGenerator.cpp
new file mode 100644 (file)
index 0000000..758b707
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * 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 "JSGenerator.h"
+
+#include "JSCInlines.h"
+#include "JSInternalFieldObjectImplInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSGenerator::s_info = { "Generator", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSGenerator) };
+
+JSGenerator* JSGenerator::create(VM& vm, Structure* structure)
+{
+    JSGenerator* generator = new (NotNull, allocateCell<JSGenerator>(vm.heap)) JSGenerator(vm, structure);
+    generator->finishCreation(vm);
+    return generator;
+}
+
+Structure* JSGenerator::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(JSGeneratorType, StructureFlags), info());
+}
+
+JSGenerator::JSGenerator(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void JSGenerator::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    internalField(static_cast<unsigned>(Field::PolyProto)).set(vm, this, jsNull());
+    internalField(static_cast<unsigned>(Field::State)).set(vm, this, jsNumber(static_cast<int32_t>(GeneratorState::Init)));
+    internalField(static_cast<unsigned>(Field::Next)).set(vm, this, jsUndefined());
+    internalField(static_cast<unsigned>(Field::This)).set(vm, this, jsUndefined());
+    internalField(static_cast<unsigned>(Field::Frame)).set(vm, this, jsUndefined());
+}
+
+void JSGenerator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    auto* thisObject = jsCast<JSGenerator*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGenerator.h b/Source/JavaScriptCore/runtime/JSGenerator.h
new file mode 100644 (file)
index 0000000..7b44e77
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "JSInternalFieldObjectImpl.h"
+
+namespace JSC {
+
+class JSGenerator final : public JSInternalFieldObjectImpl<5> {
+public:
+    using Base = JSInternalFieldObjectImpl<5>;
+
+    // JSGenerator has one inline storage slot, which is pointing internalField(0).
+    static size_t allocationSize(Checked<size_t> inlineCapacity)
+    {
+        ASSERT_UNUSED(inlineCapacity, inlineCapacity == 0U);
+        return sizeof(JSGenerator);
+    }
+
+    enum class GeneratorResumeMode : int32_t {
+        NormalMode = 0,
+        ReturnMode = 1,
+        ThrowMode = 2
+    };
+
+    enum class GeneratorState : int32_t {
+        Completed = -1,
+        Executing = -2,
+        Init = 0,
+    };
+
+    // [this], @generator, @generatorState, @generatorValue, @generatorResumeMode, @generatorFrame.
+    enum class GeneratorArgument : int32_t {
+        ThisValue = 0,
+        Generator = 1,
+        State = 2,
+        Value = 3,
+        ResumeMode = 4,
+        Frame = 5,
+    };
+
+    enum class Field : uint32_t {
+        // FIXME: JSGenerator should support PolyProto, since generator tends to be created with poly proto mode.
+        // We reserve the first internal field for PolyProto property. This offset is identical to JSFinalObject's first inline storage slot which will be used for PolyProto.
+        PolyProto = 0,
+        State,
+        Next,
+        This,
+        Frame,
+    };
+    static_assert(numberOfInternalFields == 5);
+
+    static JSGenerator* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_EXPORT_INFO;
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+protected:
+    JSGenerator(VM&, Structure*);
+    void finishCreation(VM&);
+};
+
+} // namespace JSC
index a454b9588061d48b57f56b30efe063c84f26b293..efd2890a31faf80dfac50b7440b9d2f346eca2cf 100644 (file)
@@ -41,28 +41,7 @@ class JSGeneratorFunction final : public JSFunction {
 #endif
     friend class VM;
 public:
-    typedef JSFunction Base;
-
-    enum class GeneratorResumeMode : int32_t {
-        NormalMode = 0,
-        ReturnMode = 1,
-        ThrowMode = 2
-    };
-
-    enum class GeneratorState : int32_t {
-        Completed = -1,
-        Executing = -2,
-    };
-
-    // [this], @generator, @generatorState, @generatorValue, @generatorResumeMode, @generatorFrame.
-    enum class GeneratorArgument : int32_t {
-        ThisValue = 0,
-        Generator = 1,
-        State = 2,
-        Value = 3,
-        ResumeMode = 4,
-        Frame = 5,
-    };
+    using Base = JSFunction;
 
     const static unsigned StructureFlags = Base::StructureFlags;
 
index aa73fc53d47b700d3420a862ce76e7c0dfa0c751..e87e0cb4162e078545face5271e288525d57591f 100644 (file)
@@ -819,6 +819,7 @@ capitalName ## Constructor* lowerName ## Constructor = featureFlag ? capitalName
 
     m_generatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_generatorFunctionPrototype.get(), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
     m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->prototype, m_generatorPrototype.get(), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
+    m_generatorStructure.set(vm, this, JSGenerator::createStructure(vm, this, m_generatorPrototype.get()));
 
     m_asyncFunctionPrototype.set(vm, this, AsyncFunctionPrototype::create(vm, AsyncFunctionPrototype::createStructure(vm, this, m_functionPrototype.get())));
     AsyncFunctionConstructor* asyncFunctionConstructor = AsyncFunctionConstructor::create(vm, AsyncFunctionConstructor::createStructure(vm, this, functionConstructor), m_asyncFunctionPrototype.get());
@@ -1767,6 +1768,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_generatorFunctionStructure);
     visitor.append(thisObject->m_asyncFunctionStructure);
     visitor.append(thisObject->m_asyncGeneratorFunctionStructure);
+    visitor.append(thisObject->m_generatorStructure);
     thisObject->m_iteratorResultObjectStructure.visit(visitor);
     visitor.append(thisObject->m_regExpMatchesArrayStructure);
     visitor.append(thisObject->m_regExpMatchesArrayWithGroupsStructure);
index c62315ad6bcbeb703c1ca52258a726fd78e8871f..1d2bc2da21416cbee5f910802f7f43c8bb00f21c 100644 (file)
@@ -374,6 +374,7 @@ public:
     WriteBarrier<Structure> m_asyncFunctionStructure;
     WriteBarrier<Structure> m_asyncGeneratorFunctionStructure;
     WriteBarrier<Structure> m_generatorFunctionStructure;
+    WriteBarrier<Structure> m_generatorStructure;
     LazyProperty<JSGlobalObject, Structure> m_iteratorResultObjectStructure;
     WriteBarrier<Structure> m_regExpMatchesArrayStructure;
     WriteBarrier<Structure> m_regExpMatchesArrayWithGroupsStructure;
@@ -752,6 +753,7 @@ public:
     Structure* numberObjectStructure() const { return m_numberObjectStructure.get(this); }
     Structure* mapStructure() const { return m_mapStructure.get(); }
     Structure* regExpStructure() const { return m_regExpStructure.get(); }
+    Structure* generatorStructure() const { return m_generatorStructure.get(); }
     Structure* generatorFunctionStructure() const { return m_generatorFunctionStructure.get(); }
     Structure* asyncFunctionStructure() const { return m_asyncFunctionStructure.get(); }
     Structure* asyncGeneratorFunctionStructure() const { return m_asyncGeneratorFunctionStructure.get(); }
index 849b379188efce570923f5a1a5a4f71bc9d99476..dac5e69da20451b90fd48b07a70c11223f57076a 100644 (file)
@@ -96,6 +96,7 @@ void printInternal(PrintStream& out, JSC::JSType type)
     CASE(WithScopeType)
     CASE(RegExpObjectType)
     CASE(ProxyObjectType)
+    CASE(JSGeneratorType)
     CASE(JSPromiseType)
     CASE(JSMapType)
     CASE(JSSetType)
index 8d35ac77983739b1a3fe5d50a6f91b90129ff77d..01e7022734764b18d9e31a91ee8cd60a995925ea 100644 (file)
@@ -108,6 +108,7 @@ enum JSType : uint8_t {
 
     RegExpObjectType,
     ProxyObjectType,
+    JSGeneratorType,
     JSPromiseType,
     JSMapType,
     JSSetType,