Bug 1343481 - Part 3: Add JSOP_AWAIT and rename {yieldIndex,yieldOffset} to {yieldAndAwaitIndex,yieldAndAwaitOffset}. r=shu
authorTooru Fujisawa <arai_a@mac.com>
Wed, 01 Mar 2017 20:40:04 +0900
changeset 374319 53a92e2f749e1263e72e0d38089758948d5d720a
parent 374318 5ce3e1a949a61ab7a5caf942e8ca318621babc68
child 374320 616903dd928563c67134208132320f43e38249e0
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1343481
milestone54.0a1
Bug 1343481 - Part 3: Add JSOP_AWAIT and rename {yieldIndex,yieldOffset} to {yieldAndAwaitIndex,yieldAndAwaitOffset}. r=shu
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FullParseHandler.h
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineJIT.cpp
js/src/jit/BaselineJIT.h
js/src/jit/VMFunctions.cpp
js/src/jsopcode.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/vm/GeneratorObject.cpp
js/src/vm/GeneratorObject.h
js/src/vm/Interpreter.cpp
js/src/vm/Opcodes.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2164,17 +2164,17 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
     varEmitterScope(nullptr),
     innermostNestableControl(nullptr),
     innermostEmitterScope(nullptr),
     innermostTDZCheckCache(nullptr),
     constList(cx),
     scopeList(cx),
     tryNoteList(cx),
     scopeNoteList(cx),
-    yieldOffsetList(cx),
+    yieldAndAwaitOffsetList(cx),
     typesetCount(0),
     hasSingletons(false),
     hasTryFinally(false),
     emittingRunOnceLambda(false),
     emitterMode(emitterMode),
     functionBodyEndPosSet(false)
 {
     MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
@@ -4801,31 +4801,31 @@ BytecodeEmitter::isRunOnceLambda()
 }
 
 bool
 BytecodeEmitter::emitYieldOp(JSOp op)
 {
     if (op == JSOP_FINALYIELDRVAL)
         return emit1(JSOP_FINALYIELDRVAL);
 
-    MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD);
+    MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
 
     ptrdiff_t off;
     if (!emitN(op, 3, &off))
         return false;
 
-    uint32_t yieldIndex = yieldOffsetList.length();
-    if (yieldIndex >= JS_BIT(24)) {
+    uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
+    if (yieldAndAwaitIndex >= JS_BIT(24)) {
         reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
         return false;
     }
 
-    SET_UINT24(code(off), yieldIndex);
-
-    if (!yieldOffsetList.append(offset()))
+    SET_UINT24(code(off), yieldAndAwaitIndex);
+
+    if (!yieldAndAwaitOffsetList.append(offset()))
         return false;
 
     return emit1(JSOP_DEBUGAFTERYIELD);
 }
 
 bool
 BytecodeEmitter::emitSetThis(ParseNode* pn)
 {
@@ -8328,17 +8328,17 @@ BytecodeEmitter::emitReturn(ParseNode* p
     return true;
 }
 
 bool
 BytecodeEmitter::emitYield(ParseNode* pn)
 {
     MOZ_ASSERT(sc->isFunctionBox());
 
-    if (pn->getOp() == JSOP_YIELD) {
+    if (pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT) {
         bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
         if (needsIteratorResult) {
             if (!emitPrepareIteratorResult())
                 return false;
         }
         if (pn->pn_left) {
             if (!emitTree(pn->pn_left))
                 return false;
@@ -11052,17 +11052,17 @@ CGScopeNoteList::finish(ScopeNoteArray* 
             list[i].end += prologueLength;
         MOZ_ASSERT(list[i].end >= list[i].start);
         list[i].length = list[i].end - list[i].start;
         array->vector[i] = list[i];
     }
 }
 
 void
-CGYieldOffsetList::finish(YieldOffsetArray& array, uint32_t prologueLength)
+CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
 {
     MOZ_ASSERT(length() == array.length());
 
     for (unsigned i = 0; i < length(); i++)
         array[i] = prologueLength + list[i];
 }
 
 /*
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -93,23 +93,23 @@ struct CGScopeNoteList {
 
     MOZ_MUST_USE bool append(uint32_t scopeIndex, uint32_t offset, bool inPrologue,
                              uint32_t parent);
     void recordEnd(uint32_t index, uint32_t offset, bool inPrologue);
     size_t length() const { return list.length(); }
     void finish(ScopeNoteArray* array, uint32_t prologueLength);
 };
 
-struct CGYieldOffsetList {
+struct CGYieldAndAwaitOffsetList {
     Vector<uint32_t> list;
-    explicit CGYieldOffsetList(JSContext* cx) : list(cx) {}
+    explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx) {}
 
     MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
     size_t length() const { return list.length(); }
-    void finish(YieldOffsetArray& array, uint32_t prologueLength);
+    void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
 };
 
 // Use zero inline elements because these go on the stack and affect how many
 // nested functions are possible.
 typedef Vector<jsbytecode, 0> BytecodeVector;
 typedef Vector<jssrcnote, 0> SrcNotesVector;
 
 // Linked list of jump instructions that need to be patched. The linked list is
@@ -223,20 +223,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
     CGConstList      constList;      /* constants to be included with the script */
     CGObjectList     objectList;     /* list of emitted objects */
     CGScopeList      scopeList;      /* list of emitted scopes */
     CGTryNoteList    tryNoteList;    /* list of emitted try notes */
     CGScopeNoteList  scopeNoteList;  /* list of emitted block scope notes */
 
     /*
-     * For each yield op, map the yield index (stored as bytecode operand) to
-     * the offset of the next op.
+     * For each yield or await op, map the yield and await index (stored as
+     * bytecode operand) to the offset of the next op.
      */
-    CGYieldOffsetList yieldOffsetList;
+    CGYieldAndAwaitOffsetList yieldAndAwaitOffsetList;
 
     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
     bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
 
     bool            hasTryFinally:1;    /* script contains finally block */
 
     bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -435,17 +435,17 @@ class FullParseHandler
 
     ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
         TokenPos pos(begin, value->pn_pos.end);
         return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
     }
 
     ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
         TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
-        return new_<BinaryNode>(PNK_AWAIT, JSOP_YIELD, pos, value, gen);
+        return new_<BinaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value, gen);
     }
 
     // Statements
 
     ParseNode* newStatementList(const TokenPos& pos) {
         return new_<ListNode>(PNK_STATEMENTLIST, pos);
     }
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -39,17 +39,17 @@
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::AssertedCast;
 
 BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script)
   : BaselineCompilerSpecific(cx, alloc, script),
