[JSC] Handle new_async_func / new_async_func_exp in DFG / FTL
authorcaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Nov 2016 21:14:15 +0000 (21:14 +0000)
committercaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Nov 2016 21:14:15 +0000 (21:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164037

Reviewed by Yusuke Suzuki.

JSTests:

Add tests based on tests from https://trac.webkit.org/changeset/194216.

* asyncFunctionTests.yaml:
* stress/async-function-create-nobaseline.js: Added.
* stress/async-function-create-optimized.js: Added.
* stress/async-function-declaration-sinking-no-double-allocate.js: Added.
* stress/async-function-declaration-sinking-osrexit.js: Added.
* stress/async-function-declaration-sinking-put.js: Added.
* stress/async-function-expression-sinking-no-double-allocate.js: Added.
* stress/async-function-expression-sinking-osrexit.js: Added.
* stress/async-function-expression-sinking-put.js: Added.

Source/JavaScriptCore:

This patch introduces new_async_func / new_async_func_exp into DFG and FTL,
in much the same capacity that https://trac.webkit.org/changeset/194216 added
DFG / FTL support for generators: by adding new DFG nodes (NewAsyncFunction and
PhantomNewAsyncFunction), rather than extending the existing NewFunction node type.

Like NewFunction and PhantomNewFunction, and the Generator variants, allocation of
async wrapper functions may be deferred or eliminated during the allocation sinking
phase.

* 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/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGMayExit.cpp:
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPhantomNewFunction):
(JSC::DFG::Node::convertToPhantomNewAsyncFunction):
(JSC::DFG::Node::hasCellOperand):
(JSC::DFG::Node::isFunctionAllocation):
(JSC::DFG::Node::isPhantomFunctionAllocation):
(JSC::DFG::Node::isPhantomAllocation):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileNewFunction):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStoreBarrierInsertionPhase.cpp:
* dfg/DFGStructureRegistrationPhase.cpp:
(JSC::DFG::StructureRegistrationPhase::run):
* dfg/DFGValidate.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationPopulateObjectInOSR):
(JSC::FTL::operationMaterializeObjectInOSR):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::asyncFunctionPrototype):
(JSC::JSGlobalObject::asyncFunctionStructure):
(JSC::JSGlobalObject::lazyAsyncFunctionStructure): Deleted.
(JSC::JSGlobalObject::asyncFunctionPrototypeConcurrently): Deleted.
(JSC::JSGlobalObject::asyncFunctionStructureConcurrently): Deleted.

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

36 files changed:
JSTests/ChangeLog
JSTests/asyncFunctionTests.yaml
JSTests/stress/async-function-create-nobaseline.js [new file with mode: 0644]
JSTests/stress/async-function-create-optimized.js [new file with mode: 0644]
JSTests/stress/async-function-declaration-sinking-no-double-allocate.js [new file with mode: 0644]
JSTests/stress/async-function-declaration-sinking-osrexit.js [new file with mode: 0644]
JSTests/stress/async-function-declaration-sinking-put.js [new file with mode: 0644]
JSTests/stress/async-function-expression-sinking-no-double-allocate.js [new file with mode: 0644]
JSTests/stress/async-function-expression-sinking-osrexit.js [new file with mode: 0644]
JSTests/stress/async-function-expression-sinking-put.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js
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/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGMayExit.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
Source/JavaScriptCore/dfg/DFGStructureRegistrationPhase.cpp
Source/JavaScriptCore/dfg/DFGValidate.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/ftl/FTLOperations.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h

index 111df85..41268e0 100644 (file)
@@ -1,3 +1,22 @@
+2016-11-14  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] Handle new_async_func / new_async_func_exp in DFG / FTL
+        https://bugs.webkit.org/show_bug.cgi?id=164037
+
+        Reviewed by Yusuke Suzuki.
+
+        Add tests based on tests from https://trac.webkit.org/changeset/194216.
+
+        * asyncFunctionTests.yaml:
+        * stress/async-function-create-nobaseline.js: Added.
+        * stress/async-function-create-optimized.js: Added.
+        * stress/async-function-declaration-sinking-no-double-allocate.js: Added.
+        * stress/async-function-declaration-sinking-osrexit.js: Added.
+        * stress/async-function-declaration-sinking-put.js: Added.
+        * stress/async-function-expression-sinking-no-double-allocate.js: Added.
+        * stress/async-function-expression-sinking-osrexit.js: Added.
+        * stress/async-function-expression-sinking-put.js: Added.
+
 2016-11-14  Mark Lam  <mark.lam@apple.com>
 
         Some of JSStringView::SafeView methods are not idiomatically safe for JSString to StringView conversions.
index 5fb78be..1e38bfb 100644 (file)
 - path: stress/async-await-reserved-word.js
   cmd: runDefault
 
+# FTLJIT
+- path: stress/async-function-create-optimized.js
+  cmd: runDefault
+- path: stress/async-function-create-nobaseline.js
+  cmd: runDefault
+- path: stress/async-function-declaration-sinking-no-double-allocate.js
+  cmd: runDefault
+- path: stress/async-function-declaration-sinking-osrexit.js
+  cmd: runDefault
+- path: stress/async-function-declaration-sinking-put.js
+  cmd: runDefault
+- path: stress/async-function-expression-sinking-no-double-allocate.js
+  cmd: runDefault
+- path: stress/async-function-expression-sinking-osrexit.js
+  cmd: runDefault
+- path: stress/async-function-expression-sinking-put.js
+  cmd: runDefault
+
 # Test262
 - path: test262/test/built-ins/AsyncFunction/AsyncFunction-construct.js
   cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
