[JSC] implement async functions proposal
authorcaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 28 May 2016 05:44:10 +0000 (05:44 +0000)
committercaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 28 May 2016 05:44:10 +0000 (05:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156147

Reviewed by Yusuke Suzuki.

Source/JavaScriptCore:

Adds support for `async` functions, proposed in https://tc39.github.io/ecmascript-asyncawait/.

On the front-end side, "await" becomes a contextual keyword when used within an async function,
which triggers parsing an AwaitExpression. "await" becomes an illegal identifier name within
these contexts. The bytecode generated from an "await" expression is identical to that generated
in a "yield" expression in a Generator, as AsyncFunction reuses generator's state machine mechanism.

There are numerous syntactic forms for language features, including a variation on ArrowFunctions,
requiring the keyword `async` to precede ArrowFormalParameters, and similarly, MethodDefinitions,
which are ordinary MethodDefinitions preceded by the keyword `async`.

An async function desugars to the following:

```
async function asyncFn() {
}

becomes:

function asyncFn() {
    let generator = {
        @generatorNext: function(@generator, @generatorState, @generatorValue, @generatorResumeMode) {
          // generator state machine stuff here
        },
        @generatorState: 0,
        @generatorThis: this,
        @generatorFrame: null
    };
    return @asyncFunctionResume(generator, undefined, GeneratorResumeMode::NormalMode);
}
```

`@asyncFunctionResume()` is similar to `@generatorResume`, with the exception that it will wrap the
result of invoking `@generatorNext()` in a Promise, and will avoid allocating an iterator result
object.

If the generator has yielded (an AwaitExpression has occurred), resumption will occur automatically
once the await-expression operand is finished, via Promise chaining.

* API/JSScriptRef.cpp:
(parseScript):
* CMakeLists.txt:
* DerivedSources.make:
* JavaScriptCore.xcodeproj/project.pbxproj:
* builtins/AsyncFunctionPrototype.js: Added.
(asyncFunctionResume):
* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createExecutable):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finishCreation):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::isArrowFunction):
(JSC::UnlinkedCodeBlock::isOrdinaryArrowFunction):
(JSC::UnlinkedCodeBlock::isAsyncArrowFunction):
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::generateUnlinkedFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::fromGlobalCode):
(JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
* bytecode/UnlinkedFunctionExecutable.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
(JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
(JSC::BytecodeGenerator::emitNewMethodDefinition):
(JSC::BytecodeGenerator::emitNewFunction):
(JSC::BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::makeFunction):
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionNode::emitBytecode):
* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::parse):
* 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:
* jsc.cpp:
(runInteractive):
(printUsageStatement):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createAsyncFunctionBody):
* parser/Keywords.table:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::isArrowFunctionParameters):
(JSC::Parser<LexerType>::parseAsyncFunctionSourceElements):
(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseStatement):
(JSC::Parser<LexerType>::parseFunctionDeclarationStatement):
(JSC::Parser<LexerType>::parseFormalParameters):
(JSC::stringForFunctionMode):
(JSC::Parser<LexerType>::parseFunctionParameters):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseAsyncFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseExpressionOrLabelStatement):
(JSC::Parser<LexerType>::parseImportClauseItem):
(JSC::Parser<LexerType>::parseImportDeclaration):
(JSC::Parser<LexerType>::parseExportDeclaration):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseAwaitExpression):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parseAsyncFunctionExpression):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseMemberExpression):
(JSC::Parser<LexerType>::parseArrowFunctionExpression):
(JSC::Parser<LexerType>::parseUnaryExpression):
(JSC::Parser<LexerType>::printUnexpectedTokenText):
* parser/Parser.h:
(JSC::isIdentifierOrKeyword):
(JSC::Scope::Scope):
(JSC::Scope::setSourceParseMode):
(JSC::Scope::isAsyncFunction):
(JSC::Scope::isAsyncFunctionBoundary):
(JSC::Scope::isModule):
(JSC::Scope::setIsFunction):
(JSC::Scope::setIsAsyncArrowFunction):
(JSC::Scope::setIsAsyncFunction):
(JSC::Scope::setIsAsyncFunctionBody):
(JSC::Scope::setIsAsyncArrowFunctionBody):
(JSC::Parser::ExpressionErrorClassifier::forceClassifyExpressionError):
(JSC::Parser::ExpressionErrorClassifier::propagateExpressionErrorClass):
(JSC::Parser::ExpressionErrorClassifier::indicatesPossibleAsyncArrowFunction):
(JSC::Parser::forceClassifyExpressionError):
(JSC::Parser::declarationTypeToVariableKind):
(JSC::Parser::closestParentOrdinaryFunctionNonLexicalScope):
(JSC::Parser::pushScope):
(JSC::Parser::popScopeInternal):
(JSC::Parser::matchSpecIdentifier):
(JSC::Parser::isDisallowedIdentifierAwait):
(JSC::Parser::disallowedIdentifierAwaitReason):
(JSC::parse):
* parser/ParserModes.h:
(JSC::isFunctionParseMode):
(JSC::isAsyncFunctionParseMode):
(JSC::isAsyncArrowFunctionParseMode):
(JSC::isAsyncFunctionWrapperParseMode):
(JSC::isAsyncFunctionBodyParseMode):
(JSC::isModuleParseMode):
(JSC::isProgramParseMode):
(JSC::constructAbilityForParseMode):
* parser/ParserTokens.h:
* parser/SourceCodeKey.h:
(JSC::SourceCodeKey::SourceCodeKey):
(JSC::SourceCodeKey::runtimeFlags):
(JSC::SourceCodeKey::operator==):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createAsyncFunctionBody):
* 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/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
(JSC::CodeCache::getModuleProgramCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):
* runtime/CodeCache.h:
* runtime/CommonIdentifiers.h:
* runtime/Completion.cpp:
(JSC::checkSyntax):
(JSC::checkModuleSyntax):
* runtime/Completion.h:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ProgramExecutable::checkSyntax):
* runtime/Executable.h:
* 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/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertySlot):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::createProgramCodeBlock):
(JSC::JSGlobalObject::createEvalCodeBlock):
(JSC::JSGlobalObject::createModuleProgramCodeBlock):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::asyncFunctionPrototype):
(JSC::JSGlobalObject::asyncFunctionStructure):
* runtime/ModuleLoaderObject.cpp:
(JSC::moduleLoaderObjectParseModule):
* runtime/RuntimeFlags.h:
(JSC::RuntimeFlags::operator==):
(JSC::RuntimeFlags::operator!=):
* tests/stress/async-await-basic.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrow):
(shouldThrowAsync):
(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):
* tests/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):
* tests/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):
* tests/stress/async-await-reserved-word.js: Added.
(assert):
(shouldThrowSyntaxError):
(AsyncFunction.async):
* tests/stress/async_arrow_functions_lexical_arguments_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrowAsync):
(noArgumentsArrow2.async):
* tests/stress/async_arrow_functions_lexical_new.target_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(shouldThrowAsync):
(C1):
(C2):
(shouldThrowAsync.async):
* tests/stress/async_arrow_functions_lexical_super_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(BaseClass.prototype.baseClassValue):
(BaseClass):
(ChildClass.prototype.asyncSuperProp):
(ChildClass.prototype.asyncSuperProp2):
(ChildClass):
* tests/stress/async_arrow_functions_lexical_this_binding.js: Added.
(shouldBe):
(shouldBeAsync):
(d.y):

Source/WebKit/mac:

* WebView/WebPreferencesPrivate.h:

Source/WebKit/win:

* Interfaces/IWebPreferencesPrivate.idl:

Source/WebKit2:

* UIProcess/API/C/WKPreferencesRefPrivate.h:
* UIProcess/API/Cocoa/WKPreferencesPrivate.h:

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

69 files changed:
Source/JavaScriptCore/API/JSScriptRef.cpp
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/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.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/jsc.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/Keywords.table
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserModes.h
Source/JavaScriptCore/parser/ParserTokens.h
Source/JavaScriptCore/parser/SourceCodeKey.h
Source/JavaScriptCore/parser/SyntaxChecker.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/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/Completion.cpp
Source/JavaScriptCore/runtime/Completion.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/FunctionConstructor.cpp
Source/JavaScriptCore/runtime/FunctionConstructor.h
Source/JavaScriptCore/runtime/JSAsyncFunction.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSAsyncFunction.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
Source/JavaScriptCore/runtime/RuntimeFlags.h
Source/JavaScriptCore/tests/stress/async-await-basic.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async-await-module-reserved-word.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async-await-mozilla.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async-await-reserved-word.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_arguments_binding.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_new.target_binding.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_super_binding.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_this_binding.js [new file with mode: 0644]
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebPreferencesPrivate.h
Source/WebKit/win/ChangeLog
Source/WebKit/win/Interfaces/IWebPreferencesPrivate.idl
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h
Source/WebKit2/UIProcess/API/Cocoa/WKPreferencesPrivate.h

index 60bde60..fca31f0 100644 (file)
@@ -75,7 +75,7 @@ private:
 static bool parseScript(VM* vm, const SourceCode& source, ParserError& error)
 {
     return !!JSC::parse<JSC::ProgramNode>(
-        vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+        vm, RuntimeFlags(), source, Identifier(), JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
         error);
 }
index 50c5540..f361c52 100644 (file)
@@ -609,6 +609,8 @@ set(JavaScriptCore_SOURCES
     runtime/ArrayConstructor.cpp
     runtime/ArrayIteratorPrototype.cpp
     runtime/ArrayPrototype.cpp
+    runtime/AsyncFunctionConstructor.cpp
+    runtime/AsyncFunctionPrototype.cpp
     runtime/BasicBlockLocation.cpp
     runtime/BooleanConstructor.cpp
     runtime/BooleanObject.cpp
@@ -683,6 +685,7 @@ set(JavaScriptCore_SOURCES
     runtime/JSArrayBufferPrototype.cpp
     runtime/JSArrayBufferView.cpp
     runtime/JSArrayIterator.cpp
+    runtime/JSAsyncFunction.cpp
     runtime/JSBoundFunction.cpp
     runtime/JSBoundSlotBaseFunction.cpp
     runtime/JSCJSValue.cpp
@@ -1208,6 +1211,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 db59d7a..3912e9a 100644 (file)
@@ -1,3 +1,342 @@
+2016-05-27  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] implement async functions proposal
+        https://bugs.webkit.org/show_bug.cgi?id=156147
+
+        Reviewed by Yusuke Suzuki.
+
+        Adds support for `async` functions, proposed in https://tc39.github.io/ecmascript-asyncawait/.
+
+        On the front-end side, "await" becomes a contextual keyword when used within an async function,
+        which triggers parsing an AwaitExpression. "await" becomes an illegal identifier name within
+        these contexts. The bytecode generated from an "await" expression is identical to that generated
+        in a "yield" expression in a Generator, as AsyncFunction reuses generator's state machine mechanism.
+
+        There are numerous syntactic forms for language features, including a variation on ArrowFunctions,
+        requiring the keyword `async` to precede ArrowFormalParameters, and similarly, MethodDefinitions,
+        which are ordinary MethodDefinitions preceded by the keyword `async`.
+
+        An async function desugars to the following:
+
+        ```
+        async function asyncFn() {
+        }
+
+        becomes:
+
+        function asyncFn() {
+            let generator = {
+                @generatorNext: function(@generator, @generatorState, @generatorValue, @generatorResumeMode) {
+                  // generator state machine stuff here
+                },
+                @generatorState: 0,
+                @generatorThis: this,
+                @generatorFrame: null
+            };
+            return @asyncFunctionResume(generator, undefined, GeneratorResumeMode::NormalMode);
+        }
+        ```
+
+        `@asyncFunctionResume()` is similar to `@generatorResume`, with the exception that it will wrap the
+        result of invoking `@generatorNext()` in a Promise, and will avoid allocating an iterator result
+        object.
+
+        If the generator has yielded (an AwaitExpression has occurred), resumption will occur automatically
+        once the await-expression operand is finished, via Promise chaining.
+
+        * API/JSScriptRef.cpp:
+        (parseScript):
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * builtins/AsyncFunctionPrototype.js: Added.
+        (asyncFunctionResume):
+        * builtins/BuiltinExecutables.cpp:
+        (JSC::BuiltinExecutables::createExecutable):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::finishCreation):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::isArrowFunction):
+        (JSC::UnlinkedCodeBlock::isOrdinaryArrowFunction):
+        (JSC::UnlinkedCodeBlock::isAsyncArrowFunction):
+        * bytecode/UnlinkedFunctionExecutable.cpp:
+        (JSC::generateUnlinkedFunctionCodeBlock):
+        (JSC::UnlinkedFunctionExecutable::fromGlobalCode):
+        (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
+        * bytecode/UnlinkedFunctionExecutable.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::emitNewFunctionExpressionCommon):
+        (JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
+        (JSC::BytecodeGenerator::emitNewMethodDefinition):
+        (JSC::BytecodeGenerator::emitNewFunction):
+        (JSC::BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::makeFunction):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::FunctionNode::emitBytecode):
+        * inspector/agents/InspectorRuntimeAgent.cpp:
+        (Inspector::InspectorRuntimeAgent::parse):
+        * 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:
+        * jsc.cpp:
+        (runInteractive):
+        (printUsageStatement):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createAsyncFunctionBody):
+        * parser/Keywords.table:
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::Parser):
+        (JSC::Parser<LexerType>::parseInner):
+        (JSC::Parser<LexerType>::isArrowFunctionParameters):
+        (JSC::Parser<LexerType>::parseAsyncFunctionSourceElements):
+        (JSC::Parser<LexerType>::parseStatementListItem):
+        (JSC::Parser<LexerType>::parseVariableDeclarationList):
+        (JSC::Parser<LexerType>::parseDestructuringPattern):
+        (JSC::Parser<LexerType>::parseStatement):
+        (JSC::Parser<LexerType>::parseFunctionDeclarationStatement):
+        (JSC::Parser<LexerType>::parseFormalParameters):
+        (JSC::stringForFunctionMode):
+        (JSC::Parser<LexerType>::parseFunctionParameters):
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        (JSC::Parser<LexerType>::parseAsyncFunctionDeclaration):
+        (JSC::Parser<LexerType>::parseClass):
+        (JSC::Parser<LexerType>::parseExpressionOrLabelStatement):
+        (JSC::Parser<LexerType>::parseImportClauseItem):
+        (JSC::Parser<LexerType>::parseImportDeclaration):
+        (JSC::Parser<LexerType>::parseExportDeclaration):
+        (JSC::Parser<LexerType>::parseAssignmentExpression):
+        (JSC::Parser<LexerType>::parseAwaitExpression):
+        (JSC::Parser<LexerType>::parseProperty):
+        (JSC::Parser<LexerType>::parsePropertyMethod):
+        (JSC::Parser<LexerType>::parseAsyncFunctionExpression):
+        (JSC::Parser<LexerType>::parsePrimaryExpression):
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        (JSC::Parser<LexerType>::parseArrowFunctionExpression):
+        (JSC::Parser<LexerType>::parseUnaryExpression):
+        (JSC::Parser<LexerType>::printUnexpectedTokenText):
+        * parser/Parser.h:
+        (JSC::isIdentifierOrKeyword):
+        (JSC::Scope::Scope):
+        (JSC::Scope::setSourceParseMode):
+        (JSC::Scope::isAsyncFunction):
+        (JSC::Scope::isAsyncFunctionBoundary):
+        (JSC::Scope::isModule):
+        (JSC::Scope::setIsFunction):
+        (JSC::Scope::setIsAsyncArrowFunction):
+        (JSC::Scope::setIsAsyncFunction):
+        (JSC::Scope::setIsAsyncFunctionBody):
+        (JSC::Scope::setIsAsyncArrowFunctionBody):
+        (JSC::Parser::ExpressionErrorClassifier::forceClassifyExpressionError):
+        (JSC::Parser::ExpressionErrorClassifier::propagateExpressionErrorClass):
+        (JSC::Parser::ExpressionErrorClassifier::indicatesPossibleAsyncArrowFunction):
+        (JSC::Parser::forceClassifyExpressionError):
+        (JSC::Parser::declarationTypeToVariableKind):
+        (JSC::Parser::closestParentOrdinaryFunctionNonLexicalScope):
+        (JSC::Parser::pushScope):
+        (JSC::Parser::popScopeInternal):
+        (JSC::Parser::matchSpecIdentifier):
+        (JSC::Parser::isDisallowedIdentifierAwait):
+        (JSC::Parser::disallowedIdentifierAwaitReason):
+        (JSC::parse):
+        * parser/ParserModes.h:
+        (JSC::isFunctionParseMode):
+        (JSC::isAsyncFunctionParseMode):
+        (JSC::isAsyncArrowFunctionParseMode):
+        (JSC::isAsyncFunctionWrapperParseMode):
+        (JSC::isAsyncFunctionBodyParseMode):
+        (JSC::isModuleParseMode):
+        (JSC::isProgramParseMode):
+        (JSC::constructAbilityForParseMode):
+        * parser/ParserTokens.h:
+        * parser/SourceCodeKey.h:
+        (JSC::SourceCodeKey::SourceCodeKey):
+        (JSC::SourceCodeKey::runtimeFlags):
+        (JSC::SourceCodeKey::operator==):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createAsyncFunctionBody):
+        * 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/CodeCache.cpp:
+        (JSC::CodeCache::getGlobalCodeBlock):
+        (JSC::CodeCache::getProgramCodeBlock):
+        (JSC::CodeCache::getEvalCodeBlock):
+        (JSC::CodeCache::getModuleProgramCodeBlock):
+        (JSC::CodeCache::getFunctionExecutableFromGlobalCode):
+        * runtime/CodeCache.h:
+        * runtime/CommonIdentifiers.h:
+        * runtime/Completion.cpp:
+        (JSC::checkSyntax):
+        (JSC::checkModuleSyntax):
+        * runtime/Completion.h:
+        * runtime/Executable.cpp:
+        (JSC::ScriptExecutable::newCodeBlockFor):
+        (JSC::ProgramExecutable::checkSyntax):
+        * runtime/Executable.h:
+        * 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/JSFunction.cpp:
+        (JSC::JSFunction::getOwnPropertySlot):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::createProgramCodeBlock):
+        (JSC::JSGlobalObject::createEvalCodeBlock):
+        (JSC::JSGlobalObject::createModuleProgramCodeBlock):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::asyncFunctionPrototype):
+        (JSC::JSGlobalObject::asyncFunctionStructure):
+        * runtime/ModuleLoaderObject.cpp:
+        (JSC::moduleLoaderObjectParseModule):
+        * runtime/RuntimeFlags.h:
+        (JSC::RuntimeFlags::operator==):
+        (JSC::RuntimeFlags::operator!=):
+        * tests/stress/async-await-basic.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrow):
+        (shouldThrowAsync):
+        (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):
+        * tests/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):
+        * tests/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):
+        * tests/stress/async-await-reserved-word.js: Added.
+        (assert):
+        (shouldThrowSyntaxError):
+        (AsyncFunction.async):
+        * tests/stress/async_arrow_functions_lexical_arguments_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrowAsync):
+        (noArgumentsArrow2.async):
+        * tests/stress/async_arrow_functions_lexical_new.target_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (shouldThrowAsync):
+        (C1):
+        (C2):
+        (shouldThrowAsync.async):
+        * tests/stress/async_arrow_functions_lexical_super_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (BaseClass.prototype.baseClassValue):
+        (BaseClass):
+        (ChildClass.prototype.asyncSuperProp):
+        (ChildClass.prototype.asyncSuperProp2):
+        (ChildClass):
+        * tests/stress/async_arrow_functions_lexical_this_binding.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (d.y):
+
 2016-05-27  Saam barati  <sbarati@apple.com>
 
         DebuggerCallFrame crashes when updated with the globalExec because neither ShadowChicken's algorithm nor StackVisitor's algorithm reasons about the globalExec