-    yieldOffsets_(cx),
+    yieldAndAwaitOffsets_(cx),
     modifiesArguments_(false)
 {
 }
 
 bool
 BaselineCompiler::init()
 {
     if (!analysis_.init(alloc_, cx->caches().gsnCache))
@@ -206,17 +206,17 @@ BaselineCompiler::compile()
                             epilogueOffset_.offset(),
                             profilerEnterFrameToggleOffset_.offset(),
                             profilerExitFrameToggleOffset_.offset(),
                             postDebugPrologueOffset_.offset(),
                             icEntries_.length(),
                             pcMappingIndexEntries.length(),
                             pcEntries.length(),
                             bytecodeTypeMapEntries,
-                            yieldOffsets_.length(),
+                            yieldAndAwaitOffsets_.length(),
                             traceLoggerToggleOffsets_.length()),
         JS::DeletePolicy<BaselineScript>(cx->runtime()));
     if (!baselineScript) {
         ReportOutOfMemory(cx);
         return Method_Error;
     }
 
     baselineScript->setMethod(code);
@@ -267,17 +267,17 @@ BaselineCompiler::compile()
 
     uint32_t* bytecodeMap = baselineScript->bytecodeTypeMap();
     FillBytecodeTypeMap(script, bytecodeMap);
 
     // The last entry in the last index found, and is used to avoid binary
     // searches for the sought entry when queries are in linear order.
     bytecodeMap[script->nTypeSets()] = 0;
 