diff --git a/JSTests/stress/async-function-create-nobaseline.js b/JSTests/stress/async-function-create-nobaseline.js
new file mode 100644 (file)
index 0000000..0637035
--- /dev/null
@@ -0,0 +1,16 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function test(cond)
+{
+    if (cond) {
+        var func = async function () {};
+        return func;
+    }
+
+    return 42;
+}
+noInline(test);
+
+for (var i = 0; i < 1e4; ++i)
+    test();
diff --git a/JSTests/stress/async-function-create-optimized.js b/JSTests/stress/async-function-create-optimized.js
new file mode 100644 (file)
index 0000000..56f4e04
--- /dev/null
@@ -0,0 +1,47 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var AsyncFunctionPrototype = async function() {}.__proto__;
+
+function testAsyncFunctionExpression()
+{
+    return async function()
+    {
+        await 42;
+        return 1;
+    };
+}
+noInline(testAsyncFunctionExpression);
+
+function testAsyncFunctionDeclaration()
+{
+    async function asyncFn()
+    {
+        await 42;
+        return 1;
+    }
+
+    return asyncFn;
+}
+noInline(testAsyncFunctionDeclaration);
+
+function testAsyncArrowFunction()
+{
+    return async() =>
+    {
+        await 42;
+        return 1;
+    };
+}
+noInline(testAsyncArrowFunction);
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(testAsyncFunctionExpression().__proto__, AsyncFunctionPrototype);
+    shouldBe(testAsyncFunctionDeclaration().__proto__, AsyncFunctionPrototype);
+    shouldBe(testAsyncArrowFunction().__proto__, AsyncFunctionPrototype);
+}
diff --git a/JSTests/stress/async-function-declaration-sinking-no-double-allocate.js b/JSTests/stress/async-function-declaration-sinking-no-double-allocate.js
new file mode 100644 (file)
index 0000000..0d82d14
--- /dev/null
@@ -0,0 +1,41 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg = "") {
+    if (msg)
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+var AsyncFunctionPrototype = async function(){}.__proto__;
+
+function call(o) { o.x = 3; }
+noInline(call);
+
+function sink (p, q) {
+    async function f() { };
+    if (p) {
+        call(f); // Force allocation of f
+        if (q) {
+            OSRExit();
+        }
+        return f;
+    }
+    return { 'x': 2 };
+}
+noInline(sink);
+
+for (var i = 0; i < 100000; ++i) {
+    var o = sink(true, false);
+    shouldBe(o.__proto__, AsyncFunctionPrototype);
+    if (o.x != 3)
+        throw "Error: expected o.x to be 2 but is " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+if (f.x != 3)
+    throw "Error: expected o.x to be 3 but is " + result;
diff --git a/JSTests/stress/async-function-declaration-sinking-osrexit.js b/JSTests/stress/async-function-declaration-sinking-osrexit.js
new file mode 100644 (file)
index 0000000..9a180df
--- /dev/null
@@ -0,0 +1,45 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg = "") {
+    if (msg)
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, promise, msg) {
+    let actual;
+    var hadError = false;
+    promise.then(function(value) { actual = value; },
+                 function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+var AsyncFunctionPrototype = async function(){}.__proto__;
+
+function sink (p, q) {
+    async function g(x) { return x; };
+    if (p) { if (q) OSRExit(); return g; }
+    async function f(x) { return x; };
+    return f;
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+    var f = sink(true, false);
+    shouldBe(f.__proto__, AsyncFunctionPrototype);
+    shouldBeAsync(42, f(42));
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+shouldBeAsync(42, f(42));
diff --git a/JSTests/stress/async-function-declaration-sinking-put.js b/JSTests/stress/async-function-declaration-sinking-put.js
new file mode 100644 (file)
index 0000000..3cf0281
--- /dev/null
@@ -0,0 +1,52 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg = "") {
+    if (msg)
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, promise, msg) {
+    let actual;
+    var hadError = false;
+    promise.then(function(value) { actual = value; },
+                 function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+var AsyncFunctionPrototype = async function(){}.__proto__;
+
+function sink (p, q) {
+    async function g(x) { return x; };
+    if (p) { if (q) g.inner = 42; return g; }
+    async function f(x) { return x; };
+    return f;
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+    var f = sink(true, true);
+    shouldBe(f.__proto__, AsyncFunctionPrototype);
+    shouldBeAsync(42, f(42));
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Test the allocation on the implicit inner else branch
+var f = sink(true, false);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+shouldBeAsync(12, f(12));
+
+// Check that the allocation did not sink beyond the property assignment
+var f = sink(true, true);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+var result = f.inner;
+if (result !== 42)
+    throw "Error: inner should be 42 but is " + result;
diff --git a/JSTests/stress/async-function-expression-sinking-no-double-allocate.js b/JSTests/stress/async-function-expression-sinking-no-double-allocate.js
new file mode 100644 (file)
index 0000000..8357695
--- /dev/null
@@ -0,0 +1,39 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+var AsyncFunctionPrototype = async function(){}.__proto__;
+
+function call(o) { o.x = 3; }
+noInline(call);
+
+function sink (p, q) {
+    var f = async function() { };
+    if (p) {
+        call(f); // Force allocation of f
+        if (q) {
+            OSRExit();
+        }
+        return f;
+    }
+    return { 'x': 2 };
+}
+noInline(sink);
+
+for (var i = 0; i < 100000; ++i) {
+    var o = sink(true, false);
+    shouldBe(o.__proto__, AsyncFunctionPrototype);
+    if (o.x != 3)
+        throw "Error: expected o.x to be 2 but is " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+if (f.x != 3)
+    throw "Error: expected o.x to be 3 but is " + result;
diff --git a/JSTests/stress/async-function-expression-sinking-osrexit.js b/JSTests/stress/async-function-expression-sinking-osrexit.js
new file mode 100644 (file)
index 0000000..1440da8
--- /dev/null
@@ -0,0 +1,43 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg = "") {
+    if (msg)
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+function shouldBeAsync(expected, promise, msg) {
+    let actual;
+    var hadError = false;
+    promise.then(function(value) { actual = value; },
+                 function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+var AsyncFunctionPrototype = async function(){}.__proto__;
+
+function sink (p, q) {
+    var g = async function (x) { return x; };
+    if (p) { if (q) OSRExit(); return g; }
+    return async function (x) { return x; };
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+    var f = sink(true, false);
+    shouldBe(f.__proto__, AsyncFunctionPrototype);
+    shouldBeAsync(42, f(42));
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+shouldBeAsync(42, f(42));
diff --git a/JSTests/stress/async-function-expression-sinking-put.js b/JSTests/stress/async-function-expression-sinking-put.js
new file mode 100644 (file)
index 0000000..f75cddd
--- /dev/null
@@ -0,0 +1,49 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg = "") {
+    if (msg)
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, promise, msg) {
+    let actual;
+    var hadError = false;
+    promise.then(function(value) { actual = value; },
+                 function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+var AsyncFunctionPrototype = async function(){}.__proto__;
+
+function sink (p, q) {
+    var g = async function(x) { return x; };
+    if (p) { if (q) g.inner = 42; return g; }
+    return async function(x) { return x; };
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+    var f = sink(true, true);
+    shouldBe(f.__proto__, AsyncFunctionPrototype);
+    shouldBeAsync(42, f(42));
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Test the allocation on the implicit inner else branch
+var f = sink(true, false);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+shouldBeAsync(12, f(12));
+
+// Check that the allocation did not sink beyond the property assignment
+var f = sink(true, true);
+shouldBe(f.__proto__, AsyncFunctionPrototype);
+shouldBe(42, f.inner);
index 54ce0cc..b64a9fe 100644 (file)
@@ -1,3 +1,74 @@
+2016-11-14  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] Handle new_async_func / new_async_func_exp in DFG / FTL
+        https://bugs.webkit.org/show_bug.cgi?id=164037
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch introduces new_async_func / new_async_func_exp into DFG and FTL,
+        in much the same capacity that https://trac.webkit.org/changeset/194216 added
+        DFG / FTL support for generators: by adding new DFG nodes (NewAsyncFunction and
+        PhantomNewAsyncFunction), rather than extending the existing NewFunction node type.
+
+        Like NewFunction and PhantomNewFunction, and the Generator variants, allocation of
+        async wrapper functions may be deferred or eliminated during the allocation sinking
+        phase.
+
+        * 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/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGMayExit.cpp:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToPhantomNewFunction):
+        (JSC::DFG::Node::convertToPhantomNewAsyncFunction):
+        (JSC::DFG::Node::hasCellOperand):
+        (JSC::DFG::Node::isFunctionAllocation):
+        (JSC::DFG::Node::isPhantomFunctionAllocation):
+        (JSC::DFG::Node::isPhantomAllocation):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNewFunction):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStoreBarrierInsertionPhase.cpp:
+        * dfg/DFGStructureRegistrationPhase.cpp:
+        (JSC::DFG::StructureRegistrationPhase::run):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::operationPopulateObjectInOSR):
+        (JSC::FTL::operationMaterializeObjectInOSR):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::asyncFunctionPrototype):
+        (JSC::JSGlobalObject::asyncFunctionStructure):
+        (JSC::JSGlobalObject::lazyAsyncFunctionStructure): Deleted.
+        (JSC::JSGlobalObject::asyncFunctionPrototypeConcurrently): Deleted.
+        (JSC::JSGlobalObject::asyncFunctionStructureConcurrently): Deleted.
+
 2016-11-14  Mark Lam  <mark.lam@apple.com>
 
         Some of JSStringView::SafeView methods are not idiomatically safe for JSString to StringView conversions.
index 2247882..ea90ef4 100644 (file)
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+@globalPrivate
 function asyncFunctionResume(generator, sentValue, resumeMode)
 {
     "use strict";
index 8c7e631..5df4da3 100644 (file)
@@ -1970,6 +1970,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case PhantomNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case PhantomDirectArguments:
     case PhantomClonedArguments:
@@ -2014,6 +2015,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
         break;
 
+    case NewAsyncFunction:
+        forNode(node).set(
+            m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
+        break;
+
     case NewFunction:
         forNode(node).set(
             m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure());
index 1a941d1..e7a8314 100644 (file)
@@ -5325,23 +5325,29 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         }
             
         case op_new_func:
-        case op_new_generator_func: {
+        case op_new_generator_func:
+        case op_new_async_func: {
             FunctionExecutable* decl = m_inlineStackTop->m_profiledBlock->functionDecl(currentInstruction[3].u.operand);
             FrozenValue* frozen = m_graph.freezeStrong(decl);
-            NodeType op = (opcodeID == op_new_generator_func) ? NewGeneratorFunction : NewFunction;
+            NodeType op = (opcodeID == op_new_generator_func) ? NewGeneratorFunction :
+                (opcodeID == op_new_async_func) ? NewAsyncFunction : NewFunction;
             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(op, OpInfo(frozen), get(VirtualRegister(currentInstruction[2].u.operand))));
             static_assert(OPCODE_LENGTH(op_new_func) == OPCODE_LENGTH(op_new_generator_func), "The length of op_new_func should eqaual to one of op_new_generator_func");
+            static_assert(OPCODE_LENGTH(op_new_func) == OPCODE_LENGTH(op_new_async_func), "The length of op_new_func should eqaual to one of op_new_async_func");
             NEXT_OPCODE(op_new_func);
         }
 
         case op_new_func_exp:
-        case op_new_generator_func_exp: {
+        case op_new_generator_func_exp:
+        case op_new_async_func_exp: {
             FunctionExecutable* expr = m_inlineStackTop->m_profiledBlock->functionExpr(currentInstruction[3].u.operand);
             FrozenValue* frozen = m_graph.freezeStrong(expr);
-            NodeType op = (opcodeID == op_new_generator_func_exp) ? NewGeneratorFunction : NewFunction;
+            NodeType op = (opcodeID == op_new_generator_func_exp) ? NewGeneratorFunction :
+                (opcodeID == op_new_async_func_exp) ? NewAsyncFunction : NewFunction;
             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(op, OpInfo(frozen), get(VirtualRegister(currentInstruction[2].u.operand))));
-            
+    
             static_assert(OPCODE_LENGTH(op_new_func_exp) == OPCODE_LENGTH(op_new_generator_func_exp), "The length of op_new_func_exp should eqaual to one of op_new_generator_func_exp");
+            static_assert(OPCODE_LENGTH(op_new_func_exp) == OPCODE_LENGTH(op_new_async_func_exp), "The length of op_new_func_exp should eqaual to one of op_new_async_func_exp");
             NEXT_OPCODE(op_new_func_exp);
         }
 
index bfb7019..a8789c7 100644 (file)
@@ -239,6 +239,8 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_new_func_exp:
     case op_new_generator_func:
     case op_new_generator_func_exp:
+    case op_new_async_func:
+    case op_new_async_func_exp:
     case op_set_function_name:
     case op_create_lexical_environment:
     case op_get_parent_scope:
index e12dfa8..456cf8c 100644 (file)
@@ -1273,6 +1273,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case MaterializeNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case MaterializeCreateActivation:
         read(HeapObjectCount);
@@ -1281,6 +1282,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
 
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
         if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
             write(Watchpoint_fire);
         read(HeapObjectCount);
index bd339b8..91fb271 100644 (file)
@@ -62,6 +62,7 @@ bool clobbersExitState(Graph& graph, Node* node)
     case MaterializeNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case MaterializeCreateActivation:
     case CountExecution:
@@ -80,6 +81,7 @@ bool clobbersExitState(Graph& graph, Node* node)
 
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
         // Like above, but with the JSFunction allocation caveat.
         return node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid();
 
index 9e853e3..411881c 100644 (file)
@@ -244,6 +244,7 @@ bool doesGC(Graph& graph, Node* node)
     case PhantomNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case PhantomDirectArguments:
     case PhantomCreateRest:
@@ -288,6 +289,7 @@ bool doesGC(Graph& graph, Node* node)
     case MakeRope:
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
     case NewTypedArray:
     case ThrowStaticError:
     case GetPropertyEnumerator:
index cbf7b0e..b15f00f 100644 (file)
@@ -1435,6 +1435,7 @@ private:
         case PhantomNewObject:
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
         case PhantomCreateActivation:
         case PhantomDirectArguments:
         case PhantomCreateRest:
@@ -1596,7 +1597,8 @@ private:
         case CreateScopedArguments:
         case CreateActivation:
         case NewFunction:
-        case NewGeneratorFunction: {
+        case NewGeneratorFunction:
+        case NewAsyncFunction: {
             fixEdge<CellUse>(node->child1());
             break;
         }
index 80b3374..fbbb1b9 100644 (file)
@@ -106,6 +106,7 @@ ExitMode mayExitImpl(Graph& graph, Node* node, StateType& state)
     case MaterializeNewObject:
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
     case NewStringObject:
     case ToNumber:
         result = ExitsForExceptions;
index 1b21de9..36115de 100644 (file)
@@ -587,7 +587,7 @@ public:
 
     void convertToPhantomNewFunction()
     {
-        ASSERT(m_op == NewFunction || m_op == NewGeneratorFunction);
+        ASSERT(m_op == NewFunction || m_op == NewGeneratorFunction || m_op == NewAsyncFunction);
         m_op = PhantomNewFunction;
         m_flags |= NodeMustGenerate;
         m_opInfo = OpInfoWrapper();
@@ -605,6 +605,16 @@ public:
         children = AdjacencyList();
     }
 
+    void convertToPhantomNewAsyncFunction()
+    {
+        ASSERT(m_op == NewAsyncFunction);
+        m_op = PhantomNewAsyncFunction;
+        m_flags |= NodeMustGenerate;
+        m_opInfo = OpInfoWrapper();
+        m_opInfo2 = OpInfoWrapper();
+        children = AdjacencyList();
+    }
+
     void convertToPhantomCreateActivation()
     {
         ASSERT(m_op == CreateActivation || m_op == MaterializeCreateActivation);
@@ -1498,6 +1508,7 @@ public:
         case OverridesHasInstance:
         case NewFunction:
         case NewGeneratorFunction:
+        case NewAsyncFunction:
         case CreateActivation:
         case MaterializeCreateActivation:
         case NewRegexp:
@@ -1733,6 +1744,7 @@ public:
         switch (op()) {
         case NewFunction:
         case NewGeneratorFunction:
+        case NewAsyncFunction:
             return true;
         default:
             return false;
@@ -1744,6 +1756,7 @@ public:
         switch (op()) {
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
             return true;
         default:
             return false;
@@ -1759,6 +1772,7 @@ public:
         case PhantomClonedArguments:
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
         case PhantomCreateActivation:
             return true;
         default:
index 005af66..bff7fe3 100644 (file)
@@ -307,6 +307,7 @@ namespace JSC { namespace DFG {
     macro(MaterializeNewObject, NodeResultJS | NodeHasVarArgs) \
     macro(PhantomNewFunction, NodeResultJS | NodeMustGenerate) \
     macro(PhantomNewGeneratorFunction, NodeResultJS | NodeMustGenerate) \
+    macro(PhantomNewAsyncFunction, NodeResultJS | NodeMustGenerate) \
     macro(PhantomCreateActivation, NodeResultJS | NodeMustGenerate) \
     macro(MaterializeCreateActivation, NodeResultJS | NodeHasVarArgs) \
     \
@@ -355,6 +356,8 @@ namespace JSC { namespace DFG {
     \
     macro(NewGeneratorFunction, NodeResultJS) \
     \
+    macro(NewAsyncFunction, NodeResultJS) \
+    \
     /* These aren't terminals but always exit */ \
     macro(Throw, NodeMustGenerate) \
     macro(ThrowStaticError, NodeMustGenerate) \
index 81c3061..a1b8393 100644 (file)
@@ -139,7 +139,7 @@ public:
     // once it is escaped if it still has pointers to it in order to
     // replace any use of those pointers by the corresponding
     // materialization
-    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction };
+    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction };
 
     explicit Allocation(Node* identifier = nullptr, Kind kind = Kind::Escaped)
         : m_identifier(identifier)
@@ -233,7 +233,7 @@ public:
 
     bool isFunctionAllocation() const
     {
-        return m_kind == Kind::Function || m_kind == Kind::GeneratorFunction;
+        return m_kind == Kind::Function || m_kind == Kind::GeneratorFunction || m_kind == Kind::AsyncFunction;
     }
 
     bool operator==(const Allocation& other) const
@@ -273,6 +273,10 @@ public:
             out.print("GeneratorFunction");
             break;
 
+        case Kind::AsyncFunction:
+            out.print("AsyncFunction");
+            break;
+
         case Kind::Activation:
             out.print("Activation");
             break;
@@ -832,16 +836,20 @@ private:
             break;
 
         case NewFunction:
-        case NewGeneratorFunction: {
+        case NewGeneratorFunction:
+        case NewAsyncFunction: {
             if (isStillValid(node->castOperand<FunctionExecutable*>()->singletonFunction())) {
                 m_heap.escape(node->child1().node());
                 break;
             }
-            
+
             if (node->op() == NewGeneratorFunction)
                 target = &m_heap.newAllocation(node, Allocation::Kind::GeneratorFunction);
+            else if (node->op() == NewAsyncFunction)
+                target = &m_heap.newAllocation(node, Allocation::Kind::AsyncFunction);
             else
                 target = &m_heap.newAllocation(node, Allocation::Kind::Function);
+
             writes.add(FunctionExecutablePLoc, LazyNode(node->cellOperand()));
             writes.add(FunctionActivationPLoc, LazyNode(node->child1().node()));
             break;
@@ -1444,12 +1452,14 @@ private:
                 OpInfo(set), OpInfo(data), 0, 0);
         }
 
+        case Allocation::Kind::AsyncFunction:
         case Allocation::Kind::GeneratorFunction:
         case Allocation::Kind::Function: {
             FrozenValue* executable = allocation.identifier()->cellOperand();
             
             NodeType nodeType =
-                allocation.kind() == Allocation::Kind::GeneratorFunction ? NewGeneratorFunction : NewFunction;
+                allocation.kind() == Allocation::Kind::GeneratorFunction ? NewGeneratorFunction :
+                allocation.kind() == Allocation::Kind::AsyncFunction ? NewAsyncFunction : NewFunction;
             
             return m_graph.addNode(
                 allocation.identifier()->prediction(), nodeType,
@@ -1791,6 +1801,10 @@ private:
                         node->convertToPhantomNewGeneratorFunction();
                         break;
 
+                    case NewAsyncFunction:
+                        node->convertToPhantomNewAsyncFunction();
+                        break;
+
                     case CreateActivation:
                         node->convertToPhantomCreateActivation();
                         break;
@@ -2047,7 +2061,8 @@ private:
         }
         
         case NewFunction:
-        case NewGeneratorFunction: {
+        case NewGeneratorFunction:
+        case NewAsyncFunction: {
             Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
             ASSERT(locations.size() == 2);
                 
index 0907b9f..db9f31d 100644 (file)
@@ -730,7 +730,8 @@ private:
         case GetSetter:
         case GetCallee:
         case NewFunction:
-        case NewGeneratorFunction: {
+        case NewGeneratorFunction:
+        case NewAsyncFunction: {
             setPrediction(SpecFunction);
             break;
         }
@@ -1007,6 +1008,7 @@ private:
         case PhantomNewObject:
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
         case PhantomCreateActivation:
         case PhantomDirectArguments:
         case PhantomCreateRest:
index 065e665..ae632d3 100644 (file)
@@ -303,6 +303,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case PutToArguments:
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
     case Jump:
     case Branch:
     case Switch:
@@ -351,6 +352,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case PhantomNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case PutHint:
     case CheckStructureImmediate:
index d308b98..3a1d0ff 100644 (file)
@@ -50,6 +50,7 @@
 #include "JITMulGenerator.h"
 #include "JITRightShiftGenerator.h"
 #include "JITSubGenerator.h"
+#include "JSAsyncFunction.h"
 #include "JSCInlines.h"
 #include "JSEnvironmentRecord.h"
 #include "JSFixedArray.h"
@@ -6360,7 +6361,7 @@ template <typename ClassType> void SpeculativeJIT::compileNewFunctionCommon(GPRR
 void SpeculativeJIT::compileNewFunction(Node* node)
 {
     NodeType nodeType = node->op();
-    ASSERT(nodeType == NewFunction || nodeType == NewGeneratorFunction);
+    ASSERT(nodeType == NewFunction || nodeType == NewGeneratorFunction || nodeType == NewAsyncFunction);
     
     SpeculateCellOperand scope(this, node->child1());
     GPRReg scopeGPR = scope.gpr();
@@ -6375,6 +6376,8 @@ void SpeculativeJIT::compileNewFunction(Node* node)
 
         if (nodeType == NewGeneratorFunction)
             callOperation(operationNewGeneratorFunction, resultGPR, scopeGPR, executable);
+        else if (nodeType == NewAsyncFunction)
+            callOperation(operationNewAsyncFunction, resultGPR, scopeGPR, executable);
         else
             callOperation(operationNewFunction, resultGPR, scopeGPR, executable);
         m_jit.exceptionCheck();
@@ -6384,6 +6387,7 @@ void SpeculativeJIT::compileNewFunction(Node* node)
 
     Structure* structure =
         nodeType == NewGeneratorFunction ? m_jit.graph().globalObjectFor(node->origin.semantic)->generatorFunctionStructure() :
+        nodeType == NewAsyncFunction ? m_jit.graph().globalObjectFor(node->origin.semantic)->asyncFunctionStructure() :
         m_jit.graph().globalObjectFor(node->origin.semantic)->functionStructure();
     
     GPRTemporary result(this);
@@ -6408,6 +6412,12 @@ void SpeculativeJIT::compileNewFunction(Node* node)
         addSlowPathGenerator(slowPathCall(slowPath, this, operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
     }
 
+    if (nodeType == NewAsyncFunction) {
+        compileNewFunctionCommon<JSAsyncFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSAsyncFunction::allocationSize(0), executable, JSAsyncFunction::offsetOfScopeChain(), JSAsyncFunction::offsetOfExecutable(), JSAsyncFunction::offsetOfRareData());
+
+        addSlowPathGenerator(slowPathCall(slowPath, this, operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
+    }
+
     cellResult(resultGPR, node);
 }
 
index a4e7c10..657442f 100644 (file)
@@ -5014,6 +5014,7 @@ void SpeculativeJIT::compile(Node* node)
 
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
         compileNewFunction(node);
         break;
 
@@ -5604,6 +5605,7 @@ void SpeculativeJIT::compile(Node* node)
     case PhantomNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case PutHint:
     case CheckStructureImmediate:
index c12143a..22aad77 100644 (file)
@@ -5179,6 +5179,7 @@ void SpeculativeJIT::compile(Node* node)
 
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
         compileNewFunction(node);
         break;
 
@@ -5820,6 +5821,7 @@ void SpeculativeJIT::compile(Node* node)
     case PhantomNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case GetMyArgumentByVal:
     case GetMyArgumentByValOutOfBounds:
index 5f32b4d..60b8f4a 100644 (file)
@@ -317,6 +317,7 @@ private:
             case CreateClonedArguments:
             case NewFunction:
             case NewGeneratorFunction:
+            case NewAsyncFunction:
                 // Nodes that allocate get to set their epoch because for those nodes we know
                 // that they will be the newest object in the heap.
                 m_node->setEpoch(m_currentEpoch);
index bed19f5..0b0be44 100644 (file)
@@ -177,6 +177,9 @@ public:
                 case NewGeneratorFunction:
                     registerStructure(m_graph.globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
                     break;
+                case NewAsyncFunction:
+                    registerStructure(m_graph.globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
+                    break;
 
                 default:
                     break;
index 423301c..733932f 100644 (file)
@@ -529,6 +529,7 @@ private:
                 case PhantomNewObject:
                 case PhantomNewFunction:
                 case PhantomNewGeneratorFunction:
+                case PhantomNewAsyncFunction:
                 case PhantomCreateActivation:
                 case GetMyArgumentByVal:
                 case GetMyArgumentByValOutOfBounds:
@@ -668,6 +669,7 @@ private:
                 case PhantomNewObject:
                 case PhantomNewFunction:
                 case PhantomNewGeneratorFunction:
+                case PhantomNewAsyncFunction:
                 case PhantomCreateActivation:
                 case PhantomDirectArguments:
                 case PhantomCreateRest:
index bce38a6..f99179f 100644 (file)
@@ -119,6 +119,7 @@ inline CapabilityLevel canCompile(Node* node)
     case CreateActivation:
     case NewFunction:
     case NewGeneratorFunction:
+    case NewAsyncFunction:
     case GetClosureVar:
     case PutClosureVar:
     case CreateDirectArguments:
@@ -226,6 +227,7 @@ inline CapabilityLevel canCompile(Node* node)
     case PhantomNewObject:
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomCreateActivation:
     case PutHint:
     case CheckStructureImmediate:
index fd8a90b..9fcfd65 100644 (file)
@@ -710,6 +710,7 @@ private:
             break;
         case NewFunction:
         case NewGeneratorFunction:
+        case NewAsyncFunction:
             compileNewFunction();
             break;
         case CreateDirectArguments:
@@ -1081,6 +1082,7 @@ private:
         case PhantomNewObject:
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
         case PhantomCreateActivation:
         case PhantomDirectArguments:
         case PhantomCreateRest:
@@ -3967,8 +3969,9 @@ private:
     
     void compileNewFunction()
     {
-        ASSERT(m_node->op() == NewFunction || m_node->op() == NewGeneratorFunction);
+        ASSERT(m_node->op() == NewFunction || m_node->op() == NewGeneratorFunction || m_node->op() == NewAsyncFunction);
         bool isGeneratorFunction = m_node->op() == NewGeneratorFunction;
+        bool isAsyncFunction = m_node->op() == NewAsyncFunction;
         
         LValue scope = lowCell(m_node->child1());
         
@@ -3976,6 +3979,7 @@ private:
         if (executable->singletonFunction()->isStillValid()) {
             LValue callResult =
                 isGeneratorFunction ? vmCall(Int64, m_out.operation(operationNewGeneratorFunction), m_callFrame, scope, weakPointer(executable)) :
+                isAsyncFunction ? vmCall(Int64, m_out.operation(operationNewAsyncFunction), m_callFrame, scope, weakPointer(executable)) :
                 vmCall(Int64, m_out.operation(operationNewFunction), m_callFrame, scope, weakPointer(executable));
             setJSValue(callResult);
             return;
@@ -3983,6 +3987,7 @@ private:
         
         Structure* structure =
             isGeneratorFunction ? m_graph.globalObjectFor(m_node->origin.semantic)->generatorFunctionStructure() :
+            isAsyncFunction ? m_graph.globalObjectFor(m_node->origin.semantic)->asyncFunctionStructure() :
             m_graph.globalObjectFor(m_node->origin.semantic)->functionStructure();
         
         LBasicBlock slowPath = m_out.newBlock();
@@ -4016,6 +4021,12 @@ private:
                         locations[0].directGPR(), locations[1].directGPR(),
                         CCallHelpers::TrustedImmPtr(executable));
                 }
+                if (isAsyncFunction) {
+                    return createLazyCallGenerator(
+                        operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint,
+                        locations[0].directGPR(), locations[1].directGPR(),
+                        CCallHelpers::TrustedImmPtr(executable));
+                }
                 return createLazyCallGenerator(
                     operationNewFunctionWithInvalidatedReallocationWatchpoint,
                     locations[0].directGPR(), locations[1].directGPR(),
index 592b3ca..d747524 100644 (file)
@@ -33,6 +33,7 @@
 #include "FTLJITCode.h"
 #include "FTLLazySlowPath.h"
 #include "InlineCallFrame.h"
+#include "JSAsyncFunction.h"
 #include "JSCInlines.h"
 #include "JSGeneratorFunction.h"
 #include "JSLexicalEnvironment.h"
@@ -81,6 +82,7 @@ extern "C" void JIT_OPERATION operationPopulateObjectInOSR(
 
     case PhantomNewFunction:
     case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction:
     case PhantomDirectArguments:
     case PhantomClonedArguments:
     case PhantomCreateRest:
@@ -151,7 +153,8 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(
     }
 
     case PhantomNewFunction:
-    case PhantomNewGeneratorFunction: {
+    case PhantomNewGeneratorFunction:
+    case PhantomNewAsyncFunction: {
         // Figure out what the executable and activation are
         FunctionExecutable* executable = nullptr;
         JSScope* activation = nullptr;
@@ -166,8 +169,10 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(
 
         if (materialization->type() == PhantomNewFunction)
             return JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
-        ASSERT(materialization->type() == PhantomNewGeneratorFunction);
-        return JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
+        else if (materialization->type() == PhantomNewGeneratorFunction)
+            return JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);    
+        ASSERT(materialization->type() == PhantomNewAsyncFunction);
+        return JSAsyncFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
     }
 
     case PhantomCreateActivation: {
index 8aa6c11..1675f82 100644 (file)
@@ -612,7 +612,6 @@ m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, th
     m_throwTypeErrorFunction.set(vm, this, throwTypeErrorFunction);
 
     JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get());
-    m_functionConstructor.set(vm, this, (FunctionConstructor*)functionConstructor);
 
     ArrayConstructor* arrayConstructor = ArrayConstructor::create(vm, this, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get(), m_speciesGetterSetter.get());
     m_arrayConstructor.set(vm, this, arrayConstructor);
@@ -668,15 +667,10 @@ m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->c
     m_generatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_generatorFunctionPrototype.get(), DontEnum | ReadOnly);
     m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->prototype, m_generatorPrototype.get(), DontEnum | ReadOnly);
 
-    m_asyncFunctionStructure.initLater(
-        [](LazyClassStructure::Initializer& init) {
-            AsyncFunctionPrototype* asyncFunctionPrototype = AsyncFunctionPrototype::create(init.vm, AsyncFunctionPrototype::createStructure(init.vm, init.global, init.global->m_functionPrototype.get()));
-            init.setPrototype(asyncFunctionPrototype);
-            init.setStructure(JSAsyncFunction::createStructure(init.vm, init.global, init.prototype));
-            init.setConstructor(PropertyName(nullptr), AsyncFunctionConstructor::create(init.vm, AsyncFunctionConstructor::createStructure(init.vm, init.global, init.global->m_functionConstructor.get()), asyncFunctionPrototype));
-
-            init.global->putDirectWithoutTransition(init.vm, init.vm.propertyNames->builtinNames().asyncFunctionResumePrivateName(), JSFunction::createBuiltinFunction(init.vm, asyncFunctionPrototypeAsyncFunctionResumeCodeGenerator(init.vm), init.global), DontEnum | DontDelete | ReadOnly);
-        });
+    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());
+    m_asyncFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, asyncFunctionConstructor, DontEnum | ReadOnly);
+    m_asyncFunctionStructure.set(vm, this, JSAsyncFunction::createStructure(vm, this, m_asyncFunctionPrototype.get()));
 
     m_objectPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, objectConstructor, DontEnum);
     m_functionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, functionConstructor, DontEnum);
@@ -1175,7 +1169,6 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     thisObject->m_throwTypeErrorGetterSetter.visit(visitor);
     visitor.append(&thisObject->m_throwTypeErrorArgumentsCalleeAndCallerGetterSetter);
     visitor.append(&thisObject->m_moduleLoader);
-    visitor.append(&thisObject->m_functionConstructor);
 
     visitor.append(&thisObject->m_objectPrototype);
     visitor.append(&thisObject->m_functionPrototype);
@@ -1184,7 +1177,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_iteratorPrototype);
     visitor.append(&thisObject->m_generatorFunctionPrototype);
     visitor.append(&thisObject->m_generatorPrototype);
-    thisObject->m_asyncFunctionStructure.visit(visitor);
+    visitor.append(&thisObject->m_asyncFunctionPrototype);
     visitor.append(&thisObject->m_moduleLoaderPrototype);
 
     thisObject->m_debuggerScopeStructure.visit(visitor);
@@ -1220,6 +1213,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_symbolObjectStructure);
     visitor.append(&thisObject->m_regExpStructure);
     visitor.append(&thisObject->m_generatorFunctionStructure);
+    visitor.append(&thisObject->m_asyncFunctionStructure);
     visitor.append(&thisObject->m_iteratorResultObjectStructure);
     visitor.append(&thisObject->m_regExpMatchesArrayStructure);
     visitor.append(&thisObject->m_moduleRecordStructure);
index 6b1bff8..30918cd 100644 (file)
@@ -241,7 +241,6 @@ public:
     LazyProperty<JSGlobalObject, NativeErrorConstructor> m_syntaxErrorConstructor;
     WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
     LazyProperty<JSGlobalObject, NativeErrorConstructor> m_URIErrorConstructor;
-    WriteBarrier<FunctionConstructor> m_functionConstructor;
     WriteBarrier<ObjectConstructor> m_objectConstructor;
     WriteBarrier<ArrayConstructor> m_arrayConstructor;
     WriteBarrier<JSPromiseConstructor> m_promiseConstructor;
@@ -316,7 +315,8 @@ public:
     PropertyOffset m_functionNameOffset;
     WriteBarrier<Structure> m_privateNameStructure;
     WriteBarrier<Structure> m_regExpStructure;
-    LazyClassStructure m_asyncFunctionStructure;
+    WriteBarrier<AsyncFunctionPrototype> m_asyncFunctionPrototype;
+    WriteBarrier<Structure> m_asyncFunctionStructure;
     WriteBarrier<Structure> m_generatorFunctionStructure;
     WriteBarrier<Structure> m_dollarVMStructure;
     WriteBarrier<Structure> m_iteratorResultObjectStructure;
@@ -550,19 +550,7 @@ public:
     IteratorPrototype* iteratorPrototype() const { return m_iteratorPrototype.get(); }
     GeneratorFunctionPrototype* generatorFunctionPrototype() const { return m_generatorFunctionPrototype.get(); }
     GeneratorPrototype* generatorPrototype() const { return m_generatorPrototype.get(); }
-
-    LazyClassStructure& lazyAsyncFunctionStructure()
-    {
-        return m_asyncFunctionStructure;
-    }
-    const LazyClassStructure& lazyAsyncFunctionStructure() const
-    {
-        return m_asyncFunctionStructure;
-    }
-    AsyncFunctionPrototype* asyncFunctionPrototype() const { return reinterpret_cast<AsyncFunctionPrototype*>(lazyAsyncFunctionStructure().prototype(this)); }
-    AsyncFunctionPrototype* asyncFunctionPrototypeConcurrently() const { return reinterpret_cast<AsyncFunctionPrototype*>(lazyAsyncFunctionStructure().prototypeConcurrently()); }
-    Structure* asyncFunctionStructure() const { return lazyAsyncFunctionStructure().get(this); }
-    Structure* asyncFunctionStructureConcurrently() const { return lazyAsyncFunctionStructure().getConcurrently(); }
+    AsyncFunctionPrototype* asyncFunctionPrototype() const { return m_asyncFunctionPrototype.get(); }
 
     Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(this); }
     Structure* withScopeStructure() const { return m_withScopeStructure.get(this); }
@@ -622,6 +610,7 @@ public:
     Structure* mapStructure() const { return m_mapStructure.get(); }
     Structure* regExpStructure() const { return m_regExpStructure.get(); }
     Structure* generatorFunctionStructure() const { return m_generatorFunctionStructure.get(); }
+    Structure* asyncFunctionStructure() const { return m_asyncFunctionStructure.get(); }
     Structure* setStructure() const { return m_setStructure.get(this); }
     Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
     Structure* symbolObjectStructure() const { return m_symbolObjectStructure.get(); }