Bug 630445 - JM: shrink JITScript by optimizing the representation of variable-length sections. r=dvander.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 03 Feb 2011 19:55:59 -0800
changeset 62075 a1a8cd4accba5128e33440ab7b7a49d09ec37fc8
parent 62074 10df92bfb41443af53586fa5dc0d73fbad4e70d0
child 62076 c08656eb9e399f7256a289afc0ab25705c63a2fd
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersdvander
bugs630445
milestone2.0b11pre
Bug 630445 - JM: shrink JITScript by optimizing the representation of variable-length sections. r=dvander.
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/Retcon.cpp
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -455,228 +455,198 @@ mjit::Compiler::finishThisUp(JITScript *
         js_ReportOutOfMemory(cx);
         return Compile_Error;
     }
 
     JITScript *jit = new(cursor) JITScript;
     cursor += sizeof(JITScript);
 
     jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
-    jit->nCallSites = callSites.length();
     jit->invokeEntry = result;
     jit->singleStepMode = script->singleStepMode;
+    if (fun) {
+        jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
+        jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
+    }
+
+    /* 
+     * WARNING: mics(), callICs() et al depend on the ordering of these
+     * variable-length sections.  See JITScript's declaration for details.
+     */
 
     /* Build the pc -> ncode mapping. */
-    NativeMapEntry *nmap = (NativeMapEntry *)cursor;
-    cursor += sizeof(NativeMapEntry) * nNmapLive;
-
+    NativeMapEntry *jitNmap = (NativeMapEntry *)cursor;
+    jit->nNmapPairs = nNmapLive;
+    cursor += sizeof(NativeMapEntry) * jit->nNmapPairs;
     size_t ix = 0;