-    baselineScript->copyYieldEntries(script, yieldOffsets_);
+    baselineScript->copyYieldAndAwaitEntries(script, yieldAndAwaitOffsets_);
 
     if (compileDebugInstrumentation_)
         baselineScript->setHasDebugInstrumentation();
 
     // Always register a native => bytecode mapping entry, since profiler can be
     // turned on with baseline jitcode on stack, and baseline jitcode cannot be invalidated.
     {
         JitSpew(JitSpew_Profiling, "Added JitcodeGlobalEntry for baseline script %s:%" PRIuSIZE " (%p)",
@@ -4173,47 +4173,49 @@ BaselineCompiler::emit_JSOP_GENERATOR()
         return false;
 
     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
     frame.push(R0);
     return true;
 }
 
 bool
-BaselineCompiler::addYieldOffset()
-{
-    MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
-
-    uint32_t yieldIndex = GET_UINT24(pc);
-
-    while (yieldIndex >= yieldOffsets_.length()) {
-        if (!yieldOffsets_.append(0))
+BaselineCompiler::addYieldAndAwaitOffset()
+{
+    MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
+
+    uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
+
+    while (yieldAndAwaitIndex >= yieldAndAwaitOffsets_.length()) {
+        if (!yieldAndAwaitOffsets_.append(0))
             return false;
     }
 
-    static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH,
-                  "code below assumes INITIALYIELD and YIELD have same length");
-    yieldOffsets_[yieldIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
+    static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH &&
+                  JSOP_INITIALYIELD_LENGTH == JSOP_AWAIT_LENGTH,
+                  "code below assumes INITIALYIELD and YIELD and AWAIT have same length");
+    yieldAndAwaitOffsets_[yieldAndAwaitIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_INITIALYIELD()
 {
-    if (!addYieldOffset())
+    if (!addYieldAndAwaitOffset())
         return false;
 
     frame.syncStack(0);
     MOZ_ASSERT(frame.stackDepth() == 1);
 
     Register genObj = R2.scratchReg();
     masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj);
 
     MOZ_ASSERT(GET_UINT24(pc) == 0);
-    masm.storeValue(Int32Value(0), Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
+    masm.storeValue(Int32Value(0),
+                    Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
 
     Register envObj = R0.scratchReg();
     Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
     masm.loadPtr(frame.addressOfEnvironmentChain(), envObj);
     masm.patchableCallPreBarrier(envChainSlot, MIRType::Value);
     masm.storeValue(JSVAL_TYPE_OBJECT, envObj, envChainSlot);
 
     Register temp = R1.scratchReg();
@@ -4232,34 +4234,34 @@ BaselineCompiler::emit_JSOP_INITIALYIELD
 
 typedef bool (*NormalSuspendFn)(JSContext*, HandleObject, BaselineFrame*, jsbytecode*, uint32_t);
 static const VMFunction NormalSuspendInfo =
     FunctionInfo<NormalSuspendFn>(jit::NormalSuspend, "NormalSuspend");
 
 bool
 BaselineCompiler::emit_JSOP_YIELD()
 {
-    if (!addYieldOffset())
+    if (!addYieldAndAwaitOffset())
         return false;
 
     // Store generator in R0.
     frame.popRegsAndSync(1);
 
     Register genObj = R2.scratchReg();
     masm.unboxObject(R0, genObj);
 
     MOZ_ASSERT(frame.stackDepth() >= 1);
 
     if (frame.stackDepth() == 1 && !script->isLegacyGenerator()) {
         // If the expression stack is empty, we can inline the YIELD. Don't do
         // this for legacy generators: we have to throw an exception if the
         // generator is in the closing state, see GeneratorObject::suspend.
 
         masm.storeValue(Int32Value(GET_UINT24(pc)),
-                        Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
+                        Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
 
         Register envObj = R0.scratchReg();
         Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
         masm.loadPtr(frame.addressOfEnvironmentChain(), envObj);
         masm.patchableCallPreBarrier(envChainSlot, MIRType::Value);
         masm.storeValue(JSVAL_TYPE_OBJECT, envObj, envChainSlot);
 
         Register temp = R1.scratchReg();
@@ -4281,16 +4283,22 @@ BaselineCompiler::emit_JSOP_YIELD()
         if (!callVM(NormalSuspendInfo))
             return false;
     }
 
     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand);
     return emitReturn();
 }
 
+bool
+BaselineCompiler::emit_JSOP_AWAIT()
+{
+    return emit_JSOP_YIELD();
+}
+
 typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
 static const VMFunction DebugAfterYieldInfo =
     FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
 
 bool
 BaselineCompiler::emit_JSOP_DEBUGAFTERYIELD()
 {
     if (!compileDebugInstrumentation_)
@@ -4500,26 +4508,27 @@ BaselineCompiler::emit_JSOP_RESUME()
         masm.storeValue(NullValue(), exprStackSlot);
         regs.add(initLength);
     }
 
     masm.bind(&noExprStack);
     masm.pushValue(retVal);
 
     if (resumeKind == GeneratorObject::NEXT) {
-        // Determine the resume address based on the yieldIndex and the
-        // yieldIndex -> native table in the BaselineScript.
+        // Determine the resume address based on the yieldAndAwaitIndex and the
+        // yieldAndAwaitIndex -> native table in the BaselineScript.
         masm.load32(Address(scratch1, BaselineScript::offsetOfYieldEntriesOffset()), scratch2);
         masm.addPtr(scratch2, scratch1);
-        masm.unboxInt32(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), scratch2);
+        masm.unboxInt32(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()),
+                        scratch2);
         masm.loadPtr(BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))), scratch1);
 
         // Mark as running and jump to the generator's JIT code.
-        masm.storeValue(Int32Value(GeneratorObject::YIELD_INDEX_RUNNING),
-                        Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
+        masm.storeValue(Int32Value(GeneratorObject::YIELD_AND_AWAIT_INDEX_RUNNING),
+                        Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
         masm.jump(scratch1);
     } else {
         MOZ_ASSERT(resumeKind == GeneratorObject::THROW || resumeKind == GeneratorObject::CLOSE);
 
         // Update the frame's frameSize field.
         masm.computeEffectiveAddress(Address(BaselineFrameReg, BaselineFrame::FramePointerOffset),
                                      scratch2);
         masm.movePtr(scratch2, scratch1);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -202,16 +202,17 @@ namespace jit {
     _(JSOP_ITER)               \
     _(JSOP_MOREITER)           \
     _(JSOP_ISNOITER)           \
     _(JSOP_ENDITER)            \
     _(JSOP_ISGENCLOSING)       \
     _(JSOP_GENERATOR)          \
     _(JSOP_INITIALYIELD)       \
     _(JSOP_YIELD)              \
+    _(JSOP_AWAIT)              \
     _(JSOP_DEBUGAFTERYIELD)    \
     _(JSOP_FINALYIELDRVAL)     \
     _(JSOP_RESUME)             \
     _(JSOP_CALLEE)             \
     _(JSOP_GETRVAL)            \
     _(JSOP_SETRVAL)            \
     _(JSOP_RETRVAL)            \
     _(JSOP_RETURN)             \
@@ -249,19 +250,19 @@ class BaselineCompiler : public Baseline
     // Native code offset right before the frame is popped and the method
     // returned from.
     CodeOffset epilogueOffset_;
 
     // Native code offset right after debug prologue and epilogue, or
     // equivalent positions when debug mode is off.
     CodeOffset postDebugPrologueOffset_;
 
-    // For each INITIALYIELD or YIELD op, this Vector maps the yield index
-    // to the bytecode offset of the next op.
-    Vector<uint32_t>            yieldOffsets_;
+    // For each INITIALYIELD or YIELD or AWAIT op, this Vector maps the yield
+    // index to the bytecode offset of the next op.
+    Vector<uint32_t>            yieldAndAwaitOffsets_;
 
     // Whether any on stack arguments are modified.
     bool modifiesArguments_;
 
     Label* labelOf(jsbytecode* pc) {
         return &labels_[script->pcToOffset(pc)];
     }
 
@@ -343,17 +344,17 @@ class BaselineCompiler : public Baseline
 
     MOZ_MUST_USE bool emitThrowConstAssignment();
     MOZ_MUST_USE bool emitUninitializedLexicalCheck(const ValueOperand& val);
 
     MOZ_MUST_USE bool emitIsMagicValue();
 
     MOZ_MUST_USE bool addPCMappingEntry(bool addIndexEntry);
 
-    MOZ_MUST_USE bool addYieldOffset();
+    MOZ_MUST_USE bool addYieldAndAwaitOffset();
 
     void getEnvironmentCoordinateObject(Register reg);
     Address getEnvironmentCoordinateAddressFromObject(Register objReg, Register reg);
     Address getEnvironmentCoordinateAddress(Register reg);
 };
 
 extern const VMFunction NewArrayCopyOnWriteInfo;
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3273,22 +3273,23 @@ ICCall_IsSuspendedStarGenerator::Compile
     masm.branchTestObject(Assembler::NotEqual, argVal, &returnFalse);
     masm.unboxObject(argVal, genObj);
 
     // Check if it's a StarGeneratorObject.
     Register scratch = regs.takeAny();
     masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_,
                             &returnFalse);
 
-    // If the yield index slot holds an int32 value < YIELD_INDEX_CLOSING,
+    // If the yield index slot holds an int32 value < YIELD_AND_AWAIT_INDEX_CLOSING,
     // the generator is suspended.
-    masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), argVal);
+    masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()), argVal);
     masm.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
     masm.unboxInt32(argVal, scratch);
