Bug 1508178 - Part 1: Move the stack transition comment in BytecodeEmitter and helper classes into its own line, and align globally. r=jorendorff
authorTooru Fujisawa <arai_a@mac.com>
Tue, 20 Nov 2018 14:45:08 +0900
changeset 503647 936db6d8a4733822b544355138e82a96f49fd085
parent 503646 0cb993c91806dfa218746ea7bb2aa300b7af58e8
child 503648 91a0fe92cc4b1b8a09ce6671be194318be0bb25d
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1508178
milestone65.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 1508178 - Part 1: Move the stack transition comment in BytecodeEmitter and helper classes into its own line, and align globally. r=jorendorff
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/CForEmitter.cpp
js/src/frontend/CallOrNewEmitter.cpp
js/src/frontend/ElemOpEmitter.cpp
js/src/frontend/ExpressionStatementEmitter.cpp
js/src/frontend/ForInEmitter.cpp
js/src/frontend/ForOfEmitter.cpp
js/src/frontend/ForOfLoopControl.cpp
js/src/frontend/NameOpEmitter.cpp
js/src/frontend/PropOpEmitter.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -741,52 +741,56 @@ NonLocalExitControl::prepareForNonLocalJ
                  * There's a [exception or hole, retsub pc-index] pair and the
                  * possible return value on the stack that we need to pop.
                  */
                 npops += 3;
             } else {
                 if (!flushPops(bce_)) {
                     return false;
                 }
-                if (!bce_->emitGoSub(&finallyControl.gosubs)) { // ...
+                if (!bce_->emitGoSub(&finallyControl.gosubs)) {
+                    //        [stack] ...
                     return false;
                 }
             }
             break;
           }
 
           case StatementKind::ForOfLoop:
             if (emitIteratorClose) {
                 if (!flushPops(bce_)) {
                     return false;
                 }
 
                 ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
                 if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
                                                                   /* isTarget = */ false))
-                {                                         // ...
+                {
+                    //        [stack] ...
                     return false;
                 }
             } else {
                 // The iterator next method, the iterator, and the current
                 // value are on the stack.
                 npops += 3;
             }
             break;
 
           case StatementKind::ForInLoop:
             if (!flushPops(bce_)) {
                 return false;
             }
 
             // The iterator and the current value are on the stack.
-            if (!bce_->emit1(JSOP_POP)) {                 // ... ITER
-                return false;
-            }
-            if (!bce_->emit1(JSOP_ENDITER)) {             // ...
+            if (!bce_->emit1(JSOP_POP)) {
+                //            [stack] ... ITER
+                return false;
+            }
+            if (!bce_->emit1(JSOP_ENDITER)) {
+                //            [stack] ...
                 return false;
             }
             break;
 
           default:
             break;
         }
     }
@@ -794,17 +798,18 @@ NonLocalExitControl::prepareForNonLocalJ
     if (!flushPops(bce_)) {
         return false;
     }
 
     if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
         ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
         if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
                                                           /* isTarget = */ true))
-        {                                                 // ... UNDEF UNDEF UNDEF
+        {
+            //                [stack] ... UNDEF UNDEF UNDEF
             return false;
         }
     }
 
     EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
     for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
         if (!leaveScope(es)) {
             return false;
@@ -1834,25 +1839,28 @@ BytecodeEmitter::emitPropIncDec(UnaryNod
                       isSuper
                       ? PropOpEmitter::ObjKind::Super
                       : PropOpEmitter::ObjKind::Other);
     if (!poe.prepareForObj()) {
         return false;
     }
     if (isSuper) {
         UnaryNode* base = &prop->expression().as<UnaryNode>();
-        if (!emitGetThisForSuperBase(base)) {       // THIS
+        if (!emitGetThisForSuperBase(base)) {
+            //                [stack] THIS
             return false;
         }
     } else {
         if (!emitPropLHS(prop)) {
-            return false;                           // OBJ
-        }
-    }
-    if (!poe.emitIncDec(prop->key().atom())) {      // RESULT
+            //                [stack] OBJ
+            return false;
+        }
+    }
+    if (!poe.emitIncDec(prop->key().atom())) {
+        //                    [stack] RESULT
         return false;
     }
 
     return true;
 }
 
 
 bool
