Bug 1185106 - Part 11.1: Implement async functions. r=till draft
authorTooru Fujisawa <arai_a@mac.com>
Mon, 29 Aug 2016 02:05:55 +0900
changeset 430946 266e4d69e518917b87cbf5788f73e04345d146b6
parent 430945 e5b0b573c32495ce13e17a56ef3bbac54e9ae17b
child 430947 bcebf593fff32286c09215bacff86822f35b52d8
push id33945
push userarai_a@mac.com
push dateFri, 28 Oct 2016 11:34:02 +0000
reviewerstill
bugs1185106
milestone52.0a1
Bug 1185106 - Part 11.1: Implement async functions. r=till MozReview-Commit-ID: ChWpakqUlsi
js/public/Class.h
js/src/builtin/AsyncFunctions.js
js/src/builtin/Promise.cpp
js/src/builtin/Promise.h
js/src/builtin/SelfHostingDefines.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/jit/CodeGenerator.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsscript.cpp
js/src/moz.build
js/src/vm/AsyncFunction.cpp
js/src/vm/AsyncFunction.h
js/src/vm/CommonPropertyNames.h
js/src/vm/EnvironmentObject.cpp
js/src/vm/EnvironmentObject.h
js/src/vm/GeneratorObject.cpp
js/src/vm/GlobalObject.h
js/src/vm/SelfHosting.cpp
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -780,17 +780,17 @@ struct JSClass {
 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
 // previously allowed, but is now an ES5 violation and thus unsupported.
 //
 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
 // the beginning of every global object's slots for use by the
 // application.
 #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
 #define JSCLASS_GLOBAL_SLOT_COUNT                                             \
-    (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37)
+    (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39)
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                                    \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/AsyncFunctions.js
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Called when creating async function.
+// See the comment for js::CreateAsyncFunction what unwrapped, wrapped and the
+// return value are.
+function AsyncFunction_wrap(unwrapped) {
+    var wrapper = function() {
+        // The try block is required to handle throws in default arguments properly.
+        try {
+            return AsyncFunction_start(callFunction(std_Function_apply, unwrapped, this, arguments));
+        } catch (e) {
+            var promiseCtor = GetBuiltinConstructor('Promise');
+            return callFunction(Promise_static_reject, promiseCtor, e);
+        }
+    };
+    return CreateAsyncFunction(wrapper, unwrapped);
+}
+
+function AsyncFunction_start(generator) {
+    return AsyncFunction_resume(generator, undefined, generator.next);
+}
+
+function AsyncFunction_resume(gen, v, method) {
+    var promiseCtor = GetBuiltinConstructor('Promise');
+    let result;
+    try {
+        // get back into async function, run to next await point
+        result = callFunction(method, gen, v);
+    } catch (exc) {
+        // The async function itself failed.
+        return callFunction(Promise_static_reject, promiseCtor, exc);
+    }
+
+    if (result.done)
+        return callFunction(Promise_static_resolve, promiseCtor, result.value);
+
+    // If we get here, `await` occurred. `gen` is paused at a yield point.
+    return callFunction(Promise_then,
+                        callFunction(Promise_static_resolve, promiseCtor, result.value),
+                        function(val) {
+                            return AsyncFunction_resume(gen, val, gen.next);
+                        }, function (err) {
+                            return AsyncFunction_resume(gen, err, gen.throw);
+                        });
+}
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -674,27 +674,27 @@ CommonStaticResolveRejectImpl(JSContext*
     // Step 6 of Resolve, 4 of Reject.
     args.rval().setObject(*promise);
     return true;
 }
 
 /**
  * ES2016, 25.4.4.4, Promise.reject.
  */
-static bool
-Promise_reject(JSContext* cx, unsigned argc, Value* vp)
+bool
+js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
 {
     return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode);
 }
 
 /**
  * ES2016, 25.4.4.5, Promise.resolve.
  */
-static bool
-Promise_resolve(JSContext* cx, unsigned argc, Value* vp)
+bool
+js::Promise_resolve(JSContext* cx, unsigned argc, Value* vp)
 {
     return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode);
 }
 
 // ES2016, February 12 draft, 25.4.3.1. steps 3-11.
 /* static */
 PromiseObject*
 PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -138,11 +138,16 @@ class PromiseTask : public JS::AsyncTask
 
     // Called on a helper thread after StartAsyncTask. After execute()
     // completes, the JS::FinishAsyncTaskCallback will be called. If this fails
     // the task will be enqueued for deletion at some future point without ever
     // calling finishPromise().
     virtual void execute() = 0;
 };
 
+bool
+Promise_resolve(JSContext* cx, unsigned argc, Value* vp);
+bool
+Promise_reject(JSContext* cx, unsigned argc, Value* vp);
+
 } // namespace js
 
 #endif /* builtin_Promise_h */
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -115,16 +115,19 @@
 #define REGEXP_FLAGS_SLOT 2
 
 #define REGEXP_IGNORECASE_FLAG  0x01
 #define REGEXP_GLOBAL_FLAG      0x02
 #define REGEXP_MULTILINE_FLAG   0x04
 #define REGEXP_STICKY_FLAG      0x08
 #define REGEXP_UNICODE_FLAG     0x10
 