-    masm.branch32(Assembler::AboveOrEqual, scratch, Imm32(StarGeneratorObject::YIELD_INDEX_CLOSING),
+    masm.branch32(Assembler::AboveOrEqual, scratch,
+                  Imm32(StarGeneratorObject::YIELD_AND_AWAIT_INDEX_CLOSING),
                   &returnFalse);
 
     masm.moveValue(BooleanValue(true), R0);
     EmitReturnFromIC(masm);
 
     masm.bind(&returnFalse);
     masm.moveValue(BooleanValue(false), R0);
     EmitReturnFromIC(masm);
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -762,22 +762,22 @@ BaselineScript::icEntryFromReturnAddress
 {
     MOZ_ASSERT(returnAddr > method_->raw());
     MOZ_ASSERT(returnAddr < method_->raw() + method_->instructionsSize());
     CodeOffset offset(returnAddr - method_->raw());
     return icEntryFromReturnOffset(offset);
 }
 
 void
-BaselineScript::copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets)
+BaselineScript::copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets)
 {
     uint8_t** entries = yieldEntryList();
 
-    for (size_t i = 0; i < yieldOffsets.length(); i++) {
-        uint32_t offset = yieldOffsets[i];
+    for (size_t i = 0; i < yieldAndAwaitOffsets.length(); i++) {
+        uint32_t offset = yieldAndAwaitOffsets[i];
         entries[i] = nativeCodeForPC(script, script->offsetToPC(offset));
     }
 }
 
 void
 BaselineScript::copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm)
 {
     // Fix up the return offset in the IC entries and copy them in.
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -395,17 +395,17 @@ struct BaselineScript
 
     size_t numICEntries() const {
         return icEntries_;
     }
 
     void copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm);
     void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
 
