Bug 1456039 - Part 2: Add comment for TryEmitter. r=Yoric
authorTooru Fujisawa <arai_a@mac.com>
Wed, 02 May 2018 10:35:35 +0900
changeset 472608 ff765f9cd347ba2eabde3a54d74d35ffec495fc6
parent 472607 d5df9c66d35f47256fc0a13ea77650238f44637b
child 472609 e7b20e0b67273e3dda4db315271530a3b043e2b2
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs1456039
milestone61.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 1456039 - Part 2: Add comment for TryEmitter. r=Yoric
js/src/frontend/BytecodeEmitter.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1498,28 +1498,107 @@ BytecodeEmitter::TDZCheckCache::noteTDZC
     } else {
         if (!cache_->add(p, name, check))
             return false;
     }
 
     return true;
 }
 
+// Class for emitting bytecode for blocks like try-catch-finally.
+//
+// Usage: (check for the return value is omitted for simplicity)
+//
+//   `try { try_block } catch (ex) { catch_block }`
+//     TryEmitter tryCatch(this, TryEmitter::TryCatch);
+//     tryCatch.emitTry();
+//     emit(try_block);
+//     tryCatch.emitCatch();
+//     emit(ex and catch_block); // use JSOP_EXCEPTION to get exception
+//     tryCatch.emitEnd();
+//
+//   `try { try_block } finally { finally_block }`
+//     TryEmitter tryCatch(this, TryEmitter::TryFinally);
+//     tryCatch.emitTry();
+//     emit(try_block);
+//     // finally_pos: The "{" character's position in the source code text.
+//     tryCatch.emitFinally(Some(finally_pos));
+//     emit(finally_block);
+//     tryCatch.emitEnd();
+//
+//   `try { try_block } catch (ex) {catch_block} finally { finally_block }`
+//     TryEmitter tryCatch(this, TryEmitter::TryCatchFinally);
+//     tryCatch.emitTry();
+//     emit(try_block);
+//     tryCatch.emitCatch();
+//     emit(ex and catch_block);
+//     tryCatch.emitFinally(Some(finally_pos));
+//     emit(finally_block);
+//     tryCatch.emitEnd();
+//
 class MOZ_STACK_CLASS TryEmitter
 {
   public:
     enum Kind {
         TryCatch,
         TryCatchFinally,
         TryFinally
     };
+
+    // Whether the catch and finally blocks handle the frame's return value.
+    // If UseRetVal is specified, the bytecode marked with "*" are emitted
+    // to clear return value with `undefined` before the catch block and the
+    // finally block, and also to save/restore the return value before/after
+    // the finally block.
+    //
+    //     JSOP_TRY
+    //
+    //     try_body...
+    //
+    //     JSOP_GOSUB finally
+    //     JSOP_JUMPTARGET
+    //     JSOP_GOTO end:
+    //
+    //   catch:
+    //     JSOP_JUMPTARGET
+    //   * JSOP_UNDEFINED
+    //   * JSOP_SETRVAL
+    //
+    //     catch_body...
+    //
+    //     JSOP_GOSUB finally
+    //     JSOP_JUMPTARGET
+    //     JSOP_GOTO end
+    //
+    //   finally:
+    //     JSOP_JUMPTARGET
+    //   * JSOP_GETRVAL
+    //   * JSOP_UNDEFINED
+    //   * JSOP_SETRVAL
+    //
+    //     finally_body...
+    //
+    //   * JSOP_SETRVAL
+    //     JSOP_NOP
+    //
+    //   end:
+    //     JSOP_JUMPTARGET
+    //
+    // For syntactic try-catch-finally, UseRetVal should be used.
+    // For non-syntactic try-catch-finally, DontUseRetVal should be used.
     enum ShouldUseRetVal {
         UseRetVal,
         DontUseRetVal
     };
+
+    // Whether this class should use TryFinallyControl.
+    // See the comment for `controlInfo_`.
+    //
+    // For syntactic try-catch-finally, UseControl should be used.
+    // For non-syntactic try-catch-finally, DontUseControl should be used.
     enum ShouldUseControl {
         UseControl,
         DontUseControl,
     };
 
   private:
     BytecodeEmitter* bce_;
     Kind kind_;
@@ -1541,31 +1620,59 @@ class MOZ_STACK_CLASS TryEmitter
     //     catch-block
     //
     // Additionally, a finally block may be emitted when ShouldUseControl is
     // DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
     // because GOSUBs are not emitted. This internal use shares the
     // requirements as above.
     Maybe<TryFinallyControl> controlInfo_;
 
+    // The stack depth before emitting JSOP_TRY.
     int depth_;
+
+    // The source note index for SRC_TRY.
     unsigned noteIndex_;
+
+    // The offset after JSOP_TRY.
     ptrdiff_t tryStart_;
+
+    // JSOP_JUMPTARGET after the entire try-catch-finally block.
     JumpList catchAndFinallyJump_;
+
+    // The offset of JSOP_GOTO at the end of the try block.
     JumpTarget tryEnd_;
+
+    // The offset of JSOP_JUMPTARGET at the beginning of the finally block.
     JumpTarget finallyStart_;
 
+    // The state of this emitter.
+    //
+    // +-------+ emitTry +-----+   emitCatch +-------+      emitEnd  +-----+
+    // | Start |-------->| Try |-+---------->| Catch |-+->+--------->| End |
+    // +-------+         +-----+ |           +-------+ |  ^          +-----+
+    //                           |                     |  |
+    //                           |  +------------------+  +----+
+    //                           |  |                          |
+    //                           |  v emitFinally +---------+  |
+    //                           +->+------------>| Finally |--+
+    //                                            +---------+
     enum State {
+        // The initial state.
         Start,
+
+        // After calling emitTry.
         Try,
-        TryEnd,
+
+        // After calling emitCatch.
         Catch,
-        CatchEnd,
+
+        // After calling emitFinally.
         Finally,
-        FinallyEnd,
+
+        // After calling emitEnd.
         End
     };
     State state_;
 
     bool hasCatch() const {
         return kind_ == TryCatch || kind_ == TryCatchFinally;
     }
     bool hasFinally() const {
@@ -1583,16 +1690,18 @@ class MOZ_STACK_CLASS TryEmitter
         tryStart_(0),
         state_(Start)
     {
         if (controlKind == UseControl)
             controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
         finallyStart_.offset = 0;
     }
 
+    // Emits JSOP_GOTO to the end of try-catch-finally.
+    // Used in `yield*`.
     bool emitJumpOverCatchAndFinally() {
         if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
             return false;
         return true;
     }
 
     bool emitTry() {
         MOZ_ASSERT(state_ == Start);
@@ -1682,16 +1791,20 @@ class MOZ_STACK_CLASS TryEmitter
             if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
                 return false;
         }
 
         return true;
     }
 
   public:
+    // If `finallyPos` is specified, it's an offset of the finally block's
+    // "{" character in the source code text, to improve line:column number in
+    // the error reporting.
+    // For non-syntactic try-catch-finally, `finallyPos` can be omitted.
     bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
         // If we are using controlInfo_ (i.e., emitting a syntactic try
         // blocks), we must have specified up front if there will be a finally
         // close. For internal try blocks, like those emitted for yield* and
         // IteratorClose inside for-of loops, we can emitFinally even without
         // specifying up front, since the internal try blocks emit no GOSUBs.
         if (!controlInfo_) {
             if (kind_ == TryCatch)