Bug 1535137 - Store JSOP_DOUBLE literals inline r=jandem
authorTed Campbell <tcampbell@mozilla.com>
Tue, 09 Apr 2019 13:07:45 +0000
changeset 468554 17ae35a549afd32c827d9031db5628d23c41c4f7
parent 468553 fd0ffc19dd6b3d7c56da650d5504d0d1b6a3b3b7
child 468555 7366858bc6ada4d4839937a3f3e69df1fa2a0aa3
push id35843
push usernbeleuzu@mozilla.com
push dateTue, 09 Apr 2019 22:08:13 +0000
treeherdermozilla-central@a31032a16330 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1535137
milestone68.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 1535137 - Store JSOP_DOUBLE literals inline r=jandem Replace the unaligned uint32_t index with the encoded double value. The double values are already being copied again before use, so an unaligned uint64_t load directly to double seems a more direct strategy. This also avoids needed to manage the allocation of the consts table. Differential Revision: https://phabricator.services.mozilla.com/D23396
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/jit/BaselineCompiler.cpp
js/src/jit/IonBuilder.cpp
js/src/vm/BytecodeUtil.cpp
js/src/vm/BytecodeUtil.h
js/src/vm/Interpreter.cpp
js/src/vm/Opcodes.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2006,16 +2006,29 @@ bool BytecodeEmitter::emitCallIncDec(Una
     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);
 }
 