index 72e41f4..17b43f6 100644 (file)
@@ -84,6 +84,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 8d20866..fdef50a 100644 (file)
                53529A4C1C457B75000B49C6 /* APIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 53529A4B1C457B75000B49C6 /* APIUtils.h */; };
                5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
                5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
+               5BD3A0671CAE325700F84BA3 /* AsyncFunctionConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD3A0611CAE325700F84BA3 /* AsyncFunctionConstructor.cpp */; };
+               5BD3A0681CAE325700F84BA3 /* AsyncFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD3A0621CAE325700F84BA3 /* AsyncFunctionConstructor.h */; };
+               5BD3A0691CAE325700F84BA3 /* AsyncFunctionPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD3A0631CAE325700F84BA3 /* AsyncFunctionPrototype.cpp */; };
+               5BD3A06A1CAE325700F84BA3 /* AsyncFunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD3A0641CAE325700F84BA3 /* AsyncFunctionPrototype.h */; };
+               5BD3A06B1CAE325700F84BA3 /* JSAsyncFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD3A0651CAE325700F84BA3 /* JSAsyncFunction.cpp */; };
+               5BD3A06E1CAE35BF00F84BA3 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD3A06D1CAE35BF00F84BA3 /* JSAsyncFunction.h */; };
                53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
                53F6BF6D1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F6BF6C1C3F060A00F41E5D /* InternalFunctionAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                53FA2AE11CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.h; sourceTree = "<group>"; };
                53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
                593D43CCA0BBE06D89C59707 /* MapDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapDataInlines.h; sourceTree = "<group>"; };
+               5BD3A0611CAE325700F84BA3 /* AsyncFunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionConstructor.cpp; sourceTree = "<group>"; };
+               5BD3A0621CAE325700F84BA3 /* AsyncFunctionConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionConstructor.h; sourceTree = "<group>"; };
+               5BD3A0631CAE325700F84BA3 /* AsyncFunctionPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionPrototype.cpp; sourceTree = "<group>"; };
+               5BD3A0641CAE325700F84BA3 /* AsyncFunctionPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionPrototype.h; sourceTree = "<group>"; };
+               5BD3A0651CAE325700F84BA3 /* JSAsyncFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAsyncFunction.cpp; sourceTree = "<group>"; };
+               5BD3A06D1CAE35BF00F84BA3 /* JSAsyncFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAsyncFunction.h; sourceTree = "<group>"; };
+               5BF474881CB1C5DB0002BAD7 /* 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 */,
+                               5BD3A0611CAE325700F84BA3 /* AsyncFunctionConstructor.cpp */,
+                               5BD3A0621CAE325700F84BA3 /* AsyncFunctionConstructor.h */,
+                               5BD3A0631CAE325700F84BA3 /* AsyncFunctionPrototype.cpp */,
+                               5BD3A0641CAE325700F84BA3 /* AsyncFunctionPrototype.h */,
                                52678F8C1A031009006A306D /* BasicBlockLocation.cpp */,
                                52678F8D1A031009006A306D /* BasicBlockLocation.h */,
                                147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */,
                                0F2B66BC17B6B5AB00A7AE3F /* JSArrayBufferViewInlines.h */,
                                A7BDAEC417F4EA1400F6140C /* JSArrayIterator.cpp */,
                                A7BDAEC517F4EA1400F6140C /* JSArrayIterator.h */,
+                               5BD3A0651CAE325700F84BA3 /* JSAsyncFunction.cpp */,
+                               5BD3A06D1CAE35BF00F84BA3 /* JSAsyncFunction.h */,
                                86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */,
                                86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */,
                                46D4DCBB1C5AB2D500D8D321 /* JSBoundSlotBaseFunction.cpp */,
                A7D8019F1880D66E0026C39B /* builtins */ = {
                        isa = PBXGroup;
                        children = (
+                               5BF474881CB1C5DB0002BAD7 /* AsyncFunctionPrototype.js */,
                                A7D801A01880D66E0026C39B /* ArrayPrototype.js */,
                                7CF9BC581B65D9A3009DB1EF /* ArrayConstructor.js */,
                                7CF9BC591B65D9A3009DB1EF /* ArrayIteratorPrototype.js */,
                                0F426A4B1460CD6E00131F8F /* DataFormat.h in Headers */,
                                0F2B66DF17B6B5AB00A7AE3F /* DataView.h in Headers */,
                                BCD2034A0E17135E002C7E82 /* DateConstructor.h in Headers */,
+                               5BD3A0681CAE325700F84BA3 /* AsyncFunctionConstructor.h in Headers */,
                                996B731A1BDA08D100331B84 /* DateConstructor.lut.h in Headers */,
                                41359CF30FDD89AD00206180 /* DateConversion.h in Headers */,
                                BC1166020E1997B4008066DD /* DateInstance.h in Headers */,
                                FE187A0D1C030D5C0038BBCA /* JITDivGenerator.h in Headers */,
                                2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */,
                                A5339EC91BB4B4600054F005 /* HeapObserver.h in Headers */,
+                               5BD3A06A1CAE325700F84BA3 /* AsyncFunctionPrototype.h in Headers */,
                                2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */,
                                14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */,
                                C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */,
                                A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
                                14142E511B796ECE00F4BF4B /* UnlinkedFunctionExecutable.h in Headers */,
                                0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */,
+                               5BD3A06E1CAE35BF00F84BA3 /* JSAsyncFunction.h in Headers */,
                                99DA00B11BD5994E00F4575C /* UpdateContents.py in Headers */,
                                0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */,
                                0F426A481460CBB300131F8F /* ValueRecovery.h in Headers */,
                                0FEC858B1BDACDC70080FF74 /* AirStackSlot.cpp in Sources */,
                                0FEC858D1BDACDC70080FF74 /* AirTmp.cpp in Sources */,
                                0FEC85901BDACDC70080FF74 /* AirValidate.cpp in Sources */,
+                               5BD3A06B1CAE325700F84BA3 /* JSAsyncFunction.cpp in Sources */,
                                147F39BD107EC37600427A48 /* ArgList.cpp in Sources */,
                                0F743BAA16B88249009F9277 /* ARM64Disassembler.cpp in Sources */,
                                86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */,
                                0FF729AE166AD35C000F5BA3 /* ProfilerBytecodes.cpp in Sources */,
                                0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */,
                                0FF729AF166AD35C000F5BA3 /* ProfilerCompilation.cpp in Sources */,
+                               5BD3A0671CAE325700F84BA3 /* AsyncFunctionConstructor.cpp in Sources */,
                                0FF729B0166AD35C000F5BA3 /* ProfilerCompilationKind.cpp in Sources */,
                                0FF729B1166AD35C000F5BA3 /* ProfilerCompiledBytecode.cpp in Sources */,
                                0FF729B2166AD35C000F5BA3 /* ProfilerDatabase.cpp in Sources */,
                                0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
                                1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */,
                                14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */,
+                               5BD3A0691CAE325700F84BA3 /* AsyncFunctionPrototype.cpp in Sources */,
                                14F7256514EE265E00B1652B /* WeakHandleOwner.cpp in Sources */,
                                A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */,
                                0F338DF91BE96AA80013C88F /* B3CCallValue.cpp in Sources */,
diff --git a/Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js b/Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js
new file mode 100644 (file)
index 0000000..ed9fad6
--- /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))
+        throw new @TypeError("Async function illegally resumed");
+
+    try {
+        generator.@generatorState = @GeneratorStateExecuting;
+        value = generator.@generatorNext.@call(generator.@generatorThis, generator, state, sentValue, resumeMode);
+        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 4c43b04..0489303 100644 (file)
@@ -79,7 +79,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S
     UnlinkedFunctionKind kind = isParsingDefaultConstructor ? UnlinkedNormalFunction : UnlinkedBuiltinFunction;
     RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr;
     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
-        &vm, source, Identifier(), builtinMode,
+        &vm, RuntimeFlags(), source, Identifier(), builtinMode,
         JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error,
         &positionBeforeLastNewline, constructorKind);
 
index 01efcc1..aa440cc 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_new_arrow_func_exp", "length" : 4 },
             { "name" : "op_set_function_name", "length" : 3 },
             { "name" : "op_call", "length" : 9 },
index 3f8ca2d..f5e6289 100644 (file)
@@ -149,6 +149,7 @@ void computeUsesForBytecodeOffset(
     case op_get_property_enumerator:
     case op_get_enumerable_length:
     case op_new_func_exp:
+    case op_new_async_func_exp:
     case op_new_generator_func_exp:
     case op_new_arrow_func_exp:
     case op_to_index_string:
@@ -182,6 +183,7 @@ void computeUsesForBytecodeOffset(
     case op_del_by_id:
     case op_unsigned:
     case op_new_func:
+    case op_new_async_func:
     case op_new_generator_func:
     case op_get_parent_scope:
     case op_create_scoped_arguments:
@@ -381,6 +383,8 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* bloc
     case op_new_regexp:
     case op_new_func:
     case op_new_func_exp:
+    case op_new_async_func:
+    case op_new_async_func_exp:
     case op_new_generator_func:
     case op_new_generator_func_exp:
     case op_new_arrow_func_exp:
index 8c7b6e5..e3b3f04 100644 (file)
@@ -1423,6 +1423,22 @@ 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_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_new_arrow_func_exp: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
@@ -2380,7 +2396,7 @@ void CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
     m_instructions = WTFMove(instructions);
 
     // Perform bytecode liveness analysis to determine which locals are live and should be resumed when executing op_resume.
-    if (unlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode) {
+    if (unlinkedCodeBlock->parseMode() == SourceParseMode::GeneratorBodyMode || isAsyncFunctionBodyParseMode(unlinkedCodeBlock->parseMode())) {
         if (size_t count = mergePointBytecodeOffsets.size()) {
             createRareDataIfNecessary();
             BytecodeLivenessAnalysis liveness(this);
index 2e0e293..8aa4250 100644 (file)
@@ -118,7 +118,9 @@ 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 isOrdinaryArrowFunction() || isAsyncArrowFunction(); }
+    bool isOrdinaryArrowFunction() const { return m_parseMode == SourceParseMode::ArrowFunctionMode; }
+    bool isAsyncArrowFunction() const { return m_parseMode == SourceParseMode::AsyncArrowFunctionMode; }
     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 05be3aa..7b60fed 100644 (file)
@@ -48,7 +48,7 @@ static_assert(sizeof(UnlinkedFunctionExecutable) <= 256, "UnlinkedFunctionExecut
 const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) };
 
 static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
-    VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source,
+    VM& vm, const RuntimeFlags& runtimeFlags, UnlinkedFunctionExecutable* executable, const SourceCode& source,
     CodeSpecializationKind kind, DebuggerMode debuggerMode,
     UnlinkedFunctionKind functionKind, ParserError& error, SourceParseMode parseMode)
 {
@@ -56,7 +56,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     JSParserStrictMode strictMode = executable->isInStrictContext() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
     ASSERT(isFunctionParseMode(executable->parseMode()));
     std::unique_ptr<FunctionNode> function = parse<FunctionNode>(
-        &vm, source, executable->name(), builtinMode, strictMode, executable->parseMode(), executable->superBinding(), error, nullptr);
+        &vm, runtimeFlags, source, executable->name(), builtinMode, strictMode, executable->parseMode(), executable->superBinding(), error, nullptr);
 
     if (!function) {
         ASSERT(error.isValid());
@@ -175,7 +175,7 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
     ParserError error;
     VM& vm = exec.vm();
     CodeCache* codeCache = vm.codeCache();
-    UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(vm, name, source, error);
+    UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(vm, exec.lexicalGlobalObject()->runtimeFlags(), name, source, error);
 
     auto& globalObject = *exec.lexicalGlobalObject();
     if (globalObject.hasDebugger())
@@ -190,7 +190,7 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
 }
 
 UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
-    VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, 
+    VM& vm, const RuntimeFlags& runtimeFlags, const SourceCode& source, CodeSpecializationKind specializationKind, 
     DebuggerMode debuggerMode, ParserError& error, SourceParseMode parseMode)
 {
     switch (specializationKind) {
@@ -205,7 +205,7 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
     }
 
     UnlinkedFunctionCodeBlock* result = generateUnlinkedFunctionCodeBlock(
-        vm, this, source, specializationKind, debuggerMode, 
+        vm, runtimeFlags, this, source, specializationKind, debuggerMode,
         isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, 
         error, parseMode);
     
index 646b0a6..6c04329 100644 (file)
@@ -50,6 +50,7 @@ namespace JSC {
 class FunctionMetadataNode;
 class FunctionExecutable;
 class ParserError;
+class RuntimeFlags;
 class SourceCode;
 class SourceProvider;
 class UnlinkedFunctionCodeBlock;
@@ -101,7 +102,7 @@ public:
     void setInvalidTypeProfilingOffsets();
 
     UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
-        VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode,
+        VM&, const RuntimeFlags&, const SourceCode&, CodeSpecializationKind, DebuggerMode,
         ParserError&, SourceParseMode);
 
     static UnlinkedFunctionExecutable* fromGlobalCode(
index 5803661..e862a05 100644 (file)
@@ -32,6 +32,7 @@
 #include "BytecodeGenerator.h"
 
 #include "BuiltinExecutables.h"
+#include "BuiltinNames.h"
 #include "BytecodeLivenessAnalysis.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
@@ -247,11 +248,11 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
     bool needsArguments = (functionNode->usesArguments() || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction()));
 
-    // Generator never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
-    if (parseMode == SourceParseMode::GeneratorBodyMode)
+    // Generator and AsyncFunction never provides "arguments". "arguments" reference will be resolved in an upper generator function scope.
+    if (parseMode == SourceParseMode::GeneratorBodyMode || isAsyncFunctionBodyParseMode(parseMode))
         needsArguments = false;
 
-    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode && needsArguments) {
+    if ((parseMode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(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.
@@ -298,7 +299,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     ASSERT(!(isSimpleParameterList && m_restParameter));
 
     // Before emitting a scope creation, emit a generator prologue that contains jump based on a generator's state.
-    if (parseMode == SourceParseMode::GeneratorBodyMode) {
+    if (parseMode == SourceParseMode::GeneratorBodyMode || isAsyncFunctionBodyParseMode(parseMode)) {
         m_generatorRegister = &m_parameters[1];
 
         // Jump with switch_imm based on @generatorState. We don't take the coroutine styled generator implementation.
@@ -313,6 +314,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
 
     if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode())) {
         ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
+        ASSERT(parseMode != SourceParseMode::AsyncFunctionBodyMode);
+        ASSERT(parseMode != SourceParseMode::AsyncArrowFunctionBodyMode);
         bool isDynamicScope = functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode());
         bool isFunctionNameCaptured = captures(functionNode->ident().impl());
         bool markAsCaptured = isDynamicScope || isFunctionNameCaptured;
@@ -537,6 +540,31 @@ 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) {
+            if (functionNode->usesThis() || codeBlock->usesEval()) {
+                m_codeBlock->addPropertyAccessInstruction(instructions().size());
+                emitOpcode(op_to_this);
+                instructions().append(kill(&m_thisRegister));
+                instructions().append(0);
+                instructions().append(0);
+            }
+
+            emitMove(m_generatorRegister, &m_calleeRegister);
+            emitCreateThis(m_generatorRegister);
+        } else
+            emitMove(m_generatorRegister, &m_calleeRegister);
+        break;
+    }
+
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
     case SourceParseMode::GeneratorBodyMode: {
         // |this| is already filled correctly before here.
         emitLoad(m_newTargetRegister, jsUndefined());
@@ -567,7 +595,9 @@ 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) {
+    //
+    // Also load here for AsyncArrowFunctions, as they may refer to |super| in their formal parameter expressions as well.
+    if ((SourceParseMode::ArrowFunctionMode == parseMode || parseMode == SourceParseMode::AsyncArrowFunctionMode) && !isSimpleParameterList) {
         if (functionNode->usesThis() || functionNode->usesSuperProperty())
             emitLoadThisFromArrowFunctionLexicalEnvironment();
 
@@ -586,12 +616,50 @@ 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);
+
+    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->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);
+        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) {
+    //
+    // For AsyncArrowFunctionBody functions, the lexical environment may have been loaded by the wrapper function,
+    // but may need to be loaded separately if it's used again in the function body.
+    // FIXME: only require loading the lexical context once per async arrow function.
+    if ((SourceParseMode::ArrowFunctionMode == parseMode && isSimpleParameterList) || SourceParseMode::AsyncArrowFunctionBodyMode == parseMode) {
         if (functionNode->usesThis() || functionNode->usesSuperProperty())
             emitLoadThisFromArrowFunctionLexicalEnvironment();
     
@@ -2894,6 +2962,11 @@ void BytecodeGenerator::emitNewFunctionExpressionCommon(RegisterID* dst, Functio
     default: {
         break;
     }
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+        opcodeID = op_new_async_func_exp;
+        break;
     }
     
     emitOpcode(opcodeID);
@@ -2910,7 +2983,7 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncEx
 
 RegisterID* BytecodeGenerator::emitNewArrowFunctionExpression(RegisterID* dst, ArrowFuncExprNode* func)
 {
-    ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode);
+    ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode || func->metadata()->parseMode() == SourceParseMode::AsyncArrowFunctionMode);
     emitNewFunctionExpressionCommon(dst, func->metadata());
     return dst;
 }
@@ -2920,7 +2993,8 @@ RegisterID* BytecodeGenerator::emitNewMethodDefinition(RegisterID* dst, MethodDe
     ASSERT(func->metadata()->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode
         || func->metadata()->parseMode() == SourceParseMode::GetterMode
         || func->metadata()->parseMode() == SourceParseMode::SetterMode
-        || func->metadata()->parseMode() == SourceParseMode::MethodMode);
+        || func->metadata()->parseMode() == SourceParseMode::MethodMode
+        || func->metadata()->parseMode() == SourceParseMode::AsyncMethodMode);
     emitNewFunctionExpressionCommon(dst, func->metadata());
     return dst;
 }
@@ -2947,6 +3021,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());
@@ -4235,7 +4311,7 @@ void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
 
 RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment(const Identifier& identifier)
 {
-    ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Derived || m_codeType == EvalCode);
+    ASSERT(m_codeBlock->isArrowFunction() || parseMode() == SourceParseMode::AsyncArrowFunctionBodyMode || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Derived || m_codeType == EvalCode);
 
     return emitResolveScope(nullptr, variable(identifier, ThisResolutionType::Scoped));
 }
