[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.