@@ -1884,43 +1892,51 @@ BytecodeEmitter::emitElemOpBase(JSOp op)
     checkTypeSet(op);
     return true;
 }
 
 bool
 BytecodeEmitter::emitElemObjAndKey(PropertyByValue* elem, bool isSuper, ElemOpEmitter& eoe)
 {
     if (isSuper) {
-        if (!eoe.prepareForObj()) {                       //
+        if (!eoe.prepareForObj()) {
+            //                [stack]
             return false;
         }
         UnaryNode* base = &elem->expression().as<UnaryNode>();
-        if (!emitGetThisForSuperBase(base)) {             // THIS
-            return false;
-        }
-        if (!eoe.prepareForKey()) {                       // THIS
-            return false;
-        }
-        if (!emitTree(&elem->key())) {                    // THIS KEY
+        if (!emitGetThisForSuperBase(base)) {
+            //                [stack] THIS
+            return false;
+        }
+        if (!eoe.prepareForKey()) {
+            //                [stack] THIS
+            return false;
+        }
+        if (!emitTree(&elem->key())) {
+            //                [stack] THIS KEY
             return false;
         }
 
         return true;
     }
 
-    if (!eoe.prepareForObj()) {                           //
-        return false;
-    }
-    if (!emitTree(&elem->expression())) {                 // OBJ
-        return false;
-    }
-    if (!eoe.prepareForKey()) {                           // OBJ? OBJ
-        return false;
-    }
-    if (!emitTree(&elem->key())) {                        // OBJ? OBJ KEY
+    if (!eoe.prepareForObj()) {
+        //                    [stack]
+        return false;
+    }
+    if (!emitTree(&elem->expression())) {
+        //                    [stack] OBJ
+        return false;
+    }
+    if (!eoe.prepareForKey()) {
+        //                    [stack] OBJ? OBJ
+        return false;
+    }
+    if (!emitTree(&elem->key())) {
+        //                    [stack] OBJ? OBJ KEY
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitElemIncDec(UnaryNode* incDec)
@@ -1931,43 +1947,47 @@ BytecodeEmitter::emitElemIncDec(UnaryNod
     ElemOpEmitter eoe(this,
                       kind == ParseNodeKind::PostIncrement ? ElemOpEmitter::Kind::PostIncrement
                       : kind == ParseNodeKind::PreIncrement ? ElemOpEmitter::Kind::PreIncrement
                       : kind == ParseNodeKind::PostDecrement ? ElemOpEmitter::Kind::PostDecrement
                       : ElemOpEmitter::Kind::PreDecrement,
                       isSuper
                       ? ElemOpEmitter::ObjKind::Super
                       : ElemOpEmitter::ObjKind::Other);
-    if (!emitElemObjAndKey(elemExpr, isSuper, eoe)) {     // [Super]
-        //                                                // THIS KEY
-        //                                                // [Other]
-        //                                                // OBJ KEY
-        return false;
-    }
-    if (!eoe.emitIncDec()) {                              // RESULT
-         return false;
+    if (!emitElemObjAndKey(elemExpr, isSuper, eoe)) {
+        //                    [stack] # if Super
+        //                    [stack] THIS KEY
+        //                    [stack] # otherwise
+        //                    [stack] OBJ KEY
+        return false;
+    }
+    if (!eoe.emitIncDec()) {
+        //                    [stack] RESULT
+        return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitCallIncDec(UnaryNode* incDec)
 {
     MOZ_ASSERT(incDec->isKind(ParseNodeKind::PreIncrement) ||
                incDec->isKind(ParseNodeKind::PostIncrement) ||
                incDec->isKind(ParseNodeKind::PreDecrement) ||
                incDec->isKind(ParseNodeKind::PostDecrement));
 
     ParseNode* call = incDec->kid();
     MOZ_ASSERT(call->isKind(ParseNodeKind::Call));
-    if (!emitTree(call)) {                              // CALLRESULT
-        return false;
-    }
-    if (!emit1(JSOP_POS)) {                             // N
+    if (!emitTree(call)) {
+        //                    [stack] CALLRESULT
+        return false;
+    }
+    if (!emit1(JSOP_POS)) {
+        //                    [stack] N
         return false;
     }
 
     // The increment/decrement has no side effects, so proceed to throw for
     // invalid assignment target.
     return emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS);
 }
 
@@ -2286,37 +2306,44 @@ BytecodeEmitter::emitSetThis(BinaryNode*
         uint8_t hops = AssertedCast<uint8_t>(coord.hops());
         lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops, coord.slot());
     } else {
         MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic);
         lexicalLoc = loc;
     }
 
     NameOpEmitter noe(this, name, lexicalLoc, NameOpEmitter::Kind::Initialize);
-    if (!noe.prepareForRhs()) {                           //
+    if (!noe.prepareForRhs()) {
+        //                    [stack]
         return false;
     }
 
     // Emit the new |this| value.
-    if (!emitTree(setThisNode->right()))                  // NEWTHIS
-        return false;
+    if (!emitTree(setThisNode->right())) {
+        //                    [stack] NEWTHIS
+        return false;
+    }
 
     // Get the original |this| and throw if we already initialized
     // it. Do *not* use the NameLocation argument, as that's the special
     // lexical location below to deal with super() semantics.
-    if (!emitGetName(name)) {                             // NEWTHIS THIS
-        return false;
-    }
-    if (!emit1(JSOP_CHECKTHISREINIT)) {                   // NEWTHIS THIS
-        return false;
-    }
-    if (!emit1(JSOP_POP)) {                               // NEWTHIS
-        return false;
-    }
-    if (!noe.emitAssignment()) {                          // NEWTHIS
+    if (!emitGetName(name)) {
+        //                    [stack] NEWTHIS THIS
+        return false;
+    }
+    if (!emit1(JSOP_CHECKTHISREINIT)) {
+        //                    [stack] NEWTHIS THIS
+        return false;
+    }
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] NEWTHIS
+        return false;
+    }
+    if (!noe.emitAssignment()) {
+        //                    [stack] NEWTHIS
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitScript(ParseNode* body)
@@ -2517,60 +2544,65 @@ BytecodeEmitter::emitDestructuringLHSRef
                           isSuper
                           ? PropOpEmitter::ObjKind::Super
                           : PropOpEmitter::ObjKind::Other);
         if (!poe.prepareForObj()) {
             return false;
         }
         if (isSuper) {
             UnaryNode* base = &prop->expression().as<UnaryNode>();
-            if (!emitGetThisForSuperBase(base)) {         // THIS SUPERBASE
+            if (!emitGetThisForSuperBase(base)) {
+                //            [stack] THIS SUPERBASE
                 return false;
             }
             // SUPERBASE is pushed onto THIS in poe.prepareForRhs below.
             *emitted = 2;
         } else {
-            if (!emitTree(&prop->expression())) {         // OBJ
+            if (!emitTree(&prop->expression())) {
+                //            [stack] OBJ
                 return false;
             }
             *emitted = 1;
         }
-        if (!poe.prepareForRhs()) {                       // [Super]
-            //                                            // THIS SUPERBASE
-            //                                            // [Other]
-            //                                            // OBJ
+        if (!poe.prepareForRhs()) {
+            //                [stack] # if Super
+            //                [stack] THIS SUPERBASE
+            //                [stack] # otherwise
+            //                [stack] OBJ
             return false;
         }
         break;
       }
 
       case ParseNodeKind::Elem: {
         PropertyByValue* elem = &target->as<PropertyByValue>();
         bool isSuper = elem->isSuper();
         ElemOpEmitter eoe(this,
                           ElemOpEmitter::Kind::SimpleAssignment,
                           isSuper
                           ? ElemOpEmitter::ObjKind::Super
                           : ElemOpEmitter::ObjKind::Other);
-        if (!emitElemObjAndKey(elem, isSuper, eoe)) {     // [Super]
-            //                                            // THIS KEY
-            //                                            // [Other]
-            //                                            // OBJ KEY
+        if (!emitElemObjAndKey(elem, isSuper, eoe)) {
+            //                [stack] # if Super
+            //                [stack] THIS KEY
+            //                [stack] # otherwise
+            //                [stack] OBJ KEY
             return false;
         }
         if (isSuper) {
             // SUPERBASE is pushed onto KEY in eoe.prepareForRhs below.
             *emitted = 3;
         } else {
             *emitted = 2;
         }
-        if (!eoe.prepareForRhs()) {                       // [Super]
-            //                                            // THIS KEY SUPERBASE
-            //                                            // [Other]
-            //                                            // OBJ KEY
+        if (!eoe.prepareForRhs()) {
+            //                [stack] # if Super
+            //                [stack] THIS KEY SUPERBASE
+            //                [stack] # otherwise
+            //                [stack] OBJ KEY
             return false;
         }
         break;
       }
 
       case ParseNodeKind::Call:
         MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "
                                "rejects function calls as assignment "
@@ -2631,173 +2663,193 @@ BytecodeEmitter::emitSetOrInitializeDest
 
               case DestructuringAssignment:
                 loc = lookupName(name);
                 kind = NameOpEmitter::Kind::SimpleAssignment;
                 break;
             }
 
             NameOpEmitter noe(this, name, loc, kind);
-            if (!noe.prepareForRhs()) {                   // V ENV?
+            if (!noe.prepareForRhs()) {
+                //            [stack] V ENV?
                 return false;
             }
             if (noe.emittedBindOp()) {
                 // This is like ordinary assignment, but with one difference.
                 //
                 // In `a = b`, we first determine a binding for `a` (using
                 // JSOP_BINDNAME or JSOP_BINDGNAME), then we evaluate `b`, then
                 // a JSOP_SETNAME instruction.
                 //
                 // In `[a] = [b]`, per spec, `b` is evaluated first, then we
                 // determine a binding for `a`. Then we need to do assignment--
                 // but the operands are on the stack in the wrong order for
                 // JSOP_SETPROP, so we have to add a JSOP_SWAP.
                 //
                 // In the cases where we are emitting a name op, emit a swap
                 // because of this.
-                if (!emit1(JSOP_SWAP)) {                  // ENV V
+                if (!emit1(JSOP_SWAP)) {
+                    //        [stack] ENV V
                     return false;
                 }
             } else {
                 // In cases of emitting a frame slot or environment slot,
                 // nothing needs be done.
             }
-            if (!noe.emitAssignment()) {                  // V
+            if (!noe.emitAssignment()) {
+                //            [stack] V
                 return false;
             }
 
             break;
           }
 
           case ParseNodeKind::Dot: {
             // The reference is already pushed by emitDestructuringLHSRef.
-            //                                            // [Super]
-            //                                            // THIS SUPERBASE VAL
-            //                                            // [Other]
-            //                                            // OBJ VAL
+            //                [stack] # if Super
+            //                [stack] THIS SUPERBASE VAL
+            //                [stack] # otherwise
+            //                [stack] OBJ VAL
             PropertyAccess* prop = &target->as<PropertyAccess>();
             // TODO(khyperia): Implement private field access.
             bool isSuper = prop->isSuper();
             PropOpEmitter poe(this,
                               PropOpEmitter::Kind::SimpleAssignment,
                               isSuper
                               ? PropOpEmitter::ObjKind::Super
                               : PropOpEmitter::ObjKind::Other);
             if (!poe.skipObjAndRhs()) {
                 return false;
             }
+            //                [stack] # VAL
             if (!poe.emitAssignment(prop->key().atom())) {
-                return false;                             // VAL
+                return false;
             }
             break;
           }
 
           case ParseNodeKind::Elem: {
             // The reference is already pushed by emitDestructuringLHSRef.
-            //                                            // [Super]
-            //                                            // THIS KEY SUPERBASE VAL
-            //                                            // [Other]
-            //                                            // OBJ KEY VAL
+            //                [stack] # if Super
+            //                [stack] THIS KEY SUPERBASE VAL
+            //                [stack] # otherwise
+            //                [stack] OBJ KEY VAL
             PropertyByValue* elem = &target->as<PropertyByValue>();
             bool isSuper = elem->isSuper();
             ElemOpEmitter eoe(this,
                               ElemOpEmitter::Kind::SimpleAssignment,
                               isSuper
                               ? ElemOpEmitter::ObjKind::Super
                               : ElemOpEmitter::ObjKind::Other);
             if (!eoe.skipObjAndKeyAndRhs()) {
                 return false;
             }
-            if (!eoe.emitAssignment()) {                  // VAL
+            if (!eoe.emitAssignment()) {
+                //            [stack] VAL
                 return false;
             }
             break;
           }
 
           case ParseNodeKind::Call:
             MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "
                                    "rejects function calls as assignment "
                                    "targets in destructuring assignments");
             break;
 
           default:
             MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
         }
 
         // Pop the assigned value.
-        if (!emit1(JSOP_POP)) {                           // !STACK EMPTY!
+        if (!emit1(JSOP_POP)) {
+            //                [stack] # empty
             return false;
         }
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitIteratorNext(const Maybe<uint32_t>& callSourceCoordOffset,
                                   IteratorKind iterKind /* = IteratorKind::Sync */,
                                   bool allowSelfHosted /* = false */)
 {
     MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
                ".next() iteration is prohibited in self-hosted code because it "
                "can run user-modifiable iteration code");
 
-    MOZ_ASSERT(this->stackDepth >= 2);                    // ... NEXT ITER
-
-    if (!emitCall(JSOP_CALL, 0, callSourceCoordOffset)) { // ... RESULT
+    //                        [stack] ... NEXT ITER
+    MOZ_ASSERT(this->stackDepth >= 2);
+
+    if (!emitCall(JSOP_CALL, 0, callSourceCoordOffset)) {
+        //                    [stack] ... RESULT
         return false;
     }
 
     if (iterKind == IteratorKind::Async) {
-        if (!emitAwaitInInnermostScope()) {               // ... RESULT
-            return false;
-        }
-    }
-
-    if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) { // ... RESULT
+        if (!emitAwaitInInnermostScope()) {
+            //                [stack] ... RESULT
+            return false;
+        }
+    }
+
+    if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
+        //                    [stack] ... RESULT
         return false;
     }
     checkTypeSet(JSOP_CALL);
     return true;
 }
 
 bool
 BytecodeEmitter::emitPushNotUndefinedOrNull()
 {
-    MOZ_ASSERT(this->stackDepth > 0);                     // V
-
-    if (!emit1(JSOP_DUP)) {                               // V V
-        return false;
-    }
-    if (!emit1(JSOP_UNDEFINED)) {                         // V V UNDEFINED
-        return false;
-    }
-    if (!emit1(JSOP_STRICTNE)) {                          // V ?NEQL
+    //                        [stack] V
+    MOZ_ASSERT(this->stackDepth > 0);
+
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] V V
+        return false;
+    }
+    if (!emit1(JSOP_UNDEFINED)) {
+        //                    [stack] V V UNDEFINED
+        return false;
+    }
+    if (!emit1(JSOP_STRICTNE)) {
+        //                    [stack] V NEQ
         return false;
     }
 
     JumpList undefinedOrNullJump;
-    if (!emitJump(JSOP_AND, &undefinedOrNullJump)) {      // V ?NEQL
-        return false;
-    }
-
-    if (!emit1(JSOP_POP)) {                               // V
-        return false;
-    }
-    if (!emit1(JSOP_DUP)) {                               // V V
-        return false;
-    }
-    if (!emit1(JSOP_NULL)) {                              // V V NULL
-        return false;
-    }
-    if (!emit1(JSOP_STRICTNE)) {                          // V ?NEQL
-        return false;
-    }
-
-    if (!emitJumpTargetAndPatch(undefinedOrNullJump)) {   // V NOT-UNDEF-OR-NULL
+    if (!emitJump(JSOP_AND, &undefinedOrNullJump)) {
+        //                    [stack] V NEQ
+        return false;
+    }
+
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] V
+        return false;
+    }
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] V V
+        return false;
+    }
+    if (!emit1(JSOP_NULL)) {
+        //                    [stack] V V NULL
+        return false;
+    }
+    if (!emit1(JSOP_STRICTNE)) {
+        //                    [stack] V NEQ
+        return false;
+    }
+
+    if (!emitJumpTargetAndPatch(undefinedOrNullJump)) {
+        //                    [stack] V NOT-UNDEF-OR-NULL
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope,
@@ -2809,36 +2861,40 @@ BytecodeEmitter::emitIteratorCloseInScop
                ".close() on iterators is prohibited in self-hosted code because it "
                "can run user-modifiable iteration code");
 
     // Generate inline logic corresponding to IteratorClose (ES 7.4.6).
     //
     // Callers need to ensure that the iterator object is at the top of the
     // stack.
 
-    if (!emit1(JSOP_DUP)) {                               // ... ITER ITER
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] ... ITER ITER
         return false;
     }
 
     // Step 3.
     //
     // Get the "return" method.
-    if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) {  // ... ITER RET
+    if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) {
+        //                    [stack] ... ITER RET
         return false;
     }
 
     // Step 4.
     //
     // Do nothing if "return" is undefined or null.
     InternalIfEmitter ifReturnMethodIsDefined(this);
-    if (!emitPushNotUndefinedOrNull()) {                  // ... ITER RET NOT-UNDEF-OR-NULL
-        return false;
-    }
-
-    if (!ifReturnMethodIsDefined.emitThenElse()) {        // ... ITER RET
+    if (!emitPushNotUndefinedOrNull()) {
+        //                    [stack] ... ITER RET NOT-UNDEF-OR-NULL
+        return false;
+    }
+
+    if (!ifReturnMethodIsDefined.emitThenElse()) {
+        //                    [stack] ... ITER RET
         return false;
     }
 
     if (completionKind == CompletionKind::Throw) {
         // 7.4.6 IteratorClose ( iterator, completion )
         //   ...
         //   3. Let return be ? GetMethod(iterator, "return").
         //   4. If return is undefined, return Completion(completion).
@@ -2851,128 +2907,152 @@ BytecodeEmitter::emitIteratorCloseInScop
         // is callable, and throws if not.  Since step 6 doesn't match and
         // error handling in step 3 and step 7 can be merged.
         //
         // For CompletionKind::Throw case, an error thrown by JSOP_CALL for
         // step 5 is ignored by try-catch.  So we should check if RET is
         // callable here, outside of try-catch, and the throw immediately if
         // not.
         CheckIsCallableKind kind = CheckIsCallableKind::IteratorReturn;
-        if (!emitCheckIsCallable(kind)) {                 // ... ITER RET
+        if (!emitCheckIsCallable(kind)) {
+            //                [stack] ... ITER RET
             return false;
         }
     }
 
     // Steps 5, 8.
     //
     // Call "return" if it is not undefined or null, and check that it returns
     // an Object.
-    if (!emit1(JSOP_SWAP)) {                              // ... RET ITER
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] ... RET ITER
         return false;
     }
 
     Maybe<TryEmitter> tryCatch;
 
     if (completionKind == CompletionKind::Throw) {
         tryCatch.emplace(this, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
 
         // Mutate stack to balance stack for try-catch.
-        if (!emit1(JSOP_UNDEFINED)) {                     // ... RET ITER UNDEF
-            return false;
-        }
-        if (!tryCatch->emitTry()) {                       // ... RET ITER UNDEF
-            return false;
-        }
-        if (!emitDupAt(2)) {                              // ... RET ITER UNDEF RET
-            return false;
-        }
-        if (!emitDupAt(2)) {                              // ... RET ITER UNDEF RET ITER
-            return false;
-        }
-    }
-
-    if (!emitCall(JSOP_CALL, 0)) {                        // ... ... RESULT
+        if (!emit1(JSOP_UNDEFINED)) {
+            //                [stack] ... RET ITER UNDEF
+            return false;
+        }
+        if (!tryCatch->emitTry()) {
+            //                [stack] ... RET ITER UNDEF
+            return false;
+        }
+        if (!emitDupAt(2)) {
+            //                [stack] ... RET ITER UNDEF RET
+            return false;
+        }
+        if (!emitDupAt(2)) {
+            //                [stack] ... RET ITER UNDEF RET ITER
+            return false;
+        }
+    }
+
+    if (!emitCall(JSOP_CALL, 0)) {
+        //                    [stack] ... ... RESULT
         return false;
     }
     checkTypeSet(JSOP_CALL);
 
     if (iterKind == IteratorKind::Async) {
         if (completionKind != CompletionKind::Throw) {
             // Await clobbers rval, so save the current rval.
-            if (!emit1(JSOP_GETRVAL)) {                   // ... ... RESULT RVAL
-                return false;
-            }
-            if (!emit1(JSOP_SWAP)) {                      // ... ... RVAL RESULT
-                return false;
-            }
-        }
-        if (!emitAwaitInScope(currentScope)) {            // ... ... RVAL? RESULT
+            if (!emit1(JSOP_GETRVAL)) {
+                //            [stack] ... ... RESULT RVAL
+                return false;
+            }
+            if (!emit1(JSOP_SWAP)) {
+                //            [stack] ... ... RVAL RESULT
+                return false;
+            }
+        }
+        if (!emitAwaitInScope(currentScope)) {
+            //                [stack] ... ... RVAL? RESULT
             return false;
         }
     }
 
     if (completionKind == CompletionKind::Throw) {
-        if (!emit1(JSOP_SWAP)) {                          // ... RET ITER RESULT UNDEF
-            return false;
-        }
-        if (!emit1(JSOP_POP)) {                           // ... RET ITER RESULT
-            return false;
-        }
-
-        if (!tryCatch->emitCatch()) {                     // ... RET ITER RESULT
+        if (!emit1(JSOP_SWAP)) {
+            //                [stack] ... RET ITER RESULT UNDEF
+            return false;
+        }
+        if (!emit1(JSOP_POP)) {
+            //                [stack] ... RET ITER RESULT
+            return false;
+        }
+
+        if (!tryCatch->emitCatch()) {
+            //                [stack] ... RET ITER RESULT
             return false;
         }
 
         // Just ignore the exception thrown by call and await.
-        if (!emit1(JSOP_EXCEPTION)) {                     // ... RET ITER RESULT EXC
-            return false;
-        }
-        if (!emit1(JSOP_POP)) {                           // ... RET ITER RESULT
-            return false;
-        }
-
-        if (!tryCatch->emitEnd()) {                       // ... RET ITER RESULT
+        if (!emit1(JSOP_EXCEPTION)) {
+            //                [stack] ... RET ITER RESULT EXC
+            return false;
+        }
+        if (!emit1(JSOP_POP)) {
+            //                [stack] ... RET ITER RESULT
+            return false;
+        }
+
+        if (!tryCatch->emitEnd()) {
+            //                [stack] ... RET ITER RESULT
             return false;
         }
 
         // Restore stack.
-        if (!emit2(JSOP_UNPICK, 2)) {                     // ... RESULT RET ITER
-            return false;
-        }
-        if (!emitPopN(2)) {                               // ... RESULT
+        if (!emit2(JSOP_UNPICK, 2)) {
+            //                [stack] ... RESULT RET ITER
+            return false;
+        }
+        if (!emitPopN(2)) {
+            //                [stack] ... RESULT
             return false;
         }
     } else {
-        if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) { // ... RVAL? RESULT
+        if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) {
+            //                [stack] ... RVAL? RESULT
             return false;
         }
 
         if (iterKind == IteratorKind::Async) {
-            if (!emit1(JSOP_SWAP)) {                      // ... RESULT RVAL
-                return false;
-            }
-            if (!emit1(JSOP_SETRVAL)) {                   // ... RESULT
-                return false;
-            }
-        }
-    }
-
-    if (!ifReturnMethodIsDefined.emitElse()) {            // ... ITER RET
-        return false;
-    }
-
-    if (!emit1(JSOP_POP)) {                               // ... ITER
+            if (!emit1(JSOP_SWAP)) {
+                //            [stack] ... RESULT RVAL
+                return false;
+            }
+            if (!emit1(JSOP_SETRVAL)) {
+                //            [stack] ... RESULT
+                return false;
+            }
+        }
+    }
+
+    if (!ifReturnMethodIsDefined.emitElse()) {
+        //                    [stack] ... ITER RET
+        return false;
+    }
+
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] ... ITER
         return false;
     }
 
     if (!ifReturnMethodIsDefined.emitEnd()) {
         return false;
     }
 
-    return emit1(JSOP_POP);                               // ...
+    return emit1(JSOP_POP);
+    //                        [stack] ...
 }
 
 template <typename InnerEmitter>
 bool
 BytecodeEmitter::wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth, InnerEmitter emitter)
 {
     MOZ_ASSERT(this->stackDepth >= iterDepth);
 
@@ -2999,38 +3079,45 @@ BytecodeEmitter::wrapWithDestructuringIt
 bool
 BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern)
 {
     IfEmitter ifUndefined(this);
     if (!ifUndefined.emitIf(Nothing())) {
         return false;
     }
 
-    if (!emit1(JSOP_DUP)) {                               // VALUE VALUE
-        return false;
-    }
-    if (!emit1(JSOP_UNDEFINED)) {                         // VALUE VALUE UNDEFINED
-        return false;
-    }
-    if (!emit1(JSOP_STRICTEQ)) {                          // VALUE EQL?
-        return false;
-    }
-
-    if (!ifUndefined.emitThen()) {                        // VALUE
-        return false;
-    }
-
-    if (!emit1(JSOP_POP)) {                               //
-        return false;
-    }
-    if (!emitInitializer(defaultExpr, pattern)) {         // DEFAULTVALUE
-        return false;
-    }
-
-    if (!ifUndefined.emitEnd()) {                         // VALUE/DEFAULTVALUE
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] VALUE VALUE
+        return false;
+    }
+    if (!emit1(JSOP_UNDEFINED)) {
+        //                    [stack] VALUE VALUE UNDEFINED
+        return false;
+    }
+    if (!emit1(JSOP_STRICTEQ)) {
+        //                    [stack] VALUE EQ?
+        return false;
+    }
+
+    if (!ifUndefined.emitThen()) {
+        //                    [stack] VALUE
+        return false;
+    }
+
+    if (!emit1(JSOP_POP)) {
+        //                    [stack]
+        return false;
+    }
+    if (!emitInitializer(defaultExpr, pattern)) {
+        //                    [stack] DEFAULTVALUE
+        return false;
+    }
+
+    if (!ifUndefined.emitEnd()) {
+        //                    [stack] VALUE/DEFAULTVALUE
         return false;
     }
     return true;
 }
 
 bool
 BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name)
 {
@@ -3056,21 +3143,23 @@ BytecodeEmitter::setOrEmitSetFunName(Par
     }
 
     MOZ_ASSERT(maybeFun->isKind(ParseNodeKind::Class));
 
     uint32_t nameIndex;
     if (!makeAtomIndex(name, &nameIndex)) {
         return false;
     }
-    if (!emitIndexOp(JSOP_STRING, nameIndex)) { // FUN NAME
+    if (!emitIndexOp(JSOP_STRING, nameIndex)) {
+        //                    [stack] FUN NAME
         return false;
     }
     uint8_t kind = uint8_t(FunctionPrefixKind::None);
-    if (!emit2(JSOP_SETFUNNAME, kind)) {        // FUN
+    if (!emit2(JSOP_SETFUNNAME, kind)) {
+        //                    [stack] FUN
         return false;
     }
     return true;
 }
 
 bool
 BytecodeEmitter::emitInitializer(ParseNode* initializer, ParseNode* pattern)
 {
@@ -3178,38 +3267,44 @@ BytecodeEmitter::emitDestructuringOpsArr
     //   SetOrInitialize(lref, value);        // covered by trynote
     //
     //   // === emitted after loop ===
     //   if (!done)
     //      IteratorClose(iter);
 
     // Use an iterator to destructure the RHS, instead of index lookup. We
     // must leave the *original* value on the stack.
-    if (!emit1(JSOP_DUP)) {                                       // ... OBJ OBJ
-        return false;
-    }
-    if (!emitIterator()) {                                        // ... OBJ NEXT ITER
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] ... OBJ OBJ
+        return false;
+    }
+    if (!emitIterator()) {
+        //                    [stack] ... OBJ NEXT ITER
         return false;
     }
 
     // For an empty pattern [], call IteratorClose unconditionally. Nothing
     // else needs to be done.
     if (!pattern->head()) {
-        if (!emit1(JSOP_SWAP)) {                                  // ... OBJ ITER NEXT
-            return false;
-        }
-        if (!emit1(JSOP_POP)) {                                   // ... OBJ ITER
-            return false;
-        }
-
-        return emitIteratorCloseInInnermostScope();               // ... OBJ
+        if (!emit1(JSOP_SWAP)) {
+            //                [stack] ... OBJ ITER NEXT
+            return false;
+        }
+        if (!emit1(JSOP_POP)) {
+            //                [stack] ... OBJ ITER
+            return false;
+        }
+
+        return emitIteratorCloseInInnermostScope();
+        //                    [stack] ... OBJ
     }
 
     // Push an initial FALSE value for DONE.
-    if (!emit1(JSOP_FALSE)) {                                     // ... OBJ NEXT ITER FALSE
+    if (!emit1(JSOP_FALSE)) {
+        //                    [stack] ... OBJ NEXT ITER FALSE
         return false;
     }
 
     // JSTRY_DESTRUCTURING_ITERCLOSE expects the iterator and the done value
     // to be the second to top and the top of the stack, respectively.
     // IteratorClose is called upon exception only if done is false.
     int32_t tryNoteDepth = stackDepth;
 
@@ -3223,96 +3318,112 @@ BytecodeEmitter::emitDestructuringOpsArr
         ParseNode* lhsPattern = member;
         if (lhsPattern->isKind(ParseNodeKind::Assign)) {
             lhsPattern = lhsPattern->as<AssignmentNode>().left();
         }
 
         bool isElision = lhsPattern->isKind(ParseNodeKind::Elision);
         if (!isElision) {
             auto emitLHSRef = [lhsPattern, &emitted](BytecodeEmitter* bce) {
-                return bce->emitDestructuringLHSRef(lhsPattern, &emitted); // ... OBJ NEXT ITER DONE *LREF
+                return bce->emitDestructuringLHSRef(lhsPattern, &emitted);
+                //            [stack] ... OBJ NEXT ITER DONE LREF*
             };
             if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitLHSRef)) {
                 return false;
             }
         }
 
         // Pick the DONE value to the top of the stack.
         if (emitted) {
-            if (!emit2(JSOP_PICK, emitted)) {                     // ... OBJ NEXT ITER *LREF DONE
+            if (!emit2(JSOP_PICK, emitted)) {
+                //            [stack] ... OBJ NEXT ITER LREF* DONE
                 return false;
             }
         }
 
         if (isFirst) {
             // If this element is the first, DONE is always FALSE, so pop it.
             //
             // Non-first elements should emit if-else depending on the
             // member pattern, below.
-            if (!emit1(JSOP_POP)) {                               // ... OBJ NEXT ITER *LREF
+            if (!emit1(JSOP_POP)) {
+                //            [stack] ... OBJ NEXT ITER LREF*
                 return false;
             }
         }
 
         if (member->isKind(ParseNodeKind::Spread)) {
             InternalIfEmitter ifThenElse(this);
             if (!isFirst) {
                 // If spread is not the first element of the pattern,
                 // iterator can already be completed.
-                                                                  // ... OBJ NEXT ITER *LREF DONE
-                if (!ifThenElse.emitThenElse()) {                 // ... OBJ NEXT ITER *LREF
+                //            [stack] ... OBJ NEXT ITER LREF* DONE
+
+                if (!ifThenElse.emitThenElse()) {
+                    //        [stack] ... OBJ NEXT ITER LREF*
                     return false;
                 }
 
-                if (!emitUint32Operand(JSOP_NEWARRAY, 0)) {       // ... OBJ NEXT ITER *LREF ARRAY
+                if (!emitUint32Operand(JSOP_NEWARRAY, 0)) {
+                    //        [stack] ... OBJ NEXT ITER LREF* ARRAY
                     return false;
                 }
-                if (!ifThenElse.emitElse()) {                     // ... OBJ NEXT ITER *LREF
+                if (!ifThenElse.emitElse()) {
+                    //        [stack] ... OBJ NEXT ITER LREF*
                     return false;
                 }
             }
 
             // If iterator is not completed, create a new array with the rest
             // of the iterator.
-            if (!emitDupAt(emitted + 1)) {                        // ... OBJ NEXT ITER *LREF NEXT
-                return false;
-            }
-            if (!emitDupAt(emitted + 1)) {                        // ... OBJ NEXT ITER *LREF NEXT ITER
-                return false;
-            }
-            if (!emitUint32Operand(JSOP_NEWARRAY, 0)) {           // ... OBJ NEXT ITER *LREF NEXT ITER ARRAY
-                return false;
-            }
-            if (!emitNumberOp(0)) {                               // ... OBJ NEXT ITER *LREF NEXT ITER ARRAY INDEX
-                return false;
-            }
-            if (!emitSpread()) {                                  // ... OBJ NEXT ITER *LREF ARRAY INDEX
-                return false;
-            }
-            if (!emit1(JSOP_POP)) {                               // ... OBJ NEXT ITER *LREF ARRAY
+            if (!emitDupAt(emitted + 1)) {
+                //            [stack] ... OBJ NEXT ITER LREF* NEXT
+                return false;
+            }
+            if (!emitDupAt(emitted + 1)) {
+                //            [stack] ... OBJ NEXT ITER LREF* NEXT ITER
+                return false;
+            }
+            if (!emitUint32Operand(JSOP_NEWARRAY, 0)) {
+                //            [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY
+                return false;
+            }
+            if (!emitNumberOp(0)) {
+                //            [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY INDEX
+                return false;
+            }
+            if (!emitSpread()) {
+                //            [stack] ... OBJ NEXT ITER LREF* ARRAY INDEX
+                return false;
+            }
+            if (!emit1(JSOP_POP)) {
+                //            [stack] ... OBJ NEXT ITER LREF* ARRAY
                 return false;
             }
 
             if (!isFirst) {
                 if (!ifThenElse.emitEnd()) {
                     return false;
                 }
                 MOZ_ASSERT(ifThenElse.pushed() == 1);
             }
 
             // At this point the iterator is done. Unpick a TRUE value for DONE above ITER.
-            if (!emit1(JSOP_TRUE)) {                              // ... OBJ NEXT ITER *LREF ARRAY TRUE
-                return false;
-            }
-            if (!emit2(JSOP_UNPICK, emitted + 1)) {               // ... OBJ NEXT ITER TRUE *LREF ARRAY
+            if (!emit1(JSOP_TRUE)) {
+                //            [stack] ... OBJ NEXT ITER LREF* ARRAY TRUE
+                return false;
+            }
+            if (!emit2(JSOP_UNPICK, emitted + 1)) {
+                //            [stack] ... OBJ NEXT ITER TRUE LREF* ARRAY
                 return false;
             }
 
             auto emitAssignment = [member, flav](BytecodeEmitter* bce) {
-                return bce->emitSetOrInitializeDestructuring(member, flav); // ... OBJ NEXT ITER TRUE
+                return bce->emitSetOrInitializeDestructuring(member, flav);
+                //            [stack] ... OBJ NEXT ITER TRUE
             };
             if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitAssignment)) {
                 return false;
             }
 
             MOZ_ASSERT(!hasNext);
             break;
         }
@@ -3321,84 +3432,104 @@ BytecodeEmitter::emitDestructuringOpsArr
         if (member->isKind(ParseNodeKind::Assign)) {
             pndefault = member->as<AssignmentNode>().right();
         }
 
         MOZ_ASSERT(!member->isKind(ParseNodeKind::Spread));
 
         InternalIfEmitter ifAlreadyDone(this);
         if (!isFirst) {
-                                                                  // ... OBJ NEXT ITER *LREF DONE
-            if (!ifAlreadyDone.emitThenElse()) {                  // ... OBJ NEXT ITER *LREF
-                return false;
-            }
-
-            if (!emit1(JSOP_UNDEFINED)) {                         // ... OBJ NEXT ITER *LREF UNDEF
-                return false;
-            }
-            if (!emit1(JSOP_NOP_DESTRUCTURING)) {                 // ... OBJ NEXT ITER *LREF UNDEF
+            //                [stack] ... OBJ NEXT ITER LREF* DONE
+
+            if (!ifAlreadyDone.emitThenElse()) {
+                //            [stack] ... OBJ NEXT ITER LREF*
+                return false;
+            }
+
+            if (!emit1(JSOP_UNDEFINED)) {
+                //            [stack] ... OBJ NEXT ITER LREF* UNDEF
+                return false;
+            }
+            if (!emit1(JSOP_NOP_DESTRUCTURING)) {
+                //            [stack] ... OBJ NEXT ITER LREF* UNDEF
                 return false;
             }
 
             // The iterator is done. Unpick a TRUE value for DONE above ITER.
-            if (!emit1(JSOP_TRUE)) {                              // ... OBJ NEXT ITER *LREF UNDEF TRUE
-                return false;
-            }
-            if (!emit2(JSOP_UNPICK, emitted + 1)) {               // ... OBJ NEXT ITER TRUE *LREF UNDEF
-                return false;
-            }
-
-            if (!ifAlreadyDone.emitElse()) {                      // ... OBJ NEXT ITER *LREF
-                return false;
-            }
-        }
-
-        if (!emitDupAt(emitted + 1)) {                            // ... OBJ NEXT ITER *LREF NEXT
-            return false;
-        }
-        if (!emitDupAt(emitted + 1)) {                            // ... OBJ NEXT ITER *LREF NEXT ITER
-            return false;
-        }
-        if (!emitIteratorNext(Some(pattern->pn_pos.begin))) {     // ... OBJ NEXT ITER *LREF RESULT
-            return false;
-        }
-        if (!emit1(JSOP_DUP)) {                                   // ... OBJ NEXT ITER *LREF RESULT RESULT
-            return false;
-        }
-        if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {        // ... OBJ NEXT ITER *LREF RESULT DONE
-            return false;
-        }
-
-        if (!emit1(JSOP_DUP)) {                                   // ... OBJ NEXT ITER *LREF RESULT DONE DONE
-            return false;
-        }
-        if (!emit2(JSOP_UNPICK, emitted + 2)) {                   // ... OBJ NEXT ITER DONE *LREF RESULT DONE
+            if (!emit1(JSOP_TRUE)) {
+                //            [stack] ... OBJ NEXT ITER LREF* UNDEF TRUE
+                return false;
+            }
+            if (!emit2(JSOP_UNPICK, emitted + 1)) {
+                //            [stack] ... OBJ NEXT ITER TRUE LREF* UNDEF
+                return false;
+            }
+
+            if (!ifAlreadyDone.emitElse()) {
+                //            [stack] ... OBJ NEXT ITER LREF*
+                return false;
+            }
+        }
+
+        if (!emitDupAt(emitted + 1)) {
+            //                [stack] ... OBJ NEXT ITER LREF* NEXT
+            return false;
+        }
+        if (!emitDupAt(emitted + 1)) {
+            //                [stack] ... OBJ NEXT ITER LREF* NEXT ITER
+            return false;
+        }
+        if (!emitIteratorNext(Some(pattern->pn_pos.begin))) {
+            //                [stack] ... OBJ NEXT ITER LREF* RESULT
+            return false;
+        }
+        if (!emit1(JSOP_DUP)) {
+            //                [stack] ... OBJ NEXT ITER LREF* RESULT RESULT
+            return false;
+        }
+        if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {
+            //                [stack] ... OBJ NEXT ITER LREF* RESULT DONE
+            return false;
+        }
+
+        if (!emit1(JSOP_DUP)) {
+            //                [stack] ... OBJ NEXT ITER LREF* RESULT DONE DONE
+            return false;
+        }
+        if (!emit2(JSOP_UNPICK, emitted + 2)) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF* RESULT DONE
             return false;
         }
 
         InternalIfEmitter ifDone(this);
-        if (!ifDone.emitThenElse()) {                             // ... OBJ NEXT ITER DONE *LREF RESULT
-            return false;
-        }
-
-        if (!emit1(JSOP_POP)) {                                   // ... OBJ NEXT ITER DONE *LREF
-            return false;
-        }
-        if (!emit1(JSOP_UNDEFINED)) {                             // ... OBJ NEXT ITER DONE *LREF UNDEF
-            return false;
-        }
-        if (!emit1(JSOP_NOP_DESTRUCTURING)) {                     // ... OBJ NEXT ITER DONE *LREF UNDEF
-            return false;
-        }
-
-        if (!ifDone.emitElse()) {                                 // ... OBJ NEXT ITER DONE *LREF RESULT
-            return false;
-        }
-
-        if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {       // ... OBJ NEXT ITER DONE *LREF VALUE
+        if (!ifDone.emitThenElse()) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF* RESULT
+            return false;
+        }
+
+        if (!emit1(JSOP_POP)) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF*
+            return false;
+        }
+        if (!emit1(JSOP_UNDEFINED)) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
+            return false;
+        }
+        if (!emit1(JSOP_NOP_DESTRUCTURING)) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
+            return false;
+        }
+
+        if (!ifDone.emitElse()) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF* RESULT
+            return false;
+        }
+
+        if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
+            //                [stack] ... OBJ NEXT ITER DONE LREF* VALUE
             return false;
         }
 
         if (!ifDone.emitEnd()) {
             return false;
         }
         MOZ_ASSERT(ifDone.pushed() == 0);
 
@@ -3406,59 +3537,69 @@ BytecodeEmitter::emitDestructuringOpsArr
             if (!ifAlreadyDone.emitEnd()) {
                 return false;
             }
             MOZ_ASSERT(ifAlreadyDone.pushed() == 2);
         }
 
         if (pndefault) {
             auto emitDefault = [pndefault, lhsPattern](BytecodeEmitter* bce) {
-                return bce->emitDefault(pndefault, lhsPattern);    // ... OBJ NEXT ITER DONE *LREF VALUE
+                return bce->emitDefault(pndefault, lhsPattern);
+                //            [stack] ... OBJ NEXT ITER DONE LREF* VALUE
             };
 
             if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitDefault)) {
                 return false;
             }
         }
 
         if (!isElision) {
             auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
-                return bce->emitSetOrInitializeDestructuring(lhsPattern, flav); // ... OBJ NEXT ITER DONE
+                return bce->emitSetOrInitializeDestructuring(lhsPattern, flav);
+                //            [stack] ... OBJ NEXT ITER DONE
             };
 
             if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitAssignment)) {
                 return false;
             }
         } else {
-            if (!emit1(JSOP_POP)) {                               // ... OBJ NEXT ITER DONE
+            if (!emit1(JSOP_POP)) {
+                //            [stack] ... OBJ NEXT ITER DONE
                 return false;
             }
         }
     }
 
     // The last DONE value is on top of the stack. If not DONE, call
     // IteratorClose.
-                                                                  // ... OBJ NEXT ITER DONE
+    //                        [stack] ... OBJ NEXT ITER DONE
+
     InternalIfEmitter ifDone(this);
-    if (!ifDone.emitThenElse()) {                                 // ... OBJ NEXT ITER
-        return false;
-    }
-    if (!emitPopN(2)) {                                           // ... OBJ
-        return false;
-    }
-    if (!ifDone.emitElse()) {                                     // ... OBJ NEXT ITER
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                                      // ... OBJ ITER NEXT
-        return false;
-    }
-    if (!emit1(JSOP_POP)) {                                       // ... OBJ ITER
-        return false;
-    }
-    if (!emitIteratorCloseInInnermostScope()) {                   // ... OBJ
+    if (!ifDone.emitThenElse()) {
+        //                    [stack] ... OBJ NEXT ITER
+        return false;
+    }
+    if (!emitPopN(2)) {
+        //                    [stack] ... OBJ
+        return false;
+    }
+    if (!ifDone.emitElse()) {
+        //                    [stack] ... OBJ NEXT ITER
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] ... OBJ ITER NEXT
+        return false;
+    }
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] ... OBJ ITER
+        return false;
+    }
+    if (!emitIteratorCloseInInnermostScope()) {
+        //                    [stack] ... OBJ
         return false;
     }
     if (!ifDone.emitEnd()) {
         return false;
     }
 
     return true;
 }