index 16b1f53..bc1c602 100644 (file)
@@ -822,7 +822,7 @@ namespace JSC {
         {
             DerivedContextType newDerivedContextType = DerivedContextType::None;
 
-            if (metadata->parseMode() == SourceParseMode::ArrowFunctionMode) {
+            if (metadata->parseMode() == SourceParseMode::ArrowFunctionMode || metadata->parseMode() == SourceParseMode::AsyncArrowFunctionMode) {
                 if (constructorKind() == ConstructorKind::Derived || isDerivedConstructorContext())
                     newDerivedContextType = DerivedContextType::DerivedConstructorContext;
                 else if (m_codeBlock->isClassContext() || isDerivedClassContext())
@@ -836,7 +836,7 @@ namespace JSC {
             // https://bugs.webkit.org/show_bug.cgi?id=151547
             SourceParseMode parseMode = metadata->parseMode();
             ConstructAbility constructAbility = ConstructAbility::CanConstruct;
-            if (parseMode == SourceParseMode::GetterMode || parseMode == SourceParseMode::SetterMode || parseMode == SourceParseMode::ArrowFunctionMode || parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
+            if (parseMode == SourceParseMode::GetterMode || parseMode == SourceParseMode::SetterMode || parseMode == SourceParseMode::ArrowFunctionMode || parseMode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionParseMode(parseMode))
                 constructAbility = ConstructAbility::CannotConstruct;
             else if (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() == ConstructorKind::None)
                 constructAbility = ConstructAbility::CannotConstruct;
index 9a597b5..83353ca 100644 (file)
@@ -3265,6 +3265,67 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
         break;
     }
 
+    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);
+
+        RefPtr<RegisterID> next = generator.newTemporary();
+        generator.emitNode(next.get(), funcExpr);
+
+        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());
+        }
+
+        // FIXME: Currently, we just create an object and store generator related fields as its properties for ease.
+        // But to make it efficient, we will introduce JSGenerator class, add opcode new_generator and use its C++ fields instead of these private properties.
+        // https://bugs.webkit.org/show_bug.cgi?id=151545
+
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorNextPrivateName, next.get(), PropertyNode::KnownDirect);
+
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorThisPrivateName, generator.thisRegister(), PropertyNode::KnownDirect);
+
+        RegisterID* initialState = generator.emitLoad(nullptr, jsNumber(0));
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorStatePrivateName, initialState, PropertyNode::KnownDirect);
+
+        generator.emitDirectPutById(generator.generatorRegister(), generator.propertyNames().generatorFramePrivateName, generator.emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
+
+        ASSERT(startOffset() >= lineStartOffset());
+        generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset());
+
+        // 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.emitCall(result.get(), startAsyncFunction.get(), NoExpectedFunction, args, divot, divot, divot);
+        generator.emitReturn(result.get());
+        break;
+    }
+
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
     case SourceParseMode::GeneratorBodyMode: {
         RefPtr<Label> generatorBodyLabel = generator.newLabel();
         {
index 5b22544..3eb2ec0 100644 (file)
@@ -41,6 +41,7 @@
 #include "InspectorValues.h"
 #include "JSLock.h"
 #include "ParserError.h"
+#include "RuntimeFlags.h"
 #include "ScriptDebugServer.h"
 #include "SourceCode.h"
 #include "TypeProfiler.h"
@@ -90,7 +91,7 @@ void InspectorRuntimeAgent::parse(ErrorString&, const String& expression, Inspec
     JSLockHolder lock(m_vm);
 
     ParserError error;
-    checkSyntax(m_vm, JSC::makeSource(expression), error);
+    checkSyntax(m_vm, RuntimeFlags(), JSC::makeSource(expression), error);
 
     switch (error.syntaxErrorType()) {
     case ParserError::SyntaxErrorNone:
index bf64bba..f921494 100644 (file)
@@ -285,6 +285,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_arrow_func_exp) 
         DEFINE_OP(op_new_object)
         DEFINE_OP(op_new_regexp)
index 43fbebf..f4214f5 100644 (file)
@@ -553,6 +553,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_arrow_func_exp(Instruction*);
         void emit_op_new_object(Instruction*);
         void emit_op_new_regexp(Instruction*);
index 33f8346..0c7ef0d 100644 (file)
@@ -971,6 +971,8 @@ 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 if (opcodeID == op_new_async_func)
+        callOperation(operationNewAsyncFunction, dst, regT0, funcExec);
     else {
         ASSERT(opcodeID == op_new_generator_func);
         callOperation(operationNewGeneratorFunction, 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,6 +1015,8 @@ void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
 
     if (opcodeID == op_new_func_exp || opcodeID == op_new_arrow_func_exp)
         callOperation(operationNewFunction, dst, regT0, function);
+    else if (opcodeID == op_new_async_func_exp)
+        callOperation(operationNewAsyncFunction, dst, regT0, function);
     else {
         ASSERT(opcodeID == op_new_generator_func_exp);
         callOperation(operationNewGeneratorFunction, dst, regT0, function);
@@ -1026,6 +1035,12 @@ 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_arrow_func_exp(Instruction* currentInstruction)
 {
     emitNewFuncExprCommon(currentInstruction);
index 39304bf..6e8a089 100644 (file)
@@ -46,6 +46,7 @@
 #include "JIT.h"
 #include "JITExceptions.h"
 #include "JITToDFGDeferredCompilationCallback.h"
+#include "JSAsyncFunction.h"
 #include "JSCInlines.h"
 #include "JSGeneratorFunction.h"
 #include "JSGlobalObjectFunctions.h"
@@ -1102,6 +1103,16 @@ EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatc
     return operationNewFunctionCommon<JSFunction>(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);
+}
+
 EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
 {
     return operationNewFunctionCommon<JSGeneratorFunction>(exec, scope, functionExecutable, false);
index a9726eb..9202922 100644 (file)
@@ -345,6 +345,8 @@ EncodedJSValue JIT_OPERATION operationNewArrayBufferWithProfile(ExecState*, Arra
 EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState*, ArrayAllocationProfile*, EncodedJSValue size) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewAsyncFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 void JIT_OPERATION operationSetFunctionName(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
index b021d10..ba85a2f 100644 (file)
@@ -2097,7 +2097,7 @@ static void runInteractive(GlobalObject* globalObject)
                 break;
             source = source + line;
             source = source + '\n';
-            checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
+            checkSyntax(globalObject->vm(), globalObject->runtimeFlags(), makeSource(source, interpreterName), error);
             if (!line[0])
                 break;
             add_history(line);
@@ -2160,6 +2160,7 @@ static NO_RETURN void printUsageStatement(bool help = false)
     fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
     fprintf(stderr, "  --dumpOptions              Dumps all non-default JSC VM options before continuing\n");
     fprintf(stderr, "  --<jsc VM option>=<value>  Sets the specified JSC VM option\n");
+
     fprintf(stderr, "\n");
 
     jscExit(help ? EXIT_SUCCESS : EXIT_FAILURE);
index 9e588b9..eba205b 100644 (file)
@@ -40,6 +40,7 @@
 #include "Interpreter.h"
 #include "JIT.h"
 #include "JITExceptions.h"
+#include "JSAsyncFunction.h"
 #include "JSLexicalEnvironment.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
@@ -1129,6 +1130,17 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func)
     LLINT_RETURN(JSFunction::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_generator_func)
 {
     LLINT_BEGIN();
@@ -1162,6 +1174,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_new_arrow_func_exp)
 {
     LLINT_BEGIN();
index 2499542..df167c0 100644 (file)
@@ -100,6 +100,8 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_char);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_string);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func_exp);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_async_func);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_async_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_generator_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_arrow_func_exp);
index 145003d..1e42dbd 100644 (file)
@@ -1240,6 +1240,12 @@ _llint_op_new_func:
     dispatch(4)
 
 
+_llint_op_new_async_func:
+    traceExecution()
+    callSlowPath(_llint_slow_path_new_async_func)
+    dispatch(4)
+
+
 _llint_op_new_generator_func:
     traceExecution()
     callSlowPath(_llint_slow_path_new_generator_func)
@@ -1495,7 +1501,6 @@ _llint_op_switch_string:
     callSlowPath(_llint_slow_path_switch_string)
     dispatch(0)
 
-
 _llint_op_new_func_exp:
     traceExecution()
     callSlowPath(_llint_slow_path_new_func_exp)
@@ -1506,6 +1511,11 @@ _llint_op_new_generator_func_exp:
     callSlowPath(_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_new_arrow_func_exp:
     traceExecution()
     callSlowPath(_llint_slow_path_new_arrow_func_exp)
index 9ac904a..ddbcaf3 100644 (file)
@@ -380,6 +380,17 @@ public:
         return result;
     }
 
+    ExpressionNode* createAsyncFunctionBody(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo, SourceParseMode parseMode)
+    {
+        if (parseMode == SourceParseMode::AsyncArrowFunctionBodyMode) {
+            SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.body->isArrowFunctionBodyExpression() ? functionInfo.endOffset - 1 : functionInfo.endOffset, functionInfo.startLine, functionInfo.parametersStartColumn);
+            FuncExprNode* result = new (m_parserArena) FuncExprNode(location, *functionInfo.name, functionInfo.body, source);
+            functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
+            return result;
+        }
+        return createFunctionExpr(location, functionInfo);
+    }
+
     ExpressionNode* createMethodDefinition(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
         MethodDefinitionNode* result = new (m_parserArena) MethodDefinitionNode(location, *functionInfo.name, functionInfo.body,
index 4582d00..8430ae4 100644 (file)
@@ -7,6 +7,7 @@ true            TRUETOKEN
 false          FALSETOKEN
 
 # Keywords.
+await           AWAIT
 break          BREAK
 case           CASE
 catch          CATCH
index 30bde54..25f2c55 100644 (file)
@@ -80,6 +80,8 @@
         semanticFail("Cannot use the reserved word '", getToken(), "' as a ", __VA_ARGS__); \
     if (m_token.m_type & KeywordTokenFlag) \
         semanticFail("Cannot use the keyword '", getToken(), "' as a ", __VA_ARGS__); \
+    if (isDisallowedIdentifierAwait(m_token)) \
+        semanticFail("Can't use 'await' as a ", __VA_ARGS__, " ", disallowedIdentifierAwaitReason()); \
 } while (0)
 
 using namespace std;
@@ -195,10 +197,11 @@ void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B
 }
 
 template <typename LexerType>
-Parser<LexerType>::Parser(VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding, ConstructorKind defaultConstructorKind, DerivedContextType derivedContextType, bool isEvalContext, EvalContextType evalContextType)
+Parser<LexerType>::Parser(VM* vm, RuntimeFlags runtimeFlags, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding, ConstructorKind defaultConstructorKind, DerivedContextType derivedContextType, bool isEvalContext, EvalContextType evalContextType)
     : m_vm(vm)
     , m_source(&source)
     , m_hasStackOverflow(false)
+    , m_runtimeFlags(runtimeFlags)
     , m_allowsIn(true)
     , m_syntaxAlreadyValidated(source.provider()->isValid())
     , m_statementDepth(0)
@@ -252,15 +255,15 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     scope->setIsLexicalScope();
     SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Body);
 
-    bool isArrowFunctionBodyExpression = false;
+    bool isArrowFunctionBodyExpression = parseMode == SourceParseMode::AsyncArrowFunctionBodyMode && !match(OPENBRACE);
     if (m_lexer->isReparsingFunction()) {
         ParserFunctionInfo<ASTBuilder> functionInfo;
-        if (parseMode == SourceParseMode::GeneratorBodyMode)
+        if (parseMode == SourceParseMode::GeneratorBodyMode || isAsyncFunctionBodyParseMode(parseMode))
             m_parameters = createGeneratorParameters(context);
         else
             m_parameters = parseFunctionParameters(context, parseMode, functionInfo);
 
-        if (parseMode == SourceParseMode::ArrowFunctionMode && !hasError()) {
+        if ((parseMode == SourceParseMode::ArrowFunctionMode || parseMode == SourceParseMode::AsyncArrowFunctionMode) && !hasError()) {
             // The only way we could have an error wile reparsing is if we run out of stack space.
             RELEASE_ASSERT(match(ARROWFUNCTION));
             next();
@@ -277,16 +280,16 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     SourceElements* sourceElements = nullptr;
     // The only way we can error this early is if we reparse a function and we run out of stack space.
     if (!hasError()) {
-        if (isArrowFunctionBodyExpression)
+        if (isAsyncFunctionWrapperParseMode(parseMode))
+            sourceElements = parseAsyncFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
+        else if (isArrowFunctionBodyExpression)
             sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
         else if (isModuleParseMode(parseMode))
             sourceElements = parseModuleSourceElements(context, parseMode);
-        else {
-            if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
-                sourceElements = parseGeneratorFunctionSourceElements(context, CheckForStrictMode);
-            else
-                sourceElements = parseSourceElements(context, CheckForStrictMode);
-        }
+        else if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
+            sourceElements = parseGeneratorFunctionSourceElements(context, CheckForStrictMode);
+        else
+            sourceElements = parseSourceElements(context, CheckForStrictMode);
     }
 
     bool validEnding = consume(EOFTOK);
@@ -306,7 +309,7 @@ String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMo
     for (auto& entry : capturedVariables)
         varDeclarations.markVariableAsCaptured(entry);
 
-    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode) {
+    if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(parseMode)) {
         if (scope->usedVariablesContains(m_vm->propertyNames->arguments.impl()))
             context.propagateArgumentsUse();
     }
@@ -352,7 +355,7 @@ template <typename LexerType>
 bool Parser<LexerType>::isArrowFunctionParameters()
 {
     bool isOpenParen = match(OPENPAREN);
-    bool isIdent = match(IDENT);
+    bool isIdent = matchSpecIdentifier();
     
     if (!isOpenParen && !isIdent)
         return false;
@@ -529,6 +532,51 @@ template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGenerato
 }
 
 template <typename LexerType>
+template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseAsyncFunctionSourceElements(TreeBuilder& context, SourceParseMode parseMode, bool isArrowFunctionBodyExpression, SourceElementsMode mode)
+{
+    ASSERT(isAsyncFunctionWrapperParseMode(parseMode));
+    auto sourceElements = context.createSourceElements();
+
+    unsigned functionKeywordStart = tokenStart();
+    JSTokenLocation startLocation(tokenLocation());
+    JSTextPosition start = tokenStartPosition();
+    unsigned startColumn = tokenColumn();
+    int functionNameStart = m_token.m_location.startOffset;
+    int parametersStart = m_token.m_location.startOffset;
+
+    ParserFunctionInfo<TreeBuilder> info;
+    info.name = &m_vm->propertyNames->nullIdentifier;
+    createGeneratorParameters(context);
+    info.startOffset = parametersStart;
+    info.startLine = tokenLine();
+    info.parameterCount = 4; // generator, state, value, resume mode
+    SourceParseMode innerParseMode = parseMode == SourceParseMode::AsyncArrowFunctionMode
+        ? SourceParseMode::AsyncArrowFunctionBodyMode
+        : SourceParseMode::AsyncFunctionBodyMode;
+    {
+        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");
+        popScope(asyncFunctionBodyScope, TreeBuilder::NeedsFreeVariableInfo);
+    }
+    info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, innerParseMode, isArrowFunctionBodyExpression);
+
+    info.endLine = tokenLine();
+    info.endOffset = isArrowFunctionBodyExpression ? tokenLocation().endOffset : m_token.m_data.offset;
+    info.parametersStartColumn = startColumn;
+
+    auto functionExpr = context.createAsyncFunctionBody(startLocation, info, innerParseMode);
+    auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
+    context.appendStatement(sourceElements, statement);
+
+    return sourceElements;
+}
+
+template <typename LexerType>
 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
 {
     // The grammar is documented here:
@@ -537,6 +585,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
     m_statementDepth++;
     TreeStatement result = 0;
     bool shouldSetEndOffset = true;
+
     switch (m_token.m_type) {
     case CONSTTOKEN:
         result = parseVariableDeclaration(context, DeclarationType::ConstDeclaration);
@@ -551,7 +600,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
             // For example, under a generator context, matchSpecIdentifier() for "yield" returns `false`.
             // But we would like to enter parseVariableDeclaration and raise an error under the context of parseVariableDeclaration
             // to raise consistent errors between "var", "const" and "let".
-            if (!(match(IDENT) || match(LET) || match(YIELD)) && !match(OPENBRACE) && !match(OPENBRACKET))
+            if (!(match(IDENT) || match(AWAIT) || match(LET) || match(YIELD)) && !match(OPENBRACE) && !match(OPENBRACKET))
                 shouldParseVariableDeclaration = false;
             restoreSavePoint(savePoint);
         }
@@ -570,7 +619,21 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
     case FUNCTION:
         result = parseFunctionDeclaration(context);
         break;
+
     case IDENT:
+        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
+            // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
+            // but could be mistakenly parsed as an AsyncFunctionExpression.
+            SavePoint savePoint = createSavePoint();
+            next();
+            if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
+                result = parseAsyncFunctionDeclaration(context);
+                break;
+            }
+            restoreSavePoint(savePoint);
+        }
+        FALLTHROUGH;
+    case AWAIT:
     case YIELD: {
         // This is a convenient place to notice labeled statements
         // (even though we also parse them as normal statements)
@@ -679,6 +742,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
         if (matchSpecIdentifier()) {
             failIfTrue(match(LET) && (declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::ConstDeclaration), 
                 "Can't use 'let' as an identifier name for a LexicalDeclaration");
+            semanticFailIfTrue(isDisallowedIdentifierAwait(m_token), "Can't use 'await' as a ", declarationTypeToVariableKind(declarationType), " ", disallowedIdentifierAwaitReason());
             JSTextPosition varStart = tokenStartPosition();
             JSTokenLocation varStartLocation(tokenLocation());
             identStart = varStart;
@@ -1001,6 +1065,7 @@ template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDe
                             reclassifyExpressionError(ErrorIndicatesPattern, ErrorIndicatesNothing);
                         failIfTrueIfStrict(isEvalOrArguments, "Cannot modify '", propertyName->impl(), "' in strict mode");
                     }
+                    semanticFailIfTrue(isDisallowedIdentifierAwait(identifierToken), "Can't use 'await' as a ", destructuringKindToVariableKindName(kind), " ", disallowedIdentifierAwaitReason());
                     innerPattern = createBindingPattern(context, kind, exportType, *propertyName, identifierToken, bindingContext, duplicateIdentifier);
                 }
             } else {
@@ -1069,6 +1134,7 @@ template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDe
             failWithMessage("Expected a parameter pattern or a ')' in parameter list");
         }
         failIfTrue(match(LET) && (kind == DestructuringKind::DestructureToLet || kind == DestructuringKind::DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
+        semanticFailIfTrue(isDisallowedIdentifierAwait(m_token), "Can't use 'await' as a ", destructuringKindToVariableKindName(kind), " ", disallowedIdentifierAwaitReason());
         pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, m_token, bindingContext, duplicateIdentifier);
         next();
         break;
@@ -1617,43 +1683,8 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
         result = parseVariableDeclaration(context, DeclarationType::VarDeclaration);
         break;
     case FUNCTION: {
-        if (!strictMode()) {
-            failIfFalse(parentAllowsFunctionDeclarationAsStatement, "Function declarations are only allowed inside block statements or at the top level of a program");
-            if (currentScope()->isFunction()) {
-                // Any function declaration that isn't in a block is a syntax error unless it's
-                // in an if/else statement. If it's in an if/else statement, we will magically
-                // treat it as if the if/else statement is inside a block statement.
-                // to the very top like a "var". For example:
-                // function a() {
-                //     if (cond) function foo() { }
-                // }
-                // will be rewritten as:
-                // function a() {
-                //     if (cond) { function foo() { } }
-                // }
-                AutoPopScopeRef blockScope(this, pushScope());
-                blockScope->setIsLexicalScope();
-                blockScope->preventVarDeclarations();
-                JSTokenLocation location(tokenLocation());
-                int start = tokenLine();
-
-                TreeStatement function = parseFunctionDeclaration(context);
-                propagateError();
-                failIfFalse(function, "Expected valid function statement after 'function' keyword");
-                TreeSourceElements sourceElements = context.createSourceElements();
-                context.appendStatement(sourceElements, function);
-                result = context.createBlockStatement(location, sourceElements, start, m_lastTokenEndPosition.line, currentScope()->finalizeLexicalEnvironment(), currentScope()->takeFunctionDeclarations());
-                popScope(blockScope, TreeBuilder::NeedsFreeVariableInfo);
-            } else {
-                // We only implement annex B.3.3 if we're in function mode. Otherwise, we fall back
-                // to hoisting behavior.
-                // FIXME: https://bugs.webkit.org/show_bug.cgi?id=155813
-                DepthManager statementDepth(&m_statementDepth);
-                m_statementDepth = 1;
-                result = parseFunctionDeclaration(context);
-            }
-        } else
-            failWithMessage("Function declarations are only allowed inside blocks or switch statements in strict mode");
+        const bool isAsync = false;
+        result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement);
         break;
     }
     case SEMICOLON: {
@@ -1704,7 +1735,20 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
     case DEFAULT:
         // These tokens imply the end of a set of source elements
         return 0;
+
     case IDENT:
+        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
+            SavePoint savePoint = createSavePoint();
+            next();
+            if (match(FUNCTION) && !m_lexer->prevTerminator()) {
+                const bool isAsync = true;
+                result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement);
+                break;
+            }
+            restoreSavePoint(savePoint);
+        }
+        FALLTHROUGH;
+    case AWAIT:
     case YIELD: {
         bool allowFunctionDeclarationAsStatement = false;
         result = parseExpressionOrLabelStatement(context, allowFunctionDeclarationAsStatement);
@@ -1730,6 +1774,53 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
 }
 
 template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclarationStatement(TreeBuilder& context, bool isAsync, bool parentAllowsFunctionDeclarationAsStatement)