+bool BytecodeEmitter::emitDouble(double d) {
+  ptrdiff_t offset;
+  if (!emitCheck(JSOP_DOUBLE, 9, &offset)) {
+    return false;
+  }
+
+  jsbytecode* code = this->code(offset);
+  code[0] = jsbytecode(JSOP_DOUBLE);
+  SET_DOUBLE(code, d);
+  updateDepth(offset);
+  return true;
+}
+
 bool BytecodeEmitter::emitNumberOp(double dval) {
   int32_t ival;
   if (NumberIsInt32(dval, &ival)) {
     if (ival == 0) {
       return emit1(JSOP_ZERO);
     }
     if (ival == 1) {
       return emit1(JSOP_ONE);
@@ -2040,21 +2053,17 @@ bool BytecodeEmitter::emitNumberOp(doubl
       if (!emitN(JSOP_INT32, 4, &off)) {
         return false;
       }
       SET_INT32(code(off), ival);
     }
     return true;
   }
 
-  if (!numberList.append(DoubleValue(dval))) {
-    return false;
-  }
-
-  return emitIndex32(JSOP_DOUBLE, numberList.length() - 1);
+  return emitDouble(dval);
 }
 
 /*
  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
  * LLVM is deciding to inline this function which uses a lot of stack space
  * into emitTree which is recursive and uses relatively little stack space.
  */
 MOZ_NEVER_INLINE bool BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt) {
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -551,16 +551,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   MOZ_MUST_USE bool emitUint16Operand(JSOp op, uint32_t operand);
 
   // Emit a bytecode followed by an uint32 immediate operand.
   MOZ_MUST_USE bool emitUint32Operand(JSOp op, uint32_t operand);
 
   // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
   MOZ_MUST_USE bool emitN(JSOp op, size_t extra, ptrdiff_t* offset = nullptr);
 
+  MOZ_MUST_USE bool emitDouble(double dval);
   MOZ_MUST_USE bool emitNumberOp(double dval);
 
   MOZ_MUST_USE bool emitBigIntOp(BigInt* bigint);
 
   MOZ_MUST_USE bool emitThisLiteral(ThisLiteral* pn);
   MOZ_MUST_USE bool emitGetFunctionThis(NameNode* thisName);
   MOZ_MUST_USE bool emitGetFunctionThis(const mozilla::Maybe<uint32_t>& offset);
   MOZ_MUST_USE bool emitGetThisForSuperBase(UnaryNode* superBase);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2158,28 +2158,34 @@ bool BaselineInterpreterCodeGen::emit_JS
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_RESUMEINDEX() {
   return emit_JSOP_UINT24();
 }
 
 template <>
 bool BaselineCompilerCodeGen::emit_JSOP_DOUBLE() {
-  frame.push(handler.script()->getConst(GET_UINT32_INDEX(handler.pc())));
+  frame.push(DoubleValue(GET_DOUBLE(handler.pc())));
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_DOUBLE() {
   MOZ_CRASH("NYI: interpreter JSOP_DOUBLE");
 }
 
-template <typename Handler>
-bool BaselineCodeGen<Handler>::emit_JSOP_BIGINT() {
-  return emit_JSOP_DOUBLE();
+template <>
+bool BaselineCompilerCodeGen::emit_JSOP_BIGINT() {
+  frame.push(handler.script()->getConst(GET_UINT32_INDEX(handler.pc())));
+  return true;
+}
+
+template <>
+bool BaselineInterpreterCodeGen::emit_JSOP_BIGINT() {
+  MOZ_CRASH("NYI: interpreter JSOP_BIGINT");
 }
 
 template <>
 bool BaselineCompilerCodeGen::emit_JSOP_STRING() {
   frame.push(StringValue(handler.script()->getAtom(handler.pc())));
   return true;
 }
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1962,16 +1962,19 @@ AbortReasonOr<Ok> IonBuilder::inspectOpc
     case JSOP_STRICTNE:
     case JSOP_LT:
     case JSOP_LE:
     case JSOP_GT:
     case JSOP_GE:
       return jsop_compare(op);
 
     case JSOP_DOUBLE:
+      pushConstant(DoubleValue(GET_DOUBLE(pc)));
+      return Ok();
+
     case JSOP_BIGINT:
       pushConstant(info().getConst(pc));
       return Ok();
 
     case JSOP_STRING:
       pushConstant(StringValue(info().getAtom(pc)));
       return Ok();
 
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -1469,18 +1469,25 @@ static unsigned Disassemble1(JSContext* 
         return 0;
       }
       if (!sp->jsprintf(" %s", bytes.get())) {
         return 0;
       }
       break;
     }
 
-    case JOF_BIGINT:
     case JOF_DOUBLE: {
+      double d = GET_DOUBLE(pc);
+      if (!sp->jsprintf(" %lf", d)) {
+        return 0;
+      }
+      break;
+    }
+
+    case JOF_BIGINT: {
       RootedValue v(cx, script->getConst(GET_UINT32_INDEX(pc)));
       UniqueChars bytes = ToDisassemblySource(cx, v);
       if (!bytes) {
         return 0;
       }
       if (!sp->jsprintf(" %s", bytes.get())) {
         return 0;
       }
@@ -2007,18 +2014,17 @@ bool ExpressionDecompiler::decompilePC(j
       case JSOP_CALLSITEOBJ:
         return write("OBJ");
 
       case JSOP_CLASSCONSTRUCTOR:
       case JSOP_DERIVEDCONSTRUCTOR:
         return write("CONSTRUCTOR");
 
       case JSOP_DOUBLE:
-        return sprinter.printf(
-            "%lf", script->getConst(GET_UINT32_INDEX(pc)).toDouble());
+        return sprinter.printf("%lf", GET_DOUBLE(pc));
 
       case JSOP_EXCEPTION:
         return write("EXCEPTION");
 
       case JSOP_FINALLY:
         if (defIndex == 0) {
           return write("THROWING");
         }
--- a/js/src/vm/BytecodeUtil.h
+++ b/js/src/vm/BytecodeUtil.h
@@ -52,17 +52,17 @@ enum {
   JOF_ENVCOORD = 9,     /* embedded ScopeCoordinate immediate */
   JOF_ARGC = 10,        /* uint16_t argument count */
   JOF_QARG = 11,        /* function argument index */
   JOF_LOCAL = 12,       /* var or block-local variable */
   JOF_RESUMEINDEX = 13, /* yield, await, or gosub resume index */
   JOF_ATOM = 14,        /* uint32_t constant index */
   JOF_OBJECT = 15,      /* uint32_t object index */
   JOF_REGEXP = 16,      /* uint32_t regexp index */
-  JOF_DOUBLE = 17,      /* uint32_t index for double value */
+  JOF_DOUBLE = 17,      /* inline double value */
   JOF_SCOPE = 18,       /* uint32_t scope index */
   JOF_CODE_OFFSET = 19, /* int32_t bytecode offset */
   JOF_ICINDEX = 20,     /* uint32_t IC index */
   JOF_LOOPENTRY = 21,   /* JSOP_LOOPENTRY, combines JOF_ICINDEX and JOF_UINT8 */
   JOF_BIGINT = 22,      /* uint32_t index for BigInt value */
   JOF_TYPEMASK = 0x001f, /* mask for above immediate types */
 
   JOF_NAME = 1 << 5,     /* name operation */
@@ -158,16 +158,26 @@ static MOZ_ALWAYS_INLINE uint32_t GET_UI
   mozilla::NativeEndian::copyAndSwapFromLittleEndian(&result, pc + 1, 1);
   return result;
 }
 
 static MOZ_ALWAYS_INLINE void SET_UINT32(jsbytecode* pc, uint32_t u) {
   mozilla::NativeEndian::copyAndSwapToLittleEndian(pc + 1, &u, 1);
 }
 
+static MOZ_ALWAYS_INLINE double GET_DOUBLE(const jsbytecode* pc) {
+  double result;
+  mozilla::NativeEndian::copyAndSwapFromLittleEndian(&result, pc + 1, 1);
+  return result;
+}
+
+static MOZ_ALWAYS_INLINE void SET_DOUBLE(jsbytecode* pc, double d) {
+  mozilla::NativeEndian::copyAndSwapToLittleEndian(pc + 1, &d, 1);
+}
+
 static MOZ_ALWAYS_INLINE int32_t GET_INT32(const jsbytecode* pc) {
   return static_cast<int32_t>(GET_UINT32(pc));
 }
 
 static MOZ_ALWAYS_INLINE void SET_INT32(jsbytecode* pc, int32_t i) {
   SET_UINT32(pc, static_cast<uint32_t>(i));
 }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1781,19 +1781,16 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_
   JS_END_MACRO
 
 #define COUNT_COVERAGE()                              \
   JS_BEGIN_MACRO                                      \
     MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
     COUNT_COVERAGE_PC(REGS.pc);                       \
   JS_END_MACRO
 
-#define LOAD_DOUBLE(PCOFF, dbl) \
-  ((dbl) = script->getConst(GET_UINT32_INDEX(REGS.pc + (PCOFF))).toDouble())
-
 #define SET_SCRIPT(s)                                                       \
   JS_BEGIN_MACRO                                                            \
     script = (s);                                                           \
     MOZ_ASSERT(cx->realm() == script->realm());                             \
     if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts()) \
       activation.enableInterruptsUnconditionally();                         \
   JS_END_MACRO
 
@@ -3264,21 +3261,17 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_
     END_CASE(JSOP_UINT24)
 
     CASE(JSOP_INT8) { PUSH_INT32(GET_INT8(REGS.pc)); }
     END_CASE(JSOP_INT8)
 
     CASE(JSOP_INT32) { PUSH_INT32(GET_INT32(REGS.pc)); }
     END_CASE(JSOP_INT32)
 
-    CASE(JSOP_DOUBLE) {
-      double dbl;
-      LOAD_DOUBLE(0, dbl);
-      PUSH_DOUBLE(dbl);
-    }
+    CASE(JSOP_DOUBLE) { PUSH_DOUBLE(GET_DOUBLE(REGS.pc)); }
     END_CASE(JSOP_DOUBLE)
 
     CASE(JSOP_STRING) { PUSH_STRING(script->getAtom(REGS.pc)); }
     END_CASE(JSOP_STRING)
 
     CASE(JSOP_TOSTRING) {
       MutableHandleValue oper = REGS.stackHandleAt(-1);
 
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -611,20 +611,20 @@
      *   Stack: => val
      */ \
     MACRO(JSOP_GETNAME, 59, "getname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \
     /*
      * Pushes numeric constant onto the stack.
      *
      *   Category: Literals
      *   Type: Constants
-     *   Operands: uint32_t constIndex
+     *   Operands: double literal
      *   Stack: => val
      */ \
-    MACRO(JSOP_DOUBLE, 60, "double", NULL, 5, 0, 1, JOF_DOUBLE) \
+    MACRO(JSOP_DOUBLE, 60, "double", NULL, 9, 0, 1, JOF_DOUBLE) \
     /*
      * Pushes string constant onto the stack.
      *
      *   Category: Literals
      *   Type: Constants
      *   Operands: uint32_t atomIndex
      *   Stack: => atom
      */ \