Bug 1261826 part 7 - Add a no-op bytecode to filter out branches results from the decompiler. r=jorendorff
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Tue, 17 May 2016 17:15:52 +0000
changeset 297764 2b1daf5127d47ea6101188d113c2808531e13c38
parent 297763 0feaa758b66939461b4b70fb27c991f3297200d2
child 297765 ae61f4fcb292626e3b4b35512de4380612d2c6cf
push id30267
push userryanvm@gmail.com
push dateWed, 18 May 2016 16:13:07 +0000
treeherdermozilla-central@c4449eab07d3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1261826
milestone49.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 1261826 part 7 - Add a no-op bytecode to filter out branches results from the decompiler. r=jorendorff
js/src/frontend/BytecodeEmitter.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/IonBuilder.cpp
js/src/jsopcode.cpp
js/src/vm/Interpreter.cpp
js/src/vm/Opcodes.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4217,16 +4217,18 @@ BytecodeEmitter::emitDestructuringOpsArr
             JumpList beq;
             if (!emitJump(JSOP_IFEQ, &beq))
                 return false;
 
             if (!emit1(JSOP_POP))                                 // ... OBJ? ITER
                 return false;
             if (!emit1(JSOP_UNDEFINED))                           // ... OBJ? ITER UNDEFINED
                 return false;
+            if (!emit1(JSOP_NOP_DESTRUCTURING))
+                return false;
 
             /* Jump around else, fixup the branch, emit else, fixup jump. */
             JumpList jmp;
             if (!emitJump(JSOP_GOTO, &jmp))
                 return false;
             if (!emitJumpTargetAndPatch(beq))
                 return false;
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1026,16 +1026,22 @@ OPCODE_LIST(EMIT_OP)
 
 bool
 BaselineCompiler::emit_JSOP_NOP()
 {
     return true;
 }
 
 bool