+{
+    semanticFailIfTrue(strictMode(), "Function declarations are only allowed inside blocks or switch statements in strict mode");
+    failIfFalse(parentAllowsFunctionDeclarationAsStatement, "Function declarations are only allowed inside block statements or at the top level of a program");
+    if (!currentScope()->isFunction()) {
+        // We only implement annex B.3.3 if we're in function mode. Otherwise, we fall back
+        // to hoisting behavior.
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=155813
+        DepthManager statementDepth(&m_statementDepth);
+        m_statementDepth = 1;
+        if (isAsync)
+            return parseAsyncFunctionDeclaration(context);
+        return parseFunctionDeclaration(context);
+    }
+
+    // Any function declaration that isn't in a block is a syntax error unless it's
+    // in an if/else statement. If it's in an if/else statement, we will magically
+    // treat it as if the if/else statement is inside a block statement.
+    // to the very top like a "var". For example:
+    // function a() {
+    //     if (cond) function foo() { }
+    // }
+    // will be rewritten as:
+    // function a() {
+    //     if (cond) { function foo() { } }
+    // }
+    AutoPopScopeRef blockScope(this, pushScope());
+    blockScope->setIsLexicalScope();
+    blockScope->preventVarDeclarations();
+    JSTokenLocation location(tokenLocation());
+    int start = tokenLine();
+
+    TreeStatement function = 0;
+    if (!isAsync)
+        function = parseFunctionDeclaration(context);
+    else
+        function = parseAsyncFunctionDeclaration(context);
+    propagateError();
+    failIfFalse(function, "Expected valid function statement after 'function' keyword");
+    TreeSourceElements sourceElements = context.createSourceElements();
+    context.appendStatement(sourceElements, function);
+    TreeStatement result = context.createBlockStatement(location, sourceElements, start, m_lastTokenEndPosition.line, currentScope()->finalizeLexicalEnvironment(), currentScope()->takeFunctionDeclarations());
+    popScope(blockScope, TreeBuilder::NeedsFreeVariableInfo);
+    return result;
+}
+
+template <typename LexerType>
 template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeBuilder& context, TreeFormalParameterList list, unsigned& parameterCount)
 {
 #define failIfDuplicateIfViolation() \
@@ -1749,6 +1840,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeB
         if (match(DOTDOTDOT)) {
             next();
             failIfFalse(matchSpecIdentifier(), "Rest parameter '...' should be followed by a variable identifier");
+            semanticFailIfTrue(!m_parserState.allowAwait && match(AWAIT), "Can't use 'await' as a parameter name in an async function");
             declareRestOrNormalParameter(*m_token.m_data.ident, &duplicateParameter);
             propagateError();
             JSTextPosition identifierStart = tokenStartPosition();
@@ -1814,6 +1906,14 @@ static const char* stringForFunctionMode(SourceParseMode mode)
         return "generator function";
     case SourceParseMode::ArrowFunctionMode:
         return "arrow function";
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
+        return "async function";
+    case SourceParseMode::AsyncMethodMode:
+        return "async method";
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+        return "async arrow function";
     case SourceParseMode::ProgramMode:
     case SourceParseMode::ModuleAnalyzeMode:
     case SourceParseMode::ModuleEvaluateMode:
@@ -1830,8 +1930,8 @@ template <typename LexerType> template <class TreeBuilder, class FunctionInfoTyp
     TreeFormalParameterList parameterList = context.createFormalParameterList();
     SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Parameters);
     
-    if (mode == SourceParseMode::ArrowFunctionMode) {
-        if (!match(IDENT) && !match(OPENPAREN)) {
+    if (mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode) {
+        if (!matchSpecIdentifier() && !match(OPENPAREN)) {
             semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
             failWithMessage("Expected an arrow function input parameter");
         } else {
@@ -1923,6 +2023,8 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     RELEASE_ASSERT(isFunctionParseMode(mode));
 
     bool upperScopeIsGenerator = currentScope()->isGenerator();
+    bool isDisallowedAwaitFunctionName = isDisallowedIdentifierAwait(m_token);
+    const char* isDisallowedAwaitFunctionNameReason = isDisallowedAwaitFunctionName ? disallowedIdentifierAwaitReason() : nullptr;
     AutoPopScopeRef functionScope(this, pushScope());
     functionScope->setSourceParseMode(mode);
     SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Body);
@@ -1961,7 +2063,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             ASSERT(endLocation.startOffset >= endLocation.lineStartOffset);
             
             FunctionBodyType functionBodyType;
-            if (mode == SourceParseMode::ArrowFunctionMode)
+            if (mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode)
                 functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
             else
                 functionBodyType = StandardFunctionBodyBlock;
@@ -2004,18 +2106,21 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
 
     SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
 
-    if (mode == SourceParseMode::ArrowFunctionMode) {
+    if (mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::AsyncArrowFunctionMode) {
         startLocation = tokenLocation();
         functionInfo.startLine = tokenLine();
         startColumn = tokenColumn();
-
         parametersStart = m_token.m_location.startOffset;
         functionInfo.startOffset = parametersStart;
         functionInfo.parametersStartColumn = startColumn;
 
         if (loadCachedFunction())
             return true;
-        parseFunctionParameters(syntaxChecker, mode, functionInfo);
+        {
+            SetForScope<bool> overrideAllowAwait(m_parserState.allowAwait, !isAsyncFunctionParseMode(mode));
+            parseFunctionParameters(context, mode, functionInfo);
+        }
+
         propagateError();
 
         matchOrFail(ARROWFUNCTION, "Expected a '=>' after arrow function parameter declaration");
@@ -2045,19 +2150,25 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         // GeneratorExpression :
         //     function * BindingIdentifier[Yield]opt ( FormalParameters[Yield] ) { GeneratorBody }
         //
-        // The name of FunctionExpression can accept "yield" even in the context of generator.
-        if (functionDefinitionType == FunctionDefinitionType::Expression && mode == SourceParseMode::NormalFunctionMode)
+        // The name of FunctionExpression and AsyncFunctionExpression can accept "yield" even in the context of generator.
+        if (functionDefinitionType == FunctionDefinitionType::Expression && (mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::AsyncFunctionMode))
             upperScopeIsGenerator = false;
 
         if (matchSpecIdentifier(upperScopeIsGenerator)) {
+            bool allowsAwait = functionDefinitionType == FunctionDefinitionType::Declaration || mode != SourceParseMode::AsyncFunctionMode;
             functionInfo.name = m_token.m_data.ident;
             m_parserState.lastFunctionName = functionInfo.name;
+            if (allowsAwait)
+                semanticFailIfTrue(isDisallowedAwaitFunctionName, "Cannot declare function named 'await' ", isDisallowedAwaitFunctionNameReason);
+            else
+                semanticFailIfTrue(isDisallowedAwaitFunctionName, "Cannot declare async function named 'await'");
+            
             next();
             if (!nameIsInContainingScope)
                 failIfTrueIfStrict(functionScope->declareCallee(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
         } else if (requirements == FunctionNeedsName) {
-            if (match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode)
-                semanticFail("Function statements must have a name");
+            semanticFailIfTrue(match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode, "Function statements must have a name");
+            semanticFailIfTrue(match(OPENPAREN) && mode == SourceParseMode::AsyncFunctionMode, "Async function statements must have a name");
             semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
             failDueToUnexpectedToken();
             return false;
@@ -2073,8 +2184,11 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
 
         if (loadCachedFunction())
             return true;
-        parseFunctionParameters(syntaxChecker, mode, functionInfo);
-        propagateError();
+        {
+            SetForScope<bool> overrideAllowAwait(m_parserState.allowAwait, !isAsyncFunctionParseMode(mode));
+            parseFunctionParameters(context, mode, functionInfo);
+            propagateError();
+        }
         
         matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body");
         
@@ -2118,9 +2232,15 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         return parseFunctionBody(context, syntaxChecker, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, expectedSuperBinding, functionBodyType, functionInfo.parameterCount, mode);
     };
 
-    if (mode == SourceParseMode::GeneratorWrapperFunctionMode) {
+    if (mode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(mode)) {
         AutoPopScopeRef generatorBodyScope(this, pushScope());
-        generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
+        SourceParseMode innerParseMode = SourceParseMode::GeneratorBodyMode;
+        if (isAsyncFunctionWrapperParseMode(mode)) {
+            innerParseMode = mode == SourceParseMode::AsyncArrowFunctionMode
+                ? SourceParseMode::AsyncArrowFunctionBodyMode
+                : SourceParseMode::AsyncFunctionBodyMode;
+        }
+        generatorBodyScope->setSourceParseMode(innerParseMode);
         generatorBodyScope->setConstructorKind(ConstructorKind::None);
         generatorBodyScope->setExpectedSuperBinding(expectedSuperBinding);
 
@@ -2138,7 +2258,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
     context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
     if (functionScope->strictMode() && functionInfo.name) {
-        RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode);
+        RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode || mode == SourceParseMode::GeneratorBodyMode || mode == SourceParseMode::GeneratorWrapperFunctionMode || isAsyncFunctionWrapperParseMode(mode));
         semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
         semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
     }
@@ -2225,6 +2345,35 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDecla
 }
 
 template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseAsyncFunctionDeclaration(TreeBuilder& context, ExportType exportType)
+{
+    ASSERT(match(FUNCTION));
+    JSTokenLocation location(tokenLocation());
+    unsigned functionKeywordStart = tokenStart();
+    next();
+    ParserFunctionInfo<TreeBuilder> functionInfo;
+    SourceParseMode parseMode = SourceParseMode::AsyncFunctionMode;
+
+    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this async function");
+    failIfFalse(functionInfo.name, "Async function statements must have a name");
+
+    std::pair<DeclarationResultMask, ScopeRef> functionDeclaration = declareFunction(functionInfo.name);
+    DeclarationResultMask declarationResult = functionDeclaration.first;
+    failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare an async function named '", functionInfo.name->impl(), "' in strict mode");
+    if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
+        internalFailWithMessage(false, "Cannot declare an async function that shadows a let/const/class/function variable '", functionInfo.name->impl(), "' in strict mode");
+    if (exportType == ExportType::Exported) {
+        semanticFailIfFalse(exportName(*functionInfo.name), "Cannot export a duplicate function name: '", functionInfo.name->impl(), "'");
+        currentScope()->moduleScopeData().exportBinding(*functionInfo.name);
+    }
+
+    TreeStatement result = context.createFuncDeclStatement(location, functionInfo);
+    if (TreeBuilder::CreatesAST)
+        functionDeclaration.second->appendFunction(getMetadata(functionInfo));
+    return result;
+}
+
+template <typename LexerType>
 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context, ExportType exportType)
 {
     ASSERT(match(CLASSTOKEN));
@@ -2322,8 +2471,12 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
         bool isGetter = false;
         bool isSetter = false;
         bool isGenerator = false;
+        bool isAsyncMethod = false;
+
         if (consume(TIMES))
             isGenerator = true;
+
+parseMethod:
         switch (m_token.m_type) {
         namedKeyword:
         case STRING:
@@ -2331,13 +2484,18 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
             ASSERT(ident);
             next();
             break;
+        case AWAIT:
         case IDENT:
             ident = m_token.m_data.ident;
             ASSERT(ident);
             next();
-            if (!isGenerator && (matchIdentifierOrKeyword() || match(STRING) || match(DOUBLE) || match(INTEGER) || match(OPENBRACKET))) {
+            if (!isGenerator && !isAsyncMethod && (matchIdentifierOrKeyword() || match(STRING) || match(DOUBLE) || match(INTEGER) || match(OPENBRACKET))) {
                 isGetter = *ident == propertyNames.get;
                 isSetter = *ident == propertyNames.set;
+                if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && !isAsyncMethod && *ident == propertyNames.async && !m_lexer->prevTerminator())) {
+                    isAsyncMethod = true;
+                    goto parseMethod;
+                }
             }
             break;
         case DOUBLE:
@@ -2369,7 +2527,12 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
             ParserFunctionInfo<TreeBuilder> methodInfo;
             bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
             SourceParseMode parseMode = SourceParseMode::MethodMode;
-            if (isGenerator) {
+            if (isAsyncMethod) {
+                isConstructor = false;
+                parseMode = SourceParseMode::AsyncMethodMode;
+                semanticFailIfTrue(*ident == m_vm->propertyNames->prototype, "Cannot declare an async method named 'prototype'");
+                semanticFailIfTrue(*ident == m_vm->propertyNames->constructor, "Cannot declare an async method named 'constructor'");
+            } else if (isGenerator) {
                 isConstructor = false;
                 parseMode = SourceParseMode::GeneratorWrapperFunctionMode;
                 semanticFailIfTrue(*ident == m_vm->propertyNames->prototype, "Cannot declare a generator named 'prototype'");
@@ -2453,9 +2616,11 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionOrL
             return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line);
         }
         const Identifier* ident = m_token.m_data.ident;
+        const bool isDisallowedLabelAwait = isDisallowedIdentifierAwait(m_token);
         JSTextPosition end = tokenEndPosition();
         next();
         consumeOrFail(COLON, "Labels must be followed by a ':'");
+        semanticFailIfTrue(isDisallowedLabelAwait, "Can't use 'await' as a label ", disallowedIdentifierAwaitReason());
         if (!m_syntaxAlreadyValidated) {
             // This is O(N^2) over the current list of consecutive labels, but I
             // have never seen more than one label in a row in the real world.
@@ -2648,7 +2813,7 @@ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerT
         failIfFalse(matchContextualKeyword(m_vm->propertyNames->as), "Expected 'as' before imported binding name");
         next();
 
-        matchOrFail(IDENT, "Expected a variable name for the import declaration");
+        failIfFalse(matchSpecIdentifier(), "Expected a variable name for the import declaration");
         localNameToken = m_token;
         localName = m_token.m_data.ident;
         next();
@@ -2670,7 +2835,7 @@ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerT
 
         if (matchContextualKeyword(m_vm->propertyNames->as)) {
             next();
-            matchOrFail(IDENT, "Expected a variable name for the import declaration");
+            failIfFalse(matchSpecIdentifier(), "Expected a variable name for the import declaration");
             localNameToken = m_token;
             localName = m_token.m_data.ident;
             next();
@@ -2681,7 +2846,7 @@ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerT
     case ImportSpecifierType::DefaultImport: {
         // ImportedDefaultBinding :
         // ImportedBinding
-        ASSERT(match(IDENT));
+        ASSERT(matchSpecIdentifier());
         localNameToken = m_token;
         localName = m_token.m_data.ident;
         importedName = &m_vm->propertyNames->defaultKeyword;
@@ -2691,6 +2856,7 @@ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerT
     }
 
     semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name");
+    semanticFailIfTrue(localNameToken.m_type == AWAIT, "Cannot use 'await' as an imported binding name");
     DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration, (specifierType == ImportSpecifierType::NamespaceImport) ? DeclarationImportType::ImportedNamespace : DeclarationImportType::Imported);
     if (declarationResult != DeclarationResult::Valid) {
         failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare an imported binding named ", localName->impl(), " in strict mode");
@@ -2720,7 +2886,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseImportDeclara
     }
 
     bool isFinishedParsingImport = false;
-    if (match(IDENT)) {
+    if (matchSpecIdentifier()) {
         // ImportedDefaultBinding :
         // ImportedBinding
         auto specifier = parseImportClauseItem(context, ImportSpecifierType::DefaultImport);
@@ -2830,8 +2996,17 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
         TreeStatement result = 0;
         bool isFunctionOrClassDeclaration = false;
         const Identifier* localName = nullptr;
+        bool isAsyncFunctionExport = false;
         SavePoint savePoint = createSavePoint();
 
+        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
+            next();
+            if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator()))
+                isAsyncFunctionExport = true;
+            else
+                restoreSavePoint(savePoint);
+        }
+
         bool startsWithFunction = match(FUNCTION);
         if (startsWithFunction || match(CLASSTOKEN)) {
             isFunctionOrClassDeclaration = true;
@@ -2849,7 +3024,11 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
             if (match(FUNCTION)) {
                 DepthManager statementDepth(&m_statementDepth);
                 m_statementDepth = 1;
-                result = parseFunctionDeclaration(context);
+                if (UNLIKELY(isAsyncFunctionExport)) {
+                    ASSERT(m_runtimeFlags.isAsyncAwaitEnabled());
+                    result = parseAsyncFunctionDeclaration(context);
+                } else
+                    result = parseFunctionDeclaration(context);
             } else {
                 ASSERT(match(CLASSTOKEN));
                 result = parseClassDeclaration(context);
@@ -2864,9 +3043,11 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
             //
             // In the above example, *default* is the invisible variable to the users.
             // We use the private symbol to represent the name of this variable.
+            ExpressionErrorClassifier classifier(this);
             JSTokenLocation location(tokenLocation());
             JSTextPosition start = tokenStartPosition();
             TreeExpression expression = parseAssignmentExpression(context);
+
             failIfFalse(expression, "Cannot parse expression");
 
             DeclarationResultMask declarationResult = declareVariable(&m_vm->propertyNames->starDefaultPrivateName, DeclarationType::ConstDeclaration);
@@ -2969,6 +3150,12 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
             break;
 
         default:
+            if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
+                next();
+                semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
+                result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
+                break;
+            }
             failWithMessage("Expected either a declaration or a variable statement");
             break;
         }
@@ -3039,10 +3226,10 @@ template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmen
     int initialNonLHSCount = m_parserState.nonLHSCount;
     bool maybeAssignmentPattern = match(OPENBRACE) || match(OPENBRACKET);
     bool wasOpenParen = match(OPENPAREN);
-    bool isValidArrowFunctionStart = match(OPENPAREN) || match(IDENT);
+    bool isValidArrowFunctionStart = match(OPENPAREN) || matchSpecIdentifier();
     SavePoint savePoint = createSavePoint();
     size_t usedVariablesSize = 0;
-    if (wasOpenParen) {
+    if (wasOpenParen || UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && matchContextualKeyword(m_vm->propertyNames->async))) {
         usedVariablesSize = currentScope()->currentUsedVariablesSize();
         currentScope()->pushUsedVariableSet();
     }
@@ -3057,10 +3244,17 @@ template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmen
         if (!lhs || isArrowFunctionToken) {
             SavePointWithError errorRestorationSavePoint = createSavePointForError();
             restoreSavePoint(savePoint);
+            bool isAsyncArrow = false;
+            if (UNLIKELY(classifier.indicatesPossibleAsyncArrowFunction())) {
+                ASSERT(m_runtimeFlags.isAsyncAwaitEnabled());
+                ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
+                next();
+                isAsyncArrow = !m_lexer->prevTerminator();
+            }
             if (isArrowFunctionParameters()) {
-                if (wasOpenParen)
+                if (wasOpenParen || isAsyncArrow)
                     currentScope()->revertToPreviousUsedVariables(usedVariablesSize);
-                return parseArrowFunctionExpression(context);
+                return parseArrowFunctionExpression(context, isAsyncArrow);
             }
             restoreSavePointWithError(errorRestorationSavePoint);
             if (isArrowFunctionToken)
@@ -3183,6 +3377,23 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseYieldExpress
 }
 
 template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseAwaitExpression(TreeBuilder& context)
+{
+    // AwaitExpression desugared to YieldExpression
+    ASSERT(match(AWAIT));
+    ASSERT(currentScope()->isAsyncFunction());
+    failIfTrue(m_parserState.functionParsePhase == FunctionParsePhase::Parameters, "Cannot use await expression within parameters");
+    JSTokenLocation location(tokenLocation());
+    JSTextPosition divotStart = tokenStartPosition();
+    next();
+    JSTextPosition argumentStart = tokenStartPosition();
+    TreeExpression argument = parseUnaryExpression(context);
+    failIfFalse(argument, "Failed to parse await expression");
+    const bool delegate = false;
+    return context.createYield(location, argument, delegate, divotStart, argumentStart, lastTokenEndPosition());
+}
+
+template <typename LexerType>
 template <class TreeBuilder> TreeExpression Parser<LexerType>::parseConditionalExpression(TreeBuilder& context)
 {
     JSTokenLocation location(tokenLocation());
@@ -3268,22 +3479,27 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
     bool wasIdent = false;
     bool isGenerator = false;
     bool isClassProperty = false;
+    bool isAsyncMethod = false;
+
     if (consume(TIMES))
         isGenerator = true;
+
+parseProperty:
     switch (m_token.m_type) {
     namedProperty:
+    case AWAIT:
     case IDENT:
         wasIdent = true;
         FALLTHROUGH;
     case STRING: {
         const Identifier* ident = m_token.m_data.ident;
         unsigned getterOrSetterStartOffset = tokenStart();
-        if (complete || (wasIdent && !isGenerator && (*ident == m_vm->propertyNames->get || *ident == m_vm->propertyNames->set)))
+        if (complete || (wasIdent && !isGenerator && (*ident == m_vm->propertyNames->get || *ident == m_vm->propertyNames->set || *ident == m_vm->propertyNames->async)))
             nextExpectIdentifier(LexerFlagsIgnoreReservedWords);
         else
             nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords);
 
-        if (!isGenerator && match(COLON)) {
+        if (!isGenerator && !isAsyncMethod && match(COLON)) {
             next();
             TreeExpression node = parseAssignmentExpressionOrPropagateErrorClass(context);
             failIfFalse(node, "Cannot parse expression for property declaration");
@@ -3292,11 +3508,12 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
         }
 
         if (match(OPENPAREN)) {
-            auto method = parsePropertyMethod(context, ident, isGenerator);
+            auto method = parsePropertyMethod(context, ident, isGenerator, isAsyncMethod);
             propagateError();
             return context.createProperty(ident, method, PropertyNode::Constant, PropertyNode::KnownDirect, complete, SuperBinding::Needed, isClassProperty);
         }
-        failIfTrue(isGenerator, "Expected a parenthesis for argument list");
+
+        failIfTrue(isGenerator || isAsyncMethod, "Expected a parenthesis for argument list");
 
         failIfFalse(wasIdent, "Expected an identifier as property name");
 
@@ -3318,6 +3535,11 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
             type = PropertyNode::Getter;
         else if (*ident == m_vm->propertyNames->set)
             type = PropertyNode::Setter;
+        else if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && !isGenerator && !isAsyncMethod && *ident == m_vm->propertyNames->async)) {
+            isAsyncMethod = true;
+            failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'");
+            goto parseProperty;
+        }
         else
             failWithMessage("Expected a ':' following the property name '", ident->impl(), "'");
         return parseGetterSetter(context, complete, type, getterOrSetterStartOffset, ConstructorKind::None, isClassProperty);
@@ -3329,11 +3551,11 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
 
         if (match(OPENPAREN)) {
             const Identifier& ident = m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), propertyName);
-            auto method = parsePropertyMethod(context, &ident, isGenerator);
+            auto method = parsePropertyMethod(context, &ident, isGenerator, isAsyncMethod);
             propagateError();
             return context.createProperty(&ident, method, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::Needed, isClassProperty);
         }
-        failIfTrue(isGenerator, "Expected a parenthesis for argument list");
+        failIfTrue(isGenerator || isAsyncMethod, "Expected a parenthesis for argument list");
 
         consumeOrFail(COLON, "Expected ':' after property name");
         TreeExpression node = parseAssignmentExpression(context);
@@ -3348,11 +3570,11 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
         handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
 
         if (match(OPENPAREN)) {
-            auto method = parsePropertyMethod(context, &m_vm->propertyNames->nullIdentifier, isGenerator);
+            auto method = parsePropertyMethod(context, &m_vm->propertyNames->nullIdentifier, isGenerator, isAsyncMethod);
             propagateError();
             return context.createProperty(propertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::KnownDirect, complete, SuperBinding::Needed, isClassProperty);
         }
-        failIfTrue(isGenerator, "Expected a parenthesis for argument list");
+        failIfTrue(isGenerator || isAsyncMethod, "Expected a parenthesis for argument list");
 
         consumeOrFail(COLON, "Expected ':' after property name");
         TreeExpression node = parseAssignmentExpression(context);
@@ -3367,12 +3589,12 @@ template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeB
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator)
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator, bool isAsync)
 {
     JSTokenLocation methodLocation(tokenLocation());
     unsigned methodStart = tokenStart();
     ParserFunctionInfo<TreeBuilder> methodInfo;
-    SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorWrapperFunctionMode : SourceParseMode::MethodMode;
+    SourceParseMode parseMode = isGenerator ? SourceParseMode::GeneratorWrapperFunctionMode : isAsync ? SourceParseMode::AsyncMethodMode : SourceParseMode::MethodMode;
     failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, FunctionDefinitionType::Method)), "Cannot parse this method");
     methodInfo.name = methodName;
     return context.createMethodDefinition(methodLocation, methodInfo);
@@ -3630,6 +3852,20 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseFunctionExpr
 }
 
 template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseAsyncFunctionExpression(TreeBuilder& context)
+{
+    ASSERT(match(FUNCTION));
+    JSTokenLocation location(tokenLocation());
+    unsigned functionKeywordStart = tokenStart();
+    next();
+    ParserFunctionInfo<TreeBuilder> functionInfo;
+    functionInfo.name = &m_vm->propertyNames->nullIdentifier;
+    SourceParseMode parseMode = SourceParseMode::AsyncFunctionMode;
+    failIfFalse(parseFunctionInfo(context, FunctionNoRequirements, parseMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Expression), "Cannot parse async function expression");
+    return context.createFunctionExpr(location, functionInfo);
+}
+
+template <typename LexerType>
 template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool& elementIsTail)
 {
     if (!isTemplateHead) {
@@ -3719,14 +3955,15 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpre
             currentScope()->setInnerArrowFunctionUsesThis();
         return context.createThisExpr(location);
     }
+    case AWAIT:
     case IDENT: {
     identifierExpression:
         JSTextPosition start = tokenStartPosition();
         const Identifier* ident = m_token.m_data.ident;
         JSTokenLocation location(tokenLocation());
         next();
-        if (UNLIKELY(match(ARROWFUNCTION)))
-            return 0;
+        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && match(FUNCTION) && !m_lexer->prevTerminator() && *ident == m_vm->propertyNames->async))
+            return parseAsyncFunctionExpression(context);
         currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident);
         m_parserState.lastIdentifier = ident;
         return context.createResolve(location, *ident, start, lastTokenEndPosition());