+#define ASYNC_WRAPPED_SLOT 1
+#define ASYNC_UNWRAPPED_SLOT 1
+
 #define MODULE_OBJECT_ENVIRONMENT_SLOT 2
 
 #define MODULE_STATE_FAILED       0
 #define MODULE_STATE_PARSED       1
 #define MODULE_STATE_INSTANTIATED 2
 #define MODULE_STATE_EVALUATED    3
 
 #endif
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -58,17 +58,17 @@ class MOZ_STACK_CLASS BytecodeCompiler
     // Call setters for optional arguments.
     void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
     void setSourceArgumentsNotIncluded();
 
     JSScript* compileGlobalScript(ScopeKind scopeKind);
     JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
     ModuleObject* compileModule();
     bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
-                             GeneratorKind generatorKind);
+                             GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
 
     ScriptSourceObject* sourceObjectPtr() const;
 
   private:
     JSScript* compileScript(HandleObject environment, SharedContext* sc);
     bool checkLength();
     bool createScriptSource();
     bool maybeCompressSource();
@@ -430,17 +430,18 @@ BytecodeCompiler::compileModule()
 
     MOZ_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->isExceptionPending());
     return module;
 }
 
 bool
 BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
                                       Handle<PropertyNameVector> formals,
-                                      GeneratorKind generatorKind)
+                                      GeneratorKind generatorKind,
+                                      FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT(fun->isTenured());
 
     fun->setArgCount(formals.length());
 
     if (!createSourceAndParser())
         return false;
@@ -448,18 +449,18 @@ BytecodeCompiler::compileFunctionBody(Mu
     // Speculatively parse using the default directives implied by the context.
     // If a directive is encountered (e.g., "use strict") that changes how the
     // function should have been parsed, we backup and reparse with the new set
     // of directives.
 
     ParseNode* fn;
     do {
         Directives newDirectives = directives;
-        fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind,
-                                            SyncFunction, directives, &newDirectives);
+        fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
+                                            directives, &newDirectives);
         if (!fn && !handleParseFailure(newDirectives))
             return false;
     } while (!fn);
 
     if (!NameFunctions(cx, fn))
         return false;
 
     if (fn->pn_funbox->function()->isInterpreted()) {
@@ -675,51 +676,63 @@ frontend::CompileLazyFunction(JSContext*
     return bce.emitFunctionScript(pn->pn_body);
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 static bool
 CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
                     Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
-                    HandleScope enclosingScope, GeneratorKind generatorKind)
+                    HandleScope enclosingScope, GeneratorKind generatorKind,
+                    FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(!options.isRunOnce);
 
     // FIXME: make Function pass in two strings and parse them as arguments and
     // ProgramElements respectively.
 
     BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
                               TraceLogger_ParserCompileFunction);
     compiler.setSourceArgumentsNotIncluded();
-    return compiler.compileFunctionBody(fun, formals, generatorKind);
+    return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
 }
 
 bool
 frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
                               const ReadOnlyCompileOptions& options,
                               Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
                               HandleScope enclosingScope)
 {
-    return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator);
+    return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
+                               SyncFunction);
 }
 
 bool
 frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
                               const ReadOnlyCompileOptions& options,
                               Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
 {
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
-                               NotGenerator);
+                               NotGenerator, SyncFunction);
 }
 
-
 bool
 frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
                                    const ReadOnlyCompileOptions& options,
                                    Handle<PropertyNameVector> formals,
                                    JS::SourceBufferHolder& srcBuf)
 {
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
-                               StarGenerator);
+                               StarGenerator, SyncFunction);
 }
+
+bool
+frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
+                                   const ReadOnlyCompileOptions& options,
+                                   Handle<PropertyNameVector> formals,
+                                   JS::SourceBufferHolder& srcBuf)
+{
+    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
+                               StarGenerator, AsyncFunction);
+}
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -63,16 +63,21 @@ CompileFunctionBody(JSContext* cx, Mutab
                     const ReadOnlyCompileOptions& options,
                     Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
 
 MOZ_MUST_USE bool
 CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
                          const ReadOnlyCompileOptions& options,
                          Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
 
+MOZ_MUST_USE bool
+CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
+                         const ReadOnlyCompileOptions& options,
+                         Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+
 ScriptSourceObject*
 CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
 
 /*
  * True if str consists of an IdentifierStart character, followed by one or
  * more IdentifierPart characters, i.e. it matches the IdentifierName production
  * in the language spec.
  *
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6924,16 +6924,21 @@ BytecodeEmitter::emitFunction(ParseNode*
 
     /* Make the function object a literal in the outer script's pool. */
     unsigned index = objectList.add(pn->pn_funbox);
 
     /* Non-hoisted functions simply emit their respective op. */
     if (!pn->functionIsHoisted()) {
         /* JSOP_LAMBDA_ARROW is always preceded by a new.target */
         MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
+        if (funbox->isAsync()) {
+            MOZ_ASSERT(!needsProto);
+            return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow());
+        }
+
         if (fun->isArrow()) {
             if (sc->allowNewTarget()) {
                 if (!emit1(JSOP_NEWTARGET))
                     return false;
             } else {
                 if (!emit1(JSOP_NULL))
                     return false;
             }
@@ -6975,42 +6980,120 @@ BytecodeEmitter::emitFunction(ParseNode*
 
             RootedModuleObject module(cx, sc->asModuleContext()->module());
             if (!module->noteFunctionDeclaration(cx, name, fun))
                 return false;
         } else {
             MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
             MOZ_ASSERT(pn->getOp() == JSOP_NOP);
             switchToPrologue();
-            if (!emitIndex32(JSOP_LAMBDA, index))
-                return false;
+            if (funbox->isAsync()) {
+                if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow()))
+                    return false;
+            } else {
+                if (!emitIndex32(JSOP_LAMBDA, index))
+                    return false;
+            }
             if (!emit1(JSOP_DEFFUN))
                 return false;
             if (!updateSourceCoordNotes(pn->pn_pos.begin))
                 return false;
             switchToMain();
         }
     } else {
         // For functions nested within functions and blocks, make a lambda and
         // initialize the binding name of the function in the current scope.
 
-        auto emitLambda = [index](BytecodeEmitter* bce, const NameLocation&, bool) {
+        bool isAsync = funbox->isAsync();
+        auto emitLambda = [index, isAsync](BytecodeEmitter* bce, const NameLocation&, bool) {
+            if (isAsync) {
+                return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
+                                             /* isArrow = */ false);
+            }
             return bce->emitIndexOp(JSOP_LAMBDA, index);
         };
 
         if (!emitInitializeName(name, emitLambda))
             return false;
         if (!emit1(JSOP_POP))
             return false;
     }
 
     return true;
 }
 
 bool
+BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
+    if (isArrow) {
+        if (sc->allowNewTarget()) {
+            if (!emit1(JSOP_NEWTARGET))
+                return false;
+        } else {
+            if (!emit1(JSOP_NULL))
+                return false;
+        }
+        if (!emitIndex32(JSOP_LAMBDA_ARROW, index))
+            return false;
+    } else {
+        if (!emitIndex32(JSOP_LAMBDA, index))
+            return false;
+    }
+
+    return true;
+}
+
+bool
+BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow) {
+    // needsHomeObject can be true for propertyList for extended class.
+    // In that case push both unwrapped and wrapped function, in order to
+    // initialize home object of unwrapped function, and set wrapped function
+    // as a property.
+    //
+    //   lambda       // unwrapped
+    //   getintrinsic // unwrapped AsyncFunction_wrap
+    //   undefined    // unwrapped AsyncFunction_wrap undefined
+    //   dupat 2      // unwrapped AsyncFunction_wrap undefined unwrapped
+    //   call 1       // unwrapped wrapped
+    //
+    // Emitted code is surrounded by the following code.
+    //
+    //                    // classObj classCtor classProto
+    //   (emitted code)   // classObj classCtor classProto unwrapped wrapped
+    //   swap             // classObj classCtor classProto wrapped unwrapped
+    //   inithomeobject 1 // classObj classCtor classProto wrapped unwrapped
+    //                    //   initialize the home object of unwrapped
+    //                    //   with classProto here
+    //   pop              // classObj classCtor classProto wrapped
+    //   inithiddenprop   // classObj classCtor classProto wrapped
+    //                    //   initialize the property of the classProto
+    //                    //   with wrapped function here
+    //   pop              // classObj classCtor classProto
+    //
+    // needsHomeObject is false for other cases, push wrapped function only.
+    if (needsHomeObject) {
+        if (!emitAsyncWrapperLambda(index, isArrow))
+            return false;
+    }
+    if (!emitAtomOp(cx->names().AsyncFunction_wrap, JSOP_GETINTRINSIC))
+        return false;
+    if (!emit1(JSOP_UNDEFINED))
+        return false;
+    if (needsHomeObject) {
+        if (!emitDupAt(2))
+            return false;
+    } else {
+        if (!emitAsyncWrapperLambda(index, isArrow))
+            return false;
+    }
+    if (!emitCall(JSOP_CALL, 1))
+        return false;
+    return true;
+}
+
+bool
 BytecodeEmitter::emitDo(ParseNode* pn)
 {
     /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
     unsigned noteIndex;
     if (!newSrcNote(SRC_WHILE, &noteIndex))
         return false;
     if (!emit1(JSOP_NOP))
         return false;
@@ -8381,18 +8464,27 @@ BytecodeEmitter::emitPropertyList(ParseN
 
         if (op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER)
             objp.set(nullptr);
 
         if (propdef->pn_right->isKind(PNK_FUNCTION) &&
             propdef->pn_right->pn_funbox->needsHomeObject())
         {
             MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty());
-            if (!emit2(JSOP_INITHOMEOBJECT, isIndex))
-                return false;
+            bool isAsync = propdef->pn_right->pn_funbox->isAsync();
+            if (isAsync) {
+                if (!emit1(JSOP_SWAP))
+                    return false;
+            }
+            if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync))
+                return false;
+            if (isAsync) {
+                if (!emit1(JSOP_POP))
+                    return false;
+            }
         }
 
         // Class methods are not enumerable.
         if (type == ClassBody) {
             switch (op) {
               case JSOP_INITPROP:        op = JSOP_INITHIDDENPROP;          break;
               case JSOP_INITPROP_GETTER: op = JSOP_INITHIDDENPROP_GETTER;   break;
               case JSOP_INITPROP_SETTER: op = JSOP_INITHIDDENPROP_SETTER;   break;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -598,16 +598,19 @@ struct MOZ_STACK_CLASS BytecodeEmitter
     MOZ_MUST_USE bool emitYield(ParseNode* pn);
     MOZ_MUST_USE bool emitYieldOp(JSOp op);
     MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen);
 
     MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
     MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
     MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
 
+    MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
+    MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow);
+
     MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
 
     // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
     // opcode onto the stack in the right order. In the case of SETELEM, the
     // value to be assigned must already be pushed.
     enum class EmitElemOption { Get, Set, Call, IncDec, CompoundAssign };
     MOZ_MUST_USE bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2269,16 +2269,17 @@ Parser<FullParseHandler>::standaloneFunc
     bool duplicatedParam = false;
     for (uint32_t i = 0; i < formals.length(); i++) {
         if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
             return null();
     }
     funbox->hasDuplicateParameters = duplicatedParam;
 
     YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+    AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
     ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
     if (!pn)
         return null();
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
     if (tt != TOK_EOF) {
@@ -2535,16 +2536,20 @@ Parser<ParseHandler>::newFunction(Handle
             allocKind = gc::AllocKind::FUNCTION_EXTENDED;
         }
 #endif
         flags = (generatorKind == NotGenerator
                  ? JSFunction::INTERPRETED_NORMAL
                  : JSFunction::INTERPRETED_GENERATOR);
     }
 