-    void copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets);
+    void copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets);
 
     PCMappingIndexEntry& pcMappingIndexEntry(size_t index);
     CompactBufferReader pcMappingReader(size_t indexEntry);
 
     size_t numPCMappingIndexEntries() const {
         return pcMappingIndexEntries_;
     }
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -827,17 +827,17 @@ CreateGenerator(JSContext* cx, BaselineF
 {
     return GeneratorObject::create(cx, frame);
 }
 
 bool
 NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
               uint32_t stackDepth)
 {
-    MOZ_ASSERT(*pc == JSOP_YIELD);
+    MOZ_ASSERT(*pc == JSOP_YIELD || *pc == JSOP_AWAIT);
 
     // Return value is still on the stack.
     MOZ_ASSERT(stackDepth >= 1);
 
     // The expression stack slots are stored on the stack in reverse order, so
     // we copy them to a Vector and pass a pointer to that instead. We use
     // stackDepth - 1 because we don't want to include the return value.
     AutoValueVector exprStack(cx);
@@ -908,17 +908,17 @@ DebugAfterYield(JSContext* cx, BaselineF
 bool
 GeneratorThrowOrClose(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObject*> genObj,
                       HandleValue arg, uint32_t resumeKind)
 {
     // Set the frame's pc to the current resume pc, so that frame iterators
     // work. This function always returns false, so we're guaranteed to enter
     // the exception handler where we will clear the pc.
     JSScript* script = frame->script();
-    uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
+    uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
     frame->setOverridePc(script->offsetToPC(offset));
 
     MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
     MOZ_ALWAYS_FALSE(js::GeneratorThrowOrClose(cx, frame, genObj, arg, resumeKind));
     return false;
 }
 
 bool
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -651,17 +651,18 @@ BytecodeFlowsToBitop(jsbytecode* pc)
 }
 
 extern bool
 IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
 
 inline bool
 FlowsIntoNext(JSOp op)
 {
-    /* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
+    // JSOP_YIELD/JSOP_AWAIT is considered to flow into the next instruction,
+    // like JSOP_CALL.
     switch (op) {
       case JSOP_RETRVAL:
       case JSOP_RETURN:
       case JSOP_THROW:
       case JSOP_GOTO:
       case JSOP_RETSUB:
       case JSOP_FINALYIELDRVAL:
         return false;
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -391,18 +391,18 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             nconsts = script->consts()->length;
         if (script->hasObjects())
             nobjects = script->objects()->length;
         nscopes = script->scopes()->length;
         if (script->hasTrynotes())
             ntrynotes = script->trynotes()->length;
         if (script->hasScopeNotes())
             nscopenotes = script->scopeNotes()->length;
-        if (script->hasYieldOffsets())
-            nyieldoffsets = script->yieldOffsets().length();
+        if (script->hasYieldAndAwaitOffsets())
+            nyieldoffsets = script->yieldAndAwaitOffsets().length();
 
         nTypeSets = script->nTypeSets();
         funLength = script->funLength();
 
         if (script->noScriptRval())
             scriptBits |= (1 << NoScriptRval);
         if (script->strict())
             scriptBits |= (1 << Strict);
@@ -899,17 +899,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             !xdr->codeUint32(&note->length) ||
             !xdr->codeUint32(&note->parent))
         {
             return false;
         }
     }
 
     for (i = 0; i < nyieldoffsets; ++i) {
-        uint32_t* offset = &script->yieldOffsets()[i];
+        uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
         if (!xdr->codeUint32(offset))
             return false;
     }
 
     if (scriptBits & (1 << HasLazyScript)) {
         Rooted<LazyScript*> lazy(cx);
         if (mode == XDR_ENCODE)
             lazy = script->maybeLazyScript();
@@ -2492,17 +2492,17 @@ ScriptDataSize(uint32_t nscopes, uint32_
         size += sizeof(ConstArray) + nconsts * sizeof(Value);
     if (nobjects != 0)
         size += sizeof(ObjectArray) + nobjects * sizeof(NativeObject*);
     if (ntrynotes != 0)
         size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
     if (nscopenotes != 0)
         size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
     if (nyieldoffsets != 0)
-        size += sizeof(YieldOffsetArray) + nyieldoffsets * sizeof(uint32_t);
+        size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
 
      return size;
 }
 
 void
 JSScript::initCompartment(JSContext* cx)
 {
     compartment_ = cx->compartment();
@@ -2589,20 +2589,20 @@ JSScript::partiallyInit(JSContext* cx, H
         script->setHasArray(TRYNOTES);
         cursor += sizeof(TryNoteArray);
     }
     if (nscopenotes != 0) {
         script->setHasArray(SCOPENOTES);
         cursor += sizeof(ScopeNoteArray);
     }
 
-    YieldOffsetArray* yieldOffsets = nullptr;
+    YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
     if (nyieldoffsets != 0) {
-        yieldOffsets = reinterpret_cast<YieldOffsetArray*>(cursor);
-        cursor += sizeof(YieldOffsetArray);
+        yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
+        cursor += sizeof(YieldAndAwaitOffsetArray);
     }
 
     if (nconsts != 0) {
         MOZ_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(JS::Value) == 0);
         script->consts()->length = nconsts;
         script->consts()->vector = (GCPtrValue*)cursor;
         cursor += nconsts * sizeof(script->consts()->vector[0]);
     }
@@ -2633,18 +2633,18 @@ JSScript::partiallyInit(JSContext* cx, H
         size_t vectorSize = nscopenotes * sizeof(script->scopeNotes()->vector[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
     }
 
     if (nyieldoffsets != 0) {
-        yieldOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
-        size_t vectorSize = nyieldoffsets * sizeof(script->yieldOffsets()[0]);
+        yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
+        size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
     }
 
     MOZ_ASSERT(cursor == script->data + size);
     return true;
@@ -2654,20 +2654,20 @@ JSScript::partiallyInit(JSContext* cx, H
 JSScript::initFunctionPrototype(JSContext* cx, Handle<JSScript*> script,
                                 HandleFunction functionProto)
 {
     uint32_t numScopes = 1;
     uint32_t numConsts = 0;
     uint32_t numObjects = 0;
     uint32_t numTryNotes = 0;
     uint32_t numScopeNotes = 0;
-    uint32_t numYieldOffsets = 0;
+    uint32_t numYieldAndAwaitOffsets = 0;
     uint32_t numTypeSets = 0;
     if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
-                       numScopeNotes, numYieldOffsets, numTypeSets))
+                       numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
     {
         return false;
     }
 
     RootedScope enclosing(cx, &cx->global()->emptyGlobalScope());
     Scope* functionProtoScope = FunctionScope::create(cx, nullptr, false, false, functionProto,
                                                       enclosing);
     if (!functionProtoScope)
@@ -2770,17 +2770,17 @@ JSScript::fullyInitFromEmitter(JSContext
     uint32_t prologueLength = bce->prologueOffset();
     uint32_t nsrcnotes;
     if (!bce->finishTakingSrcNotes(&nsrcnotes))
         return false;
     uint32_t natoms = bce->atomIndices->count();
     if (!partiallyInit(cx, script,
                        bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
                        bce->tryNoteList.length(), bce->scopeNoteList.length(),
-                       bce->yieldOffsetList.length(), bce->typesetCount))
+                       bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
     {
         return false;
     }
 
     MOZ_ASSERT(script->mainOffset() == 0);
     script->mainOffset_ = prologueLength;
 
     script->lineno_ = bce->firstLine;
@@ -2825,18 +2825,18 @@ JSScript::fullyInitFromEmitter(JSContext
 
     if (bce->sc->isFunctionBox())
         initFromFunctionBox(cx, script, bce->sc->asFunctionBox());
     else if (bce->sc->isModuleContext())
         initFromModuleContext(cx, script, bce->sc->asModuleContext());
 
     // Copy yield offsets last, as the generator kind is set in
     // initFromFunctionBox.
-    if (bce->yieldOffsetList.length() != 0)
-        bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength);
+    if (bce->yieldAndAwaitOffsetList.length() != 0)
+        bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
 
 #ifdef DEBUG
     script->assertValidJumpTargets();
 #endif
 
     return true;
 }
 
@@ -3273,17 +3273,17 @@ js::detail::CopyScript(JSContext* cx, Ha
     /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
     MOZ_ASSERT(!src->sourceObject()->asTenured().isMarked(gc::GRAY));
 
     uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
     uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
     uint32_t nscopes   = src->scopes()->length;
     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
     uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
-    uint32_t nyieldoffsets = src->hasYieldOffsets() ? src->yieldOffsets().length() : 0;
+    uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
 
     /* Script data */
 
     size_t size = src->dataSize();
     ScopedJSFreePtr<uint8_t> data(AllocScriptData(cx->zone(), size));
     if (size && !data) {
         ReportOutOfMemory(cx);
         return false;
@@ -3416,18 +3416,20 @@ js::detail::CopyScript(JSContext* cx, Ha
         dst->scopes()->vector = vector;
         for (uint32_t i = 0; i < nscopes; ++i)
             vector[i].init(scopes[i]);
     }
     if (ntrynotes != 0)
         dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
     if (nscopenotes != 0)
         dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector);
-    if (nyieldoffsets != 0)
-        dst->yieldOffsets().vector_ = Rebase<uint32_t>(dst, src, src->yieldOffsets().vector_);
+    if (nyieldoffsets != 0) {
+        dst->yieldAndAwaitOffsets().vector_ =
+            Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsets().vector_);
+    }
 
     /*
      * Function delazification assumes that their script does not have a
      * non-syntactic global scope.  We ensure that as follows:
      *
      * 1) Initial parsing only creates lazy functions if
      *    !hasNonSyntacticScope.
      * 2) Cloning a lazy function into a non-global scope will always require
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -150,17 +150,17 @@ struct TryNoteArray {
     uint32_t        length;     // Count of indexed try notes.
 };
 
 struct ScopeNoteArray {
     ScopeNote* vector;          // Array of indexed ScopeNote records.
     uint32_t   length;          // Count of indexed try notes.
 };
 
-class YieldOffsetArray {
+class YieldAndAwaitOffsetArray {
     friend bool
     detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
                        MutableHandle<GCVector<Scope*>> scopes);
 
     uint32_t*       vector_;    // Array of bytecode offsets.
     uint32_t        length_;    // Count of bytecode offsets.
 
   public:
@@ -1701,26 +1701,30 @@ class JSScript : public js::gc::TenuredC
     }
     void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
     void cloneHasArray(JSScript* script) { hasArrayBits = script->hasArrayBits; }
 
     bool hasConsts() const       { return hasArray(CONSTS); }
     bool hasObjects() const      { return hasArray(OBJECTS); }
     bool hasTrynotes() const     { return hasArray(TRYNOTES); }
     bool hasScopeNotes() const   { return hasArray(SCOPENOTES); }
-    bool hasYieldOffsets() const { return isStarGenerator() || isLegacyGenerator() || isAsync(); }
+    bool hasYieldAndAwaitOffsets() const {
+        return isStarGenerator() || isLegacyGenerator() || isAsync();
+    }
 
 #define OFF(fooOff, hasFoo, t)   (fooOff() + (hasFoo() ? sizeof(t) : 0))
 
     size_t scopesOffset() const       { return 0; }
     size_t constsOffset() const       { return scopesOffset() + sizeof(js::ScopeArray); }
     size_t objectsOffset() const      { return OFF(constsOffset,     hasConsts,     js::ConstArray); }
     size_t trynotesOffset() const     { return OFF(objectsOffset,    hasObjects,    js::ObjectArray); }
     size_t scopeNotesOffset() const   { return OFF(trynotesOffset,   hasTrynotes,   js::TryNoteArray); }
-    size_t yieldOffsetsOffset() const { return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray); }
+    size_t yieldAndAwaitOffsetsOffset() const {
+        return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray);
+    }
 
 #undef OFF
 
     size_t dataSize() const { return dataSize_; }
 
     js::ConstArray* consts() {
         MOZ_ASSERT(hasConsts());
         return reinterpret_cast<js::ConstArray*>(data + constsOffset());
@@ -1740,19 +1744,20 @@ class JSScript : public js::gc::TenuredC
         return reinterpret_cast<js::TryNoteArray*>(data + trynotesOffset());
     }
 
     js::ScopeNoteArray* scopeNotes() {
         MOZ_ASSERT(hasScopeNotes());
         return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset());
     }
 
-    js::YieldOffsetArray& yieldOffsets() {
-        MOZ_ASSERT(hasYieldOffsets());
-        return *reinterpret_cast<js::YieldOffsetArray*>(data + yieldOffsetsOffset());
+    js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsets() {
+        MOZ_ASSERT(hasYieldAndAwaitOffsets());
+        return *reinterpret_cast<js::YieldAndAwaitOffsetArray*>(data +
+                                                                yieldAndAwaitOffsetsOffset());
     }
 
     bool hasLoops();
 
     size_t natoms() const {
         MOZ_ASSERT(scriptData_);
         return scriptData_->natoms();
     }
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -59,29 +59,33 @@ GeneratorObject::create(JSContext* cx, A
 
     return obj;
 }
 
 bool
 GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
                          Value* vp, unsigned nvalues)
 {
-    MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
+    MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
 
     Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
     MOZ_ASSERT(!genObj->hasExpressionStack());
+    MOZ_ASSERT_IF(*pc == JSOP_AWAIT, genObj->callee().isAsync());
+    MOZ_ASSERT_IF(*pc == JSOP_YIELD,
+                  genObj->callee().isStarGenerator() ||
+                  genObj->callee().isLegacyGenerator());
 
     if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
         RootedValue val(cx, ObjectValue(*frame.callee()));
         ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_IGNORE_STACK, val, nullptr);
         return false;
     }
 
-    uint32_t yieldIndex = GET_UINT24(pc);
-    genObj->setYieldIndex(yieldIndex);
+    uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
+    genObj->setYieldAndAwaitIndex(yieldAndAwaitIndex);
     genObj->setEnvironmentChain(*frame.environmentChain());
 
     if (nvalues) {
         ArrayObject* stack = NewDenseCopiedArray(cx, nvalues, vp);
         if (!stack)
             return false;
         genObj->setExpressionStack(*stack);
     }
@@ -168,17 +172,17 @@ GeneratorObject::resume(JSContext* cx, I
         MOZ_ASSERT(activation.regs().spForStackDepth(len));
         const Value* src = genObj->expressionStack().getDenseElements();
         mozilla::PodCopy(activation.regs().sp, src, len);
         activation.regs().sp += len;
         genObj->clearExpressionStack();
     }
 
     JSScript* script = callee->nonLazyScript();
-    uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
+    uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
     activation.regs().pc = script->offsetToPC(offset);
 
     // Always push on a value, even if we are raising an exception. In the
     // exception case, the stack needs to have something on it so that exception
     // handling doesn't skip the catch blocks. See TryNoteIter::settle.
     activation.regs().sp++;
     MOZ_ASSERT(activation.regs().spForStackDepth(activation.regs().stackDepth()));
     activation.regs().sp[-1] = arg;
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -16,25 +16,25 @@
 
 namespace js {
 
 class GeneratorObject : public NativeObject
 {
   public:
     // Magic values stored in the yield index slot when the generator is
     // running or closing. See the yield index comment below.
-    static const int32_t YIELD_INDEX_RUNNING = INT32_MAX;
-    static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1;
+    static const int32_t YIELD_AND_AWAIT_INDEX_RUNNING = INT32_MAX;
+    static const int32_t YIELD_AND_AWAIT_INDEX_CLOSING = INT32_MAX - 1;
 
     enum {
         CALLEE_SLOT = 0,
         ENV_CHAIN_SLOT,
         ARGS_OBJ_SLOT,
         EXPRESSION_STACK_SLOT,
-        YIELD_INDEX_SLOT,
+        YIELD_AND_AWAIT_INDEX_SLOT,
         NEWTARGET_SLOT,
         RESERVED_SLOTS
     };
 
     enum ResumeKind { NEXT, THROW, CLOSE };
 
   private:
     static bool suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
@@ -119,81 +119,82 @@ class GeneratorObject : public NativeObj
     void setNewTarget(const Value& newTarget) {
         setFixedSlot(NEWTARGET_SLOT, newTarget);
     }
 
 
     // The yield index slot is abused for a few purposes.  It's undefined if
     // it hasn't been set yet (before the initial yield), and null if the
     // generator is closed. If the generator is running, the yield index is
-    // YIELD_INDEX_RUNNING. If the generator is in that bizarre "closing"
-    // state, the yield index is YIELD_INDEX_CLOSING.
+    // YIELD_AND_AWAIT_INDEX_RUNNING. If the generator is in that bizarre
+    // "closing" state, the yield index is YIELD_AND_AWAIT_INDEX_CLOSING.
     //
     // If the generator is suspended, it's the yield index (stored as
-    // JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that
-    // suspended the generator. The yield index can be mapped to the bytecode
-    // offset (interpreter) or to the native code offset (JIT).
+    // JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield
+    // instruction that suspended the generator. The yield index can be mapped
+    // to the bytecode offset (interpreter) or to the native code offset (JIT).
 
     bool isRunning() const {
         MOZ_ASSERT(!isClosed());
-        return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_RUNNING;
+        return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_RUNNING;
     }
     bool isClosing() const {
-        return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING;
+        return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_CLOSING;
     }
     bool isSuspended() const {
         // Note: also update Baseline's IsSuspendedStarGenerator code if this
         // changes.
         MOZ_ASSERT(!isClosed());
-        static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING,
-                      "test below should return false for YIELD_INDEX_RUNNING");
-        return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING;
+        static_assert(YIELD_AND_AWAIT_INDEX_CLOSING < YIELD_AND_AWAIT_INDEX_RUNNING,
+                      "test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
+        return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
     }
     void setRunning() {
         MOZ_ASSERT(isSuspended());
-        setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_RUNNING));
+        setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_RUNNING));
     }
     void setClosing() {
         MOZ_ASSERT(isSuspended());
-        setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_CLOSING));
+        setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
     }
-    void setYieldIndex(uint32_t yieldIndex) {
-        MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined());
-        MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing());
-        MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING));
-        setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex));
+    void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
+        MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
+                      getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
+        MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
+        MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
+        setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
         MOZ_ASSERT(isSuspended());
     }
-    uint32_t yieldIndex() const {
+    uint32_t yieldAndAwaitIndex() const {
         MOZ_ASSERT(isSuspended());
-        return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
+        return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
     }
     bool isClosed() const {
         return getFixedSlot(CALLEE_SLOT).isNull();
     }
     void setClosed() {
         setFixedSlot(CALLEE_SLOT, NullValue());
         setFixedSlot(ENV_CHAIN_SLOT, NullValue());
         setFixedSlot(ARGS_OBJ_SLOT, NullValue());
         setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
-        setFixedSlot(YIELD_INDEX_SLOT, NullValue());
+        setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, NullValue());
         setFixedSlot(NEWTARGET_SLOT, NullValue());
     }
 
     static size_t offsetOfCalleeSlot() {
         return getFixedSlotOffset(CALLEE_SLOT);
     }
     static size_t offsetOfEnvironmentChainSlot() {
         return getFixedSlotOffset(ENV_CHAIN_SLOT);
     }
     static size_t offsetOfArgsObjSlot() {
         return getFixedSlotOffset(ARGS_OBJ_SLOT);
     }
-    static size_t offsetOfYieldIndexSlot() {
-        return getFixedSlotOffset(YIELD_INDEX_SLOT);
+    static size_t offsetOfYieldAndAwaitIndexSlot() {
+        return getFixedSlotOffset(YIELD_AND_AWAIT_INDEX_SLOT);
     }
     static size_t offsetOfExpressionStackSlot() {
         return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
     }
     static size_t offsetOfNewTargetSlot() {
         return getFixedSlotOffset(NEWTARGET_SLOT);
     }
 };
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1876,17 +1876,16 @@ CASE(EnableInterruptsPseudoOpcode)
     SANITY_CHECKS();
     DISPATCH_TO(op);
 }
 
 /* Various 1-byte no-ops. */
 CASE(JSOP_NOP)
 CASE(JSOP_NOP_DESTRUCTURING)
 CASE(JSOP_UNUSED192)
-CASE(JSOP_UNUSED209)
 CASE(JSOP_UNUSED210)
 CASE(JSOP_UNUSED211)
 CASE(JSOP_UNUSED220)
 CASE(JSOP_UNUSED221)
 CASE(JSOP_UNUSED222)
 CASE(JSOP_UNUSED223)
 CASE(JSOP_CONDSWITCH)
 {
@@ -3930,16 +3929,17 @@ CASE(JSOP_INITIALYIELD)
     POP_RETURN_VALUE();
     MOZ_ASSERT(REGS.stackDepth() == 0);
     if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc))
         goto error;
     goto successful_return_continuation;
 }
 
 CASE(JSOP_YIELD)