-    if (nNmapLive > 0) {
+    if (jit->nNmapPairs > 0) {
         for (size_t i = 0; i < script->length; i++) {
             analyze::Bytecode *opinfo = analysis->maybeCode(i);
             if (opinfo && opinfo->safePoint) {
                 Label L = jumpMap[i];
                 JS_ASSERT(L.isValid());
-                nmap[ix].bcOff = i;
-                nmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
+                jitNmap[ix].bcOff = i;
+                jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
                 ix++;
             }
         }
     }
-    JS_ASSERT(ix == nNmapLive);
-
-    if (fun) {
-        jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
-        jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
-    }
+    JS_ASSERT(ix == jit->nNmapPairs);
 
 #if defined JS_MONOIC
+    ic::MICInfo *jitMICs = (ic::MICInfo *)cursor;
     jit->nMICs = mics.length();
-    if (mics.length()) {
-        jit->mics = (ic::MICInfo *)cursor;
-        cursor += sizeof(ic::MICInfo) * mics.length();
-    } else {
-        jit->mics = NULL;
-    }
-
-    if (ic::MICInfo *scriptMICs = jit->mics) {
-        for (size_t i = 0; i < mics.length(); i++) {
-            scriptMICs[i].kind = mics[i].kind;
-            scriptMICs[i].entry = fullCode.locationOf(mics[i].entry);
-            switch (mics[i].kind) {
-              case ic::MICInfo::GET:
-              case ic::MICInfo::SET:
-                if (mics[i].kind == ic::MICInfo::GET)
-                    scriptMICs[i].load = fullCode.locationOf(mics[i].load);
-                else
-                    scriptMICs[i].load = fullCode.locationOf(mics[i].store).labelAtOffset(0);
-                scriptMICs[i].shape = fullCode.locationOf(mics[i].shape);
-                scriptMICs[i].stubCall = stubCode.locationOf(mics[i].call);
-                scriptMICs[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
-                scriptMICs[i].u.name.typeConst = mics[i].u.name.typeConst;
-                scriptMICs[i].u.name.dataConst = mics[i].u.name.dataConst;
-                scriptMICs[i].u.name.usePropertyCache = mics[i].u.name.usePropertyCache;
-                break;
-              default:
-                JS_NOT_REACHED("Bad MIC kind");
-            }
-            stubCode.patch(mics[i].addrLabel, &scriptMICs[i]);
+    cursor += sizeof(ic::MICInfo) * jit->nMICs;
+    for (size_t i = 0; i < jit->nMICs; i++) {
+        jitMICs[i].kind = mics[i].kind;
+        jitMICs[i].entry = fullCode.locationOf(mics[i].entry);
+        switch (mics[i].kind) {
+          case ic::MICInfo::GET:
+          case ic::MICInfo::SET:
+            if (mics[i].kind == ic::MICInfo::GET)
+                jitMICs[i].load = fullCode.locationOf(mics[i].load);
+            else
+                jitMICs[i].load = fullCode.locationOf(mics[i].store).labelAtOffset(0);
+            jitMICs[i].shape = fullCode.locationOf(mics[i].shape);
+            jitMICs[i].stubCall = stubCode.locationOf(mics[i].call);
+            jitMICs[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
+            jitMICs[i].u.name.typeConst = mics[i].u.name.typeConst;
+            jitMICs[i].u.name.dataConst = mics[i].u.name.dataConst;
+            jitMICs[i].u.name.usePropertyCache = mics[i].u.name.usePropertyCache;
+            break;
+          default:
+            JS_NOT_REACHED("Bad MIC kind");
         }
-    }
-
-    jit->nCallICs = callICs.length();
-    if (callICs.length()) {
-        jit->callICs = (ic::CallICInfo *)cursor;
-        cursor += sizeof(ic::CallICInfo) * callICs.length();
-    } else {
-        jit->callICs = NULL;
+        stubCode.patch(mics[i].addrLabel, &jitMICs[i]);
     }
 
-    if (ic::CallICInfo *cics = jit->callICs) {
-        for (size_t i = 0; i < callICs.length(); i++) {
-            cics[i].reset();
-            cics[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
-            cics[i].funJump = fullCode.locationOf(callICs[i].funJump);
-            cics[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
-
-            /* Compute the hot call offset. */
-            uint32 offset = fullCode.locationOf(callICs[i].hotJump) -
-                            fullCode.locationOf(callICs[i].funGuard);
-            cics[i].hotJumpOffset = offset;
-            JS_ASSERT(cics[i].hotJumpOffset == offset);
-
-            /* Compute the join point offset. */
-            offset = fullCode.locationOf(callICs[i].joinPoint) -
-                     fullCode.locationOf(callICs[i].funGuard);
-            cics[i].joinPointOffset = offset;
-            JS_ASSERT(cics[i].joinPointOffset == offset);
-                                            
-            /* Compute the OOL call offset. */
-            offset = stubCode.locationOf(callICs[i].oolCall) -
-                     stubCode.locationOf(callICs[i].slowPathStart);
-            cics[i].oolCallOffset = offset;
-            JS_ASSERT(cics[i].oolCallOffset == offset);
-
-            /* Compute the OOL jump offset. */
-            offset = stubCode.locationOf(callICs[i].oolJump) -
-                     stubCode.locationOf(callICs[i].slowPathStart);
-            cics[i].oolJumpOffset = offset;
-            JS_ASSERT(cics[i].oolJumpOffset == offset);
-
-            /* Compute the start of the OOL IC call. */
-            offset = stubCode.locationOf(callICs[i].icCall) -
-                     stubCode.locationOf(callICs[i].slowPathStart);
-            cics[i].icCallOffset = offset;
-            JS_ASSERT(cics[i].icCallOffset == offset);
-
-            /* Compute the slow join point offset. */
-            offset = stubCode.locationOf(callICs[i].slowJoinPoint) -
-                     stubCode.locationOf(callICs[i].slowPathStart);
-            cics[i].slowJoinOffset = offset;
-            JS_ASSERT(cics[i].slowJoinOffset == offset);
-
-            /* Compute the join point offset for continuing on the hot path. */
-            offset = stubCode.locationOf(callICs[i].hotPathLabel) -
-                     stubCode.locationOf(callICs[i].funGuard);
-            cics[i].hotPathOffset = offset;
-            JS_ASSERT(cics[i].hotPathOffset == offset);
-
-            cics[i].pc = callICs[i].pc;
-            cics[i].frameSize = callICs[i].frameSize;
-            cics[i].funObjReg = callICs[i].funObjReg;
-            cics[i].funPtrReg = callICs[i].funPtrReg;
-            stubCode.patch(callICs[i].addrLabel1, &cics[i]);
-            stubCode.patch(callICs[i].addrLabel2, &cics[i]);
-        } 
+    ic::CallICInfo *jitCallICs = (ic::CallICInfo *)cursor;
+    jit->nCallICs = callICs.length();
+    cursor += sizeof(ic::CallICInfo) * jit->nCallICs;
+    for (size_t i = 0; i < jit->nCallICs; i++) {
+        jitCallICs[i].reset();
+        jitCallICs[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
+        jitCallICs[i].funJump = fullCode.locationOf(callICs[i].funJump);
+        jitCallICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
+
+        /* Compute the hot call offset. */
+        uint32 offset = fullCode.locationOf(callICs[i].hotJump) -
+                        fullCode.locationOf(callICs[i].funGuard);
+        jitCallICs[i].hotJumpOffset = offset;
+        JS_ASSERT(jitCallICs[i].hotJumpOffset == offset);
+
+        /* Compute the join point offset. */
+        offset = fullCode.locationOf(callICs[i].joinPoint) -
+                 fullCode.locationOf(callICs[i].funGuard);
+        jitCallICs[i].joinPointOffset = offset;
+        JS_ASSERT(jitCallICs[i].joinPointOffset == offset);
+                                        
+        /* Compute the OOL call offset. */
+        offset = stubCode.locationOf(callICs[i].oolCall) -
+                 stubCode.locationOf(callICs[i].slowPathStart);
+        jitCallICs[i].oolCallOffset = offset;
+        JS_ASSERT(jitCallICs[i].oolCallOffset == offset);
+
+        /* Compute the OOL jump offset. */
+        offset = stubCode.locationOf(callICs[i].oolJump) -
+                 stubCode.locationOf(callICs[i].slowPathStart);
+        jitCallICs[i].oolJumpOffset = offset;
+        JS_ASSERT(jitCallICs[i].oolJumpOffset == offset);
+
+        /* Compute the start of the OOL IC call. */
+        offset = stubCode.locationOf(callICs[i].icCall) -
+                 stubCode.locationOf(callICs[i].slowPathStart);
+        jitCallICs[i].icCallOffset = offset;
+        JS_ASSERT(jitCallICs[i].icCallOffset == offset);
+
+        /* Compute the slow join point offset. */
+        offset = stubCode.locationOf(callICs[i].slowJoinPoint) -
+                 stubCode.locationOf(callICs[i].slowPathStart);
+        jitCallICs[i].slowJoinOffset = offset;
+        JS_ASSERT(jitCallICs[i].slowJoinOffset == offset);
+
+        /* Compute the join point offset for continuing on the hot path. */
+        offset = stubCode.locationOf(callICs[i].hotPathLabel) -
+                 stubCode.locationOf(callICs[i].funGuard);
+        jitCallICs[i].hotPathOffset = offset;
+        JS_ASSERT(jitCallICs[i].hotPathOffset == offset);
+
+        jitCallICs[i].pc = callICs[i].pc;
+        jitCallICs[i].frameSize = callICs[i].frameSize;
+        jitCallICs[i].funObjReg = callICs[i].funObjReg;
+        jitCallICs[i].funPtrReg = callICs[i].funPtrReg;
+        stubCode.patch(callICs[i].addrLabel1, &jitCallICs[i]);
+        stubCode.patch(callICs[i].addrLabel2, &jitCallICs[i]);
     }
 
+    ic::EqualityICInfo *jitEqualityICs = (ic::EqualityICInfo *)cursor;
     jit->nEqualityICs = equalityICs.length();
-    if (equalityICs.length()) {
-        jit->equalityICs = (ic::EqualityICInfo *)cursor;
-        cursor += sizeof(ic::EqualityICInfo) * equalityICs.length();
-    } else {
-        jit->equalityICs = NULL;
+    cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs;
+    for (size_t i = 0; i < jit->nEqualityICs; i++) {
+        uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
+        JS_ASSERT(jumpMap[offs].isValid());
+        jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
+        jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
+        jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
+        jitEqualityICs[i].stub = equalityICs[i].stub;
+        jitEqualityICs[i].lvr = equalityICs[i].lvr;
+        jitEqualityICs[i].rvr = equalityICs[i].rvr;
+        jitEqualityICs[i].tempReg = equalityICs[i].tempReg;
+        jitEqualityICs[i].cond = equalityICs[i].cond;
+        if (equalityICs[i].jumpToStub.isSet())
+            jitEqualityICs[i].jumpToStub = fullCode.locationOf(equalityICs[i].jumpToStub.get());
+        jitEqualityICs[i].fallThrough = fullCode.locationOf(equalityICs[i].fallThrough);
+        
+        stubCode.patch(equalityICs[i].addrLabel, &jitEqualityICs[i]);
     }
 
-    if (ic::EqualityICInfo *scriptEICs = jit->equalityICs) {
-        for (size_t i = 0; i < equalityICs.length(); i++) {
-            uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
-            JS_ASSERT(jumpMap[offs].isValid());
-            scriptEICs[i].target = fullCode.locationOf(jumpMap[offs]);
-            scriptEICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
-            scriptEICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
-            scriptEICs[i].stub = equalityICs[i].stub;
-            scriptEICs[i].lvr = equalityICs[i].lvr;
-            scriptEICs[i].rvr = equalityICs[i].rvr;
-            scriptEICs[i].tempReg = equalityICs[i].tempReg;
-            scriptEICs[i].cond = equalityICs[i].cond;
-            if (equalityICs[i].jumpToStub.isSet())
-                scriptEICs[i].jumpToStub = fullCode.locationOf(equalityICs[i].jumpToStub.get());
-            scriptEICs[i].fallThrough = fullCode.locationOf(equalityICs[i].fallThrough);
-            
-            stubCode.patch(equalityICs[i].addrLabel, &scriptEICs[i]);
-        }
-    }
-
+    ic::TraceICInfo *jitTraceICs = (ic::TraceICInfo *)cursor;
     jit->nTraceICs = traceICs.length();
-    if (traceICs.length()) {
-        jit->traceICs = (ic::TraceICInfo *)cursor;
-        cursor += sizeof(ic::TraceICInfo) * traceICs.length();
-    } else {
-        jit->traceICs = NULL;
-    }
-
-    if (ic::TraceICInfo *scriptTICs = jit->traceICs) {
-        for (size_t i = 0; i < traceICs.length(); i++) {
-            scriptTICs[i].initialized = traceICs[i].initialized;
-            if (!traceICs[i].initialized)
-                continue;
-
-            uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
-            JS_ASSERT(jumpMap[offs].isValid());
-            scriptTICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
-            scriptTICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
-            scriptTICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
-            scriptTICs[i].traceData = NULL;
+    cursor += sizeof(ic::TraceICInfo) * jit->nTraceICs;
+    for (size_t i = 0; i < jit->nTraceICs; i++) {
+        jitTraceICs[i].initialized = traceICs[i].initialized;
+        if (!traceICs[i].initialized)
+            continue;
+
+        uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
+        JS_ASSERT(jumpMap[offs].isValid());
+        jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
+        jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
+        jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
+        jitTraceICs[i].traceData = NULL;
 #ifdef DEBUG
-            scriptTICs[i].jumpTargetPC = traceICs[i].jumpTarget;
+        jitTraceICs[i].jumpTargetPC = traceICs[i].jumpTarget;
 #endif
-            scriptTICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet();
-            if (traceICs[i].slowTraceHint.isSet())
-                scriptTICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get());
+        jitTraceICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet();
+        if (traceICs[i].slowTraceHint.isSet())
+            jitTraceICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get());
 #ifdef JS_TRACER
-            scriptTICs[i].loopCounterStart = GetHotloop(cx);
+        jitTraceICs[i].loopCounterStart = GetHotloop(cx);
 #endif
-            scriptTICs[i].loopCounter = scriptTICs[i].loopCounterStart;
-            
-            stubCode.patch(traceICs[i].addrLabel, &scriptTICs[i]);
-        }
+        jitTraceICs[i].loopCounter = jitTraceICs[i].loopCounterStart;
+        
+        stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
     }
 #endif /* JS_MONOIC */
 
     for (size_t i = 0; i < callPatches.length(); i++) {
         CallPatchInfo &patch = callPatches[i];
 
         if (patch.hasFastNcode)
             fullCode.patch(patch.fastNcodePatch, fullCode.locationOf(patch.joinPoint));
         if (patch.hasSlowNcode)
             stubCode.patch(patch.slowNcodePatch, fullCode.locationOf(patch.joinPoint));
     }
 
 #ifdef JS_POLYIC
+    ic::GetElementIC *jitGetElems = (ic::GetElementIC *)cursor;
     jit->nGetElems = getElemICs.length();
-    if (getElemICs.length()) {
-        jit->getElems = (ic::GetElementIC *)cursor;
-        cursor += sizeof(ic::GetElementIC) * getElemICs.length();
-    } else {
-        jit->getElems = NULL;
-    }
-
-    for (size_t i = 0; i < getElemICs.length(); i++) {
-        ic::GetElementIC &to = jit->getElems[i];
+    cursor += sizeof(ic::GetElementIC) * jit->nGetElems;
+    for (size_t i = 0; i < jit->nGetElems; i++) {
+        ic::GetElementIC &to = jitGetElems[i];
         GetElementICInfo &from = getElemICs[i];
 
         new (&to) ic::GetElementIC();
         from.copyTo(to, fullCode, stubCode);
 
         to.typeReg = from.typeReg;
         to.objReg = from.objReg;
         to.idRemat = from.id;
@@ -690,26 +660,21 @@ mjit::Compiler::finishThisUp(JITScript *
         int inlineClaspGuard = fullCode.locationOf(from.claspGuard) -
                                fullCode.locationOf(from.fastPathStart);
         to.inlineClaspGuard = inlineClaspGuard;
         JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard);
 
         stubCode.patch(from.paramAddr, &to);
     }
 
+    ic::SetElementIC *jitSetElems = (ic::SetElementIC *)cursor;
     jit->nSetElems = setElemICs.length();
-    if (setElemICs.length()) {
-        jit->setElems = (ic::SetElementIC *)cursor;
-        cursor += sizeof(ic::SetElementIC) * setElemICs.length();
-    } else {
-        jit->setElems = NULL;
-    }
-
-    for (size_t i = 0; i < setElemICs.length(); i++) {
-        ic::SetElementIC &to = jit->setElems[i];
+    cursor += sizeof(ic::SetElementIC) * jit->nSetElems;
+    for (size_t i = 0; i < jit->nSetElems; i++) {
+        ic::SetElementIC &to = jitSetElems[i];
         SetElementICInfo &from = setElemICs[i];
 
         new (&to) ic::SetElementIC();
         from.copyTo(to, fullCode, stubCode);
 
         to.strictMode = script->strictModeCode;
         to.vr = from.vr;
         to.objReg = from.objReg;
@@ -735,50 +700,43 @@ mjit::Compiler::finishThisUp(JITScript *
         CheckIsStubCall(to.slowPathCall.labelAtOffset(0));
 
         to.volatileMask = from.volatileMask;
         JS_ASSERT(to.volatileMask == from.volatileMask);
 
         stubCode.patch(from.paramAddr, &to);
     }
 
+    ic::PICInfo *jitPics = (ic::PICInfo *)cursor;
     jit->nPICs = pics.length();
-    if (pics.length()) {
-        jit->pics = (ic::PICInfo *)cursor;
-        cursor += sizeof(ic::PICInfo) * pics.length();
-    } else {
-        jit->pics = NULL;
-    }
-
-    if (ic::PICInfo *scriptPICs = jit->pics) {
-        for (size_t i = 0; i < pics.length(); i++) {
-            new (&scriptPICs[i]) ic::PICInfo();
-            pics[i].copyTo(scriptPICs[i], fullCode, stubCode);
-            pics[i].copySimpleMembersTo(scriptPICs[i]);
-
-            scriptPICs[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
-                                         masm.distanceOf(pics[i].fastPathStart);
-            JS_ASSERT(scriptPICs[i].shapeGuard == masm.distanceOf(pics[i].shapeGuard) -
-                                         masm.distanceOf(pics[i].fastPathStart));
-            scriptPICs[i].shapeRegHasBaseShape = true;
-            scriptPICs[i].pc = pics[i].pc;
-
-            if (pics[i].kind == ic::PICInfo::SET ||
-                pics[i].kind == ic::PICInfo::SETMETHOD) {
-                scriptPICs[i].u.vr = pics[i].vr;
-            } else if (pics[i].kind != ic::PICInfo::NAME) {
-                if (pics[i].hasTypeCheck) {
-                    int32 distance = stubcc.masm.distanceOf(pics[i].typeCheck) -
-                                     stubcc.masm.distanceOf(pics[i].slowPathStart);
-                    JS_ASSERT(distance <= 0);
-                    scriptPICs[i].u.get.typeCheckOffset = distance;
-                }
+    cursor += sizeof(ic::PICInfo) * jit->nPICs;
+    for (size_t i = 0; i < jit->nPICs; i++) {
+        new (&jitPics[i]) ic::PICInfo();
+        pics[i].copyTo(jitPics[i], fullCode, stubCode);
+        pics[i].copySimpleMembersTo(jitPics[i]);
+
+        jitPics[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
+                                masm.distanceOf(pics[i].fastPathStart);
+        JS_ASSERT(jitPics[i].shapeGuard == masm.distanceOf(pics[i].shapeGuard) -
+                                           masm.distanceOf(pics[i].fastPathStart));
+        jitPics[i].shapeRegHasBaseShape = true;
+        jitPics[i].pc = pics[i].pc;
+
+        if (pics[i].kind == ic::PICInfo::SET ||
+            pics[i].kind == ic::PICInfo::SETMETHOD) {
+            jitPics[i].u.vr = pics[i].vr;
+        } else if (pics[i].kind != ic::PICInfo::NAME) {
+            if (pics[i].hasTypeCheck) {
+                int32 distance = stubcc.masm.distanceOf(pics[i].typeCheck) -
+                                 stubcc.masm.distanceOf(pics[i].slowPathStart);
+                JS_ASSERT(distance <= 0);
+                jitPics[i].u.get.typeCheckOffset = distance;
             }
-            stubCode.patch(pics[i].paramAddr, &scriptPICs[i]);
         }
+        stubCode.patch(pics[i].paramAddr, &jitPics[i]);
     }
 #endif
 
     /* Link fast and slow paths together. */
     stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());
 
     /* Patch all double references. */
     size_t doubleOffset = masm.size() + stubcc.size();
@@ -810,37 +768,30 @@ mjit::Compiler::finishThisUp(JITScript *
     /* Patch all outgoing calls. */
     masm.finalize(fullCode);
     stubcc.masm.finalize(stubCode);
 
     JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size());
     JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
 
     /* Build the table of call sites. */
+    CallSite *jitCallSites = (CallSite *)cursor;
     jit->nCallSites = callSites.length();
-    if (callSites.length()) {
-        jit->callSites = (CallSite *)cursor;
-        cursor += sizeof(CallSite) * callSites.length();
-
-        for (size_t i = 0; i < callSites.length(); i++) {
-            CallSite &to = jit->callSites[i];
-            InternalCallSite &from = callSites[i];
-            uint32 codeOffset = from.ool
-                                ? masm.size() + from.returnOffset
-                                : from.returnOffset;
-            to.initialize(codeOffset, from.pc - script->code, from.id);
-        }
-    } else {
-        jit->callSites = NULL;
+    cursor += sizeof(CallSite) * jit->nCallSites;
+    for (size_t i = 0; i < jit->nCallSites; i++) {
+        CallSite &to = jitCallSites[i];
+        InternalCallSite &from = callSites[i];
+        uint32 codeOffset = from.ool
+                            ? masm.size() + from.returnOffset
+                            : from.returnOffset;
+        to.initialize(codeOffset, from.pc - script->code, from.id);
     }
 
     JS_ASSERT(size_t(cursor - (uint8*)jit) == totalBytes);
 
-    jit->nmap = nmap;
-    jit->nNmapPairs = nNmapLive;
     *jitp = jit;
 
     /* We tolerate a race in the stats. */
     cx->runtime->mjitMemoryUsed += totalSize + totalBytes;
 
     return Compile_Okay;
 }
 
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -206,17 +206,16 @@ class Compiler : public BaseCompiler
     struct PICGenInfo : public BaseICInfo {
         PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
           : BaseICInfo(op), kind(kind), usePropCache(usePropCache)
         { }
         ic::PICInfo::Kind kind;
         Label typeCheck;
         RegisterID shapeReg;
         RegisterID objReg;
-        RegisterID idReg;
         RegisterID typeReg;
         bool usePropCache;
         Label shapeGuard;
         jsbytecode *pc;
         JSAtom *atom;
         bool hasTypeCheck;
         ValueRemat vr;
 #ifdef JS_HAS_IC_LABELS
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -936,17 +936,17 @@ DisableTraceHint(JITScript *jit, ic::Tra
 }
 
 static void
 ResetTraceHintAt(JSScript *script, js::mjit::JITScript *jit,
                  jsbytecode *pc, uint16_t index, bool full)
 {
     if (index >= jit->nTraceICs)
         return;
-    ic::TraceICInfo &ic = jit->traceICs[index];
+    ic::TraceICInfo &ic = jit->traceICs()[index];
     if (!ic.initialized)
         return;
     
     JS_ASSERT(ic.jumpTargetPC == pc);
 
     JaegerSpew(JSpew_PICs, "Enabling trace IC %u in script %p\n", index, script);
 
     Repatcher repatcher(jit);
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -796,50 +796,142 @@ js::mjit::JaegerShotAtSafePoint(JSContex
 {
 #ifdef JS_TRACER
     JS_ASSERT(!TRACE_RECORDER(cx));
 #endif
 
     return CheckStackAndEnterMethodJIT(cx, cx->fp(), safePoint);
 }
 
+NativeMapEntry *
+JITScript::nmap() const
+{
+    return (NativeMapEntry *)((char*)this + sizeof(JITScript));
+}
+
+char *
+JITScript::nmapSectionLimit() const
+{
+    return (char *)nmap() + sizeof(NativeMapEntry) * nNmapPairs;
+}
+
+#ifdef JS_MONOIC
+ic::MICInfo *
+JITScript::mics() const
+{
+    return (ic::MICInfo *)nmapSectionLimit();
+}
+
+ic::CallICInfo *
+JITScript::callICs() const
+{
+    return (ic::CallICInfo *)((char *)mics() + sizeof(ic::MICInfo) * nMICs);
+}
+
+ic::EqualityICInfo *
+JITScript::equalityICs() const
+{
+    return (ic::EqualityICInfo *)((char *)callICs() + sizeof(ic::CallICInfo) * nCallICs);
+}
+
+ic::TraceICInfo *
+JITScript::traceICs() const
+{
+    return (ic::TraceICInfo *)((char *)equalityICs() + sizeof(ic::EqualityICInfo) * nEqualityICs);
+}
+
+char *
+JITScript::monoICSectionsLimit() const
+{
+    return (char *)traceICs() + sizeof(ic::TraceICInfo) * nTraceICs;
+}
+#else   // JS_MONOIC
+char *
+JITScript::monoICSectionsLimit() const
+{
+    return nmapSectionsLimit();
+}
+#endif  // JS_MONOIC
+
+#ifdef JS_POLYIC
+ic::GetElementIC *
+JITScript::getElems() const
+{
+    return (ic::GetElementIC *)monoICSectionsLimit();
+}
+
+ic::SetElementIC *
+JITScript::setElems() const
+{
+    return (ic::SetElementIC *)((char *)getElems() + sizeof(ic::GetElementIC) * nGetElems);
+}
+
+ic::PICInfo *
+JITScript::pics() const
+{
+    return (ic::PICInfo *)((char *)setElems() + sizeof(ic::SetElementIC) * nSetElems);
+}
+
+char *
+JITScript::polyICSectionsLimit() const
+{
+    return (char *)pics() + sizeof(ic::PICInfo) * nPICs;
+}
+#else   // JS_POLYIC
+char *
+JITScript::polyICSectionsLimit() const
+{
+    return monoICSectionsLimit();
+}
+#endif  // JS_POLYIC
+
+js::mjit::CallSite *
+JITScript::callSites() const
+{
+    return (js::mjit::CallSite *)polyICSectionsLimit();
+}
+
 template <typename T>
 static inline void Destroy(T &t)
 {
     t.~T();
 }
 
 mjit::JITScript::~JITScript()
 {
 #if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
     void *addr = code.m_code.executableAddress();
     memset(addr, 0xcc, code.m_size);
 #endif
 
     code.m_executablePool->release();
 
 #if defined JS_POLYIC
-    for (uint32 i = 0; i < nPICs; i++)
-        Destroy(pics[i]);
+    ic::GetElementIC *getElems_ = getElems();
+    ic::SetElementIC *setElems_ = setElems();
+    ic::PICInfo *pics_ = pics();
     for (uint32 i = 0; i < nGetElems; i++)
-        Destroy(getElems[i]);
+        Destroy(getElems_[i]);
     for (uint32 i = 0; i < nSetElems; i++)
-        Destroy(setElems[i]);
+        Destroy(setElems_[i]);
+    for (uint32 i = 0; i < nPICs; i++)
+        Destroy(pics_[i]);
 #endif
 
 #if defined JS_MONOIC
     for (JSC::ExecutablePool **pExecPool = execPools.begin();
          pExecPool != execPools.end();
          ++pExecPool)
     {
         (*pExecPool)->release();
     }
     
+    ic::CallICInfo *callICs_ = callICs();
     for (uint32 i = 0; i < nCallICs; i++)
-        callICs[i].releasePools();
+        callICs_[i].releasePools();
 #endif
 }
 
 /* Please keep in sync with Compiler::finishThisUp! */
 size_t
 mjit::JITScript::scriptDataSize()
 {
     return sizeof(JITScript) +
@@ -919,25 +1011,24 @@ PICPCComparator(const void *key, const v
 }
 
 uintN
 mjit::GetCallTargetCount(JSScript *script, jsbytecode *pc)
 {
     ic::PICInfo *pic;
     
     if (mjit::JITScript *jit = script->getJIT(false)) {
-        pic = (ic::PICInfo *)bsearch(pc, jit->pics, jit->nPICs, sizeof(jit->pics[0]),
+        pic = (ic::PICInfo *)bsearch(pc, jit->pics(), jit->nPICs, sizeof(ic::PICInfo),
                                      PICPCComparator);
         if (pic)
             return pic->stubsGenerated + 1; /* Add 1 for the inline path. */
     }
     
     if (mjit::JITScript *jit = script->getJIT(true)) {
-        pic = (ic::PICInfo *)bsearch(pc, jit->pics,
-                                     jit->nPICs, sizeof(jit->pics[0]),
+        pic = (ic::PICInfo *)bsearch(pc, jit->pics(), jit->nPICs, sizeof(ic::PICInfo),
                                      PICPCComparator);
         if (pic)
             return pic->stubsGenerated + 1; /* Add 1 for the inline path. */
     }
 
     return 1;
 }
 #else
@@ -948,29 +1039,30 @@ mjit::GetCallTargetCount(JSScript *scrip
 }
 #endif
 
 jsbytecode *
 JITScript::nativeToPC(void *returnAddress) const
 {
     size_t low = 0;
     size_t high = nCallICs;
+    js::mjit::ic::CallICInfo *callICs_ = callICs();
     while (high > low + 1) {
         /* Could overflow here on a script with 2 billion calls. Oh well. */
         size_t mid = (high + low) / 2;
-        void *entry = callICs[mid].funGuard.executableAddress();
+        void *entry = callICs_[mid].funGuard.executableAddress();
 
         /*
          * Use >= here as the return address of the call is likely to be
          * the start address of the next (possibly IC'ed) operation.
          */
         if (entry >= returnAddress)
             high = mid;
         else
             low = mid;
     }
 
-    js::mjit::ic::CallICInfo &ic = callICs[low];
+    js::mjit::ic::CallICInfo &ic = callICs_[low];
 
     JS_ASSERT((uint8*)ic.funGuard.executableAddress() + ic.joinPointOffset == returnAddress);
     return ic.pc;
 }
 
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -295,58 +295,65 @@ struct NativeMapEntry {
     size_t          bcOff;  /* bytecode offset in script */
     void            *ncode; /* pointer to native code */
 };
 
 struct JITScript {
     typedef JSC::MacroAssemblerCodeRef CodeRef;
     CodeRef         code;       /* pool & code addresses */
 
-    NativeMapEntry  *nmap;      /* array of NativeMapEntrys, sorted by .bcOff.
-                                   .ncode values may not be NULL. */
-    size_t          nNmapPairs; /* number of entries in nmap */
 
     void            *invokeEntry;       /* invoke address */
     void            *fastEntry;         /* cached entry, fastest */
     void            *arityCheckEntry;   /* arity check address */
 
-    /* To minimize the size of this struct on 64-bit, put uint32s after all pointers. */
-    js::mjit::CallSite *callSites;
-#ifdef JS_MONOIC
-    ic::MICInfo     *mics;      /* MICs in this script. */
-    ic::CallICInfo  *callICs;   /* CallICs in this script. */
-    ic::EqualityICInfo *equalityICs;
-    ic::TraceICInfo *traceICs;
-#endif
-#ifdef JS_POLYIC
-    ic::PICInfo     *pics;      /* PICs in this script */
-    ic::GetElementIC *getElems;
-    ic::SetElementIC *setElems;
-#endif
-
-    uint32          nCallSites:31;
+    /*
+     * This struct has several variable-length sections that are allocated on
+     * the end:  nmaps, MICs, callICs, etc.  To save space -- worthwhile
+     * because JITScripts are common -- we only record their lengths.  We can
+     * find any of the sections from the lengths because we know their order.
+     * Therefore, do not change the section ordering in finishThisUp() without
+     * changing nMICs() et al as well.
+     */
+    uint32          nNmapPairs:31;      /* The NativeMapEntrys are sorted by .bcOff.
+                                           .ncode values may not be NULL. */
     bool            singleStepMode:1;   /* compiled in "single step mode" */
 #ifdef JS_MONOIC
-    uint32          nMICs;      /* number of MonoICs */
-    uint32          nCallICs;   /* number of call ICs */
+    uint32          nMICs;
+    uint32          nCallICs;
     uint32          nEqualityICs;
     uint32          nTraceICs;
 #endif
 #ifdef JS_POLYIC
-    uint32          nPICs;      /* number of PolyICs */
     uint32          nGetElems;
     uint32          nSetElems;
+    uint32          nPICs;
 #endif
+    uint32          nCallSites;
 
 #ifdef JS_MONOIC
     // Additional ExecutablePools that IC stubs were generated into.
     typedef Vector<JSC::ExecutablePool *, 0, SystemAllocPolicy> ExecPoolVector;
     ExecPoolVector execPools;
 #endif
 
+    NativeMapEntry *nmap() const;
+#ifdef JS_MONOIC
+    ic::MICInfo    *mics() const;
+    ic::CallICInfo *callICs() const;
+    ic::EqualityICInfo *equalityICs() const;
+    ic::TraceICInfo *traceICs() const;
+#endif
+#ifdef JS_POLYIC
+    ic::GetElementIC *getElems() const;
+    ic::SetElementIC *setElems() const;
+    ic::PICInfo     *pics() const;
+#endif
+    js::mjit::CallSite *callSites() const;
+
     ~JITScript();
 
     bool isValidCode(void *ptr) {
         char *jitcode = (char *)code.m_code.executableAddress();
         char *jcheck = (char *)ptr;
         return jcheck >= jitcode && jcheck < jitcode + code.m_size;
     }
 
@@ -355,16 +362,22 @@ struct JITScript {
     void purgeMICs();
     void purgePICs();
 
     size_t scriptDataSize();
 
     size_t mainCodeSize() { return code.m_size; } /* doesn't account for fragmentation */
 
     jsbytecode *nativeToPC(void *returnAddress) const;
+
+  private:
+    /* Helpers used to navigate the variable-length sections. */
+    char *nmapSectionLimit() const;
+    char *monoICSectionsLimit() const;
+    char *polyICSectionsLimit() const;
 };
 
 /*
  * Execute the given mjit code. This is a low-level call and callers must
  * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
  */
 JSBool EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit);
 
@@ -463,25 +476,25 @@ inline void * bsearch_nmap(NativeMapEntr
 
 inline void *
 JSScript::maybeNativeCodeForPC(bool constructing, jsbytecode *pc)
 {
     js::mjit::JITScript *jit = getJIT(constructing);
     if (!jit)
         return NULL;
     JS_ASSERT(pc >= code && pc < code + length);
-    return bsearch_nmap(jit->nmap, jit->nNmapPairs, (size_t)(pc - code));
+    return bsearch_nmap(jit->nmap(), jit->nNmapPairs, (size_t)(pc - code));
 }
 
 inline void *
 JSScript::nativeCodeForPC(bool constructing, jsbytecode *pc)
 {
     js::mjit::JITScript *jit = getJIT(constructing);
     JS_ASSERT(pc >= code && pc < code + length);
-    void* native = bsearch_nmap(jit->nmap, jit->nNmapPairs, (size_t)(pc - code));
+    void* native = bsearch_nmap(jit->nmap(), jit->nNmapPairs, (size_t)(pc - code));
     JS_ASSERT(native);
     return native;
 }
 
 #ifdef _MSC_VER
 extern "C" void *JaegerThrowpoline(js::VMFrame *vmFrame);
 #else
 extern "C" void JaegerThrowpoline();
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -1034,18 +1034,19 @@ ic::SplatApplyArgs(VMFrame &f)
 void
 JITScript::purgeMICs()
 {
     if (!nMICs)
         return;
 
     Repatcher repatch(this);
 
+    ic::MICInfo *mics_ = mics();
     for (uint32 i = 0; i < nMICs; i++) {
-        ic::MICInfo &mic = mics[i];
+        ic::MICInfo &mic = mics_[i];
         switch (mic.kind) {
           case ic::MICInfo::SET:
           case ic::MICInfo::GET:
           {
             /* Patch shape guard. */
             repatch.repatch(mic.shape, int(JSObjectMap::INVALID_SHAPE));
 
             /* 
@@ -1076,18 +1077,19 @@ ic::PurgeMICs(JSContext *cx, JSScript *s
 void
 JITScript::nukeScriptDependentICs()
 {
     if (!nCallICs)
         return;
 
     Repatcher repatcher(this);
 
+    ic::CallICInfo *callICs_ = callICs();
     for (uint32 i = 0; i < nCallICs; i++) {
-        ic::CallICInfo &ic = callICs[i];
+        ic::CallICInfo &ic = callICs_[i];
         if (!ic.fastGuardedObject)
             continue;
         repatcher.repatch(ic.funGuard, NULL);
         repatcher.relink(ic.funJump, ic.slowPathStart);
         ic.releasePool(CallICInfo::Pool_ClosureStub);
         ic.fastGuardedObject = NULL;
         ic.hasJsFunCheck = false;
     }
@@ -1099,18 +1101,19 @@ JITScript::sweepCallICs(JSContext *cx, b
     Repatcher repatcher(this);
 
     /*
      * If purgeAll is set, purge stubs in the script except those covered by PurgePICs
      * (which is always called during GC). We want to remove references which can keep
      * alive pools that we are trying to destroy (see JSCompartment::sweep).
      */
 
+    ic::CallICInfo *callICs_ = callICs();
     for (uint32 i = 0; i < nCallICs; i++) {
-        ic::CallICInfo &ic = callICs[i];
+        ic::CallICInfo &ic = callICs_[i];
 
         /*
          * If the object is unreachable, we're guaranteed not to be currently
          * executing a stub generated by a guard on that object. This lets us
          * precisely GC call ICs while keeping the identity guard safe.
          */
         bool fastFunDead = ic.fastGuardedObject &&
             (purgeAll || IsAboutToBeFinalized(cx, ic.fastGuardedObject));
@@ -1139,18 +1142,19 @@ JITScript::sweepCallICs(JSContext *cx, b
         repatcher.relink(ic.funJump, ic.slowPathStart);
         ic.hit = false;
     }
 
     if (purgeAll) {
         /* Purge ICs generating stubs into execPools. */
         uint32 released = 0;
 
+        ic::EqualityICInfo *equalityICs_ = equalityICs();
         for (uint32 i = 0; i < nEqualityICs; i++) {
-            ic::EqualityICInfo &ic = equalityICs[i];
+            ic::EqualityICInfo &ic = equalityICs_[i];
             if (!ic.generated)
                 continue;
 
             JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, ic::Equality));
             repatcher.relink(ic.stubCall, fptr);
             repatcher.relink(ic.jumpToStub, ic.stubEntry);
 
             ic.generated = false;
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2697,18 +2697,19 @@ template void JS_FASTCALL ic::SetElement
 void
 JITScript::purgePICs()
 {
     if (!nPICs && !nGetElems && !nSetElems)
         return;
 
     Repatcher repatcher(this);
 
+    ic::PICInfo *pics_ = pics();
     for (uint32 i = 0; i < nPICs; i++) {
-        ic::PICInfo &pic = pics[i];
+        ic::PICInfo &pic = pics_[i];
         switch (pic.kind) {
           case ic::PICInfo::SET:
           case ic::PICInfo::SETMETHOD:
             SetPropCompiler::reset(repatcher, pic);
             break;
           case ic::PICInfo::NAME:
           case ic::PICInfo::XNAME:
             ScopeNameCompiler::reset(repatcher, pic);
@@ -2722,20 +2723,22 @@ JITScript::purgePICs()
             break;
           default:
             JS_NOT_REACHED("Unhandled PIC kind");
             break;
         }
         pic.reset();
     }
 
+    ic::GetElementIC *getElems_ = getElems();
+    ic::SetElementIC *setElems_ = setElems();
     for (uint32 i = 0; i < nGetElems; i++)
-        getElems[i].purge(repatcher);
+        getElems_[i].purge(repatcher);
     for (uint32 i = 0; i < nSetElems; i++)
-        setElems[i].purge(repatcher);
+        setElems_[i].purge(repatcher);
 }
 
 void
 ic::PurgePICs(JSContext *cx, JSScript *script)
 {
     if (script->jitNormal)
         script->jitNormal->purgePICs();
     if (script->jitCtor)
--- a/js/src/methodjit/Retcon.cpp
+++ b/js/src/methodjit/Retcon.cpp
@@ -71,21 +71,22 @@ AutoScriptRetrapper::untrap(jsbytecode *
     *pc = JS_GetTrapOpcode(cx, script, pc);
     return true;
 }
 
 Recompiler::PatchableAddress
 Recompiler::findPatch(JITScript *jit, void **location)
 { 
     uint8* codeStart = (uint8 *)jit->code.m_code.executableAddress();
+    CallSite *callSites_ = jit->callSites();
     for (uint32 i = 0; i < jit->nCallSites; i++) {
-        if (jit->callSites[i].codeOffset + codeStart == *location) {
+        if (callSites_[i].codeOffset + codeStart == *location) {
             PatchableAddress result;
             result.location = location;
-            result.callSite = jit->callSites[i];
+            result.callSite = callSites_[i];
             return result;
         }
     }
 
     JS_NOT_REACHED("failed to find call site");
     return PatchableAddress();
 }
 
@@ -182,18 +183,19 @@ Recompiler::recompile()
     }
 
     return true;
 }
 
 bool
 Recompiler::saveTraps(JITScript *jit, Vector<CallSite> *sites)
 {
+    CallSite *callSites_ = jit->callSites();
     for (uint32 i = 0; i < jit->nCallSites; i++) {
-        CallSite &site = jit->callSites[i];
+        CallSite &site = callSites_[i];
         if (site.isTrap() && !sites->append(site))
             return false;
     }
     return true;
 }
 
 bool
 Recompiler::recompile(JSStackFrame *fp, Vector<PatchableAddress> &patches,