@@ -3470,30 +3611,34 @@ BytecodeEmitter::emitComputedPropertyNam
     return emitTree(computedPropName->kid()) && emit1(JSOP_TOID);
 }
 
 bool
 BytecodeEmitter::emitDestructuringOpsObject(ListNode* pattern, DestructuringFlavor flav)
 {
     MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
 
-    MOZ_ASSERT(this->stackDepth > 0);                             // ... RHS
-
-    if (!emit1(JSOP_CHECKOBJCOERCIBLE)) {                         // ... RHS
+    //                        [stack] ... RHS
+    MOZ_ASSERT(this->stackDepth > 0);
+
+    if (!emit1(JSOP_CHECKOBJCOERCIBLE)) {
+        //                    [stack] ... RHS
         return false;
     }
 
     bool needsRestPropertyExcludedSet = pattern->count() > 1 &&
                                         pattern->last()->isKind(ParseNodeKind::Spread);
     if (needsRestPropertyExcludedSet) {
-        if (!emitDestructuringObjRestExclusionSet(pattern)) {     // ... RHS SET
-            return false;
-        }
-
-        if (!emit1(JSOP_SWAP)) {                                  // ... SET RHS
+        if (!emitDestructuringObjRestExclusionSet(pattern)) {
+            //                [stack] ... RHS SET
+            return false;
+        }
+
+        if (!emit1(JSOP_SWAP)) {
+            //                [stack] ... SET RHS
             return false;
         }
     }
 
     for (ParseNode* member : pattern->contents()) {
         ParseNode* subpattern;
         if (member->isKind(ParseNodeKind::MutateProto) ||
             member->isKind(ParseNodeKind::Spread))
@@ -3508,127 +3653,147 @@ BytecodeEmitter::emitDestructuringOpsObj
         ParseNode* lhs = subpattern;
         MOZ_ASSERT_IF(member->isKind(ParseNodeKind::Spread),
                       !lhs->isKind(ParseNodeKind::Assign));
         if (lhs->isKind(ParseNodeKind::Assign)) {
             lhs = lhs->as<AssignmentNode>().left();
         }
 
         size_t emitted;
-        if (!emitDestructuringLHSRef(lhs, &emitted)) {            // ... *SET RHS *LREF
+        if (!emitDestructuringLHSRef(lhs, &emitted)) {
+            //                [stack] ... SET? RHS LREF*
             return false;
         }
 
         // Duplicate the value being destructured to use as a reference base.
-        if (!emitDupAt(emitted)) {                                // ... *SET RHS *LREF RHS
+        if (!emitDupAt(emitted)) {
+            //                [stack] ... SET? RHS LREF* RHS
             return false;
         }
 
         if (member->isKind(ParseNodeKind::Spread)) {
             if (!updateSourceCoordNotes(member->pn_pos.begin)) {
                 return false;
             }
 
-            if (!emitNewInit()) {                                 // ... *SET RHS *LREF RHS TARGET
-                return false;
-            }
-            if (!emit1(JSOP_DUP)) {                               // ... *SET RHS *LREF RHS TARGET TARGET
-                return false;
-            }
-            if (!emit2(JSOP_PICK, 2)) {                           // ... *SET RHS *LREF TARGET TARGET RHS
+            if (!emitNewInit()) {
+                //            [stack] ... SET? RHS LREF* RHS TARGET
+                return false;
+            }
+            if (!emit1(JSOP_DUP)) {
+                //            [stack] ... SET? RHS LREF* RHS TARGET TARGET
+                return false;
+            }
+            if (!emit2(JSOP_PICK, 2)) {
+                //            [stack] ... SET? RHS LREF* TARGET TARGET RHS
                 return false;
             }
 
             if (needsRestPropertyExcludedSet) {
-                if (!emit2(JSOP_PICK, emitted + 4)) {             // ... RHS *LREF TARGET TARGET RHS SET
+                if (!emit2(JSOP_PICK, emitted + 4)) {
+                    //        [stack] ... RHS LREF* TARGET TARGET RHS SET
                     return false;
                 }
             }
 
             CopyOption option = needsRestPropertyExcludedSet
                                 ? CopyOption::Filtered
                                 : CopyOption::Unfiltered;
-            if (!emitCopyDataProperties(option)) {                // ... RHS *LREF TARGET
+            if (!emitCopyDataProperties(option)) {
+                //            [stack] ... RHS LREF* TARGET
                 return false;
             }
 
             // Destructure TARGET per this member's lhs.
-            if (!emitSetOrInitializeDestructuring(lhs, flav)) {   // ... RHS
+            if (!emitSetOrInitializeDestructuring(lhs, flav)) {
+                //            [stack] ... RHS
                 return false;
             }
 
             MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
             break;
         }
 
         // Now push the property name currently being matched, which is the
         // current property name "label" on the left of a colon in the object
         // initialiser.
         bool needsGetElem = true;
 
         if (member->isKind(ParseNodeKind::MutateProto)) {
-            if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) {   // ... *SET RHS *LREF PROP
+            if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) {
+                //            [stack] ... SET? RHS LREF* PROP
                 return false;
             }
             needsGetElem = false;
         } else {
             MOZ_ASSERT(member->isKind(ParseNodeKind::Colon) ||
                        member->isKind(ParseNodeKind::Shorthand));
 
             ParseNode* key = member->as<BinaryNode>().left();
             if (key->isKind(ParseNodeKind::Number)) {
                 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
-                    return false;                                 // ... *SET RHS *LREF RHS KEY
+                    //        [stack]... SET? RHS LREF* RHS KEY
+                    return false;
                 }
             } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
                        key->isKind(ParseNodeKind::String))
             {
                 if (!emitAtomOp(key->as<NameNode>().atom(), JSOP_GETPROP)) {
-                    return false;                                 // ... *SET RHS *LREF PROP
+                    //        [stack] ... SET? RHS LREF* PROP
+                    return false;
                 }
                 needsGetElem = false;
             } else {
                 if (!emitComputedPropertyName(&key->as<UnaryNode>())) {
-                    return false;                                 // ... *SET RHS *LREF RHS KEY
+                    //        [stack] ... SET? RHS LREF* RHS KEY
+                    return false;
                 }
 
                 // Add the computed property key to the exclusion set.
                 if (needsRestPropertyExcludedSet) {
-                    if (!emitDupAt(emitted + 3)) {                // ... SET RHS *LREF RHS KEY SET
+                    if (!emitDupAt(emitted + 3)) {
+                        //    [stack] ... SET RHS LREF* RHS KEY SET
                         return false;
                     }
-                    if (!emitDupAt(1)) {                          // ... SET RHS *LREF RHS KEY SET KEY
+                    if (!emitDupAt(1)) {
+                        //    [stack] ... SET RHS LREF* RHS KEY SET KEY
                         return false;
                     }
-                    if (!emit1(JSOP_UNDEFINED)) {                 // ... SET RHS *LREF RHS KEY SET KEY UNDEFINED
+                    if (!emit1(JSOP_UNDEFINED)) {
+                        //    [stack] ... SET RHS LREF* RHS KEY SET KEY UNDEFINED
                         return false;
                     }
-                    if (!emit1(JSOP_INITELEM)) {                  // ... SET RHS *LREF RHS KEY SET
+                    if (!emit1(JSOP_INITELEM)) {
+                        //    [stack] ... SET RHS LREF* RHS KEY SET
                         return false;
                     }
-                    if (!emit1(JSOP_POP)) {                       // ... SET RHS *LREF RHS KEY
+                    if (!emit1(JSOP_POP)) {
+                        //    [stack] ... SET RHS LREF* RHS KEY
                         return false;
                     }
                 }
             }
         }
 
         // Get the property value if not done already.
-        if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) {      // ... *SET RHS *LREF PROP
+        if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) {
+            //                [stack] ... SET? RHS LREF* PROP
             return false;
         }
 
         if (subpattern->isKind(ParseNodeKind::Assign)) {
             if (!emitDefault(subpattern->as<AssignmentNode>().right(), lhs)) {
-                return false;                                     // ... *SET RHS *LREF VALUE
+                //            [stack] ... SET? RHS LREF* VALUE
+                return false;
             }
         }
 
         // Destructure PROP per this member's lhs.
-        if (!emitSetOrInitializeDestructuring(subpattern, flav)) {  // ... *SET RHS
+        if (!emitSetOrInitializeDestructuring(subpattern, flav)) {
+            //                [stack] ... SET? RHS
             return false;
         }
     }
 
     return true;
 }
 
 bool
@@ -3838,38 +4003,43 @@ BytecodeEmitter::emitSingleDeclaration(L
     MOZ_ASSERT(decl->isKind(ParseNodeKind::Name));
 
     // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
     if (!initializer && declList->isKind(ParseNodeKind::Var)) {
         return true;
     }
 
     NameOpEmitter noe(this, decl->name(), NameOpEmitter::Kind::Initialize);
-    if (!noe.prepareForRhs()) {                           // ENV?
+    if (!noe.prepareForRhs()) {
+        //                    [stack] ENV?
         return false;
     }
     if (!initializer) {
         // Lexical declarations are initialized to undefined without an
         // initializer.
         MOZ_ASSERT(declList->isKind(ParseNodeKind::Let),
                    "var declarations without initializers handled above, "
                    "and const declarations must have initializers");
-        if (!emit1(JSOP_UNDEFINED)) {                     // ENV? UNDEF
+        if (!emit1(JSOP_UNDEFINED)) {
+            //                [stack] ENV? UNDEF
             return false;
         }
     } else {
         MOZ_ASSERT(initializer);
-        if (!emitInitializer(initializer, decl)) {        // ENV? V
-            return false;
-        }
-    }
-    if (!noe.emitAssignment()) {                          // V
-         return false;
-    }
-    if (!emit1(JSOP_POP)) {                               //
+        if (!emitInitializer(initializer, decl)) {
+            //                [stack] ENV? V
+            return false;
+        }
+    }
+    if (!noe.emitAssignment()) {
+        //                    [stack] V
+        return false;
+    }
+    if (!emit1(JSOP_POP)) {
+        //                    [stack]
         return false;
     }
 
     return true;
 }
 
 static bool
 EmitAssignmentRhs(BytecodeEmitter* bce, ParseNode* rhs, uint8_t offset)
@@ -3921,41 +4091,46 @@ BytecodeEmitter::emitAssignment(ParseNod
     if (lhs->isKind(ParseNodeKind::Name)) {
         NameNode* nameNode = &lhs->as<NameNode>();
         RootedAtom name(cx, nameNode->name());
         NameOpEmitter noe(this,
                           name,
                           isCompound
                           ? NameOpEmitter::Kind::CompoundAssignment
                           : NameOpEmitter::Kind::SimpleAssignment);
-        if (!noe.prepareForRhs()) {                       // ENV? VAL?
+        if (!noe.prepareForRhs()) {
+            //                [stack] ENV? VAL?
             return false;
         }
 
         // Emit the RHS. If we emitted a BIND[G]NAME, then the scope is on
         // the top of the stack and we need to pick the right RHS value.
         uint8_t offset = noe.emittedBindOp() ? 2 : 1;
-        if (!EmitAssignmentRhs(this, rhs, offset)) {      // ENV? VAL? RHS
+        if (!EmitAssignmentRhs(this, rhs, offset)) {
+            //                [stack] ENV? VAL? RHS
             return false;
         }
         if (rhs && rhs->isDirectRHSAnonFunction()) {
             MOZ_ASSERT(!nameNode->isInParens());
             MOZ_ASSERT(!isCompound);
-            if (!setOrEmitSetFunName(rhs, name)) {         // ENV? VAL? RHS
+            if (!setOrEmitSetFunName(rhs, name)) {
+                //            [stack] ENV? VAL? RHS
                 return false;
             }
         }
 
         // Emit the compound assignment op if there is one.
         if (isCompound) {
-            if (!emit1(compoundOp)) {                     // ENV? VAL
-                return false;
-            }
-        }
-        if (!noe.emitAssignment()) {                      // VAL
+            if (!emit1(compoundOp)) {
+                //            [stack] ENV? VAL
+                return false;
+            }
+        }
+        if (!noe.emitAssignment()) {
+            //                [stack] VAL
             return false;
         }
 
         return true;
     }
 
     Maybe<PropOpEmitter> poe;
     Maybe<ElemOpEmitter> eoe;
@@ -3974,43 +4149,46 @@ BytecodeEmitter::emitAssignment(ParseNod
                     isSuper
                     ? PropOpEmitter::ObjKind::Super
                     : PropOpEmitter::ObjKind::Other);
         if (!poe->prepareForObj()) {
             return false;
         }
         if (isSuper) {
             UnaryNode* base = &prop->expression().as<UnaryNode>();
-            if (!emitGetThisForSuperBase(base)) {         // THIS SUPERBASE
+            if (!emitGetThisForSuperBase(base)) {
+                //            [stack] THIS SUPERBASE
                 return false;
             }
             // SUPERBASE is pushed onto THIS later in poe->emitGet below.
             offset += 2;
         } else {
-            if (!emitTree(&prop->expression())) {         // OBJ
+            if (!emitTree(&prop->expression())) {
+                //            [stack] OBJ
                 return false;
             }
             offset += 1;
         }
         break;
       }
       case ParseNodeKind::Elem: {
         PropertyByValue* elem = &lhs->as<PropertyByValue>();
         bool isSuper = elem->isSuper();
         eoe.emplace(this,
                     isCompound
                     ? ElemOpEmitter::Kind::CompoundAssignment
                     : ElemOpEmitter::Kind::SimpleAssignment,
                     isSuper
                     ? ElemOpEmitter::ObjKind::Super
                     : ElemOpEmitter::ObjKind::Other);
-        if (!emitElemObjAndKey(elem, isSuper, *eoe)) {    // [Super]
-            //                                            // THIS KEY
-            //                                            // [Other]
-            //                                            // OBJ KEY
+        if (!emitElemObjAndKey(elem, isSuper, *eoe)) {
+            //                [stack] # if Super
+            //                [stack] THIS KEY
+            //                [stack] # otherwise
+            //                [stack] OBJ KEY
             return false;
         }
         if (isSuper) {
             // SUPERBASE is pushed onto KEY in eoe->emitGet below.
             offset += 3;
         } else {
             offset += 2;
         }
@@ -4040,102 +4218,111 @@ BytecodeEmitter::emitAssignment(ParseNod
     }
 
     if (isCompound) {
         MOZ_ASSERT(rhs);
         switch (lhs->getKind()) {
           case ParseNodeKind::Dot: {
             PropertyAccess* prop = &lhs->as<PropertyAccess>();
             // TODO(khyperia): Implement private field access.
-            if (!poe->emitGet(prop->key().atom())) {      // [Super]
-                //                                        // THIS SUPERBASE PROP
-                //                                        // [Other]
-                //                                        // OBJ PROP
+            if (!poe->emitGet(prop->key().atom())) {
+                //            [stack] # if Super
+                //            [stack] THIS SUPERBASE PROP
+                //            [stack] # otherwise
+                //            [stack] OBJ PROP
                 return false;
             }
             break;
           }
           case ParseNodeKind::Elem: {
-            if (!eoe->emitGet()) {                        // KEY THIS OBJ ELEM
+            if (!eoe->emitGet()) {
+                //            [stack] KEY THIS OBJ ELEM
                 return false;
             }
             break;
           }
           case ParseNodeKind::Call:
             // We just emitted a JSOP_THROWMSG and popped the call's return
             // value.  Push a random value to make sure the stack depth is
             // correct.
             if (!emit1(JSOP_NULL)) {
+                //            [stack] NULL
                 return false;
             }
             break;
           default:;
         }
     }
 
     switch (lhs->getKind()) {
       case ParseNodeKind::Dot:
-        if (!poe->prepareForRhs()) {                      // [Simple,Super]
-            //                                            // THIS SUPERBASE
-            //                                            // [Simple,Other]
-            //                                            // OBJ
-            //                                            // [Compound,Super]
-            //                                            // THIS SUPERBASE PROP
-            //                                            // [Compound,Other]
-            //                                            // OBJ PROP
+        if (!poe->prepareForRhs()) {
+            //                [stack] # if Simple Assignment with Super
+            //                [stack] THIS SUPERBASE
+            //                [stack] # if Simple Assignment with other
+            //                [stack] OBJ
+            //                [stack] # if Compound Assignment with Super
+            //                [stack] THIS SUPERBASE PROP
+            //                [stack] # if Compound Assignment with other
+            //                [stack] OBJ PROP
             return false;
         }
         break;
       case ParseNodeKind::Elem:
-        if (!eoe->prepareForRhs()) {                      // [Simple,Super]
-            //                                            // THIS KEY SUPERBASE
-            //                                            // [Simple,Other]
-            //                                            // OBJ KEY
-            //                                            // [Compound,Super]
-            //                                            // THIS KEY SUPERBASE ELEM
-            //                                            // [Compound,Other]
-            //                                            // OBJ KEY ELEM
+        if (!eoe->prepareForRhs()) {
+            //                [stack] # if Simple Assignment with Super
+            //                [stack] THIS KEY SUPERBASE
+            //                [stack] # if Simple Assignment with other
+            //                [stack] OBJ KEY
+            //                [stack] # if Compound Assignment with Super
+            //                [stack] THIS KEY SUPERBASE ELEM
+            //                [stack] # if Compound Assignment with other
+            //                [stack] OBJ KEY ELEM
             return false;
         }
         break;
       default:
         break;
     }
 
-    if (!EmitAssignmentRhs(this, rhs, offset)) {          // ... VAL? RHS
+    if (!EmitAssignmentRhs(this, rhs, offset)) {
+        //                    [stack] ... VAL? RHS
         return false;
     }
 
     /* If += etc., emit the binary operator with a source note. */
     if (isCompound) {
         if (!newSrcNote(SRC_ASSIGNOP)) {
             return false;
         }
-        if (!emit1(compoundOp)) {                         // ... VAL
+        if (!emit1(compoundOp)) {
+            //                [stack] ... VAL
             return false;
         }
     }
 
     /* Finally, emit the specialized assignment bytecode. */
     switch (lhs->getKind()) {
       case ParseNodeKind::Dot: {
         PropertyAccess* prop = &lhs->as<PropertyAccess>();
         // TODO(khyperia): Implement private field access.
-        if (!poe->emitAssignment(prop->key().atom())) {   // VAL
+        if (!poe->emitAssignment(prop->key().atom())) {
+            //                [stack] VAL
             return false;
         }
 
         poe.reset();
         break;
       }
       case ParseNodeKind::Call:
         // We threw above, so nothing to do here.
         break;
       case ParseNodeKind::Elem: {
-        if (!eoe->emitAssignment()) {                     // VAL
+        if (!eoe->emitAssignment()) {
+            //                [stack] VAL
             return false;
         }
 
         eoe.reset();
         break;
       }
       case ParseNodeKind::Array:
       case ParseNodeKind::Object:
@@ -4683,55 +4870,65 @@ BytecodeEmitter::emitWith(BinaryNode* wi
 
 bool
 BytecodeEmitter::emitCopyDataProperties(CopyOption option)
 {
     DebugOnly<int32_t> depth = this->stackDepth;
 
     uint32_t argc;
     if (option == CopyOption::Filtered) {
-        MOZ_ASSERT(depth > 2);                 // TARGET SOURCE SET
+        MOZ_ASSERT(depth > 2);
+        //                    [stack] TARGET SOURCE SET
         argc = 3;
 
         if (!emitAtomOp(cx->names().CopyDataProperties,
-                        JSOP_GETINTRINSIC))    // TARGET SOURCE SET COPYDATAPROPERTIES
+                        JSOP_GETINTRINSIC))
         {
+            //                [stack] TARGET SOURCE SET COPYDATAPROPERTIES
             return false;
         }
     } else {
-        MOZ_ASSERT(depth > 1);                 // TARGET SOURCE
+        MOZ_ASSERT(depth > 1);
+        //                    [stack] TARGET SOURCE
         argc = 2;
 
         if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered,
-                        JSOP_GETINTRINSIC))    // TARGET SOURCE COPYDATAPROPERTIES
+                        JSOP_GETINTRINSIC))
         {
-            return false;
-        }
-    }
-
-    if (!emit1(JSOP_UNDEFINED)) {              // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED
-        return false;
-    }
-    if (!emit2(JSOP_PICK, argc + 1)) {         // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET
-        return false;
-    }
-    if (!emit2(JSOP_PICK, argc + 1)) {         // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE
+            //                [stack] TARGET SOURCE COPYDATAPROPERTIES
+            return false;
+        }
+    }
+
+    if (!emit1(JSOP_UNDEFINED)) {
+        //                    [stack] TARGET SOURCE SET? COPYDATAPROPERTIES UNDEFINED
+        return false;
+    }
+    if (!emit2(JSOP_PICK, argc + 1)) {
+        //                    [stack] SOURCE SET? COPYDATAPROPERTIES UNDEFINED TARGET
+        return false;
+    }
+    if (!emit2(JSOP_PICK, argc + 1)) {
+        //                    [stack] SET? COPYDATAPROPERTIES UNDEFINED TARGET SOURCE
         return false;
     }
     if (option == CopyOption::Filtered) {
-        if (!emit2(JSOP_PICK, argc + 1)) {     // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
-            return false;
-        }
-    }
-    if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) { // IGNORED
+        if (!emit2(JSOP_PICK, argc + 1)) {
+            //                [stack] COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
+            return false;
+        }
+    }
+    if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) {
+        //                    [stack] IGNORED
         return false;
     }
     checkTypeSet(JSOP_CALL_IGNORES_RV);
 
-    if (!emit1(JSOP_POP)) {                    // -
+    if (!emit1(JSOP_POP)) {
+        //                    [stack]
         return false;
     }
 
     MOZ_ASSERT(depth - int(argc) == this->stackDepth);
     return true;
 }
 
 #ifdef ENABLE_BIGINT
@@ -4744,132 +4941,165 @@ BytecodeEmitter::emitBigIntOp(BigInt* bi
     return emitIndex32(JSOP_BIGINT, numberList.length() - 1);
 }
 #endif
 
 bool
 BytecodeEmitter::emitIterator()
 {
     // Convert iterable to iterator.
-    if (!emit1(JSOP_DUP)) {                                       // OBJ OBJ
-        return false;
-    }
-    if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) { // OBJ OBJ @@ITERATOR
-        return false;
-    }
-    if (!emitElemOpBase(JSOP_CALLELEM)) {                         // OBJ ITERFN
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                                      // ITERFN OBJ
-        return false;
-    }
-    if (!emitCall(JSOP_CALLITER, 0)) {                            // ITER
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] OBJ OBJ
+        return false;
+    }
+    if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) {
+        //                    [stack] OBJ OBJ @@ITERATOR
+        return false;
+    }
+    if (!emitElemOpBase(JSOP_CALLELEM)) {
+        //                    [stack] OBJ ITERFN
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] ITERFN OBJ
+        return false;
+    }
+    if (!emitCall(JSOP_CALLITER, 0)) {
+        //                    [stack] ITER
         return false;
     }
     checkTypeSet(JSOP_CALLITER);
-    if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {        // ITER
-        return false;
-    }
-    if (!emit1(JSOP_DUP)) {                                       // ITER ITER
-        return false;
-    }
-    if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) {            // ITER NEXT
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                                      // NEXT ITER
+    if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
+        //                    [stack] ITER
+        return false;
+    }
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] ITER ITER
+        return false;
+    }
+    if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) {
+        //                    [stack] ITER NEXT
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] NEXT ITER
         return false;
     }
     return true;
 }
 
 bool
 BytecodeEmitter::emitAsyncIterator()
 {
     // Convert iterable to iterator.
-    if (!emit1(JSOP_DUP)) {                                       // OBJ OBJ
-        return false;
-    }
-    if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) { // OBJ OBJ @@ASYNCITERATOR
-        return false;
-    }
-    if (!emitElemOpBase(JSOP_CALLELEM)) {                         // OBJ ITERFN
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] OBJ OBJ
+        return false;
+    }
+    if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) {
+        //                    [stack] OBJ OBJ @@ASYNCITERATOR
+        return false;
+    }
+    if (!emitElemOpBase(JSOP_CALLELEM)) {
+        //                    [stack] OBJ ITERFN
         return false;
     }
 
     InternalIfEmitter ifAsyncIterIsUndefined(this);
-    if (!emitPushNotUndefinedOrNull()) {                          // OBJ ITERFN !UNDEF-OR-NULL
-        return false;
-    }
-    if (!emit1(JSOP_NOT)) {                                       // OBJ ITERFN UNDEF-OR-NULL
-        return false;
-    }
-    if (!ifAsyncIterIsUndefined.emitThenElse()) {                 // OBJ ITERFN
-        return false;
-    }
-
-    if (!emit1(JSOP_POP)) {                                       // OBJ
-        return false;
-    }
-    if (!emit1(JSOP_DUP)) {                                       // OBJ OBJ
-        return false;
-    }
-    if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) { // OBJ OBJ @@ITERATOR
-        return false;
-    }
-    if (!emitElemOpBase(JSOP_CALLELEM)) {                         // OBJ ITERFN
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                                      // ITERFN OBJ
-        return false;
-    }
-    if (!emitCall(JSOP_CALLITER, 0)) {                            // ITER
+    if (!emitPushNotUndefinedOrNull()) {
+        //                    [stack] OBJ ITERFN !UNDEF-OR-NULL
+        return false;
+    }
+    if (!emit1(JSOP_NOT)) {
+        //                    [stack] OBJ ITERFN UNDEF-OR-NULL
+        return false;
+    }
+    if (!ifAsyncIterIsUndefined.emitThenElse()) {
+        //                    [stack] OBJ ITERFN
+        return false;
+    }
+
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] OBJ
+        return false;
+    }
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] OBJ OBJ
+        return false;
+    }
+    if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) {
+        //                    [stack] OBJ OBJ @@ITERATOR
+        return false;
+    }
+    if (!emitElemOpBase(JSOP_CALLELEM)) {
+        //                    [stack] OBJ ITERFN
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] ITERFN OBJ
+        return false;
+    }
+    if (!emitCall(JSOP_CALLITER, 0)) {
+        //                    [stack] ITER
         return false;
     }
     checkTypeSet(JSOP_CALLITER);
-    if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {        // ITER
-        return false;
-    }
-
-    if (!emit1(JSOP_DUP)) {                                       // ITER ITER
-        return false;
-    }
-    if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) {            // ITER SYNCNEXT
-        return false;
-    }
-
-    if (!emit1(JSOP_TOASYNCITER)) {                               // ITER
-        return false;
-    }
-
-    if (!ifAsyncIterIsUndefined.emitElse()) {                     // OBJ ITERFN
-        return false;
-    }
-
-    if (!emit1(JSOP_SWAP)) {                                      // ITERFN OBJ
-        return false;
-    }
-    if (!emitCall(JSOP_CALLITER, 0)) {                            // ITER
+    if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
+        //                    [stack] ITER
+        return false;
+    }
+
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] ITER ITER
+        return false;
+    }
+    if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) {
+        //                    [stack] ITER SYNCNEXT
+        return false;
+    }
+
+    if (!emit1(JSOP_TOASYNCITER)) {
+        //                    [stack] ITER
+        return false;
+    }
+
+    if (!ifAsyncIterIsUndefined.emitElse()) {
+        //                    [stack] OBJ ITERFN
+        return false;
+    }
+
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] ITERFN OBJ
+        return false;
+    }
+    if (!emitCall(JSOP_CALLITER, 0)) {
+        //                    [stack] ITER
         return false;
     }
     checkTypeSet(JSOP_CALLITER);