@@ -3899,6 +4136,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
             failDueToUnexpectedToken();
     }
 
+    bool baseIsAsyncKeyword = false;
     if (baseIsSuper) {
         ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
         semanticFailIfFalse(currentScope()->isFunction() || (closestOrdinaryFunctionScope->isEvalContext() && closestOrdinaryFunctionScope->expectedSuperBinding() == SuperBinding::Needed), "super is not valid in this context");
@@ -3916,10 +4154,23 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
                 semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super is not valid in this context");
             }
         }
-    } else if (!baseIsNewTarget)
+    } else if (!baseIsNewTarget) {
+        currentFunctionScope()->setNeedsSuperBinding();
+        const bool isAsync = matchContextualKeyword(m_vm->propertyNames->async);
         base = parsePrimaryExpression(context);
+        failIfFalse(base, "Cannot parse base expression");
+        if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && isAsync && context.isResolve(base) && !m_lexer->prevTerminator())) {
+            if (matchSpecIdentifier()) {
+                // AsyncArrowFunction
+                forceClassifyExpressionError(ErrorIndicatesAsyncArrowFunction);
+                return 0;
+            }
+            baseIsAsyncKeyword = true;
+        }
+    }
 
     failIfFalse(base, "Cannot parse base expression");
+
     while (true) {
         location = tokenLocation();
         switch (m_token.m_type) {
@@ -3952,6 +4203,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
             } else {
                 JSTextPosition expressionEnd = lastTokenEndPosition();
                 TreeArguments arguments = parseArguments(context);
+                if (UNLIKELY(baseIsAsyncKeyword && (!arguments || match(ARROWFUNCTION))))
+                    forceClassifyExpressionError(ErrorIndicatesAsyncArrowFunction);
                 failIfFalse(arguments, "Cannot parse call arguments");
                 if (baseIsSuper) {
                     ScopeRef functionScope = currentFunctionScope();
@@ -3997,6 +4250,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
             m_parserState.nonLHSCount = nonLHSCount;
             break;
         }
+
         default:
             goto endMemberExpression;
         }
@@ -4010,7 +4264,7 @@ endMemberExpression:
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrowFunctionExpression(TreeBuilder& context)
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrowFunctionExpression(TreeBuilder& context, bool isAsync)
 {
     JSTokenLocation location;
 
@@ -4018,7 +4272,9 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrowFunctio
     location = tokenLocation();
     ParserFunctionInfo<TreeBuilder> info;
     info.name = &m_vm->propertyNames->nullIdentifier;
-    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::ArrowFunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, FunctionDefinitionType::Expression)), "Cannot parse arrow function expression");
+    SourceParseMode parseMode = isAsync ? SourceParseMode::AsyncArrowFunctionMode : SourceParseMode::ArrowFunctionMode;
+
+    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, FunctionDefinitionType::Expression)), "Cannot parse arrow function expression");
 
     return context.createArrowFunctionExpr(location, info);
 }
