[esnext] prototype runtime implementation for async functions
BUG=v8:4483
LOG=N
R=littledan@chromium.org, adamk@chromium.org
Review-Url: https://codereview.chromium.org/1895603002
Cr-Commit-Position: refs/heads/master@{#36263}
diff --git a/BUILD.gn b/BUILD.gn
index 911a7c4..b6a0415 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -421,6 +421,7 @@
sources = [
"src/js/macros.py",
"src/messages.h",
+ "src/js/harmony-async-await.js",
"src/js/harmony-atomics.js",
"src/js/harmony-regexp-exec.js",
"src/js/harmony-sharedarraybuffer.js",
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 0575536..8461bef 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -163,6 +163,7 @@
void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
void CreateIteratorMaps(Handle<JSFunction> empty);
+ void CreateAsyncFunctionMaps(Handle<JSFunction> empty);
void CreateJSProxyMaps();
// Make the "arguments" and "caller" properties throw a TypeError on access.
@@ -806,6 +807,32 @@
*generator_object_prototype_map);
}
+void Genesis::CreateAsyncFunctionMaps(Handle<JSFunction> empty) {
+ // %AsyncFunctionPrototype% intrinsic
+ Handle<JSObject> async_function_prototype =
+ factory()->NewJSObject(isolate()->object_function(), TENURED);
+ SetObjectPrototype(async_function_prototype, empty);
+
+ JSObject::AddProperty(async_function_prototype,
+ factory()->to_string_tag_symbol(),
+ factory()->NewStringFromAsciiChecked("AsyncFunction"),
+ static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
+
+ Handle<Map> strict_function_map(
+ native_context()->strict_function_without_prototype_map());
+ Handle<Map> sloppy_async_function_map =
+ Map::Copy(strict_function_map, "SloppyAsyncFunction");
+ sloppy_async_function_map->set_is_constructor(false);
+ Map::SetPrototype(sloppy_async_function_map, async_function_prototype);
+ native_context()->set_sloppy_async_function_map(*sloppy_async_function_map);
+
+ Handle<Map> strict_async_function_map =
+ Map::Copy(strict_function_map, "StrictAsyncFunction");
+ strict_async_function_map->set_is_constructor(false);
+ Map::SetPrototype(strict_async_function_map, async_function_prototype);
+ native_context()->set_strict_async_function_map(*strict_async_function_map);
+}
+
void Genesis::CreateJSProxyMaps() {
// Allocate the different maps for all Proxy types.
// Next to the default proxy, we need maps indicating callable and
@@ -2411,6 +2438,42 @@
script_is_embedder_debug_script, attribs);
script_map->AppendDescriptor(&d);
}
+
+ {
+ PrototypeIterator iter(native_context->sloppy_async_function_map());
+ Handle<JSObject> async_function_prototype(iter.GetCurrent<JSObject>());
+
+ static const bool kUseStrictFunctionMap = true;
+ Handle<JSFunction> async_function_constructor = InstallFunction(
+ container, "AsyncFunction", JS_FUNCTION_TYPE, JSFunction::kSize,
+ async_function_prototype, Builtins::kAsyncFunctionConstructor,
+ kUseStrictFunctionMap);
+ async_function_constructor->set_prototype_or_initial_map(
+ native_context->sloppy_async_function_map());
+ async_function_constructor->shared()->DontAdaptArguments();
+ async_function_constructor->shared()->set_construct_stub(
+ *isolate->builtins()->AsyncFunctionConstructor());
+ async_function_constructor->shared()->set_length(1);
+ InstallWithIntrinsicDefaultProto(isolate, async_function_constructor,
+ Context::ASYNC_FUNCTION_FUNCTION_INDEX);
+
+ JSObject::AddProperty(
+ async_function_prototype, factory->constructor_string(),
+ async_function_constructor,
+ static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
+
+ JSFunction::SetPrototype(async_function_constructor,
+ async_function_prototype);
+
+ Handle<JSFunction> async_function_next =
+ SimpleInstallFunction(container, "AsyncFunctionNext",
+ Builtins::kGeneratorPrototypeNext, 2, false);
+ Handle<JSFunction> async_function_throw =
+ SimpleInstallFunction(container, "AsyncFunctionThrow",
+ Builtins::kGeneratorPrototypeThrow, 2, false);
+ async_function_next->shared()->set_native(true);
+ async_function_throw->shared()->set_native(true);
+ }
}
}
@@ -3031,7 +3094,8 @@
static const char* icu_case_mapping_natives[] = {"native icu-case-mapping.js",
nullptr};
#endif
- static const char* harmony_async_await_natives[] = {nullptr};
+ static const char* harmony_async_await_natives[] = {
+ "native harmony-async-await.js", nullptr};
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
@@ -3627,6 +3691,7 @@
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
CreateStrictModeFunctionMaps(empty_function);
CreateIteratorMaps(empty_function);
+ CreateAsyncFunctionMaps(empty_function);
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
diff --git a/src/builtins.cc b/src/builtins.cc
index 20d00bb..77d4b3a 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -4223,6 +4223,13 @@
return *result;
}
+BUILTIN(AsyncFunctionConstructor) {
+ HandleScope scope(isolate);
+ Handle<JSFunction> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result, CreateDynamicFunction(isolate, args, "async function"));
+ return *result;
+}
// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case.
BUILTIN(SymbolConstructor) {
diff --git a/src/builtins.h b/src/builtins.h
index 4414351..0c0891a 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -114,6 +114,7 @@
V(FunctionPrototypeToString, kNone) \
\
V(GeneratorFunctionConstructor, kTargetAndNewTarget) \
+ V(AsyncFunctionConstructor, kTargetAndNewTarget) \
\
V(GlobalEval, kTarget) \
\
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 22595e0..a421b61 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -1023,7 +1023,7 @@
private:
STATIC_ASSERT(LANGUAGE_END == 3);
class LanguageModeBits : public BitField<LanguageMode, 0, 2> {};
- class FunctionKindBits : public BitField<FunctionKind, 2, 8> {};
+ class FunctionKindBits : public BitField<FunctionKind, 2, 9> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);
diff --git a/src/compiler.cc b/src/compiler.cc
index 87ff9ea..92c48b6 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -430,7 +430,7 @@
bool UseIgnition(CompilationInfo* info) {
if (info->is_debug()) return false;
- if (info->shared_info()->is_generator() && !FLAG_ignition_generators) {
+ if (info->shared_info()->is_resumable() && !FLAG_ignition_generators) {
return false;
}
diff --git a/src/contexts.h b/src/contexts.h
index 40d5f20..6950712 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -90,51 +90,54 @@
V(MATH_FLOOR, JSFunction, math_floor) \
V(MATH_SQRT, JSFunction, math_sqrt)
-#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
- V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
- V(ARRAY_POP_INDEX, JSFunction, array_pop) \
- V(ARRAY_PUSH_INDEX, JSFunction, array_push) \
- V(ARRAY_SHIFT_INDEX, JSFunction, array_shift) \
- V(ARRAY_SPLICE_INDEX, JSFunction, array_splice) \
- V(ARRAY_SLICE_INDEX, JSFunction, array_slice) \
- V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
- V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
- V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
- V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
- V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
- V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
- V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
- V(JSON_SERIALIZE_ADAPTER_INDEX, JSFunction, json_serialize_adapter) \
- V(MAKE_ERROR_FUNCTION_INDEX, JSFunction, make_error_function) \
- V(MAP_DELETE_METHOD_INDEX, JSFunction, map_delete) \
- V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \
- V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \
- V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \
- V(MATH_POW_METHOD_INDEX, JSFunction, math_pow) \
- V(MESSAGE_GET_COLUMN_NUMBER_INDEX, JSFunction, message_get_column_number) \
- V(MESSAGE_GET_LINE_NUMBER_INDEX, JSFunction, message_get_line_number) \
- V(MESSAGE_GET_SOURCE_LINE_INDEX, JSFunction, message_get_source_line) \
- V(NO_SIDE_EFFECTS_TO_STRING_FUN_INDEX, JSFunction, \
- no_side_effects_to_string_fun) \
- V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
- V(OBJECT_TO_STRING, JSFunction, object_to_string) \
- V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
- V(PROMISE_CHAIN_INDEX, JSFunction, promise_chain) \
- V(PROMISE_CREATE_INDEX, JSFunction, promise_create) \
- V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \
- V(PROMISE_HAS_USER_DEFINED_REJECT_HANDLER_INDEX, JSFunction, \
- promise_has_user_defined_reject_handler) \
- V(PROMISE_REJECT_INDEX, JSFunction, promise_reject) \
- V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
- V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
- V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
- V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
- V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \
- V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \
- V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \
- V(STACK_OVERFLOW_BOILERPLATE_INDEX, JSObject, stack_overflow_boilerplate) \
- V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
- V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
+#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
+ V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
+ V(ARRAY_POP_INDEX, JSFunction, array_pop) \
+ V(ARRAY_PUSH_INDEX, JSFunction, array_push) \
+ V(ARRAY_SHIFT_INDEX, JSFunction, array_shift) \
+ V(ARRAY_SPLICE_INDEX, JSFunction, array_splice) \
+ V(ARRAY_SLICE_INDEX, JSFunction, array_slice) \
+ V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
+ V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
+ V(ASYNC_FUNCTION_AWAIT_INDEX, JSFunction, async_function_await) \
+ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
+ V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
+ V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
+ V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
+ V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
+ V(JSON_SERIALIZE_ADAPTER_INDEX, JSFunction, json_serialize_adapter) \
+ V(MAKE_ERROR_FUNCTION_INDEX, JSFunction, make_error_function) \
+ V(MAP_DELETE_METHOD_INDEX, JSFunction, map_delete) \
+ V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \
+ V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \
+ V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \
+ V(MATH_POW_METHOD_INDEX, JSFunction, math_pow) \
+ V(MESSAGE_GET_COLUMN_NUMBER_INDEX, JSFunction, message_get_column_number) \
+ V(MESSAGE_GET_LINE_NUMBER_INDEX, JSFunction, message_get_line_number) \
+ V(MESSAGE_GET_SOURCE_LINE_INDEX, JSFunction, message_get_source_line) \
+ V(NO_SIDE_EFFECTS_TO_STRING_FUN_INDEX, JSFunction, \
+ no_side_effects_to_string_fun) \
+ V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
+ V(OBJECT_TO_STRING, JSFunction, object_to_string) \
+ V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
+ V(PROMISE_CHAIN_INDEX, JSFunction, promise_chain) \
+ V(PROMISE_CREATE_INDEX, JSFunction, promise_create) \
+ V(PROMISE_FUNCTION_INDEX, JSFunction, promise_function) \
+ V(PROMISE_HAS_USER_DEFINED_REJECT_HANDLER_INDEX, JSFunction, \
+ promise_has_user_defined_reject_handler) \
+ V(PROMISE_REJECT_INDEX, JSFunction, promise_reject) \
+ V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
+ V(PROMISE_CREATE_RESOLVED_INDEX, JSFunction, promise_create_resolved) \
+ V(PROMISE_CREATE_REJECTED_INDEX, JSFunction, promise_create_rejected) \
+ V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
+ V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
+ V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
+ V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \
+ V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \
+ V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \
+ V(STACK_OVERFLOW_BOILERPLATE_INDEX, JSObject, stack_overflow_boilerplate) \
+ V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
+ V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function)
#define NATIVE_CONTEXT_FIELDS(V) \
@@ -147,6 +150,7 @@
V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(ARRAY_BUFFER_MAP_INDEX, Map, array_buffer_map) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
+ V(ASYNC_FUNCTION_FUNCTION_INDEX, JSFunction, async_function_constructor) \
V(BOOL16X8_FUNCTION_INDEX, JSFunction, bool16x8_function) \
V(BOOL32X4_FUNCTION_INDEX, JSFunction, bool32x4_function) \
V(BOOL8X16_FUNCTION_INDEX, JSFunction, bool8x16_function) \
@@ -234,8 +238,10 @@
V(SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \
sloppy_function_with_readonly_prototype_map) \
V(WASM_FUNCTION_MAP_INDEX, Map, wasm_function_map) \
+ V(SLOPPY_ASYNC_FUNCTION_MAP_INDEX, Map, sloppy_async_function_map) \
V(SLOPPY_GENERATOR_FUNCTION_MAP_INDEX, Map, sloppy_generator_function_map) \
V(SLOW_ALIASED_ARGUMENTS_MAP_INDEX, Map, slow_aliased_arguments_map) \
+ V(STRICT_ASYNC_FUNCTION_MAP_INDEX, Map, strict_async_function_map) \
V(STRICT_ARGUMENTS_MAP_INDEX, Map, strict_arguments_map) \
V(STRICT_FUNCTION_MAP_INDEX, Map, strict_function_map) \
V(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
@@ -518,6 +524,11 @@
: SLOPPY_GENERATOR_FUNCTION_MAP_INDEX;
}
+ if (IsAsyncFunction(kind)) {
+ return is_strict(language_mode) ? STRICT_ASYNC_FUNCTION_MAP_INDEX
+ : SLOPPY_ASYNC_FUNCTION_MAP_INDEX;
+ }
+
if (IsClassConstructor(kind)) {
// Use strict function map (no own "caller" / "arguments")
return STRICT_FUNCTION_MAP_INDEX;
diff --git a/src/factory.cc b/src/factory.cc
index 93911b8..7d2dad0 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -1662,7 +1662,7 @@
Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
Handle<JSFunction> function) {
- DCHECK(function->shared()->is_generator());
+ DCHECK(function->shared()->is_resumable());
JSFunction::EnsureHasInitialMap(function);
Handle<Map> map(function->initial_map());
DCHECK_EQ(JS_GENERATOR_OBJECT_TYPE, map->instance_type());
@@ -2068,6 +2068,11 @@
shared->set_instance_class_name(isolate()->heap()->Generator_string());
shared->DisableOptimization(kGenerator);
}
+ if (IsAsyncFunction(kind)) {
+ // TODO(caitp): Enable optimization of async functions when they are enabled
+ // for generators functions.
+ shared->DisableOptimization(kGenerator);
+ }
return shared;
}
diff --git a/src/globals.h b/src/globals.h
index 777f429..cd13e21 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1058,6 +1058,7 @@
if (IsConciseMethod(kind)) return false;
if (IsArrowFunction(kind)) return false;
if (IsGeneratorFunction(kind)) return false;
+ if (IsAsyncFunction(kind)) return false;
return true;
}
diff --git a/src/js/harmony-async-await.js b/src/js/harmony-async-await.js
new file mode 100644
index 0000000..c6705ef
--- /dev/null
+++ b/src/js/harmony-async-await.js
@@ -0,0 +1,43 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function(global, utils, extrasUtils) {
+
+"use strict";
+
+%CheckIsBootstrapping();
+
+// -------------------------------------------------------------------
+// Imports
+
+var AsyncFunctionNext;
+var AsyncFunctionThrow;
+var PromiseReject;
+var PromiseResolve;
+var PromiseThen;
+
+utils.Import(function(from) {
+ AsyncFunctionNext = from.AsyncFunctionNext;
+ AsyncFunctionThrow = from.AsyncFunctionThrow;
+ PromiseReject = from.PromiseCreateRejected;
+ PromiseResolve = from.PromiseCreateResolved;
+ PromiseThen = from.PromiseThen;
+});
+
+// -------------------------------------------------------------------
+
+function AsyncFunctionAwait(generator, value) {
+ return %_Call(
+ PromiseThen, PromiseResolve(value),
+ function(sentValue) {
+ return %_Call(AsyncFunctionNext, generator, sentValue);
+ },
+ function(sentError) {
+ return %_Call(AsyncFunctionThrow, generator, sentError);
+ });
+}
+
+%InstallToContext([ "async_function_await", AsyncFunctionAwait ]);
+
+})
diff --git a/src/js/prologue.js b/src/js/prologue.js
index 0d1f939..b352eb1 100644
--- a/src/js/prologue.js
+++ b/src/js/prologue.js
@@ -183,6 +183,8 @@
var expose_list = [
"AddBoundMethod",
"ArrayToString",
+ "AsyncFunctionNext",
+ "AsyncFunctionThrow",
"ErrorToString",
"GetIterator",
"GetMethod",
@@ -201,6 +203,9 @@
"PromiseChain",
"PromiseDefer",
"PromiseAccept",
+ "PromiseCreateRejected",
+ "PromiseCreateResolved",
+ "PromiseThen",
"RegExpSubclassExecJS",
"RegExpSubclassMatch",
"RegExpSubclassReplace",
diff --git a/src/js/promise.js b/src/js/promise.js
index 65a8bf3..42b772b 100644
--- a/src/js/promise.js
+++ b/src/js/promise.js
@@ -293,6 +293,16 @@
}
}
+// Shortcut Promise.reject and Promise.resolve() implementations, used by
+// Async Functions implementation.
+function PromiseCreateRejected(r) {
+ return %_Call(PromiseReject, GlobalPromise, r);
+}
+
+function PromiseCreateResolved(x) {
+ return %_Call(PromiseResolve, GlobalPromise, x);
+}
+
// ES#sec-promise.prototype.then
// Promise.prototype.then ( onFulfilled, onRejected )
// Multi-unwrapped chaining with thenable coercion.
@@ -487,6 +497,8 @@
"promise_reject", RejectPromise,
"promise_resolve", FulfillPromise,
"promise_then", PromiseThen,
+ "promise_create_rejected", PromiseCreateRejected,
+ "promise_create_resolved", PromiseCreateResolved
]);
// This allows extras to create promises quickly without building extra
@@ -506,6 +518,10 @@
to.PromiseChain = PromiseChain;
to.PromiseDefer = PromiseDefer;
to.PromiseAccept = PromiseAccept;
+
+ to.PromiseCreateRejected = PromiseCreateRejected;
+ to.PromiseCreateResolved = PromiseCreateResolved;
+ to.PromiseThen = PromiseThen;
});
})
diff --git a/src/objects.cc b/src/objects.cc
index dab7aa1..05a1ab0 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -11948,7 +11948,7 @@
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
- DCHECK(function->IsConstructor() || function->shared()->is_generator());
+ DCHECK(function->IsConstructor() || function->shared()->is_resumable());
if (function->has_initial_map()) return;
Isolate* isolate = function->GetIsolate();
@@ -11959,7 +11959,7 @@
// First create a new map with the size and number of in-object properties
// suggested by the function.
InstanceType instance_type;
- if (function->shared()->is_generator()) {
+ if (function->shared()->is_resumable()) {
instance_type = JS_GENERATOR_OBJECT_TYPE;
} else {
instance_type = JS_OBJECT_TYPE;
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index 82a3897..d7ae67e 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -3321,18 +3321,25 @@
function_state_->return_expr_context());
ReturnExprScope allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
- ExpressionT expression =
- ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
- Traits::RewriteNonPattern(&classifier, CHECK_OK);
body = this->NewStatementList(1, zone());
- this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
- body->Add(factory()->NewReturnStatement(expression, pos), zone());
+ this->AddParameterInitializationBlock(formal_parameters, body, is_async,
+ CHECK_OK);
+ if (is_async) {
+ this->ParseAsyncArrowSingleExpressionBody(body, accept_IN, &classifier,
+ pos, CHECK_OK);
+ Traits::RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ ExpressionT expression =
+ ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
+ Traits::RewriteNonPattern(&classifier, CHECK_OK);
+ body->Add(factory()->NewReturnStatement(expression, pos), zone());
+ if (allow_tailcalls() && !is_sloppy(language_mode())) {
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ this->MarkTailPosition(expression);
+ }
+ }
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
- if (allow_tailcalls() && !is_sloppy(language_mode())) {
- // ES6 14.6.1 Static Semantics: IsInTailPosition
- this->MarkTailPosition(expression);
- }
this->MarkCollectedTailCallExpressions();
}
super_loc = function_state.super_location();
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index 6ddf555..cecb31c 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -2754,6 +2754,8 @@
if (is_generator()) {
return_value = BuildIteratorResult(return_value, true);
+ } else if (is_async_function()) {
+ return_value = BuildPromiseResolve(return_value, return_value->position());
}
result = factory()->NewReturnStatement(return_value, loc.beg_pos);
@@ -3994,6 +3996,63 @@
AddFormalParameter(parameters, expr, initializer, end_pos, is_rest);
}
+void ParserTraits::ParseAsyncArrowSingleExpressionBody(
+ ZoneList<Statement*>* body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok) {
+ parser_->DesugarAsyncFunctionBody(
+ parser_->ast_value_factory()->empty_string(), parser_->scope_, body,
+ classifier, kAsyncArrowFunction, FunctionBody::SingleExpression,
+ accept_IN, pos, ok);
+}
+
+void Parser::DesugarAsyncFunctionBody(const AstRawString* function_name,
+ Scope* scope, ZoneList<Statement*>* body,
+ ExpressionClassifier* classifier,
+ FunctionKind kind, FunctionBody body_type,
+ bool accept_IN, int pos, bool* ok) {
+ // function async_function() {
+ // try {
+ // .generator_object = %CreateGeneratorObject();
+ // ... function body ...
+ // } catch (e) {
+ // return Promise.reject(e);
+ // }
+ // }
+ scope->ForceContextAllocation();
+ Variable* temp =
+ scope_->NewTemporary(ast_value_factory()->dot_generator_object_string());
+ function_state_->set_generator_object_variable(temp);
+
+ Expression* init_generator_variable = factory()->NewAssignment(
+ Token::INIT, factory()->NewVariableProxy(temp),
+ BuildCreateJSGeneratorObject(pos), RelocInfo::kNoPosition);
+ body->Add(factory()->NewExpressionStatement(init_generator_variable,
+ RelocInfo::kNoPosition),
+ zone());
+
+ Block* try_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
+
+ ZoneList<Statement*>* inner_body = try_block->statements();
+
+ Expression* return_value = nullptr;
+ if (body_type == FunctionBody::Normal) {
+ ParseStatementList(inner_body, Token::RBRACE, ok);
+ if (!*ok) return;
+ return_value = factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
+ } else {
+ return_value = ParseAssignmentExpression(accept_IN, classifier, ok);
+ if (!*ok) return;
+ ParserTraits::RewriteNonPattern(classifier, ok);
+ if (!*ok) return;
+ }
+
+ return_value = BuildPromiseResolve(return_value, return_value->position());
+ inner_body->Add(
+ factory()->NewReturnStatement(return_value, return_value->position()),
+ zone());
+ body->Add(BuildRejectPromiseOnException(try_block), zone());
+ scope->set_end_position(scanner()->location().end_pos);
+}
DoExpression* Parser::ParseDoExpression(bool* ok) {
// AssignmentExpression ::
@@ -4542,6 +4601,54 @@
return init_block;
}
+Block* Parser::BuildRejectPromiseOnException(Block* block) {
+ // try { <block> } catch (error) { return Promise.reject(error); }
+ Block* try_block = block;
+ Scope* catch_scope = NewScope(scope_, CATCH_SCOPE);
+ catch_scope->set_is_hidden();
+ Variable* catch_variable =
+ catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR,
+ kCreatedInitialized, Variable::NORMAL);
+ Block* catch_block =
+ factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+
+ Expression* promise_reject = BuildPromiseReject(
+ factory()->NewVariableProxy(catch_variable), RelocInfo::kNoPosition);
+
+ ReturnStatement* return_promise_reject =
+ factory()->NewReturnStatement(promise_reject, RelocInfo::kNoPosition);
+ catch_block->statements()->Add(return_promise_reject, zone());
+ TryStatement* try_catch_statement =
+ factory()->NewTryCatchStatement(try_block, catch_scope, catch_variable,
+ catch_block, RelocInfo::kNoPosition);
+
+ block = factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+ block->statements()->Add(try_catch_statement, zone());
+ return block;
+}
+
+Expression* Parser::BuildCreateJSGeneratorObject(int pos) {
+ DCHECK_NOT_NULL(function_state_->generator_object_variable());
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
+ args->Add(factory()->NewThisFunction(pos), zone());
+ args->Add(ThisExpression(scope_, factory(), RelocInfo::kNoPosition), zone());
+ return factory()->NewCallRuntime(Runtime::kCreateJSGeneratorObject, args,
+ pos);
+}
+
+Expression* Parser::BuildPromiseResolve(Expression* value, int pos) {
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(value, zone());
+ return factory()->NewCallRuntime(Context::PROMISE_CREATE_RESOLVED_INDEX, args,
+ pos);
+}
+
+Expression* Parser::BuildPromiseReject(Expression* value, int pos) {
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(value, zone());
+ return factory()->NewCallRuntime(Context::PROMISE_CREATE_REJECTED_INDEX, args,
+ pos);
+}
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
const AstRawString* function_name, int pos,
@@ -4595,14 +4702,7 @@
factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
{
- ZoneList<Expression*>* arguments =
- new (zone()) ZoneList<Expression*>(2, zone());
- arguments->Add(factory()->NewThisFunction(pos), zone());
- arguments->Add(
- ThisExpression(scope_, factory(), RelocInfo::kNoPosition), zone());
- CallRuntime* allocation = factory()->NewCallRuntime(
- Runtime::kCreateJSGeneratorObject, arguments, pos);
-
+ Expression* allocation = BuildCreateJSGeneratorObject(pos);
VariableProxy* init_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Assignment* assignment = factory()->NewAssignment(
@@ -4638,6 +4738,10 @@
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
RelocInfo::kNoPosition),
zone());
+ } else if (IsAsyncFunction(kind)) {
+ const bool accept_IN = true;
+ DesugarAsyncFunctionBody(function_name, inner_scope, body, nullptr, kind,
+ FunctionBody::Normal, accept_IN, pos, CHECK_OK);
} else {
ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
@@ -4659,6 +4763,11 @@
DCHECK_EQ(body, inner_block->statements());
SetLanguageMode(scope_, inner_scope->language_mode());
Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK);
+
+ if (IsAsyncFunction(kind)) {
+ init_block = BuildRejectPromiseOnException(init_block);
+ }
+
DCHECK_NOT_NULL(init_block);
inner_scope->set_end_position(scanner()->location().end_pos);
@@ -5463,9 +5572,28 @@
}
Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) {
- // TODO(caitp): Implement AsyncFunctionAwait()
- // per tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await
- return value;
+ // yield %AsyncFunctionAwait(.generator_object, <operand>)
+ Variable* generator_object_variable =
+ parser_->function_state_->generator_object_variable();
+
+ // If generator_object_variable is null,
+ if (!generator_object_variable) return value;
+
+ Expression* generator_object =
+ parser_->factory()->NewVariableProxy(generator_object_variable);
+
+ ZoneList<Expression*>* async_function_await_args =
+ new (zone()) ZoneList<Expression*>(2, zone());
+ async_function_await_args->Add(generator_object, zone());
+ async_function_await_args->Add(value, zone());
+ Expression* async_function_await = parser_->factory()->NewCallRuntime(
+ Context::ASYNC_FUNCTION_AWAIT_INDEX, async_function_await_args,
+ RelocInfo::kNoPosition);
+
+ generator_object =
+ parser_->factory()->NewVariableProxy(generator_object_variable);
+ return parser_->factory()->NewYield(generator_object, async_function_await,
+ pos);
}
Zone* ParserTraits::zone() const {
diff --git a/src/parsing/parser.h b/src/parsing/parser.h
index e91ad77..02feecf 100644
--- a/src/parsing/parser.h
+++ b/src/parsing/parser.h
@@ -535,7 +535,11 @@
V8_INLINE void AddParameterInitializationBlock(
const ParserFormalParameters& parameters,
- ZoneList<v8::internal::Statement*>* body, bool* ok);
+ ZoneList<v8::internal::Statement*>* body, bool is_async, bool* ok);
+
+ void ParseAsyncArrowSingleExpressionBody(
+ ZoneList<Statement*>* body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok);
V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
FunctionKind kind = kNormalFunction);
@@ -971,6 +975,12 @@
ZoneList<const AstRawString*>* names, ForStatement* loop, Statement* init,
Expression* cond, Statement* next, Statement* body, bool* ok);
+ void DesugarAsyncFunctionBody(const AstRawString* function_name, Scope* scope,
+ ZoneList<Statement*>* body,
+ Type::ExpressionClassifier* classifier,
+ FunctionKind kind, FunctionBody type,
+ bool accept_IN, int pos, bool* ok);
+
void RewriteDoExpression(Expression* expr, bool* ok);
FunctionLiteral* ParseFunctionLiteral(
@@ -1041,6 +1051,7 @@
Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok);
+ Block* BuildRejectPromiseOnException(Block* block);
// Consumes the ending }.
ZoneList<Statement*>* ParseEagerFunctionBody(
@@ -1085,6 +1096,10 @@
friend class InitializerRewriter;
void RewriteParameterInitializer(Expression* expr, Scope* scope);
+ Expression* BuildCreateJSGeneratorObject(int pos);
+ Expression* BuildPromiseResolve(Expression* value, int pos);
+ Expression* BuildPromiseReject(Expression* value, int pos);
+
Scanner scanner_;
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
@@ -1254,14 +1269,18 @@
}
}
-
void ParserTraits::AddParameterInitializationBlock(
const ParserFormalParameters& parameters,
- ZoneList<v8::internal::Statement*>* body, bool* ok) {
+ ZoneList<v8::internal::Statement*>* body, bool is_async, bool* ok) {
if (!parameters.is_simple) {
auto* init_block =
parser_->BuildParameterInitializationBlock(parameters, ok);
if (!*ok) return;
+
+ if (is_async) {
+ init_block = parser_->BuildRejectPromiseOnException(init_block);
+ }
+
if (init_block != nullptr) {
body->Add(init_block, parser_->zone());
}
diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc
index 47eca82..0a091c6 100644
--- a/src/parsing/preparser.cc
+++ b/src/parsing/preparser.cc
@@ -1296,6 +1296,19 @@
return PreParserExpression::Default();
}
+void PreParserTraits::ParseAsyncArrowSingleExpressionBody(
+ PreParserStatementList body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok) {
+ Scope* scope = pre_parser_->scope_;
+ scope->ForceContextAllocation();
+
+ PreParserExpression return_value =
+ pre_parser_->ParseAssignmentExpression(accept_IN, classifier, ok);
+ if (!*ok) return;
+
+ body->Add(PreParserStatement::ExpressionStatement(return_value), zone());
+}
+
#undef CHECK_OK
diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
index e5a1994..4a818c9 100644
--- a/src/parsing/preparser.h
+++ b/src/parsing/preparser.h
@@ -860,8 +860,8 @@
}
static void AddParameterInitializationBlock(
- const PreParserFormalParameters& parameters,
- PreParserStatementList list, bool* ok) {}
+ const PreParserFormalParameters& parameters, PreParserStatementList list,
+ bool is_async, bool* ok) {}
V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
int* expected_property_count, bool* ok) {
@@ -878,6 +878,10 @@
PreParserExpression expression, const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok);
+ void ParseAsyncArrowSingleExpressionBody(
+ PreParserStatementList body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok);
+
V8_INLINE PreParserExpression ParseAsyncFunctionExpression(bool* ok);
void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
diff --git a/src/runtime/runtime-generator.cc b/src/runtime/runtime-generator.cc
index 9176639..7ff7fc8 100644
--- a/src/runtime/runtime-generator.cc
+++ b/src/runtime/runtime-generator.cc
@@ -17,7 +17,7 @@
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
- RUNTIME_ASSERT(function->shared()->is_generator());
+ RUNTIME_ASSERT(function->shared()->is_resumable());
Handle<FixedArray> operand_stack;
if (FLAG_ignition && FLAG_ignition_generators) {
@@ -46,7 +46,7 @@
JavaScriptFrameIterator stack_iterator(isolate);
JavaScriptFrame* frame = stack_iterator.frame();
- RUNTIME_ASSERT(frame->function()->shared()->is_generator());
+ RUNTIME_ASSERT(frame->function()->shared()->is_resumable());
DCHECK_EQ(frame->function(), generator_object->function());
DCHECK(frame->function()->shared()->is_compiled());
DCHECK(!frame->function()->IsOptimized());
diff --git a/src/v8.gyp b/src/v8.gyp
index 414aa7a..de6c4d6 100644
--- a/src/v8.gyp
+++ b/src/v8.gyp
@@ -2039,6 +2039,7 @@
'js/harmony-unicode-regexps.js',
'js/harmony-string-padding.js',
'js/promise-extra.js',
+ 'js/harmony-async-await.js'
],
'libraries_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries.bin',
'libraries_experimental_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries-experimental.bin',
diff --git a/test/cctest/interpreter/bytecode_expectations/CallRuntime.golden b/test/cctest/interpreter/bytecode_expectations/CallRuntime.golden
index 10fa820..ed2fb0a 100644
--- a/test/cctest/interpreter/bytecode_expectations/CallRuntime.golden
+++ b/test/cctest/interpreter/bytecode_expectations/CallRuntime.golden
@@ -83,7 +83,7 @@
B(Star), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(Star), R(1),
- B(CallJSRuntime), U8(118), R(0), U8(2),
+ B(CallJSRuntime), U8(121), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
diff --git a/test/mjsunit/harmony/async-arrow-lexical-arguments.js b/test/mjsunit/harmony/async-arrow-lexical-arguments.js
new file mode 100644
index 0000000..44d38a4
--- /dev/null
+++ b/test/mjsunit/harmony/async-arrow-lexical-arguments.js
@@ -0,0 +1,42 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-async-await --allow-natives-syntax
+
+function assertEqualsAsync(expected, run, msg) {
+ var actual;
+ var hadValue = false;
+ var hadError = false;
+ var promise = run();
+
+ if (typeof promise !== "object" || typeof promise.then !== "function") {
+ throw new MjsUnitAssertionError(
+ "Expected " + run.toString() +
+ " to return a Promise, but it returned " + PrettyPrint(promise));
+ }
+
+ promise.then(function(value) { hadValue = true; actual = value; },
+ function(error) { hadError = true; actual = error; });
+
+ assertFalse(hadValue || hadError);
+
+ %RunMicrotasks();
+
+ if (hadError) throw actual;
+
+ assertTrue(
+ hadValue, "Expected '" + run.toString() + "' to produce a value");
+
+ assertEquals(expected, actual, msg);
+};
+
+assertEqualsAsync("[1,2,3]", () => (function() {
+ return (async () => JSON.stringify([...arguments]))();
+})(1, 2, 3));
+
+assertEqualsAsync("[4,5,6]",
+ () => (function() {
+ return (async () => {
+ return JSON.stringify([...await arguments]) })();
+ })(4, 5, 6));
diff --git a/test/mjsunit/harmony/async-arrow-lexical-new.target.js b/test/mjsunit/harmony/async-arrow-lexical-new.target.js
new file mode 100644
index 0000000..72b29e6
--- /dev/null
+++ b/test/mjsunit/harmony/async-arrow-lexical-new.target.js
@@ -0,0 +1,43 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-async-await --allow-natives-syntax
+
+function assertEqualsAsync(expected, run, msg) {
+ var actual;
+ var hadValue = false;
+ var hadError = false;
+ var promise = run();
+
+ if (typeof promise !== "object" || typeof promise.then !== "function") {
+ throw new MjsUnitAssertionError(
+ "Expected " + run.toString() +
+ " to return a Promise, but it returned " + PrettyPrint(promise));
+ }
+
+ promise.then(function(value) { hadValue = true; actual = value; },
+ function(error) { hadError = true; actual = error; });
+
+ assertFalse(hadValue || hadError);
+
+ %RunMicrotasks();
+
+ if (hadError) throw actual;
+
+ assertTrue(
+ hadValue, "Expected '" + run.toString() + "' to produce a value");
+
+ assertEquals(expected, actual, msg);
+};
+
+class BaseClass {
+ constructor() {
+ return async () => new.target;
+ }
+}
+
+class ChildClass extends BaseClass {}
+
+assertEqualsAsync(BaseClass, () => new BaseClass()());
+assertEqualsAsync(ChildClass, () => new ChildClass()());
diff --git a/test/mjsunit/harmony/async-arrow-lexical-super.js b/test/mjsunit/harmony/async-arrow-lexical-super.js
new file mode 100644
index 0000000..78f5d55
--- /dev/null
+++ b/test/mjsunit/harmony/async-arrow-lexical-super.js
@@ -0,0 +1,58 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-async-await --allow-natives-syntax
+
+function assertEqualsAsync(expected, run, msg) {
+ var actual;
+ var hadValue = false;
+ var hadError = false;
+ var promise = run();
+
+ if (typeof promise !== "object" || typeof promise.then !== "function") {
+ throw new MjsUnitAssertionError(
+ "Expected " + run.toString() +
+ " to return a Promise, but it returned " + PrettyPrint(promise));
+ }
+
+ promise.then(function(value) { hadValue = true; actual = value; },
+ function(error) { hadError = true; actual = error; });
+
+ assertFalse(hadValue || hadError);
+
+ %RunMicrotasks();
+
+ if (hadError) throw actual;
+
+ assertTrue(
+ hadValue, "Expected '" + run.toString() + "' to produce a value");
+
+ assertEquals(expected, actual, msg);
+};
+
+class BaseClass {
+ constructor(x) {
+ this.name_ = x;
+ }
+ get name() { return this.name_; }
+};
+
+class DeferredSuperCall extends BaseClass {
+ constructor(x) {
+ return async() => super(x);
+ }
+};
+
+assertEqualsAsync(
+ "LexicalSuperCall",
+ () => new DeferredSuperCall("LexicalSuperCall")().then(x => x.name));
+
+
+class DeferredSuperProperty extends BaseClass {
+ deferredName() { return async() => super.name; }
+};
+
+assertEqualsAsync(
+ "LexicalSuperProperty",
+ () => new DeferredSuperProperty("LexicalSuperProperty").deferredName()());
diff --git a/test/mjsunit/harmony/async-arrow-lexical-this.js b/test/mjsunit/harmony/async-arrow-lexical-this.js
new file mode 100644
index 0000000..182db47
--- /dev/null
+++ b/test/mjsunit/harmony/async-arrow-lexical-this.js
@@ -0,0 +1,48 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-async-await --allow-natives-syntax
+
+function assertEqualsAsync(expected, run, msg) {
+ var actual;
+ var hadValue = false;
+ var hadError = false;
+ var promise = run();
+
+ if (typeof promise !== "object" || typeof promise.then !== "function") {
+ throw new MjsUnitAssertionError(
+ "Expected " + run.toString() +
+ " to return a Promise, but it returned " + PrettyPrint(promise));
+ }
+
+ promise.then(function(value) { hadValue = true; actual = value; },
+ function(error) { hadError = true; actual = error; });
+
+ assertFalse(hadValue || hadError);
+
+ %RunMicrotasks();
+
+ if (hadError) throw actual;
+
+ assertTrue(
+ hadValue, "Expected '" + run.toString() + "' to produce a value");
+
+ assertEquals(expected, actual, msg);
+};
+
+var O = {
+ [Symbol.toStringTag]: "LexicalThis",
+ run(n) {
+ return async passFail => `${n}. ${passFail}: ${this}`;
+ },
+};
+
+assertEqualsAsync("1. PASS: [object LexicalThis]", () => O.run(1)("PASS"));
+
+var O2 = {
+ [Symbol.toStringTag]: "LexicalThis",
+ run: O.run(2)
+};
+
+assertEqualsAsync("2. PASS: [object LexicalThis]", () => O2.run("PASS"));
diff --git a/test/mjsunit/harmony/async-await-basic.js b/test/mjsunit/harmony/async-await-basic.js
new file mode 100644
index 0000000..9c8af3c
--- /dev/null
+++ b/test/mjsunit/harmony/async-await-basic.js
@@ -0,0 +1,338 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-async-await --allow-natives-syntax
+
+// Do not install `AsyncFunction` constructor on global object
+
+function assertThrowsAsync(run, errorType, message) {
+ var actual;
+ var hadValue = false;
+ var hadError = false;
+ var promise = run();
+
+ if (typeof promise !== "object" || typeof promise.then !== "function") {
+ throw new MjsUnitAssertionError(
+ "Expected " + run.toString() +
+ " to return a Promise, but it returned " + PrettyPrint(promise));
+ }
+
+ promise.then(function(value) { hadValue = true; actual = value; },
+ function(error) { hadError = true; actual = error; });
+
+ assertFalse(hadValue || hadError);
+
+ %RunMicrotasks();
+
+ if (!hadError) {
+ throw new MjsUnitAssertionError(
+ "Expected " + run + "() to throw " + errorType.name +
+ ", but did not throw.");
+ }
+ if (!(actual instanceof errorType))
+ throw new MjsUnitAssertionError(
+ "Expected " + run + "() to throw " + errorType.name +
+ ", but threw '" + actual + "'");
+ if (message !== void 0 && actual.message !== message)
+ throw new MjsUnitAssertionError(
+ "Expected " + run + "() to throw '" + message + "', but threw '" +
+ actual.message + "'");
+};
+
+function assertEqualsAsync(expected, run, msg) {
+ var actual;
+ var hadValue = false;
+ var hadError = false;
+ var promise = run();
+
+ if (typeof promise !== "object" || typeof promise.then !== "function") {
+ throw new MjsUnitAssertionError(
+ "Expected " + run.toString() +
+ " to return a Promise, but it returned " + PrettyPrint(promise));
+ }
+
+ promise.then(function(value) { hadValue = true; actual = value; },
+ function(error) { hadError = true; actual = error; });
+
+ assertFalse(hadValue || hadError);
+
+ %RunMicrotasks();
+
+ if (hadError) throw actual;
+
+ assertTrue(
+ hadValue, "Expected '" + run.toString() + "' to produce a value");
+
+ assertEquals(expected, actual, msg);
+};
+
+assertEquals(undefined, this.AsyncFunction);
+let AsyncFunction = (async function() {}).constructor;
+
+// Let functionPrototype be the intrinsic object %AsyncFunctionPrototype%.
+async function asyncFunctionForProto() {}
+assertEquals(AsyncFunction.prototype,
+ Object.getPrototypeOf(asyncFunctionForProto));
+assertEquals(AsyncFunction.prototype,
+ Object.getPrototypeOf(async function() {}));
+assertEquals(AsyncFunction.prototype, Object.getPrototypeOf(async () => {}));
+assertEquals(AsyncFunction.prototype,
+ Object.getPrototypeOf({ async method() {} }.method));
+assertEquals(AsyncFunction.prototype, Object.getPrototypeOf(AsyncFunction()));
+assertEquals(AsyncFunction.prototype,
+ Object.getPrototypeOf(new AsyncFunction()));
+
+// AsyncFunctionCreate does not produce an object with a Prototype
+assertEquals(undefined, asyncFunctionForProto.prototype);
+assertEquals(false, asyncFunctionForProto.hasOwnProperty("prototype"));
+assertEquals(undefined, (async function() {}).prototype);
+assertEquals(false, (async function() {}).hasOwnProperty("prototype"));
+assertEquals(undefined, (async() => {}).prototype);
+assertEquals(false, (async() => {}).hasOwnProperty("prototype"));
+assertEquals(undefined, ({ async method() {} }).method.prototype);
+assertEquals(false, ({ async method() {} }).method.hasOwnProperty("prototype"));
+assertEquals(undefined, AsyncFunction().prototype);
+assertEquals(false, AsyncFunction().hasOwnProperty("prototype"));
+assertEquals(undefined, (new AsyncFunction()).prototype);
+assertEquals(false, (new AsyncFunction()).hasOwnProperty("prototype"));
+
+assertEquals(1, async function(a) { await 1; }.length);
+assertEquals(2, async function(a, b) { await 1; }.length);
+assertEquals(1, async function(a, b = 2) { await 1; }.length);
+assertEquals(2, async function(a, b, ...c) { await 1; }.length);
+
+assertEquals(1, (async(a) => await 1).length);
+assertEquals(2, (async(a, b) => await 1).length);
+assertEquals(1, (async(a, b = 2) => await 1).length);
+assertEquals(2, (async(a, b, ...c) => await 1).length);
+
+assertEquals(1, ({ async f(a) { await 1; } }).f.length);
+assertEquals(2, ({ async f(a, b) { await 1; } }).f.length);
+assertEquals(1, ({ async f(a, b = 2) { await 1; } }).f.length);
+assertEquals(2, ({ async f(a, b, ...c) { await 1; } }).f.length);
+
+assertEquals(1, AsyncFunction("a", "await 1").length);
+assertEquals(2, AsyncFunction("a", "b", "await 1").length);
+assertEquals(1, AsyncFunction("a", "b = 2", "await 1").length);
+assertEquals(2, AsyncFunction("a", "b", "...c", "await 1").length);
+
+assertEquals(1, (new AsyncFunction("a", "await 1")).length);
+assertEquals(2, (new AsyncFunction("a", "b", "await 1")).length);
+assertEquals(1, (new AsyncFunction("a", "b = 2", "await 1")).length);
+assertEquals(2, (new AsyncFunction("a", "b", "...c", "await 1")).length);
+
+// AsyncFunction.prototype[ @@toStringTag ]
+var descriptor =
+ Object.getOwnPropertyDescriptor(AsyncFunction.prototype,
+ Symbol.toStringTag);
+assertEquals("AsyncFunction", descriptor.value);
+assertEquals(false, descriptor.enumerable);
+assertEquals(false, descriptor.writable);
+assertEquals(true, descriptor.configurable);
+
+assertEquals(1, AsyncFunction.length);
+
+// Let F be ! FunctionAllocate(functionPrototype, Strict, "non-constructor")
+async function asyncNonConstructorDecl() {}
+assertThrows(
+ () => new asyncNonConstructorDecl(), TypeError);
+assertThrows(
+ () => new (async function() {}), TypeError);
+assertThrows(
+ () => new ({ async nonConstructor() {} }).nonConstructor(), TypeError);
+assertThrows(
+ () => new (() => "not a constructor!"), TypeError);
+assertThrows(
+ () => new (AsyncFunction()), TypeError);
+assertThrows(
+ () => new (new AsyncFunction()), TypeError);
+
+// Normal completion
+async function asyncDecl() { return "test"; }
+assertEqualsAsync("test", asyncDecl);
+assertEqualsAsync("test2", async function() { return "test2"; });
+assertEqualsAsync("test3", async () => "test3");
+assertEqualsAsync("test4", () => ({ async f() { return "test4"; } }).f());
+assertEqualsAsync("test5", () => AsyncFunction("no", "return 'test' + no;")(5));
+assertEqualsAsync("test6",
+ () => (new AsyncFunction("no", "return 'test' + no;"))(6));
+
+class MyError extends Error {};
+
+// Throw completion
+async function asyncDeclThrower(e) { throw new MyError(e); }
+assertThrowsAsync(() => asyncDeclThrower("boom!"), MyError, "boom!");
+assertThrowsAsync(
+ () => (async function(e) { throw new MyError(e); })("boom!!!"),
+ MyError, "boom!!!");
+assertThrowsAsync(
+ () => (async e => { throw new MyError(e) })("boom!!"), MyError, "boom!!");
+assertThrowsAsync(
+ () => ({ async thrower(e) { throw new MyError(e); } }).thrower("boom!1!"),
+ MyError, "boom!1!");
+assertThrowsAsync(
+ () => AsyncFunction("msg", "throw new MyError(msg)")("boom!2!!"),
+ MyError, "boom!2!!");
+assertThrowsAsync(
+ () => (new AsyncFunction("msg", "throw new MyError(msg)"))("boom!2!!!"),
+ MyError, "boom!2!!!");
+
+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;
+}
+
+assertEqualsAsync(4, () => resumeAfterNormal(1));
+assertEquals("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 = [];
+assertEqualsAsync(5, () => O.resumeAfterNormal(2));
+assertEquals("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 = [];
+assertEqualsAsync(6, () => resumeAfterNormalArrow(3));
+assertEquals("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 = [];
+assertEqualsAsync(7, () => resumeAfterNormalEval(4));
+assertEquals("start:4 resume:5 resume:6", log.join(" "));
+
+var resumeAfterNormalNewEval = new 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 = [];
+assertEqualsAsync(8, () => resumeAfterNormalNewEval(5));
+assertEquals("start:5 resume:6 resume:7", 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 = [];
+assertEqualsAsync(2, () => resumeAfterThrow(1));
+assertEquals("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 = [];
+assertEqualsAsync(3, () => O.resumeAfterThrow(2));
+assertEquals("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 = [];
+
+assertEqualsAsync(4, () => resumeAfterThrowArrow(3));
+assertEquals("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 = [];
+assertEqualsAsync(5, () => resumeAfterThrowEval(4));
+assertEquals("start:4 resume:throw1 resume:throw2", log.join(" "));
+
+var resumeAfterThrowNewEval = new 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 = [];
+assertEqualsAsync(6, () => resumeAfterThrowNewEval(5));
+assertEquals("start:5 resume:throw1 resume:throw2", log.join(" "));
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index bb90311..e259822 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -55,6 +55,9 @@
'es6/debug-promises/reject-with-undefined-reject': [FAIL],
'es6/debug-promises/reject-with-invalid-reject': [FAIL],
+ # TODO(caitp): fix super-call and super-property in async arrow functions
+ 'harmony/async-arrow-lexical-super': [FAIL],
+
##############################################################################
# TurboFan compiler failures.