-    if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {        // ITER
-        return false;
-    }
-
-    if (!ifAsyncIterIsUndefined.emitEnd()) {                      // ITER
-        return false;
-    }
-
-    if (!emit1(JSOP_DUP)) {                                       // ITER ITER
-        return false;
-    }
-    if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) {            // ITER NEXT
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                                      // NEXT ITER
+    if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
+        //                    [stack] ITER
+        return false;
+    }
+
+    if (!ifAsyncIterIsUndefined.emitEnd()) {
+        //                    [stack] ITER
+        return false;
+    }
+
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] ITER ITER
+        return false;
+    }
+    if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) {
+        //                    [stack] ITER NEXT
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] NEXT ITER
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitSpread(bool allowSelfHosted)
@@ -4882,70 +5112,81 @@ BytecodeEmitter::emitSpread(bool allowSe
     unsigned noteIndex;
     if (!newSrcNote(SRC_FOR_OF, &noteIndex)) {
         return false;
     }
 
     // Jump down to the loop condition to minimize overhead, assuming at least
     // one iteration.  (This is also what we do for loops; whether this
     // assumption holds for spreads is an unanswered question.)
-    if (!loopInfo.emitEntryJump(this)) {                  // NEXT ITER ARR I (during the goto)
-        return false;
-    }
-
-    if (!loopInfo.emitLoopHead(this, Nothing())) {        // NEXT ITER ARR I
+    if (!loopInfo.emitEntryJump(this)) {
+        //                    [stack] NEXT ITER ARR I (during the goto)
+        return false;
+    }
+
+    if (!loopInfo.emitLoopHead(this, Nothing())) {
+        //                    [stack] NEXT ITER ARR I
         return false;
     }
 
     // When we enter the goto above, we have NEXT ITER ARR I on the stack. But
     // when we reach this point on the loop backedge (if spreading produces at
     // least one value), we've additionally pushed a RESULT iteration value.
     // Increment manually to reflect this.
     this->stackDepth++;
 
     {
 #ifdef DEBUG
         auto loopDepth = this->stackDepth;
 #endif
 
         // Emit code to assign result.value to the iteration variable.
-        if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) { // NEXT ITER ARR I VALUE
-            return false;
-        }
-        if (!emit1(JSOP_INITELEM_INC)) {                  // NEXT ITER ARR (I+1)
+        if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
+            //                [stack] NEXT ITER ARR I VALUE
+            return false;
+        }
+        if (!emit1(JSOP_INITELEM_INC)) {
+            //                [stack] NEXT ITER ARR (I+1)
             return false;
         }
 
         MOZ_ASSERT(this->stackDepth == loopDepth - 1);
 
         // Spread operations can't contain |continue|, so don't bother setting loop
         // and enclosing "update" offsets, as we do with for-loops.
 
         // COME FROM the beginning of the loop to here.
-        if (!loopInfo.emitLoopEntry(this, Nothing())) {   // NEXT ITER ARR I
-            return false;
-        }
-
-        if (!emitDupAt(3)) {                              // NEXT ITER ARR I NEXT
-            return false;
-        }
-        if (!emitDupAt(3)) {                              // NEXT ITER ARR I NEXT ITER
+        if (!loopInfo.emitLoopEntry(this, Nothing())) {
+            //                [stack] NEXT ITER ARR I
+            return false;
+        }
+
+        if (!emitDupAt(3)) {
+            //                [stack] NEXT ITER ARR I NEXT
+            return false;
+        }
+        if (!emitDupAt(3)) {
+            //                [stack] NEXT ITER ARR I NEXT ITER
             return false;
         }
         if (!emitIteratorNext(Nothing(), IteratorKind::Sync, allowSelfHosted)) {
-            return false;                                 // ITER ARR I RESULT
-        }
-        if (!emit1(JSOP_DUP)) {                           // NEXT ITER ARR I RESULT RESULT
-            return false;
-        }
-        if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {  // NEXT ITER ARR I RESULT DONE
-            return false;
-        }
-
-        if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ)) {     // NEXT ITER ARR I RESULT
+            //                [stack] ITER ARR I RESULT
+            return false;
+        }
+        if (!emit1(JSOP_DUP)) {
+            //                [stack] NEXT ITER ARR I RESULT RESULT
+            return false;
+        }
+        if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {
+            //                [stack] NEXT ITER ARR I RESULT DONE
+            return false;
+        }
+
+        if (!loopInfo.emitLoopEnd(this, JSOP_IFEQ)) {
+            //                [stack] NEXT ITER ARR I RESULT
             return false;
         }
 
         MOZ_ASSERT(this->stackDepth == loopDepth);
     }
 
     // Let Ion know where the closing jump of this loop is.
     if (!setSrcNoteOffset(noteIndex, SrcNote::ForOf::BackJumpOffset,
@@ -4959,24 +5200,27 @@ BytecodeEmitter::emitSpread(bool allowSe
     MOZ_ASSERT(loopInfo.continues.offset == -1);
 
     if (!addTryNote(JSTRY_FOR_OF, stackDepth, loopInfo.headOffset(),
                     loopInfo.breakTargetOffset()))
     {
         return false;
     }
 
-    if (!emit2(JSOP_PICK, 4)) {                           // ITER ARR FINAL_INDEX RESULT NEXT
-        return false;
-    }
-    if (!emit2(JSOP_PICK, 4)) {                           // ARR FINAL_INDEX RESULT NEXT ITER
-        return false;
-    }
-
-    return emitPopN(3);                                   // ARR FINAL_INDEX
+    if (!emit2(JSOP_PICK, 4)) {
+        //                    [stack] ITER ARR FINAL_INDEX RESULT NEXT
+        return false;
+    }
+    if (!emit2(JSOP_PICK, 4)) {
+        //                    [stack] ARR FINAL_INDEX RESULT NEXT ITER
+        return false;
+    }
+
+    return emitPopN(3);
+    //                        [stack] ARR FINAL_INDEX
 }
 
 bool
 BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead)
 {
     MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
                forHead->isKind(ParseNodeKind::ForOf));
 
@@ -4985,17 +5229,18 @@ BytecodeEmitter::emitInitializeForInOrOf
 
     ParseNode* target = forHead->kid1();
     MOZ_ASSERT(!forHead->kid2());
 
     // If the for-in/of loop didn't have a variable declaration, per-loop
     // initialization is just assigning the iteration value to a target
     // expression.
     if (!parser->astGenerator().isDeclarationList(target)) {
-        return emitAssignment(target, JSOP_NOP, nullptr); // ... ITERVAL
+        return emitAssignment(target, JSOP_NOP, nullptr);
+        //                    [stack] ... ITERVAL
     }
 
     // Otherwise, per-loop initialization is (possibly) declaration
     // initialization.  If the declaration is a lexical declaration, it must be
     // initialized.  If the declaration is a variable declaration, an
     // assignment to that name (which does *not* necessarily assign to the
     // variable!) must be generated.
 
@@ -5017,18 +5262,18 @@ BytecodeEmitter::emitInitializeForInOrOf
             // iteration value *before* initializing.  Thus the initializing
             // value may be buried under a bind-specific value on the stack.
             // Swap it to the top of the stack.
             MOZ_ASSERT(stackDepth >= 2);
             if (!emit1(JSOP_SWAP)) {
                 return false;
             }
         } else {
-             // In cases of emitting a frame slot or environment slot,
-             // nothing needs be done.
+            // In cases of emitting a frame slot or environment slot,
+            // nothing needs be done.
             MOZ_ASSERT(stackDepth >= 1);
         }
         if (!noe.emitAssignment()) {
             return false;
         }
 
         // The caller handles removing the iteration value from the stack.
         return true;
@@ -5065,49 +5310,56 @@ BytecodeEmitter::emitForOf(ForNode* forO
     if (emitterMode == BytecodeEmitter::SelfHosting &&
         forHeadExpr->isKind(ParseNodeKind::Call) &&
         forHeadExpr->as<BinaryNode>().left()->isName(cx->names().allowContentIter)) {
         allowSelfHostedIter = true;
     }
 
     ForOfEmitter forOf(this, headLexicalEmitterScope, allowSelfHostedIter, iterKind);
 
-    if (!forOf.emitIterated()) {                          //
-        return false;
-    }
-
-    if (!emitTree(forHeadExpr)) {                         // ITERABLE
+    if (!forOf.emitIterated()) {
+        //                    [stack]
+        return false;
+    }
+
+    if (!emitTree(forHeadExpr)) {
+        //                    [stack] ITERABLE
         return false;
     }
 
     if (headLexicalEmitterScope) {
         DebugOnly<ParseNode*> forOfTarget = forOfHead->kid1();
         MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::Let) ||
                    forOfTarget->isKind(ParseNodeKind::Const));
     }
 
     if (!forOf.emitInitialize(Some(forOfHead->pn_pos.begin))) {
-        return false;                                     // NEXT ITER VALUE
-    }
-
-    if (!emitInitializeForInOrOfTarget(forOfHead)) {      // NEXT ITER VALUE
-        return false;
-    }
-
-    if (!forOf.emitBody()) {                              // NEXT ITER UNDEF
+        //                    [stack] NEXT ITER VALUE
+        return false;
+    }
+
+    if (!emitInitializeForInOrOfTarget(forOfHead)) {
+        //                    [stack] NEXT ITER VALUE
+        return false;
+    }
+
+    if (!forOf.emitBody()) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
     // Perform the loop body.
     ParseNode* forBody = forOfLoop->body();
-    if (!emitTree(forBody)) {                             // NEXT ITER UNDEF
-        return false;
-    }
-
-    if (!forOf.emitEnd(Some(forHeadExpr->pn_pos.begin))) {  //
+    if (!emitTree(forBody)) {
+        //                    [stack] NEXT ITER UNDEF
+        return false;
+    }
+
+    if (!forOf.emitEnd(Some(forHeadExpr->pn_pos.begin))) {
+        //                    [stack]
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitForIn(ForNode* forInLoop, const EmitterScope* headLexicalEmitterScope)
@@ -5149,51 +5401,58 @@ BytecodeEmitter::emitForIn(ForNode* forI
                 // Pop the initializer.
                 if (!emit1(JSOP_POP)) {
                     return false;
                 }
             }
         }
     }
 
-    if (!forIn.emitIterated()) {                          //
+    if (!forIn.emitIterated()) {
+        //                    [stack]
         return false;
     }
 
     // Evaluate the expression being iterated.
     ParseNode* expr = forInHead->kid3();
-    if (!emitTree(expr)) {                                // EXPR
+    if (!emitTree(expr)) {
+        //                    [stack] EXPR
         return false;
     }
 
     MOZ_ASSERT(forInLoop->iflags() == 0);
 
     MOZ_ASSERT_IF(headLexicalEmitterScope,
                   forInTarget->isKind(ParseNodeKind::Let) ||
                   forInTarget->isKind(ParseNodeKind::Const));
 
-    if (!forIn.emitInitialize()) {                        // ITER ITERVAL
-        return false;
-    }
-
-    if (!emitInitializeForInOrOfTarget(forInHead)) {      // ITER ITERVAL
-        return false;
-    }
-
-    if (!forIn.emitBody()) {                              // ITER ITERVAL
+    if (!forIn.emitInitialize()) {
+        //                    [stack] ITER ITERVAL
+        return false;
+    }
+
+    if (!emitInitializeForInOrOfTarget(forInHead)) {
+        //                    [stack] ITER ITERVAL
+        return false;
+    }
+
+    if (!forIn.emitBody()) {
+        //                    [stack] ITER ITERVAL
         return false;
     }
 
     // Perform the loop body.
     ParseNode* forBody = forInLoop->body();
-    if (!emitTree(forBody)) {                             // ITER ITERVAL
-        return false;
-    }
-
-    if (!forIn.emitEnd(Some(forInHead->pn_pos.begin))) {  //
+    if (!emitTree(forBody)) {
+        //                    [stack] ITER ITERVAL
+        return false;
+    }
+
+    if (!forIn.emitEnd(Some(forInHead->pn_pos.begin))) {
+        //                    [stack]
         return false;
     }
 
     return true;
 }
 
 /* C-style `for (init; cond; update) ...` loop. */
 bool
@@ -5204,80 +5463,91 @@ BytecodeEmitter::emitCStyleFor(ForNode* 
     ParseNode* init = forHead->kid1();
     ParseNode* cond = forHead->kid2();
     ParseNode* update = forHead->kid3();
     bool isLet = init && init->isKind(ParseNodeKind::Let);
 
     CForEmitter cfor(this, isLet ? headLexicalEmitterScope : nullptr);
 
     if (!cfor.emitInit(init ? Some(init->pn_pos.begin) : Nothing())) {
-        return false;                                     //
+        //                    [stack]
+        return false;
     }
 
     // If the head of this for-loop declared any lexical variables, the parser
     // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
     // representing the implicit scope of those variables. By the time we get
     // here, we have already entered that scope. So far, so good.
     if (init) {
         // Emit the `init` clause, whether it's an expression or a variable
         // declaration. (The loop variables were hoisted into an enclosing
         // scope, but we still need to emit code for the initializers.)
         if (init->isForLoopDeclaration()) {
-            if (!emitTree(init)) {                        //
+            if (!emitTree(init)) {
+                //            [stack]
                 return false;
             }
         } else {
             // 'init' is an expression, not a declaration. emitTree left its
             // value on the stack.
-            if (!emitTree(init, ValueUsage::IgnoreValue)) { // VAL
-                return false;
-            }
-            if (!emit1(JSOP_POP)) {                       //
+            if (!emitTree(init, ValueUsage::IgnoreValue)) {
+                //            [stack] VAL
+                return false;
+            }
+            if (!emit1(JSOP_POP)) {
+                //            [stack]
                 return false;
             }
         }
     }
 
     if (!cfor.emitBody(cond ? CForEmitter::Cond::Present : CForEmitter::Cond::Missing,
-                       getOffsetForLoop(forBody)))        //
+                       getOffsetForLoop(forBody)))
     {
-        return false;
-    }
-
-    if (!emitTree(forBody)) {                             //
+        //                    [stack]
+        return false;
+    }
+
+    if (!emitTree(forBody)) {
+        //                    [stack]
         return false;
     }
 
     if (!cfor.emitUpdate(update ? CForEmitter::Update::Present : CForEmitter::Update::Missing,
                          update ? Some(update->pn_pos.begin) : Nothing()))
-    {                                                     //
+    {
+        //                    [stack]
         return false;
     }
 
     // Check for update code to do before the condition (if any).
     if (update) {
-        if (!emitTree(update, ValueUsage::IgnoreValue)) { // VAL
+        if (!emitTree(update, ValueUsage::IgnoreValue)) {
+            //                [stack] VAL
             return false;
         }
     }
 
     if (!cfor.emitCond(Some(forNode->pn_pos.begin),
                        cond ? Some(cond->pn_pos.begin) : Nothing(),
-                       Some(forNode->pn_pos.end)))        //
+                       Some(forNode->pn_pos.end)))
     {
+        //                    [stack]
         return false;
     }
 
     if (cond) {
-        if (!emitTree(cond)) {                            // VAL
-            return false;
-        }
-    }
-
-    if (!cfor.emitEnd()) {                                //
+        if (!emitTree(cond)) {
+            //                [stack] VAL
+            return false;
+        }
+    }
+
+    if (!cfor.emitEnd()) {
+        //                    [stack]
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitFor(ForNode* forNode, const EmitterScope* headLexicalEmitterScope)
@@ -5728,50 +5998,56 @@ bool
 BytecodeEmitter::emitGetFunctionThis(const mozilla::Maybe<uint32_t>& offset)
 {
     if (offset) {
         if (!updateLineNumberNotes(*offset)) {
             return false;
         }
     }
 
-    if (!emitGetName(cx->names().dotThis)) {              // THIS
+    if (!emitGetName(cx->names().dotThis)) {
+        //                    [stack] THIS
         return false;
     }
     if (sc->needsThisTDZChecks()) {
-        if (!emit1(JSOP_CHECKTHIS)) {                     // THIS
+        if (!emit1(JSOP_CHECKTHIS)) {
+            //                [stack] THIS
             return false;
         }
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitGetThisForSuperBase(UnaryNode* superBase)
 {
     MOZ_ASSERT(superBase->isKind(ParseNodeKind::SuperBase));
     NameNode* nameNode = &superBase->kid()->as<NameNode>();
-    return emitGetFunctionThis(nameNode);                 // THIS
+    return emitGetFunctionThis(nameNode);
+    //                        [stack] THIS
 }
 
 bool
 BytecodeEmitter::emitThisLiteral(ThisLiteral* pn)
 {
     if (ParseNode* kid = pn->kid()) {
         NameNode* thisName = &kid->as<NameNode>();
-        return emitGetFunctionThis(thisName);             // THIS
+        return emitGetFunctionThis(thisName);
+        //                    [stack] THIS
     }
 
     if (sc->thisBinding() == ThisBinding::Module) {
-        return emit1(JSOP_UNDEFINED);                     // UNDEF
+        return emit1(JSOP_UNDEFINED);
+        //                    [stack] UNDEF
     }
 
     MOZ_ASSERT(sc->thisBinding() == ThisBinding::Global);
-    return emit1(JSOP_GLOBALTHIS);                        // THIS
+    return emit1(JSOP_GLOBALTHIS);
+    //                        [stack] THIS
 }
 
 bool
 BytecodeEmitter::emitCheckDerivedClassConstructorReturn()
 {
     MOZ_ASSERT(lookupName(cx->names().dotThis).hasKnownSlot());
     if (!emitGetName(cx->names().dotThis)) {
         return false;
@@ -5920,48 +6196,55 @@ bool
 BytecodeEmitter::emitYield(UnaryNode* yieldNode)
 {
     MOZ_ASSERT(sc->isFunctionBox());
     MOZ_ASSERT(yieldNode->isKind(ParseNodeKind::Yield));
 
     bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
     if (needsIteratorResult) {
         if (!emitPrepareIteratorResult()) {
+            //                [stack] ITEROBJ
             return false;
         }
     }
     if (ParseNode* expr = yieldNode->kid()) {
         if (!emitTree(expr)) {
+            //                [stack] ITEROBJ VAL
             return false;
         }
     } 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 (!emitAwaitInInnermostScope()) {               // RESULT
+        if (!emitAwaitInInnermostScope()) {
+            //                [stack] ITEROBJ RESULT
             return false;
         }
     }
 
     if (needsIteratorResult) {
         if (!emitFinishIteratorResult(false)) {
+            //                [stack] ITEROBJ
             return false;
         }
     }
 
     if (!emitGetDotGeneratorInInnermostScope()) {
+        //                    [stack] ITEROBJ .GENERATOR
         return false;
     }
 
     if (!emitYieldOp(JSOP_YIELD)) {
+        //                    [stack] YIELDRESULT
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitAwaitInInnermostScope(UnaryNode* awaitNode)
@@ -5973,33 +6256,38 @@ BytecodeEmitter::emitAwaitInInnermostSco
         return false;
     }
     return emitAwaitInInnermostScope();
 }
 
 bool
 BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope)
 {
-    if (!emit1(JSOP_TRYSKIPAWAIT)) {            // VALUE_OR_RESOLVED CANSKIP
-        return false;
-    }
-
-    if (!emit1(JSOP_NOT)) {                     // VALUE_OR_RESOLVED !CANSKIP
+    if (!emit1(JSOP_TRYSKIPAWAIT)) {
+        //                    [stack] VALUE_OR_RESOLVED CANSKIP
+        return false;
+    }
+
+    if (!emit1(JSOP_NOT)) {
+        //                    [stack] VALUE_OR_RESOLVED !CANSKIP
         return false;
     }
 
     InternalIfEmitter ifCanSkip(this);
-    if (!ifCanSkip.emitThen()) {                // VALUE_OR_RESOLVED
+    if (!ifCanSkip.emitThen()) {
+        //                    [stack] VALUE_OR_RESOLVED
         return false;
     }
 
     if (!emitGetDotGeneratorInScope(currentScope)) {
-        return false;                           // VALUE GENERATOR
-    }
-    if (!emitYieldOp(JSOP_AWAIT)) {             // RESOLVED
+        //                    [stack] VALUE GENERATOR
+        return false;
+    }
+    if (!emitYieldOp(JSOP_AWAIT)) {
+        //                    [stack] RESOLVED
         return false;
     }
 
     if (!ifCanSkip.emitEnd()) {
         return false;
     }
 
     MOZ_ASSERT(ifCanSkip.popped() == 0);
@@ -6012,356 +6300,433 @@ BytecodeEmitter::emitYieldStar(ParseNode
 {
     MOZ_ASSERT(sc->isFunctionBox());
     MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
 
     IteratorKind iterKind = sc->asFunctionBox()->isAsync()
                             ? IteratorKind::Async
                             : IteratorKind::Sync;
 
-    if (!emitTree(iter)) {                                // ITERABLE
+    if (!emitTree(iter)) {
+        //                    [stack] ITERABLE
         return false;
     }
     if (iterKind == IteratorKind::Async) {
-        if (!emitAsyncIterator()) {                       // NEXT ITER
+        if (!emitAsyncIterator()) {
+            //                [stack] NEXT ITER
             return false;
         }
     } else {
-        if (!emitIterator()) {                            // NEXT ITER
+        if (!emitIterator()) {
+            //                [stack] NEXT ITER
             return false;
         }
     }
 
     // Initial send value is undefined.
-    if (!emit1(JSOP_UNDEFINED)) {                         // NEXT ITER RECEIVED
+    if (!emit1(JSOP_UNDEFINED)) {
+        //                    [stack] NEXT ITER RECEIVED
         return false;
     }
 
     int32_t savedDepthTemp;
     int32_t startDepth = stackDepth;
     MOZ_ASSERT(startDepth >= 3);
 
     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
                         TryEmitter::ControlKind::NonSyntactic);
-    if (!tryCatch.emitJumpOverCatchAndFinally()) {        // NEXT ITER RESULT
+    if (!tryCatch.emitJumpOverCatchAndFinally()) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
 
     JumpTarget tryStart{ offset() };
-    if (!tryCatch.emitTry()) {                            // NEXT ITER RESULT
+    if (!tryCatch.emitTry()) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
 
     MOZ_ASSERT(this->stackDepth == startDepth);
 
     // 11.4.3.7 AsyncGeneratorYield step 5.
     if (iterKind == IteratorKind::Async) {
-        if (!emitAwaitInInnermostScope()) {               // NEXT ITER RESULT
+        if (!emitAwaitInInnermostScope()) {
+            //                [stack] NEXT ITER RESULT
             return false;
         }
     }
 
     // Load the generator object.
-    if (!emitGetDotGeneratorInInnermostScope()) {         // NEXT ITER RESULT GENOBJ
+    if (!emitGetDotGeneratorInInnermostScope()) {
+        //                    [stack] NEXT ITER RESULT GENOBJ
         return false;
     }
 
     // Yield RESULT as-is, without re-boxing.
-    if (!emitYieldOp(JSOP_YIELD)) {                       // NEXT ITER RECEIVED
-        return false;
-    }
-
-    if (!tryCatch.emitCatch()) {                          // NEXT ITER RESULT
+    if (!emitYieldOp(JSOP_YIELD)) {
+        //                    [stack] NEXT ITER RECEIVED
+        return false;
+    }
+
+    if (!tryCatch.emitCatch()) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
 
     MOZ_ASSERT(stackDepth == startDepth);
 
-    if (!emit1(JSOP_EXCEPTION)) {                         // NEXT ITER RESULT EXCEPTION
-        return false;
-    }
-    if (!emitDupAt(2)) {                                  // NEXT ITER RESULT EXCEPTION ITER
-        return false;
-    }
-    if (!emit1(JSOP_DUP)) {                               // NEXT ITER RESULT EXCEPTION ITER ITER
-        return false;
-    }
-    if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP)) { // NEXT ITER RESULT EXCEPTION ITER THROW
+    if (!emit1(JSOP_EXCEPTION)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION
+        return false;
+    }
+    if (!emitDupAt(2)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER
+        return false;
+    }
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER ITER
+        return false;
+    }
+    if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER THROW
         return false;
     }
 
     savedDepthTemp = stackDepth;
     InternalIfEmitter ifThrowMethodIsNotDefined(this);
-    if (!emitPushNotUndefinedOrNull()) {                  // NEXT ITER RESULT EXCEPTION ITER THROW NOT-UNDEF-OR-NULL
-        return false;
-    }
-
-    if (!ifThrowMethodIsNotDefined.emitThenElse()) {      // NEXT ITER RESULT EXCEPTION ITER THROW
-        return false;
-    }
+    if (!emitPushNotUndefinedOrNull()) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER THROW NOT-UNDEF-OR-NULL
+        return false;
+    }
+
+    if (!ifThrowMethodIsNotDefined.emitThenElse()) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER THROW
+        return false;
+    }
+
+    //                        [stack] NEXT ITER OLDRESULT EXCEPTION ITER THROW
 
     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
-    // RESULT = ITER.throw(EXCEPTION)                     // NEXT ITER OLDRESULT EXCEPTION ITER THROW
-    if (!emit1(JSOP_SWAP)) {                              // NEXT ITER OLDRESULT EXCEPTION THROW ITER
-        return false;
-    }
-    if (!emit2(JSOP_PICK, 2)) {                           // NEXT ITER OLDRESULT THROW ITER EXCEPTION
-        return false;
-    }
-    if (!emitCall(JSOP_CALL, 1, iter)) {                  // NEXT ITER OLDRESULT RESULT
+    // RESULT = ITER.throw(EXCEPTION)
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] NEXT ITER OLDRESULT EXCEPTION THROW ITER
+        return false;
+    }
+    if (!emit2(JSOP_PICK, 2)) {
+        //                    [stack] NEXT ITER OLDRESULT THROW ITER EXCEPTION
+        return false;
+    }
+    if (!emitCall(JSOP_CALL, 1, iter)) {
+        //                    [stack] NEXT ITER OLDRESULT RESULT
         return false;
     }
     checkTypeSet(JSOP_CALL);
 
     if (iterKind == IteratorKind::Async) {
-        if (!emitAwaitInInnermostScope()) {               // NEXT ITER OLDRESULT RESULT
-            return false;
-        }
-    }
-
-    if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) { // NEXT ITER OLDRESULT RESULT
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                              // NEXT ITER RESULT OLDRESULT
-        return false;
-    }
-    if (!emit1(JSOP_POP)) {                               // NEXT ITER RESULT
+        if (!emitAwaitInInnermostScope()) {
+            //                [stack] NEXT ITER OLDRESULT RESULT
+            return false;
+        }
+    }
+
+    if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) {
+        //                    [stack] NEXT ITER OLDRESULT RESULT
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] NEXT ITER RESULT OLDRESULT
+        return false;
+    }
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
     MOZ_ASSERT(this->stackDepth == startDepth);
     JumpList checkResult;
     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.ii.
     //
     // Note that there is no GOSUB to the finally block here. If the iterator has a
     // "throw" method, it does not perform IteratorClose.
-    if (!emitJump(JSOP_GOTO, &checkResult)) {             // goto checkResult
+    if (!emitJump(JSOP_GOTO, &checkResult)) {
+        //                    [stack] NEXT ITER RESULT
+        //                    [stack] # goto checkResult
         return false;
     }
 
     stackDepth = savedDepthTemp;
-    if (!ifThrowMethodIsNotDefined.emitElse()) {          // NEXT ITER RESULT EXCEPTION ITER THROW
-        return false;
-    }
-
-    if (!emit1(JSOP_POP)) {                               // NEXT ITER RESULT EXCEPTION ITER
+    if (!ifThrowMethodIsNotDefined.emitElse()) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER THROW
+        return false;
+    }
+
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION ITER
         return false;
     }
     // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
     //
     // If the iterator does not have a "throw" method, it calls IteratorClose
     // and then throws a TypeError.
-    if (!emitIteratorCloseInInnermostScope(iterKind)) {   // NEXT ITER RESULT EXCEPTION
-        return false;
-    }
-    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) { // throw
+    if (!emitIteratorCloseInInnermostScope(iterKind)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION
+        return false;
+    }
+    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) {
+        //                    [stack] NEXT ITER RESULT EXCEPTION
+        //                    [stack] # throw
         return false;
     }
 
     stackDepth = savedDepthTemp;
     if (!ifThrowMethodIsNotDefined.emitEnd()) {
         return false;
     }
 
     stackDepth = startDepth;
     if (!tryCatch.emitFinally()) {
-         return false;
+        return false;
     }
 
     // ES 14.4.13, yield * AssignmentExpression, step 5.c
     //
     // Call iterator.return() for receiving a "forced return" completion from
     // the generator.
 
     InternalIfEmitter ifGeneratorClosing(this);
-    if (!emit1(JSOP_ISGENCLOSING)) {                      // NEXT ITER RESULT FTYPE FVALUE CLOSING
-        return false;
-    }
-    if (!ifGeneratorClosing.emitThen()) {                 // NEXT ITER RESULT FTYPE FVALUE
+    if (!emit1(JSOP_ISGENCLOSING)) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE CLOSING
+        return false;
+    }
+    if (!ifGeneratorClosing.emitThen()) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE
         return false;
     }
 
     // Step ii.
     //
     // Get the "return" method.
-    if (!emitDupAt(3)) {                                  // NEXT ITER RESULT FTYPE FVALUE ITER
-        return false;
-    }
-    if (!emit1(JSOP_DUP)) {                               // NEXT ITER RESULT FTYPE FVALUE ITER ITER
-        return false;
-    }
-    if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) {  // NEXT ITER RESULT FTYPE FVALUE ITER RET
+    if (!emitDupAt(3)) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE ITER
+        return false;
+    }
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE ITER ITER
+        return false;
+    }
+    if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE ITER RET
         return false;
     }
 
     // Step iii.
     //
     // Do nothing if "return" is undefined or null.
     InternalIfEmitter ifReturnMethodIsDefined(this);
-    if (!emitPushNotUndefinedOrNull()) {                  // NEXT ITER RESULT FTYPE FVALUE ITER RET NOT-UNDEF-OR-NULL
+    if (!emitPushNotUndefinedOrNull()) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE ITER RET NOT-UNDEF-OR-NULL
         return false;
     }
 
     // Step iv.
     //
     // Call "return" with the argument passed to Generator.prototype.return,
     // which is currently in rval.value.
-    if (!ifReturnMethodIsDefined.emitThenElse()) {        // NEXT ITER OLDRESULT FTYPE FVALUE ITER RET
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                              // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER
-        return false;
-    }
-    if (!emit1(JSOP_GETRVAL)) {                           // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER RVAL
-        return false;
-    }
-    if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {   // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER VALUE
-        return false;
-    }
-    if (!emitCall(JSOP_CALL, 1)) {                        // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
+    if (!ifReturnMethodIsDefined.emitThenElse()) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE ITER RET
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RET ITER
+        return false;
+    }
+    if (!emit1(JSOP_GETRVAL)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RET ITER RVAL
+        return false;
+    }
+    if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RET ITER VALUE
+        return false;
+    }
+    if (!emitCall(JSOP_CALL, 1)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
         return false;
     }
     checkTypeSet(JSOP_CALL);
 
     if (iterKind == IteratorKind::Async) {
-        if (!emitAwaitInInnermostScope()) {               // ... FTYPE FVALUE RESULT
+        if (!emitAwaitInInnermostScope()) {
+            //                [stack] ... FTYPE FVALUE RESULT
             return false;
         }
     }
 
     // Step v.
-    if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) { // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
+    if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
         return false;
     }
 
     // Steps vi-viii.
     //
     // Check if the returned object from iterator.return() is done. If not,
     // continuing yielding.
     InternalIfEmitter ifReturnDone(this);
-    if (!emit1(JSOP_DUP)) {                               // NEXT ITER OLDRESULT FTYPE FVALUE RESULT RESULT
-        return false;
-    }
-    if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {    // NEXT ITER OLDRESULT FTYPE FVALUE RESULT DONE
-        return false;
-    }
-    if (!ifReturnDone.emitThenElse()) {                   // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
-        return false;
-    }
-    if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {   // NEXT ITER OLDRESULT FTYPE FVALUE VALUE
-        return false;
-    }
-
-    if (!emitPrepareIteratorResult()) {                   // NEXT ITER OLDRESULT FTYPE FVALUE VALUE RESULT
-        return false;
-    }
-    if (!emit1(JSOP_SWAP)) {                              // NEXT ITER OLDRESULT FTYPE FVALUE RESULT VALUE
-        return false;
-    }
-    if (!emitFinishIteratorResult(true)) {                // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
-        return false;
-    }
-    if (!emit1(JSOP_SETRVAL)) {                           // NEXT ITER OLDRESULT FTYPE FVALUE
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT RESULT
+        return false;
+    }
+    if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT DONE
+        return false;
+    }
+    if (!ifReturnDone.emitThenElse()) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
+        return false;
+    }
+    if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE VALUE
+        return false;
+    }
+
+    if (!emitPrepareIteratorResult()) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE VALUE RESULT
+        return false;
+    }
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT VALUE
+        return false;
+    }
+    if (!emitFinishIteratorResult(true)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
+        return false;
+    }
+    if (!emit1(JSOP_SETRVAL)) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE
         return false;
     }
     savedDepthTemp = this->stackDepth;
-    if (!ifReturnDone.emitElse()) {                       // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
-        return false;
-    }
-    if (!emit2(JSOP_UNPICK, 3)) {                         // NEXT ITER RESULT OLDRESULT FTYPE FVALUE
-        return false;
-    }
-    if (!emitPopN(3)) {                                   // NEXT ITER RESULT
+    if (!ifReturnDone.emitElse()) {
+        //                    [stack] NEXT ITER OLDRESULT FTYPE FVALUE RESULT
+        return false;
+    }
+    if (!emit2(JSOP_UNPICK, 3)) {
+        //                    [stack] NEXT ITER RESULT OLDRESULT FTYPE FVALUE
+        return false;
+    }
+    if (!emitPopN(3)) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
     {
         // goto tryStart;
         JumpList beq;
         JumpTarget breakTarget{ -1 };
-        if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq, &breakTarget)) { // NEXT ITER RESULT
+        if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq, &breakTarget)) {
+            //                [stack] NEXT ITER RESULT
             return false;
         }
     }
     this->stackDepth = savedDepthTemp;
     if (!ifReturnDone.emitEnd()) {
         return false;
     }
 