@@ -4062,6 +4318,10 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpress
     bool modifiesExpr = false;
     bool requiresLExpr = false;
     unsigned lastOperator = 0;
+
+    if (UNLIKELY(m_runtimeFlags.isAsyncAwaitEnabled() && match(AWAIT) && currentFunctionScope()->isAsyncFunction()))
+        return parseAwaitExpression(context);
+
     while (isUnaryOp(m_token.m_type)) {
         if (strictMode()) {
             switch (m_token.m_type) {
@@ -4242,7 +4502,8 @@ template <typename LexerType> void Parser<LexerType>::printUnexpectedTokenText(W
     case INVALID_PRIVATE_NAME_ERRORTOK:
         out.print("Invalid private name '", getToken(), "'");
         return;
-            
+
+    case AWAIT:
     case IDENT:
         out.print("Unexpected identifier '", getToken(), "'");
         return;
index c700f07..ab6f11d 100644 (file)
@@ -33,6 +33,7 @@
 #include "ParserError.h"
 #include "ParserFunctionInfo.h"
 #include "ParserTokens.h"
+#include "RuntimeFlags.h"
 #include "SourceProvider.h"
 #include "SourceProviderCache.h"
 #include "SourceProviderCacheItem.h"
@@ -125,7 +126,7 @@ ALWAYS_INLINE static bool isEvalOrArgumentsIdentifier(const VM* vm, const Identi
 }
 ALWAYS_INLINE static bool isIdentifierOrKeyword(const JSToken& token)
 {
-    return token.m_type == IDENT || token.m_type & KeywordTokenFlag;
+    return token.m_type == IDENT || token.m_type == AWAIT || token.m_type & KeywordTokenFlag;
 }
 
 class ModuleScopeData : public RefCounted<ModuleScopeData> {
@@ -153,7 +154,7 @@ struct Scope {
     WTF_MAKE_NONCOPYABLE(Scope);
 
 public:
-    Scope(const VM* vm, bool isFunction, bool isGenerator, bool strictMode, bool isArrowFunction)
+    Scope(const VM* vm, bool isFunction, bool isGenerator, bool strictMode, bool isArrowFunction, bool isAsyncFunction)
         : m_vm(vm)
         , m_shadowsArguments(false)
         , m_usesEval(false)
@@ -168,6 +169,8 @@ public:
         , m_isGeneratorBoundary(false)
         , m_isArrowFunction(isArrowFunction)
         , m_isArrowFunctionBoundary(false)
+        , m_isAsyncFunction(isAsyncFunction)
+        , m_isAsyncFunctionBoundary(false)
         , m_isLexicalScope(false)
         , m_isFunctionBoundary(false)
         , m_isValidStrictMode(true)
@@ -255,6 +258,14 @@ public:
     void setSourceParseMode(SourceParseMode mode)
     {
         switch (mode) {
+        case SourceParseMode::AsyncArrowFunctionBodyMode:
+            setIsAsyncArrowFunctionBody();
+            break;
+
+        case SourceParseMode::AsyncFunctionBodyMode:
+            setIsAsyncFunctionBody();
+            break;
+
         case SourceParseMode::GeneratorBodyMode:
             setIsGenerator();
             break;
@@ -274,6 +285,15 @@ public:
             setIsArrowFunction();
             break;
 
+        case SourceParseMode::AsyncFunctionMode:
+        case SourceParseMode::AsyncMethodMode:
+            setIsAsyncFunction();
+            break;
+
+        case SourceParseMode::AsyncArrowFunctionMode:
+            setIsAsyncArrowFunction();
+            break;
+
         case SourceParseMode::ProgramMode:
             break;
 
@@ -288,6 +308,8 @@ public:
     bool isFunctionBoundary() const { return m_isFunctionBoundary; }
     bool isGenerator() const { return m_isGenerator; }
     bool isGeneratorBoundary() const { return m_isGeneratorBoundary; }
+    bool isAsyncFunction() const { return m_isAsyncFunction; }
+    bool isAsyncFunctionBoundary() const { return m_isAsyncFunctionBoundary; }
 
     bool hasArguments() const { return m_hasArguments; }
 
@@ -317,6 +339,11 @@ public:
         return *m_moduleScopeData;
     }
 
+    bool isModule() const
+    {
+        return !!m_moduleScopeData;
+    }
+
     void computeLexicallyCapturedVariablesAndPurgeCandidates()
     {
         // Because variables may be defined at any time in the range of a lexical scope, we must
@@ -699,6 +726,8 @@ private:
         m_isGeneratorBoundary = false;
         m_isArrowFunctionBoundary = false;
         m_isArrowFunction = false;
+        m_isAsyncFunctionBoundary = false;
+        m_isAsyncFunction = false;
     }
 
     void setIsGeneratorFunction()
@@ -722,6 +751,34 @@ private:
         m_isArrowFunction = true;
     }
 
+    void setIsAsyncArrowFunction()
+    {
+        setIsArrowFunction();
+        m_isAsyncFunction = true;
+    }
+
+    void setIsAsyncFunction()
+    {
+        setIsFunction();
+        m_isAsyncFunction = true;
+    }
+
+    void setIsAsyncFunctionBody()
+    {
+        setIsFunction();
+        m_hasArguments = false;
+        m_isAsyncFunction = true;
+        m_isAsyncFunctionBoundary = true;
+    }
+
+    void setIsAsyncArrowFunctionBody()
+    {
+        setIsArrowFunction();
+        m_hasArguments = false;
+        m_isAsyncFunction = true;
+        m_isAsyncFunctionBoundary = true;
+    }
+
     void setIsModule()
     {
         m_moduleScopeData = ModuleScopeData::create();
@@ -741,6 +798,8 @@ private:
     bool m_isGeneratorBoundary;
     bool m_isArrowFunction;
     bool m_isArrowFunctionBoundary;
+    bool m_isAsyncFunction;
+    bool m_isAsyncFunctionBoundary;
     bool m_isLexicalScope;
     bool m_isFunctionBoundary;
     bool m_isValidStrictMode;
@@ -814,7 +873,7 @@ class Parser {
     WTF_MAKE_FAST_ALLOCATED;
 
 public:
-    Parser(VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode, SuperBinding, ConstructorKind defaultConstructorKind = ConstructorKind::None, DerivedContextType = DerivedContextType::None, bool isEvalContext = false, EvalContextType = EvalContextType::None);
+    Parser(VM*, RuntimeFlags, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode, SuperBinding, ConstructorKind defaultConstructorKind = ConstructorKind::None, DerivedContextType = DerivedContextType::None, bool isEvalContext = false, EvalContextType = EvalContextType::None);
     ~Parser();
 
     template <class ParsedNode>
@@ -903,8 +962,9 @@ private:
     };
 
     enum ExpressionErrorClass {
-        ErrorIndicatesNothing,
-        ErrorIndicatesPattern
+        ErrorIndicatesNothing = 0,
+        ErrorIndicatesPattern,
+        ErrorIndicatesAsyncArrowFunction
     };
 
     struct ExpressionErrorClassifier {
@@ -928,6 +988,11 @@ private:
             m_class = classification;
         }
 
+        void forceClassifyExpressionError(ExpressionErrorClass classification)
+        {
+            m_class = classification;
+        }
+
         void reclassifyExpressionError(ExpressionErrorClass oldClassification, ExpressionErrorClass classification)
         {
             if (m_class != oldClassification)
@@ -937,12 +1002,12 @@ private:
 
         void propagateExpressionErrorClass()
         {
-            if (m_previous && m_class != ErrorIndicatesNothing)
+            if (m_previous)
                 m_previous->m_class = m_class;
         }
 
         bool indicatesPossiblePattern() const { return m_class == ErrorIndicatesPattern; }
-
+        bool indicatesPossibleAsyncArrowFunction() const { return m_class == ErrorIndicatesAsyncArrowFunction; }
     private:
         ExpressionErrorClass m_class;
         ExpressionErrorClassifier* m_previous;
@@ -955,6 +1020,12 @@ private:
             m_expressionErrorClassifier->classifyExpressionError(classification);
     }
 
+    ALWAYS_INLINE void forceClassifyExpressionError(ExpressionErrorClass classification)
+    {
+        if (m_expressionErrorClassifier)
+            m_expressionErrorClassifier->forceClassifyExpressionError(classification);
+    }
+
     ALWAYS_INLINE void reclassifyExpressionError(ExpressionErrorClass oldClassification, ExpressionErrorClass classification)
     {
         if (m_expressionErrorClassifier)
@@ -976,6 +1047,19 @@ private:
         return DestructuringKind::DestructureToVariables;
     }
 
+    ALWAYS_INLINE const char* declarationTypeToVariableKind(DeclarationType type)
+    {
+        switch (type) {
+        case DeclarationType::VarDeclaration:
+            return "variable name";
+        case DeclarationType::LetDeclaration:
+        case DeclarationType::ConstDeclaration:
+            return "lexical variable name";
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return "invalid";
+    }
+
     ALWAYS_INLINE AssignmentContext assignmentContextFromDeclarationType(DeclarationType type)
     {
         switch (type) {
@@ -1032,7 +1116,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].isArrowFunctionBoundary() || m_scopeStack[i].isAsyncFunctionBoundary()))
             i--;
         // When reaching the top level scope (it can be non ordinary function scope), we return it.
         return ScopeRef(&m_scopeStack, i);
@@ -1044,13 +1128,15 @@ private:
         bool isStrict = false;
         bool isGenerator = false;
         bool isArrowFunction = false;
+        bool isAsyncFunction = false;
         if (!m_scopeStack.isEmpty()) {
             isStrict = m_scopeStack.last().strictMode();
             isFunction = m_scopeStack.last().isFunction();
             isGenerator = m_scopeStack.last().isGenerator();
             isArrowFunction = m_scopeStack.last().isArrowFunction();
+            isAsyncFunction = m_scopeStack.last().isAsyncFunction();
         }
-        m_scopeStack.constructAndAppend(m_vm, isFunction, isGenerator, isStrict, isArrowFunction);
+        m_scopeStack.constructAndAppend(m_vm, isFunction, isGenerator, isStrict, isArrowFunction, isAsyncFunction);
         return currentScope();
     }
 
@@ -1062,7 +1148,7 @@ private:
         
         if (m_scopeStack.last().isArrowFunction())
             m_scopeStack.last().setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded();
-        
+
         if (!(m_scopeStack.last().isFunctionBoundary() && !m_scopeStack.last().isArrowFunctionBoundary()))
             m_scopeStack[m_scopeStack.size() - 2].mergeInnerArrowFunctionFeatures(m_scopeStack.last().innerArrowFunctionFeatures());
 
@@ -1359,7 +1445,7 @@ private:
     // http://ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions-static-semantics-early-errors
     ALWAYS_INLINE bool matchSpecIdentifier(bool inGenerator)
     {
-        return match(IDENT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator);
+        return match(IDENT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator) || match(AWAIT);
     }
 
     ALWAYS_INLINE bool matchSpecIdentifier()
@@ -1369,11 +1455,14 @@ private:
 
     template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
     template <class TreeBuilder> TreeSourceElements parseGeneratorFunctionSourceElements(TreeBuilder&, SourceElementsMode);
+    template <class TreeBuilder> TreeSourceElements parseAsyncFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode);
     template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
     template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
     enum class ExportType { Exported, NotExported };
     template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
     template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
+    template <class TreeBuilder> TreeStatement parseFunctionDeclarationStatement(TreeBuilder&, bool isAsync, bool parentAllowsFunctionDeclarationAsStatement);
+    template <class TreeBuilder> TreeStatement parseAsyncFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
     template <class TreeBuilder> TreeStatement parseVariableDeclaration(TreeBuilder&, DeclarationType, ExportType = ExportType::NotExported);
     template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
@@ -1400,23 +1489,25 @@ private:
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
+    template <class TreeBuilder> NEVER_INLINE TreeExpression parseAwaitExpression(TreeBuilder&);
     template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
     template <class TreeBuilder> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseFunctionExpression(TreeBuilder&);
+    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseAsyncFunctionExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArgument(TreeBuilder&, ArgumentType&);
     template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
-    template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator);
+    template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator, bool isAsyncMethod);
     template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind, bool isClassProperty);
     template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, SyntaxChecker&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, SuperBinding, FunctionBodyType, unsigned, SourceParseMode);
     template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, unsigned&);
     enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
     template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, ExportType, bool& forLoopConstDoesNotHaveInitializer);
     template <class TreeBuilder> TreeSourceElements parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder&);
-    template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
+    template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&, bool isAsync);
     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, JSToken, AssignmentContext, const Identifier** duplicateIdentifier);
     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createAssignmentElement(TreeBuilder&, TreeExpression&, const JSTextPosition&, const JSTextPosition&);
     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth);
@@ -1474,6 +1565,21 @@ private:
         return !m_errorMessage.isNull();
     }
 
