[JSC] implement runtime for async functions
authorcaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Oct 2016 16:37:38 +0000 (16:37 +0000)
committercaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Oct 2016 16:37:38 +0000 (16:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163760

Reviewed by Yusuke Suzuki.

JSTests:

* stress/async-await-basic.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrow):
(shouldThrowAsync):
(shouldThrowSyntaxError):
(let.AsyncFunction.async):
(async.asyncFunctionForProto):
(Object.getPrototypeOf.async):
(Object.getPrototypeOf.async.method):
(async):
(async.method):
(async.asyncNonConstructorDecl):
(shouldThrow.new.async):
(shouldThrow.new.async.nonConstructor):
(async.asyncDecl):
(async.f):
(MyError):
(async.asyncDeclThrower):
(shouldThrowAsync.async):
(resolveLater):
(rejectLater):
(async.resumeAfterNormal):
(O.async.resumeAfterNormal):
(resumeAfterNormalArrow.async):
(async.resumeAfterThrow):
(O.async.resumeAfterThrow):
(resumeAfterThrowArrow.async):
(catch):
* stress/async-await-module-reserved-word.js: Added.
(shouldThrow):
(SyntaxError.Canstring_appeared_hereawait.checkModuleSyntaxError.String.raw.await):
(checkModuleSyntaxError.String.raw.await):
(checkModuleSyntaxError.String.raw.async.await):
(SyntaxError.Cannot.declare.named):
* stress/async-await-mozilla.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrow):
(shouldThrowAsync):
(assert):
(shouldThrowSyntaxError):
(mozSemantics.async.empty):
(mozSemantics.async.simpleReturn):
(mozSemantics.async.simpleAwait):
(mozSemantics.async.simpleAwaitAsync):
(mozSemantics.async.returnOtherAsync):
(mozSemantics.async.simpleThrower):
(mozSemantics.async.delegatedThrower):
(mozSemantics.async.tryCatch):
(mozSemantics.async.tryCatchThrow):
(mozSemantics.async.wellFinally):
(mozSemantics.async.finallyMayFail):
(mozSemantics.async.embedded.async.inner):
(mozSemantics.async.embedded):
(mozSemantics.async.fib):
(mozSemantics.async.isOdd.async.isEven):
(mozSemantics.async.isOdd):
(mozSemantics.hardcoreFib.async.fib2):
(mozSemantics.namedAsyncExpr.async.simple):
(mozSemantics.async.executionOrder.async.first):
(mozSemantics.async.executionOrder.async.second):
(mozSemantics.async.executionOrder.async.third):
(mozSemantics.async.executionOrder):
(mozSemantics.async.miscellaneous):
(mozSemantics.thrower):
(mozSemantics.async.defaultArgs):
(mozSemantics.shouldThrow):
(mozSemantics):
(mozMethods.X):
(mozMethods.X.prototype.async.getValue):
(mozMethods.X.prototype.setValue):
(mozMethods.X.prototype.async.increment):
(mozMethods.X.prototype.async.getBaseClassName):
(mozMethods.X.async.getStaticValue):
(mozMethods.Y.prototype.async.getBaseClassName):
(mozMethods.Y):
(mozFunctionNameInferrence.async.test):
(mozSyntaxErrors):
* stress/async-await-reserved-word.js: Added.
(assert):
(shouldThrowSyntaxError):
(AsyncFunction.async):
* stress/async_arrow_functions_lexical_arguments_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrowAsync):
(noArgumentsArrow2.async):
* stress/async_arrow_functions_lexical_new.target_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrowAsync):
(C1):
(C2):
(shouldThrowAsync.async):
* stress/async_arrow_functions_lexical_super_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(BaseClass.prototype.baseClassValue):
(BaseClass.prototype.get property):
(BaseClass):
(ChildClass.prototype.asyncSuperProp):
(ChildClass.prototype.asyncSuperProp2):
(ChildClass):
(ChildClass2):
* stress/async_arrow_functions_lexical_this_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(d.y):

Source/JavaScriptCore:

Async functions generate bytecode equivalent to the following, which is
highly dependent on the Generator implementation:

```
// Before translation:
async function asyncfn() {}

// After translation:
function asyncfn() {
    let generator = {
        @generatorNext: function(@generator, @generatorState, @generatorValue, @generatorResumeMode, @generatorFrameState) {
            // Body of async function
        },
        @generatorState: 0,
        @generatorThis: this,
        @generatorFrameState: <frame state>,
    };
    return @asyncFunctionResume(generator, undefined, GeneratorResumeMode::NormalMode);
}
```

Await Expressions are equivalent to non-delegating Yield expressions, and emit identical bytecode.

There are some caveats to be addressed later:

1) the `op_to_this` is always performed, whether it's used or not, like normal generators. (https://bugs.webkit.org/show_bug.cgi?id=151586)

2) for async arrow functions, the home object is always stored on the "body" function, regardless of whether it's needed or
not, for the same reason as #1 (and should also be fixed as part of https://bugs.webkit.org/show_bug.cgi?id=151586)

* CMakeLists.txt:
* DerivedSources.make:
* JavaScriptCore.xcodeproj/project.pbxproj:
* builtins/AsyncFunctionPrototype.js: Added.
(asyncFunctionResume):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::isArrowFunction):
* bytecode/UnlinkedFunctionExecutable.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
(JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
(JSC::BytecodeGenerator::emitNewFunction):
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionNode::emitBytecode):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emitNewFuncCommon):
(JSC::JIT::emit_op_new_async_func):
(JSC::JIT::emitNewFuncExprCommon):
(JSC::JIT::emit_op_new_async_func_exp):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseAsyncFunctionSourceElements):
(JSC::Parser<LexerType>::parseFunctionInfo):
* parser/Parser.h:
(JSC::Scope::setSourceParseMode):
* parser/ParserModes.h:
(JSC::isGeneratorOrAsyncFunctionBodyParseMode):
(JSC::isGeneratorOrAsyncFunctionWrapperParseMode):
* runtime/AsyncFunctionConstructor.cpp: Added.
(JSC::AsyncFunctionConstructor::AsyncFunctionConstructor):
(JSC::AsyncFunctionConstructor::finishCreation):
(JSC::callAsyncFunctionConstructor):
(JSC::constructAsyncFunctionConstructor):
(JSC::AsyncFunctionConstructor::getCallData):
(JSC::AsyncFunctionConstructor::getConstructData):
* runtime/AsyncFunctionConstructor.h: Added.
(JSC::AsyncFunctionConstructor::create):
(JSC::AsyncFunctionConstructor::createStructure):
* runtime/AsyncFunctionPrototype.cpp: Added.
(JSC::AsyncFunctionPrototype::AsyncFunctionPrototype):
(JSC::AsyncFunctionPrototype::finishCreation):
* runtime/AsyncFunctionPrototype.h: Added.
(JSC::AsyncFunctionPrototype::create):
(JSC::AsyncFunctionPrototype::createStructure):
* runtime/FunctionConstructor.cpp:
(JSC::constructFunctionSkippingEvalEnabledCheck):
* runtime/FunctionConstructor.h:
* runtime/JSAsyncFunction.cpp: Added.
(JSC::JSAsyncFunction::JSAsyncFunction):
(JSC::JSAsyncFunction::createImpl):
(JSC::JSAsyncFunction::create):
(JSC::JSAsyncFunction::createWithInvalidatedReallocationWatchpoint):
* runtime/JSAsyncFunction.h: Added.
(JSC::JSAsyncFunction::allocationSize):
(JSC::JSAsyncFunction::createStructure):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::lazyAsyncFunctionStructure):
(JSC::JSGlobalObject::asyncFunctionPrototype):
(JSC::JSGlobalObject::asyncFunctionPrototypeConcurrently):
(JSC::JSGlobalObject::asyncFunctionStructure):
(JSC::JSGlobalObject::asyncFunctionStructureConcurrently):

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

45 files changed:
JSTests/ChangeLog
JSTests/asyncFunctionTests.yaml [new file with mode: 0644]
JSTests/stress/async-arrow-functions-lexical-arguments-binding.js [new file with mode: 0644]
JSTests/stress/async-arrow-functions-lexical-new.target-binding.js [new file with mode: 0644]
JSTests/stress/async-arrow-functions-lexical-super-binding.js [new file with mode: 0644]
JSTests/stress/async-arrow-functions-lexical-this-binding.js [new file with mode: 0644]
JSTests/stress/async-await-basic.js [new file with mode: 0644]
JSTests/stress/async-await-module-reserved-word.js [new file with mode: 0644]
JSTests/stress/async-await-mozilla.js [new file with mode: 0644]
JSTests/stress/async-await-reserved-word.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js [new file with mode: 0644]
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserModes.h
Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/FunctionConstructor.cpp
Source/JavaScriptCore/runtime/FunctionConstructor.h
Source/JavaScriptCore/runtime/FunctionPrototype.cpp
Source/JavaScriptCore/runtime/JSAsyncFunction.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSAsyncFunction.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h

index 9cf70a7..27d5cce 100644 (file)
@@ -1,3 +1,120 @@
+2016-10-20  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] implement runtime for async functions
+        https://bugs.webkit.org/show_bug.cgi?id=163760
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/async-await-basic.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrow):
+        (shouldThrowAsync):
+        (shouldThrowSyntaxError):
+        (let.AsyncFunction.async):
+        (async.asyncFunctionForProto):
+        (Object.getPrototypeOf.async):
+        (Object.getPrototypeOf.async.method):
+        (async):
+        (async.method):
+        (async.asyncNonConstructorDecl):
+        (shouldThrow.new.async):
+        (shouldThrow.new.async.nonConstructor):
+        (async.asyncDecl):
+        (async.f):
+        (MyError):
+        (async.asyncDeclThrower):
+        (shouldThrowAsync.async):
+        (resolveLater):
+        (rejectLater):
+        (async.resumeAfterNormal):
+        (O.async.resumeAfterNormal):
+        (resumeAfterNormalArrow.async):
+        (async.resumeAfterThrow):
+        (O.async.resumeAfterThrow):
+        (resumeAfterThrowArrow.async):
+        (catch):
+        * stress/async-await-module-reserved-word.js: Added.
+        (shouldThrow):
+        (SyntaxError.Canstring_appeared_hereawait.checkModuleSyntaxError.String.raw.await):
+        (checkModuleSyntaxError.String.raw.await):
+        (checkModuleSyntaxError.String.raw.async.await):
+        (SyntaxError.Cannot.declare.named):
+        * stress/async-await-mozilla.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrow):
+        (shouldThrowAsync):
+        (assert):
+        (shouldThrowSyntaxError):
+        (mozSemantics.async.empty):
+        (mozSemantics.async.simpleReturn):
+        (mozSemantics.async.simpleAwait):
+        (mozSemantics.async.simpleAwaitAsync):
+        (mozSemantics.async.returnOtherAsync):
+        (mozSemantics.async.simpleThrower):
+        (mozSemantics.async.delegatedThrower):
+        (mozSemantics.async.tryCatch):
+        (mozSemantics.async.tryCatchThrow):
+        (mozSemantics.async.wellFinally):
+        (mozSemantics.async.finallyMayFail):
+        (mozSemantics.async.embedded.async.inner):
+        (mozSemantics.async.embedded):
+        (mozSemantics.async.fib):
+        (mozSemantics.async.isOdd.async.isEven):
+        (mozSemantics.async.isOdd):
+        (mozSemantics.hardcoreFib.async.fib2):
+        (mozSemantics.namedAsyncExpr.async.simple):
+        (mozSemantics.async.executionOrder.async.first):
+        (mozSemantics.async.executionOrder.async.second):
+        (mozSemantics.async.executionOrder.async.third):
+        (mozSemantics.async.executionOrder):
+        (mozSemantics.async.miscellaneous):
+        (mozSemantics.thrower):
+        (mozSemantics.async.defaultArgs):
+        (mozSemantics.shouldThrow):
+        (mozSemantics):
+        (mozMethods.X):
+        (mozMethods.X.prototype.async.getValue):
+        (mozMethods.X.prototype.setValue):
+        (mozMethods.X.prototype.async.increment):
+        (mozMethods.X.prototype.async.getBaseClassName):
+        (mozMethods.X.async.getStaticValue):
+        (mozMethods.Y.prototype.async.getBaseClassName):
+        (mozMethods.Y):
+        (mozFunctionNameInferrence.async.test):
+        (mozSyntaxErrors):
+        * stress/async-await-reserved-word.js: Added.
+        (assert):
+        (shouldThrowSyntaxError):
+        (AsyncFunction.async):
+        * stress/async_arrow_functions_lexical_arguments_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrowAsync):
+        (noArgumentsArrow2.async):
+        * stress/async_arrow_functions_lexical_new.target_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrowAsync):
+        (C1):
+        (C2):
+        (shouldThrowAsync.async):
+        * stress/async_arrow_functions_lexical_super_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (BaseClass.prototype.baseClassValue):
+        (BaseClass.prototype.get property):
+        (BaseClass):
+        (ChildClass.prototype.asyncSuperProp):
+        (ChildClass.prototype.asyncSuperProp2):
+        (ChildClass):
+        (ChildClass2):
+        * stress/async_arrow_functions_lexical_this_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (d.y):
+
 2016-10-28  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         Skip 2 JS stress tests on memory limited devices