+    // We store the async wrapper in a slot for later access.
+    if (asyncKind == AsyncFunction)
+        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
+
     fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,
                                allocKind, TenuredObject);
     if (!fun)
         return nullptr;
     if (options().selfHostingMode) {
         fun->setIsSelfHostedBuiltin();
 #ifdef DEBUG
         if (isGlobalSelfHostedBuiltin)
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2429,17 +2429,18 @@ CodeGenerator::visitLambda(LLambda* lir)
 
     MOZ_ASSERT(!info.singletonType);
 
     masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
 
     emitLambdaInit(output, envChain, info);
 
     if (info.flags & JSFunction::EXTENDED) {
-        MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin());
+        MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin() ||
+                   info.fun->isAsync());
         static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
         masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
         masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
     }
 
     masm.bind(ool->rejoin());
 }
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -37,16 +37,17 @@
 #include "jit/InlinableNatives.h"
 #include "jit/Ion.h"
 #include "jit/JitFrameIterator.h"
 #include "js/CallNonGenericMethod.h"
 #include "js/Proxy.h"
 #include "vm/Debugger.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
 #include "vm/Shape.h"
 #include "vm/SharedImmutableStringsCache.h"
 #include "vm/StringBuffer.h"
 #include "vm/WrapperObject.h"
 #include "vm/Xdr.h"
 
 #include "jsscriptinlines.h"
 
@@ -1653,40 +1654,46 @@ const JSFunctionSpec js::function_method
     JS_FN(js_call_str,       fun_call,       1,0),
     JS_FN("isGenerator",     fun_isGenerator,0,0),
     JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, JSFUN_HAS_REST),
     JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
     JS_FS_END
 };
 
 static bool
-FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind)
+FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind,
+                    FunctionAsyncKind asyncKind)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Block this call if security callbacks forbid it. */
     Rooted<GlobalObject*> global(cx, &args.callee().global());
     if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
     bool isStarGenerator = generatorKind == StarGenerator;
+    bool isAsync = asyncKind == AsyncFunction;
     MOZ_ASSERT(generatorKind != LegacyGenerator);
+    MOZ_ASSERT_IF(isAsync, isStarGenerator);
+    MOZ_ASSERT_IF(!isStarGenerator, !isAsync);
 
     RootedScript maybeScript(cx);
     const char* filename;
     unsigned lineno;
     bool mutedErrors;
     uint32_t pcOffset;
     DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
                                          &mutedErrors);
 
     const char* introductionType = "Function";
-    if (generatorKind != NotGenerator)
+    if (isAsync)
+        introductionType = "AsyncFunction";
+    else if (generatorKind != NotGenerator)
         introductionType = "GeneratorFunction";
 
     const char* introducerFilename = filename;
     if (maybeScript && maybeScript->scriptSource()->introducerFilename())
         introducerFilename = maybeScript->scriptSource()->introducerFilename();
 
     CompileOptions options(cx);
     options.setMutedErrors(mutedErrors)