+    bool isDisallowedIdentifierAwait(const JSToken& token)
+    {
+        return token.m_type == AWAIT && (currentScope()->isAsyncFunctionBoundary() || currentScope()->isModule() || !m_parserState.allowAwait);
+    }
+
+    const char* disallowedIdentifierAwaitReason()
+    {
+        if (!m_parserState.allowAwait || currentScope()->isAsyncFunctionBoundary())
+            return "in an async function";
+        if (currentScope()->isModule())
+            return "in a module";
+        RELEASE_ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+
     enum class FunctionParsePhase { Parameters, Body };
     struct ParserState {
         int assignmentCount { 0 };
@@ -1482,6 +1588,7 @@ private:
         FunctionParsePhase functionParsePhase { FunctionParsePhase::Body };
         const Identifier* lastIdentifier { nullptr };
         const Identifier* lastFunctionName { nullptr };
+        bool allowAwait { true };
     };
 
     // If you're using this directly, you probably should be using
@@ -1592,6 +1699,7 @@ private:
     bool m_hasStackOverflow;
     String m_errorMessage;
     JSToken m_token;
+    RuntimeFlags m_runtimeFlags;
     bool m_allowsIn;
     JSTextPosition m_lastTokenEndPosition;
     bool m_syntaxAlreadyValidated;
@@ -1724,7 +1832,7 @@ std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const I
 
 template <class ParsedNode>
 std::unique_ptr<ParsedNode> parse(
-    VM* vm, const SourceCode& source,
+    VM* vm, RuntimeFlags runtimeFlags, const SourceCode& source,
     const Identifier& name, JSParserBuiltinMode builtinMode,
     JSParserStrictMode strictMode, SourceParseMode parseMode, SuperBinding superBinding,
     ParserError& error, JSTextPosition* positionBeforeLastNewline = nullptr,
@@ -1732,7 +1840,7 @@ std::unique_ptr<ParsedNode> parse(
 {
     ASSERT(!source.provider()->source().isNull());
     if (source.provider()->source().is8Bit()) {
-        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType);
+        Parser<Lexer<LChar>> parser(vm, runtimeFlags, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType);
         std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
         if (positionBeforeLastNewline)
             *positionBeforeLastNewline = parser.positionBeforeLastNewline();
@@ -1743,7 +1851,7 @@ std::unique_ptr<ParsedNode> parse(
         return result;
     }
     ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string");
-    Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType);
+    Parser<Lexer<UChar>> parser(vm, runtimeFlags, source, builtinMode, strictMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType);
     std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
     if (positionBeforeLastNewline)
         *positionBeforeLastNewline = parser.positionBeforeLastNewline();
index d2571e5..06c5389 100644 (file)
@@ -27,6 +27,7 @@
 #ifndef ParserModes_h
 #define ParserModes_h
 
+#include "ConstructAbility.h"
 #include "Identifier.h"
 
 namespace JSC {
@@ -50,6 +51,11 @@ enum class SourceParseMode : uint8_t {
     SetterMode,
     MethodMode,
     ArrowFunctionMode,
+    AsyncFunctionBodyMode,
+    AsyncArrowFunctionBodyMode,
+    AsyncFunctionMode,
+    AsyncMethodMode,
+    AsyncArrowFunctionMode,
     ProgramMode,
     ModuleAnalyzeMode,
     ModuleEvaluateMode
@@ -65,6 +71,11 @@ inline bool isFunctionParseMode(SourceParseMode parseMode)
     case SourceParseMode::SetterMode:
     case SourceParseMode::MethodMode:
     case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
         return true;
 
     case SourceParseMode::ProgramMode:
@@ -76,6 +87,111 @@ inline bool isFunctionParseMode(SourceParseMode parseMode)
     return false;
 }
 
+inline bool isAsyncFunctionParseMode(SourceParseMode parseMode)
+{
+    switch (parseMode) {
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+        return true;
+
+    case SourceParseMode::NormalFunctionMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
+    case SourceParseMode::GetterMode:
+    case SourceParseMode::SetterMode:
+    case SourceParseMode::MethodMode:
+    case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::ModuleAnalyzeMode:
+    case SourceParseMode::ModuleEvaluateMode:
+    case SourceParseMode::ProgramMode:
+        return false;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
+inline bool isAsyncArrowFunctionParseMode(SourceParseMode parseMode)
+{
+    switch (parseMode) {
+    case SourceParseMode::AsyncArrowFunctionMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+        return true;
+
+    case SourceParseMode::NormalFunctionMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
+    case SourceParseMode::GetterMode:
+    case SourceParseMode::SetterMode:
+    case SourceParseMode::MethodMode:
+    case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::ModuleAnalyzeMode:
+    case SourceParseMode::ModuleEvaluateMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::ProgramMode:
+        return false;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
+inline bool isAsyncFunctionWrapperParseMode(SourceParseMode parseMode)
+{
+    switch (parseMode) {
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+        return true;
+
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+    case SourceParseMode::NormalFunctionMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
+    case SourceParseMode::GetterMode:
+    case SourceParseMode::SetterMode:
+    case SourceParseMode::MethodMode:
+    case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::ModuleAnalyzeMode:
+    case SourceParseMode::ModuleEvaluateMode:
+    case SourceParseMode::ProgramMode:
+        return false;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
+inline bool isAsyncFunctionBodyParseMode(SourceParseMode parseMode)
+{
+    switch (parseMode) {
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+        return true;
+
+    case SourceParseMode::NormalFunctionMode:
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
+    case SourceParseMode::GetterMode:
+    case SourceParseMode::SetterMode:
+    case SourceParseMode::MethodMode:
+    case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+    case SourceParseMode::ModuleAnalyzeMode:
+    case SourceParseMode::ModuleEvaluateMode:
+    case SourceParseMode::ProgramMode:
+        return false;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
 inline bool isModuleParseMode(SourceParseMode parseMode)
 {
     switch (parseMode) {
@@ -90,6 +206,11 @@ inline bool isModuleParseMode(SourceParseMode parseMode)
     case SourceParseMode::SetterMode:
     case SourceParseMode::MethodMode:
     case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
     case SourceParseMode::ProgramMode:
         return false;
     }
@@ -110,6 +231,11 @@ inline bool isProgramParseMode(SourceParseMode parseMode)
     case SourceParseMode::SetterMode:
     case SourceParseMode::MethodMode:
     case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
     case SourceParseMode::ModuleAnalyzeMode:
     case SourceParseMode::ModuleEvaluateMode:
         return false;
@@ -118,6 +244,34 @@ inline bool isProgramParseMode(SourceParseMode parseMode)
     return false;
 }
 
+inline ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode)
+{
+    switch (parseMode) {
+    case SourceParseMode::NormalFunctionMode:
+        return ConstructAbility::CanConstruct;
+
+    case SourceParseMode::GeneratorBodyMode:
+    case SourceParseMode::GeneratorWrapperFunctionMode:
+    case SourceParseMode::GetterMode:
+    case SourceParseMode::SetterMode:
+    case SourceParseMode::MethodMode:
+    case SourceParseMode::ArrowFunctionMode:
+    case SourceParseMode::AsyncFunctionBodyMode:
+    case SourceParseMode::AsyncArrowFunctionBodyMode:
+    case SourceParseMode::AsyncFunctionMode:
+    case SourceParseMode::AsyncMethodMode:
+    case SourceParseMode::AsyncArrowFunctionMode:
+        return ConstructAbility::CannotConstruct;
+
+    case SourceParseMode::ProgramMode:
+    case SourceParseMode::ModuleAnalyzeMode:
+    case SourceParseMode::ModuleEvaluateMode:
+        break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return ConstructAbility::CanConstruct;
+}
+
 inline bool functionNameIsInScope(const Identifier& name, FunctionMode functionMode)
 {
     if (name.isNull())
index aff4a30..e42d150 100644 (file)
@@ -113,6 +113,8 @@ enum JSTokenType {
     OREQUAL,
     DOTDOTDOT,
     ARROWFUNCTION,
+    // Untagged conditional keywords
+    AWAIT,
     LastUntaggedToken,
 
     // Begin tagged tokens
index ee8a50f..b32f245 100644 (file)
@@ -28,6 +28,7 @@
 #define SourceCodeKey_h
 
 #include "ParserModes.h"
+#include "RuntimeFlags.h"
 #include "SourceCode.h"
 #include <wtf/HashTraits.h>
 
@@ -66,11 +67,12 @@ public:
     {
     }
 
-    SourceCodeKey(const SourceCode& sourceCode, const String& name, SourceCodeType codeType, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DerivedContextType derivedContextType, EvalContextType evalContextType, bool isArrowFunctionContext)
+    SourceCodeKey(const SourceCode& sourceCode, const RuntimeFlags& runtimeFlags, const String& name, SourceCodeType codeType, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DerivedContextType derivedContextType, EvalContextType evalContextType, bool isArrowFunctionContext)
         : m_sourceCode(sourceCode)
         , m_name(name)
         , m_flags(codeType, builtinMode, strictMode, derivedContextType, evalContextType, isArrowFunctionContext)
         , m_hash(sourceCode.hash())
+        , m_runtimeFlags(runtimeFlags)
     {
     }
 
@@ -91,13 +93,16 @@ public:
     // providers cache their strings to make this efficient.
     StringView string() const { return m_sourceCode.view(); }
 
+    const RuntimeFlags& runtimeFlags() const { return m_runtimeFlags; }
+
     bool operator==(const SourceCodeKey& other) const
     {
         return m_hash == other.m_hash
             && length() == other.length()
             && m_flags == other.m_flags
             && m_name == other.m_name
-            && string() == other.string();
+            && string() == other.string()
+            && m_runtimeFlags == other.runtimeFlags();
     }
 
     struct Hash {
@@ -116,6 +121,7 @@ private:
     String m_name;
     SourceCodeFlags m_flags;
     unsigned m_hash;
+    RuntimeFlags m_runtimeFlags;
 };
 
 }
index bf0d8ff..92ae31a 100644 (file)
@@ -184,6 +184,7 @@ public:
     ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool, int, int, int) { return YieldExpr; }
     ClassExpression createClassExpr(const JSTokenLocation&, const ParserClassInfo<SyntaxChecker>&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
     ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
+    ExpressionType createAsyncFunctionBody(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
     int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool, InnerArrowFunctionCodeFeatures = NoInnerArrowFunctionFeatures) { return FunctionBodyResult; }
     ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
     ExpressionType createMethodDefinition(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp
new file mode 100644 (file)
index 0000000..55246f9
--- /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* asyncFunctionPrototype)
+{
+    Base::finishCreation(vm, "AsyncFunction");
+    putDirectWithoutTransition(vm, vm.propertyNames->prototype, asyncFunctionPrototype, DontEnum | DontDelete | ReadOnly);
+
+    // Number of arguments for constructor
+    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontDelete | 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..3c4afcf
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef AsyncFunctionConstructor_h
+#define AsyncFunctionConstructor_h
+
+#include "InternalFunction.h"
+
+namespace WTF {
+class TextPosition;
+}
+
+namespace JSC {
+
+class AsyncFunctionPrototype;
+
+class AsyncFunctionConstructor : public InternalFunction {
+public:
+    typedef InternalFunction Base;
+
+    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;
+    }
+
+    DECLARE_INFO;
+
+    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
+
+#endif // AsyncFunctionConstructor_h
diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp
new file mode 100644 (file)
index 0000000..9b814b7
--- /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.
+ */
+
+#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 {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(AsyncFunctionPrototype);
+
+const ClassInfo AsyncFunctionPrototype::s_info = { "AsyncFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(AsyncFunctionPrototype) };
+
+AsyncFunctionPrototype::AsyncFunctionPrototype(VM& vm, Structure* structure)
+    : 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..171af42
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef AsyncFunctionPrototype_h
+#define AsyncFunctionPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class AsyncFunctionPrototype : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+
+    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());
+    }
+
+    DECLARE_INFO;
+
+protected:
+    void finishCreation(VM&);
+
+private:
+    AsyncFunctionPrototype(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // AsyncFunctionPrototype_h
index 96bbd17..c31e27b 100644 (file)
@@ -81,11 +81,11 @@ template <> struct CacheTypes<UnlinkedModuleProgramCodeBlock> {
 };
 
 template <class UnlinkedCodeBlockType, class ExecutableType>
-UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
+UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, const RuntimeFlags& runtimeFlags, ExecutableType* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 {
     DerivedContextType derivedContextType = executable->derivedContextType();
     bool isArrowFunctionContext = executable->isArrowFunctionContext();
-    SourceCodeKey key(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, builtinMode, strictMode, derivedContextType, evalContextType, isArrowFunctionContext);
+    SourceCodeKey key(source, runtimeFlags, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, builtinMode, strictMode, derivedContextType, evalContextType, isArrowFunctionContext);
     SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
     // FIXME: We should do something smart for TDZ instead of just disabling caching.
     // https://bugs.webkit.org/show_bug.cgi?id=154010
@@ -104,7 +104,7 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
     }
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(
-        &vm, source, Identifier(), builtinMode, strictMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType);
+        &vm, runtimeFlags, source, Identifier(), builtinMode, strictMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType);
     if (!rootNode)
         return nullptr;
 
@@ -133,29 +133,29 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
     return unlinkedCodeBlock;
 }
 
-UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error)
+UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, const RuntimeFlags& runtimeFlags, ProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error)
 {
     VariableEnvironment emptyParentTDZVariables;
-    return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, builtinMode, strictMode, debuggerMode, error, EvalContextType::None, &emptyParentTDZVariables);
+    return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, runtimeFlags, executable, source, builtinMode, strictMode, debuggerMode, error, EvalContextType::None, &emptyParentTDZVariables);
 }
 
-UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
+UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, const RuntimeFlags& runtimeFlags, EvalExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 {
-    return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, builtinMode, strictMode, debuggerMode, error, evalContextType, variablesUnderTDZ);
+    return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, runtimeFlags, executable, source, builtinMode, strictMode, debuggerMode, error, evalContextType, variablesUnderTDZ);
 }
 
-UnlinkedModuleProgramCodeBlock* CodeCache::getModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, DebuggerMode debuggerMode, ParserError& error)
+UnlinkedModuleProgramCodeBlock* CodeCache::getModuleProgramCodeBlock(VM& vm, const RuntimeFlags& runtimeFlags, ModuleProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, DebuggerMode debuggerMode, ParserError& error)
 {
     VariableEnvironment emptyParentTDZVariables;
-    return getGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, builtinMode, JSParserStrictMode::Strict, debuggerMode, error, EvalContextType::None, &emptyParentTDZVariables);
+    return getGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, runtimeFlags, executable, source, builtinMode, JSParserStrictMode::Strict, debuggerMode, error, EvalContextType::None, &emptyParentTDZVariables);
 }
 
 // FIXME: There's no need to add the function's name to the key here. It's already in the source code.
-UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error)
+UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const RuntimeFlags& runtimeFlags, const Identifier& name, const SourceCode& source, ParserError& error)
 {
     bool isArrowFunctionContext = false;
     SourceCodeKey key(
-        source, name.string(), SourceCodeType::FunctionType,
+        source, runtimeFlags, name.string(), SourceCodeType::FunctionType,
         JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::NotStrict,
         DerivedContextType::None,
@@ -171,7 +171,7 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
 
     JSTextPosition positionBeforeLastNewline;
     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
-        &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+        &vm, runtimeFlags, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
         error, &positionBeforeLastNewline);
     if (!program) {
@@ -201,7 +201,9 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
     metadata->setEndPosition(positionBeforeLastNewline);
     // The Function constructor only has access to global variables, so no variables will be under TDZ.
     VariableEnvironment emptyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables, DerivedContextType::None);
+
+    ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode());
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, emptyTDZVariables, DerivedContextType::None);
 
     functionExecutable->setSourceURLDirective(source.provider()->sourceURL());
     functionExecutable->setSourceMappingURLDirective(source.provider()->sourceMappingURL());
index 529c489..2b64b3e 100644 (file)
@@ -49,6 +49,7 @@ class UnlinkedFunctionExecutable;
 class UnlinkedModuleProgramCodeBlock;
 class UnlinkedProgramCodeBlock;
 class VM;
+class RuntimeFlags;
 class VariableEnvironment;
 
 struct SourceCodeValue {
@@ -187,10 +188,10 @@ public:
     CodeCache();
     ~CodeCache();
 
-    UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ParserError&);
-    UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ParserError&, EvalContextType, const VariableEnvironment*);
-    UnlinkedModuleProgramCodeBlock* getModuleProgramCodeBlock(VM&, ModuleProgramExecutable*, const SourceCode&, JSParserBuiltinMode, DebuggerMode, ParserError&);
-    UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&);
+    UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, const RuntimeFlags&, ProgramExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ParserError&);
+    UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, const RuntimeFlags&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ParserError&, EvalContextType, const VariableEnvironment*);
+    UnlinkedModuleProgramCodeBlock* getModuleProgramCodeBlock(VM&, const RuntimeFlags&, ModuleProgramExecutable*, const SourceCode&, JSParserBuiltinMode, DebuggerMode, ParserError&);
+    UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const RuntimeFlags&, const Identifier&, const SourceCode&, ParserError&);
 
     void clear()
     {
@@ -199,7 +200,7 @@ public:
 
 private:
     template <class UnlinkedCodeBlockType, class ExecutableType> 
-    UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ParserError&, EvalContextType, const VariableEnvironment*);
+    UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, const RuntimeFlags&, ExecutableType*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ParserError&, EvalContextType, const VariableEnvironment*);
 
     CodeCacheMap m_sourceCode;
 };
index 1d32539..642e7ef 100644 (file)
     macro(arguments) \
     macro(as) \
     macro(assign) \
+    macro(async) \
     macro(back) \
     macro(bind) \
     macro(blur) \
     macro(year)
 
 #define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
+    macro(await) \
     macro(break) \
     macro(case) \
     macro(catch) \
index dec5553..ce742af 100644 (file)
@@ -39,6 +39,7 @@
 #include "ModuleAnalyzer.h"
 #include "ModuleLoaderObject.h"
 #include "Parser.h"
+#include "RuntimeFlags.h"
 #include "ScriptProfilingScope.h"
 #include <wtf/WTFThreadData.h>
 
@@ -60,12 +61,12 @@ bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedExc
     return true;
 }
     
-bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error)
+bool checkSyntax(VM& vm, const RuntimeFlags& runtimeFlags, const SourceCode& source, ParserError& error)
 {
     JSLockHolder lock(vm);
     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
     return !!parse<ProgramNode>(
-        &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+        &vm, runtimeFlags, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
 }
 
@@ -75,7 +76,7 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e
     JSLockHolder lock(vm);
     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
-        &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+        &vm, exec->lexicalGlobalObject()->runtimeFlags(), source, Identifier(), JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
     if (!moduleProgramNode)
         return false;
index f131cc5..b9d90af 100644 (file)
@@ -33,11 +33,12 @@ class Exception;
 class ExecState;
 class JSObject;
 class ParserError;
+class RuntimeFlags;
 class SourceCode;
 class VM;
 class JSInternalPromise;
 
-JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&);
+JS_EXPORT_PRIVATE bool checkSyntax(VM&, const RuntimeFlags&, const SourceCode&, ParserError&);
 JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
 JS_EXPORT_PRIVATE bool checkModuleSyntax(ExecState*, const SourceCode&, ParserError&);
 