diff --git a/JSTests/asyncFunctionTests.yaml b/JSTests/asyncFunctionTests.yaml
new file mode 100644 (file)
index 0000000..5fb78be
--- /dev/null
@@ -0,0 +1,392 @@
+# Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Provided to simplify running async function tests. To be removed once async
+# functions are no longer behind a feature flag.
+
+---
+- path: stress/async-arrow-functions-lexical-super-binding.js
+  cmd: runDefault
+- path: stress/async-arrow-functions-lexical-arguments-binding.js
+  cmd: runDefault
+- path: stress/async-arrow-functions-lexical-this-binding.js
+  cmd: runDefault
+- path: stress/async-arrow-functions-lexical-new.target-binding.js
+  cmd: runDefault
+- path: stress/async-await-basic.js
+  cmd: runDefault
+- path: stress/async-await-mozilla.js
+  cmd: runDefault
+- path: stress/async-await-syntax.js
+  cmd: runDefault
+- path: stress/async-await-module-reserved-word.js
+  cmd: runDefault
+- path: stress/async-await-reserved-word.js
+  cmd: runDefault
+
+# Test262
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-construct.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-construct.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-is-extensible.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-is-extensible.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-is-subclass.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-is-subclass.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-length.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-length.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-name.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-name.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-prototype.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction-prototype.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunction.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunctionPrototype-is-extensible.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunctionPrototype-is-extensible.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunctionPrototype-prototype.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunctionPrototype-prototype.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/AsyncFunctionPrototype-to-string.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], []
+- path: test262/test/built-ins/AsyncFunction/AsyncFunctionPrototype-to-string.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/instance-construct.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/instance-construct.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/instance-has-name.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], []
+- path: test262/test/built-ins/AsyncFunction/instance-has-name.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/instance-length.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], []
+- path: test262/test/built-ins/AsyncFunction/instance-length.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js", "../../../harness/propertyHelper.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/instance-prototype-property.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/instance-prototype-property.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/AsyncFunction/is-not-a-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], []
+- path: test262/test/built-ins/AsyncFunction/is-not-a-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../harness/assert.js", "../../../harness/sta.js"], [:strict]
+
+# FIXME: CreateDynamicFunction() is broken in JSC, need to parse formal parameters and body separately.
+- path: test262/test/built-ins/Function/prototype/toString/AsyncFunction.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
+- path: test262/test/built-ins/Function/prototype/toString/AsyncFunction.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
+
+# FIXME: These tests require F.p.toString revisions (https://tc39.github.io/Function-prototype-toString-revision/)
+- path: test262/test/built-ins/Function/prototype/toString/async-function-declaration.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
+- path: test262/test/built-ins/Function/prototype/toString/async-function-declaration.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/Function/prototype/toString/async-function-expression.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
+- path: test262/test/built-ins/Function/prototype/toString/async-function-expression.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
+- path: test262/test/built-ins/Function/prototype/toString/async-method.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], []
+- path: test262/test/built-ins/Function/prototype/toString/async-method.js
+  cmd: runTest262 :fail, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js"], [:strict]
+
+- path: test262/test/language/expressions/async-arrow-function/arrow-returns-promise.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/async-arrow-function/arrow-returns-promise.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-NSPL-with-USD.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-NSPL-with-USD.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-arguments-in-formal-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-await-in-formals-default.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-await-in-formals-default.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-await-in-formals.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-await-in-formals.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-body-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-body-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-body-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-body-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-duplicate-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-eval-in-formal-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-formals-body-duplicate.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-formals-body-duplicate.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-formals-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-formals-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-formals-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-arrow-function/early-errors-arrow-formals-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-NSPL-with-USD.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-NSPL-with-USD.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-binding-identifier-arguments.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-binding-identifier-eval.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-body-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-body-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-body-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-body-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-eval-in-formal-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-formals-body-duplicate.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-formals-body-duplicate.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-formals-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-formals-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-formals-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-formals-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/early-errors-expression-not-simple-assignment-target.js
+  cmd: runTest262 :normal, "ReferenceError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/early-errors-expression-not-simple-assignment-target.js
+  cmd: runTest262 :normal, "ReferenceError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/expression-returns-promise.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/expression-returns-promise.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/async-function/syntax-expression-is-PrimaryExpression.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/async-function/syntax-expression-is-PrimaryExpression.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-BindingIdentifier-in-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-BindingIdentifier-in-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-BindingIdentifier-nested.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-BindingIdentifier-nested.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-awaits-thenable-not-callable.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/await/await-awaits-thenable-not-callable.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/expressions/await/await-awaits-thenables-that-throw.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/await/await-awaits-thenables-that-throw.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/expressions/await/await-awaits-thenables.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/await/await-awaits-thenables.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/expressions/await/await-in-function.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-in-function.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-in-generator.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-in-generator.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-in-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-in-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-in-nested-function.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-in-nested-function.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-in-nested-generator.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-in-nested-generator.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/await-throws-rejections.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/await-throws-rejections.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+
+#FIXME: JSC always throws these ReferenceErrors at runtime rather than at parse time.
+- path: test262/test/language/expressions/await/early-errors-await-not-simple-assignment-target.js
+  cmd: runTest262 :fail, "ReferenceError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/early-errors-await-not-simple-assignment-target.js
+  cmd: runTest262 :fail, "ReferenceError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+
+- path: test262/test/language/expressions/await/no-operand.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/expressions/await/no-operand.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/expressions/await/syntax-await-has-UnaryExpression-with-MultiplicativeExpression.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/await/syntax-await-has-UnaryExpression-with-MultiplicativeExpression.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/expressions/await/syntax-await-has-UnaryExpression.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/await/syntax-await-has-UnaryExpression.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+
+- path: test262/test/language/expressions/object/method-definition/async-super-call-body.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/object/method-definition/async-super-call-body.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/expressions/object/method-definition/async-super-call-param.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/expressions/object/method-definition/async-super-call-param.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
+
+- path: test262/test/language/statements/async-function/declaration-returns-promise.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/declaration-returns-promise.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-NSPL-with-USD.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-NSPL-with-USD.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-arguments-in-formal-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-await-in-formals-default.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-await-in-formals-default.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-await-in-formals.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-await-in-formals.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-binding-identifier-arguments.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-binding-identifier-eval.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-body-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-body-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-body-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-body-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-duplicate-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-eval-in-formal-parameters.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-formals-body-duplicate.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-formals-body-duplicate.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-formals-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-formals-contains-super-call.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-declaration-formals-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-declaration-formals-contains-super-property.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/early-errors-no-async-generator.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/early-errors-no-async-generator.js
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/evaluation-body-that-returns-after-await.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-returns-after-await.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-returns.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-returns.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-throws-after-await.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-throws-after-await.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-throws.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-body-that-throws.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/evaluation-body.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/evaluation-body.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/evaluation-default-that-throws.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-default-that-throws.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/evaluation-mapped-arguments.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-this-value-global.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-this-value-passed.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-this-value-passed.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/evaluation-unmapped-arguments.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/evaluation-unmapped-arguments.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/async-function/syntax-declaration-line-terminators-allowed.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/syntax-declaration-line-terminators-allowed.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/syntax-declaration-no-line-terminator.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+- path: test262/test/language/statements/async-function/syntax-declaration-no-line-terminator.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+- path: test262/test/language/statements/async-function/syntax-declaration.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/async-function/syntax-declaration.js
+  cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
+
+- path: test262/test/language/statements/class/definition/methods-async-super-call-body.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/class/definition/methods-async-super-call-body.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
+- path: test262/test/language/statements/class/definition/methods-async-super-call-param.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:async]
+- path: test262/test/language/statements/class/definition/methods-async-super-call-param.js
+  cmd: runTest262 :normal, "NoException", ["../../../../../harness/assert.js", "../../../../../harness/sta.js", "../../../../../harness/doneprintHandle.js"], [:strict, :async]
diff --git a/JSTests/stress/async-arrow-functions-lexical-arguments-binding.js b/JSTests/stress/async-arrow-functions-lexical-arguments-binding.js
new file mode 100644 (file)
index 0000000..15e02a3
--- /dev/null
@@ -0,0 +1,53 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = "";
+    else
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+function shouldThrowAsync(run, errorType, message) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (!hadError)
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
+    if (!(actual instanceof errorType))
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but threw '" + actual + "'");
+    if (message !== void 0 && actual.message !== message)
+        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
+}
+
+var noArgumentsArrow = async () => await [...arguments];
+shouldThrowAsync(() => noArgumentsArrow(1, 2, 3), ReferenceError);
+var noArgumentsArrow2 = async () => { return await [...arguments]; }
+shouldThrowAsync(() => noArgumentsArrow2(1, 2, 3), ReferenceError);
+
+shouldBeAsync("[1,2,3]", () => (function() { return (async () => JSON.stringify([...arguments]))(); })(1, 2, 3));
+shouldBeAsync("[4,5,6]", () => (function() { return (async () => { return JSON.stringify([...await arguments]) })(); })(4, 5, 6));
+
+(function testArgumentsBinding() {
+    var argsBinding;
+    var promise = (function() { argsBinding = arguments; return (async() => arguments)() })(1, 2, 3);
+    shouldBeAsync(argsBinding, () => promise);
+})();
diff --git a/JSTests/stress/async-arrow-functions-lexical-new.target-binding.js b/JSTests/stress/async-arrow-functions-lexical-new.target-binding.js
new file mode 100644 (file)
index 0000000..426a398
--- /dev/null
@@ -0,0 +1,55 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = "";
+    else
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+function shouldThrowAsync(run, errorType, message) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (!hadError)
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
+    if (!(actual instanceof errorType))
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but threw '" + actual + "'");
+    if (message !== void 0 && actual.message !== message)
+        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
+}
+
+function C1() {
+    return async () => await new.target;
+}
+
+function C2() {
+    return async () => { return await new.target };
+}
+
+shouldBeAsync(C1, new C1());
+shouldBeAsync(undefined, C1());
+shouldBeAsync(C2, new C2());
+shouldBeAsync(undefined, C2());
+
+shouldThrowAsync(async () => await new.target, ReferenceError);
+shouldThrowAsync(async () => { return await new.target; }, ReferenceError);
diff --git a/JSTests/stress/async-arrow-functions-lexical-super-binding.js b/JSTests/stress/async-arrow-functions-lexical-super-binding.js
new file mode 100644 (file)
index 0000000..08bf0f9
--- /dev/null
@@ -0,0 +1,55 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = "";
+    else
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+class BaseClass {
+    baseClassValue() {
+        return "BaseClassValue";
+    }
+    get property() {
+        return "test!";
+    }
+}
+
+class ChildClass extends BaseClass {
+    asyncSuperProp() {
+        return async x => super.baseClassValue();
+    }
+    asyncSuperProp2() {
+        return async x => { return super.baseClassValue(); }
+    }
+}
+
+// FIXME: super bindings in async arrow functions are broken
+shouldBeAsync("BaseClassValue", new ChildClass().asyncSuperProp());
+shouldBeAsync("BaseClassValue", new ChildClass().asyncSuperProp2());
+
+class ChildClass2 extends BaseClass {
+    constructor() {
+        return async (self = super()) => self.baseClassValue() + ' ' + super.property;
+    }
+}
+
+shouldBeAsync("BaseClassValue test!", new ChildClass2());
diff --git a/JSTests/stress/async-arrow-functions-lexical-this-binding.js b/JSTests/stress/async-arrow-functions-lexical-this-binding.js
new file mode 100644 (file)
index 0000000..72afa11
--- /dev/null
@@ -0,0 +1,30 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = "";
+    else
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+var d = ({ x : "bar", y : function() { return async z => this.x + z; }}).y();
+var e = { x : "baz", y : d };
+
+shouldBeAsync("barley", () => d("ley"));
+shouldBeAsync("barley", () => e.y("ley"));
diff --git a/JSTests/stress/async-await-basic.js b/JSTests/stress/async-await-basic.js
new file mode 100644 (file)
index 0000000..e8f2065
--- /dev/null
@@ -0,0 +1,299 @@
+// 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, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+function shouldThrow(run, errorType, message) {
+    let actual;
+    var hadError = false;
+
+    try {
+        actual = run();
+    } catch (e) {
+        hadError = true;
+        actual = e;
+    }
+
+    if (!hadError)
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
+    if (!(actual instanceof errorType))
+        throw new Error("Expeced " + run + "() to throw " + errorType.name + " , but threw '" + actual + "'");
+    if (message !== void 0 && actual.message !== message)
+        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
+}
+
+function shouldThrowAsync(run, errorType, message) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (!hadError)
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
+    if (!(actual instanceof errorType))
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but threw '" + actual + "'");
+    if (message !== void 0 && actual.message !== message)
+        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
+}
+
+function shouldThrowSyntaxError(str, message) {
+    try {
+        eval(str);
+        throw new Error("Expected `" + str + "` to throw a SyntaxError, but did not throw.")
+    } catch (e) {
+        if (e.constructor !== SyntaxError)
+            throw new Error("Expected `" + str + "` to throw a SyntaxError, but threw '" + e + "'");
+        if (message !== void 0 && e.message !== message)
+            throw new Error("Expected `" + str + "` to throw SyntaxError: '" + message + "', but threw '" + e + "'");
+    }
+}
+
+// Do not install `AsyncFunction` constructor on global object
+shouldBe(undefined, this.AsyncFunction);
+let AsyncFunction = (async function() {}).constructor;
+
+// Let functionPrototype be the intrinsic object %AsyncFunctionPrototype%.
+async function asyncFunctionForProto() {}
+shouldBe(AsyncFunction.prototype, Object.getPrototypeOf(asyncFunctionForProto));
+shouldBe(AsyncFunction.prototype, Object.getPrototypeOf(async function() {}));
+shouldBe(AsyncFunction.prototype, Object.getPrototypeOf(async () => {}));
+shouldBe(AsyncFunction.prototype, Object.getPrototypeOf({ async method() {} }.method));
+
+// FIXME: AsyncFunction constructor should build functions with correct prototype.
+// shouldBe(AsyncFunction.prototype, Object.getPrototypeOf(AsyncFunction()));
+
+// AsyncFunctionCreate does not produce an object with a Prototype
+shouldBe(undefined, asyncFunctionForProto.prototype);
+shouldBe(false, asyncFunctionForProto.hasOwnProperty("prototype"));
+shouldBe(undefined, (async function() {}).prototype);
+shouldBe(false, (async function() {}).hasOwnProperty("prototype"));
+shouldBe(undefined, (async() => {}).prototype);
+shouldBe(false, (async() => {}).hasOwnProperty("prototype"));
+shouldBe(undefined, ({ async method() {} }).method.prototype);
+shouldBe(false, ({ async method() {} }).method.hasOwnProperty("prototype"));
+shouldBe(undefined, AsyncFunction().prototype);
+shouldBe(false, AsyncFunction().hasOwnProperty("prototype"));
+
+// AsyncFunction.prototype[ @@toStringTag ]
+var descriptor = Object.getOwnPropertyDescriptor(AsyncFunction.prototype, Symbol.toStringTag);
+shouldBe("AsyncFunction", descriptor.value);
+shouldBe(false, descriptor.enumerable);
+shouldBe(false, descriptor.writable);
+shouldBe(true, descriptor.configurable);
+
+shouldBe(1, AsyncFunction.length);
+
+// Let F be ! FunctionAllocate(functionPrototype, Strict, "non-constructor")
+async function asyncNonConstructorDecl() {}
+shouldThrow(() => new asyncNonConstructorDecl(), TypeError);
+shouldThrow(() => new (async function() {}), TypeError);
+shouldThrow(() => new ({ async nonConstructor() {} }).nonConstructor(), TypeError);
+shouldThrow(() => new (() => "not a constructor!"), TypeError);
+shouldThrow(() => new (AsyncFunction()), TypeError);
+
+// Normal completion
+async function asyncDecl() { return "test"; }
+shouldBeAsync("test", asyncDecl);
+shouldBeAsync("test2", async function() { return "test2"; });
+shouldBeAsync("test3", async () => "test3");
+shouldBeAsync("test4", () => ({ async f() { return "test4"; } }).f());
+
+class MyError extends Error {};
+
+// Throw completion
+async function asyncDeclThrower(e) { throw new MyError(e); }
+shouldThrowAsync(() => asyncDeclThrower("boom!"), MyError, "boom!");
+shouldThrowAsync(() => (async function(e) { throw new MyError(e); })("boom!!!"), MyError, "boom!!!");
+shouldThrowAsync(() => (async e => { throw new MyError(e) })("boom!!"), MyError, "boom!!");
+shouldThrowAsync(() => ({ async thrower(e) { throw new MyError(e); } }).thrower("boom!!!!"), MyError, "boom!!!!");
+
+function resolveLater(value) { return Promise.resolve(value); }
+function rejectLater(error) { return Promise.reject(error); }
+
+// Resume after Normal completion
+var log = [];
+async function resumeAfterNormal(value) {
+    log.push("start:" + value);
+    value = await resolveLater(value + 1);
+    log.push("resume:" + value);
+    value = await resolveLater(value + 1);
+    log.push("resume:" + value);
+    return value + 1;
+}
+
+shouldBeAsync(4, () => resumeAfterNormal(1));
+shouldBe("start:1 resume:2 resume:3", log.join(" "));
+
+var O = {
+    async resumeAfterNormal(value) {
+        log.push("start:" + value);
+        value = await resolveLater(value + 1);
+        log.push("resume:" + value);
+        value = await resolveLater(value + 1);
+        log.push("resume:" + value);
+        return value + 1;
+    }
+};
+log = [];
+shouldBeAsync(5, () => O.resumeAfterNormal(2));
+shouldBe("start:2 resume:3 resume:4", log.join(" "));
+
+var resumeAfterNormalArrow = async (value) => {
+    log.push("start:" + value);
+    value = await resolveLater(value + 1);
+    log.push("resume:" + value);
+    value = await resolveLater(value + 1);
+    log.push("resume:" + value);
+    return value + 1;
+};
+log = [];
+shouldBeAsync(6, () => resumeAfterNormalArrow(3));
+shouldBe("start:3 resume:4 resume:5", log.join(" "));
+
+var resumeAfterNormalEval = AsyncFunction("value", `
+    log.push("start:" + value);
+    value = await resolveLater(value + 1);
+    log.push("resume:" + value);
+    value = await resolveLater(value + 1);
+    log.push("resume:" + value);
+    return value + 1;
+`);
+log = [];
+shouldBeAsync(7, () => resumeAfterNormalEval(4));
+shouldBe("start:4 resume:5 resume:6", log.join(" "));
+
+// Resume after Throw completion
+async function resumeAfterThrow(value) {
+    log.push("start:" + value);
+    try {
+        value = await rejectLater("throw1");
+    } catch (e) {
+        log.push("resume:" + e);
+    }
+    try {
+        value = await rejectLater("throw2");
+    } catch (e) {
+        log.push("resume:" + e);
+    }
+    return value + 1;
+}
+
+log = [];
+shouldBeAsync(2, () => resumeAfterThrow(1));
+shouldBe("start:1 resume:throw1 resume:throw2", log.join(" "));
+
+var O = {
+    async resumeAfterThrow(value) {
+        log.push("start:" + value);
+        try {
+            value = await rejectLater("throw1");
+        } catch (e) {
+            log.push("resume:" + e);
+        }
+        try {
+            value = await rejectLater("throw2");
+        } catch (e) {
+            log.push("resume:" + e);
+        }
+        return value + 1;
+    }
+}
+log = [];
+shouldBeAsync(3, () => O.resumeAfterThrow(2));
+shouldBe("start:2 resume:throw1 resume:throw2", log.join(" "));
+
+var resumeAfterThrowArrow = async (value) => {
+    log.push("start:" + value);
+    try {
+        value = await rejectLater("throw1");
+    } catch (e) {
+        log.push("resume:" + e);
+    }
+    try {
+        value = await rejectLater("throw2");
+    } catch (e) {
+        log.push("resume:" + e);
+    }
+    return value + 1;
+};
+log = [];
+shouldBeAsync(4, () => resumeAfterThrowArrow(3));
+shouldBe("start:3 resume:throw1 resume:throw2", log.join(" "));
+
+var resumeAfterThrowEval = AsyncFunction("value", `
+    log.push("start:" + value);
+    try {
+        value = await rejectLater("throw1");
+    } catch (e) {
+        log.push("resume:" + e);
+    }
+    try {
+        value = await rejectLater("throw2");
+    } catch (e) {
+        log.push("resume:" + e);
+    }
+    return value + 1;
+`);
+log = [];
+shouldBeAsync(5, () => resumeAfterThrowEval(4));
+shouldBe("start:4 resume:throw1 resume:throw2", log.join(" "));
+
+// MethoodDefinition SyntaxErrors
+shouldThrowSyntaxError("var obj = { async foo : true };", "Unexpected token ':'. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async foo = true };", "Unexpected token '='. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async foo , bar };", "Unexpected token ','. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async foo }", "Unexpected token '}'. Expected a parenthesis for argument list.");
+
+shouldThrowSyntaxError("var obj = { async 0 : true };", "Unexpected token ':'. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async 0 = true };", "Unexpected token '='. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async 0 , bar };", "Unexpected token ','. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async 0 }", "Unexpected token '}'. Expected a parenthesis for argument list.");
+
+shouldThrowSyntaxError("var obj = { async 'foo' : true };", "Unexpected token ':'. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async 'foo' = true };", "Unexpected token '='. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async 'foo' , bar };", "Unexpected token ','. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async 'foo' }", "Unexpected token '}'. Expected a parenthesis for argument list.");
+
+shouldThrowSyntaxError("var obj = { async ['foo'] : true };", "Unexpected token ':'. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async ['foo'] = true };", "Unexpected token '='. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async ['foo'] , bar };", "Unexpected token ','. Expected a parenthesis for argument list.");
+shouldThrowSyntaxError("var obj = { async ['foo'] }", "Unexpected token '}'. Expected a parenthesis for argument list.");
+
+shouldThrowSyntaxError("class C { async foo : true };", "Unexpected token ':'. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async foo = true };", "Unexpected token '='. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async foo , bar };", "Unexpected token ','. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async foo }", "Unexpected token '}'. Expected an opening '(' before a async method's parameter list.");
+
+shouldThrowSyntaxError("class C { async 0 : true };", "Unexpected token ':'. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async 0 = true };", "Unexpected token '='. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async 0 , bar };", "Unexpected token ','. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async 0 }", "Unexpected token '}'. Expected an opening '(' before a async method's parameter list.");
+
+shouldThrowSyntaxError("class C { async 'foo' : true };", "Unexpected token ':'. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async 'foo' = true };", "Unexpected token '='. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async 'foo' , bar };", "Unexpected token ','. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async 'foo' }", "Unexpected token '}'. Expected an opening '(' before a async method's parameter list.");
+
+shouldThrowSyntaxError("class C { async ['foo'] : true };", "Unexpected token ':'. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async ['foo'] = true };", "Unexpected token '='. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async ['foo'] , bar };", "Unexpected token ','. Expected an opening '(' before a async method's parameter list.");
+shouldThrowSyntaxError("class C { async ['foo'] }", "Unexpected token '}'. Expected an opening '(' before a async method's parameter list.");
diff --git a/JSTests/stress/async-await-module-reserved-word.js b/JSTests/stress/async-await-module-reserved-word.js
new file mode 100644 (file)
index 0000000..08b24fe
--- /dev/null
@@ -0,0 +1,72 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+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 checkModuleSyntaxError(source, errorMessage) {
+    shouldThrow(() => checkModuleSyntax(source), errorMessage);
+}
+
+checkModuleSyntaxError(String.raw`
+var await;
+`, `SyntaxError: Can't use 'await' as a variable name in a module.:2`);
+checkModuleSyntaxError(`
+export var await;
+`, `SyntaxError: Can't use 'await' as a variable name in a module.:2`);
+checkModuleSyntaxError(String.raw`
+let await;
+`, `SyntaxError: Can't use 'await' as a lexical variable name in a module.:2`);
+checkModuleSyntaxError(String.raw`
+export let await;
+`, `SyntaxError: Can't use 'await' as a lexical variable name in a module.:2`);
+checkModuleSyntaxError(String.raw`
+const await = 1
+`, `SyntaxError: Can't use 'await' as a lexical variable name in a module.:2`);
+checkModuleSyntaxError(String.raw`
+export const await = 1
+`, `SyntaxError: Can't use 'await' as a lexical variable name in a module.:2`);
+
+checkModuleSyntaxError(String.raw`
+function await() {}
+`, `SyntaxError: Cannot declare function named 'await' in a module.:2`);
+checkModuleSyntaxError(String.raw`
+function* await() {}
+`, `SyntaxError: Cannot declare function named 'await' in a module.:2`);
+checkModuleSyntaxError(String.raw`
+async function await() {}
+`, `SyntaxError: Cannot declare function named 'await' in a module.:2`);
+
+checkModuleSyntaxError(String.raw`
+import {await} from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
+checkModuleSyntaxError(String.raw`
+import {foo as await} from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
+checkModuleSyntaxError(String.raw`
+import * as await from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
+checkModuleSyntaxError(String.raw`
+import await, {x, y, z} from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
+checkModuleSyntaxError(String.raw`
+import await, {x, y, z,} from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
+checkModuleSyntaxError(String.raw`
+import await from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
+checkModuleSyntaxError(String.raw`
+import await, * as foo from 'foo';
+`, `SyntaxError: Cannot use 'await' as an imported binding name.:2`);
diff --git a/JSTests/stress/async-await-mozilla.js b/JSTests/stress/async-await-mozilla.js
new file mode 100644 (file)
index 0000000..0c5d6b9
--- /dev/null
@@ -0,0 +1,305 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://moz.org/MPL/2.0/. */
+
+// 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, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+    if (hadError)
+        throw actual;
+    shouldBe(expected, actual, msg);
+}
+
+function shouldThrow(run, errorType, message) {
+    let actual;
+    var hadError = false;
+    try {
+        actual = run();
+    } catch (e) {
+        hadError = true;
+        actual = e;
+    }
+    if (!hadError)
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
+    if (!(actual instanceof errorType))
+        throw new Error("Expeced " + run + "() to throw " + errorType.name + " , but threw '" + actual + "'");
+    if (message !== void 0 && actual.message !== message)
+        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
+}
+
+function shouldThrowAsync(run, errorType, message) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+    if (!hadError)
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but did not throw.");
+    if (!(actual instanceof errorType))
+        throw new Error("Expected " + run + "() to throw " + errorType.name + ", but threw '" + actual + "'");
+    if (message !== void 0 && actual.message !== message)
+        throw new Error("Expected " + run + "() to throw '" + message + "', but threw '" + actual.message + "'");
+}
+
+function assert(cond, msg = "") {
+    if (!cond)
+        throw new Error(msg);
+}
+
+function shouldThrowSyntaxError(str, message) {
+    var hadError = false;
+    try {
+        eval(str);
+    } catch (e) {
+        if (e instanceof SyntaxError) {
+            hadError = true;
+            if (typeof message === "string")
+                assert(e.message === message, "Expected '" + message + "' but threw '" + e.message + "'");
+        }
+    }
+    assert(hadError, "Did not throw syntax error");
+}
+
+// semantics.js
+(function mozSemantics() {
+
+async function empty() {
+}
+
+async function simpleReturn() {
+    return 1;
+}
+
+async function simpleAwait() {
+    var result = await 2;
+    return result;
+}
+
+async function simpleAwaitAsync() {
+    var result = await simpleReturn();
+    return 2 + result;
+}
+
+async function returnOtherAsync() {
+    return 1 + await simpleAwaitAsync();
+}
+
+async function simpleThrower() {
+    throw new Error();
+}
+
+async function delegatedThrower() {
+    var val = await simpleThrower();
+    return val;
+}
+
+async function tryCatch() {
+    try {
+        await delegatedThrower();
+        return 'FAILED';
+    } catch (_) {
+        return 5;
+    }
+}
+
+async function tryCatchThrow() {
+    try {
+        await delegatedThrower();
+        return 'FAILED';
+    } catch (_) {
+        return delegatedThrower();
+    }
+}
+
+async function wellFinally() {
+    try {
+        await delegatedThrower();
+    } catch (_) {
+        return 'FAILED';
+    } finally {
+        return 6;
+    }
+}
+
+async function finallyMayFail() {
+    try {
+        await delegatedThrower();
+    } catch (_) {
+        return 5;
+    } finally {
+        return delegatedThrower();
+    }
+}
+
+async function embedded() {
+    async function inner() {
+        return 7;
+    }
+    return await inner();
+}
+
+// recursion, it works!
+async function fib(n) {
+    return (n == 0 || n == 1) ? n : await fib(n - 1) + await fib(n - 2);
+}
+
+// mutual recursion
+async function isOdd(n) {
+    async function isEven(n) {
+        return n === 0 || await isOdd(n - 1);
+    }
+    return n !== 0 && await isEven(n - 1);
+}
+
+// recursion, take three!
+var hardcoreFib = async function fib2(n) {
+    return (n == 0 || n == 1) ? n : await fib2(n - 1) + await fib2(n - 2);
+}
+
+var asyncExpr = async function() {
+    return 10;
+}
+
+var namedAsyncExpr = async function simple() {
+    return 11;
+}
+
+async function executionOrder() {
+    var value = 0;
+    async function first() {
+        return (value = value === 0 ? 1 : value);
+    }
+    async function second() {
+        return (value = value === 0 ? 2 : value);
+    }
+    async function third() {
+        return (value = value === 0 ? 3 : value);
+    }
+    return await first() + await second() + await third() + 6;
+}
+
+async function miscellaneous() {
+    if (arguments.length === 3 &&
+        arguments.callee.name === "miscellaneous")
+        return 14;
+}
+
+function thrower() {
+    throw 15;
+}
+
+async function defaultArgs(arg = thrower()) {
+}
+
+// Async functions are not constructible
+shouldThrow(() => {
+    async function Person() {
+    }
+    new Person();
+}, TypeError);
+
+shouldBeAsync(undefined, empty);
+shouldBeAsync(1, simpleReturn);
+shouldBeAsync(2, simpleAwait);
+shouldBeAsync(3, simpleAwaitAsync);
+shouldBeAsync(4, returnOtherAsync);
+shouldThrowAsync(simpleThrower, Error);
+shouldBeAsync(5, tryCatch);
+shouldBeAsync(6, wellFinally);
+shouldThrowAsync(finallyMayFail, Error);
+shouldBeAsync(7, embedded);
+shouldBeAsync(8, () => fib(6));
+shouldBeAsync(9, executionOrder);
+shouldBeAsync(10, asyncExpr);
+shouldBeAsync(11, namedAsyncExpr);
+shouldBeAsync(12, () => isOdd(12).then(v => v ? "oops" : 12));
+shouldBeAsync(13, () => hardcoreFib(7));
+shouldBeAsync(14, () => miscellaneous(1, 2, 3));
+shouldBeAsync(15, () => defaultArgs().catch(e => e));
+
+})();
+
+// methods.js
+(function mozMethods() {
+
+class X {
+    constructor() {
+        this.value = 42;
+    }
+    async getValue() {
+        return this.value;
+    }
+    setValue(value) {
+        this.value = value;
+    }
+    async increment() {
+        var value = await this.getValue();
+        this.setValue(value + 1);
+        return this.getValue();
+    }
+    async getBaseClassName() {
+        return 'X';
+    }
+    static async getStaticValue() {
+        return 44;
+    }
+}
+
+class Y extends X {
+    async getBaseClassName() {
+        return super.getBaseClassName();
+    }
+}
+
+var objLiteral = {
+    async get() {
+        return 45;
+    },
+    someStuff: 5
+};
+
+var x = new X();
+var y = new Y();
+
+shouldBeAsync(42, () => x.getValue());
+shouldBeAsync(43, () => x.increment());
+shouldBeAsync(44, () => X.getStaticValue());
+shouldBeAsync(45, () => objLiteral.get());
+shouldBeAsync('X', () => y.getBaseClassName());
+
+})();
+
+(function mozFunctionNameInferrence() {
+
+async function test() { }
+
+var anon = async function() { }
+
+shouldBe("test", test.name);
+shouldBe("anon", anon.name);
+
+})();
+
+(function mozSyntaxErrors() {
+
+shouldThrowSyntaxError("'use strict'; async function eval() {}");
+shouldThrowSyntaxError("'use strict'; async function arguments() {}");
+shouldThrowSyntaxError("async function a(k = super.prop) { }");
+shouldThrowSyntaxError("async function a() { super.prop(); }");
+shouldThrowSyntaxError("async function a() { super(); }");
+shouldThrowSyntaxError("async function a(k = await 3) {}");
+
+})();
\ No newline at end of file
diff --git a/JSTests/stress/async-await-reserved-word.js b/JSTests/stress/async-await-reserved-word.js
new file mode 100644 (file)
index 0000000..c8e1d33
--- /dev/null
@@ -0,0 +1,166 @@
+// This test requires ENABLE_ES2017_ASYNCFUNCTION_SYNTAX to be enabled at build time.
+//@ skip
+
+function assert(cond, msg = "") {
+    if (!cond)
+        throw new Error(msg);
+}
+noInline(assert);
+
+function shouldThrowSyntaxError(str, message) {
+    var hadError = false;
+    try {
+        eval(str);
+    } catch (e) {
+        if (e instanceof SyntaxError) {
+            hadError = true;
+            if (typeof message === "string")
+                assert(e.message === message, "Expected '" + message + "' but threw '" + e.message + "'");
+        }
+    }
+    assert(hadError, "Did not throw syntax error");
+}
+noInline(shouldThrowSyntaxError);
+
+var AsyncFunction = (async function() {}).constructor;
+
+// AsyncFunctionExpression
+shouldThrowSyntaxError("(async function() { var await; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("(async function() { var [await] = []; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("(async function() { var [...await] = []; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("(async function() { var {await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("(async function() { var {isAsync: await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("(async function() { var {isAsync: await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("(async function() { let await; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { let [await] = []; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { let [...await] = []; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { let {await} = {}; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { let {isAsync: await} = {}; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { let {isAsync: await} = {}; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { const await; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { const [await] = []; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { const [...await] = []; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { const {await} = {}; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { const {isAsync: await} = {}; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { const {isAsync: await} = {}; })", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("(async function() { function await() {} })", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("(async function() { async function await() {} })", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("(async function(await) {})", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("(async function f([await]) {})", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("(async function f([...await]) {})", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("(async function f(...await) {})", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("(async function f({await}) {})", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("(async function f({isAsync: await}) {})", "Can't use 'await' as a parameter name in an async function.");
+
+// AsyncFunctionDeclaration
+shouldThrowSyntaxError("async function f() { var await; }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("async function f() { var [await] = []; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("async function f() { var [...await] = []; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("async function f() { var {await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("async function f() { var {isAsync: await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("async function f() { var {isAsync: await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("async function f() { let await; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { let [await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { let [...await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { let {await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { let {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { let {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { const await; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { const [await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { const [...await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { const {await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { const {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { const {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("async function f() { function await() {} }", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("async function f() { async function await() {} }", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("async function f(await) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("async function f([await]) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("async function f([...await]) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("async function f(...await) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("async function f({await}) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("async function f({isAsync: await}) {}", "Can't use 'await' as a parameter name in an async function.");
+
+// AsyncArrowFunction
+shouldThrowSyntaxError("var f = async () => { var await; }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { var [await] = []; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { var [...await] = []; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { var {await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { var {isAsync: await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { var {isAsync: await} = {}; })", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { let await; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { let [await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { let [...await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { let {await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { let {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { let {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { const await; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { const [await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { const [...await] = []; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { const {await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { const {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { const {isAsync: await} = {}; }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var f = async () => { function await() {} }", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("var f = async () => { async function await() {} }", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("var f = async (await) => {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var f = async ([await]) => {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var f = async ([...await]) => {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var f = async (...await) => {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var f = async ({await}) => {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var f = async ({isAsync: await}) => {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var f = async await => {}", "Can't use 'await' as a parameter name in an async function.");
+
+// AsyncMethod
+shouldThrowSyntaxError("var O = { async f() { var await; } }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { var [await] = []; } }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { var [...await] = []; } }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { var {await} = {}; } }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { var {isAsync: await} = {}; } }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { var {isAsync: await} = {}; } }", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { let await; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { let [await] = []; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { let [...await] = []; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { let {await} = {}; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { let {isAsync: await} = {}; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { let {isAsync: await} = {}; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { const await; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { const [await] = []; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { const [...await] = []; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { const {await} = {}; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { const {isAsync: await} = {}; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { const {isAsync: await} = {}; } }", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("var O = { async f() { function await() {} }", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("var O = { async f() { async function await() {} } }", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("var O = { async f(await) {} } ", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var O = { async f([await]) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var O = { async f([...await]) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var O = { async f(...await) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var O = { async f({await}) {}", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("var O = { async f({isAsync: await}) {}", "Can't use 'await' as a parameter name in an async function.");
+
+// AsyncFunction constructor
+shouldThrowSyntaxError("AsyncFunction('var await;')", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('var [await] = [];')", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('var [...await] = [];')", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('var {await} = {};')", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('var {isAsync: await} = {};')", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('var {isAsync: await} = {};')", "Can't use 'await' as a variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('let await;')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('let [await] = [];')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('let [...await] = [];')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('let {await} = {};')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('let {isAsync: await} = {};')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('let {isAsync: await} = {};')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('const await;')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('const [await] = [];')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('const [...await] = [];')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('const {await} = {};')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('const {isAsync: await} = {};')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('const {isAsync: await} = {};')", "Can't use 'await' as a lexical variable name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('function await() {}')", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("AsyncFunction('async function await() {}')", "Cannot declare function named 'await' in an async function.");
+shouldThrowSyntaxError("AsyncFunction('await', '')", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('[await]', '')", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('[...await]', '')", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('...await', '')", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('{await}', '')", "Can't use 'await' as a parameter name in an async function.");
+shouldThrowSyntaxError("AsyncFunction('{isAsync: await}', '')", "Can't use 'await' as a parameter name in an async function.");
index 81560a3..c095346 100644 (file)
@@ -638,6 +638,8 @@ set(JavaScriptCore_SOURCES
     runtime/ArrayConventions.cpp
     runtime/ArrayIteratorPrototype.cpp
     runtime/ArrayPrototype.cpp
+    runtime/AsyncFunctionConstructor.cpp
+    runtime/AsyncFunctionPrototype.cpp
     runtime/BasicBlockLocation.cpp
     runtime/BooleanConstructor.cpp
     runtime/BooleanObject.cpp
@@ -714,6 +716,7 @@ set(JavaScriptCore_SOURCES
     runtime/JSArrayBufferConstructor.cpp
     runtime/JSArrayBufferPrototype.cpp
     runtime/JSArrayBufferView.cpp
+    runtime/JSAsyncFunction.cpp
     runtime/JSBoundFunction.cpp
     runtime/JSCJSValue.cpp
     runtime/JSCallee.cpp
@@ -1298,6 +1301,7 @@ set(JavaScriptCore_BUILTINS_SOURCES
     ${JAVASCRIPTCORE_DIR}/builtins/ArrayConstructor.js
     ${JAVASCRIPTCORE_DIR}/builtins/ArrayIteratorPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/ArrayPrototype.js
+    ${JAVASCRIPTCORE_DIR}/builtins/AsyncFunctionPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/DatePrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/FunctionPrototype.js
     ${JAVASCRIPTCORE_DIR}/builtins/GeneratorPrototype.js
index 78e8c3a..397bbed 100644 (file)
@@ -1,3 +1,121 @@
+2016-10-20  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] implement runtime for async functions
+        https://bugs.webkit.org/show_bug.cgi?id=163760
+
+        Reviewed by Yusuke Suzuki.
+
+        Async functions generate bytecode equivalent to the following, which is
+        highly dependent on the Generator implementation:
+        
+        ```
+        // Before translation:
+        async function asyncfn() {}
+
+        // After translation:
+        function asyncfn() {
+            let generator = {
+                @generatorNext: function(@generator, @generatorState, @generatorValue, @generatorResumeMode, @generatorFrameState) {
+                    // Body of async function
+                },
+                @generatorState: 0,
+                @generatorThis: this,
+                @generatorFrameState: <frame state>,
+            };
+            return @asyncFunctionResume(generator, undefined, GeneratorResumeMode::NormalMode);
+        }
+        ```
+
+        Await Expressions are equivalent to non-delegating Yield expressions, and emit identical bytecode.
+
+        There are some caveats to be addressed later:
+        
+        1) the `op_to_this` is always performed, whether it's used or not, like normal generators. (https://bugs.webkit.org/show_bug.cgi?id=151586)
+        
+        2) for async arrow functions, the home object is always stored on the "body" function, regardless of whether it's needed or
+        not, for the same reason as #1 (and should also be fixed as part of https://bugs.webkit.org/show_bug.cgi?id=151586)
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * builtins/AsyncFunctionPrototype.js: Added.
+        (asyncFunctionResume):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::isArrowFunction):
+        * bytecode/UnlinkedFunctionExecutable.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
+        (JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
+        (JSC::BytecodeGenerator::emitNewFunction):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::FunctionNode::emitBytecode):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emitNewFuncCommon):
+        (JSC::JIT::emit_op_new_async_func):
+        (JSC::JIT::emitNewFuncExprCommon):
+        (JSC::JIT::emit_op_new_async_func_exp):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseInner):
+        (JSC::Parser<LexerType>::parseAsyncFunctionSourceElements):
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        * parser/Parser.h:
+        (JSC::Scope::setSourceParseMode):
+        * parser/ParserModes.h:
+        (JSC::isGeneratorOrAsyncFunctionBodyParseMode):
+        (JSC::isGeneratorOrAsyncFunctionWrapperParseMode):
+        * runtime/AsyncFunctionConstructor.cpp: Added.
+        (JSC::AsyncFunctionConstructor::AsyncFunctionConstructor):
+        (JSC::AsyncFunctionConstructor::finishCreation):
+        (JSC::callAsyncFunctionConstructor):
+        (JSC::constructAsyncFunctionConstructor):
+        (JSC::AsyncFunctionConstructor::getCallData):
+        (JSC::AsyncFunctionConstructor::getConstructData):
+        * runtime/AsyncFunctionConstructor.h: Added.
+        (JSC::AsyncFunctionConstructor::create):
+        (JSC::AsyncFunctionConstructor::createStructure):
+        * runtime/AsyncFunctionPrototype.cpp: Added.
+        (JSC::AsyncFunctionPrototype::AsyncFunctionPrototype):
+        (JSC::AsyncFunctionPrototype::finishCreation):
+        * runtime/AsyncFunctionPrototype.h: Added.
+        (JSC::AsyncFunctionPrototype::create):
+        (JSC::AsyncFunctionPrototype::createStructure):
+        * runtime/FunctionConstructor.cpp:
+        (JSC::constructFunctionSkippingEvalEnabledCheck):
+        * runtime/FunctionConstructor.h:
+        * runtime/JSAsyncFunction.cpp: Added.
+        (JSC::JSAsyncFunction::JSAsyncFunction):
+        (JSC::JSAsyncFunction::createImpl):
+        (JSC::JSAsyncFunction::create):
+        (JSC::JSAsyncFunction::createWithInvalidatedReallocationWatchpoint):
+        * runtime/JSAsyncFunction.h: Added.
+        (JSC::JSAsyncFunction::allocationSize):
+        (JSC::JSAsyncFunction::createStructure):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::lazyAsyncFunctionStructure):
+        (JSC::JSGlobalObject::asyncFunctionPrototype):
+        (JSC::JSGlobalObject::asyncFunctionPrototypeConcurrently):
+        (JSC::JSGlobalObject::asyncFunctionStructure):
+        (JSC::JSGlobalObject::asyncFunctionStructureConcurrently):
+
 2016-10-27  Mark Lam  <mark.lam@apple.com>
 
         JSFunction::put() should not allow caching of lazily reified properties.
index 4c59736..343205f 100644 (file)
@@ -89,6 +89,7 @@ JavaScriptCore_BUILTINS_SOURCES = \
     $(JavaScriptCore)/builtins/ArrayConstructor.js \
     $(JavaScriptCore)/builtins/ArrayIteratorPrototype.js \
     $(JavaScriptCore)/builtins/ArrayPrototype.js \
+    $(JavaScriptCore)/builtins/AsyncFunctionPrototype.js \
     $(JavaScriptCore)/builtins/DatePrototype.js \
     $(JavaScriptCore)/builtins/FunctionPrototype.js \
     $(JavaScriptCore)/builtins/GeneratorPrototype.js \
index e5d1e31..0caea23 100644 (file)
                53FD04D31D7AB277003287D3 /* WasmCallingConvention.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */; };
                53FD04D41D7AB291003287D3 /* WasmCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */; };
                5C4E8E961DBEBE620036F1FC /* JSONParseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */; };
+               5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */; };
+               5B70CFDF1DB69E6600EC23F9 /* JSAsyncFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */; };
+               5B70CFE01DB69E6600EC23F9 /* AsyncFunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */; };
+               5B70CFE11DB69E6600EC23F9 /* AsyncFunctionPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFDB1DB69E5C00EC23F9 /* AsyncFunctionPrototype.cpp */; };
+               5B70CFE21DB69E6600EC23F9 /* AsyncFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */; };
+               5B70CFE31DB69E6600EC23F9 /* AsyncFunctionConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */; };
                5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; };
                5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
                5DBB1525131D0BD70056AD36 /* minidom.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 1412110D0A48788700480255 /* minidom.js */; };
                53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmCallingConvention.h; sourceTree = "<group>"; };
                5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONParseTest.cpp; path = API/tests/JSONParseTest.cpp; sourceTree = "<group>"; };
                5C4E8E951DBEBDA20036F1FC /* JSONParseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONParseTest.h; path = API/tests/JSONParseTest.h; sourceTree = "<group>"; };
+               5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAsyncFunction.h; sourceTree = "<group>"; };
+               5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAsyncFunction.cpp; sourceTree = "<group>"; };
+               5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionPrototype.h; sourceTree = "<group>"; };
+               5B70CFDB1DB69E5C00EC23F9 /* AsyncFunctionPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionPrototype.cpp; sourceTree = "<group>"; };
+               5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionConstructor.h; sourceTree = "<group>"; };
+               5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionConstructor.cpp; sourceTree = "<group>"; };
+               5B8243041DB7AA4900EA6384 /* AsyncFunctionPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = AsyncFunctionPrototype.js; sourceTree = "<group>"; };
                5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.dylib; sourceTree = "<absolute>"; };
                5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = "<group>"; };
                5DDDF44614FEE72200B4FB4D /* LLIntDesiredOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntDesiredOffsets.h; path = LLIntOffsets/LLIntDesiredOffsets.h; sourceTree = BUILT_PRODUCTS_DIR; };
                                F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */,
                                F692A84E0255597D01FF60F7 /* ArrayPrototype.h */,
                                0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */,
+                               5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */,
+                               5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */,
+                               5B70CFDB1DB69E5C00EC23F9 /* AsyncFunctionPrototype.cpp */,
+                               5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */,
                                0F38D2A01D44196600680499 /* AuxiliaryBarrier.h */,
                                0F38D2A11D44196600680499 /* AuxiliaryBarrierInlines.h */,
                                52678F8C1A031009006A306D /* BasicBlockLocation.cpp */,
                                0F2B66BB17B6B5AB00A7AE3F /* JSArrayBufferView.h */,
                                0F2B66BC17B6B5AB00A7AE3F /* JSArrayBufferViewInlines.h */,
                                539FB8B91C99DA7C00940FA1 /* JSArrayInlines.h */,
+                               5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */,
+                               5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */,
                                86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */,
                                86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */,
                                657CF45619BF6662004ACBF2 /* JSCallee.cpp */,
                                A7D801A01880D66E0026C39B /* ArrayPrototype.js */,
                                7CF9BC581B65D9A3009DB1EF /* ArrayConstructor.js */,
                                7CF9BC591B65D9A3009DB1EF /* ArrayIteratorPrototype.js */,
+                               5B8243041DB7AA4900EA6384 /* AsyncFunctionPrototype.js */,
                                DE26E9061CB5DD9600D2BE82 /* BuiltinExecutableCreator.cpp */,
                                DE26E9021CB5DD0500D2BE82 /* BuiltinExecutableCreator.h */,
                                A7D801A11880D66E0026C39B /* BuiltinExecutables.cpp */,
                                DC3D2B0A1D34316200BA918C /* HeapCell.h in Headers */,
                                0FC3CCFC19ADA410006AC72A /* DFGBlockMap.h in Headers */,
                                0FC3CCFD19ADA410006AC72A /* DFGBlockMapInlines.h in Headers */,
+                               5B70CFE21DB69E6600EC23F9 /* AsyncFunctionConstructor.h in Headers */,
                                0FC3CCFE19ADA410006AC72A /* DFGBlockSet.h in Headers */,
                                0FBF158D19B7A53100695DD0 /* DFGBlockSetInlines.h in Headers */,
                                0FC3CD0019ADA410006AC72A /* DFGBlockWorklist.h in Headers */,
                                7C184E1B17BEDBD3007CB63A /* JSPromise.h in Headers */,
                                7C184E2317BEE240007CB63A /* JSPromiseConstructor.h in Headers */,
                                996B731E1BDA08EF00331B84 /* JSPromiseConstructor.lut.h in Headers */,
+                               5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */,
                                7C008CDB187124BB00955C24 /* JSPromiseDeferred.h in Headers */,
                                7C184E1F17BEE22E007CB63A /* JSPromisePrototype.h in Headers */,
                                996B731F1BDA08EF00331B84 /* JSPromisePrototype.lut.h in Headers */,
                                BC18C43F0E16F5CD00B34460 /* Nodes.h in Headers */,
                                99E45A2818A1B2590026D88F /* NondeterministicInput.h in Headers */,
                                BC18C4410E16F5CD00B34460 /* NumberConstructor.h in Headers */,
+                               5B70CFE01DB69E6600EC23F9 /* AsyncFunctionPrototype.h in Headers */,
                                BC18C4420E16F5CD00B34460 /* NumberConstructor.lut.h in Headers */,
                                BC18C4430E16F5CD00B34460 /* NumberObject.h in Headers */,
                                BC18C4440E16F5CD00B34460 /* NumberPrototype.h in Headers */,
                                A55714BF1CD804A40004D2C6 /* ConsoleObject.cpp in Sources */,
                                0FEC85251BDACDAC0080FF74 /* B3PatchpointSpecial.cpp in Sources */,
                                0FEC85271BDACDAC0080FF74 /* B3PatchpointValue.cpp in Sources */,
+                               5B70CFE31DB69E6600EC23F9 /* AsyncFunctionConstructor.cpp in Sources */,
                                0FEC85291BDACDAC0080FF74 /* B3PhaseScope.cpp in Sources */,
                                0FEC852B1BDACDAC0080FF74 /* B3Procedure.cpp in Sources */,
                                43422A621C158E6A00E2EB98 /* B3ConstFloatValue.cpp in Sources */,
                                0F5513A81D5A68CD00C32BD8 /* FreeList.cpp in Sources */,
                                FE99B24A1C24C3D700C82159 /* JITNegGenerator.cpp in Sources */,
                                86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */,
+                               5B70CFE11DB69E6600EC23F9 /* AsyncFunctionPrototype.cpp in Sources */,
                                A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */,
                                0FB415841D78FB4C00DF8D09 /* ArrayConventions.cpp in Sources */,
                                0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */,
                                148F21B7107EC5470042EC2C /* Nodes.cpp in Sources */,
                                DC69AA661CF7A1F200C6272F /* MatchResult.cpp in Sources */,
                                E3963CEE1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp in Sources */,
+                               5B70CFDF1DB69E6600EC23F9 /* JSAsyncFunction.cpp in Sources */,
                                655EB29B10CE2581001A990E /* NodesCodegen.cpp in Sources */,
                                6546F5211A32B313006F07D5 /* NullGetterFunction.cpp in Sources */,
                                E322E5A21DA64439006E7709 /* DFGDOMJITPatchpointParams.cpp in Sources */,
diff --git a/Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js b/Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js
new file mode 100644 (file)
index 0000000..2247882
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+function asyncFunctionResume(generator, sentValue, resumeMode)
+{
+    "use strict";
+    let state = generator.@generatorState;
+    let value = @undefined;
+
+    if (state === @GeneratorStateCompleted || (resumeMode !== @GeneratorResumeModeNormal && resumeMode !== @GeneratorResumeModeThrow))
+        @throwTypeError("Async function illegally resumed");
+
+    try {
+        generator.@generatorState = @GeneratorStateExecuting;
+        value = generator.@generatorNext.@call(generator.@generatorThis, generator, state, sentValue, resumeMode, generator.@generatorFrame);
+        if (generator.@generatorState === @GeneratorStateExecuting) {
+            generator.@generatorState = @GeneratorStateCompleted;
+            return @Promise.@resolve(value);
+        }
+    } catch (error) {
+        generator.@generatorState = @GeneratorStateCompleted;
+        return @Promise.@reject(error);
+    }
+
+    return @Promise.@resolve(value).@then(
+        function(value) { return @asyncFunctionResume(generator, value, @GeneratorResumeModeNormal); },
+        function(error) { return @asyncFunctionResume(generator, error, @GeneratorResumeModeThrow); });
+}
index 576de40..84ae3bd 100644 (file)
             { "name" : "op_new_func_exp", "length" : 4 },
             { "name" : "op_new_generator_func", "length" : 4 },
             { "name" : "op_new_generator_func_exp", "length" : 4 },
+            { "name" : "op_new_async_func", "length" : 4 },
+            { "name" : "op_new_async_func_exp", "length" : 4 },
             { "name" : "op_set_function_name", "length" : 3 },
             { "name" : "op_call", "length" : 9 },
             { "name" : "op_tail_call", "length" : 9 },
index d973bcf..162db28 100644 (file)
@@ -164,6 +164,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_get_enumerable_length:
     case op_new_func_exp:
     case op_new_generator_func_exp:
+    case op_new_async_func_exp:
     case op_to_index_string:
     case op_create_lexical_environment:
     case op_resolve_scope:
@@ -196,6 +197,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_unsigned:
     case op_new_func:
     case op_new_generator_func:
+    case op_new_async_func:
     case op_get_parent_scope:
     case op_create_scoped_arguments:
     case op_create_rest:
@@ -388,6 +390,8 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     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_call_varargs:
     case op_tail_call_varargs:
     case op_tail_call_forward_arguments:
index 5b7483c..f799990 100644 (file)
@@ -1464,6 +1464,14 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
             break;
         }
+        case op_new_async_func: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int f0 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "new_async_func");
+            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+            break;
+        }
         case op_new_func_exp: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
@@ -1480,6 +1488,14 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
             break;
         }
+        case op_new_async_func_exp: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int f0 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "new_async_func_exp");
+            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+            break;
+        }
         case op_set_function_name: {
             int funcReg = (++it)->u.operand;
             int nameReg = (++it)->u.operand;
index 25a357b..e918a93 100644 (file)
@@ -122,7 +122,7 @@ public:
     bool isStrictMode() const { return m_isStrictMode; }
     bool usesEval() const { return m_usesEval; }
     SourceParseMode parseMode() const { return m_parseMode; }
-    bool isArrowFunction() const { return m_parseMode == SourceParseMode::ArrowFunctionMode; }
+    bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
     DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
     EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); }
     bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
index bac4054..6f558cf 100644 (file)
@@ -132,7 +132,7 @@ public:
     bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
     const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
     
-    bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
+    bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
 
     JSC::DerivedContextType derivedContextType() const {return static_cast<JSC::DerivedContextType>(m_derivedContextType); }
 
index f7e1031..d149551 100644 (file)
@@ -158,7 +158,7 @@ ParserError BytecodeGenerator::generate()
     }
     
 
-    if (m_codeBlock->parseMode() == SourceParseMode::GeneratorBodyMode)
+    if (isGeneratorOrAsyncFunctionBodyParseMode(m_codeBlock->parseMode()))
         performGeneratorification(m_codeBlock.get(), m_instructions, m_generatorFrameSymbolTable.get(), m_generatorFrameSymbolTableIndex);
 
     m_codeBlock->setInstructions(std::make_unique<UnlinkedInstructionStream>(m_instructions));
@@ -268,15 +268,15 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
     bool needsArguments = (functionNode->usesArguments() || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction()));
 
-    if (parseMode == SourceParseMode::GeneratorBodyMode) {
-        // Generator never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
+    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) {
+        // Generator and AsyncFunction never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
         needsArguments = false;
 
-        // Generator uses the var scope to save and resume its variables. So the lexical scope is always instantiated.
+        // Generator and AsyncFunction uses the var scope to save and resume its variables. So the lexical scope is always instantiated.
         shouldCaptureSomeOfTheThings = true;
     }
 
-    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode && needsArguments) {
+    if (isGeneratorOrAsyncFunctionWrapperParseMode(parseMode) && needsArguments) {
         // Generator does not provide "arguments". Instead, wrapping GeneratorFunction provides "arguments".
         // This is because arguments of a generator should be evaluated before starting it.
         // To workaround it, we evaluate these arguments as arguments of a wrapping generator function, and reference it from a generator.
@@ -320,13 +320,14 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
 
     emitEnter();
 
-    if (parseMode == SourceParseMode::GeneratorBodyMode)
+    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
         m_generatorRegister = &m_parameters[1];
 
     allocateAndEmitScope();
 
     if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode())) {
         ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
+        ASSERT(!isAsyncFunctionBodyParseMode(parseMode));
         bool isDynamicScope = functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode());
         bool isFunctionNameCaptured = captures(functionNode->ident().impl());
         bool markAsCaptured = isDynamicScope || isFunctionNameCaptured;
@@ -505,7 +506,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             }
         }
 
-        bool shouldCreateArgumensVariable = !haveParameterNamedArguments && !m_codeBlock->isArrowFunction();
+        bool shouldCreateArgumensVariable = !haveParameterNamedArguments
+            && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(m_codeBlock->parseMode());
         shouldCreateArgumentsVariableInParameterScope = shouldCreateArgumensVariable && !isSimpleParameterList;
         // Do not create arguments variable in case of Arrow function. Value will be loaded from parent scope
         if (shouldCreateArgumensVariable && !shouldCreateArgumentsVariableInParameterScope) {
@@ -549,6 +551,29 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
         break;
     }
 
+    case SourceParseMode::AsyncArrowFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncFunctionMode: {
+        ASSERT(!isConstructor());
+        ASSERT(constructorKind() == ConstructorKind::None);
+        m_generatorRegister = addVar();
+
+        if (parseMode != SourceParseMode::AsyncArrowFunctionMode) {
+            // FIXME: Emit to_this only when AsyncFunctionBody uses it.
+            // https://bugs.webkit.org/show_bug.cgi?id=151586
+            m_codeBlock->addPropertyAccessInstruction(instructions().size());
+            emitOpcode(op_to_this);
+            instructions().append(kill(&m_thisRegister));
+            instructions().append(0);
+            instructions().append(0);
+        }
+
+        emitNewObject(m_generatorRegister);
+        break;
+    }
+
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
     case SourceParseMode::GeneratorBodyMode: {
         // |this| is already filled correctly before here.
         emitLoad(m_newTargetRegister, jsUndefined());
@@ -608,7 +633,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
 
     // We need load |super| & |this| for arrow function before initializeDefaultParameterValuesAndSetupFunctionScopeStack
     // if we have default parameter expression. Because |super| & |this| values can be used there
-    if (SourceParseMode::ArrowFunctionMode == parseMode && !isSimpleParameterList) {
+    if ((SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(parseMode) && !isSimpleParameterList) || parseMode == SourceParseMode::AsyncArrowFunctionBodyMode) {
         if (functionNode->usesThis() || functionNode->usesSuperProperty())
             emitLoadThisFromArrowFunctionLexicalEnvironment();
 
@@ -627,12 +652,46 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
     // because a function's default parameter ExpressionNodes will use temporary registers.
     pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ);
+
+    TryData* tryFormalParametersData = nullptr;
+    if (isAsyncFunctionWrapperParseMode(parseMode) && !isSimpleParameterList) {
+        RefPtr<Label> tryFormalParametersStart = emitLabel(newLabel().get());
+        tryFormalParametersData = pushTry(tryFormalParametersStart.get());
+    }
+
     initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, isSimpleParameterList, functionNode, functionSymbolTable, symbolTableConstantIndex, captures, shouldCreateArgumentsVariableInParameterScope);
-    
+
+    if (isAsyncFunctionWrapperParseMode(parseMode) && !isSimpleParameterList) {
+        RefPtr<Label> didNotThrow = newLabel();
+        emitJump(didNotThrow.get());
+        RefPtr<RegisterID> exception = newTemporary();
+        RefPtr<RegisterID> thrownValue = newTemporary();
+        RefPtr<Label> catchHere = emitLabel(newLabel().get());
+        popTryAndEmitCatch(tryFormalParametersData, exception.get(), thrownValue.get(), catchHere.get(), HandlerType::Catch);
+
+        // return @Promise.@reject(thrownValue);
+        Variable promiseVar = variable(m_vm->propertyNames->builtinNames().PromisePrivateName());
+        RefPtr<RegisterID> scope = emitResolveScope(newTemporary(), promiseVar);
+        RefPtr<RegisterID> promiseConstructor = emitGetFromScope(newTemporary(), scope.get(), promiseVar, ResolveMode::ThrowIfNotFound);
+        RefPtr<RegisterID> promiseReject = emitGetById(newTemporary(), promiseConstructor.get(), m_vm->propertyNames->builtinNames().rejectPrivateName());
+
+        CallArguments args(*this, nullptr, 1);
+
+        emitMove(args.thisRegister(), promiseConstructor.get());
+        emitMove(args.argumentRegister(0), thrownValue.get());
+
+        JSTextPosition divot(functionNode->firstLine(), functionNode->startOffset(), functionNode->lineStartOffset());
+
+        RefPtr<RegisterID> result = emitCall(newTemporary(), promiseReject.get(), NoExpectedFunction, args, divot, divot, divot, DebuggableCall::No);
+        emitReturn(result.get());
+
+        emitLabel(didNotThrow.get());
+    }
+
     // If we don't have  default parameter expression, then loading |this| inside an arrow function must be done
     // after initializeDefaultParameterValuesAndSetupFunctionScopeStack() because that function sets up the
     // SymbolTable stack and emitLoadThisFromArrowFunctionLexicalEnvironment() consults the SymbolTable stack
-    if (SourceParseMode::ArrowFunctionMode == parseMode && isSimpleParameterList) {
+    if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(parseMode) && isSimpleParameterList) {
         if (functionNode->usesThis() || functionNode->usesSuperProperty())
             emitLoadThisFromArrowFunctionLexicalEnvironment();
     
@@ -642,7 +701,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     
     // Set up the lexical environment scope as the generator frame. We store the saved and resumed generator registers into this scope with the symbol keys.
     // Since they are symbol keyed, these variables cannot be reached from the usual code.
-    if (SourceParseMode::GeneratorBodyMode == parseMode) {
+    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) {
         ASSERT(m_lexicalEnvironmentRegister);
         m_generatorFrameSymbolTable.set(*m_vm, functionSymbolTable);
         m_generatorFrameSymbolTableIndex = symbolTableConstantIndex;
@@ -2644,6 +2703,21 @@ void BytecodeGenerator::emitPutSetterByVal(RegisterID* base, RegisterID* propert
     instructions().append(setter->index());
 }
 
+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);
+
+    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);
+}
+
 RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
 {
     emitOpcode(op_del_by_id);
@@ -2986,6 +3060,11 @@ void BytecodeGenerator::emitNewFunctionExpressionCommon(RegisterID* dst, Functio
     case SourceParseMode::GeneratorWrapperFunctionMode:
         opcodeID = op_new_generator_func_exp;
         break;
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+        opcodeID = op_new_async_func_exp;
+        break;
     default:
         break;
     }
@@ -3004,7 +3083,7 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncEx
 
 RegisterID* BytecodeGenerator::emitNewArrowFunctionExpression(RegisterID* dst, ArrowFuncExprNode* func)
 {
-    ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode || func->metadata()->parseMode() == SourceParseMode::AsyncArrowFunctionMode);
+    ASSERT(SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(func->metadata()->parseMode()));
     emitNewFunctionExpressionCommon(dst, func->metadata());
     return dst;
 }
@@ -3038,6 +3117,8 @@ RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionMetadata
     unsigned index = m_codeBlock->addFunctionDecl(makeFunction(function));
     if (function->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
         emitOpcode(op_new_generator_func);
+    else if (function->parseMode() == SourceParseMode::AsyncFunctionMode)
+        emitOpcode(op_new_async_func);
     else
         emitOpcode(op_new_func);
     instructions().append(dst->index());
index d4c1c8e..7c01729 100644 (file)
@@ -576,7 +576,10 @@ namespace JSC {
         void emitPutGetterSetter(RegisterID* base, const Identifier& property, unsigned attributes, RegisterID* getter, RegisterID* setter);
         void emitPutGetterByVal(RegisterID* base, RegisterID* property, unsigned propertyDescriptorOptions, RegisterID* getter);
         void emitPutSetterByVal(RegisterID* base, RegisterID* property, unsigned propertyDescriptorOptions, RegisterID* setter);
-        
+
+        // Initialize object with generator fields (@generatorThis, @generatorNext, @generatorState, @generatorFrame)
+        void emitPutGeneratorFields(RegisterID* nextFunction);
+
         ExpectedFunction expectedFunctionForIdentifier(const Identifier&);
         RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall);
         RegisterID* emitCallInTailPosition(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall);
@@ -842,7 +845,7 @@ namespace JSC {
         {
             DerivedContextType newDerivedContextType = DerivedContextType::None;
 
-            if (metadata->parseMode() == SourceParseMode::ArrowFunctionMode) {
+            if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(metadata->parseMode())) {
                 if (constructorKind() == ConstructorKind::Extends || isDerivedConstructorContext())
                     newDerivedContextType = DerivedContextType::DerivedConstructorContext;
                 else if (m_codeBlock->isClassContext() || isDerivedClassContext())
index d387cdf..ef2c5e6 100644 (file)
@@ -3402,25 +3402,64 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
             emitPutHomeObject(generator, next.get(), homeObject.get());
         }
 
-        // FIXME: Currently, we just create an object and store generator related fields as its properties for ease.
-        // But to make it efficient, we will introduce JSGenerator class, add opcode new_generator and use its C++ fields instead of these private properties.
-        // https://bugs.webkit.org/show_bug.cgi?id=151545
+        generator.emitPutGeneratorFields(next.get());
 
-        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().builtinNames().generatorNextPrivateName(), next.get(), PropertyNode::KnownDirect);
+        ASSERT(startOffset() >= lineStartOffset());
+        generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
+        generator.emitReturn(generator.generatorRegister());
+        break;
+    }
 
-        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().builtinNames().generatorThisPrivateName(), generator.thisRegister(), PropertyNode::KnownDirect);
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode: {
+        StatementNode* singleStatement = this->singleStatement();
+        ASSERT(singleStatement->isExprStatement());
+        ExprStatementNode* exprStatement = static_cast<ExprStatementNode*>(singleStatement);
+        ExpressionNode* expr = exprStatement->expr();
+        ASSERT(expr->isFuncExprNode());
+        FuncExprNode* funcExpr = static_cast<FuncExprNode*>(expr);
 
-        RegisterID* initialState = generator.emitLoad(nullptr, jsNumber(0));
-        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().builtinNames().generatorStatePrivateName(), initialState, PropertyNode::KnownDirect);
+        RefPtr<RegisterID> next = generator.newTemporary();
+        generator.emitNode(next.get(), funcExpr);
 
-        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().builtinNames().generatorFramePrivateName(), generator.emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
+        if (generator.superBinding() == SuperBinding::Needed || generator.parseMode() == SourceParseMode::AsyncArrowFunctionMode) {
+            // FIXME: Don't always load home object for async arrows
+            RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
+            emitPutHomeObject(generator, next.get(), homeObject.get());
+        }
+
+        generator.emitPutGeneratorFields(next.get());
 
         ASSERT(startOffset() >= lineStartOffset());
         generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
-        generator.emitReturn(generator.generatorRegister());
+
+        // load @asyncFunctionResume, and call.
+        RefPtr<RegisterID> startAsyncFunction = generator.newTemporary();
+        auto var = generator.variable(generator.propertyNames().builtinNames().asyncFunctionResumePrivateName());
+
+        RefPtr<RegisterID> scope = generator.newTemporary();
+        generator.moveToDestinationIfNeeded(scope.get(), generator.emitResolveScope(scope.get(), var));
+        generator.emitGetFromScope(startAsyncFunction.get(), scope.get(), var, ThrowIfNotFound);
+
+        // return @asyncFunctionResume.@call(this, @generator, @undefined, GeneratorResumeMode::NormalMode)
+        CallArguments args(generator, nullptr, 3);
+        unsigned argumentCount = 0;
+        generator.emitLoad(args.thisRegister(), jsUndefined());
+        generator.emitMove(args.argumentRegister(argumentCount++), generator.generatorRegister());
+        generator.emitLoad(args.argumentRegister(argumentCount++), jsUndefined());
+        generator.emitLoad(args.argumentRegister(argumentCount++), jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)));
+        // JSTextPosition(int _line, int _offset, int _lineStartOffset)
+        JSTextPosition divot(firstLine(), startOffset(), lineStartOffset());
+
+        RefPtr<RegisterID> result = generator.newTemporary();
+        generator.emitCallInTailPosition(result.get(), startAsyncFunction.get(), NoExpectedFunction, args, divot, divot, divot, DebuggableCall::No);
+        generator.emitReturn(result.get());
         break;
     }
 
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
     case SourceParseMode::GeneratorBodyMode: {
         RefPtr<Label> generatorBodyLabel = generator.newLabel();
         {
index 542a471..49b1a86 100644 (file)
@@ -299,6 +299,8 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_new_func_exp)
         DEFINE_OP(op_new_generator_func)
         DEFINE_OP(op_new_generator_func_exp)
+        DEFINE_OP(op_new_async_func)
+        DEFINE_OP(op_new_async_func_exp)
         DEFINE_OP(op_new_object)
         DEFINE_OP(op_new_regexp)
         DEFINE_OP(op_not)
index 05de28c..6d20249 100644 (file)
@@ -544,6 +544,8 @@ namespace JSC {
         void emit_op_new_func_exp(Instruction*);
         void emit_op_new_generator_func(Instruction*);
         void emit_op_new_generator_func_exp(Instruction*);
+        void emit_op_new_async_func(Instruction*);
+        void emit_op_new_async_func_exp(Instruction*);
         void emit_op_new_object(Instruction*);
         void emit_op_new_regexp(Instruction*);
         void emit_op_not(Instruction*);
index b901bb4..9f99aba 100644 (file)
@@ -971,9 +971,11 @@ void JIT::emitNewFuncCommon(Instruction* currentInstruction)
     OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
     if (opcodeID == op_new_func)
         callOperation(operationNewFunction, dst, regT0, funcExec);
-    else {
-        ASSERT(opcodeID == op_new_generator_func);
+    else if (opcodeID == op_new_generator_func)
         callOperation(operationNewGeneratorFunction, dst, regT0, funcExec);
+    else {
+        ASSERT(opcodeID == op_new_async_func);
+        callOperation(operationNewAsyncFunction, dst, regT0, funcExec);
     }
 }
 
@@ -987,6 +989,11 @@ void JIT::emit_op_new_generator_func(Instruction* currentInstruction)
     emitNewFuncCommon(currentInstruction);
 }
 
+void JIT::emit_op_new_async_func(Instruction* currentInstruction)
+{
+    emitNewFuncCommon(currentInstruction);
+}
+
 void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
 {
     Jump notUndefinedScope;
@@ -1008,9 +1015,11 @@ void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
 
     if (opcodeID == op_new_func_exp)
         callOperation(operationNewFunction, dst, regT0, function);
-    else {
-        ASSERT(opcodeID == op_new_generator_func_exp);
+    else if (opcodeID == op_new_generator_func_exp)
         callOperation(operationNewGeneratorFunction, dst, regT0, function);
+    else {
+        ASSERT(opcodeID == op_new_async_func_exp);
+        callOperation(operationNewAsyncFunction, dst, regT0, function);
     }
 
     done.link(this);
@@ -1026,6 +1035,11 @@ void JIT::emit_op_new_generator_func_exp(Instruction* currentInstruction)
     emitNewFuncExprCommon(currentInstruction);
 }
 
+void JIT::emit_op_new_async_func_exp(Instruction* currentInstruction)
+{
+    emitNewFuncExprCommon(currentInstruction);
+}
+
 void JIT::emit_op_new_array(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
index 2c045f8..744e905 100644 (file)
@@ -48,6 +48,7 @@
 #include "JIT.h"
 #include "JITExceptions.h"
 #include "JITToDFGDeferredCompilationCallback.h"
+#include "JSAsyncFunction.h"
 #include "JSCInlines.h"
 #include "JSGeneratorFunction.h"
 #include "JSGlobalObjectFunctions.h"
@@ -1178,6 +1179,16 @@ EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedRealloc
     return operationNewFunctionCommon<JSGeneratorFunction>(exec, scope, functionExecutable, true);
 }
 
+EncodedJSValue JIT_OPERATION operationNewAsyncFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
+{
+    return operationNewFunctionCommon<JSAsyncFunction>(exec, scope, functionExecutable, false);
+}
+
+EncodedJSValue JIT_OPERATION operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
+{
+    return operationNewFunctionCommon<JSAsyncFunction>(exec, scope, functionExecutable, true);
+}
+
 void JIT_OPERATION operationSetFunctionName(ExecState* exec, JSCell* funcCell, EncodedJSValue encodedName)
 {
     VM* vm = &exec->vm();
index adfef78..db5ba89 100644 (file)
@@ -375,6 +375,8 @@ EncodedJSValue JIT_OPERATION operationNewFunction(ExecState*, JSScope*, JSCell*)
 EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewAsyncFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 void JIT_OPERATION operationSetFunctionName(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
index 8758251..f58f4f9 100644 (file)
@@ -41,6 +41,7 @@
 #include "JIT.h"
 #include "JITExceptions.h"
 #include "JITWorklist.h"
+#include "JSAsyncFunction.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
 #include "JSGeneratorFunction.h"
@@ -1149,6 +1150,17 @@ LLINT_SLOW_PATH_DECL(slow_path_new_generator_func)
     LLINT_RETURN(JSGeneratorFunction::create(vm, codeBlock->functionDecl(pc[3].u.operand), scope));
 }
 
+LLINT_SLOW_PATH_DECL(slow_path_new_async_func)
+{
+    LLINT_BEGIN();
+    CodeBlock* codeBlock = exec->codeBlock();
+    JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+#if LLINT_SLOW_PATH_TRACING
+    dataLogF("Creating async function!\n");
+#endif
+    LLINT_RETURN(JSAsyncFunction::create(vm, codeBlock->functionDecl(pc[3].u.operand), scope));
+}
+
 LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
 {
     LLINT_BEGIN();
@@ -1171,6 +1183,17 @@ LLINT_SLOW_PATH_DECL(slow_path_new_generator_func_exp)
     LLINT_RETURN(JSGeneratorFunction::create(vm, executable, scope));
 }
 
+LLINT_SLOW_PATH_DECL(slow_path_new_async_func_exp)
+{
+    LLINT_BEGIN();
+    
+    CodeBlock* codeBlock = exec->codeBlock();
+    JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+    FunctionExecutable* executable = codeBlock->functionExpr(pc[3].u.operand);
+    
+    LLINT_RETURN(JSAsyncFunction::create(vm, executable, scope));
+}
+
 LLINT_SLOW_PATH_DECL(slow_path_set_function_name)
 {
     LLINT_BEGIN();
index 984e9cc..d76138c 100644 (file)
@@ -103,6 +103,8 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func_exp);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_async_func);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_async_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_set_function_name);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct);
index 560df3e..6445a47 100644 (file)
@@ -1321,6 +1321,12 @@ _llint_op_new_generator_func:
     dispatch(4)
 
 
+_llint_op_new_async_func:
+    traceExecution()
+    callSlowPath(_llint_slow_path_new_async_func)
+    dispatch(4)
+
+
 _llint_op_new_array:
     traceExecution()
     callOpcodeSlowPath(_llint_slow_path_new_array)
@@ -1599,6 +1605,12 @@ _llint_op_new_generator_func_exp:
     callOpcodeSlowPath(_llint_slow_path_new_generator_func_exp)
     dispatch(4)
 
+_llint_op_new_async_func_exp:
+    traceExecution()
+    callSlowPath(_llint_slow_path_new_async_func_exp)
+    dispatch(4)
+
+
 _llint_op_set_function_name:
     traceExecution()
     callOpcodeSlowPath(_llint_slow_path_set_function_name)
index d91037c..ce6bfa7 100644 (file)
@@ -261,7 +261,7 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     bool isArrowFunctionBodyExpression = parseMode == SourceParseMode::AsyncArrowFunctionBodyMode && !match(OPENBRACE);
     if (m_lexer->isReparsingFunction()) {
         ParserFunctionInfo<ASTBuilder> functionInfo;
-        if (SourceParseModeSet(SourceParseMode::GeneratorBodyMode).contains(parseMode) || isAsyncFunctionBodyParseMode(parseMode))
+        if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
             m_parameters = createGeneratorParameters(context, functionInfo.parameterCount);
         else
             m_parameters = parseFunctionParameters(context, parseMode, functionInfo);
@@ -568,11 +568,18 @@ template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseAsyncFun
     {
         AutoPopScopeRef asyncFunctionBodyScope(this, pushScope());
         asyncFunctionBodyScope->setSourceParseMode(innerParseMode);
-        SyntaxChecker asyncFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
-        if (isArrowFunctionBodyExpression)
-            failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(asyncFunctionContext), "Cannot parse the body of async arrow function");
-        else
-            failIfFalse(parseSourceElements(asyncFunctionContext, mode), "Cannot parse the body of async function");
+        SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
+        if (isArrowFunctionBodyExpression) {
+            if (m_debuggerParseData)
+                failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(context), "Cannot parse the body of async arrow function");
+            else
+                failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(syntaxChecker), "Cannot parse the body of async arrow function");
+        } else {
+            if (m_debuggerParseData)
+                failIfFalse(parseSourceElements(context, mode), "Cannot parse the body of async function");
+            else
+                failIfFalse(parseSourceElements(syntaxChecker, mode), "Cannot parse the body of async function");
+        }
         popScope(asyncFunctionBodyScope, TreeBuilder::NeedsFreeVariableInfo);
     }
     info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, info.functionLength, innerParseMode, isArrowFunctionBodyExpression);
@@ -2341,7 +2348,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         return parseFunctionBody(context, syntaxChecker, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, functionInfo.functionLength, mode);
     };
 
-    if (mode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(mode)) {
+    if (isGeneratorOrAsyncFunctionWrapperParseMode(mode)) {
         AutoPopScopeRef generatorBodyScope(this, pushScope());
         SourceParseMode innerParseMode = SourceParseMode::GeneratorBodyMode;
         if (isAsyncFunctionWrapperParseMode(mode)) {
index 15a8f12..0ca4ab3 100644 (file)
@@ -245,7 +245,7 @@ public:
             break;
 
         case SourceParseMode::AsyncFunctionBodyMode:
-            setIsAsyncArrowFunctionBody();
+            setIsAsyncFunctionBody();
             break;
 
         case SourceParseMode::GeneratorBodyMode:
@@ -1098,7 +1098,7 @@ private:
     {
         unsigned i = m_scopeStack.size() - 1;
         ASSERT(i < m_scopeStack.size() && m_scopeStack.size());
-        while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isArrowFunctionBoundary()))
+        while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isAsyncFunctionBoundary() || m_scopeStack[i].isArrowFunctionBoundary()))
             i--;
         // When reaching the top level scope (it can be non ordinary function scope), we return it.
         return ScopeRef(&m_scopeStack, i);
index a0d7404..6da8837 100644 (file)
@@ -148,6 +148,32 @@ ALWAYS_INLINE bool isMethodParseMode(SourceParseMode parseMode)
         SourceParseMode::AsyncMethodMode).contains(parseMode);
 }
 
+ALWAYS_INLINE bool isGeneratorOrAsyncFunctionBodyParseMode(SourceParseMode parseMode)
+{
+    return SourceParseModeSet(
+        SourceParseMode::GeneratorBodyMode,
+        SourceParseMode::AsyncFunctionBodyMode,
+        SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
+}
+
+ALWAYS_INLINE bool isGeneratorOrAsyncFunctionWrapperParseMode(SourceParseMode parseMode)
+{
+    return SourceParseModeSet(
+        SourceParseMode::GeneratorWrapperFunctionMode,
+        SourceParseMode::AsyncFunctionMode,
+        SourceParseMode::AsyncArrowFunctionMode,
+        SourceParseMode::AsyncMethodMode).contains(parseMode);
+}
+
+ALWAYS_INLINE bool isArrowFunctionParseMode(SourceParseMode parseMode)
+{
+    return SourceParseModeSet(
+        SourceParseMode::ArrowFunctionMode,
+        SourceParseMode::AsyncArrowFunctionMode,
+        SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
+}
+
+
 ALWAYS_INLINE bool isModuleParseMode(SourceParseMode parseMode) 
 { 
     return SourceParseModeSet( 
diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp
new file mode 100644 (file)
index 0000000..a767c57
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AsyncFunctionConstructor.h"
+
+#include "AsyncFunctionPrototype.h"
+#include "FunctionConstructor.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(AsyncFunctionConstructor);
+
+const ClassInfo AsyncFunctionConstructor::s_info = { "AsyncFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(AsyncFunctionConstructor) };
+
+AsyncFunctionConstructor::AsyncFunctionConstructor(VM& vm, Structure* structure)
+    : InternalFunction(vm, structure)
+{
+}
+
+void AsyncFunctionConstructor::finishCreation(VM& vm, AsyncFunctionPrototype* prototype)
+{
+    Base::finishCreation(vm, "AsyncFunction");
+    putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
+
+    // Number of arguments for constructor
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL callAsyncFunctionConstructor(ExecState* exec)
+{
+    ArgList args(exec);
+    return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Async));
+}
+
+static EncodedJSValue JSC_HOST_CALL constructAsyncFunctionConstructor(ExecState* exec)
+{
+    ArgList args(exec);
+    return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Async));
+}
+
+CallType AsyncFunctionConstructor::getCallData(JSCell*, CallData& callData)
+{
+    callData.native.function = callAsyncFunctionConstructor;
+    return CallType::Host;
+}
+
+ConstructType AsyncFunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+    constructData.native.function = constructAsyncFunctionConstructor;
+    return ConstructType::Host;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h
new file mode 100644 (file)
index 0000000..035a2c1
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class AsyncFunctionPrototype;
+
+class AsyncFunctionConstructor : public InternalFunction {
+public:
+    typedef InternalFunction Base;
+
+    DECLARE_INFO;
+
+    static AsyncFunctionConstructor* create(VM& vm, Structure* structure, AsyncFunctionPrototype* asyncFunctionPrototype)
+    {
+        AsyncFunctionConstructor* constructor = new (NotNull, allocateCell<AsyncFunctionConstructor>(vm.heap)) AsyncFunctionConstructor(vm, structure);
+        constructor->finishCreation(vm, asyncFunctionPrototype);
+        return constructor;
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+private:
+    AsyncFunctionConstructor(VM&, Structure*);
+    void finishCreation(VM&, AsyncFunctionPrototype*);
+    static ConstructType getConstructData(JSCell*, ConstructData&);
+    static CallType getCallData(JSCell*, CallData&);
+};
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp
new file mode 100644 (file)
index 0000000..fb1f0e1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AsyncFunctionPrototype.h"
+
+#include "BuiltinExecutables.h"
+#include "BuiltinNames.h"
+#include "Error.h"
+#include "JSArray.h"
+#include "JSCInlines.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "Lexer.h"
+
+namespace JSC {
+
+const ClassInfo AsyncFunctionPrototype::s_info = { "AsyncFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(AsyncFunctionPrototype) };
+
+AsyncFunctionPrototype::AsyncFunctionPrototype(VM& vm, Structure* structure)
+    : JSC::JSNonFinalObject(vm, structure)
+{
+}
+
+void AsyncFunctionPrototype::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(info()));
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "AsyncFunction"), DontEnum | ReadOnly);
+    vm.prototypeMap.addPrototype(this);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h
new file mode 100644 (file)
index 0000000..b201e6b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class AsyncFunctionPrototype : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+
+    DECLARE_INFO;
+
+    static AsyncFunctionPrototype* create(VM& vm, Structure* structure)
+    {
+        AsyncFunctionPrototype* prototype = new (NotNull, allocateCell<AsyncFunctionPrototype>(vm.heap)) AsyncFunctionPrototype(vm, structure);
+        prototype->finishCreation(vm);
+        return prototype;
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+protected:
+    void finishCreation(VM&);
+
+private:
+    AsyncFunctionPrototype(VM&, Structure*);
+};
+
+} // namespace JSC
index d2f3352..0a1a34c 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "ExceptionHelpers.h"
 #include "FunctionPrototype.h"
+#include "JSAsyncFunction.h"
 #include "JSFunction.h"
 #include "JSGeneratorFunction.h"
 #include "JSGlobalObject.h"
@@ -93,18 +94,33 @@ JSObject* constructFunctionSkippingEvalEnabledCheck(
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
+    const char* prefix = nullptr;
+    Structure* structure = nullptr;
+    switch (functionConstructionMode) {
+    case FunctionConstructionMode::Function:
+        structure = globalObject->functionStructure();
+        prefix = "{function ";
+        break;
+    case FunctionConstructionMode::Generator:
+        structure = globalObject->generatorFunctionStructure();
+        prefix = "{function *";
+        break;
+    case FunctionConstructionMode::Async:
+        structure = globalObject->asyncFunctionStructure();
+        prefix = "{async function ";
+        break;
+    }
+
     // How we stringify functions is sometimes important for web compatibility.
     // See https://bugs.webkit.org/show_bug.cgi?id=24350.
     String program;
     if (args.isEmpty())
-        program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n\n}}");
+        program = makeString(prefix, functionName.string(), "() {\n\n}}");
     else if (args.size() == 1)
-        program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
+        program = makeString(prefix, functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
     else {
         StringBuilder builder;
-        builder.appendLiteral("{function ");
-        if (functionConstructionMode == FunctionConstructionMode::Generator)
-            builder.append('*');
+        builder.append(prefix);
         builder.append(functionName.string());
         builder.append('(');
         builder.append(args.at(0).toString(exec)->view(exec).get());
@@ -126,12 +142,20 @@ JSObject* constructFunctionSkippingEvalEnabledCheck(
         return throwException(exec, scope, exception);
     }
 
-    Structure* subclassStructure = InternalFunction::createSubclassStructure(exec, newTarget, functionConstructionMode == FunctionConstructionMode::Generator ? globalObject->generatorFunctionStructure() : globalObject->functionStructure());
+    Structure* subclassStructure = InternalFunction::createSubclassStructure(exec, newTarget, structure);
     RETURN_IF_EXCEPTION(scope, nullptr);
 
-    if (functionConstructionMode == FunctionConstructionMode::Generator)
+    switch (functionConstructionMode) {
+    case FunctionConstructionMode::Function:
+        return JSFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
+    case FunctionConstructionMode::Generator:
         return JSGeneratorFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
-    return JSFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
+    case FunctionConstructionMode::Async:
+        return JSAsyncFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
+    }
+
+    ASSERT_NOT_REACHED();
+    return nullptr;
 }
 
 // ECMA 15.3.2 The Function Constructor
index 31c33d6..deee9a5 100644 (file)
@@ -58,6 +58,7 @@ private:
 enum class FunctionConstructionMode {
     Function,
     Generator,
+    Async,
 };
 
 JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&, FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
index 339e41b..61e7eec 100644 (file)
@@ -26,6 +26,7 @@
 #include "Error.h"
 #include "GetterSetter.h"
 #include "JSArray.h"
+#include "JSAsyncFunction.h"
 #include "JSFunction.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSString.h"
@@ -105,6 +106,15 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
             return JSValue::encode(jsString(exec, classSource.toStringWithoutCopying()));
         }
 
+        if (thisValue.inherits(JSAsyncFunction::info())) {
+            String functionHeader = executable->isArrowFunction() ? "async " : "async function ";
+
+            StringView source = executable->source().provider()->getRange(
+                executable->parametersStartOffset(),
+                executable->parametersStartOffset() + executable->source().length());
+            return JSValue::encode(jsMakeNontrivialString(exec, functionHeader, function->name(vm), source));
+        }
+
         String functionHeader = executable->isArrowFunction() ? "" : "function ";
         
         StringView source = executable->source().provider()->getRange(
diff --git a/Source/JavaScriptCore/runtime/JSAsyncFunction.cpp b/Source/JavaScriptCore/runtime/JSAsyncFunction.cpp
new file mode 100644 (file)
index 0000000..aba7437
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSAsyncFunction.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSCJSValue.h"
+#include "JSFunction.h"
+#include "JSFunctionInlines.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSAsyncFunction::s_info = { "AsyncFunction",  &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSAsyncFunction) };
+
+JSAsyncFunction::JSAsyncFunction(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+    : Base(vm, executable, scope, structure)
+{
+}
+
+JSAsyncFunction* JSAsyncFunction::createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+{
+    JSAsyncFunction* asyncFunction = new (NotNull, allocateCell<JSAsyncFunction>(vm.heap)) JSAsyncFunction(vm, executable, scope, structure);
+    ASSERT(asyncFunction->structure()->globalObject());
+    asyncFunction->finishCreation(vm);
+    return asyncFunction;
+}
+
+JSAsyncFunction* JSAsyncFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    JSAsyncFunction* asyncFunction = createImpl(vm, executable, scope, scope->globalObject()->asyncFunctionStructure());
+    executable->singletonFunction()->notifyWrite(vm, asyncFunction, "Allocating an async function");
+    return asyncFunction;
+}
+
+JSAsyncFunction* JSAsyncFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+{
+    JSAsyncFunction* asyncFunction = createImpl(vm, executable, scope, structure);
+    executable->singletonFunction()->notifyWrite(vm, asyncFunction, "Allocating an async function");
+    return asyncFunction;
+}
+
+JSAsyncFunction* JSAsyncFunction::createWithInvalidatedReallocationWatchpoint(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    return createImpl(vm, executable, scope, scope->globalObject()->asyncFunctionStructure());
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/JSAsyncFunction.h b/Source/JavaScriptCore/runtime/JSAsyncFunction.h
new file mode 100644 (file)
index 0000000..d7da87d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Caitlin Potter <caitp@igalia.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class JSAsyncFunction : public JSFunction {
+    friend class JIT;
+    friend class VM;
+public:
+    typedef JSFunction Base;
+
+    const static unsigned StructureFlags = Base::StructureFlags;
+
+    DECLARE_EXPORT_INFO;
+
+    static JSAsyncFunction* create(VM&, FunctionExecutable*, JSScope*);
+    static JSAsyncFunction* create(VM&, FunctionExecutable*, JSScope*, Structure*);
+    static JSAsyncFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
+
+    static size_t allocationSize(size_t inlineCapacity)
+    {
+        ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+        return sizeof(JSAsyncFunction);
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        ASSERT(globalObject);
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+    }
+
+private:
+    JSAsyncFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
+
+    static JSAsyncFunction* createImpl(VM&, FunctionExecutable*, JSScope*, Structure*);
+};
+
+} // namespace JSC
index 384082d..cb3b300 100644 (file)
@@ -33,6 +33,8 @@
 #include "ArrayConstructor.h"
 #include "ArrayIteratorPrototype.h"
 #include "ArrayPrototype.h"
+#include "AsyncFunctionConstructor.h"
+#include "AsyncFunctionPrototype.h"
 #include "BooleanConstructor.h"
 #include "BooleanPrototype.h"
 #include "BuiltinNames.h"
@@ -63,6 +65,7 @@
 #include "JSArrayBuffer.h"
 #include "JSArrayBufferConstructor.h"
 #include "JSArrayBufferPrototype.h"
+#include "JSAsyncFunction.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSCallbackConstructor.h"
@@ -585,6 +588,8 @@ 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);
     
@@ -630,7 +635,17 @@ 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_objectPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, objectConstructor, DontEnum);
     m_functionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, functionConstructor, DontEnum);
     m_arrayPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, arrayConstructor, DontEnum);
@@ -1102,6 +1117,7 @@ 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);
@@ -1110,6 +1126,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_moduleLoaderPrototype);
 
     thisObject->m_debuggerScopeStructure.visit(visitor);
index 40846ce..2dd4416 100644 (file)
@@ -56,6 +56,7 @@ namespace JSC {
 
 class ArrayConstructor;
 class ArrayPrototype;
+class AsyncFunctionPrototype;
 class BooleanPrototype;
 class ConsoleClient;
 class Debugger;
@@ -63,6 +64,7 @@ class ErrorConstructor;
 class ErrorPrototype;
 class EvalCodeBlock;
 class EvalExecutable;
+class FunctionConstructor;
 class FunctionPrototype;
 class GeneratorPrototype;
 class GeneratorFunctionPrototype;
@@ -233,6 +235,7 @@ 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;
@@ -306,6 +309,7 @@ public:
     PropertyOffset m_functionNameOffset;
     WriteBarrier<Structure> m_privateNameStructure;
     WriteBarrier<Structure> m_regExpStructure;
+    LazyClassStructure m_asyncFunctionStructure;
     WriteBarrier<Structure> m_generatorFunctionStructure;
     WriteBarrier<Structure> m_dollarVMStructure;
     WriteBarrier<Structure> m_iteratorResultObjectStructure;
@@ -527,6 +531,19 @@ public:
     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(); }
+
     Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(this); }
     Structure* withScopeStructure() const { return m_withScopeStructure.get(this); }
     Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); }