+BaselineCompiler::emit_JSOP_NOP_DESTRUCTURING()
+{
+    return true;
+}
+
+bool
 BaselineCompiler::emit_JSOP_LABEL()
 {
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_POP()
 {
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -26,16 +26,17 @@
 # error "Unknown architecture!"
 #endif
 
 namespace js {
 namespace jit {
 
 #define OPCODE_LIST(_)         \
     _(JSOP_NOP)                \
+    _(JSOP_NOP_DESTRUCTURING)  \
     _(JSOP_LABEL)              \
     _(JSOP_POP)                \
     _(JSOP_POPN)               \
     _(JSOP_DUPAT)              \
     _(JSOP_ENTERWITH)          \
     _(JSOP_LEAVEWITH)          \
     _(JSOP_DUP)                \
     _(JSOP_DUP2)               \
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1637,16 +1637,17 @@ IonBuilder::snoopControlFlow(JSOp op)
 
 bool
 IonBuilder::inspectOpcode(JSOp op)
 {
     MOZ_ASSERT(analysis_.maybeInfo(pc), "Compiling unreachable op");
 
     switch (op) {
       case JSOP_NOP:
+      case JSOP_NOP_DESTRUCTURING:
       case JSOP_LINENO:
       case JSOP_LOOPENTRY:
         return true;
 
       case JSOP_LABEL:
         return jsop_label();
 
       case JSOP_UNDEFINED:
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -253,34 +253,47 @@ class BytecodeParser
             if (stackDepth) {
                 for (uint32_t n = 0; n < stackDepth; n++)
                     offsetStack[n] = stack[n];
             }
             return true;
         }
 
         // When control-flow merges, intersect the stacks, marking slots that
-        // are defined by different offsets with the UINT32_MAX sentinel.
+        // are defined by different offsets with the UnknownOffset sentinel.
         // This is sufficient for forward control-flow.  It doesn't grok loops
         // -- for that you would have to iterate to a fixed point -- but there
         // shouldn't be operands on the stack at a loop back-edge anyway.
         void mergeOffsetStack(const uint32_t* stack, uint32_t depth) {
             MOZ_ASSERT(depth == stackDepth);
-            for (uint32_t n = 0; n < stackDepth; n++)
+            for (uint32_t n = 0; n < stackDepth; n++) {
+                if (stack[n] == SpecialOffsets::IgnoreOffset)
+                    continue;
+                if (offsetStack[n] == SpecialOffsets::IgnoreOffset)
+                    offsetStack[n] = stack[n];
                 if (offsetStack[n] != stack[n])
-                    offsetStack[n] = UINT32_MAX;
+                    offsetStack[n] = SpecialOffsets::UnknownOffset;
+            }
         }
     };
 
     JSContext* cx_;
     LifoAllocScope allocScope_;
     RootedScript script_;
 
     Bytecode** codeArray_;
 
+    // Use a struct instead of an enum class to avoid casting the enumerated
+    // value.
+    struct SpecialOffsets {
+        static const uint32_t UnknownOffset = UINT32_MAX;
+        static const uint32_t IgnoreOffset = UINT32_MAX - 1;
+        static const uint32_t FirstSpecialOffset = IgnoreOffset;
+    };
+
   public:
     BytecodeParser(JSContext* cx, JSScript* script)
       : cx_(cx),
         allocScope_(&cx->tempLifoAlloc()),
         script_(cx, script),
         codeArray_(nullptr) { }
 
     bool parse();
@@ -304,17 +317,17 @@ class BytecodeParser
             operand += code.stackDepth;
             MOZ_ASSERT(operand >= 0);
         }
         MOZ_ASSERT(uint32_t(operand) < code.stackDepth);
         return code.offsetStack[operand];
     }
     jsbytecode* pcForStackOperand(jsbytecode* pc, int operand) {
         uint32_t offset = offsetForStackOperand(script_->pcToOffset(pc), operand);
-        if (offset == UINT32_MAX)
+        if (offset >= SpecialOffsets::FirstSpecialOffset)
             return nullptr;
         return script_->offsetToPC(offsetForStackOperand(script_->pcToOffset(pc), operand));
     }
 
   private:
     LifoAlloc& alloc() {
         return allocScope_.alloc();
     }
@@ -370,16 +383,21 @@ BytecodeParser::simulateOp(JSOp op, uint
     // unless it just reshuffles the stack.  In that case we want to preserve
     // the opcode that generated the original value.
     switch (op) {
       default:
         for (uint32_t n = 0; n != ndefs; ++n)
             offsetStack[stackDepth + n] = offset;
         break;
 
+      case JSOP_NOP_DESTRUCTURING:
+        // Poison the last offset to not obfuscate the error message.
+        offsetStack[stackDepth - 1] = SpecialOffsets::IgnoreOffset;
+        break;
+
       case JSOP_CASE:
         /* Keep the switch value. */
         MOZ_ASSERT(ndefs == 1);
         break;
 
       case JSOP_DUP:
         MOZ_ASSERT(ndefs == 2);
         if (offsetStack)
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1784,16 +1784,17 @@ CASE(EnableInterruptsPseudoOpcode)
 
     /* Commence executing the actual opcode. */
     SANITY_CHECKS();
     DISPATCH_TO(op);
 }
 
 /* Various 1-byte no-ops. */
 CASE(JSOP_NOP)
+CASE(JSOP_NOP_DESTRUCTURING)
 CASE(JSOP_UNUSED14)
 CASE(JSOP_UNUSED65)
 CASE(JSOP_UNUSED149)
 CASE(JSOP_UNUSED179)
 CASE(JSOP_UNUSED180)
 CASE(JSOP_UNUSED181)
 CASE(JSOP_UNUSED182)
 CASE(JSOP_UNUSED183)
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -2167,24 +2167,31 @@ 1234567890123456789012345678901234567890
      */ \
     macro(JSOP_LOOPENTRY,     227, "loopentry",    NULL,  2,  0,  0,  JOF_UINT8) \
     /*
      * Converts the value on the top of the stack to a String
      *   Category: Other
      *   Operands:
      *   Stack: val => ToString(val)
      */ \
-    macro(JSOP_TOSTRING,    228, "tostring",       NULL,  1,  1,  1,  JOF_BYTE)
+    macro(JSOP_TOSTRING,    228, "tostring",       NULL,  1,  1,  1,  JOF_BYTE) \
+    /*
+     * No-op used by the decompiler to produce nicer error messages about
+     * destructuring code.
+     *   Category: Other
+     *   Operands:
+     *   Stack: =>
+     */ \
+    macro(JSOP_NOP_DESTRUCTURING, 229, "nop-destructuring", NULL, 1, 0, 0, JOF_BYTE)
 
 /*
  * In certain circumstances it may be useful to "pad out" the opcode space to
  * a power of two.  Use this macro to do so.
  */
 #define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
-    macro(229) \
     macro(230) \
     macro(231) \
     macro(232) \
     macro(233) \
     macro(234) \
     macro(235) \
     macro(236) \
     macro(237) \