index 49d9f98..b1de99f 100644 (file)
@@ -314,7 +314,7 @@ CodeBlock* ScriptExecutable::newCodeBlockFor(
     DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
     UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 
         executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
-            *vm, executable->m_source, kind, debuggerMode, error, 
+            *vm, globalObject->runtimeFlags(), executable->m_source, kind, debuggerMode, error, 
             executable->parseMode());
     recordParse(
         executable->m_unlinkedExecutable->features(), 
@@ -569,7 +569,7 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
     VM* vm = &exec->vm();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
     std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>(
-        vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin, 
+        vm, lexicalGlobalObject->runtimeFlags(), m_source, Identifier(), JSParserBuiltinMode::NotBuiltin, 
         JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
     if (programNode)
         return 0;
index b79a59b..ecce274 100644 (file)
@@ -652,6 +652,7 @@ public:
     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
     bool isClass() const { return !classSource().isNull(); }
     bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
+    bool isAsyncFunction() const { return isAsyncFunctionParseMode(parseMode()); }
     bool isGetter() const { return parseMode() == SourceParseMode::GetterMode; }
     bool isSetter() const { return parseMode() == SourceParseMode::SetterMode; }
     DerivedContextType derivedContextType() const { return m_unlinkedExecutable->derivedContextType(); }
index d439066..98d6304 100644 (file)
@@ -95,14 +95,18 @@ JSObject* constructFunctionSkippingEvalEnabledCheck(
     // 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("{", functionConstructionMode == FunctionConstructionMode::Async ? "async function " : "function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", 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("{", functionConstructionMode == FunctionConstructionMode::Async ? "async function " : "function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
     else {
         StringBuilder builder;
-        builder.appendLiteral("{function ");
-        if (functionConstructionMode == FunctionConstructionMode::Generator)
-            builder.append('*');
+        if (functionConstructionMode == FunctionConstructionMode::Async)
+            builder.appendLiteral("{async function ");
+        else {
+            builder.appendLiteral("{function ");
+            if (functionConstructionMode == FunctionConstructionMode::Generator)
+                builder.append('*');
+        }
         builder.append(functionName.string());
         builder.append('(');
         builder.append(args.at(0).toString(exec)->view(exec).get());
index 63bc408..54c12f4 100644 (file)
@@ -59,6 +59,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());
diff --git a/Source/JavaScriptCore/runtime/JSAsyncFunction.cpp b/Source/JavaScriptCore/runtime/JSAsyncFunction.cpp
new file mode 100644 (file)
index 0000000..d349096
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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)
+    : Base(vm, executable, scope, scope->globalObject()->asyncFunctionStructure())
+{
+}
+
+JSAsyncFunction* JSAsyncFunction::createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    JSAsyncFunction* asyncFunction = new (NotNull, allocateCell<JSAsyncFunction>(vm.heap)) JSAsyncFunction(vm, executable, scope);
+    ASSERT(asyncFunction->structure()->globalObject());
+    asyncFunction->finishCreation(vm);
+    return asyncFunction;
+}
+
+JSAsyncFunction* JSAsyncFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+    JSAsyncFunction* asyncFunction = createImpl(vm, executable, scope);
+    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);
+}
+
+} // namespace JSC
+
+
diff --git a/Source/JavaScriptCore/runtime/JSAsyncFunction.h b/Source/JavaScriptCore/runtime/JSAsyncFunction.h
new file mode 100644 (file)
index 0000000..e9959ec
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef JSAsyncFunction_h
+#define JSAsyncFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+class LLIntDesiredOffsets;
+
+class JSAsyncFunction : public JSFunction {
+    friend class JIT;
+#if ENABLE(DFG_JIT)
+    friend class DFG::SpeculativeJIT;
+    friend class DFG::JITCompiler;
+#endif
+    friend class VM;
+public:
+    typedef JSFunction Base;
+
+    const static unsigned StructureFlags = Base::StructureFlags;
+
+    DECLARE_EXPORT_INFO;
+
+    static JSAsyncFunction* create(VM&, FunctionExecutable*, JSScope*);
+    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*);
+
+    static JSAsyncFunction* createImpl(VM&, FunctionExecutable*, JSScope*);
+
+    friend class LLIntOffsetsExtractor;
+};
+
+} // namespace JSC
+
+#endif // JSAsyncFunction_h
index ae30dcc..3174abc 100644 (file)
@@ -351,7 +351,7 @@ bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyN
     if (thisObject->isHostOrBuiltinFunction())
         return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
 
-    if (propertyName == exec->propertyNames().prototype && !thisObject->jsExecutable()->isArrowFunction()) {
+    if (propertyName == exec->propertyNames().prototype && !thisObject->jsExecutable()->isArrowFunction() && !thisObject->jsExecutable()->isAsyncFunction()) {
         VM& vm = exec->vm();
         unsigned attributes;
         PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
index 7a5b05c..40ea889 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"
@@ -64,6 +66,7 @@
 #include "JSArrayBufferConstructor.h"
 #include "JSArrayBufferPrototype.h"
 #include "JSArrayIterator.h"
+#include "JSAsyncFunction.h"
 #include "JSBoundFunction.h"
 #include "JSBoundSlotBaseFunction.h"
 #include "JSCInlines.h"
@@ -612,6 +615,11 @@ m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->c
             init.set(NativeErrorConstructor::create(init.vm, init.owner, init.owner->m_nativeErrorStructure.get(), init.owner->m_nativeErrorPrototypeStructure.get(), ASCIILiteral("URIError")));
         });
 
+    m_asyncFunctionPrototype.set(vm, this, AsyncFunctionPrototype::create(vm, AsyncFunctionPrototype::createStructure(vm, this, m_functionPrototype.get())));
+    AsyncFunctionConstructor* asyncFunctionConstructor = AsyncFunctionConstructor::create(vm, AsyncFunctionConstructor::createStructure(vm, this, functionConstructor), m_asyncFunctionPrototype.get());
+    m_asyncFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, asyncFunctionConstructor, DontEnum | ReadOnly);
+    m_asyncFunctionStructure.set(vm, this, JSAsyncFunction::createStructure(vm, this, m_asyncFunctionPrototype.get()));
+
     m_generatorFunctionPrototype.set(vm, this, GeneratorFunctionPrototype::create(vm, GeneratorFunctionPrototype::createStructure(vm, this, m_functionPrototype.get())));
     GeneratorFunctionConstructor* generatorFunctionConstructor = GeneratorFunctionConstructor::create(vm, GeneratorFunctionConstructor::createStructure(vm, this, functionConstructor), m_generatorFunctionPrototype.get());
     m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, generatorFunctionConstructor, DontEnum);
@@ -764,6 +772,8 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
         GlobalPropertyInfo(vm.propertyNames->builtinNames().generatorResumePrivateName(), JSFunction::createBuiltinFunction(vm, generatorPrototypeGeneratorResumeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().thisTimeValuePrivateName(), privateFuncThisTimeValue, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().thisNumberValuePrivateName(), privateFuncThisNumberValue, DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().asyncFunctionResumePrivateName(), JSFunction::createBuiltinFunction(vm, asyncFunctionPrototypeAsyncFunctionResumeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+
 #if ENABLE(INTL)
         GlobalPropertyInfo(vm.propertyNames->builtinNames().CollatorPrivateName(), intl->getDirect(vm, vm.propertyNames->Collator), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().DateTimeFormatPrivateName(), intl->getDirect(vm, vm.propertyNames->DateTimeFormat), DontEnum | DontDelete | ReadOnly),
@@ -1216,7 +1226,7 @@ UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* call
     JSParserStrictMode strictMode = executable->isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
     DebuggerMode debuggerMode = hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
     UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getProgramCodeBlock(
-        vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, 
+        vm(), runtimeFlags(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, 
         debuggerMode, error);
 
     if (hasDebugger())
@@ -1238,7 +1248,7 @@ UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame,
     EvalContextType evalContextType = executable->executableInfo().evalContextType();
     
     UnlinkedEvalCodeBlock* unlinkedCodeBlock = vm().codeCache()->getEvalCodeBlock(
-        vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, debuggerMode, error, evalContextType, variablesUnderTDZ);
+        vm(), runtimeFlags(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, debuggerMode, error, evalContextType, variablesUnderTDZ);
 
     if (hasDebugger())
         debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
@@ -1256,7 +1266,7 @@ UnlinkedModuleProgramCodeBlock* JSGlobalObject::createModuleProgramCodeBlock(Cal
     ParserError error;
     DebuggerMode debuggerMode = hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
     UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getModuleProgramCodeBlock(
-        vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, debuggerMode, error);
+        vm(), runtimeFlags(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, debuggerMode, error);
 
     if (hasDebugger())
         debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
index e952342..0d5e9d6 100644 (file)
@@ -56,6 +56,7 @@ class JSGlobalObjectInspectorController;
 namespace JSC {
 
 class ArrayPrototype;
+class AsyncFunctionPrototype;
 class BooleanPrototype;
 class ConsoleClient;
 class Debugger;
@@ -256,6 +257,7 @@ public:
     WriteBarrier<ObjectPrototype> m_objectPrototype;
     WriteBarrier<FunctionPrototype> m_functionPrototype;
     WriteBarrier<ArrayPrototype> m_arrayPrototype;
+    WriteBarrier<AsyncFunctionPrototype> m_asyncFunctionPrototype;
     WriteBarrier<RegExpPrototype> m_regExpPrototype;
     WriteBarrier<IteratorPrototype> m_iteratorPrototype;
     WriteBarrier<GeneratorFunctionPrototype> m_generatorFunctionPrototype;
@@ -297,6 +299,7 @@ public:
     PropertyOffset m_functionNameOffset;
     WriteBarrier<Structure> m_privateNameStructure;
     WriteBarrier<Structure> m_regExpStructure;
+    WriteBarrier<Structure> m_asyncFunctionStructure;
     WriteBarrier<Structure> m_generatorFunctionStructure;
     WriteBarrier<Structure> m_dollarVMStructure;
     WriteBarrier<Structure> m_iteratorResultObjectStructure;
@@ -501,6 +504,7 @@ public:
     ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
     FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
     ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
+    AsyncFunctionPrototype* asyncFunctionPrototype() const { return m_asyncFunctionPrototype.get(); }
     JSObject* booleanPrototype() const { return m_booleanObjectStructure.prototype(this); }
     StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
     SymbolPrototype* symbolPrototype() const { return m_symbolPrototype.get(); }
@@ -569,6 +573,7 @@ public:
     Structure* privateNameStructure() const { return m_privateNameStructure.get(); }
     Structure* mapStructure() const { return m_mapStructure.get(); }
     Structure* regExpStructure() const { return m_regExpStructure.get(); }
+    Structure* asyncFunctionStructure() const { return m_asyncFunctionStructure.get(); }
     Structure* generatorFunctionStructure() const { return m_generatorFunctionStructure.get(); }
     Structure* setStructure() const { return m_setStructure.get(this); }
     Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
index 20a4a6a..5555d0b 100644 (file)
@@ -275,7 +275,7 @@ EncodedJSValue JSC_HOST_CALL moduleLoaderObjectParseModule(ExecState* exec)
 
     ParserError error;
     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
-        &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
+        &vm, exec->vmEntryGlobalObject()->runtimeFlags(), sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
 
     if (error.isValid()) {
index 8cd30c6..25a777c 100644 (file)
@@ -30,8 +30,9 @@
 
 namespace JSC {
 
-// macro(name, isEnabledFlag)
-#define JSC_RUNTIME_FLAG(macro)
+// macro(name, flagName, isEnabledFlag)
+#define JSC_RUNTIME_FLAG(macro) \
+    macro(AsyncAwaitEnabled, true)
 
 class RuntimeFlags {
 private:
@@ -90,6 +91,16 @@ public:
         );
     }
 
+    bool operator==(const RuntimeFlags& other) const
+    {
+        return m_flags == other.m_flags;
+    }
+
+    bool operator!=(const RuntimeFlags& other) const
+    {
+        return m_flags != other.m_flags;
+    }
+
 private:
     unsigned m_flags;
 };
diff --git a/Source/JavaScriptCore/tests/stress/async-await-basic.js b/Source/JavaScriptCore/tests/stress/async-await-basic.js
new file mode 100644 (file)
index 0000000..cdf79c7
--- /dev/null
@@ -0,0 +1,299 @@
+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 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/Source/JavaScriptCore/tests/stress/async-await-module-reserved-word.js b/Source/JavaScriptCore/tests/stress/async-await-module-reserved-word.js
new file mode 100644 (file)
index 0000000..eb2562c
--- /dev/null
@@ -0,0 +1,69 @@
+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/Source/JavaScriptCore/tests/stress/async-await-mozilla.js b/Source/JavaScriptCore/tests/stress/async-await-mozilla.js
new file mode 100644 (file)
index 0000000..eac71aa
--- /dev/null
@@ -0,0 +1,304 @@
+/* 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/. */
+
+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 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) {}");
+
+})();
diff --git a/Source/JavaScriptCore/tests/stress/async-await-reserved-word.js b/Source/JavaScriptCore/tests/stress/async-await-reserved-word.js
new file mode 100644 (file)
index 0000000..9c9f104
--- /dev/null
@@ -0,0 +1,163 @@
+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.");
diff --git a/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_arguments_binding.js b/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_arguments_binding.js
new file mode 100644 (file)
index 0000000..1c6764a
--- /dev/null
@@ -0,0 +1,44 @@
+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));
diff --git a/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_new.target_binding.js b/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_new.target_binding.js
new file mode 100644 (file)
index 0000000..36df0a3
--- /dev/null
@@ -0,0 +1,52 @@
+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/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_super_binding.js b/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_super_binding.js
new file mode 100644 (file)
index 0000000..a000463
--- /dev/null
@@ -0,0 +1,50 @@
+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(); }
+    }
+}
+
+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/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_this_binding.js b/Source/JavaScriptCore/tests/stress/async_arrow_functions_lexical_this_binding.js
new file mode 100644 (file)
index 0000000..3d06682
--- /dev/null
@@ -0,0 +1,27 @@
+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"));
index cd18935..65e9475 100644 (file)
@@ -1,3 +1,12 @@
+2016-05-27  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] implement async functions proposal
+        https://bugs.webkit.org/show_bug.cgi?id=156147
+
+        Reviewed by Yusuke Suzuki.
+
+        * WebView/WebPreferencesPrivate.h:
+
 2016-05-26  Darin Adler  <darin@apple.com>
 
         Media queries and platform screen modernization and streamlining
index 23994a6..40ce4d0 100644 (file)
@@ -53,6 +53,7 @@ typedef enum {
 } WebStorageBlockingPolicy;
 
 typedef enum {
+    WebKitJavaScriptRuntimeFlagsAsyncAwaitEnabled = 1u << 0,
     WebKitJavaScriptRuntimeFlagsAllEnabled = 0
 } WebKitJavaScriptRuntimeFlags;
 
index db8b671..611fdfb 100644 (file)
@@ -1,3 +1,12 @@
+2016-05-27  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] implement async functions proposal
+        https://bugs.webkit.org/show_bug.cgi?id=156147
+
+        Reviewed by Yusuke Suzuki.
+
+        * Interfaces/IWebPreferencesPrivate.idl:
+
 2016-05-23  Chris Dumez  <cdumez@apple.com>
 
         Generate bindings code for EventTarget.addEventListener() / removeEventListener()
index 16af296..cdd1689 100644 (file)
@@ -32,6 +32,7 @@ import "ocidl.idl";
 #endif
 
 typedef enum WebKitJavaScriptRuntimeFlags {
+    WebKitJavaScriptRuntimeFlagsAsyncAwaitEnabled = 1, // 1u << 0
     WebKitJavaScriptRuntimeFlagsAllEnabled = 0
 } WebKitJavaScriptRuntimeFlags;
 
index c15edcd..ea0cc90 100644 (file)
@@ -1,3 +1,13 @@
+2016-05-27  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] implement async functions proposal
+        https://bugs.webkit.org/show_bug.cgi?id=156147
+
+        Reviewed by Yusuke Suzuki.
+
+        * UIProcess/API/C/WKPreferencesRefPrivate.h:
+        * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+
 2016-05-27  Chris Dumez  <cdumez@apple.com>
 
         Improve lambda capture in NetworkCache::Storage::synchronize()
index 5e09f66..2427223 100644 (file)
@@ -50,6 +50,7 @@ enum WKEditableLinkBehavior {
 typedef enum WKEditableLinkBehavior WKEditableLinkBehavior;
 
 enum WKJavaScriptRuntimeFlags {
+    kWKJavaScriptRuntimeFlagsAsyncAwaitEnabled = 1 << 0,
     kWKJavaScriptRuntimeFlagsAllEnabled = 0
 };
 typedef unsigned WKJavaScriptRuntimeFlagSet;
index af8dde3..d016010 100644 (file)
@@ -43,6 +43,7 @@ typedef NS_OPTIONS(NSUInteger, _WKDebugOverlayRegions) {
 } WK_ENUM_AVAILABLE(10_11, 9_0);
 
 typedef NS_OPTIONS(NSUInteger, _WKJavaScriptRuntimeFlags) {
+    _WKJavaScriptRuntimeFlagsAsyncAwaitEnabled = 1 << 0,
     _WKJavaScriptRuntimeFlagsAllEnabled = 0
 } WK_ENUM_AVAILABLE(10_11, 9_0);