-    if (!ifReturnMethodIsDefined.emitElse()) {            // NEXT ITER RESULT FTYPE FVALUE ITER RET
-        return false;
-    }
-    if (!emitPopN(2)) {                                   // NEXT ITER RESULT FTYPE FVALUE
+    if (!ifReturnMethodIsDefined.emitElse()) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE ITER RET
+        return false;
+    }
+    if (!emitPopN(2)) {
+        //                    [stack] NEXT ITER RESULT FTYPE FVALUE
         return false;
     }
     if (!ifReturnMethodIsDefined.emitEnd()) {
         return false;
     }
 
     if (!ifGeneratorClosing.emitEnd()) {
         return false;
     }
 
     if (!tryCatch.emitEnd()) {
         return false;
     }
 
+    //                        [stack] NEXT ITER RECEIVED
+
     // After the try-catch-finally block: send the received value to the iterator.
-    // result = iter.next(received)                              // NEXT ITER RECEIVED
-    if (!emit2(JSOP_UNPICK, 2)) {                                // RECEIVED NEXT ITER
-        return false;
-    }
-    if (!emit1(JSOP_DUP2)) {                                     // RECEIVED NEXT ITER NEXT ITER
-        return false;
-    }
-    if (!emit2(JSOP_PICK, 4)) {                                  // NEXT ITER NEXT ITER RECEIVED
-        return false;
-    }
-    if (!emitCall(JSOP_CALL, 1, iter)) {                         // NEXT ITER RESULT
+    // result = iter.next(received)
+    if (!emit2(JSOP_UNPICK, 2)) {
+        //                    [stack] RECEIVED NEXT ITER
+        return false;
+    }
+    if (!emit1(JSOP_DUP2)) {
+        //                    [stack] RECEIVED NEXT ITER NEXT ITER
+        return false;
+    }
+    if (!emit2(JSOP_PICK, 4)) {
+        //                    [stack] NEXT ITER NEXT ITER RECEIVED
+        return false;
+    }
+    if (!emitCall(JSOP_CALL, 1, iter)) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
     checkTypeSet(JSOP_CALL);
 
     if (iterKind == IteratorKind::Async) {
-        if (!emitAwaitInInnermostScope()) {                      // NEXT ITER RESULT RESULT
-            return false;
-        }
-    }
-
-    if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {      // NEXT ITER RESULT
+        if (!emitAwaitInInnermostScope()) {
+            //                [stack] NEXT ITER RESULT RESULT
+            return false;
+        }
+    }
+
+    if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
     MOZ_ASSERT(this->stackDepth == startDepth);
 
-    if (!emitJumpTargetAndPatch(checkResult)) {                  // checkResult:
-        return false;
-    }
-
-    // if (!result.done) goto tryStart;                          // NEXT ITER RESULT
-    if (!emit1(JSOP_DUP)) {                                      // NEXT ITER RESULT RESULT
-        return false;
-    }
-    if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {           // NEXT ITER RESULT DONE
+    if (!emitJumpTargetAndPatch(checkResult)) {
+        //                    [stack] NEXT ITER RESULT
+        //                    [stack] # checkResult:
+        return false;
+    }
+
+    //                        [stack] NEXT ITER RESULT
+
+    // if (!result.done) goto tryStart;
+    if (!emit1(JSOP_DUP)) {
+        //                    [stack] NEXT ITER RESULT RESULT
+        return false;
+    }
+    if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) {
+        //                    [stack] NEXT ITER RESULT DONE
         return false;
     }
     // if (!DONE) goto tryStart;
     {
         JumpList beq;
         JumpTarget breakTarget{ -1 };
-        if (!emitBackwardJump(JSOP_IFEQ, tryStart, &beq, &breakTarget)) { // NEXT ITER RESULT
+        if (!emitBackwardJump(JSOP_IFEQ, tryStart, &beq, &breakTarget)) {
+            //                [stack] NEXT ITER RESULT
             return false;
         }
     }
 
     // result.value
-    if (!emit2(JSOP_UNPICK, 2)) {                                // RESULT NEXT ITER
-        return false;
-    }
-    if (!emitPopN(2)) {                                          // RESULT
-        return false;
-    }
-    if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {          // VALUE
+    if (!emit2(JSOP_UNPICK, 2)) {
+        //                    [stack] RESULT NEXT ITER
+        return false;
+    }
+    if (!emitPopN(2)) {
+        //                    [stack] RESULT
+        return false;
+    }
+    if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) {
+        //                    [stack] VALUE
         return false;
     }
 
     MOZ_ASSERT(this->stackDepth == startDepth - 2);
 
     return true;
 }
 
@@ -6493,32 +6858,35 @@ BytecodeEmitter::emitDeleteProperty(Unar
                       ? PropOpEmitter::ObjKind::Super
                       : PropOpEmitter::ObjKind::Other);
     if (propExpr->isSuper()) {
         // The expression |delete super.foo;| has to evaluate |super.foo|,
         // which could throw if |this| hasn't yet been set by a |super(...)|
         // call or the super-base is not an object, before throwing a
         // ReferenceError for attempting to delete a super-reference.
         UnaryNode* base = &propExpr->expression().as<UnaryNode>();
-        if (!emitGetThisForSuperBase(base)) {             // THIS
+        if (!emitGetThisForSuperBase(base)) {
+            //                [stack] THIS
             return false;
         }
     } else {
         if (!poe.prepareForObj()) {
             return false;
         }
-        if (!emitPropLHS(propExpr)) {                         // OBJ
-            return false;
-        }
-    }
-
-    if (!poe.emitDelete(propExpr->key().atom())) {        // [Super]
-        //                                                // THIS
-        //                                                // [Other]
-        //                                                // SUCCEEDED
+        if (!emitPropLHS(propExpr)) {
+            //                [stack] OBJ
+            return false;
+        }
+    }
+
+    if (!poe.emitDelete(propExpr->key().atom())) {
+        //                    [stack] # if Super
+        //                    [stack] THIS
+        //                    [stack] # otherwise
+        //                    [stack] SUCCEEDED
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitDeleteElement(UnaryNode* deleteNode)
@@ -6533,39 +6901,45 @@ BytecodeEmitter::emitDeleteElement(Unary
                       ? ElemOpEmitter::ObjKind::Super
                       : ElemOpEmitter::ObjKind::Other);
     if (isSuper) {
         // The expression |delete super[foo];| has to evaluate |super[foo]|,
         // which could throw if |this| hasn't yet been set by a |super(...)|
         // call, or trigger side-effects when evaluating ToPropertyKey(foo),
         // or also throw when the super-base is not an object, before throwing
         // a ReferenceError for attempting to delete a super-reference.
-        if (!eoe.prepareForObj()) {                       //
+        if (!eoe.prepareForObj()) {
+            //                [stack]
             return false;
         }
 
         UnaryNode* base = &elemExpr->expression().as<UnaryNode>();
-        if (!emitGetThisForSuperBase(base)) {             // THIS
-            return false;
-        }
-        if (!eoe.prepareForKey()) {                       // THIS
-            return false;
-        }
-        if (!emitTree(&elemExpr->key())) {                // THIS KEY
+        if (!emitGetThisForSuperBase(base)) {
+            //                [stack] THIS
+            return false;
+        }
+        if (!eoe.prepareForKey()) {
+            //                [stack] THIS
+            return false;
+        }
+        if (!emitTree(&elemExpr->key())) {
+            //                [stack] THIS KEY
             return false;
         }
     } else {
-        if (!emitElemObjAndKey(elemExpr, false, eoe)) {   // OBJ KEY
-            return false;
-        }
-    }
-    if (!eoe.emitDelete()) {                              // [Super]
-        //                                                // THIS
-        //                                                // [Other]
-        //                                                // SUCCEEDED
+        if (!emitElemObjAndKey(elemExpr, false, eoe)) {
+            //                [stack] OBJ KEY
+            return false;
+        }
+    }
+    if (!eoe.emitDelete()) {
+        //                    [stack] # if Super
+        //                    [stack] THIS
+        //                    [stack] # otherwise
+        //                    [stack] SUCCEEDED
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitDeleteExpression(UnaryNode* deleteNode)
@@ -6877,116 +7251,129 @@ BytecodeEmitter::isRestParameter(ParseNo
 }
 
 bool
 BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, ParseNode* call, CallOrNewEmitter& cone)
 {
     switch (callee->getKind()) {
       case ParseNodeKind::Name:
         if (!cone.emitNameCallee(callee->as<NameNode>().name())) {
-            return false;                                 // CALLEE THIS
+            //                [stack] CALLEE THIS
+            return false;
         }
         break;
       case ParseNodeKind::Dot: {
         MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
         PropertyAccess* prop = &callee->as<PropertyAccess>();
         // TODO(khyperia): Implement private field access.
         bool isSuper = prop->isSuper();
 
         PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
         if (!poe.prepareForObj()) {
             return false;
         }
         if (isSuper) {
             UnaryNode* base = &prop->expression().as<UnaryNode>();
-            if (!emitGetThisForSuperBase(base)) {        // THIS
+            if (!emitGetThisForSuperBase(base)) {
+                //            [stack] THIS
                 return false;
             }
         } else {
-            if (!emitPropLHS(prop)) {                    // OBJ
-                return false;
-            }
-        }
-        if (!poe.emitGet(prop->key().atom())) {           // CALLEE THIS?
+            if (!emitPropLHS(prop)) {
+                //            [stack] OBJ
+                return false;
+            }
+        }
+        if (!poe.emitGet(prop->key().atom())) {
+            //                [stack] CALLEE THIS?
             return false;
         }
 
         break;
       }
       case ParseNodeKind::Elem: {
         MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
         PropertyByValue* elem = &callee->as<PropertyByValue>();
         bool isSuper = elem->isSuper();
 
         ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
-        if (!emitElemObjAndKey(elem, isSuper, eoe)) {     // [Super]
-            //                                            // THIS? THIS KEY
-            //                                            // [needsThis,Other]
-            //                                            // OBJ? OBJ KEY
-            return false;
-        }
-        if (!eoe.emitGet()) {                             // CALLEE? THIS
+        if (!emitElemObjAndKey(elem, isSuper, eoe)) {
+            //                [stack] # if Super
+            //                [stack] THIS? THIS KEY
+            //                [stack] # otherwise
+            //                [stack] OBJ? OBJ KEY
+            return false;
+        }
+        if (!eoe.emitGet()) {
+            //                [stack] CALLEE? THIS
             return false;
         }
 
         break;
       }
       case ParseNodeKind::Function:
         if (!cone.prepareForFunctionCallee()) {
             return false;
         }
-        if (!emitTree(callee)) {                          // CALLEE
+        if (!emitTree(callee)) {
+            //                [stack] CALLEE
             return false;
         }
         break;
       case ParseNodeKind::SuperBase:
         MOZ_ASSERT(call->isKind(ParseNodeKind::SuperCall));
         MOZ_ASSERT(parser->astGenerator().isSuperBase(callee));
-        if (!cone.emitSuperCallee()) {                    // CALLEE THIS
+        if (!cone.emitSuperCallee()) {
+            //                [stack] CALLEE THIS
             return false;
         }
         break;
       default:
         if (!cone.prepareForOtherCallee()) {
             return false;
         }
         if (!emitTree(callee)) {
             return false;
         }
         break;
     }
 
-    if (!cone.emitThis()) {                               // CALLEE THIS
+    if (!cone.emitThis()) {
+        //                    [stack] CALLEE THIS
         return false;
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitPipeline(ListNode* node)
 {
     MOZ_ASSERT(node->count() >= 2);
 
-    if (!emitTree(node->head())) {                        // ARG
+    if (!emitTree(node->head())) {
+        //                    [stack] ARG
         return false;
     }
 
     ParseNode* callee = node->head()->pn_next;
     CallOrNewEmitter cone(this, JSOP_CALL,
                           CallOrNewEmitter::ArgumentsKind::Other,
                           ValueUsage::WantValue);
     do {
-        if (!emitCalleeAndThis(callee, node, cone)) {     // ARG CALLEE THIS
-            return false;
-        }
-        if (!emit2(JSOP_PICK, 2)) {                       // CALLEE THIS ARG
-            return false;
-        }
-        if (!cone.emitEnd(1, Some(node->pn_pos.begin))) { // RVAL
+        if (!emitCalleeAndThis(callee, node, cone)) {
+            //                [stack] ARG CALLEE THIS
+            return false;
+        }
+        if (!emit2(JSOP_PICK, 2)) {
+            //                [stack] CALLEE THIS ARG
+            return false;
+        }
+        if (!cone.emitEnd(1, Some(node->pn_pos.begin))) {
+            //                [stack] RVAL
             return false;
         }
 
         cone.reset();
 
         checkTypeSet(JSOP_CALL);
     } while ((callee = callee->pn_next));
 
@@ -6998,35 +7385,40 @@ BytecodeEmitter::emitArguments(ListNode*
                                CallOrNewEmitter& cone)
 {
     uint32_t argc = argsList->count();
     if (argc >= ARGC_LIMIT) {
         reportError(argsList, isCall ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
         return false;
     }
     if (!isSpread) {
-        if (!cone.prepareForNonSpreadArguments()) {       // CALLEE THIS
+        if (!cone.prepareForNonSpreadArguments()) {
+            //                [stack] CALLEE THIS
             return false;
         }
         for (ParseNode* arg : argsList->contents()) {
             if (!emitTree(arg)) {
+                //            [stack] CALLEE THIS ARG*
                 return false;
             }
         }
     } else {
         if (cone.wantSpreadOperand()) {
             UnaryNode* spreadNode = &argsList->head()->as<UnaryNode>();
-            if (!emitTree(spreadNode->kid())) {           // CALLEE THIS ARG0
-                return false;
-            }
-        }
-        if (!cone.emitSpreadArgumentsTest()) {            // CALLEE THIS
-            return false;
-        }
-        if (!emitArray(argsList->head(), argc)) {         // CALLEE THIS ARR
+            if (!emitTree(spreadNode->kid())) {
+                //            [stack] CALLEE THIS ARG0
+                return false;
+            }
+        }
+        if (!cone.emitSpreadArgumentsTest()) {
+            //                [stack] CALLEE THIS
+            return false;
+        }
+        if (!emitArray(argsList->head(), argc)) {
+            //                [stack] CALLEE THIS ARR
             return false;
         }
     }
 
     return true;
 }
 
 bool
@@ -7090,21 +7482,23 @@ BytecodeEmitter::emitCallOrNew(BinaryNod
     JSOp op = callNode->getOp();
     uint32_t argc = argsList->count();
     CallOrNewEmitter cone(this, op,
                           isSpread && (argc == 1) &&
                           isRestParameter(argsList->head()->as<UnaryNode>().kid())
                           ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest
                           : CallOrNewEmitter::ArgumentsKind::Other,
                           valueUsage);
-    if (!emitCalleeAndThis(calleeNode, callNode, cone)) { // CALLEE THIS
+    if (!emitCalleeAndThis(calleeNode, callNode, cone)) {
+        //                    [stack] CALLEE THIS
         return false;
     }
     if (!emitArguments(argsList, isCall, isSpread, cone)) {
-        return false;                                     // CALLEE THIS ARGS...
+        //                    [stack] CALLEE THIS ARGS...
+        return false;
     }
 
     ParseNode* coordNode = callNode;
     if (op == JSOP_CALL || op == JSOP_SPREADCALL) {
         switch (calleeNode->getKind()) {
           case ParseNodeKind::Dot: {
 
             // Check if this member is a simple chain of simple chain of
@@ -7142,17 +7536,18 @@ BytecodeEmitter::emitCallOrNew(BinaryNod
             //          ^  // column coord
             coordNode = argsList;
             break;
           default:
             break;
         }
     }
     if (!cone.emitEnd(argc, Some(coordNode->pn_pos.begin))) {
-        return false;                                     // RVAL
+        //                    [stack] RVAL
+        return false;
     }
 
     return true;
 }
 
 static const JSOp ParseNodeKindToJSOp[] = {
     // JSOP_NOP is for pipeline operator which does not emit its own JSOp
     // but has highest precedence in binary operators
@@ -7737,27 +8132,29 @@ BytecodeEmitter::emitArray(ParseNode* ar
                   "and DoSetElemFallback's handling of JSOP_INITELEM_ARRAY");
     MOZ_ASSERT(count >= nspread);
     MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
                "the parser must throw an error if the array exceeds maximum "
                "length");
 
     // For arrays with spread, this is a very pessimistic allocation, the
     // minimum possible final size.
-    if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) {       // ARRAY
+    if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) {
+        //                    [stack] ARRAY
         return false;
     }
 
     ParseNode* elem = arrayHead;
     uint32_t index;
     bool afterSpread = false;
     for (index = 0; elem; index++, elem = elem->pn_next) {
         if (!afterSpread && elem->isKind(ParseNodeKind::Spread)) {
             afterSpread = true;
-            if (!emitNumberOp(index)) {                             // ARRAY INDEX
+            if (!emitNumberOp(index)) {
+                //            [stack] ARRAY INDEX
                 return false;
             }
         }
         if (!updateSourceCoordNotes(elem->pn_pos.begin)) {
             return false;
         }
 
         bool allowSelfHostedIter = false;
@@ -7773,46 +8170,52 @@ BytecodeEmitter::emitArray(ParseNode* ar
                 if (emitterMode == BytecodeEmitter::SelfHosting &&
                     expr->isKind(ParseNodeKind::Call) &&
                     expr->as<BinaryNode>().left()->isName(cx->names().allowContentIter)) {
                     allowSelfHostedIter = true;
                 }
             } else {
                 expr = elem;
             }
-            if (!emitTree(expr)) {                                       // ARRAY INDEX? VALUE
+            if (!emitTree(expr)) {
+                //            [stack] ARRAY INDEX? VALUE
                 return false;
             }
         }
         if (elem->isKind(ParseNodeKind::Spread)) {
-            if (!emitIterator()) {                                       // ARRAY INDEX NEXT ITER
-                return false;
-            }
-            if (!emit2(JSOP_PICK, 3)) {                                  // INDEX NEXT ITER ARRAY
-                return false;
-            }
-            if (!emit2(JSOP_PICK, 3)) {                                  // NEXT ITER ARRAY INDEX
-                return false;
-            }
-            if (!emitSpread(allowSelfHostedIter)) {                      // ARRAY INDEX
+            if (!emitIterator()) {
+                //            [stack] ARRAY INDEX NEXT ITER
+                return false;
+            }
+            if (!emit2(JSOP_PICK, 3)) {
+                //            [stack] INDEX NEXT ITER ARRAY
+                return false;
+            }
+            if (!emit2(JSOP_PICK, 3)) {
+                //            [stack] NEXT ITER ARRAY INDEX
+                return false;
+            }
+            if (!emitSpread(allowSelfHostedIter)) {
+                //            [stack] ARRAY INDEX
                 return false;
             }
         } else if (afterSpread) {
             if (!emit1(JSOP_INITELEM_INC)) {
                 return false;
             }
         } else {
             if (!emitUint32Operand(JSOP_INITELEM_ARRAY, index)) {
                 return false;
             }
         }
     }
     MOZ_ASSERT(index == count);
     if (afterSpread) {
-        if (!emit1(JSOP_POP)) {                                          // ARRAY
+        if (!emit1(JSOP_POP)) {
+            //                [stack] ARRAY
             return false;
         }
     }
     return true;
 }
 
 static inline JSOp
 UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
@@ -8018,22 +8421,24 @@ BytecodeEmitter::emitFunctionFormalParam
         // First push the RHS if there is a default expression or if it is
         // rest.
 
         if (initializer) {
             // If we have an initializer, emit the initializer and assign it
             // to the argument slot. TDZ is taken care of afterwards.
             MOZ_ASSERT(hasParameterExprs);
 
-            if (!emitArgOp(JSOP_GETARG, argSlot)) {       // ARG
+            if (!emitArgOp(JSOP_GETARG, argSlot)) {
+                //            [stack] ARG
                 return false;
             }
 
             if (!emitDefault(initializer, bindingElement)) {
-                return false;                             // ARG/DEFAULT
+                //            [stack] ARG/DEFAULT
+                return false;
             }
         } else if (isRest) {
             if (!emit1(JSOP_REST)) {
                 return false;
             }
             checkTypeSet(JSOP_REST);
         }
 
@@ -8310,155 +8715,181 @@ BytecodeEmitter::emitClass(ClassNode* cl
 
     // This is kind of silly. In order to the get the home object defined on
     // the constructor, we have to make it second, but we want the prototype
     // on top for EmitPropertyList, because we expect static properties to be
     // rarer. The result is a few more swaps than we would like. Such is life.
     if (heritageExpression) {
         InternalIfEmitter ifThenElse(this);
 
-        if (!emitTree(heritageExpression)) {                    // ... HERITAGE
+        if (!emitTree(heritageExpression)) {
+            //                [stack] ... HERITAGE
             return false;
         }
 
         // Heritage must be null or a non-generator constructor
-        if (!emit1(JSOP_CHECKCLASSHERITAGE)) {                  // ... HERITAGE
+        if (!emit1(JSOP_CHECKCLASSHERITAGE)) {
+            //                [stack] ... HERITAGE
             return false;
         }
 
         // [IF] (heritage !== null)
-        if (!emit1(JSOP_DUP)) {                                 // ... HERITAGE HERITAGE
-            return false;
-        }
-        if (!emit1(JSOP_NULL)) {                                // ... HERITAGE HERITAGE NULL
-            return false;
-        }
-        if (!emit1(JSOP_STRICTNE)) {                            // ... HERITAGE NE
+        if (!emit1(JSOP_DUP)) {
+            //                [stack] ... HERITAGE HERITAGE
+            return false;
+        }
+        if (!emit1(JSOP_NULL)) {
+            //                [stack] ... HERITAGE HERITAGE NULL
+            return false;
+        }
+        if (!emit1(JSOP_STRICTNE)) {
+            //                [stack] ... HERITAGE NE
             return false;
         }
 
         // [THEN] funProto = heritage, objProto = heritage.prototype
         if (!ifThenElse.emitThenElse()) {
             return false;
         }
-        if (!emit1(JSOP_DUP)) {                                 // ... HERITAGE HERITAGE
-            return false;
-        }
-        if (!emitAtomOp(cx->names().prototype, JSOP_GETPROP)) { // ... HERITAGE PROTO
+        if (!emit1(JSOP_DUP)) {
+            //                [stack] ... HERITAGE HERITAGE
+            return false;
+        }
+        if (!emitAtomOp(cx->names().prototype, JSOP_GETPROP)) {
+            //                [stack] ... HERITAGE PROTO
             return false;
         }
 
         // [ELSE] funProto = %FunctionPrototype%, objProto = null
         if (!ifThenElse.emitElse()) {
             return false;
         }
-        if (!emit1(JSOP_POP)) {                                 // ...
-            return false;
-        }
-        if (!emit2(JSOP_BUILTINPROTO, JSProto_Function)) {      // ... PROTO
-            return false;
-        }
-        if (!emit1(JSOP_NULL)) {                                // ... PROTO NULL
+        if (!emit1(JSOP_POP)) {
+            //                [stack] ...
+            return false;
+        }
+        if (!emit2(JSOP_BUILTINPROTO, JSProto_Function)) {
+            //                [stack] ... PROTO
+            return false;
+        }
+        if (!emit1(JSOP_NULL)) {
+            //                [stack] ... PROTO NULL
             return false;
         }
 
         // [ENDIF]
         if (!ifThenElse.emitEnd()) {
             return false;
         }
 
-        if (!emit1(JSOP_OBJWITHPROTO)) {                        // ... HERITAGE HOMEOBJ
-            return false;
-        }
-        if (!emit1(JSOP_SWAP)) {                                // ... HOMEOBJ HERITAGE
+        if (!emit1(JSOP_OBJWITHPROTO)) {
+            //                [stack] ... HERITAGE HOMEOBJ
+            return false;
+        }
+        if (!emit1(JSOP_SWAP)) {
+            //                [stack] ... HOMEOBJ HERITAGE
             return false;
         }
     } else {
-        if (!emitNewInit()) {                                   // ... HOMEOBJ
+        if (!emitNewInit()) {
+            //                [stack] ... HOMEOBJ
             return false;
         }
     }
 
     // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
     // is not used, an implicit value of %FunctionPrototype% is implied.
 
     if (constructor) {
-        if (!emitFunction(constructor, !!heritageExpression)) { // ... HOMEOBJ CONSTRUCTOR
+        if (!emitFunction(constructor, !!heritageExpression)) {
+            //                [stack] ... HOMEOBJ CONSTRUCTOR
             return false;
         }
         if (constructor->funbox()->needsHomeObject()) {
-            if (!emit2(JSOP_INITHOMEOBJECT, 0)) {               // ... HOMEOBJ CONSTRUCTOR
+            if (!emit2(JSOP_INITHOMEOBJECT, 0)) {
+                //            [stack] ... HOMEOBJ CONSTRUCTOR
                 return false;
             }
         }
     } else {
         // In the case of default class constructors, emit the start and end
         // offsets in the source buffer as source notes so that when we
         // actually make the constructor during execution, we can give it the
         // correct toString output.
         ptrdiff_t classStart = ptrdiff_t(classNode->pn_pos.begin);
         ptrdiff_t classEnd = ptrdiff_t(classNode->pn_pos.end);
         if (!newSrcNote3(SRC_CLASS_SPAN, classStart, classEnd)) {
             return false;
         }
 
         JSAtom *name = names ? names->innerBinding()->as<NameNode>().atom() : cx->names().empty;
         if (heritageExpression) {
-            if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR)) {   // ... HOMEOBJ CONSTRUCTOR
+            if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR)) {
+                //            [stack] ... HOMEOBJ CONSTRUCTOR
                 return false;
             }
         } else {
-            if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) {     // ... HOMEOBJ CONSTRUCTOR
-                return false;
-            }
-        }
-    }
-
-    if (!emit1(JSOP_SWAP)) {                                    // ... CONSTRUCTOR HOMEOBJ
-        return false;
-    }
-
-    if (!emit1(JSOP_DUP2)) {                                        // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR HOMEOBJ
-        return false;
-    }
-    if (!emitAtomOp(cx->names().prototype, JSOP_INITLOCKEDPROP)) {  // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR
-        return false;
-    }
-    if (!emitAtomOp(cx->names().constructor, JSOP_INITHIDDENPROP)) {  // ... CONSTRUCTOR HOMEOBJ
+            if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) {
+                //            [stack] ... HOMEOBJ CONSTRUCTOR
+                return false;
+            }
+        }
+    }
+
+    if (!emit1(JSOP_SWAP)) {
+        //                    [stack] ... CONSTRUCTOR HOMEOBJ
+        return false;
+    }
+
+    if (!emit1(JSOP_DUP2)) {
+        //                    [stack] ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR HOMEOBJ
+        return false;
+    }
+    if (!emitAtomOp(cx->names().prototype, JSOP_INITLOCKEDPROP)) {
+        //                    [stack] ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR
+        return false;
+    }
+    if (!emitAtomOp(cx->names().constructor, JSOP_INITHIDDENPROP)) {
+        //                    [stack] ... CONSTRUCTOR HOMEOBJ
         return false;
     }
 
     RootedPlainObject obj(cx);
-    if (!emitPropertyList(classMembers, &obj, ClassBody)) {     // ... CONSTRUCTOR HOMEOBJ
-        return false;
-    }
-
-    if (!emit1(JSOP_POP)) {                                     // ... CONSTRUCTOR
+    if (!emitPropertyList(classMembers, &obj, ClassBody)) {
+        //                    [stack] ... CONSTRUCTOR HOMEOBJ
+        return false;
+    }
+
+    if (!emit1(JSOP_POP)) {
+        //                    [stack] ... CONSTRUCTOR
         return false;
     }
 
     if (names) {
         NameNode* innerName = names->innerBinding();
-        if (!emitLexicalInitialization(innerName)) {            // ... CONSTRUCTOR
+        if (!emitLexicalInitialization(innerName)) {
+            //                [stack] ... CONSTRUCTOR
             return false;
         }
 
         // Pop the inner scope.
         if (!emitterScope->leave(this)) {
             return false;
         }
         emitterScope.reset();
 
         if (NameNode* outerName = names->outerBinding()) {
-            if (!emitLexicalInitialization(outerName)) {        // ... CONSTRUCTOR
+            if (!emitLexicalInitialization(outerName)) {
+                //            [stack] ... CONSTRUCTOR
                 return false;
             }
             // Only class statements make outer bindings, and they do not leave
             // themselves on the stack.
-            if (!emit1(JSOP_POP)) {                             // ...
+            if (!emit1(JSOP_POP)) {
+                //            [stack] ...
                 return false;
             }
         }
     }
 
     // The CONSTRUCTOR is left on stack if this is an expression.
 
     MOZ_ALWAYS_TRUE(sc->setLocalStrictMode(savedStrictness));
@@ -8806,45 +9237,50 @@ BytecodeEmitter::emitTree(ParseNode* pn,
                           isSuper
                           ? PropOpEmitter::ObjKind::Super
                           : PropOpEmitter::ObjKind::Other);
         if (!poe.prepareForObj()) {
             return false;
         }
         if (isSuper) {
             UnaryNode* base = &prop->expression().as<UnaryNode>();
-            if (!emitGetThisForSuperBase(base)) {         // THIS
+            if (!emitGetThisForSuperBase(base)) {
+                //            [stack] THIS
                 return false;
             }
         } else {
-            if (!emitPropLHS(prop)) {                     // OBJ
-                return false;
-            }
-        }
-        if (!poe.emitGet(prop->key().atom())) {           // PROP
+            if (!emitPropLHS(prop)) {
+                //            [stack] OBJ
+                return false;
+            }
+        }
+        if (!poe.emitGet(prop->key().atom())) {
+            //                [stack] PROP
             return false;
         }
         break;
       }
 
       case ParseNodeKind::Elem: {
         PropertyByValue* elem = &pn->as<PropertyByValue>();
         bool isSuper = elem->isSuper();
         ElemOpEmitter eoe(this,
                           ElemOpEmitter::Kind::Get,
                           isSuper
                           ? ElemOpEmitter::ObjKind::Super
                           : ElemOpEmitter::ObjKind::Other);
-        if (!emitElemObjAndKey(elem, isSuper, eoe)) {     // [Super]
-            //                                            // THIS KEY
-            //                                            // [Other]
-            //                                            // OBJ KEY
-            return false;
-        }
-        if (!eoe.emitGet()) {                             // ELEM
+        if (!emitElemObjAndKey(elem, isSuper, eoe)) {
+            //                [stack] # if Super
+            //                [stack] THIS KEY
+            //                [stack] # otherwise
+            //                [stack] OBJ KEY
+            return false;
+        }
+        if (!eoe.emitGet()) {
+            //                [stack] ELEM
             return false;
         }
 
         break;
       }
 
       case ParseNodeKind::New:
       case ParseNodeKind::TaggedTemplate:
--- a/js/src/frontend/CForEmitter.cpp
+++ b/js/src/frontend/CForEmitter.cpp
@@ -70,34 +70,37 @@ CForEmitter::emitBody(Cond cond, const M
             }
         }
     }
 
     if (!bce_->newSrcNote(SRC_FOR, &noteIndex_)) {
         return false;
     }
     if (!bce_->emit1(JSOP_NOP)) {
+        //                    [stack]
         return false;
     }
 
     biasedTop_ = bce_->offset();
 
     if (cond_ == Cond::Present) {
         // Goto the loop condition, which branches back to iterate.
         if (!loopInfo_->emitEntryJump(bce_)) {
             return false;
         }
     }
 
     if (!loopInfo_->emitLoopHead(bce_, bodyPos)) {
+        //                    [stack]
         return false;
     }
 
     if (cond_ == Cond::Missing) {
         if (!loopInfo_->emitLoopEntry(bce_, bodyPos)) {
+            //                [stack]
             return false;
         }
     }
 
     tdzCache_.emplace(bce_);
 
 #ifdef DEBUG
     state_ = State::Body;
@@ -152,17 +155,20 @@ CForEmitter::emitUpdate(Update update, c
 bool
 CForEmitter::emitCond(const Maybe<uint32_t>& forPos,
                       const Maybe<uint32_t>& condPos,
                       const Maybe<uint32_t>& endPos)
 {
     MOZ_ASSERT(state_ == State::Update);
 
     if (update_ == Update::Present) {
-        if (!bce_->emit1(JSOP_POP)) {                 //
+        //                    [stack] UPDATE
+
+        if (!bce_->emit1(JSOP_POP)) {
+            //                [stack]
             return false;
         }
 
         // Restore the absolute line number for source note readers.
         if (endPos) {
             uint32_t lineNum =
                 bce_->parser->errorReporter().lineAt(*endPos);
             if (bce_->currentLine() != lineNum) {
@@ -178,16 +184,17 @@ CForEmitter::emitCond(const Maybe<uint32
     if (update_ == Update::Present) {
         tdzCache_.reset();
     }
 
     condOffset_ = bce_->offset();
 
     if (cond_ == Cond::Present) {
         if (!loopInfo_->emitLoopEntry(bce_, condPos)) {
+            //                [stack]
             return false;
         }
     } else if (update_ == Update::Missing) {
         // If there is no condition clause and no update clause, mark
         // the loop-ending "goto" with the location of the "for".
         // This ensures that the debugger will stop on each loop
         // iteration.
         if (forPos) {
@@ -216,17 +223,18 @@ CForEmitter::emitEnd()
     if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::For::UpdateOffset,
                                 loopInfo_->continueTargetOffset() - biasedTop_))
     {
         return false;
     }
 
     // If no loop condition, just emit a loop-closing jump.
     if (!loopInfo_->emitLoopEnd(bce_, cond_ == Cond::Present ? JSOP_IFNE : JSOP_GOTO)) {
-        return false;                                 //
+        //                    [stack]
+        return false;
     }
 
     // The third note offset helps us find the loop-closing jump.
     if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::For::BackJumpOffset,
                                 loopInfo_->loopEndOffset() - biasedTop_))
 
     {
         return false;
@@ -234,16 +242,17 @@ CForEmitter::emitEnd()
 
     if (!bce_->addTryNote(JSTRY_LOOP, bce_->stackDepth, loopInfo_->headOffset(),
                           loopInfo_->breakTargetOffset()))
     {
         return false;
     }
 
     if (!loopInfo_->patchBreaksAndContinues(bce_)) {
+        //                    [stack]
         return false;
     }
 
     loopInfo_.reset();
 
 #ifdef DEBUG
     state_ = State::End;
 #endif
--- a/js/src/frontend/CallOrNewEmitter.cpp
+++ b/js/src/frontend/CallOrNewEmitter.cpp
@@ -47,17 +47,18 @@ bool
 CallOrNewEmitter::emitNameCallee(JSAtom* name)
 {
     MOZ_ASSERT(state_ == State::Start);
 
     NameOpEmitter noe(bce_, name,
                       isCall()
                       ? NameOpEmitter::Kind::Call
                       : NameOpEmitter::Kind::Get);
-    if (!noe.emitGet()) {                             // CALLEE THIS
+    if (!noe.emitGet()) {
+        //                    [stack] CALLEE THIS
         return false;
     }
 
     state_ = State::NameCallee;
     return true;
 }
 
 MOZ_MUST_USE PropOpEmitter&
@@ -115,20 +116,22 @@ CallOrNewEmitter::prepareForFunctionCall
     return true;
 }
 
 bool
 CallOrNewEmitter::emitSuperCallee()
 {
     MOZ_ASSERT(state_ == State::Start);
 
-    if (!bce_->emit1(JSOP_SUPERFUN)) {                // CALLEE
+    if (!bce_->emit1(JSOP_SUPERFUN)) {
+        //                    [stack] CALLEE
         return false;
     }
-    if (!bce_->emit1(JSOP_IS_CONSTRUCTING)) {         // CALLEE THIS
+    if (!bce_->emit1(JSOP_IS_CONSTRUCTING)) {
+        //                    [stack] CALLEE THIS
         return false;
     }
 
     state_ = State::SuperCallee;
     return true;
 }
 
 bool
@@ -177,21 +180,23 @@ CallOrNewEmitter::emitThis()
         break;
       case State::OtherCallee:
         needsThis = true;
         break;
       default:;
     }
     if (needsThis) {
         if (isNew() || isSuperCall()) {
-            if (!bce_->emit1(JSOP_IS_CONSTRUCTING)) { // CALLEE THIS
+            if (!bce_->emit1(JSOP_IS_CONSTRUCTING)) {
+                //            [stack] CALLEE THIS
                 return false;
             }
         } else {
-            if (!bce_->emit1(JSOP_UNDEFINED)) {       // CALLEE THIS
+            if (!bce_->emit1(JSOP_UNDEFINED)) {
+                //            [stack] CALLEE THIS
                 return false;
             }
         }
     }
 
     state_ = State::This;
     return true;
 }
@@ -241,72 +246,82 @@ CallOrNewEmitter::emitSpreadArgumentsTes
         //     g(...args);
         //   }
         //
         // If the spread operand is a rest parameter and it's optimizable
         // array, skip spread operation and pass it directly to spread call
         // operation.  See the comment in OptimizeSpreadCall in
         // Interpreter.cpp for the optimizable conditons.
 
+        //                    [stack] CALLEE THIS ARG0
+
         ifNotOptimizable_.emplace(bce_);
-        //                                            // CALLEE THIS ARG0
-        if (!bce_->emit1(JSOP_OPTIMIZE_SPREADCALL)) { // CALLEE THIS ARG0 OPTIMIZED
+        if (!bce_->emit1(JSOP_OPTIMIZE_SPREADCALL)) {
+            //                [stack] CALLEE THIS ARG0 OPTIMIZED
             return false;
         }
-        if (!bce_->emit1(JSOP_NOT)) {                 // CALLEE THIS ARG0 !OPTIMIZED
+        if (!bce_->emit1(JSOP_NOT)) {
+            //                [stack] CALLEE THIS ARG0 !OPTIMIZED
             return false;
         }
-        if (!ifNotOptimizable_->emitThen()) {         // CALLEE THIS ARG0
+        if (!ifNotOptimizable_->emitThen()) {
+            //                [stack] CALLEE THIS ARG0
             return false;
         }
-        if (!bce_->emit1(JSOP_POP)) {                 // CALLEE THIS
+        if (!bce_->emit1(JSOP_POP)) {
+            //                [stack] CALLEE THIS
             return false;
         }
     }
 
     state_ = State::Arguments;
     return true;
 }
 
 bool
 CallOrNewEmitter::emitEnd(uint32_t argc, const Maybe<uint32_t>& beginPos)
 {
     MOZ_ASSERT(state_ == State::Arguments);
 
     if (isSingleSpreadRest()) {
-        if (!ifNotOptimizable_->emitEnd()) {          // CALLEE THIS ARR
+        if (!ifNotOptimizable_->emitEnd()) {
+            //                [stack] CALLEE THIS ARR
             return false;
         }
 
         ifNotOptimizable_.reset();
     }
     if (isNew() || isSuperCall()) {
         if (isSuperCall()) {
-            if (!bce_->emit1(JSOP_NEWTARGET)) {       // CALLEE THIS ARG.. NEW.TARGET
+            if (!bce_->emit1(JSOP_NEWTARGET)) {
+                //            [stack] CALLEE THIS ARG.. NEW.TARGET
                 return false;
             }
         } else {
             // Repush the callee as new.target
             uint32_t effectiveArgc = isSpread() ? 1 : argc;
             if (!bce_->emitDupAt(effectiveArgc + 1)) {
-                return false;                         // CALLEE THIS ARR CALLEE
+                //            [stack] CALLEE THIS ARR CALLEE
+                return false;
             }
         }
     }
     if (!isSpread()) {
-        if (!bce_->emitCall(op_, argc, beginPos)) {   // RVAL
+        if (!bce_->emitCall(op_, argc, beginPos)) {
+            //                [stack] RVAL
             return false;
         }
     } else {
         if (beginPos) {
             if (!bce_->updateSourceCoordNotes(*beginPos)) {
                 return false;
             }
         }
-        if (!bce_->emit1(op_)) {                      // RVAL
+        if (!bce_->emit1(op_)) {
+            //                [stack] RVAL
             return false;
         }
     }
     bce_->checkTypeSet(op_);
 
     if (isEval() && beginPos) {
         uint32_t lineNum = bce_->parser->errorReporter().lineAt(*beginPos);
         if (!bce_->emitUint32Operand(JSOP_LINENO, lineNum)) {
--- a/js/src/frontend/ElemOpEmitter.cpp
+++ b/js/src/frontend/ElemOpEmitter.cpp
@@ -31,95 +31,103 @@ ElemOpEmitter::prepareForObj()
 }
 
 bool
 ElemOpEmitter::prepareForKey()
 {
     MOZ_ASSERT(state_ == State::Obj);
 
     if (!isSuper() && isIncDec()) {
-        if (!bce_->emit1(JSOP_CHECKOBJCOERCIBLE)) {   // OBJ
+        if (!bce_->emit1(JSOP_CHECKOBJCOERCIBLE)) {
+            //                [stack] OBJ
             return false;
         }
     }
     if (isCall()) {
-        if (!bce_->emit1(JSOP_DUP)) {                 // [Super]
-            //                                        // THIS THIS
-            //                                        // [Other]
-            //                                        // OBJ OBJ
+        if (!bce_->emit1(JSOP_DUP)) {
+            //                [stack] # if Super
+            //                [stack] THIS THIS
+            //                [stack] # otherwise
+            //                [stack] OBJ OBJ
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::Key;
 #endif
     return true;
 }
 
 bool
 ElemOpEmitter::emitGet()
 {
     MOZ_ASSERT(state_ == State::Key);
 
     if (isIncDec() || isCompoundAssignment()) {
-        if (!bce_->emit1(JSOP_TOID)) {                // [Super]
-            //                                        // THIS KEY
-            //                                        // [Other]
-            //                                        // OBJ KEY
+        if (!bce_->emit1(JSOP_TOID)) {
+            //                [stack] # if Super
+            //                [stack] THIS KEY
+            //                [stack] # otherwise
+            //                [stack] OBJ KEY
             return false;
         }
     }
     if (isSuper()) {
-        if (!bce_->emit1(JSOP_SUPERBASE)) {           // THIS? THIS KEY SUPERBASE
+        if (!bce_->emit1(JSOP_SUPERBASE)) {
+            //                [stack] THIS? THIS KEY SUPERBASE
             return false;
         }
     }
     if (isIncDec() || isCompoundAssignment()) {
         if (isSuper()) {
             // There's no such thing as JSOP_DUP3, so we have to be creative.
             // Note that pushing things again is no fewer JSOps.
-            if (!bce_->emitDupAt(2)) {                // THIS KEY SUPERBASE THIS
+            if (!bce_->emitDupAt(2)) {
+                //            [stack] THIS KEY SUPERBASE THIS
                 return false;
             }
-            if (!bce_->emitDupAt(2)) {                // THIS KEY SUPERBASE THIS KEY
+            if (!bce_->emitDupAt(2)) {
+                //            [stack] THIS KEY SUPERBASE THIS KEY
                 return false;
             }
-            if (!bce_->emitDupAt(2)) {                // THIS KEY SUPERBASE THIS KEY SUPERBASE
+            if (!bce_->emitDupAt(2)) {
+                //            [stack] THIS KEY SUPERBASE THIS KEY SUPERBASE
                 return false;
             }
         } else {
-            if (!bce_->emit1(JSOP_DUP2)) {            // OBJ KEY OBJ KEY
+            if (!bce_->emit1(JSOP_DUP2)) {
+                //            [stack] OBJ KEY OBJ KEY
                 return false;
             }
         }
     }
 
     JSOp op;
     if (isSuper()) {
         op = JSOP_GETELEM_SUPER;
     } else if (isCall()) {
         op = JSOP_CALLELEM;
     } else {
         op = JSOP_GETELEM;
     }
-    if (!bce_->emitElemOpBase(op)) {                  // [Get]
-        //                                            // ELEM
-        //                                            // [Call]
-        //                                            // THIS ELEM
-        //                                            // [Inc/Dec/Assignment,
-        //                                            //  Super]
-        //                                            // THIS KEY SUPERBASE ELEM
-        //                                            // [Inc/Dec/Assignment,
-        //                                            //  Other]
-        //                                            // OBJ KEY ELEM
+    if (!bce_->emitElemOpBase(op)) {
+        //                    [stack] # if Get
+        //                    [stack] ELEM
+        //                    [stack] # if Call
+        //                    [stack] THIS ELEM
+        //                    [stack] # if Inc/Dec/Assignment, with Super
+        //                    [stack] THIS KEY SUPERBASE ELEM
+        //                    [stack] # if Inc/Dec/Assignment, other
+        //                    [stack] OBJ KEY ELEM
         return false;
     }
     if (isCall()) {
-        if (!bce_->emit1(JSOP_SWAP)) {                // ELEM THIS
+        if (!bce_->emit1(JSOP_SWAP)) {
+            //                [stack] ELEM THIS
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::Get;
 #endif
     return true;
@@ -130,17 +138,18 @@ ElemOpEmitter::prepareForRhs()
 {
     MOZ_ASSERT(isSimpleAssignment() || isCompoundAssignment());
     MOZ_ASSERT_IF(isSimpleAssignment(), state_ == State::Key);
     MOZ_ASSERT_IF(isCompoundAssignment(), state_ == State::Get);
 
     if (isSimpleAssignment()) {
         // For CompoundAssignment, SUPERBASE is already emitted by emitGet.
         if (isSuper()) {
-            if (!bce_->emit1(JSOP_SUPERBASE)) {           // THIS KEY SUPERBASE
+            if (!bce_->emit1(JSOP_SUPERBASE)) {
+                //            [stack] THIS KEY SUPERBASE
                 return false;
             }
         }
     }
 
 #ifdef DEBUG
     state_ = State::Rhs;
 #endif
@@ -161,36 +170,41 @@ ElemOpEmitter::skipObjAndKeyAndRhs()
 
 bool
 ElemOpEmitter::emitDelete()
 {
     MOZ_ASSERT(state_ == State::Key);
     MOZ_ASSERT(isDelete());
 
     if (isSuper()) {
-        if (!bce_->emit1(JSOP_TOID)) {                // THIS KEY
+        if (!bce_->emit1(JSOP_TOID)) {
+            //                [stack] THIS KEY
             return false;
         }
-        if (!bce_->emit1(JSOP_SUPERBASE)) {           // THIS KEY SUPERBASE
+        if (!bce_->emit1(JSOP_SUPERBASE)) {
+            //                [stack] THIS KEY SUPERBASE
             return false;
         }
 
         // Unconditionally throw when attempting to delete a super-reference.
         if (!bce_->emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER)) {
-            return false;                             // THIS KEY SUPERBASE
+            //                [stack] THIS KEY SUPERBASE
+            return false;
         }
 
         // Another wrinkle: Balance the stack from the emitter's point of view.
         // Execution will not reach here, as the last bytecode threw.
-        if (!bce_->emitPopN(2)) {                     // THIS
+        if (!bce_->emitPopN(2)) {
+            //                [stack] THIS
             return false;
         }
     } else {
         JSOp op = bce_->sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
-        if (!bce_->emitElemOpBase(op)){              // SUCCEEDED
+        if (!bce_->emitElemOpBase(op)) {
+            // SUCCEEDED
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::Delete;
 #endif
     return true;
@@ -200,88 +214,107 @@ bool
 ElemOpEmitter::emitAssignment()
 {
     MOZ_ASSERT(isSimpleAssignment() || isCompoundAssignment());
     MOZ_ASSERT(state_ == State::Rhs);
 
     JSOp setOp = isSuper()
                  ? bce_->sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER
                  : bce_->sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
-    if (!bce_->emitElemOpBase(setOp)) {               // ELEM
+    if (!bce_->emitElemOpBase(setOp)) {
+        //                    [stack] ELEM
         return false;
     }
 
 #ifdef DEBUG
     state_ = State::Assignment;
 #endif
     return true;
 }
 
 bool
 ElemOpEmitter::emitIncDec()
 {
     MOZ_ASSERT(state_ == State::Key);
     MOZ_ASSERT(isIncDec());
 
-    if (!emitGet()) {                                 // ... ELEM
+    if (!emitGet()) {
+        //                    [stack] ... ELEM
         return false;
     }
 
     MOZ_ASSERT(state_ == State::Get);
 
     JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB;
-    if (!bce_->emit1(JSOP_POS)) {                     // ... N
+    if (!bce_->emit1(JSOP_POS)) {
+        //                    [stack] ... N
         return false;
     }
     if (isPostIncDec()) {
-        if (!bce_->emit1(JSOP_DUP)) {                 // ... N? N
+        if (!bce_->emit1(JSOP_DUP)) {
+            //                [stack] ... N? N
             return false;
         }
     }
-    if (!bce_->emit1(JSOP_ONE)) {                     // ... N? N 1
+    if (!bce_->emit1(JSOP_ONE)) {
+        //                    [stack] ... N? N 1
         return false;
     }
-    if (!bce_->emit1(binOp)) {                        // ... N? N+1
+    if (!bce_->emit1(binOp)) {
+        //                    [stack] ... N? N+1
         return false;
     }
     if (isPostIncDec()) {
-        if (isSuper()) {                              // THIS KEY OBJ N N+1
-            if (!bce_->emit2(JSOP_PICK, 4)) {         // KEY SUPERBASE N N+1 THIS
+        if (isSuper()) {
+            //                [stack] THIS KEY OBJ N N+1
+
+            if (!bce_->emit2(JSOP_PICK, 4)) {
+                //            [stack] KEY SUPERBASE N N+1 THIS
                 return false;
             }
-            if (!bce_->emit2(JSOP_PICK, 4)) {         // SUPERBASE N N+1 THIS KEY
+            if (!bce_->emit2(JSOP_PICK, 4)) {
+                //            [stack] SUPERBASE N N+1 THIS KEY
                 return false;
             }
-            if (!bce_->emit2(JSOP_PICK, 4)) {         // N N+1 THIS KEY SUPERBASE
+            if (!bce_->emit2(JSOP_PICK, 4)) {
+                //            [stack] N N+1 THIS KEY SUPERBASE
                 return false;
             }
-            if (!bce_->emit2(JSOP_PICK, 3)) {         // N THIS KEY SUPERBASE N+1
+            if (!bce_->emit2(JSOP_PICK, 3)) {
+                //            [stack] N THIS KEY SUPERBASE N+1
                 return false;
             }
-        } else {                                      // OBJ KEY N N+1
-            if (!bce_->emit2(JSOP_PICK, 3)) {         // KEY N N+1 OBJ
+        } else {
+            //                [stack] OBJ KEY N N+1
+
+            if (!bce_->emit2(JSOP_PICK, 3)) {
+                //            [stack] KEY N N+1 OBJ
                 return false;
             }
-            if (!bce_->emit2(JSOP_PICK, 3)) {         // N N+1 OBJ KEY
+            if (!bce_->emit2(JSOP_PICK, 3)) {
+                //            [stack] N N+1 OBJ KEY
                 return false;
             }
-            if (!bce_->emit2(JSOP_PICK, 2)) {         // N OBJ KEY N+1
+            if (!bce_->emit2(JSOP_PICK, 2)) {
+                //            [stack] N OBJ KEY N+1
                 return false;
             }
         }
     }
 
     JSOp setOp = isSuper()
                  ? (bce_->sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
                  : (bce_->sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
-    if (!bce_->emitElemOpBase(setOp)) {               // N? N+1
+    if (!bce_->emitElemOpBase(setOp)) {
+        //                    [stack] N? N+1
         return false;
     }
     if (isPostIncDec()) {
-        if (!bce_->emit1(JSOP_POP)) {                 // N
+        if (!bce_->emit1(JSOP_POP)) {
+            //                [stack] N
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::IncDec;
 #endif
     return true;
--- a/js/src/frontend/ExpressionStatementEmitter.cpp
+++ b/js/src/frontend/ExpressionStatementEmitter.cpp
@@ -39,18 +39,24 @@ ExpressionStatementEmitter::prepareForEx
 }
 
 bool
 ExpressionStatementEmitter::emitEnd()
 {
     MOZ_ASSERT(state_ == State::Expr);
     MOZ_ASSERT(bce_->stackDepth == depth_ + 1);
 
+    //                        [stack] VAL
+
     JSOp op = valueUsage_ == ValueUsage::WantValue ? JSOP_SETRVAL : JSOP_POP;
     if (!bce_->emit1(op)) {
+        //                    [stack] # if WantValue
+        //                    [stack] VAL
+        //                    [stack] # otherwise
+        //                    [stack]
         return false;
     }
 
 #ifdef DEBUG
     state_ = State::End;
 #endif
     return true;
 }
--- a/js/src/frontend/ForInEmitter.cpp
+++ b/js/src/frontend/ForInEmitter.cpp
@@ -36,40 +36,44 @@ ForInEmitter::emitIterated()
 }
 
 bool
 ForInEmitter::emitInitialize()
 {
     MOZ_ASSERT(state_ == State::Iterated);
     tdzCacheForIteratedValue_.reset();
 
-    if (!bce_->emit1(JSOP_ITER)) {                    // ITER
+    if (!bce_->emit1(JSOP_ITER)) {
+        //                    [stack] ITER
         return false;
     }
 
     // For-in loops have both the iterator and the value on the stack. Push
     // undefined to balance the stack.
-    if (!bce_->emit1(JSOP_UNDEFINED)) {               // ITER ITERVAL
+    if (!bce_->emit1(JSOP_UNDEFINED)) {
+        //                    [stack] ITER ITERVAL
         return false;
     }
 
     loopInfo_.emplace(bce_, StatementKind::ForInLoop);
 
     // Annotate so IonMonkey can find the loop-closing jump.
     if (!bce_->newSrcNote(SRC_FOR_IN, &noteIndex_)) {
         return false;
     }
 
     // Jump down to the loop condition to minimize overhead (assuming at
     // least one iteration, just like the other loop forms).
-    if (!loopInfo_->emitEntryJump(bce_)) {            // ITER ITERVAL
+    if (!loopInfo_->emitEntryJump(bce_)) {
+        //                    [stack] ITER ITERVAL
         return false;
     }
 
-    if (!loopInfo_->emitLoopHead(bce_, Nothing())) {  // ITER ITERVAL
+    if (!loopInfo_->emitLoopHead(bce_, Nothing())) {
+        //                    [stack] ITER ITERVAL
         return false;
     }
 
     // If the loop had an escaping lexical declaration, reset the declaration's
     // bindings to uninitialized to implement TDZ semantics.
     if (headLexicalEmitterScope_) {
         // The environment chain only includes an environment for the
         // for-in loop head *if* a scope binding is captured, thereby
@@ -77,32 +81,34 @@ ForInEmitter::emitInitialize()
         // for the head, it must be the innermost one. If that scope has
         // closed-over bindings inducing an environment, recreate the
         // current environment.
         MOZ_ASSERT(headLexicalEmitterScope_ == bce_->innermostEmitterScope());
         MOZ_ASSERT(headLexicalEmitterScope_->scope(bce_)->kind() == ScopeKind::Lexical);
 
         if (headLexicalEmitterScope_->hasEnvironment()) {
             if (!bce_->emit1(JSOP_RECREATELEXICALENV)) {
-                return false;                         // ITER ITERVAL
+                //            [stack] ITER ITERVAL
+                return false;
             }
         }
 
         // For uncaptured bindings, put them back in TDZ.
         if (!headLexicalEmitterScope_->deadZoneFrameSlots(bce_)) {
             return false;
         }
     }
 
 #ifdef DEBUG
     loopDepth_ = bce_->stackDepth;
 #endif
     MOZ_ASSERT(loopDepth_ >= 2);
 
-    if (!bce_->emit1(JSOP_ITERNEXT)) {                // ITER ITERVAL
+    if (!bce_->emit1(JSOP_ITERNEXT)) {
+        //                    [stack] ITER ITERVAL
         return false;
     }
 
 #ifdef DEBUG
     state_ = State::Initialize;
 #endif
     return true;
 }
@@ -130,56 +136,63 @@ ForInEmitter::emitEnd(const Maybe<uint32
 
     if (forPos) {
         // Make sure this code is attributed to the "for".
         if (!bce_->updateSourceCoordNotes(*forPos)) {
             return false;
         }
     }
 
-    if (!loopInfo_->emitLoopEntry(bce_, Nothing())) { // ITER ITERVAL
+    if (!loopInfo_->emitLoopEntry(bce_, Nothing())) {
+        //                    [stack] ITER ITERVAL
         return false;
     }
-    if (!bce_->emit1(JSOP_POP)) {                     // ITER
+    if (!bce_->emit1(JSOP_POP)) {
+        //                    [stack] ITER
         return false;
     }
-    if (!bce_->emit1(JSOP_MOREITER)) {                // ITER NEXTITERVAL?
+    if (!bce_->emit1(JSOP_MOREITER)) {
+        //                    [stack] ITER NEXTITERVAL?
         return false;
     }
-    if (!bce_->emit1(JSOP_ISNOITER)) {                // ITER NEXTITERVAL? ISNOITER
+    if (!bce_->emit1(JSOP_ISNOITER)) {
+        //                    [stack] ITER NEXTITERVAL? ISNOITER
         return false;
     }
 
-    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ)) {   // ITER NEXTITERVAL
+    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ)) {
+        //                    [stack] ITER NEXTITERVAL
         return false;
     }
 
     // Set the srcnote offset so we can find the closing jump.
     if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::ForIn::BackJumpOffset,
                                 loopInfo_->loopEndOffsetFromEntryJump()))
     {
         return false;
     }
 
     if (!loopInfo_->patchBreaksAndContinues(bce_)) {
         return false;
     }
 
     // Pop the enumeration value.
-    if (!bce_->emit1(JSOP_POP)) {                     // ITER
+    if (!bce_->emit1(JSOP_POP)) {
+        //                    [stack] ITER
         return false;
     }
 
     if (!bce_->addTryNote(JSTRY_FOR_IN, bce_->stackDepth, loopInfo_->headOffset(),
                           bce_->offset()))
     {
         return false;
     }
 
-    if (!bce_->emit1(JSOP_ENDITER)) {                 //
+    if (!bce_->emit1(JSOP_ENDITER)) {
+        //                    [stack]
         return false;
     }
 
     loopInfo_.reset();
 
 #ifdef DEBUG
     state_ = State::End;
 #endif
--- a/js/src/frontend/ForOfEmitter.cpp
+++ b/js/src/frontend/ForOfEmitter.cpp
@@ -46,63 +46,69 @@ ForOfEmitter::emitIterated()
 bool
 ForOfEmitter::emitInitialize(const Maybe<uint32_t>& forPos)
 {
     MOZ_ASSERT(state_ == State::Iterated);
 
     tdzCacheForIteratedValue_.reset();
 
     if (iterKind_ == IteratorKind::Async) {
-        if (!bce_->emitAsyncIterator()) {             // NEXT ITER
+        if (!bce_->emitAsyncIterator()) {
+            //                [stack] NEXT ITER
             return false;
         }
     } else {
-        if (!bce_->emitIterator()) {                  // NEXT ITER
+        if (!bce_->emitIterator()) {
+            //                [stack] NEXT ITER
             return false;
         }
     }
 
     int32_t iterDepth = bce_->stackDepth;
 
     // For-of loops have the iterator next method, the iterator itself, and
     // the result.value on the stack.
     // Push an undefined to balance the stack.
-    if (!bce_->emit1(JSOP_UNDEFINED)) {               // NEXT ITER UNDEF
+    if (!bce_->emit1(JSOP_UNDEFINED)) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
     loopInfo_.emplace(bce_, iterDepth, allowSelfHostedIter_, iterKind_);
 
     // Annotate so IonMonkey can find the loop-closing jump.
     if (!bce_->newSrcNote(SRC_FOR_OF, &noteIndex_)) {
         return false;
     }
 
-    if (!loopInfo_->emitEntryJump(bce_)) {            // NEXT ITER UNDEF
+    if (!loopInfo_->emitEntryJump(bce_)) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
-    if (!loopInfo_->emitLoopHead(bce_, Nothing())) {  // NEXT ITER UNDEF
+    if (!loopInfo_->emitLoopHead(bce_, Nothing())) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
     // If the loop had an escaping lexical declaration, replace the current
     // environment with an dead zoned one to implement TDZ semantics.
     if (headLexicalEmitterScope_) {
         // The environment chain only includes an environment for the for-of
         // loop head *if* a scope binding is captured, thereby requiring
         // recreation each iteration. If a lexical scope exists for the head,
         // it must be the innermost one. If that scope has closed-over
         // bindings inducing an environment, recreate the current environment.
         MOZ_ASSERT(headLexicalEmitterScope_ == bce_->innermostEmitterScope());
         MOZ_ASSERT(headLexicalEmitterScope_->scope(bce_)->kind() == ScopeKind::Lexical);
 
         if (headLexicalEmitterScope_->hasEnvironment()) {
             if (!bce_->emit1(JSOP_RECREATELEXICALENV)) {
-                return false;                         // NEXT ITER UNDEF
+                //            [stack] NEXT ITER UNDEF
+                return false;
             }
         }
 
         // For uncaptured bindings, put them back in TDZ.
         if (!headLexicalEmitterScope_->deadZoneFrameSlots(bce_)) {
             return false;
         }
     }
@@ -113,64 +119,75 @@ ForOfEmitter::emitInitialize(const Maybe
 
     // Make sure this code is attributed to the "for".
     if (forPos) {
         if (!bce_->updateSourceCoordNotes(*forPos)) {
             return false;
         }
     }
 
-    if (!bce_->emit1(JSOP_POP)) {                     // NEXT ITER
+    if (!bce_->emit1(JSOP_POP)) {
+        //                    [stack] NEXT ITER
         return false;
     }
-    if (!bce_->emit1(JSOP_DUP2)) {                    // NEXT ITER NEXT ITER
+    if (!bce_->emit1(JSOP_DUP2)) {
+        //                    [stack] NEXT ITER NEXT ITER
         return false;
     }
 
     if (!bce_->emitIteratorNext(forPos, iterKind_, allowSelfHostedIter_)) {
-        return false;                                 // NEXT ITER RESULT
+        //                    [stack] NEXT ITER RESULT
+        return false;
     }
 
-    if (!bce_->emit1(JSOP_DUP)) {                     // NEXT ITER RESULT RESULT
+    if (!bce_->emit1(JSOP_DUP)) {
+        //                    [stack] NEXT ITER RESULT RESULT
         return false;
     }
     if (!bce_->emitAtomOp(bce_->cx->names().done, JSOP_GETPROP)) {
-        return false;                                 // NEXT ITER RESULT DONE
+        //                    [stack] NEXT ITER RESULT DONE
+        return false;
     }
 
     InternalIfEmitter ifDone(bce_);
 
-    if (!ifDone.emitThen()) {                         // NEXT ITER RESULT
+    if (!ifDone.emitThen()) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
 
     // Remove RESULT from the stack to release it.
-    if (!bce_->emit1(JSOP_POP)) {                     // NEXT ITER
+    if (!bce_->emit1(JSOP_POP)) {
+        //                    [stack] NEXT ITER
         return false;
     }
-    if (!bce_->emit1(JSOP_UNDEFINED)) {               // NEXT ITER UNDEF
+    if (!bce_->emit1(JSOP_UNDEFINED)) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
     // If the iteration is done, leave loop here, instead of the branch at
     // the end of the loop.
-    if (!loopInfo_->emitSpecialBreakForDone(bce_)) {  // NEXT ITER UNDEF
+    if (!loopInfo_->emitSpecialBreakForDone(bce_)) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
-    if (!ifDone.emitEnd()) {                          // NEXT ITER RESULT
+    if (!ifDone.emitEnd()) {
+        //                    [stack] NEXT ITER RESULT
         return false;
     }
 
     // Emit code to assign result.value to the iteration variable.
     //
     // Note that ES 13.7.5.13, step 5.c says getting result.value does not
     // call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
     if (!bce_->emitAtomOp(bce_->cx->names().value, JSOP_GETPROP)) {
-        return false;                                 // NEXT ITER VALUE
+        //                    [stack] NEXT ITER VALUE
+        return false;
     }
 
     if (!loopInfo_->emitBeginCodeNeedingIteratorClose(bce_)) {
         return false;
     }
 
 #ifdef DEBUG
     state_ = State::Initialize;
@@ -183,20 +200,22 @@ ForOfEmitter::emitBody()
 {
     MOZ_ASSERT(state_ == State::Initialize);
 
     MOZ_ASSERT(bce_->stackDepth == loopDepth_,
                "the stack must be balanced around the initializing "
                "operation");
 
     // Remove VALUE from the stack to release it.
-    if (!bce_->emit1(JSOP_POP)) {                     // NEXT ITER
+    if (!bce_->emit1(JSOP_POP)) {
+        //                    [stack] NEXT ITER
         return false;
     }
-    if (!bce_->emit1(JSOP_UNDEFINED)) {               // NEXT ITER UNDEF
+    if (!bce_->emit1(JSOP_UNDEFINED)) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
 #ifdef DEBUG
     state_ = State::Body;
 #endif
     return true;
 }
@@ -218,20 +237,22 @@ ForOfEmitter::emitEnd(const Maybe<uint32
     // We use the iterated value's position to attribute JSOP_LOOPENTRY,
     // which corresponds to the iteration protocol.
     // This is a bit misleading for 2nd and later iterations and might need
     // some fix (bug 1482003).
     if (!loopInfo_->emitLoopEntry(bce_, iteratedPos)) {
         return false;
     }
 
-    if (!bce_->emit1(JSOP_FALSE)) {                   // NEXT ITER UNDEF FALSE
+    if (!bce_->emit1(JSOP_FALSE)) {
+        //                    [stack] NEXT ITER UNDEF FALSE
         return false;
     }
-    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ)) {   // NEXT ITER UNDEF
+    if (!loopInfo_->emitLoopEnd(bce_, JSOP_IFEQ)) {
+        //                    [stack] NEXT ITER UNDEF
         return false;
     }
 
     MOZ_ASSERT(bce_->stackDepth == loopDepth_);
 
     // Let Ion know where the closing jump of this loop is.
     if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::ForOf::BackJumpOffset,
                                 loopInfo_->loopEndOffsetFromEntryJump()))
@@ -244,17 +265,18 @@ ForOfEmitter::emitEnd(const Maybe<uint32
     }
 
     if (!bce_->addTryNote(JSTRY_FOR_OF, bce_->stackDepth, loopInfo_->headOffset(),
                           loopInfo_->breakTargetOffset()))
     {
         return false;
     }
 
-    if (!bce_->emitPopN(3)) {                         //
+    if (!bce_->emitPopN(3)) {
+        //                    [stack]
         return false;
     }
 
     loopInfo_.reset();
 
 #ifdef DEBUG
     state_ = State::End;
 #endif
--- a/js/src/frontend/ForOfLoopControl.cpp
+++ b/js/src/frontend/ForOfLoopControl.cpp
@@ -35,82 +35,96 @@ ForOfLoopControl::emitBeginCodeNeedingIt
     numYieldsAtBeginCodeNeedingIterClose_ = bce->numYields;
 
     return true;
 }
 
 bool
 ForOfLoopControl::emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce)
 {
-    if (!tryCatch_->emitCatch()) {            // ITER ...
+    if (!tryCatch_->emitCatch()) {
+        //                    [stack] ITER ...
         return false;
     }
 
-    if (!bce->emit1(JSOP_EXCEPTION)) {        // ITER ... EXCEPTION
+    if (!bce->emit1(JSOP_EXCEPTION)) {
+        //                    [stack] ITER ... EXCEPTION
         return false;
     }
     unsigned slotFromTop = bce->stackDepth - iterDepth_;
-    if (!bce->emitDupAt(slotFromTop)) {       // ITER ... EXCEPTION ITER
+    if (!bce->emitDupAt(slotFromTop)) {
+        //                    [stack] ITER ... EXCEPTION ITER
         return false;
     }
 
     // If ITER is undefined, it means the exception is thrown by
     // IteratorClose for non-local jump, and we should't perform
     // IteratorClose again here.
-    if (!bce->emit1(JSOP_UNDEFINED)) {        // ITER ... EXCEPTION ITER UNDEF
+    if (!bce->emit1(JSOP_UNDEFINED)) {
+        //                    [stack] ITER ... EXCEPTION ITER UNDEF
         return false;
     }
-    if (!bce->emit1(JSOP_STRICTNE)) {         // ITER ... EXCEPTION NE
+    if (!bce->emit1(JSOP_STRICTNE)) {
+        //                    [stack] ITER ... EXCEPTION NE
         return false;
     }
 
     InternalIfEmitter ifIteratorIsNotClosed(bce);
-    if (!ifIteratorIsNotClosed.emitThen()) {  // ITER ... EXCEPTION
+    if (!ifIteratorIsNotClosed.emitThen()) {
+        //                    [stack] ITER ... EXCEPTION
         return false;
     }
 
     MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
-    if (!bce->emitDupAt(slotFromTop)) {       // ITER ... EXCEPTION ITER
+    if (!bce->emitDupAt(slotFromTop)) {
+        //                    [stack] ITER ... EXCEPTION ITER
         return false;
     }
     if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw)) {
         return false;                         // ITER ... EXCEPTION
     }
 
-    if (!ifIteratorIsNotClosed.emitEnd()) {   // ITER ... EXCEPTION
+    if (!ifIteratorIsNotClosed.emitEnd()) {
+        //                    [stack] ITER ... EXCEPTION
         return false;
     }
 
-    if (!bce->emit1(JSOP_THROW)) {            // ITER ...
+    if (!bce->emit1(JSOP_THROW)) {
+        //                    [stack] ITER ...
         return false;
     }
 
     // If any yields were emitted, then this for-of loop is inside a star
     // generator and must handle the case of Generator.return. Like in
     // yield*, it is handled with a finally block.
     uint32_t numYieldsEmitted = bce->numYields;
     if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
         if (!tryCatch_->emitFinally()) {
             return false;
         }
 
         InternalIfEmitter ifGeneratorClosing(bce);
-        if (!bce->emit1(JSOP_ISGENCLOSING)) { // ITER ... FTYPE FVALUE CLOSING
+        if (!bce->emit1(JSOP_ISGENCLOSING)) {
+            //                [stack] ITER ... FTYPE FVALUE CLOSING
             return false;
         }
-        if (!ifGeneratorClosing.emitThen()) { // ITER ... FTYPE FVALUE
+        if (!ifGeneratorClosing.emitThen()) {
+            //                [stack] ITER ... FTYPE FVALUE
             return false;
         }
-        if (!bce->emitDupAt(slotFromTop + 1)) { // ITER ... FTYPE FVALUE ITER
+        if (!bce->emitDupAt(slotFromTop + 1)) {
+            //                [stack] ITER ... FTYPE FVALUE ITER
             return false;
         }
         if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal)) {
-            return false;                     // ITER ... FTYPE FVALUE
+            //                [stack] ITER ... FTYPE FVALUE
+            return false;
         }
-        if (!ifGeneratorClosing.emitEnd()) {  // ITER ... FTYPE FVALUE
+        if (!ifGeneratorClosing.emitEnd()) {
+            //                [stack] ITER ... FTYPE FVALUE
             return false;
         }
     }
 
     if (!tryCatch_->emitEnd()) {
         return false;
     }
 
@@ -155,51 +169,60 @@ bool
 ForOfLoopControl::emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
                                                       EmitterScope& currentScope,
                                                       bool isTarget)
 {
     // Pop unnecessary value from the stack.  Effectively this means
     // leaving try-catch block.  However, the performing IteratorClose can
     // reach the depth for try-catch, and effectively re-enter the
     // try-catch block.
-    if (!bce->emit1(JSOP_POP)) {                      // NEXT ITER
+    if (!bce->emit1(JSOP_POP)) {
+        //                    [stack] NEXT ITER
         return false;
     }
 
     // Pop the iterator's next method.
-    if (!bce->emit1(JSOP_SWAP)) {                     // ITER NEXT
+    if (!bce->emit1(JSOP_SWAP)) {
+        //                    [stack] ITER NEXT
         return false;
     }
-    if (!bce->emit1(JSOP_POP)) {                      // ITER
+    if (!bce->emit1(JSOP_POP)) {
+        //                    [stack] ITER
         return false;
     }
 
     // Clear ITER slot on the stack to tell catch block to avoid performing
     // IteratorClose again.
-    if (!bce->emit1(JSOP_UNDEFINED)) {                // ITER UNDEF
+    if (!bce->emit1(JSOP_UNDEFINED)) {
+        //                    [stack] ITER UNDEF
         return false;
     }
-    if (!bce->emit1(JSOP_SWAP)) {                     // UNDEF ITER
+    if (!bce->emit1(JSOP_SWAP)) {
+        //                    [stack] UNDEF ITER
         return false;
     }
 
-    if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) { // UNDEF
+    if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) {
+        //                    [stack] UNDEF
         return false;
     }
 
     if (isTarget) {
         // At the level of the target block, there's bytecode after the
         // loop that will pop the next method, the iterator, and the
         // value, so push two undefineds to balance the stack.
-        if (!bce->emit1(JSOP_UNDEFINED)) {            // UNDEF UNDEF
+        if (!bce->emit1(JSOP_UNDEFINED)) {
+            //                [stack] UNDEF UNDEF
             return false;
         }
-        if (!bce->emit1(JSOP_UNDEFINED)) {            // UNDEF UNDEF UNDEF
+        if (!bce->emit1(JSOP_UNDEFINED)) {
+            //                [stack] UNDEF UNDEF UNDEF
             return false;
         }
     } else {
-        if (!bce->emit1(JSOP_POP)) {                  //
+        if (!bce->emit1(JSOP_POP)) {
+            //                [stack]
             return false;
         }
     }
 
     return true;
 }
--- a/js/src/frontend/NameOpEmitter.cpp
+++ b/js/src/frontend/NameOpEmitter.cpp
@@ -33,90 +33,101 @@ NameOpEmitter::NameOpEmitter(BytecodeEmi
 
 bool
 NameOpEmitter::emitGet()
 {
     MOZ_ASSERT(state_ == State::Start);
 
     switch (loc_.kind()) {
       case NameLocation::Kind::Dynamic:
-        if (!bce_->emitAtomOp(name_, JSOP_GETNAME)) { // VAL
+        if (!bce_->emitAtomOp(name_, JSOP_GETNAME)) {
+            //                [stack] VAL
             return false;
         }
         break;
       case NameLocation::Kind::Global:
-        if (!bce_->emitAtomOp(name_, JSOP_GETGNAME)) {// VAL
+        if (!bce_->emitAtomOp(name_, JSOP_GETGNAME)) {
+            //                [stack] VAL
             return false;
         }
         break;
       case NameLocation::Kind::Intrinsic:
         if (!bce_->emitAtomOp(name_, JSOP_GETINTRINSIC)) {
-            return false;                             // VAL
+            //                [stack] VAL
+            return false;
         }
         break;
       case NameLocation::Kind::NamedLambdaCallee:
-        if (!bce_->emit1(JSOP_CALLEE)) {              // VAL
+        if (!bce_->emit1(JSOP_CALLEE)) {
+            //                [stack] VAL
             return false;
         }
         break;
       case NameLocation::Kind::Import:
         if (!bce_->emitAtomOp(name_, JSOP_GETIMPORT)) {
-            return false;                             // VAL
+            //                [stack] VAL
+            return false;
         }
         break;
       case NameLocation::Kind::ArgumentSlot:
         if (!bce_->emitArgOp(JSOP_GETARG, loc_.argumentSlot())) {
-            return false;                             // VAL
+            //                [stack] VAL
+            return false;
         }
         break;
       case NameLocation::Kind::FrameSlot:
         if (loc_.isLexical()) {
             if (!bce_->emitTDZCheckIfNeeded(name_, loc_)) {
                 return false;
             }
         }
         if (!bce_->emitLocalOp(JSOP_GETLOCAL, loc_.frameSlot())) {
-            return false;                             // VAL
+            //                [stack] VAL
+            return false;
         }
         break;
       case NameLocation::Kind::EnvironmentCoordinate:
         if (loc_.isLexical()) {
             if (!bce_->emitTDZCheckIfNeeded(name_, loc_)) {
                 return false;
             }
         }
         if (!bce_->emitEnvCoordOp(JSOP_GETALIASEDVAR, loc_.environmentCoordinate())) {
-            return false;                             // VAL
+            //                [stack] VAL
+            return false;
         }
         break;
       case NameLocation::Kind::DynamicAnnexBVar:
         MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization");
     }
 
     if (isCall()) {
         switch (loc_.kind()) {
           case NameLocation::Kind::Dynamic: {
             JSOp thisOp = bce_->needsImplicitThis() ? JSOP_IMPLICITTHIS : JSOP_GIMPLICITTHIS;
-            if (!bce_->emitAtomOp(name_, thisOp)) {   // CALLEE THIS
+            if (!bce_->emitAtomOp(name_, thisOp)) {
+                //            [stack] CALLEE THIS
                 return false;
             }
             break;
           }
           case NameLocation::Kind::Global:
             if (!bce_->emitAtomOp(name_, JSOP_GIMPLICITTHIS)) {
-                return false;                         // CALLEE THIS
+                //            [stack] CALLEE THIS
+                return false;
             }
             break;
           case NameLocation::Kind::Intrinsic:
           case NameLocation::Kind::NamedLambdaCallee:
           case NameLocation::Kind::Import:
           case NameLocation::Kind::ArgumentSlot:
           case NameLocation::Kind::FrameSlot:
           case NameLocation::Kind::EnvironmentCoordinate:
-            if (!bce_->emit1(JSOP_UNDEFINED)) {       // CALLEE UNDEF
+            if (!bce_->emit1(JSOP_UNDEFINED)) {
+                //            [stack] CALLEE UNDEF
                 return false;
             }
             break;
           case NameLocation::Kind::DynamicAnnexBVar:
             MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization");
         }
     }
 
@@ -137,37 +148,40 @@ NameOpEmitter::prepareForRhs()
       case NameLocation::Kind::DynamicAnnexBVar:
         if (!bce_->makeAtomIndex(name_, &atomIndex_)) {
             return false;
         }
         if (loc_.kind() == NameLocation::Kind::DynamicAnnexBVar) {
             // Annex B vars always go on the nearest variable environment,
             // even if lexical environments in between contain same-named
             // bindings.
-            if (!bce_->emit1(JSOP_BINDVAR)) {         // ENV
+            if (!bce_->emit1(JSOP_BINDVAR)) {
+                //            [stack] ENV
                 return false;
             }
         } else {
             if (!bce_->emitIndexOp(JSOP_BINDNAME, atomIndex_)) {
-                return false;                         // ENV
+                //            [stack] ENV
+                return false;
             }
         }
         emittedBindOp_ = true;
         break;
       case NameLocation::Kind::Global:
         if (!bce_->makeAtomIndex(name_, &atomIndex_)) {
             return false;
         }
         if (loc_.isLexical() && isInitialize()) {
             // INITGLEXICAL always gets the global lexical scope. It doesn't
             // need a BINDGNAME.
             MOZ_ASSERT(bce_->innermostScope()->is<GlobalScope>());
         } else {
             if (!bce_->emitIndexOp(JSOP_BINDGNAME, atomIndex_)) {
-                return false;                         // ENV
+                //            [stack] ENV
+                return false;
             }
             emittedBindOp_ = true;
         }
         break;
       case NameLocation::Kind::Intrinsic:
         break;
       case NameLocation::Kind::NamedLambdaCallee:
         break;
@@ -197,24 +211,27 @@ NameOpEmitter::prepareForRhs()
         if (loc_.kind() == NameLocation::Kind::Dynamic) {
             // For dynamic accesses we need to emit GETBOUNDNAME instead of
             // GETNAME for correctness: looking up @@unscopables on the
             // environment chain (due to 'with' environments) must only happen
             // once.
             //
             // GETBOUNDNAME uses the environment already pushed on the stack
             // from the earlier BINDNAME.
-            if (!bce_->emit1(JSOP_DUP)) {             // ENV ENV
+            if (!bce_->emit1(JSOP_DUP)) {
+                //            [stack] ENV ENV
                 return false;
             }
             if (!bce_->emitAtomOp(name_, JSOP_GETBOUNDNAME)) {
-                return false;                         // ENV V
+                //            [stack] ENV V
+                return false;
             }
         } else {
-            if (!emitGet()) {                         // ENV? V
+            if (!emitGet()) {
+                //            [stack] ENV? V
                 return false;
             }
         }
     }
 
 #ifdef DEBUG
     state_ = State::Rhs;
 #endif
@@ -335,46 +352,55 @@ NameOpEmitter::emitAssignment()
 }
 
 bool
 NameOpEmitter::emitIncDec()
 {
     MOZ_ASSERT(state_ == State::Start);
 
     JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB;
-    if (!prepareForRhs()) {                           // ENV? V
+    if (!prepareForRhs()) {
+        //                    [stack] ENV? V
         return false;
     }
-    if (!bce_->emit1(JSOP_POS)) {                     // ENV? N
+    if (!bce_->emit1(JSOP_POS)) {
+        //                    [stack] ENV? N
         return false;
     }
     if (isPostIncDec()) {
-        if (!bce_->emit1(JSOP_DUP)) {                 // ENV? N? N
+        if (!bce_->emit1(JSOP_DUP)) {
+            //                [stack] ENV? N? N
             return false;
         }
     }
-    if (!bce_->emit1(JSOP_ONE)) {                     // ENV? N? N 1
+    if (!bce_->emit1(JSOP_ONE)) {
+        //                    [stack] ENV? N? N 1
         return false;
     }
-    if (!bce_->emit1(binOp)) {                        // ENV? N? N+1
+    if (!bce_->emit1(binOp)) {
+        //                    [stack] ENV? N? N+1
         return false;
     }
     if (isPostIncDec() && emittedBindOp()) {
-        if (!bce_->emit2(JSOP_PICK, 2)) {             // N? N+1 ENV?
+        if (!bce_->emit2(JSOP_PICK, 2)) {
+            //                [stack] N? N+1 ENV?
             return false;
         }
-        if (!bce_->emit1(JSOP_SWAP)) {                // N? ENV? N+1
+        if (!bce_->emit1(JSOP_SWAP)) {
+            //                [stack] N? ENV? N+1
             return false;
         }
     }
-    if (!emitAssignment()) {                          // N? N+1
+    if (!emitAssignment()) {
+        //                    [stack] N? N+1
         return false;
     }
     if (isPostIncDec()) {
-        if (!bce_->emit1(JSOP_POP)) {                 // N
+        if (!bce_->emit1(JSOP_POP)) {
+            //                [stack] N
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::IncDec;
 #endif
     return true;
--- a/js/src/frontend/PropOpEmitter.cpp
+++ b/js/src/frontend/PropOpEmitter.cpp
@@ -46,62 +46,66 @@ bool
 PropOpEmitter::emitGet(JSAtom* prop)
 {
     MOZ_ASSERT(state_ == State::Obj);
 
     if (!prepareAtomIndex(prop)) {
         return false;
     }
     if (isCall()) {
-        if (!bce_->emit1(JSOP_DUP)) {                 // [Super]
-            //                                        // THIS THIS
-            //                                        // [Other]
-            //                                        // OBJ OBJ
+        if (!bce_->emit1(JSOP_DUP)) {
+            //                [stack] # if Super
+            //                [stack] THIS THIS
+            //                [stack] # otherwise
+            //                [stack] OBJ OBJ
             return false;
         }
     }
     if (isSuper()) {
-        if (!bce_->emit1(JSOP_SUPERBASE)) {           // THIS? THIS SUPERBASE
+        if (!bce_->emit1(JSOP_SUPERBASE)) {
+            //                [stack] THIS? THIS SUPERBASE
             return false;
         }
     }
     if (isIncDec() || isCompoundAssignment()) {
         if (isSuper()) {
-            if (!bce_->emit1(JSOP_DUP2)) {            // THIS SUPERBASE THIS SUPERBASE
+            if (!bce_->emit1(JSOP_DUP2)) {
+                //            [stack] THIS SUPERBASE THIS SUPERBASE
                 return false;
             }
         } else {
-            if (!bce_->emit1(JSOP_DUP)) {             // OBJ OBJ
+            if (!bce_->emit1(JSOP_DUP)) {
+                //            [stack] OBJ OBJ
                 return false;
             }
         }
     }
 
     JSOp op;
     if (isSuper()) {
         op = JSOP_GETPROP_SUPER;
     } else if (isCall()) {
         op = JSOP_CALLPROP;
     } else {
         op = isLength_ ? JSOP_LENGTH : JSOP_GETPROP;
     }
-    if (!bce_->emitAtomOp(propAtomIndex_, op)) {      // [Get]
-        //                                            // PROP
-        //                                            // [Call]
-        //                                            // THIS PROP
-        //                                            // [Inc/Dec/Compound,
-        //                                            //  Super]
-        //                                            // THIS SUPERBASE PROP
-        //                                            // [Inc/Dec/Compound,
-        //                                            //  Other]
-        //                                            // OBJ PROP
+    if (!bce_->emitAtomOp(propAtomIndex_, op)) {
+        //                    [stack] # if Get
+        //                    [stack] PROP
+        //                    [stack] # if Call
+        //                    [stack] THIS PROP
+        //                    [stack] # if Inc/Dec/Compound, Super]
+        //                    [stack] THIS SUPERBASE PROP
+        //                    [stack] # if Inc/Dec/Compound, other
+        //                    [stack] OBJ PROP
         return false;
     }
     if (isCall()) {
-        if (!bce_->emit1(JSOP_SWAP)) {                // PROP THIS
+        if (!bce_->emit1(JSOP_SWAP)) {
+            //                [stack] PROP THIS
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::Get;
 #endif
     return true;
@@ -112,17 +116,18 @@ PropOpEmitter::prepareForRhs()
 {
     MOZ_ASSERT(isSimpleAssignment() || isCompoundAssignment());
     MOZ_ASSERT_IF(isSimpleAssignment(), state_ == State::Obj);
     MOZ_ASSERT_IF(isCompoundAssignment(), state_ == State::Get);
 
     if (isSimpleAssignment()) {
         // For CompoundAssignment, SUPERBASE is already emitted by emitGet.
         if (isSuper()) {
-            if (!bce_->emit1(JSOP_SUPERBASE)) {       // THIS SUPERBASE
+            if (!bce_->emit1(JSOP_SUPERBASE)) {
+                //            [stack] THIS SUPERBASE
                 return false;
             }
         }
     }
 
 #ifdef DEBUG
     state_ = State::Rhs;
 #endif
@@ -147,33 +152,37 @@ PropOpEmitter::emitDelete(JSAtom* prop)
     MOZ_ASSERT_IF(!isSuper(), state_ == State::Obj);
     MOZ_ASSERT_IF(isSuper(), state_ == State::Start);
     MOZ_ASSERT(isDelete());
 
     if (!prepareAtomIndex(prop)) {
         return false;
     }
     if (isSuper()) {
-        if (!bce_->emit1(JSOP_SUPERBASE)) {           // THIS SUPERBASE
+        if (!bce_->emit1(JSOP_SUPERBASE)) {
+            //                [stack] THIS SUPERBASE
             return false;
         }
 
         // Unconditionally throw when attempting to delete a super-reference.
         if (!bce_->emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER)) {
-            return false;                             // THIS SUPERBASE
+            //                [stack] THIS SUPERBASE
+            return false;
         }
 
         // Another wrinkle: Balance the stack from the emitter's point of view.
         // Execution will not reach here, as the last bytecode threw.
-        if (!bce_->emit1(JSOP_POP)) {                 // THIS
+        if (!bce_->emit1(JSOP_POP)) {
+            //                [stack] THIS
             return false;
         }
     } else {
         JSOp op = bce_->sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
-        if (!bce_->emitAtomOp(propAtomIndex_, op)) {  // SUCCEEDED
+        if (!bce_->emitAtomOp(propAtomIndex_, op)) {
+            //                [stack] SUCCEEDED
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::Delete;
 #endif
     return true;
@@ -189,17 +198,18 @@ PropOpEmitter::emitAssignment(JSAtom* pr
         if (!prepareAtomIndex(prop)) {
             return false;
         }
     }
 
     JSOp setOp = isSuper()
                  ? bce_->sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
                  : bce_->sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
-    if (!bce_->emitAtomOp(propAtomIndex_, setOp)) {   // VAL
+    if (!bce_->emitAtomOp(propAtomIndex_, setOp)) {
+        //                    [stack] VAL
         return false;
     }
 
 #ifdef DEBUG
     state_ = State::Assignment;
 #endif
     return true;
 }
@@ -213,62 +223,76 @@ PropOpEmitter::emitIncDec(JSAtom* prop)
     if (!emitGet(prop)) {
         return false;
     }
 
     MOZ_ASSERT(state_ == State::Get);
 
     JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB;
 
-    if (!bce_->emit1(JSOP_POS)) {                     // ... N
+    if (!bce_->emit1(JSOP_POS)) {
+        //                    [stack] ... N
         return false;
     }
     if (isPostIncDec()) {
-        if (!bce_->emit1(JSOP_DUP)) {                 // ... N N
+        if (!bce_->emit1(JSOP_DUP)) {
+            //                [stack] .. N N
             return false;
         }
     }
-    if (!bce_->emit1(JSOP_ONE)) {                     // ... N? N 1
+    if (!bce_->emit1(JSOP_ONE)) {
+        //                    [stack] ... N? N 1
         return false;
     }
-    if (!bce_->emit1(binOp)) {                        // ... N? N+1
+    if (!bce_->emit1(binOp)) {
+        //                    [stack] ... N? N+1
         return false;
     }
     if (isPostIncDec()) {
-        if (isSuper()) {                              // THIS OBJ N N+1
-            if (!bce_->emit2(JSOP_PICK, 3)) {         // OBJ N N+1 THIS
+        if (isSuper()) {
+            //                [stack] THIS OBJ N N+1
+            if (!bce_->emit2(JSOP_PICK, 3)) {
+                //            [stack] OBJ N N+1 THIS
                 return false;
             }
-            if (!bce_->emit1(JSOP_SWAP)) {            // OBJ N THIS N+1
+            if (!bce_->emit1(JSOP_SWAP)) {
+                //            [stack] OBJ N THIS N+1
                 return false;
             }
-            if (!bce_->emit2(JSOP_PICK, 3)) {         // N THIS N+1 OBJ
+            if (!bce_->emit2(JSOP_PICK, 3)) {
+                //            [stack] N THIS N+1 OBJ
                 return false;
             }
-            if (!bce_->emit1(JSOP_SWAP)) {            // N THIS OBJ N+1
+            if (!bce_->emit1(JSOP_SWAP)) {
+                //            [stack] N THIS OBJ N+1
                 return false;
             }
-        } else {                                      // OBJ N N+1
-            if (!bce_->emit2(JSOP_PICK, 2)) {         // N N+1 OBJ
+        } else {
+            //                [stack] OBJ N N+1
+            if (!bce_->emit2(JSOP_PICK, 2)) {
+                //            [stack] N N+1 OBJ
                 return false;
             }
-            if (!bce_->emit1(JSOP_SWAP)) {            // N OBJ N+1
+            if (!bce_->emit1(JSOP_SWAP)) {
+                //            [stack] N OBJ N+1
                 return false;
             }
         }
     }
 
     JSOp setOp = isSuper()
                  ? bce_->sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
                  : bce_->sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
-    if (!bce_->emitAtomOp(propAtomIndex_, setOp)) {   // N? N+1
+    if (!bce_->emitAtomOp(propAtomIndex_, setOp)) {
+        //                    [stack] N? N+1
         return false;
     }
     if (isPostIncDec()) {
-        if (!bce_->emit1(JSOP_POP)) {                 // N
+        if (!bce_->emit1(JSOP_POP)) {
+            //                [stack] N
             return false;
         }
     }
 
 #ifdef DEBUG
     state_ = State::IncDec;
 #endif
     return true;