Bug 720316 - Convert RegExp indexes into uint32_t. r=luke
authorJeff Walden <jwalden@mit.edu>
Thu, 19 Jan 2012 17:15:24 -0800
changeset 86382 f8d4887aae8df037b0c8a45b3349601c21f958b5
parent 86381 6a2a7edff3c554a1db08794ffe771a93a91526c2
child 86383 3e8c74abc6e569faaa93acf650205798f7aac7c3
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs720316
milestone12.0a1
Bug 720316 - Convert RegExp indexes into uint32_t. r=luke
js/src/frontend/BytecodeEmitter.cpp
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsxdrapi.h
js/src/methodjit/Compiler.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1010,16 +1010,39 @@ EmitAtomOp(JSContext *cx, ParseNode *pn,
 
 static JSBool
 EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
 {
     JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
     return EmitIndexOp(cx, op, bce->objectList.index(objbox), bce);
 }
 
+static bool
+EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
+{
+    const size_t len = 1 + UINT32_INDEX_LEN;
+    ptrdiff_t offset = EmitCheck(cx, bce, len);
+    if (offset < 0)
+        return false;
+
+    jsbytecode *next = bce->next();
+    next[0] = jsbytecode(op);
+    SET_UINT32_INDEX(next, index);
+    bce->current->next = next + len;
+    UpdateDepth(cx, bce, offset);
+    CheckTypeSet(cx, bce, op);
+    return true;
+}
+
+static bool
+EmitRegExp(JSContext *cx, uint32_t index, BytecodeEmitter *bce)
+{
+    return EmitIndex32(cx, JSOP_REGEXP, index, bce);
+}
+
 /*
  * What good are ARGNO_LEN and SLOTNO_LEN, you ask?  The answer is that, apart
  * from EmitSlotIndexOp, they abstract out the detail that both are 2, and in
  * other parts of the code there's no necessary relationship between the two.
  * The abstraction cracks here in order to share EmitSlotIndexOp code among
  * the JSOP_DEFLOCALFUN and JSOP_GET{ARG,VAR,LOCAL}PROP cases.
  */
 JS_STATIC_ASSERT(ARGNO_LEN == 2);
@@ -6665,17 +6688,17 @@ frontend::EmitTree(JSContext *cx, Byteco
         break;
 
       case PNK_NUMBER:
         ok = EmitNumberOp(cx, pn->pn_dval, bce);
         break;
 
       case PNK_REGEXP:
         JS_ASSERT(pn->isOp(JSOP_REGEXP));
-        ok = EmitIndexOp(cx, JSOP_REGEXP, bce->regexpList.index(pn->pn_objbox), bce);
+        ok = EmitRegExp(cx, bce->regexpList.index(pn->pn_objbox), bce);
         break;
 
 #if JS_HAS_XML_SUPPORT
       case PNK_ANYNAME:
 #endif
       case PNK_TRUE:
       case PNK_FALSE:
       case PNK_THIS:
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1598,18 +1598,18 @@ js::Interpret(JSContext *cx, StackFrame 
 
     if (!entryFrame)
         entryFrame = regs.fp();
 
     /*
      * Initialize the index segment register used by LOAD_ATOM and
      * GET_FULL_INDEX macros below. As a register we use a pointer based on
      * the atom map to turn frequently executed LOAD_ATOM into simple array
-     * access. For less frequent object and regexp loads we have to recover
-     * the segment from atoms pointer first.
+     * access. For less frequent object loads we have to recover the segment
+     * from atoms pointer first.
      */
     JSAtom **atoms = script->atoms;
 
 #if JS_HAS_GENERATORS
     if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
         JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
         JS_ASSERT((size_t) (regs.sp - regs.fp()->base()) <= StackDepth(script));
 
@@ -3080,17 +3080,17 @@ BEGIN_CASE(JSOP_OBJECT)
 END_CASE(JSOP_OBJECT)
 
 BEGIN_CASE(JSOP_REGEXP)
 {
     /*
      * Push a regexp object cloned from the regexp literal object mapped by the
      * bytecode at pc.
      */
-    jsatomid index = GET_FULL_INDEX(0);
+    uint32_t index = GET_UINT32_INDEX(regs.pc);
     JSObject *proto = regs.fp()->scopeChain().global().getOrCreateRegExpPrototype(cx);
     if (!proto)
         goto error;
     JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto);
     if (!obj)
         goto error;
     PUSH_OBJECT(*obj);
 }
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -565,50 +565,56 @@ js_Disassemble1(JSContext *cx, JSScript 
 
       case JOF_JUMP: {
         ptrdiff_t off = GET_JUMP_OFFSET(pc);
         Sprint(sp, " %u (%+d)", loc + (intN) off, (intN) off);
         break;
       }
 
       case JOF_ATOM:
-      case JOF_OBJECT:
-      case JOF_REGEXP: {
+      case JOF_OBJECT: {
         uintN index = js_GetIndexFromBytecode(script, pc, 0);
         jsval v;
         if (type == JOF_ATOM) {
             if (op == JSOP_DOUBLE) {
                 v = script->getConst(index);
             } else {
                 JSAtom *atom = script->getAtom(index);
                 v = STRING_TO_JSVAL(atom);
             }
         } else {
-            JSObject *obj;
-            if (type == JOF_OBJECT) {
-                /* Don't call obj.toSource if analysis/inference is active. */
-                if (cx->compartment->activeAnalysis) {
-                    Sprint(sp, " object");
-                    break;
-                }
-                obj = script->getObject(index);
-            } else {
-                obj = script->getRegExp(index);
+            JS_ASSERT(type == JOF_OBJECT);
+
+            /* Don't call obj.toSource if analysis/inference is active. */
+            if (cx->compartment->activeAnalysis) {
+                Sprint(sp, " object");
+                break;
             }
+
+            JSObject *obj = script->getObject(index);
             v = OBJECT_TO_JSVAL(obj);
         }
         {
             JSAutoByteString bytes;
             if (!ToDisassemblySource(cx, v, &bytes))
                 return 0;
             Sprint(sp, " %s", bytes.ptr());
         }
         break;
       }
 
+      case JOF_REGEXP: {
+        JSObject *obj = script->getRegExp(GET_UINT32_INDEX(pc));
+        JSAutoByteString bytes;
+        if (!ToDisassemblySource(cx, ObjectValue(*obj), &bytes))
+            return 0;
+        Sprint(sp, " %s", bytes.ptr());
+        break;
+      }
+
       case JOF_TABLESWITCH:
       {
         jsint i, low, high;
 
         ptrdiff_t off = GET_JUMP_OFFSET(pc);
         jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
         low = GET_JUMP_OFFSET(pc2);
         pc2 += JUMP_OFFSET_LEN;
@@ -2657,19 +2663,16 @@ Decompile(SprintStack *ss, jsbytecode *p
     JS_END_MACRO
 
 #define LOAD_OBJECT(PCOFF)                                                    \
     GET_OBJECT_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
 
 #define LOAD_FUNCTION(PCOFF)                                                  \
     GET_FUNCTION_FROM_BYTECODE(jp->script, pc, PCOFF, fun)
 
-#define LOAD_REGEXP(PCOFF)                                                    \
-    GET_REGEXP_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
-
 #define GET_SOURCE_NOTE_ATOM(sn, atom)                                        \
     JS_BEGIN_MACRO                                                            \
         jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0);        \
                                                                               \
         LOCAL_ASSERT(atomIndex_ < jp->script->natoms);                        \
         (atom) = jp->script->atoms[atomIndex_];                               \
     JS_END_MACRO
 
@@ -4929,17 +4932,17 @@ Decompile(SprintStack *ss, jsbytecode *p
               case JSOP_OBJECT:
                 LOAD_OBJECT(0);
                 str = js_ValueToSource(cx, ObjectValue(*obj));
                 if (!str)
                     return NULL;
                 goto sprint_string;
 
               case JSOP_REGEXP:
-                GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj);
+                obj = jp->script->getRegExp(GET_UINT32_INDEX(pc));
                 str = obj->asRegExp().toString(cx);
                 if (!str)
                     return NULL;
                 goto sprint_string;
 
               case JSOP_TABLESWITCH:
               {
                 ptrdiff_t off, off2;
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -84,17 +84,17 @@ typedef enum JSOp {
 #define JOF_LOCAL         7       /* var or block-local variable */
 /* 8 is unused */
 #define JOF_UINT24        12      /* extended unsigned 24-bit literal (index) */
 #define JOF_UINT8         13      /* uint8_t immediate, e.g. top 8 bits of 24-bit
                                      atom index */
 #define JOF_INT32         14      /* int32_t immediate operand */
 #define JOF_OBJECT        15      /* unsigned 16-bit object index */
 #define JOF_SLOTOBJECT    16      /* uint16_t slot index + object index */
-#define JOF_REGEXP        17      /* unsigned 16-bit regexp index */
+#define JOF_REGEXP        17      /* unsigned 32-bit regexp index */
 #define JOF_INT8          18      /* int8_t immediate operand */
 #define JOF_ATOMOBJECT    19      /* uint16_t constant index + object index */
 #define JOF_UINT16PAIR    20      /* pair of uint16_t immediates */
 #define JOF_TYPEMASK      0x001f  /* mask for above immediate types */
 
 #define JOF_NAME          (1U<<5) /* name operation */
 #define JOF_PROP          (2U<<5) /* obj.prop operation */
 #define JOF_ELEM          (3U<<5) /* obj[index] operation */
@@ -186,20 +186,37 @@ static JS_ALWAYS_INLINE void
 SET_JUMP_OFFSET(jsbytecode *pc, int32_t off)
 {
     pc[1] = (jsbytecode)(off >> 24);
     pc[2] = (jsbytecode)(off >> 16);
     pc[3] = (jsbytecode)(off >> 8);
     pc[4] = (jsbytecode)off;
 }
 
+#define UINT32_INDEX_LEN        4
+
+static JS_ALWAYS_INLINE uint32_t
+GET_UINT32_INDEX(jsbytecode *pc)
+{
+    return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4];
+}
+
+static JS_ALWAYS_INLINE void
+SET_UINT32_INDEX(jsbytecode *pc, uint32_t index)
+{
+    pc[1] = (jsbytecode)(index >> 24);
+    pc[2] = (jsbytecode)(index >> 16);
+    pc[3] = (jsbytecode)(index >> 8);
+    pc[4] = (jsbytecode)index;
+}
+
 /*
  * A literal is indexed by a per-script atom or object maps. Most scripts
- * have relatively few literals, so the standard JOF_ATOM, JOF_OBJECT and
- * JOF_REGEXP formats specifies a fixed 16 bits of immediate operand index.
+ * have relatively few literals, so the standard JOF_ATOM and JOF_OBJECT
+ * format specifies a fixed 16 bits of immediate operand index.
  * A script with more than 64K literals must wrap the bytecode into
  * JSOP_INDEXBASE and JSOP_RESETBASE pair.
  */
 #define INDEX_LEN               2
 #define INDEX_HI(i)             ((jsbytecode)((i) >> 8))
 #define INDEX_LO(i)             ((jsbytecode)(i))
 #define GET_INDEX(pc)           GET_UINT16(pc)
 #define SET_INDEX(pc,i)         ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i))
@@ -352,22 +369,16 @@ js_GetIndexFromBytecode(JSScript *script
     JS_END_MACRO
 
 #define GET_FUNCTION_FROM_BYTECODE(script, pc, pcoff, fun)                    \
     JS_BEGIN_MACRO                                                            \
         uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
         fun = (script)->getFunction(index_);                                  \
     JS_END_MACRO
 
-#define GET_REGEXP_FROM_BYTECODE(script, pc, pcoff, obj)                      \
-    JS_BEGIN_MACRO                                                            \
-        uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
-        obj = (script)->getRegExp(index_);                                    \
-    JS_END_MACRO
-
 #ifdef __cplusplus
 namespace js {
 
 extern uintN
 StackUses(JSScript *script, jsbytecode *pc);
 
 extern uintN
 StackDefs(JSScript *script, jsbytecode *pc);
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -406,17 +406,17 @@ OPDEF(JSOP_RETRVAL,       153,"retrval",
 OPDEF(JSOP_GETGNAME,      154,"getgname",  NULL,       3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME)
 OPDEF(JSOP_SETGNAME,      155,"setgname",  NULL,       3,  2,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME)
 OPDEF(JSOP_INCGNAME,      156,"incgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 OPDEF(JSOP_DECGNAME,      157,"decgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 OPDEF(JSOP_GNAMEINC,      158,"gnameinc",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 OPDEF(JSOP_GNAMEDEC,      159,"gnamedec",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 
 /* Regular expression literal requiring special "fork on exec" handling. */
-OPDEF(JSOP_REGEXP,        160,"regexp",   NULL,       3,  0,  1, 19,  JOF_REGEXP)
+OPDEF(JSOP_REGEXP,        160,"regexp",   NULL,       5,  0,  1, 19,  JOF_REGEXP)
 
 /* XML (ECMA-357, a.k.a. "E4X") support. */
 OPDEF(JSOP_DEFXMLNS,      161,"defxmlns",   NULL,     1,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_ANYNAME,       162,"anyname",    NULL,     1,  0,  1, 19,  JOF_BYTE|JOF_XMLNAME)
 OPDEF(JSOP_QNAMEPART,     163,"qnamepart",  NULL,     3,  0,  1, 19,  JOF_ATOM|JOF_XMLNAME)
 OPDEF(JSOP_QNAMECONST,    164,"qnameconst", NULL,     3,  1,  1, 19,  JOF_ATOM|JOF_XMLNAME)
 OPDEF(JSOP_QNAME,         165,"qname",      NULL,     1,  2,  1,  0,  JOF_BYTE|JOF_XMLNAME)
 OPDEF(JSOP_TOATTRNAME,    166,"toattrname", NULL,     1,  1,  1, 19,  JOF_BYTE|JOF_XMLNAME)
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -221,17 +221,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 104)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 105)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -6865,17 +6865,17 @@ mjit::Compiler::jsop_newinit()
     frame.extra(frame.peek(-1)).initObject = baseobj;
 
     return true;
 }
 
 bool
 mjit::Compiler::jsop_regexp()
 {
-    JSObject *obj = script->getRegExp(fullAtomIndex(PC));
+    JSObject *obj = script->getRegExp(GET_UINT32_INDEX(PC));
     RegExpStatics *res = globalObj ? globalObj->getRegExpStatics() : NULL;
 
     if (!globalObj ||
         &obj->global() != globalObj ||
         !cx->typeInferenceEnabled() ||
         analysis->localsAliasStack() ||
         types::TypeSet::HasObjectFlags(cx, globalObj->getType(cx),
                                        types::OBJECT_FLAG_REGEXP_FLAGS_SET)) {