Bug 1499544 - [Part 2] Use ByteCodeLocation and ByteCodeIterator r=djvj
authorMatthew Gaudet <mgaudet@mozilla.com>
Tue, 16 Oct 2018 15:44:37 -0400
changeset 491280 1417a92298ff87a3b0f328566ed20b06cbcb1d65
parent 491279 908a0972c1b529a90e9bee5055f83c86b06a0bb2
child 491281 e8b53fa4ae7e8047eabaab6b2da701c209a74cba
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersdjvj
bugs1499544
milestone65.0a1
Bug 1499544 - [Part 2] Use ByteCodeLocation and ByteCodeIterator r=djvj The interface is expanded and refined in this patch, showing a more complicated set of requirements and the answers to those requirements Differential Revision: https://phabricator.services.mozilla.com/D8920
js/src/vm/BytecodeLocation.h
js/src/vm/JSScript.cpp
--- a/js/src/vm/BytecodeLocation.h
+++ b/js/src/vm/BytecodeLocation.h
@@ -118,21 +118,59 @@ class BytecodeLocation
         MOZ_ASSERT(isInBounds());
         return getOp() == op;
     }
 
     bool isJumpTarget() const {
         return BytecodeIsJumpTarget(getOp());
     }
 
+    bool isJump() const {
+        return IsJumpOpcode(getOp());
+    }
+
+    bool fallsThrough() const {
+        return BytecodeFallsThrough(getOp());
+    }
+
     // Accessors:
     JSOp getOp() const {
         return JSOp(*rawBytecode_);
     }
 
+    BytecodeLocation getJumpTarget() const {
+        // The default target of a JSOP_TABLESWITCH also follows this format.
+        MOZ_ASSERT(isJump() || is(JSOP_TABLESWITCH));
+        return BytecodeLocation(*this, rawBytecode_ + GET_JUMP_OFFSET(rawBytecode_));
+    }
+
+    // Return the 'low' parameter to the tableswitch opcode
+    int32_t getTableSwitchLow() const {
+        MOZ_ASSERT(is(JSOP_TABLESWITCH));
+        return GET_JUMP_OFFSET(rawBytecode_ + JUMP_OFFSET_LEN);
+    }
+
+    // Return the 'high' parameter to the tableswitch opcode
+    int32_t getTableSwitchHigh() const {
+        MOZ_ASSERT(is(JSOP_TABLESWITCH));
+        return GET_JUMP_OFFSET(rawBytecode_ + (2 * JUMP_OFFSET_LEN));
+    }
+
+    // Return the BytecodeLocation referred to by index number in the table
+    // of the table switch.
+    //
+    // Returns (effectively) |this| on a gap in the table.
+    BytecodeLocation getTableSwitchCaseByIndex(size_t index) const {
+        MOZ_ASSERT(is(JSOP_TABLESWITCH));
+        RawBytecode offsetLoc = rawBytecode_ +
+                                (3 *  JUMP_OFFSET_LEN) + // Skip over low and high
+                                (index * JUMP_OFFSET_LEN); // Select table entry
+        return BytecodeLocation(*this, rawBytecode_ + GET_JUMP_OFFSET(offsetLoc));
+    }
+
 #ifdef DEBUG
     // To ease writing assertions
     bool isValid() const {
         return isValid(debugOnlyScript_);
     }
 
     bool isInBounds() const {
         return isInBounds(debugOnlyScript_);
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -3564,60 +3564,59 @@ JSScript::fullyInitFromEmitter(JSContext
 
     return true;
 }
 
 #ifdef DEBUG
 void
 JSScript::assertValidJumpTargets() const
 {
-    jsbytecode* end = codeEnd();
-    jsbytecode* mainEntry = main();
-    for (jsbytecode* pc = code(); pc != end; pc = GetNextPc(pc)) {
+    BytecodeLocation mainLoc = mainLocation();
+    BytecodeLocation endLoc = endLocation();
+    AllBytecodesIterable iter(this);
+    for (BytecodeLocation loc : iter) {
         // Check jump instructions' target.
-        if (IsJumpOpcode(JSOp(*pc))) {
-            jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
-            MOZ_ASSERT(mainEntry <= target && target < end);
-            MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*target)));
+        if (loc.isJump()){
+            BytecodeLocation target = loc.getJumpTarget();
+            MOZ_ASSERT(mainLoc <= target && target < endLoc);
+            MOZ_ASSERT(target.isJumpTarget());
 
             // Check fallthrough of conditional jump instructions.
-            if (BytecodeFallsThrough(JSOp(*pc))) {
-                jsbytecode* fallthrough = GetNextPc(pc);
-                MOZ_ASSERT(mainEntry <= fallthrough && fallthrough < end);
-                MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*fallthrough)));
+            if (loc.fallsThrough()) {
+                BytecodeLocation fallthrough = loc.next();
+                MOZ_ASSERT(mainLoc <= fallthrough && fallthrough < endLoc);
+                MOZ_ASSERT(fallthrough.isJumpTarget());
             }
         }
 
         // Check table switch case labels.
-        if (JSOp(*pc) == JSOP_TABLESWITCH) {
-            jsbytecode* pc2 = pc;
-            int32_t len = GET_JUMP_OFFSET(pc2);
+        if (loc.is(JSOP_TABLESWITCH)) {
+            BytecodeLocation target = loc.getJumpTarget();
 
             // Default target.
-            MOZ_ASSERT(mainEntry <= pc + len && pc + len < end);
-            MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*(pc + len))));
-
-            pc2 += JUMP_OFFSET_LEN;
-            int32_t low = GET_JUMP_OFFSET(pc2);
-            pc2 += JUMP_OFFSET_LEN;
-            int32_t high = GET_JUMP_OFFSET(pc2);
+            MOZ_ASSERT(mainLoc <= target && target < endLoc);
+            MOZ_ASSERT(target.isJumpTarget());
+
+            int32_t low = loc.getTableSwitchLow();
+            int32_t high = loc.getTableSwitchHigh();
 
             for (int i = 0; i < high - low + 1; i++) {
-                pc2 += JUMP_OFFSET_LEN;
-                int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
-                // Case (i + low)
-                MOZ_ASSERT_IF(off, mainEntry <= pc + off && pc + off < end);
-                MOZ_ASSERT_IF(off, BytecodeIsJumpTarget(JSOp(*(pc + off))));
+                BytecodeLocation switchCase = loc.getTableSwitchCaseByIndex(i);
+                MOZ_ASSERT_IF(switchCase != loc, mainLoc <= switchCase && switchCase < endLoc);
+                MOZ_ASSERT_IF(switchCase != loc, switchCase.isJumpTarget());
             }
         }
     }
 
     // Check catch/finally blocks as jump targets.
     if (hasTrynotes()) {
         for (const JSTryNote& tn : trynotes()) {
+            jsbytecode* end = codeEnd();
+            jsbytecode* mainEntry = main();
+
             jsbytecode* tryStart = offsetToPC(tn.start);
             jsbytecode* tryPc = tryStart - 1;
             if (tn.kind != JSTRY_CATCH && tn.kind != JSTRY_FINALLY) {
                 continue;
             }
 
             MOZ_ASSERT(JSOp(*tryPc) == JSOP_TRY);
             jsbytecode* tryTarget = tryStart + tn.length;