Bug 1530324 - Part 8: Remove wrapper function for async functions. r=arai
authorAndré Bargull <andre.bargull@gmail.com>
Tue, 26 Feb 2019 08:35:41 -0800
changeset 506189 55b6a8c4e0154ac41f710bf1f3f5627c68ce8d42
parent 506188 dfcdd2084fea42de8d450614a26f196d12fe8106
child 506190 ec32c653cca2ca7eff0aac75df3a16306e37fdee
push idunknown
push userunknown
push dateunknown
reviewersarai
bugs1530324
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1530324 - Part 8: Remove wrapper function for async functions. r=arai
js/src/builtin/ModuleObject.cpp
js/src/builtin/Object.cpp
js/src/builtin/TestingFunctions.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ObjectEmitter.cpp
js/src/frontend/ObjectEmitter.h
js/src/frontend/Parser.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/Lowering.cpp
js/src/jit/MIR.h
js/src/jit/shared/LIR-shared.h
js/src/tests/non262/async-functions/clone.js
js/src/vm/ArgumentsObject.cpp
js/src/vm/AsyncFunction.cpp
js/src/vm/AsyncFunction.h
js/src/vm/AsyncIteration.cpp
js/src/vm/BytecodeUtil.cpp
js/src/vm/Debugger.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/EnvironmentObject.h
js/src/vm/GeneratorObject.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/Interpreter.cpp
js/src/vm/JSFunction.cpp
js/src/vm/JSScript.cpp
js/src/vm/Opcodes.h
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -995,24 +995,16 @@ bool ModuleObject::noteFunctionDeclarati
 
   for (const auto& funDecl : *funDecls) {
     fun = funDecl.fun;
     obj = Lambda(cx, fun, env);
     if (!obj) {
       return false;
     }
 
-    if (fun->isAsync() && !fun->isGenerator()) {
-      obj = WrapAsyncFunction(cx, obj.as<JSFunction>());
-    }
-
-    if (!obj) {
-      return false;
-    }
-
     value = ObjectValue(*obj);
     if (!SetProperty(cx, env, funDecl.name->asPropertyName(), value)) {
       return false;
     }
   }
 
   js_delete(funDecls);
   self->setReservedSlot(FunctionDeclarationsSlot, UndefinedValue());
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -363,17 +363,17 @@ JSString* js::ObjectToSource(JSContext* 
         if (!buf.append("get ")) {
           return false;
         }
       } else if (kind == PropertyKind::Setter) {
         if (!buf.append("set ")) {
           return false;
         }
       } else if (kind == PropertyKind::Method && fun) {
-        if (IsWrappedAsyncFunction(fun) || fun->isAsync()) {
+        if (fun->isAsync()) {
           if (!buf.append("async ")) {
             return false;
           }
         }
 
         if (fun->isGenerator()) {
           if (!buf.append('*')) {
             return false;
@@ -407,17 +407,16 @@ JSString* js::ObjectToSource(JSContext* 
       }
     }
     return true;
   };
 
   RootedId id(cx);
   Rooted<PropertyDescriptor> desc(cx);
   RootedValue val(cx);
-  RootedFunction fun(cx);
   for (size_t i = 0; i < idv.length(); ++i) {
     id = idv[i];
     if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) {
       return nullptr;
     }
 
     if (!desc.object()) {
       continue;
@@ -435,27 +434,23 @@ JSString* js::ObjectToSource(JSContext* 
         if (!AddProperty(id, val, PropertyKind::Setter)) {
           return nullptr;
         }
       }
       continue;
     }
 
     val.set(desc.value());
-    if (IsFunctionObject(val, fun.address())) {
-      if (IsWrappedAsyncFunction(fun)) {
-        fun = GetUnwrappedAsyncFunction(fun);
+
+    JSFunction* fun;
+    if (IsFunctionObject(val, &fun) && fun->isMethod()) {
+      if (!AddProperty(id, val, PropertyKind::Method)) {
+        return nullptr;
       }
-
-      if (fun->isMethod()) {
-        if (!AddProperty(id, val, PropertyKind::Method)) {
-          return nullptr;
-        }
-        continue;
-      }
+      continue;
     }
 
     if (!AddProperty(id, val, PropertyKind::Normal)) {
       return nullptr;
     }
   }
 
   if (!buf.append('}')) {
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -5434,21 +5434,16 @@ JSScript* js::TestingFunctionArgumentToS
     JSObject* target = fun->getBoundFunctionTarget();
     if (target && target->is<JSFunction>()) {
       fun = &target->as<JSFunction>();
     } else {
       break;
     }
   }
 
-  // Get unwrapped async function.
-  if (IsWrappedAsyncFunction(fun)) {
-    fun = GetUnwrappedAsyncFunction(fun);
-  }
-
   if (!fun->isInterpreted()) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_TESTING_SCRIPTS_ONLY);
     return nullptr;
   }
 
   JSScript* script = JSFunction::getOrCreateScript(cx, fun);
   if (!script) {
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3194,41 +3194,25 @@ bool BytecodeEmitter::emitAnonymousFunct
 }
 
 bool BytecodeEmitter::emitAnonymousFunctionWithComputedName(
     ParseNode* node, FunctionPrefixKind prefixKind) {
   MOZ_ASSERT(node->isDirectRHSAnonFunction());
 
   if (node->is<FunctionNode>()) {
     if (!emitTree(node)) {
-      //            [stack] # !isAsync || isGenerator || !needsHomeObject
       //            [stack] NAME FUN
-      //            [stack] # isAsync && !isGenerator && needsHomeObject
-      //            [stack] NAME UNWRAPPED WRAPPED
-      return false;
-    }
-    unsigned depth = 1;
-    FunctionNode* funNode = &node->as<FunctionNode>();
-    FunctionBox* funbox = funNode->funbox();
-    if (funbox->isAsync() && !funbox->isGenerator() &&
-        funbox->needsHomeObject()) {
-      depth = 2;
-    }
-    if (!emitDupAt(depth)) {
-      //            [stack] # !isAsync || !needsHomeObject
+      return false;
+    }
+    if (!emitDupAt(1)) {
       //            [stack] NAME FUN NAME
-      //            [stack] # isAsync && needsHomeObject
-      //            [stack] NAME UNWRAPPED WRAPPED NAME
       return false;
     }
     if (!emit2(JSOP_SETFUNNAME, uint8_t(prefixKind))) {
-      //            [stack] # !isAsync || !needsHomeObject
       //            [stack] NAME FUN
-      //            [stack] # isAsync && needsHomeObject
-      //            [stack] NAME UNWRAPPED WRAPPED
       return false;
     }
     return true;
   }
 
   MOZ_ASSERT(node->is<ClassNode>());
   MOZ_ASSERT(prefixKind == FunctionPrefixKind::None);
 
@@ -5804,20 +5788,16 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::e
   // Make the function object a literal in the outer script's pool.
   unsigned index = objectList.add(funNode->funbox());
 
   // Non-hoisted functions simply emit their respective op.
   if (!funNode->functionIsHoisted()) {
     // JSOP_LAMBDA_ARROW is always preceded by a new.target
     MOZ_ASSERT(fun->isArrow() ==
                (funNode->syntaxKind() == FunctionSyntaxKind::Arrow));
-    if (funbox->isAsync() && !funbox->isGenerator()) {
-      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)) {
@@ -5863,123 +5843,45 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::e
       RootedModuleObject module(cx, sc->asModuleContext()->module());
       if (!module->noteFunctionDeclaration(cx, name, fun)) {
         return false;
       }
     } else {
       MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
       MOZ_ASSERT(funNode->syntaxKind() == FunctionSyntaxKind::Statement);
       MOZ_ASSERT(inPrologue());
-      if (funbox->isAsync() && !funbox->isGenerator()) {
-        if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow())) {
-          return false;
-        }
-      } else {
-        if (!emitIndex32(JSOP_LAMBDA, index)) {
-          return false;
-        }
+      if (!emitIndex32(JSOP_LAMBDA, index)) {
+        return false;
       }
       if (!emit1(JSOP_DEFFUN)) {
         return false;
       }
     }
   } else {
     // For functions nested within functions and blocks, make a lambda and
     // initialize the binding name of the function in the current scope.
 
     NameOpEmitter noe(this, name, NameOpEmitter::Kind::Initialize);
     if (!noe.prepareForRhs()) {
       return false;
     }
-    if (funbox->isAsync() && !funbox->isGenerator()) {
-      if (!emitAsyncWrapper(index, /* needsHomeObject = */ false,
-                            /* isArrow = */ false)) {
-        return false;
-      }
-    } else {
-      if (!emitIndexOp(JSOP_LAMBDA, index)) {
-        return false;
-      }
+    if (!emitIndexOp(JSOP_LAMBDA, index)) {
+      return false;
     }
     if (!noe.emitAssignment()) {
       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
-  //   dup          // unwrapped unwrapped
-  //   toasync      // 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
-  //   dupat 2          // classObj classCtor classProto wrapped unwrapped
-  //   classProto inithomeobject   // 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 (!emitAsyncWrapperLambda(index, isArrow)) {
-    return false;
-  }
-  if (needsHomeObject) {
-    if (!emit1(JSOP_DUP)) {
-      return false;
-    }
-  }
-  if (!emit1(JSOP_TOASYNC)) {
-    return false;
-  }
-  return true;
-}
-
 bool BytecodeEmitter::emitDo(BinaryNode* doNode) {
   ParseNode* bodyNode = doNode->left();
 
   DoWhileEmitter doWhile(this);
   if (!doWhile.emitBody(Some(doNode->pn_pos.begin),
                         getOffsetForLoop(bodyNode))) {
     return false;
   }
@@ -6170,19 +6072,17 @@ bool BytecodeEmitter::emitReturn(UnaryNo
   }
 
   /* Push a return value */
   if (ParseNode* expr = returnNode->kid()) {
     if (!emitTree(expr)) {
       return false;
     }
 
-    bool isAsyncGenerator =
-        sc->asFunctionBox()->isAsync() && sc->asFunctionBox()->isGenerator();
-    if (isAsyncGenerator) {
+    if (sc->asFunctionBox()->isAsync() && sc->asFunctionBox()->isGenerator()) {
       if (!emitAwaitInInnermostScope()) {
         return false;
       }
     }
   } else {
     /* No explicit return value provided */
     if (!emit1(JSOP_UNDEFINED)) {
       return false;
@@ -6329,18 +6229,17 @@ bool BytecodeEmitter::emitYield(UnaryNod
   } else {
     if (!emit1(JSOP_UNDEFINED)) {
       //            [stack] ITEROBJ UNDEFINED
       return false;
     }
   }
 
   // 11.4.3.7 AsyncGeneratorYield step 5.
-  bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
-  if (isAsyncGenerator) {
+  if (sc->asFunctionBox()->isAsync()) {
     if (!emitAwaitInInnermostScope()) {
       //            [stack] ITEROBJ RESULT
       return false;
     }
   }
 
   if (needsIteratorResult) {
     if (!emitFinishIteratorResult(false)) {
@@ -7921,21 +7820,22 @@ bool BytecodeEmitter::emitPropertyList(L
         if (!emitTree(propVal)) {
           //        [stack] CTOR? OBJ CTOR? KEY? VAL
           return false;
         }
       }
 
       if (propVal->is<FunctionNode>() &&
           propVal->as<FunctionNode>().funbox()->needsHomeObject()) {
-        FunctionBox* funbox = propVal->as<FunctionNode>().funbox();
-        MOZ_ASSERT(funbox->function()->allowSuperProperty());
-
-        bool isAsyncNonGenerator = funbox->isAsync() && !funbox->isGenerator();
-        if (!pe.emitInitHomeObject(isAsyncNonGenerator)) {
+        MOZ_ASSERT(propVal->as<FunctionNode>()
+                       .funbox()
+                       ->function()
+                       ->allowSuperProperty());
+
+        if (!pe.emitInitHomeObject()) {
           //        [stack] CTOR? OBJ CTOR? KEY? FUN
           return false;
         }
       }
       return true;
     };
 
     PropertyEmitter::Kind kind =
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -650,20 +650,16 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
     return emitAwaitInScope(*innermostEmitterScope());
   }
   MOZ_MUST_USE bool emitAwaitInInnermostScope(UnaryNode* awaitNode);
   MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
 
   MOZ_MUST_USE bool emitPropLHS(PropertyAccess* prop);
   MOZ_MUST_USE bool emitPropIncDec(UnaryNode* incDec);
 
-  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(UnaryNode* 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, Call, IncDec, CompoundAssign, Ref };
   MOZ_MUST_USE bool emitElemOperands(PropertyByValue* elem,
                                      EmitElemOption opts);
--- a/js/src/frontend/ObjectEmitter.cpp
+++ b/js/src/frontend/ObjectEmitter.cpp
@@ -222,60 +222,44 @@ bool PropertyEmitter::prepareForComputed
   }
 
 #ifdef DEBUG
   propertyState_ = PropertyState::ComputedValue;
 #endif
   return true;
 }
 
-bool PropertyEmitter::emitInitHomeObject(
-    bool isAsyncNonGenerator /* = false */) {
+bool PropertyEmitter::emitInitHomeObject() {
   MOZ_ASSERT(propertyState_ == PropertyState::PropValue ||
              propertyState_ == PropertyState::IndexValue ||
              propertyState_ == PropertyState::ComputedValue);
 
   //                [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
 
-  if (isAsyncNonGenerator) {
-    //              [stack] CTOR? HOMEOBJ CTOR? KEY? UNWRAPPED WRAPPED
-    if (!bce_->emit1(JSOP_SWAP)) {
-      //            [stack] CTOR? HOMEOBJ CTOR? KEY? WRAPPED UNWRAPPED
-      return false;
-    }
-  }
-
   // There are the following values on the stack conditionally, between
   // HOMEOBJ and FUN:
   //   * the 2nd CTOR if isStatic_
   //   * KEY if isIndexOrComputed_
-  //   * WRAPPED if isAsync
   //
   // JSOP_INITHOMEOBJECT uses one of the following:
   //   * HOMEOBJ if !isStatic_
   //     (`super.foo` points the super prototype property)
   //   * the 2nd CTOR if isStatic_
   //     (`super.foo` points the super constructor property)
-  if (!bce_->emitDupAt(1 + isIndexOrComputed_ + isAsyncNonGenerator)) {
+  if (!bce_->emitDupAt(1 + isIndexOrComputed_)) {
     //              [stack] # non-static method
-    //              [stack] CTOR? HOMEOBJ CTOR KEY? WRAPPED? FUN CTOR
+    //              [stack] CTOR? HOMEOBJ CTOR KEY? FUN CTOR
     //              [stack] # static method
-    //              [stack] CTOR? HOMEOBJ KEY? WRAPPED? FUN HOMEOBJ
+    //              [stack] CTOR? HOMEOBJ KEY? FUN HOMEOBJ
     return false;
   }
   if (!bce_->emit1(JSOP_INITHOMEOBJECT)) {
-    //              [stack] CTOR? HOMEOBJ CTOR? KEY? WRAPPED? FUN
+    //              [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
     return false;
   }
-  if (isAsyncNonGenerator) {
-    if (!bce_->emit1(JSOP_POP)) {
-      //            [stack] CTOR? HOMEOBJ CTOR? KEY? WRAPPED
-      return false;
-    }
-  }
 
 #ifdef DEBUG
   if (propertyState_ == PropertyState::PropValue) {
     propertyState_ = PropertyState::InitHomeObj;
   } else if (propertyState_ == PropertyState::IndexValue) {
     propertyState_ = PropertyState::InitHomeObjForIndex;
   } else {
     propertyState_ = PropertyState::InitHomeObjForComputed;
--- a/js/src/frontend/ObjectEmitter.h
+++ b/js/src/frontend/ObjectEmitter.h
@@ -237,17 +237,17 @@ class MOZ_STACK_CLASS PropertyEmitter {
   // { [ key ]: value }
   //   ^
   //   |
   //   keyPos
   MOZ_MUST_USE bool prepareForComputedPropKey(
       const mozilla::Maybe<uint32_t>& keyPos, Kind kind = Kind::Prototype);
   MOZ_MUST_USE bool prepareForComputedPropValue();
 
-  MOZ_MUST_USE bool emitInitHomeObject(bool isAsyncNonGenerator = false);
+  MOZ_MUST_USE bool emitInitHomeObject();
 
   // @param key
   //        Property key
   MOZ_MUST_USE bool emitInitProp(JS::Handle<JSAtom*> key);
   MOZ_MUST_USE bool emitInitGetter(JS::Handle<JSAtom*> key);
   MOZ_MUST_USE bool emitInitSetter(JS::Handle<JSAtom*> key);
 
   MOZ_MUST_USE bool emitInitIndexProp();
@@ -510,17 +510,17 @@ class MOZ_RAII AutoSaveLocalStrictMode {
 //     emit(function_for_m);
 //     ce.emitInitHomeObject();
 //     ce.emitInitProp(atom_of_m);
 //
 //   `async m() { super.f(); }` in class
 //     // after emitInitConstructor/emitInitDefaultConstructor
 //     ce.prepareForPropValue(Some(offset_of_m));
 //     emit(function_for_m);
-//     ce.emitInitHomeObject(true);
+//     ce.emitInitHomeObject();
 //     ce.emitInitProp(atom_of_m);
 //
 //   `get p() { super.f(); }` in class
 //     // after emitInitConstructor/emitInitDefaultConstructor
 //     ce.prepareForPropValue(Some(offset_of_p));
 //     emit(function_for_p);
 //     ce.emitInitHomeObject();
 //     ce.emitInitGetter(atom_of_m);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1981,22 +1981,16 @@ JSFunction* AllocNewFunction(JSContext* 
       }
 #endif
       flags = (generatorKind == GeneratorKind::NotGenerator &&
                        asyncKind == FunctionAsyncKind::SyncFunction
                    ? JSFunction::INTERPRETED_NORMAL
                    : JSFunction::INTERPRETED_GENERATOR_OR_ASYNC);
   }
 
-  // We store the async wrapper in a slot for later access.
-  if (asyncKind == FunctionAsyncKind::AsyncFunction &&
-      generatorKind == GeneratorKind::NotGenerator) {
-    allocKind = gc::AllocKind::FUNCTION_EXTENDED;
-  }
-
   fun = NewFunctionWithProto(cx, nullptr, 0, flags, nullptr, atom, proto,
                              allocKind, TenuredObject);
   if (!fun) {
     return nullptr;
   }
   if (isSelfHosting) {
     fun->setIsSelfHostedBuiltin();
 #ifdef DEBUG
@@ -2562,25 +2556,30 @@ GeneralParser<ParseHandler, Unit>::funct
     if (!skipLazyInnerFunction(funNode, toStringStart, kind, tryAnnexB)) {
       return null();
     }
 
     return funNode;
   }
 
   RootedObject proto(cx_);
-  if (generatorKind == GeneratorKind::Generator ||
-      asyncKind == FunctionAsyncKind::AsyncFunction) {
-    if (generatorKind == GeneratorKind::Generator &&
-        asyncKind == FunctionAsyncKind::AsyncFunction) {
-      proto = GlobalObject::getOrCreateAsyncGenerator(cx_, cx_->global());
-    } else {
-      proto = GlobalObject::getOrCreateGeneratorFunctionPrototype(
-          cx_, cx_->global());
-    }
+  if (asyncKind == FunctionAsyncKind::AsyncFunction &&
+      generatorKind == GeneratorKind::Generator) {
+    proto = GlobalObject::getOrCreateAsyncGenerator(cx_, cx_->global());
+    if (!proto) {
+      return null();
+    }
+  } else if (asyncKind == FunctionAsyncKind::AsyncFunction) {
+    proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx_, cx_->global());
+    if (!proto) {
+      return null();
+    }
+  } else if (generatorKind == GeneratorKind::Generator) {
+    proto =
+        GlobalObject::getOrCreateGeneratorFunctionPrototype(cx_, cx_->global());
     if (!proto) {
       return null();
     }
   }
   RootedFunction fun(
       cx_, newFunction(funName, kind, generatorKind, asyncKind, proto));
   if (!fun) {
     return null();
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -4612,38 +4612,16 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   }
 
   masm.bind(&done);
   frame.pop();  // Pop index.
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*ToAsyncFn)(JSContext*, HandleFunction);
-static const VMFunction ToAsyncInfo =
-    FunctionInfo<ToAsyncFn>(js::WrapAsyncFunction, "ToAsync");
-
-template <typename Handler>
-bool BaselineCodeGen<Handler>::emit_JSOP_TOASYNC() {
-  frame.syncStack(0);
-  masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
-
-  prepareVMCall();
-  pushArg(R0.scratchReg());
-
-  if (!callVM(ToAsyncInfo)) {
-    return false;
-  }
-
-  masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
-  frame.pop();
-  frame.push(R0);
-  return true;
-}
-
 typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject, HandleValue);
 static const VMFunction ToAsyncIterInfo =
     FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOASYNCITER() {
   frame.syncStack(0);
   masm.unboxObject(frame.addressOfStackValue(-2), R0.scratchReg());
@@ -6102,16 +6080,17 @@ MethodStatus BaselineCompiler::emitBody(
       return Method_Error;
     }
 
     switch (op) {
       // ===== NOT Yet Implemented =====
       case JSOP_FORCEINTERPRETER:
         // Intentionally not implemented.
       case JSOP_UNUSED71:
+      case JSOP_UNUSED149:
       case JSOP_LIMIT:
         // === !! WARNING WARNING WARNING !! ===
         // DO NOT add new ops to this list! All bytecode ops MUST have Baseline
         // support. Follow-up bugs are not acceptable.
         JitSpew(JitSpew_BaselineAbort, "Unhandled op: %s", CodeName[op]);
         return Method_CantCompile;
 
 #define EMIT_OP(OP)                                            \
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -186,17 +186,16 @@ namespace jit {
   _(JSOP_RECREATELEXICALENV)    \
   _(JSOP_DEBUGLEAVELEXICALENV)  \
   _(JSOP_PUSHVARENV)            \
   _(JSOP_POPVARENV)             \
   _(JSOP_EXCEPTION)             \
   _(JSOP_DEBUGGER)              \
   _(JSOP_ARGUMENTS)             \
   _(JSOP_REST)                  \
-  _(JSOP_TOASYNC)               \
   _(JSOP_TOASYNCITER)           \
   _(JSOP_TOID)                  \
   _(JSOP_TOSTRING)              \
   _(JSOP_TABLESWITCH)           \
   _(JSOP_ITER)                  \
   _(JSOP_MOREITER)              \
   _(JSOP_ISNOITER)              \
   _(JSOP_ENDITER)               \
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11364,25 +11364,16 @@ void CodeGenerator::visitOutOfLineTypeOf
   masm.passABIArg(output);
   masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::TypeOfObject));
   masm.storeCallPointerResult(output);
   restoreVolatile(output);
 
   masm.jump(ool->rejoin());
 }
 
-typedef JSObject* (*ToAsyncFn)(JSContext*, HandleFunction);
-static const VMFunction ToAsyncInfo =
-    FunctionInfo<ToAsyncFn>(js::WrapAsyncFunction, "ToAsync");
-
-void CodeGenerator::visitToAsync(LToAsync* lir) {
-  pushArg(ToRegister(lir->unwrapped()));
-  callVM(ToAsyncInfo, lir);
-}
-
 typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject, HandleValue);
 static const VMFunction ToAsyncIterInfo =
     FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
 
 void CodeGenerator::visitToAsyncIter(LToAsyncIter* lir) {
   pushArg(ToValue(lir, LToAsyncIter::NextMethodIndex));
   pushArg(ToRegister(lir->iterator()));
   callVM(ToAsyncIterInfo, lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2327,19 +2327,16 @@ AbortReasonOr<Ok> IonBuilder::inspectOpc
 
     case JSOP_CLASSCONSTRUCTOR:
       return jsop_classconstructor();
 
     case JSOP_TYPEOF:
     case JSOP_TYPEOFEXPR:
       return jsop_typeof();
 
-    case JSOP_TOASYNC:
-      return jsop_toasync();
-
     case JSOP_TOASYNCITER:
       return jsop_toasynciter();
 
     case JSOP_TOID:
       return jsop_toid();
 
     case JSOP_ITERNEXT:
       return jsop_iternext();
@@ -2526,16 +2523,17 @@ AbortReasonOr<Ok> IonBuilder::inspectOpc
       // operation in the optimizing compiler?
       break;
 
     case JSOP_FORCEINTERPRETER:
       // Intentionally not implemented.
       break;
 
     case JSOP_UNUSED71:
+    case JSOP_UNUSED149:
     case JSOP_LIMIT:
       break;
   }
 
   // Track a simpler message, since the actionable abort message is a
   // static string, and the internal opcode name isn't an actionable
   // thing anyways.
   trackActionableAbort("Unsupported bytecode");
@@ -13118,28 +13116,16 @@ AbortReasonOr<Ok> IonBuilder::jsop_typeo
   ins->cacheInputMaybeCallableOrEmulatesUndefined(constraints());
 
   current->add(ins);
   current->push(ins);
 
   return Ok();
 }
 
-AbortReasonOr<Ok> IonBuilder::jsop_toasync() {
-  MDefinition* unwrapped = current->pop();
-  MOZ_ASSERT(unwrapped->type() == MIRType::Object);
-
-  MToAsync* ins = MToAsync::New(alloc(), unwrapped);
-
-  current->add(ins);
-  current->push(ins);
-
-  return resumeAfter(ins);
-}
-
 AbortReasonOr<Ok> IonBuilder::jsop_toasynciter() {
   MDefinition* nextMethod = current->pop();
   MDefinition* iterator = current->pop();
   MOZ_ASSERT(iterator->type() == MIRType::Object);
 
   MToAsyncIter* ins = MToAsyncIter::New(alloc(), iterator, nextMethod);
 
   current->add(ins);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1120,22 +1120,16 @@ void LIRGenerator::lowerBitOp(JSOp op, M
 void LIRGenerator::visitTypeOf(MTypeOf* ins) {
   MDefinition* opd = ins->input();
   MOZ_ASSERT(opd->type() == MIRType::Value);
 
   LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox());
   define(lir, ins);
 }
 
-void LIRGenerator::visitToAsync(MToAsync* ins) {
-  LToAsync* lir = new (alloc()) LToAsync(useRegisterAtStart(ins->input()));
-  defineReturn(lir, ins);
-  assignSafepoint(lir, ins);
-}
-
 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) {
   LToAsyncIter* lir =
       new (alloc()) LToAsyncIter(useRegisterAtStart(ins->getIterator()),
                                  useBoxAtStart(ins->getNextMethod()));
   defineReturn(lir, ins);
   assignSafepoint(lir, ins);
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4366,27 +4366,16 @@ class MTypeOf : public MUnaryInstruction
     return congruentIfOperandsEqual(ins);
   }
 
   MOZ_MUST_USE bool writeRecoverData(
       CompactBufferWriter& writer) const override;
   bool canRecoverOnBailout() const override { return true; }
 };
 
-class MToAsync : public MUnaryInstruction, public SingleObjectPolicy::Data {
-  explicit MToAsync(MDefinition* unwrapped)
-      : MUnaryInstruction(classOpcode, unwrapped) {
-    setResultType(MIRType::Object);
-  }
-
- public:
-  INSTRUCTION_HEADER(ToAsync)
-  TRIVIAL_NEW_WRAPPERS
-};
-
 class MToAsyncIter : public MBinaryInstruction,
                      public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>::Data {
   explicit MToAsyncIter(MDefinition* iterator, MDefinition* nextMethod)
       : MBinaryInstruction(classOpcode, iterator, nextMethod) {
     setResultType(MIRType::Object);
   }
 
  public:
@@ -6786,20 +6775,19 @@ struct LambdaFunctionInfo {
         scriptOrLazyScript(fun->hasScript() ? (gc::Cell*)fun->nonLazyScript()
                                             : (gc::Cell*)fun->lazyScript()),
         singletonType(fun->isSingleton()),
         useSingletonForClone(ObjectGroup::useSingletonForClone(fun)) {
     // If this assert fails, make sure CodeGenerator::visitLambda does the
     // right thing. We can't assert this off-thread in CodeGenerator,
     // because fun->isAsync() accesses the script/lazyScript and can race
     // with delazification on the main thread.
-    MOZ_ASSERT_IF(flags & JSFunction::EXTENDED,
-                  fun->isArrow() || fun->allowSuperProperty() ||
-                      fun->isSelfHostedBuiltin() ||
-                      (fun->isAsync() && !fun->isGenerator()));
+    MOZ_ASSERT_IF(flags & JSFunction::EXTENDED, fun->isArrow() ||
+                                                    fun->allowSuperProperty() ||
+                                                    fun->isSelfHostedBuiltin());
   }
 
   // Be careful when calling this off-thread. Don't call any JSFunction*
   // methods that depend on script/lazyScript - this can race with
   // delazification on the main thread.
   JSFunction* funUnsafe() const { return fun_; }
 
   bool appendRoots(MRootList& roots) const {
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -775,28 +775,16 @@ class LTypeOfV : public LInstructionHelp
 
   static const size_t Input = 0;
 
   const LDefinition* tempToUnbox() { return getTemp(0); }
 
   MTypeOf* mir() const { return mir_->toTypeOf(); }
 };
 
-class LToAsync : public LCallInstructionHelper<1, 1, 0> {
- public:
-  LIR_HEADER(ToAsync)
-
-  explicit LToAsync(const LAllocation& input)
-      : LCallInstructionHelper(classOpcode) {
-    setOperand(0, input);
-  }
-
-  const LAllocation* unwrapped() { return getOperand(0); }
-};
-
 class LToAsyncIter : public LCallInstructionHelper<1, 1 + BOX_PIECES, 0> {
  public:
   LIR_HEADER(ToAsyncIter)
 
   explicit LToAsyncIter(const LAllocation& iterator,
                         const LBoxAllocation& nextMethod)
       : LCallInstructionHelper(classOpcode) {
     setOperand(0, iterator);
--- a/js/src/tests/non262/async-functions/clone.js
+++ b/js/src/tests/non262/async-functions/clone.js
@@ -1,14 +1,24 @@
 // |reftest| skip-if(!xulRuntime.shell) -- needs clone, cloneAndExecuteScript, drainJobQueue
 
-// Async function cannot be cloned.
-assertThrowsInstanceOf(() => clone(async function f() {}), TypeError);
+// Async functions can be cloned.
+let f = clone(async function f() {
+  var a = await 1;
+  var b = await 2;
+  var c = await 3;
+  return a + b + c;
+});
 
-// unwrapped async function can be cloned.
+var V;
+f().then(v => V = v);
+drainJobQueue();
+assertEq(V, 6);
+
+// Async function source code scripts can be cloned.
 let g = newGlobal();
 cloneAndExecuteScript(`
 async function f() {
   var a = await 1;
   var b = await 2;
   var c = await 3;
   return a + b + c;
 }
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -469,22 +469,17 @@ static bool MappedArgGetter(JSContext* c
     }
   } else if (JSID_IS_ATOM(id, cx->names().length)) {
     if (!argsobj.hasOverriddenLength()) {
       vp.setInt32(argsobj.initialLength());
     }
   } else {
     MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().callee));
     if (!argsobj.hasOverriddenCallee()) {
-      RootedFunction callee(cx, &argsobj.callee());
-      if (callee->isAsync() && !callee->isGenerator()) {
-        vp.setObject(*GetWrappedAsyncFunction(callee));
-      } else {
-        vp.setObject(*callee);
-      }
+      vp.setObject(argsobj.callee());
     }
   }
   return true;
 }
 
 static bool MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id,
                             HandleValue v, ObjectOpResult& result) {
   if (!obj->is<MappedArgumentsObject>()) {
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -56,111 +56,16 @@ using mozilla::Maybe;
   }
 
   global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
   global->setReservedSlot(ASYNC_FUNCTION_PROTO,
                           ObjectValue(*asyncFunctionProto));
   return true;
 }
 
-#define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
-#define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
-
-// Async Functions proposal 1.1.8 and 1.2.14.
-static bool WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp) {
-  CallArgs args = CallArgsFromVp(argc, vp);
-
-  RootedValue unwrappedVal(cx);
-  unwrappedVal = args.callee().as<JSFunction>().getExtendedSlot(
-      WRAPPED_ASYNC_UNWRAPPED_SLOT);
-
-  // Step 2.
-  // Also does a part of 2.2 steps 1-2.
-  InvokeArgs args2(cx);
-  if (!FillArgumentsFromArraylike(cx, args2, args)) {
-    return false;
-  }
-
-  if (Call(cx, unwrappedVal, args.thisv(), args2, args.rval())) {
-    return true;
-  }
-
-  if (!cx->isExceptionPending()) {
-    return false;
-  }
-
-  // Steps 1, 4.
-  RootedValue exc(cx);
-  if (!GetAndClearException(cx, &exc)) {
-    return false;
-  }
-  JSObject* rejectPromise = PromiseObject::unforgeableReject(cx, exc);
-  if (!rejectPromise) {
-    return false;
-  }
-
-  // Step 5.
-  args.rval().setObject(*rejectPromise);
-  return true;
-}
-
-// Async Functions proposal 2.1 steps 1, 3 (partially).
-// In the spec it creates a function, but we create 2 functions `unwrapped` and
-// `wrapped`.  `unwrapped` is a generator that corresponds to
-//  the async function's body, replacing `await` with `yield`.  `wrapped` is a
-// function that is visible to the outside, and handles yielded values.
-JSObject* js::WrapAsyncFunctionWithProto(JSContext* cx,
-                                         HandleFunction unwrapped,
-                                         HandleObject proto) {
-  MOZ_ASSERT(unwrapped->isAsync());
-  MOZ_ASSERT(proto,
-             "We need an explicit prototype to avoid the default"
-             "%FunctionPrototype% fallback in NewFunctionWithProto().");
-
-  // Create a new function with AsyncFunctionPrototype, reusing the name and
-  // the length of `unwrapped`.
-
-  RootedAtom funName(cx, unwrapped->explicitName());
-  uint16_t length;
-  if (!JSFunction::getLength(cx, unwrapped, &length)) {
-    return nullptr;
-  }
-
-  // Steps 3 (partially).
-  JSFunction* wrapped = NewFunctionWithProto(
-      cx, WrappedAsyncFunction, length, JSFunction::NATIVE_FUN, nullptr,
-      funName, proto, gc::AllocKind::FUNCTION_EXTENDED);
-  if (!wrapped) {
-    return nullptr;
-  }
-
-  if (unwrapped->hasInferredName()) {
-    wrapped->setInferredName(unwrapped->inferredName());
-  }
-
-  // Link them to each other to make GetWrappedAsyncFunction and
-  // GetUnwrappedAsyncFunction work.
-  unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT,
-                             ObjectValue(*wrapped));
-  wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT,
-                           ObjectValue(*unwrapped));
-
-  return wrapped;
-}
-
-JSObject* js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped) {
-  RootedObject proto(
-      cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
-  if (!proto) {
-    return nullptr;
-  }
-
-  return WrapAsyncFunctionWithProto(cx, unwrapped, proto);
-}
-
 enum class ResumeKind { Normal, Throw };
 
 // Async Functions proposal 2.2 steps 3.f, 3.g.
 // Async Functions proposal 2.2 steps 3.d-e, 3.g.
 // Implemented in js/src/builtin/Promise.cpp
 
 // Async Functions proposal 2.2 steps 3-8, 2.4 steps 2-7, 2.5 steps 2-7.
 static bool AsyncFunctionResume(JSContext* cx,
@@ -243,37 +148,16 @@ JSObject* js::AsyncFunctionResolve(
   } else {
     if (!AsyncFunctionThrown(cx, promise, valueOrReason)) {
       return nullptr;
     }
   }
   return promise;
 }
 
-JSFunction* js::GetWrappedAsyncFunction(JSFunction* unwrapped) {
-  MOZ_ASSERT(unwrapped->isAsync());
-  return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT)
-              .toObject()
-              .as<JSFunction>();
-}
-
-JSFunction* js::GetUnwrappedAsyncFunction(JSFunction* wrapped) {
-  MOZ_ASSERT(IsWrappedAsyncFunction(wrapped));
-  JSFunction* unwrapped =
-      &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
-           .toObject()
-           .as<JSFunction>();
-  MOZ_ASSERT(unwrapped->isAsync());
-  return unwrapped;
-}
-
-bool js::IsWrappedAsyncFunction(JSFunction* fun) {
-  return fun->maybeNative() == WrappedAsyncFunction;
-}
-
 const Class AsyncFunctionGeneratorObject::class_ = {
     "AsyncFunctionGenerator",
     JSCLASS_HAS_RESERVED_SLOTS(AsyncFunctionGeneratorObject::RESERVED_SLOTS)};
 
 AsyncFunctionGeneratorObject* AsyncFunctionGeneratorObject::create(
     JSContext* cx, HandleFunction fun) {
   MOZ_ASSERT(fun->isAsync() && !fun->isGenerator());
 
--- a/js/src/vm/AsyncFunction.h
+++ b/js/src/vm/AsyncFunction.h
@@ -10,47 +10,16 @@
 #include "builtin/Promise.h"
 #include "js/Class.h"
 #include "vm/GeneratorObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 
 namespace js {
 
-// An async function is implemented using two function objects, which are
-// referred to as the "unwrapped" and the "wrapped" async function object.
-// The unwrapped function is a generator function compiled from the async
-// function's script. |await| expressions within the async function are
-// compiled like |yield| expression for the generator function with dedicated
-// opcode,. The unwrapped function is never exposed to user script.
-// The wrapped function is a native function which wraps the generator function,
-// hence its name, and is the publicly exposed object of the async function.
-//
-// The unwrapped async function is created while compiling the async function,
-// and the wrapped async function is created while executing the async function
-// declaration or expression.
-
-// Returns a wrapped async function from an unwrapped async function.
-JSFunction* GetWrappedAsyncFunction(JSFunction* unwrapped);
-
-// Returns an unwrapped async function from a wrapped async function.
-JSFunction* GetUnwrappedAsyncFunction(JSFunction* wrapped);
-
-// Returns true if the given function is a wrapped async function.
-bool IsWrappedAsyncFunction(JSFunction* fun);
-
-// Create a wrapped async function from unwrapped async function with given
-// prototype object.
-JSObject* WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped,
-                                     HandleObject proto);
-
-// Create a wrapped async function from unwrapped async function with default
-// prototype object.
-JSObject* WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped);
-
 class AsyncFunctionGeneratorObject;
 
 // Resume the async function when the `await` operand resolves.
 // Split into two functions depending on whether the awaited value was
 // fulfilled or rejected.
 MOZ_MUST_USE bool AsyncFunctionAwaitedFulfilled(
     JSContext* cx, Handle<AsyncFunctionGeneratorObject*> generator,
     HandleValue value);
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -440,19 +440,16 @@ static const JSFunctionSpec async_genera
   }
 
   // Async Iteration proposal 11.3.3 %AsyncGenerator%.
   RootedObject asyncGenerator(
       cx, NewSingletonObjectWithFunctionPrototype(cx, global));
   if (!asyncGenerator) {
     return false;
   }
-  if (!JSObject::setDelegate(cx, asyncGenerator)) {
-    return false;
-  }
   if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto,
                                    JSPROP_READONLY, JSPROP_READONLY) ||
       !DefineToStringTag(cx, asyncGenerator,
                          cx->names().AsyncGeneratorFunction)) {
     return false;
   }
 
   RootedValue function(cx, global->getConstructor(JSProto_Function));
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -2058,17 +2058,16 @@ bool ExpressionDecompiler::decompilePC(j
       case JSOP_IS_CONSTRUCTING:
         return write("JS_IS_CONSTRUCTING");
 
       case JSOP_ITER:
         return write("ITER");
 
       case JSOP_LAMBDA:
       case JSOP_LAMBDA_ARROW:
-      case JSOP_TOASYNC:
         return write("FUN");
 
       case JSOP_TOASYNCITER:
         return write("ASYNCITER");
 
       case JSOP_MOREITER:
         // For stack dump, defIndex == 0 is not used.
         MOZ_ASSERT(defIndex == 1);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -197,41 +197,16 @@ static const ClassOps DebuggerSource_cla
 
 static const Class DebuggerSource_class = {
     "Source",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT),
     &DebuggerSource_classOps};
 
 /*** Utils ******************************************************************/
 
-/*
- * If fun is an interpreted function, remove any async function/generator
- * wrapper and return the underlying scripted function. Otherwise, return fun
- * unchanged.
- *
- * Async functions are implemented as native functions wrapped around a scripted
- * function. JSScripts hold ordinary inner JSFunctions in their object arrays,
- * and when we need to actually create a JS-visible function object, we build an
- * ordinary JS closure and apply the async wrapper to it. Async generators are
- * similar.
- *
- * This means that JSFunction::isInterpreted returns false for such functions,
- * even though their actual code is indeed JavaScript. Debugger should treat
- * async functions and generators like any other scripted function, so we must
- * carefully check for them whenever we want inspect a function.
- */
-
-static JSFunction* RemoveAsyncWrapper(JSFunction* fun) {
-  if (js::IsWrappedAsyncFunction(fun)) {
-    fun = js::GetUnwrappedAsyncFunction(fun);
-  }
-
-  return fun;
-}
-
 static inline bool EnsureFunctionHasScript(JSContext* cx, HandleFunction fun) {
   if (fun->isInterpretedLazy()) {
     AutoRealm ar(cx, fun);
     return !!JSFunction::getOrCreateScript(cx, fun);
   }
   return true;
 }
 
@@ -10224,17 +10199,17 @@ static DebuggerObject* DebuggerObject_ch
                                                Value* vp) {
   THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get script", args, dbg, obj);
 
   if (!obj->is<JSFunction>()) {
     args.rval().setUndefined();
     return true;
   }
 
-  RootedFunction fun(cx, RemoveAsyncWrapper(&obj->as<JSFunction>()));
+  RootedFunction fun(cx, &obj->as<JSFunction>());
   if (!fun->isInterpreted()) {
     args.rval().setUndefined();
     return true;
   }
 
   RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
   if (!script) {
     return false;
@@ -10262,17 +10237,17 @@ static DebuggerObject* DebuggerObject_ch
 
   // Don't bother switching compartments just to check obj's type and get its
   // env.
   if (!obj->is<JSFunction>()) {
     args.rval().setUndefined();
     return true;
   }
 
-  RootedFunction fun(cx, RemoveAsyncWrapper(&obj->as<JSFunction>()));
+  RootedFunction fun(cx, &obj->as<JSFunction>());
   if (!fun->isInterpreted()) {
     args.rval().setUndefined();
     return true;
   }
 
   // Only hand out environments of debuggee functions.
   if (!dbg->observesGlobal(&fun->global())) {
     args.rval().setNull();
@@ -11262,29 +11237,29 @@ bool DebuggerObject::isBoundFunction() c
   MOZ_ASSERT(isDebuggeeFunction());
 
   return referent()->isBoundFunction();
 }
 
 bool DebuggerObject::isArrowFunction() const {
   MOZ_ASSERT(isDebuggeeFunction());
 
-  return RemoveAsyncWrapper(&referent()->as<JSFunction>())->isArrow();
+  return referent()->as<JSFunction>().isArrow();
 }
 
 bool DebuggerObject::isAsyncFunction() const {
   MOZ_ASSERT(isDebuggeeFunction());
 
-  return RemoveAsyncWrapper(&referent()->as<JSFunction>())->isAsync();
+  return referent()->as<JSFunction>().isAsync();
 }
 
 bool DebuggerObject::isGeneratorFunction() const {
   MOZ_ASSERT(isDebuggeeFunction());
 
-  return RemoveAsyncWrapper(&referent()->as<JSFunction>())->isGenerator();
+  return referent()->as<JSFunction>().isGenerator();
 }
 
 bool DebuggerObject::isGlobal() const { return referent()->is<GlobalObject>(); }
 
 bool DebuggerObject::isScriptedProxy() const {
   return js::IsScriptedProxy(referent());
 }
 
@@ -11355,18 +11330,17 @@ double DebuggerObject::promiseTimeToReso
   return promise()->timeToResolution();
 }
 
 /* static */ bool DebuggerObject::getParameterNames(
     JSContext* cx, HandleDebuggerObject object,
     MutableHandle<StringVector> result) {
   MOZ_ASSERT(object->isDebuggeeFunction());
 
-  RootedFunction referent(
-      cx, RemoveAsyncWrapper(&object->referent()->as<JSFunction>()));
+  RootedFunction referent(cx, &object->referent()->as<JSFunction>());
 
   if (!result.growBy(referent->nargs())) {
     return false;
   }
   if (referent->isInterpreted()) {
     RootedScript script(cx, GetOrCreateFunctionScript(cx, referent));
     if (!script) {
       return false;
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -1101,23 +1101,16 @@ const Class LexicalEnvironmentObject::cl
 
 /* static */ NamedLambdaObject* NamedLambdaObject::create(
     JSContext* cx, AbstractFramePtr frame) {
   RootedFunction fun(cx, frame.callee());
   RootedObject enclosing(cx, frame.environmentChain());
   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_);
 }
 
 /* static */ RuntimeLexicalErrorObject* RuntimeLexicalErrorObject::create(
     JSContext* cx, HandleObject enclosing, unsigned errorNumber) {
   RuntimeLexicalErrorObject* obj =
@@ -3637,25 +3630,17 @@ bool js::CheckGlobalOrEvalDeclarationCon
 bool js::InitFunctionEnvironmentObjects(JSContext* cx, AbstractFramePtr frame) {
   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;
-    if (callee->isAsync() && !callee->isGenerator()) {
-      // 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);
-    }
+    NamedLambdaObject* 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.
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -589,18 +589,16 @@ class NamedLambdaObject : public Lexical
                                    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
@@ -223,17 +223,25 @@ static const JSFunctionSpec generator_me
 
 JSObject* js::NewSingletonObjectWithFunctionPrototype(
     JSContext* cx, Handle<GlobalObject*> global) {
   RootedObject proto(cx,
                      GlobalObject::getOrCreateFunctionPrototype(cx, global));
   if (!proto) {
     return nullptr;
   }
-  return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
+  RootedObject obj(
+      cx, NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject));
+  if (!obj) {
+    return nullptr;
+  }
+  if (!JSObject::setDelegate(cx, obj)) {
+    return nullptr;
+  }
+  return obj;
 }
 
 /* static */ bool GlobalObject::initGenerators(JSContext* cx,
                                                Handle<GlobalObject*> global) {
   if (global->getReservedSlot(GENERATOR_OBJECT_PROTO).isObject()) {
     return true;
   }
 
@@ -251,17 +259,17 @@ JSObject* js::NewSingletonObjectWithFunc
   if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr,
                                     generator_methods) ||
       !DefineToStringTag(cx, genObjectProto, cx->names().Generator)) {
     return false;
   }
 
   RootedObject genFunctionProto(
       cx, NewSingletonObjectWithFunctionPrototype(cx, global));
-  if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto)) {
+  if (!genFunctionProto) {
     return false;
   }
   if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto,
                                    JSPROP_READONLY, JSPROP_READONLY) ||
       !DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction)) {
     return false;
   }
 
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -407,19 +407,20 @@ inline int32_t GlobalObject::OffThreadPl
 /* static */ JSObject* GlobalObject::createOffThreadObject(
     JSContext* cx, Handle<GlobalObject*> global, unsigned slot) {
   // Don't create prototype objects for off-thread parse globals. Instead
   // create a placeholder object which we can use to find the real prototype
   // when the off-thread compartment is merged back into the target
   // compartment.
 
   MOZ_ASSERT(global->zone()->createdForHelperThread());
-  MOZ_ASSERT(slot == GENERATOR_FUNCTION_PROTO || slot == ASYNC_GENERATOR ||
-             slot == MODULE_PROTO || slot == IMPORT_ENTRY_PROTO ||
-             slot == EXPORT_ENTRY_PROTO || slot == REQUESTED_MODULE_PROTO);
+  MOZ_ASSERT(slot == GENERATOR_FUNCTION_PROTO || slot == ASYNC_FUNCTION_PROTO ||
+             slot == ASYNC_GENERATOR || slot == MODULE_PROTO ||
+             slot == IMPORT_ENTRY_PROTO || slot == EXPORT_ENTRY_PROTO ||
+             slot == REQUESTED_MODULE_PROTO);
 
   auto placeholder = OffThreadPlaceholderObject::New(cx, slot);
   if (!placeholder) {
     return nullptr;
   }
 
   global->setSlot(slot, ObjectValue(*placeholder));
   return placeholder;
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -741,16 +741,20 @@ static bool EnsureParserCreatedClasses(J
   if (!EnsureConstructor(cx, global, JSProto_RegExp)) {
     return false;  // needed by regular expression literals
   }
 
   if (!GlobalObject::initGenerators(cx, global)) {
     return false;  // needed by function*() {}
   }
 
+  if (!GlobalObject::initAsyncFunction(cx, global)) {
+    return false;  // needed by async function() {}
+  }
+
   if (!GlobalObject::initAsyncGenerators(cx, global)) {
     return false;  // needed by async function*() {}
   }
 
   if (kind == ParseTaskKind::Module &&
       !GlobalObject::ensureModulePrototypesCreated(cx, global)) {
     return false;
   }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1941,16 +1941,17 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_
       DISPATCH_TO(op);
     }
 
     /* Various 1-byte no-ops. */
     CASE(JSOP_NOP)
     CASE(JSOP_NOP_DESTRUCTURING)
     CASE(JSOP_TRY_DESTRUCTURING)
     CASE(JSOP_UNUSED71)
+    CASE(JSOP_UNUSED149)
     CASE(JSOP_TRY)
     CASE(JSOP_CONDSWITCH) {
       MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
       ADVANCE_AND_DISPATCH(1);
     }
 
     CASE(JSOP_JUMPTARGET)
     CASE(JSOP_LOOPHEAD) {
@@ -3579,28 +3580,16 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_
         goto error;
       }
 
       MOZ_ASSERT(obj->staticPrototype());
       REGS.sp[-1].setObject(*obj);
     }
     END_CASE(JSOP_LAMBDA_ARROW)
 
-    CASE(JSOP_TOASYNC) {
-      ReservedRooted<JSFunction*> unwrapped(
-          &rootFunction0, &REGS.sp[-1].toObject().as<JSFunction>());
-      JSObject* wrapped = WrapAsyncFunction(cx, unwrapped);
-      if (!wrapped) {
-        goto error;
-      }
-
-      REGS.sp[-1].setObject(*wrapped);
-    }
-    END_CASE(JSOP_TOASYNC)
-
     CASE(JSOP_TOASYNCITER) {
       ReservedRooted<Value> nextMethod(&rootValue0, REGS.sp[-1]);
       ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-2].toObject());
       JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter, nextMethod);
       if (!asyncIter) {
         goto error;
       }
 
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -285,21 +285,17 @@ bool CallerGetterImpl(JSContext* cx, con
     ++iter;
   }
 
   if (iter.done() || !iter.isFunctionFrame()) {
     args.rval().setNull();
     return true;
   }
 
-  JSFunction* callerFun = iter.callee(cx);
-  if (callerFun->isAsync() && !callerFun->isGenerator()) {
-    callerFun = GetWrappedAsyncFunction(callerFun);
-  }
-  RootedObject caller(cx, callerFun);
+  RootedObject caller(cx, iter.callee(cx));
   if (!cx->compartment()->wrap(cx, &caller)) {
     return false;
   }
 
   // Censor the caller if we don't have full access to it.  If we do, but the
   // caller is a function with strict mode code, throw a TypeError per ES5.
   // If we pass these checks, we can return the computed caller.
   {
@@ -311,19 +307,16 @@ bool CallerGetterImpl(JSContext* cx, con
 
     if (JS_IsDeadWrapper(callerObj)) {
       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                 JSMSG_DEAD_OBJECT);
       return false;
     }
 
     JSFunction* callerFun = &callerObj->as<JSFunction>();
-    if (IsWrappedAsyncFunction(callerFun)) {
-      callerFun = GetUnwrappedAsyncFunction(callerFun);
-    }
     MOZ_ASSERT(!callerFun->isBuiltin(),
                "non-builtin iterator returned a builtin?");
 
     if (callerFun->strict()) {
       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                 JSMSG_CALLER_IS_STRICT);
       return false;
     }
@@ -608,23 +601,29 @@ XDRResult js::XDRInterpretedFunction(XDR
 
   if (firstword & HasAtom) {
     MOZ_TRY(XDRAtom(xdr, &atom));
   }
   MOZ_TRY(xdr->codeUint32(&flagsword));
 
   if (mode == XDR_DECODE) {
     RootedObject proto(cx);
-    if ((firstword & IsGenerator) || (firstword & IsAsync)) {
-      if ((firstword & IsGenerator) && (firstword & IsAsync)) {
-        proto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-      } else {
-        proto = GlobalObject::getOrCreateGeneratorFunctionPrototype(
-            cx, cx->global());
+    if ((firstword & IsAsync) && (firstword & IsGenerator)) {
+      proto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
+      if (!proto) {
+        return xdr->fail(JS::TranscodeResult_Throw);
       }
+    } else if (firstword & IsAsync) {
+      proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
+      if (!proto) {
+        return xdr->fail(JS::TranscodeResult_Throw);
+      }
+    } else if (firstword & IsGenerator) {
+      proto =
+          GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
       if (!proto) {
         return xdr->fail(JS::TranscodeResult_Throw);
       }
     }
 
     gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
     if (uint16_t(flagsword) & JSFunction::EXTENDED) {
       allocKind = gc::AllocKind::FUNCTION_EXTENDED;
@@ -876,21 +875,16 @@ JSString* js::FunctionToString(JSContext
 
   if (IsAsmJSModule(fun)) {
     return AsmJSModuleToString(cx, fun, isToSource);
   }
   if (IsAsmJSFunction(fun)) {
     return AsmJSFunctionToString(cx, fun);
   }
 
-  if (IsWrappedAsyncFunction(fun)) {
-    RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
-    return FunctionToString(cx, unwrapped, isToSource);
-  }
-
   RootedScript script(cx);
   if (fun->hasScript()) {
     script = fun->nonLazyScript();
   }
 
   // Default class constructors are self-hosted, but have their source
   // objects overridden to refer to the span of the class statement or
   // expression. Non-default class constructors are never self-hosted. So,
@@ -1907,40 +1901,42 @@ static bool CreateDynamicFunction(JSCont
    * 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);
 
   // Initialize the function with the default prototype:
   // Leave as nullptr to get the default from clasp for normal functions.
-  // Use %Generator% for generators and the unwrapped function of async
-  // functions. Use %AsyncGenerator% for async generator functions.
   RootedObject defaultProto(cx);
-  if (isGenerator || isAsync) {
-    if (isGenerator && isAsync) {
-      defaultProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-    } else {
-      defaultProto =
-          GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, global);
+  if (isAsync && isGenerator) {
+    defaultProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
+    if (!defaultProto) {
+      return false;
     }
+  } else if (isAsync) {
+    defaultProto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, global);
+    if (!defaultProto) {
+      return false;
+    }
+  } else if (isGenerator) {
+    defaultProto =
+        GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, global);
     if (!defaultProto) {
       return false;
     }
   }
 
   // Step 30-37 (reordered).
   RootedObject globalLexical(cx, &global->lexicalEnvironment());
   JSFunction::Flags flags =
       (isGenerator || isAsync)
           ? JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC
           : JSFunction::INTERPRETED_LAMBDA;
-  gc::AllocKind allocKind = (isAsync && !isGenerator)
-                                ? gc::AllocKind::FUNCTION_EXTENDED
-                                : gc::AllocKind::FUNCTION;
+  gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
   RootedFunction fun(
       cx,
       NewFunctionWithProto(cx, nullptr, 0, flags, globalLexical, anonymousAtom,
                            defaultProto, allocKind, TenuredObject));
   if (!fun) {
     return false;
   }
 
@@ -1992,33 +1988,20 @@ static bool CreateDynamicFunction(JSCont
   }
 
   // Steps 6, 29.
   RootedObject proto(cx);
   if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
     return false;
   }
 
-  if (isAsync && !isGenerator) {
-    // Create the async function wrapper.
-
-    // Step 9.d, use %AsyncFunctionPrototype% as the fallback prototype.
-    JSObject* wrapped = proto ? WrapAsyncFunctionWithProto(cx, fun, proto)
-                              : WrapAsyncFunction(cx, fun);
-    if (!wrapped) {
-      return false;
-    }
-
-    fun = &wrapped->as<JSFunction>();
-  } else {
-    // Steps 7.d, 8.d (implicit).
-    // Call SetPrototype if an explicit prototype was given.
-    if (proto && !SetPrototype(cx, fun, proto)) {
-      return false;
-    }
+  // Steps 7.d, 8.d (implicit).
+  // Call SetPrototype if an explicit prototype was given.
+  if (proto && !SetPrototype(cx, fun, proto)) {
+    return false;
   }
 
   // Step 38.
   args.rval().setObject(*fun);
   return true;
 }
 
 bool js::Function(JSContext* cx, unsigned argc, Value* vp) {
@@ -2191,25 +2174,34 @@ bool js::CanReuseScriptForClone(JS::Real
                           : fun->lazyScript()->hasNonSyntacticScope();
 }
 
 static inline JSFunction* NewFunctionClone(JSContext* cx, HandleFunction fun,
                                            NewObjectKind newKind,
                                            gc::AllocKind allocKind,
                                            HandleObject proto) {
   RootedObject cloneProto(cx, proto);
-  if (!proto && (fun->isGenerator() || fun->isAsync())) {
-    if (fun->isGenerator() && fun->isAsync()) {
+  if (!proto) {
+    if (fun->isAsync() && fun->isGenerator()) {
       cloneProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-    } else {
+      if (!cloneProto) {
+        return nullptr;
+      }
+    } else if (fun->isAsync()) {
+      cloneProto =
+          GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
+      if (!cloneProto) {
+        return nullptr;
+      }
+    } else if (fun->isGenerator()) {
       cloneProto =
           GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
-    }
-    if (!cloneProto) {
-      return nullptr;
+      if (!cloneProto) {
+        return nullptr;
+      }
     }
   }
 
   RootedFunction clone(cx);
   clone =
       NewObjectWithClassProto<JSFunction>(cx, cloneProto, allocKind, newKind);
   if (!clone) {
     return nullptr;
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -3950,23 +3950,30 @@ void js::DescribeScriptedCallerForCompil
   }
 }
 
 static JSObject* CloneInnerInterpretedFunction(
     JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun,
     Handle<ScriptSourceObject*> sourceObject) {
   /* NB: Keep this in sync with XDRInterpretedFunction. */
   RootedObject cloneProto(cx);
-  if (srcFun->isGenerator() || srcFun->isAsync()) {
-    if (srcFun->isGenerator() && srcFun->isAsync()) {
-      cloneProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
-    } else {
-      cloneProto =
-          GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
+  if (srcFun->isAsync() && srcFun->isGenerator()) {
+    cloneProto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
+    if (!cloneProto) {
+      return nullptr;
     }
+  } else if (srcFun->isAsync()) {
+    cloneProto =
+        GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
+    if (!cloneProto) {
+      return nullptr;
+    }
+  } else if (srcFun->isGenerator()) {
+    cloneProto =
+        GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
     if (!cloneProto) {
       return nullptr;
     }
   }
 
   gc::AllocKind allocKind = srcFun->getAllocKind();
   uint16_t flags = srcFun->flags();
   if (srcFun->isSelfHostedBuiltin()) {
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1599,25 +1599,18 @@
      *
      *   Category: Variables and Scopes
      *   Type: Arguments
      *   Operands:
      *   Stack: => new.target
      */ \
     MACRO(JSOP_NEWTARGET, 148, "newtarget", NULL, 1, 0, 1, JOF_BYTE) \
     /*
-     * Pops the top of stack value as 'unwrapped', converts it to async
-     * function 'wrapped', and pushes 'wrapped' back on the stack.
-     *
-     *   Category: Statements
-     *   Type: Function
-     *   Operands:
-     *   Stack: unwrapped => wrapped
      */ \
-    MACRO(JSOP_TOASYNC, 149, "toasync", NULL, 1, 1, 1, JOF_BYTE) \
+    MACRO(JSOP_UNUSED149, 149, "unused149", NULL, 1, 0, 0, JOF_BYTE) \
     /*
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * the result of 'Math.pow(lval, rval)'.
      *
      *   Category: Operators
      *   Type: Arithmetic Operators
      *   Operands:
      *   Stack: lval, rval => (lval ** rval)