@@ -1770,29 +1777,32 @@ FunctionConstructor(JSContext* cx, unsig
      * NB: (new Function) is not lexically closed by its caller, it's just an
      * anonymous function in the top-level scope that its constructor inhabits.
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
      */
     RootedAtom anonymousAtom(cx, cx->names().anonymous);
     RootedObject proto(cx);
     if (isStarGenerator) {
+        // Unwrapped function of async function should use GeneratorFunction,
+        // while wrapped function isn't generator.
         proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
         if (!proto)
             return false;
     } else {
         if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
             return false;
     }
 
     RootedObject globalLexical(cx, &global->lexicalEnvironment());
+    AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
     RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
                                                 JSFunction::INTERPRETED_LAMBDA, globalLexical,
                                                 anonymousAtom, proto,
-                                                AllocKind::FUNCTION, TenuredObject));
+                                                allocKind, TenuredObject));
     if (!fun)
         return false;
 
     if (!JSFunction::setTypeForScriptedFunction(cx, fun))
         return false;
 
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, bodyText))
@@ -1870,34 +1880,49 @@ FunctionConstructor(JSContext* cx, unsig
         fun->setHasRest();
 
     mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
     SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
                                               ? SourceBufferHolder::GiveOwnership
                                               : SourceBufferHolder::NoOwnership;
     bool ok;
     SourceBufferHolder srcBuf(chars.start().get(), chars.length(), ownership);
-    if (isStarGenerator)
+    if (isAsync)
+        ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
+    else if (isStarGenerator)
         ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
     else
         ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
     args.rval().setObject(*fun);
     return ok;
 }
 
 bool
 js::Function(JSContext* cx, unsigned argc, Value* vp)
 {
-    return FunctionConstructor(cx, argc, vp, NotGenerator);
+    return FunctionConstructor(cx, argc, vp, NotGenerator, SyncFunction);
 }
 
 bool
 js::Generator(JSContext* cx, unsigned argc, Value* vp)
 {
-    return FunctionConstructor(cx, argc, vp, StarGenerator);
+    return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
+}
+
+bool
+js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (!FunctionConstructor(cx, argc, vp, StarGenerator, AsyncFunction))
+        return false;
+
+    FixedInvokeArgs<1> args2(cx);
+    args2[0].set(args.rval());
+    return CallSelfHostedFunction(cx, cx->names().AsyncFunction_wrap,
+                                  NullHandleValue, args2, args.rval());
 }
 
 bool
 JSFunction::isBuiltinFunctionConstructor()
 {
     return maybeNative() == Function || maybeNative() == Generator;
 }
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -615,16 +615,19 @@ fun_toStringHelper(JSContext* cx, js::Ha
 namespace js {
 
 extern bool
 Function(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 Generator(JSContext* cx, unsigned argc, Value* vp);
 
+extern bool
+AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
+
 // Allocate a new function backed by a JSNative.  Note that by default this
 // creates a singleton object.
 extern JSFunction*
 NewNativeFunction(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
                   gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                   NewObjectKind newKind = SingletonObject);
 
 // Allocate a new constructor backed by a JSNative.  Note that by default this
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3100,16 +3100,18 @@ Rebase(JSScript* dst, JSScript* src, T* 
 {
     size_t off = reinterpret_cast<uint8_t*>(srcp) - src->data;
     return reinterpret_cast<T*>(dst->data + off);
 }
 
 static JSObject*
 CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun)
 {
+    /* async function should not appear as inner function. */
+    MOZ_ASSERT(!srcFun->isAsync());
     /* NB: Keep this in sync with XDRInterpretedFunction. */
     RootedObject cloneProto(cx);
     if (srcFun->isStarGenerator()) {
         cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
         if (!cloneProto)
             return nullptr;
     }
 
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -319,16 +319,17 @@ UNIFIED_SOURCES += [
     'proxy/OpaqueCrossCompartmentWrapper.cpp',
     'proxy/Proxy.cpp',
     'proxy/ScriptedProxyHandler.cpp',
     'proxy/SecurityWrapper.cpp',
     'proxy/Wrapper.cpp',
     'threading/Mutex.cpp',
     'vm/ArgumentsObject.cpp',
     'vm/ArrayBufferObject.cpp',
+    'vm/AsyncFunction.cpp',
     'vm/Caches.cpp',
     'vm/CallNonGenericMethod.cpp',
     'vm/CharacterEncoding.cpp',
     'vm/CodeCoverage.cpp',
     'vm/Compression.cpp',
     'vm/DateTime.cpp',
     'vm/Debugger.cpp',
     'vm/DebuggerMemory.cpp',
@@ -744,16 +745,17 @@ GENERATED_FILES += [('selfhosted.out.h',
 selfhosted = GENERATED_FILES[('selfhosted.out.h', 'selfhosted.js')]
 selfhosted.script = 'builtin/embedjs.py:generate_selfhosted'
 selfhosted.inputs = [
     'js.msg',
     'builtin/TypedObjectConstants.h',
     'builtin/SelfHostingDefines.h',
     'builtin/Utilities.js',
     'builtin/Array.js',
+    'builtin/AsyncFunctions.js',
     'builtin/Classes.js',
     'builtin/Date.js',
     'builtin/Error.js',
     'builtin/Function.js',
     'builtin/Generator.js',
     'builtin/Intl.js',
     'builtin/IntlData.js',
     'builtin/Iterator.js',
new file mode 100644
--- /dev/null
+++ b/js/src/vm/AsyncFunction.cpp
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/AsyncFunction.h"
+
+#include "jscompartment.h"
+
+#include "builtin/SelfHostingDefines.h"
+#include "vm/GlobalObject.h"
+#include "vm/SelfHosting.h"
+
+using namespace js;
+using namespace js::gc;
+
+/* static */ bool
+GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
+{
+    if (global->getReservedSlot(ASYNC_FUNCTION_PROTO).isObject())
+        return true;
+
+    RootedObject asyncFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+    if (!asyncFunctionProto)
+        return false;
+
+    RootedValue function(cx, global->getConstructor(JSProto_Function));
+    if (!function.toObjectOrNull())
+        return false;
+    RootedObject proto(cx, &function.toObject());
+    RootedAtom name(cx, cx->names().AsyncFunction);
+    RootedObject asyncFunction(cx, NewFunctionWithProto(cx, AsyncFunctionConstructor, 1,
+                                                        JSFunction::NATIVE_CTOR, nullptr, name,
+                                                        proto));
+    if (!asyncFunction)
+        return false;
+    if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
+        return false;
+
+    global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
+    global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
+    return true;
+}
+
+JSFunction*
+js::GetWrappedAsyncFunction(JSFunction* unwrapped)
+{
+    MOZ_ASSERT(unwrapped->isAsync());
+    return &unwrapped->getExtendedSlot(ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
+}
+
+JSFunction*
+js::GetUnwrappedAsyncFunction(JSFunction* wrapper)
+{
+    JSFunction* unwrapped = &wrapper->getExtendedSlot(ASYNC_UNWRAPPED_SLOT).toObject().as<JSFunction>();
+    MOZ_ASSERT(unwrapped->isAsync());
+    return unwrapped;
+}
+
+bool
+js::IsWrappedAsyncFunction(JSContext* cx, JSFunction* wrapper)
+{
+    return IsSelfHostedFunctionWithName(wrapper, cx->names().AsyncWrapped);
+}
+
+bool
+js::CreateAsyncFunction(JSContext* cx, HandleFunction wrapper, HandleFunction unwrapped,
+                        MutableHandleFunction result)
+{
+    // Create a new function with AsyncFunctionPrototype, reusing the script
+    // and the environment of `wrapper` function, and the name and the length
+    // of `unwrapped` function.
+    RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
+    RootedObject scope(cx, wrapper->environment());
+    RootedAtom atom(cx, unwrapped->name());
+    RootedFunction wrapped(cx, NewFunctionWithProto(cx, nullptr, 0,
+                                                    JSFunction::INTERPRETED_LAMBDA,
+                                                    scope, atom, proto,
+                                                    AllocKind::FUNCTION_EXTENDED, TenuredObject));
+    if (!wrapped)
+        return false;
+
+    wrapped->initScript(wrapper->nonLazyScript());
+
+    // Link them each other to make GetWrappedAsyncFunction and
+    // GetUnwrappedAsyncFunction work.
+    unwrapped->setExtendedSlot(ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
+    wrapped->setExtendedSlot(ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
+
+    // The script of `wrapper` is self-hosted, so `wrapped` should also be
+    // set as self-hosted function.
+    wrapped->setIsSelfHostedBuiltin();
+
+    // Set LAZY_FUNCTION_NAME_SLOT to "AsyncWrapped" to make it detectable in
+    // IsWrappedAsyncFunction.
+    wrapped->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(cx->names().AsyncWrapped));
+
+    // The length of the script of `wrapper` is different than the length of
+    // `unwrapped`.  We should set actual length as resolved length, to avoid
+    // using the length of the script.
+    uint16_t length;
+    if (!unwrapped->getLength(cx, &length))
+        return false;
+
+    RootedValue lengthValue(cx, NumberValue(length));
+    if (!DefineProperty(cx, wrapped, cx->names().length, lengthValue,
+                        nullptr, nullptr, JSPROP_READONLY))
+    {
+        return false;
+    }
+
+    result.set(wrapped);
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/vm/AsyncFunction.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_AsyncFunction_h
+#define vm_AsyncFunction_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+namespace js {
+
+JSFunction*
+GetWrappedAsyncFunction(JSFunction* unwrapped);
+
+JSFunction*
+GetUnwrappedAsyncFunction(JSFunction* wrapper);
+
+bool
+IsWrappedAsyncFunction(JSContext* cx, JSFunction* wrapper);
+
+bool
+CreateAsyncFunction(JSContext* cx, HandleFunction wrapper, HandleFunction unwrapped,
+                    MutableHandleFunction result);
+
+} // namespace js
+
+#endif /* vm_AsyncFunction_h */
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -24,16 +24,19 @@
     macro(ArraySpecies, ArraySpecies, "ArraySpecies") \
     macro(ArraySpeciesCreate, ArraySpeciesCreate, "ArraySpeciesCreate") \
     macro(ArrayToLocaleString, ArrayToLocaleString, "ArrayToLocaleString") \
     macro(ArrayType, ArrayType, "ArrayType") \
     macro(ArrayValues, ArrayValues, "ArrayValues") \
     macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
     macro(as, as, "as") \
     macro(Async, Async, "Async") \
+    macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
+    macro(AsyncFunction_wrap, AsyncFunction_wrap, "AsyncFunction_wrap") \
+    macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
     macro(async, async, "async") \
     macro(await, await, "await") \
     macro(Bool8x16, Bool8x16, "Bool8x16") \
     macro(Bool16x8, Bool16x8, "Bool16x8") \
     macro(Bool32x4, Bool32x4, "Bool32x4") \
     macro(Bool64x2, Bool64x2, "Bool64x2") \
     macro(boundWithSpace, boundWithSpace, "bound ") \
     macro(breakdown, breakdown, "breakdown") \
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -12,16 +12,17 @@
 
 #include "jscompartment.h"
 #include "jsiter.h"
 
 #include "builtin/ModuleObject.h"
 #include "frontend/ParseNode.h"
 #include "gc/Policy.h"
 #include "vm/ArgumentsObject.h"
+#include "vm/AsyncFunction.h"
 #include "vm/GlobalObject.h"
 #include "vm/ProxyObject.h"
 #include "vm/Shape.h"
 #include "vm/Xdr.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
@@ -1018,17 +1019,19 @@ const Class LexicalEnvironmentObject::cl
     JSCLASS_IS_ANONYMOUS,
     JS_NULL_CLASS_OPS,
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT,
     JS_NULL_OBJECT_OPS
 };
 
 /* static */ NamedLambdaObject*
-NamedLambdaObject::create(JSContext* cx, HandleFunction callee, HandleObject enclosing,
+NamedLambdaObject::create(JSContext* cx, HandleFunction callee,
+                          HandleFunction func,
+                          HandleObject enclosing,
                           gc::InitialHeap heap)
 {
     MOZ_ASSERT(callee->isNamedLambda());
     RootedScope scope(cx, callee->nonLazyScript()->maybeNamedLambdaScope());
     MOZ_ASSERT(scope && scope->environmentShape());
     MOZ_ASSERT(scope->environmentShape()->slot() == lambdaSlot());
     MOZ_ASSERT(!scope->environmentShape()->writable());
 
@@ -1040,32 +1043,40 @@ NamedLambdaObject::create(JSContext* cx,
 #endif
 
     LexicalEnvironmentObject* obj =
         LexicalEnvironmentObject::createTemplateObject(cx, scope.as<LexicalScope>(),
                                                        enclosing, heap);
     if (!obj)
         return nullptr;
 
-    obj->initFixedSlot(lambdaSlot(), ObjectValue(*callee));
+    obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
     return static_cast<NamedLambdaObject*>(obj);
 }
 
 /* static */ NamedLambdaObject*
 NamedLambdaObject::createTemplateObject(JSContext* cx, HandleFunction callee, gc::InitialHeap heap)
 {
-    return create(cx, callee, nullptr, heap);
+    return create(cx, callee, callee, nullptr, heap);
 }
 
 /* static */ NamedLambdaObject*
 NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame)
 {
     RootedFunction fun(cx, frame.callee());
     RootedObject enclosing(cx, frame.environmentChain());
-    return create(cx, fun, enclosing, gc::DefaultHeap);
+    return create(cx, fun, fun, enclosing, gc::DefaultHeap);
+}
+
+/* static */ NamedLambdaObject*
+NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame, HandleFunction replacement)
+{
+    RootedFunction fun(cx, frame.callee());
+    RootedObject enclosing(cx, frame.environmentChain());
+    return create(cx, fun, replacement, enclosing, gc::DefaultHeap);
 }
 
 /* static */ size_t
 NamedLambdaObject::lambdaSlot()
 {
     // Named lambda environments have exactly one name.
     return JSSLOT_FREE(&LexicalEnvironmentObject::class_);
 }
@@ -3360,17 +3371,25 @@ js::InitFunctionEnvironmentObjects(JSCon
 {
     MOZ_ASSERT(frame.isFunctionFrame());
     MOZ_ASSERT(frame.callee()->needsSomeEnvironmentObject());
 
     RootedFunction callee(cx, frame.callee());
 
     // Named lambdas may have an environment that holds itself for recursion.
     if (callee->needsNamedLambdaEnvironment()) {
-        NamedLambdaObject* declEnv = NamedLambdaObject::create(cx, frame);
+        NamedLambdaObject* declEnv;
+        if (callee->isAsync()) {
+            // Named async function needs special environment to return
+            // wrapped function for the binding.
+            RootedFunction fun(cx, GetWrappedAsyncFunction(callee));
+            declEnv = NamedLambdaObject::create(cx, frame, fun);
+        } else {
+            declEnv = NamedLambdaObject::create(cx, frame);
+        }
         if (!declEnv)
             return false;
         frame.pushOnEnvironmentChain(*declEnv);
     }
 
     // If the function has parameter default expressions, there may be an
     // extra environment to hold the parameters.
     if (callee->needsCallObject()) {
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -510,23 +510,26 @@ class LexicalEnvironmentObject : public 
     // For extensible lexical environments, the 'this' value for its
     // scope. Otherwise asserts.
     Value thisValue() const;
 };
 
 class NamedLambdaObject : public LexicalEnvironmentObject
 {
     static NamedLambdaObject* create(JSContext* cx, HandleFunction callee,
+                                     HandleFunction replacement,
                                      HandleObject enclosing, gc::InitialHeap heap);
 
   public:
     static NamedLambdaObject* createTemplateObject(JSContext* cx, HandleFunction callee,
                                                    gc::InitialHeap heap);
 
     static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame);
+    static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame,
+                                     HandleFunction replacement);
 
     // For JITs.
     static size_t lambdaSlot();
 };
 
 // A non-syntactic dynamic scope object that captures non-lexical
 // bindings. That is, a scope object that captures both qualified var
 // assignments and unqualified bareword assignments. Its parent is always the
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -255,18 +255,18 @@ static JSObject*
 NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle<GlobalObject*> global)
 {
     RootedObject proto(cx, global->getOrCreateObjectPrototype(cx));
     if (!proto)
         return nullptr;
     return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
 }
 
-static JSObject*
-NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
+JSObject*
+js::NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
 {
     RootedObject proto(cx, global->getOrCreateFunctionPrototype(cx));
     if (!proto)
         return nullptr;
     return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
 }
 
 /* static */ bool
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -95,16 +95,18 @@ class GlobalObject : public NativeObject
         EMPTY_GLOBAL_SCOPE,
         ITERATOR_PROTO,
         ARRAY_ITERATOR_PROTO,
         STRING_ITERATOR_PROTO,
         LEGACY_GENERATOR_OBJECT_PROTO,
         STAR_GENERATOR_OBJECT_PROTO,
         STAR_GENERATOR_FUNCTION_PROTO,
         STAR_GENERATOR_FUNCTION,
+        ASYNC_FUNCTION_PROTO,
+        ASYNC_FUNCTION,
         MAP_ITERATOR_PROTO,
         SET_ITERATOR_PROTO,
         COLLATOR_PROTO,
         NUMBER_FORMAT_PROTO,
         DATE_TIME_FORMAT_PROTO,
         MODULE_PROTO,
         IMPORT_ENTRY_PROTO,
         EXPORT_ENTRY_PROTO,
@@ -574,16 +576,29 @@ class GlobalObject : public NativeObject
     }
 
     static JSObject* getOrCreateStarGeneratorFunction(JSContext* cx,
                                                       Handle<GlobalObject*> global)
     {
         return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators);
     }
 
+    static NativeObject* getOrCreateAsyncFunctionPrototype(JSContext* cx,
+                                                           Handle<GlobalObject*> global)
+    {
+        return MaybeNativeObject(global->getOrCreateObject(cx, ASYNC_FUNCTION_PROTO,
+                                                           initAsyncFunction));
+    }
+
+    static JSObject* getOrCreateAsyncFunction(JSContext* cx,
+                                              Handle<GlobalObject*> global)
+    {
+        return global->getOrCreateObject(cx, ASYNC_FUNCTION, initAsyncFunction);
+    }
+
     static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx,
                                                      Handle<GlobalObject*> global)
     {
         return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto);
     }
 
     static JSObject* getOrCreateSetIteratorPrototype(JSContext* cx,
                                                      Handle<GlobalObject*> global)
@@ -723,16 +738,18 @@ class GlobalObject : public NativeObject
     static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in vm/GeneratorObject.cpp.
     static bool initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initStarGenerators(JSContext* cx, Handle<GlobalObject*> global);
 
+    static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
+
     // Implemented in builtin/MapObject.cpp.
     static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in Intl.cpp.
     static bool initIntlObject(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/ModuleObject.cpp
@@ -983,16 +1000,19 @@ inline JSProtoKey
 StandardProtoKeyOrNull(const JSObject* obj)
 {
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
     if (key == JSProto_Error)
         return GetExceptionProtoKey(obj->as<ErrorObject>().type());
     return key;
 }
 
+JSObject*
+NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global);
+
 } // namespace js
 
 template<>
 inline bool
 JSObject::is<js::GlobalObject>() const
 {
     return !!(getClass()->flags & JSCLASS_IS_GLOBAL);
 }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -34,16 +34,17 @@
 #include "builtin/TypedObject.h"
 #include "builtin/WeakSetObject.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "jit/AtomicOperations.h"
 #include "jit/InlinableNatives.h"
 #include "js/CharacterEncoding.h"
 #include "js/Date.h"
+#include "vm/AsyncFunction.h"
 #include "vm/Compression.h"
 #include "vm/GeneratorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/RegExpObject.h"
 #include "vm/String.h"
 #include "vm/StringBuffer.h"
 #include "vm/TypedArrayCommon.h"
 #include "vm/WrapperObject.h"
@@ -1928,16 +1929,33 @@ intrinsic_HostPromiseRejectionTracker(JS
     Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
     mozilla::DebugOnly<bool> isHandled = args[1].toBoolean();
     MOZ_ASSERT(isHandled, "HostPromiseRejectionTracker intrinsic currently only marks as handled");
     cx->runtime()->removeUnhandledRejectedPromise(cx, promise);
     args.rval().setUndefined();
     return true;
 }
 
+bool
+intrinsic_CreateAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 2);
+
+    RootedFunction wrapper(cx, &args[0].toObject().as<JSFunction>());
+    RootedFunction unwrapped(cx, &args[1].toObject().as<JSFunction>());
+
+    RootedFunction wrapped(cx);
+    if (!CreateAsyncFunction(cx, wrapper, unwrapped, &wrapped))
+        return false;
+
+    args.rval().setObject(*wrapped);
+    return true;
+}
+
 /**
  * Returns the default locale as a well-formed, but not necessarily canonicalized,
  * BCP-47 language tag.
  */
 static bool
 intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -2393,16 +2411,18 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
     JS_FN("_NameForTypedArray",      intrinsic_NameForTypedArray, 1,0),
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
     JS_FN("LocalTZA",                intrinsic_LocalTZA,                0,0),
     JS_FN("AddContentTelemetry",     intrinsic_AddContentTelemetry,     2,0),
 
+    JS_FN("CreateAsyncFunction",     intrinsic_CreateAsyncFunction,     1,0),
+
     JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing,        0,0,
                     IntrinsicIsConstructing),
     JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel,       3,0,
                     IntrinsicSubstringKernel),
     JS_INLINABLE_FN("_DefineDataProperty",              intrinsic_DefineDataProperty,      4,0,
                     IntrinsicDefineDataProperty),
     JS_INLINABLE_FN("ObjectHasPrototype",               intrinsic_ObjectHasPrototype,      2,0,
                     IntrinsicObjectHasPrototype),
@@ -2535,16 +2555,19 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("_GetObjectFromIncumbentGlobal",  intrinsic_GetObjectFromIncumbentGlobal, 0, 0),
     JS_FN("IsPromise",                      intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1,0),
     JS_FN("IsWrappedPromise",               intrinsic_IsWrappedPromiseObject,     1, 0),
     JS_FN("_EnqueuePromiseReactionJob",     intrinsic_EnqueuePromiseReactionJob,  2, 0),
     JS_FN("HostPromiseRejectionTracker",    intrinsic_HostPromiseRejectionTracker,2, 0),
     JS_FN("CallPromiseMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<PromiseObject>>,      2,0),
 
+    JS_FN("Promise_static_resolve",                Promise_resolve, 1, 0),
+    JS_FN("Promise_static_reject",                 Promise_reject, 1, 0),
+
     // See builtin/TypedObject.h for descriptors of the typedobj functions.
     JS_FN("NewOpaqueTypedObject",           js::NewOpaqueTypedObject, 1, 0),
     JS_FN("NewDerivedTypedObject",          js::NewDerivedTypedObject, 3, 0),
     JS_FN("TypedObjectBuffer",              TypedObject::GetBuffer, 1, 0),
     JS_FN("TypedObjectByteOffset",          TypedObject::GetByteOffset, 1, 0),
     JS_FN("AttachTypedObject",              js::AttachTypedObject, 3, 0),
     JS_FN("TypedObjectIsAttached",          js::TypedObjectIsAttached, 1, 0),
     JS_FN("TypedObjectTypeDescr",           js::TypedObjectTypeDescr, 1, 0),