+CASE(JSOP_AWAIT)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
     MOZ_ASSERT(REGS.fp()->isFunctionFrame());
     ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
     if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc,
                                         REGS.spForStackDepth(0), REGS.stackDepth() - 2))
     {
         goto error;
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -2066,26 +2066,26 @@ 1234567890123456789012345678901234567890
      */ \
     macro(JSOP_DEBUGLEAVELEXICALENV, 201,"debugleavelexicalenv", NULL, 1,  0,  0,  JOF_BYTE) \
     \
     /*
      * Pops the generator from the top of the stack, suspends it and stops
      * interpretation.
      *   Category: Statements
      *   Type: Generator
-     *   Operands: uint24_t yieldIndex
+     *   Operands: uint24_t yieldAndAwaitIndex
      *   Stack: generator => generator
      */ \
     macro(JSOP_INITIALYIELD,  202,"initialyield", NULL,   4,  1,  1,  JOF_UINT24) \
     /*
      * Pops the generator and the return value 'rval1', stops interpretation and
      * returns 'rval1'. Pushes sent value from 'send()' onto the stack.
      *   Category: Statements
      *   Type: Generator
-     *   Operands: uint24_t yieldIndex
+     *   Operands: uint24_t yieldAndAwaitIndex
      *   Stack: rval1, gen => rval2
      */ \
     macro(JSOP_YIELD,         203,"yield",       NULL,    4,  2,  1,  JOF_UINT24) \
     /*
      * Pops the generator and suspends and closes it. Yields the value in the
      * frame's return value slot.
      *   Category: Statements
      *   Type: Generator
@@ -2130,17 +2130,25 @@ 1234567890123456789012345678901234567890
      * fix up the frame in the JITs. No-op in the interpreter.
      *
      *   Category: Operators
      *   Type: Debugger
      *   Operands:
      *   Stack: =>
      */ \
     macro(JSOP_DEBUGAFTERYIELD,  208, "debugafteryield",  NULL,  1,  0,  0,  JOF_BYTE) \
-    macro(JSOP_UNUSED209,     209, "unused209",    NULL,  1,  0,  0,  JOF_BYTE) \
+    /*
+     * Pops the generator and the return value 'result', stops interpretation
+     * and returns 'result'. Pushes resolved value onto the stack.
+     *   Category: Statements
+     *   Type: Generator
+     *   Operands: uint24_t yieldAndAwaitIndex
+     *   Stack: result, gen => resolved
+     */ \
+    macro(JSOP_AWAIT,         209, "await",        NULL,  4,  2,  1,  JOF_UINT24) \
     macro(JSOP_UNUSED210,     210, "unused210",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED211,     211, "unused211",    NULL,  1,  0,  0,  JOF_BYTE) \
     /*
      * Initializes generator frame, creates a generator and pushes it on the
      * stack.
      *   Category: Statements
      *   Type: Generator
      *   Operands: