Split up MIC structures to avoid bloat (bug 627486 part 2, r=cdleary).
☠☠ backed out by 884ece114035 ☠ ☠
authorDavid Anderson <danderson@mozilla.com>
Tue, 01 Feb 2011 11:48:58 -0800
changeset 62037 aa1cf1121a203aac671b85ba308510976a9cf454
parent 62036 54a515a97151625ed10eb2096546ee40bb3ce95e
child 62038 a7a3317dac326fe906fffe2f241968e901b66a84
child 62041 884ece11403551ac0c3ceea021d05c34d2cf57a3
push idunknown
push userunknown
push dateunknown
reviewerscdleary
bugs627486
milestone2.0b11pre
Split up MIC structures to avoid bloat (bug 627486 part 2, r=cdleary).
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -92,17 +92,18 @@ mjit::Compiler::Compiler(JSContext *cx, 
     fun(fp->isFunctionFrame() && !fp->isEvalFrame()
         ? fp->fun()
         : NULL),
     isConstructing(fp->isConstructing()),
     analysis(NULL), jumpMap(NULL), savedTraps(NULL),
     frame(cx, script, fun, masm),
     branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
 #if defined JS_MONOIC
-    mics(CompilerAllocPolicy(cx, *thisFromCtor())),
+    getGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
+    setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
     callICs(CompilerAllocPolicy(cx, *thisFromCtor())),
     equalityICs(CompilerAllocPolicy(cx, *thisFromCtor())),
     traceICs(CompilerAllocPolicy(cx, *thisFromCtor())),
 #endif
 #if defined JS_POLYIC
     pics(CompilerAllocPolicy(cx, *thisFromCtor())), 
     getElemICs(CompilerAllocPolicy(cx, *thisFromCtor())),
     setElemICs(CompilerAllocPolicy(cx, *thisFromCtor())),
@@ -432,17 +433,18 @@ mjit::Compiler::finishThisUp(JITScript *
         if (opinfo && opinfo->safePoint)
             nNmapLive++;
     }
 
     /* Please keep in sync with JITScript::scriptDataSize! */
     size_t totalBytes = sizeof(JITScript) +
                         sizeof(NativeMapEntry) * nNmapLive +
 #if defined JS_MONOIC
-                        sizeof(ic::MICInfo) * mics.length() +
+                        sizeof(ic::GetGlobalNameIC) * getGlobalNames.length() +
+                        sizeof(ic::SetGlobalNameIC) * setGlobalNames.length() +
                         sizeof(ic::CallICInfo) * callICs.length() +
                         sizeof(ic::EqualityICInfo) * equalityICs.length() +
                         sizeof(ic::TraceICInfo) * traceICs.length() +
 #endif
 #if defined JS_POLYIC
                         sizeof(ic::PICInfo) * pics.length() +
                         sizeof(ic::GetElementIC) * getElemICs.length() +
                         sizeof(ic::SetElementIC) * setElemICs.length() +
@@ -484,56 +486,72 @@ mjit::Compiler::finishThisUp(JITScript *
     JS_ASSERT(ix == nNmapLive);
 
     if (fun) {
         jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
         jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
     }
 
 #if defined JS_MONOIC
-    jit->nMICs = mics.length();
-    if (mics.length()) {
-        jit->mics = (ic::MICInfo *)cursor;
-        cursor += sizeof(ic::MICInfo) * mics.length();
+    jit->nGetGlobalNames = getGlobalNames.length();
+    if (getGlobalNames.length()) {
+        jit->getGlobalNames = (ic::GetGlobalNameIC *)cursor;
+        cursor += sizeof(ic::GetGlobalNameIC) * getGlobalNames.length();
     } else {
-        jit->mics = NULL;
+        jit->getGlobalNames = NULL;
+    }
+
+    for (size_t i = 0; i < getGlobalNames.length(); i++) {
+        ic::GetGlobalNameIC &to = jit->getGlobalNames[i];
+        GetGlobalNameICInfo &from = getGlobalNames[i];
+        from.copyTo(to, fullCode, stubCode);
+
+        int offset = fullCode.locationOf(from.load) - to.fastPathStart;
+        to.loadStoreOffset = offset;
+        JS_ASSERT(to.loadStoreOffset == offset);
+
+        stubCode.patch(from.addrLabel, &to);
+    }
+
+    jit->nSetGlobalNames = setGlobalNames.length();
+    if (setGlobalNames.length()) {
+        jit->setGlobalNames = (ic::SetGlobalNameIC *)cursor;
+        cursor += sizeof(ic::SetGlobalNameIC) * setGlobalNames.length();
+    } else {
+        jit->setGlobalNames = NULL;
     }
 
-    if (ic::MICInfo *scriptMICs = jit->mics) {
-        for (size_t i = 0; i < mics.length(); i++) {
-            scriptMICs[i].kind = mics[i].kind;
-            scriptMICs[i].fastPathStart = fullCode.locationOf(mics[i].fastPathStart);
-            scriptMICs[i].slowPathStart = stubCode.locationOf(mics[i].slowPathStart);
-            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].usePropertyCache = mics[i].usePropertyCache;
-            scriptMICs[i].extraShapeGuard = 0;
-            scriptMICs[i].objConst = mics[i].objConst;
-            scriptMICs[i].shapeReg = mics[i].shapeReg;
-            scriptMICs[i].objReg = mics[i].objReg;
-            scriptMICs[i].vr = mics[i].vr;
-
-            if (mics[i].kind == ic::MICInfo::SET) {
-                int offset = fullCode.locationOf(mics[i].shapeGuardJump) -
-                             scriptMICs[i].fastPathStart;
-                scriptMICs[i].inlineShapeJump = offset;
-                JS_ASSERT(scriptMICs[i].inlineShapeJump == offset);
-
-                offset = fullCode.locationOf(mics[i].fastPathRejoin) -
-                         scriptMICs[i].fastPathStart;
-                scriptMICs[i].fastRejoinOffset = offset;
-                JS_ASSERT(scriptMICs[i].fastRejoinOffset == offset);
-            }
-
-            stubCode.patch(mics[i].addrLabel, &scriptMICs[i]);
-        }
+    for (size_t i = 0; i < setGlobalNames.length(); i++) {
+        ic::SetGlobalNameIC &to = jit->setGlobalNames[i];
+        SetGlobalNameICInfo &from = setGlobalNames[i];
+        from.copyTo(to, fullCode, stubCode);
+        to.slowPathStart = stubCode.locationOf(from.slowPathStart);
+
+        int offset = fullCode.locationOf(from.store).labelAtOffset(0) -
+                     to.fastPathStart;
+        to.loadStoreOffset = offset;
+        JS_ASSERT(to.loadStoreOffset == offset);
+
+        to.extraShapeGuard = 0;
+        to.objConst = from.objConst;
+        to.shapeReg = from.shapeReg;
+        to.objReg = from.objReg;
+        to.vr = from.vr;
+
+        offset = fullCode.locationOf(from.shapeGuardJump) -
+                 to.fastPathStart;
+        to.inlineShapeJump = offset;
+        JS_ASSERT(to.inlineShapeJump == offset);
+
+        offset = fullCode.locationOf(from.fastPathRejoin) -
+                 to.fastPathStart;
+        to.fastRejoinOffset = offset;
+        JS_ASSERT(to.fastRejoinOffset == offset);
+
+        stubCode.patch(from.addrLabel, &to);
     }
 
     jit->nCallICs = callICs.length();
     if (callICs.length()) {
         jit->callICs = (ic::CallICInfo *)cursor;
         cursor += sizeof(ic::CallICInfo) * callICs.length();
     } else {
         jit->callICs = NULL;
@@ -2971,19 +2989,19 @@ mjit::Compiler::jsop_length()
     frame.pop();
     frame.pushSynced();
     return true;
 #endif
 }
 
 #ifdef JS_MONOIC
 void
-mjit::Compiler::passMICAddress(MICGenInfo &mic)
+mjit::Compiler::passMICAddress(GlobalNameICInfo &ic)
 {
-    mic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
+    ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
 }
 #endif
 
 #if defined JS_POLYIC
 void
 mjit::Compiler::passICAddress(BaseICInfo *ic)
 {
     ic->paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
@@ -4307,68 +4325,69 @@ mjit::Compiler::jsop_getgname(uint32 ind
         return;
     }
 #if defined JS_MONOIC
     jsop_bindgname();
 
     FrameEntry *fe = frame.peek(-1);
     JS_ASSERT(fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_OBJECT);
 
-    MICGenInfo mic(ic::MICInfo::GET);
+    GetGlobalNameICInfo ic;
     RESERVE_IC_SPACE(masm);
     RegisterID objReg;
     Jump shapeGuard;
 
-    mic.fastPathStart = masm.label();
+    ic.usePropertyCache = true;
+
+    ic.fastPathStart = masm.label();
     if (fe->isConstant()) {
         JSObject *obj = &fe->getValue().toObject();
         frame.pop();
         JS_ASSERT(obj->isNative());
 
         objReg = frame.allocReg();
 
         masm.load32FromImm(&obj->objShape, objReg);
         shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, objReg,
-                                            Imm32(int32(JSObjectMap::INVALID_SHAPE)), mic.shape);
+                                            Imm32(int32(JSObjectMap::INVALID_SHAPE)), ic.shape);
         masm.move(ImmPtr(obj), objReg);
     } else {
         objReg = frame.ownRegForData(fe);
         frame.pop();
         RegisterID reg = frame.allocReg();
 
         masm.loadShape(objReg, reg);
         shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, reg,
-                                            Imm32(int32(JSObjectMap::INVALID_SHAPE)), mic.shape);
+                                            Imm32(int32(JSObjectMap::INVALID_SHAPE)), ic.shape);
         frame.freeReg(reg);
     }
-    mic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(0));
+    stubcc.linkExit(shapeGuard, Uses(0));
 
     stubcc.leave();
-    passMICAddress(mic);
-    mic.call = OOL_STUBCALL(ic::GetGlobalName);
+    passMICAddress(ic);
+    ic.slowPathCall = OOL_STUBCALL(ic::GetGlobalName);
 
     /* Garbage value. */
     uint32 slot = 1 << 24;
 
     masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
     Address address(objReg, slot);
     
     /* Allocate any register other than objReg. */
     RegisterID treg = frame.allocReg();
     /* After dreg is loaded, it's safe to clobber objReg. */
     RegisterID dreg = objReg;
 
-    mic.load = masm.loadValueWithAddressOffsetPatch(address, treg, dreg);
+    ic.load = masm.loadValueWithAddressOffsetPatch(address, treg, dreg);
 
     frame.pushRegs(treg, dreg);
 
     stubcc.rejoin(Changes(1));
 
-    mic.fastPathRejoin = masm.label();
-    mics.append(mic);
+    getGlobalNames.append(ic);
 
 #else
     jsop_getgname_slow(index);
 #endif
 }
 
 void
 mjit::Compiler::jsop_setgname_slow(JSAtom *atom, bool usePropertyCache)
@@ -4386,79 +4405,79 @@ mjit::Compiler::jsop_setgname_slow(JSAto
 void
 mjit::Compiler::jsop_setgname(JSAtom *atom, bool usePropertyCache)
 {
 #if defined JS_MONOIC
     FrameEntry *objFe = frame.peek(-2);
     FrameEntry *fe = frame.peek(-1);
     JS_ASSERT_IF(objFe->isTypeKnown(), objFe->getKnownType() == JSVAL_TYPE_OBJECT);
 
-    MICGenInfo mic(ic::MICInfo::SET);
-    frame.pinEntry(fe, mic.vr);
+    SetGlobalNameICInfo ic;
+
+    frame.pinEntry(fe, ic.vr);
+    Jump shapeGuard;
 
     RESERVE_IC_SPACE(masm);
-    Jump shapeGuard;
-
-    mic.fastPathStart = masm.label();
+    ic.fastPathStart = masm.label();
     if (objFe->isConstant()) {
         JSObject *obj = &objFe->getValue().toObject();
         JS_ASSERT(obj->isNative());
 
-        mic.objReg = frame.allocReg();
-        mic.shapeReg = mic.objReg;
-        mic.objConst = true;
-
-        masm.load32FromImm(&obj->objShape, mic.shapeReg);
-        shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, mic.shapeReg,
+        ic.objReg = frame.allocReg();
+        ic.shapeReg = ic.objReg;
+        ic.objConst = true;
+
+        masm.load32FromImm(&obj->objShape, ic.shapeReg);
+        shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, ic.shapeReg,
                                             Imm32(int32(JSObjectMap::INVALID_SHAPE)),
-                                            mic.shape);
-        masm.move(ImmPtr(obj), mic.objReg);
+                                            ic.shape);
+        masm.move(ImmPtr(obj), ic.objReg);
     } else {
-        mic.objReg = frame.copyDataIntoReg(objFe);
-        mic.shapeReg = frame.allocReg();
-        mic.objConst = false;
-
-        masm.loadShape(mic.objReg, mic.shapeReg);
-        shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, mic.shapeReg,
+        ic.objReg = frame.copyDataIntoReg(objFe);
+        ic.shapeReg = frame.allocReg();
+        ic.objConst = false;
+
+        masm.loadShape(ic.objReg, ic.shapeReg);
+        shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, ic.shapeReg,
                                             Imm32(int32(JSObjectMap::INVALID_SHAPE)),
-                                            mic.shape);
-        frame.freeReg(mic.shapeReg);
+                                            ic.shape);
+        frame.freeReg(ic.shapeReg);
     }
-    mic.shapeGuardJump = shapeGuard;
-    mic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(2));
+    ic.shapeGuardJump = shapeGuard;
+    ic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(2));
 
     stubcc.leave();
-    passMICAddress(mic);
-    mic.call = OOL_STUBCALL(ic::SetGlobalName);
+    passMICAddress(ic);
+    ic.slowPathCall = OOL_STUBCALL(ic::SetGlobalName);
 
     /* Garbage value. */
     uint32 slot = 1 << 24;
 
-    mic.usePropertyCache = usePropertyCache;
-
-    masm.loadPtr(Address(mic.objReg, offsetof(JSObject, slots)), mic.objReg);
-    Address address(mic.objReg, slot);
-
-    if (mic.vr.isConstant()) {
-        mic.store = masm.storeValueWithAddressOffsetPatch(mic.vr.value(), address);
-    } else if (mic.vr.isTypeKnown()) {
-        mic.store = masm.storeValueWithAddressOffsetPatch(ImmType(mic.vr.knownType()),
-                                                          mic.vr.dataReg(), address);
+    ic.usePropertyCache = usePropertyCache;
+
+    masm.loadPtr(Address(ic.objReg, offsetof(JSObject, slots)), ic.objReg);
+    Address address(ic.objReg, slot);
+
+    if (ic.vr.isConstant()) {
+        ic.store = masm.storeValueWithAddressOffsetPatch(ic.vr.value(), address);
+    } else if (ic.vr.isTypeKnown()) {
+        ic.store = masm.storeValueWithAddressOffsetPatch(ImmType(ic.vr.knownType()),
+                                                          ic.vr.dataReg(), address);
     } else {
-        mic.store = masm.storeValueWithAddressOffsetPatch(mic.vr.typeReg(), mic.vr.dataReg(), address);
+        ic.store = masm.storeValueWithAddressOffsetPatch(ic.vr.typeReg(), ic.vr.dataReg(), address);
     }
 
-    frame.freeReg(mic.objReg);
-    frame.unpinEntry(mic.vr);
+    frame.freeReg(ic.objReg);
+    frame.unpinEntry(ic.vr);
     frame.shimmy(1);
 
     stubcc.rejoin(Changes(1));
 
-    mic.fastPathRejoin = masm.label();
-    mics.append(mic);
+    ic.fastPathRejoin = masm.label();
+    setGlobalNames.append(ic);
 #else
     jsop_setgname_slow(atom, usePropertyCache);
 #endif
 }
 
 void
 mjit::Compiler::jsop_setelem_slow()
 {
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -62,34 +62,48 @@ class Compiler : public BaseCompiler
           : jump(j), pc(pc)
         { }
 
         Jump jump;
         jsbytecode *pc;
     };
 
 #if defined JS_MONOIC
-    struct MICGenInfo {
-        MICGenInfo(ic::MICInfo::Kind kind) : kind(kind)
-        { }
+    struct GlobalNameICInfo {
         Label fastPathStart;
+        Call slowPathCall;
+        DataLabel32 shape;
+        DataLabelPtr addrLabel;
+        bool usePropertyCache;
+
+        void copyTo(ic::GlobalNameIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
+            to.fastPathStart = full.locationOf(fastPathStart);
+
+            int offset = full.locationOf(shape) - to.fastPathStart;
+            to.shapeOffset = offset;
+            JS_ASSERT(to.shapeOffset == offset);
+
+            to.slowPathCall = stub.locationOf(slowPathCall);
+            to.usePropertyCache = usePropertyCache;
+        }
+    };
+
+    struct GetGlobalNameICInfo : public GlobalNameICInfo {
+        Label load;
+    };
+
+    struct SetGlobalNameICInfo : public GlobalNameICInfo {
         Label slowPathStart;
         Label fastPathRejoin;
-        Label load;
-        DataLabel32 shape;
-        DataLabelPtr addrLabel;
         DataLabel32 store;
-        Call call;
-        ic::MICInfo::Kind kind;
         Jump shapeGuardJump;
         ValueRemat vr;
         RegisterID objReg;
         RegisterID shapeReg;
         bool objConst;
-        bool usePropertyCache;
     };
 
     struct EqualityGenInfo {
         DataLabelPtr addrLabel;
         Label stubEntry;
         Call stubCall;
         BoolStub stub;
         MaybeJump jumpToStub;
@@ -322,17 +336,18 @@ class Compiler : public BaseCompiler
     analyze::Script *analysis;
     Label *jumpMap;
     bool *savedTraps;
     jsbytecode *PC;
     Assembler masm;
     FrameState frame;
     js::Vector<BranchPatch, 64, CompilerAllocPolicy> branchPatches;
 #if defined JS_MONOIC
-    js::Vector<MICGenInfo, 64, CompilerAllocPolicy> mics;
+    js::Vector<GetGlobalNameICInfo, 16, CompilerAllocPolicy> getGlobalNames;
+    js::Vector<SetGlobalNameICInfo, 16, CompilerAllocPolicy> setGlobalNames;
     js::Vector<CallGenInfo, 64, CompilerAllocPolicy> callICs;
     js::Vector<EqualityGenInfo, 64, CompilerAllocPolicy> equalityICs;
     js::Vector<TraceGenInfo, 64, CompilerAllocPolicy> traceICs;
 #endif
 #if defined JS_POLYIC
     js::Vector<PICGenInfo, 16, CompilerAllocPolicy> pics;
     js::Vector<GetElementICInfo, 16, CompilerAllocPolicy> getElemICs;
     js::Vector<SetElementICInfo, 16, CompilerAllocPolicy> setElemICs;
@@ -394,17 +409,17 @@ class Compiler : public BaseCompiler
     void iterNext();
     bool iterMore();
     void iterEnd();
     MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
 #ifdef JS_POLYIC
     void passICAddress(BaseICInfo *ic);
 #endif
 #ifdef JS_MONOIC
-    void passMICAddress(MICGenInfo &mic);
+    void passMICAddress(GlobalNameICInfo &mic);
 #endif
     bool constructThis();
 
     /* Opcode handlers. */
     bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL);
     void jsop_bindname(JSAtom *atom, bool usePropCache);
     void jsop_setglobal(uint32 index);
     void jsop_getglobal(uint32 index);
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -840,17 +840,18 @@ mjit::JITScript::~JITScript()
 
 /* Please keep in sync with Compiler::finishThisUp! */
 size_t
 mjit::JITScript::scriptDataSize()
 {
     return sizeof(JITScript) +
         sizeof(NativeMapEntry) * nNmapPairs +
 #if defined JS_MONOIC
-        sizeof(ic::MICInfo) * nMICs +
+        sizeof(ic::GetGlobalNameIC) * nGetGlobalNames +
+        sizeof(ic::SetGlobalNameIC) * nSetGlobalNames +
         sizeof(ic::CallICInfo) * nCallICs +
         sizeof(ic::EqualityICInfo) * nEqualityICs +
         sizeof(ic::TraceICInfo) * nTraceICs +
 #endif
 #if defined JS_POLYIC
         sizeof(ic::PICInfo) * nPICs +
         sizeof(ic::GetElementIC) * nGetElems +
         sizeof(ic::SetElementIC) * nSetElems +
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -241,17 +241,18 @@ class CompilerAllocPolicy : public Conte
 
 namespace ic {
 # if defined JS_POLYIC
     struct PICInfo;
     struct GetElementIC;
     struct SetElementIC;
 # endif
 # if defined JS_MONOIC
-    struct MICInfo;
+    struct GetGlobalNameIC;
+    struct SetGlobalNameIC;
     struct EqualityICInfo;
     struct TraceICInfo;
     struct CallICInfo;
 # endif
 }
 }
 
 typedef void (JS_FASTCALL *VoidStub)(VMFrame &);
@@ -271,18 +272,18 @@ typedef void (JS_FASTCALL *VoidStubAtom)
 typedef JSString * (JS_FASTCALL *JSStrStub)(VMFrame &);
 typedef JSString * (JS_FASTCALL *JSStrStubUInt32)(VMFrame &, uint32);
 typedef void (JS_FASTCALL *VoidStubJSObj)(VMFrame &, JSObject *);
 typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *);
 typedef JSBool (JS_FASTCALL *BoolStubUInt32)(VMFrame &f, uint32);
 #ifdef JS_MONOIC
 typedef void (JS_FASTCALL *VoidStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *);
 typedef void * (JS_FASTCALL *VoidPtrStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *);
-typedef void (JS_FASTCALL *VoidStubMIC)(VMFrame &, js::mjit::ic::MICInfo *);
-typedef void * (JS_FASTCALL *VoidPtrStubMIC)(VMFrame &, js::mjit::ic::MICInfo *);
+typedef void (JS_FASTCALL *VoidStubGetGlobal)(VMFrame &, js::mjit::ic::GetGlobalNameIC *);
+typedef void (JS_FASTCALL *VoidStubSetGlobal)(VMFrame &, js::mjit::ic::SetGlobalNameIC *);
 typedef JSBool (JS_FASTCALL *BoolStubEqualityIC)(VMFrame &, js::mjit::ic::EqualityICInfo *);
 typedef void * (JS_FASTCALL *VoidPtrStubTraceIC)(VMFrame &, js::mjit::ic::TraceICInfo *);
 #endif
 #ifdef JS_POLYIC
 typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *);
 typedef void (JS_FASTCALL *VoidStubGetElemIC)(VMFrame &, js::mjit::ic::GetElementIC *);
 typedef void (JS_FASTCALL *VoidStubSetElemIC)(VMFrame &f, js::mjit::ic::SetElementIC *);
 #endif
@@ -306,37 +307,39 @@ struct JITScript {
 
     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;
+    ic::GetGlobalNameIC *getGlobalNames;
+    ic::SetGlobalNameIC *setGlobalNames;
+    ic::CallICInfo      *callICs;
+    ic::EqualityICInfo  *equalityICs;
+    ic::TraceICInfo     *traceICs;
 #endif
 #ifdef JS_POLYIC
-    ic::PICInfo     *pics;      /* PICs in this script */
-    ic::GetElementIC *getElems;
-    ic::SetElementIC *setElems;
+    ic::PICInfo         *pics;
+    ic::GetElementIC    *getElems;
+    ic::SetElementIC    *setElems;
 #endif
 
     uint32          nCallSites:31;
     bool            singleStepMode:1;   /* compiled in "single step mode" */
 #ifdef JS_MONOIC
-    uint32          nMICs;      /* number of MonoICs */
-    uint32          nCallICs;   /* number of call ICs */
+    uint32          nGetGlobalNames;
+    uint32          nSetGlobalNames;
+    uint32          nCallICs;
     uint32          nEqualityICs;
     uint32          nTraceICs;
 #endif
 #ifdef JS_POLYIC
-    uint32          nPICs;      /* number of PolyICs */
+    uint32          nPICs;
     uint32          nGetElems;
     uint32          nSetElems;
 #endif
 
 #ifdef JS_MONOIC
     // Additional ExecutablePools that IC stubs were generated into.
     typedef Vector<JSC::ExecutablePool *, 0, SystemAllocPolicy> ExecPoolVector;
     ExecPoolVector execPools;
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -68,109 +68,108 @@ typedef JSC::MacroAssembler::Imm32 Imm32
 typedef JSC::MacroAssembler::ImmPtr ImmPtr;
 typedef JSC::MacroAssembler::Call Call;
 typedef JSC::MacroAssembler::Label Label;
 typedef JSC::MacroAssembler::DataLabel32 DataLabel32;
 
 #if defined JS_MONOIC
 
 static void
-PatchGetFallback(VMFrame &f, ic::MICInfo *ic)
+PatchGetFallback(VMFrame &f, ic::GetGlobalNameIC *ic)
 {
     Repatcher repatch(f.jit());
     JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::GetGlobalName));
-    repatch.relink(ic->stubCall, fptr);
+    repatch.relink(ic->slowPathCall, fptr);
 }
 
 void JS_FASTCALL
-ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic)
+ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
 {
     JSObject *obj = f.fp()->scopeChain().getGlobal();
     JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
     jsid id = ATOM_TO_JSID(atom);
 
-    JS_ASSERT(ic->kind == ic::MICInfo::GET);
-
     const Shape *shape = obj->nativeLookup(id);
     if (!shape ||
         !shape->hasDefaultGetterOrIsMethod() ||
         !shape->hasSlot())
     {
         if (shape)
             PatchGetFallback(f, ic);
         stubs::GetGlobalName(f);
         return;
     }
     uint32 slot = shape->slot;
 
     /* Patch shape guard. */
     Repatcher repatcher(f.jit());
-    repatcher.repatch(ic->shape, obj->shape());
+    repatcher.repatch(ic->fastPathStart.dataLabel32AtOffset(ic->shapeOffset), obj->shape());
 
     /* Patch loads. */
-    repatcher.patchAddressOffsetForValueLoad(ic->load, slot * sizeof(Value));
+    JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset);
+    repatcher.patchAddressOffsetForValueLoad(label, slot * sizeof(Value));
 
     /* Do load anyway... this time. */
     stubs::GetGlobalName(f);
 }
 
 template <JSBool strict>
 static void JS_FASTCALL
-DisabledSetGlobal(VMFrame &f, ic::MICInfo *ic)
+DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic)
 {
     JSScript *script = f.fp()->script();
     JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc));
     stubs::SetGlobalName<strict>(f, atom);
 }
 
-template void JS_FASTCALL DisabledSetGlobal<true>(VMFrame &f, ic::MICInfo *ic);
-template void JS_FASTCALL DisabledSetGlobal<false>(VMFrame &f, ic::MICInfo *ic);
+template void JS_FASTCALL DisabledSetGlobal<true>(VMFrame &f, ic::SetGlobalNameIC *ic);
+template void JS_FASTCALL DisabledSetGlobal<false>(VMFrame &f, ic::SetGlobalNameIC *ic);
 
 template <JSBool strict>
 static void JS_FASTCALL
-DisabledSetGlobalNoCache(VMFrame &f, ic::MICInfo *ic)
+DisabledSetGlobalNoCache(VMFrame &f, ic::SetGlobalNameIC *ic)
 {
     JSScript *script = f.fp()->script();
     JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc));
     stubs::SetGlobalNameNoCache<strict>(f, atom);
 }
 
-template void JS_FASTCALL DisabledSetGlobalNoCache<true>(VMFrame &f, ic::MICInfo *ic);
-template void JS_FASTCALL DisabledSetGlobalNoCache<false>(VMFrame &f, ic::MICInfo *ic);
+template void JS_FASTCALL DisabledSetGlobalNoCache<true>(VMFrame &f, ic::SetGlobalNameIC *ic);
+template void JS_FASTCALL DisabledSetGlobalNoCache<false>(VMFrame &f, ic::SetGlobalNameIC *ic);
 
 static void
-PatchSetFallback(VMFrame &f, ic::MICInfo *ic)
+PatchSetFallback(VMFrame &f, ic::SetGlobalNameIC *ic)
 {
     JSScript *script = f.fp()->script();
 
     Repatcher repatch(f.jit());
-    VoidStubMIC stub = ic->usePropertyCache
-                       ? STRICT_VARIANT(DisabledSetGlobal)
-                       : STRICT_VARIANT(DisabledSetGlobalNoCache);
+    VoidStubSetGlobal stub = ic->usePropertyCache
+                             ? STRICT_VARIANT(DisabledSetGlobal)
+                             : STRICT_VARIANT(DisabledSetGlobalNoCache);
     JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stub));
-    repatch.relink(ic->stubCall, fptr);
+    repatch.relink(ic->slowPathCall, fptr);
 }
 
 static LookupStatus
-UpdateSetGlobalNameStub(VMFrame &f, ic::MICInfo *ic, JSObject *obj, const Shape *shape)
+UpdateSetGlobalNameStub(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Shape *shape)
 {
     Repatcher repatcher(ic->extraStub);
 
     JSC::CodeLocationLabel label(JSC::MacroAssemblerCodePtr(ic->extraStub.start()));
     repatcher.repatch(label.dataLabel32AtOffset(ic->extraShapeGuard), obj->shape());
 
     label = label.labelAtOffset(ic->extraStoreOffset);
     repatcher.patchAddressOffsetForValueStore(label, shape->slot * sizeof(Value),
                                               ic->vr.isTypeKnown());
 
     return Lookup_Cacheable;
 }
 
 static LookupStatus
-AttachSetGlobalNameStub(VMFrame &f, ic::MICInfo *ic, JSObject *obj, const Shape *shape)
+AttachSetGlobalNameStub(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Shape *shape)
 {
     Assembler masm;
 
     Label start = masm.label();
 
     DataLabel32 shapeLabel;
     Jump guard = masm.branch32WithPatch(Assembler::NotEqual, ic->shapeReg, Imm32(obj->shape()),
                                         shapeLabel);
@@ -242,17 +241,17 @@ AttachSetGlobalNameStub(VMFrame &f, ic::
     offset = linker.locationOf(store) - linker.locationOf(start);
     ic->extraStoreOffset = offset;
     JS_ASSERT(ic->extraStoreOffset == offset);
 
     return Lookup_Cacheable;
 }
 
 static LookupStatus
-UpdateGlobalName(VMFrame &f, ic::MICInfo *ic, JSObject *obj, const Shape *shape)
+UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Shape *shape)
 {
     /* Give globals a chance to appear. */
     if (!shape)
         return Lookup_Uncacheable;
 
     if (shape->isMethod() ||
         !shape->hasDefaultSetter() ||
         !shape->writable() ||
@@ -285,32 +284,34 @@ UpdateGlobalName(VMFrame &f, ic::MICInfo
         if (ic->extraShapeGuard)
             return UpdateSetGlobalNameStub(f, ic, obj, shape);
 
         return AttachSetGlobalNameStub(f, ic, obj, shape);
     }
 
     /* Object is not branded, so we can use the inline path. */
     Repatcher repatcher(f.jit());
-    repatcher.repatch(ic->shape, obj->shape());
-    repatcher.patchAddressOffsetForValueStore(ic->load, shape->slot * sizeof(Value),
+    repatcher.repatch(ic->fastPathStart.dataLabel32AtOffset(ic->shapeOffset), obj->shape());
+
+    JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset);
+    repatcher.patchAddressOffsetForValueStore(label, shape->slot * sizeof(Value),
                                               ic->vr.isTypeKnown());
 
     return Lookup_Cacheable;
 }
 
 void JS_FASTCALL
-ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
+ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic)
 {
     JSObject *obj = f.fp()->scopeChain().getGlobal();
     JSScript *script = f.fp()->script();
     JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc));
     const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom));
 
-    LookupStatus status = UpdateGlobalName(f, ic, obj, shape);
+    LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape);
     if (status == Lookup_Error)
         THROW();
 
     if (ic->usePropertyCache)
         STRICT_VARIANT(stubs::SetGlobalName)(f, atom);
     else
         STRICT_VARIANT(stubs::SetGlobalNameNoCache)(f, atom);
 }
@@ -1153,40 +1154,31 @@ ic::SplatApplyArgs(VMFrame &f)
 
     f.u.call.dynamicArgc = n;
     return true;
 }
 
 void
 JITScript::purgeMICs()
 {
-    if (!nMICs)
+    if (!nGetGlobalNames || !nSetGlobalNames)
         return;
 
     Repatcher repatch(this);
 
-    for (uint32 i = 0; i < nMICs; 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));
+    for (uint32 i = 0; i < nGetGlobalNames; i++) {
+        ic::GetGlobalNameIC &ic = getGlobalNames[i];
+        JSC::CodeLocationDataLabel32 label = ic.fastPathStart.dataLabel32AtOffset(ic.shapeOffset);
+        repatch.repatch(label, int(JSObjectMap::INVALID_SHAPE));
+    }
 
-            /* 
-             * If the stub call was patched, leave it alone -- it probably will
-             * just be invalidated again.
-             */
-            break;
-          }
-          default:
-            JS_NOT_REACHED("Unknown MIC type during purge");
-            break;
-        }
+    for (uint32 i = 0; i < nSetGlobalNames; i++) {
+        ic::SetGlobalNameIC &ic = setGlobalNames[i];
+        JSC::CodeLocationDataLabel32 label = ic.fastPathStart.dataLabel32AtOffset(ic.shapeOffset);
+        repatch.repatch(label, int(JSObjectMap::INVALID_SHAPE));
     }
 }
 
 void
 ic::PurgeMICs(JSContext *cx, JSScript *script)
 {
     /* MICs are purged during GC to handle changing shapes. */
     JS_ASSERT(cx->runtime->gcRegenShapes);
@@ -1276,21 +1268,20 @@ JITScript::sweepCallICs(JSContext *cx, b
             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;
             released++;
         }
 
-        for (uint32 i = 0; i < nMICs; i ++) {
-            ic::MICInfo &ic = mics[i];
+        for (uint32 i = 0; i < nSetGlobalNames; i++) {
+            ic::SetGlobalNameIC &ic = setGlobalNames[i];
             if (!ic.extraShapeGuard)
                 continue;
-            JS_ASSERT(ic.kind == ic::MICInfo::SET);
             repatcher.relink(ic.fastPathStart.jumpAtOffset(ic.inlineShapeJump), ic.slowPathStart);
             ic.extraShapeGuard = 0;
             released++;
         }
 
         JS_ASSERT(released == execPools.length());
         for (uint32 i = 0; i < released; i++)
             execPools[i]->release();
--- a/js/src/methodjit/MonoIC.h
+++ b/js/src/methodjit/MonoIC.h
@@ -86,53 +86,54 @@ class FrameSize
 
     uint32 getArgc(VMFrame &f) const {
         return isStatic() ? staticArgc() : f.u.call.dynamicArgc;
     }
 };
 
 namespace ic {
 
-struct MICInfo {
-    enum Kind
-#ifdef _MSC_VER
-    : uint8_t
-#endif
-    {
-        GET,
-        SET
-    };
-
+struct GlobalNameIC
+{
     typedef JSC::MacroAssembler::RegisterID RegisterID;
 
-    JSC::CodeLocationLabel fastPathStart;
-    JSC::CodeLocationLabel slowPathStart;
+    JSC::CodeLocationLabel  fastPathStart;
+    JSC::CodeLocationCall   slowPathCall;
 
     /*
      * - ARM and x64 always emit exactly one instruction which needs to be
      *   patched. On ARM, the label points to the patched instruction, whilst
      *   on x64 it points to the instruction after it.
      * - For x86, the label "load" points to the start of the load/store
      *   sequence, which may consist of one or two "mov" instructions. Because
      *   of this, x86 is the only platform which requires non-trivial patching
      *   code.
      */
-    JSC::CodeLocationLabel load;
-    JSC::CodeLocationDataLabel32 shape;
-    JSC::CodeLocationCall stubCall;
+    int32 loadStoreOffset   : 15;
+    int32 shapeOffset       : 15;
+    bool usePropertyCache   : 1;
+};
+
+struct GetGlobalNameIC : public GlobalNameIC
+{
+};
+
+struct SetGlobalNameIC : public GlobalNameIC
+{
+    JSC::CodeLocationLabel  slowPathStart;
+
+    /* Dynamically generted stub for method-write checks. */
+    JSC::JITCode            extraStub;
 
     /* SET only, if we had to generate an out-of-line path. */
-    Kind kind : 2;
-    bool usePropertyCache : 1;
     int inlineShapeJump : 10;   /* Offset into inline path for shape jump. */
     int extraShapeGuard : 6;    /* Offset into stub for shape guard. */
     bool objConst : 1;          /* True if the object is constant. */
     RegisterID objReg   : 5;    /* Register for object, if objConst is false. */
     RegisterID shapeReg : 5;    /* Register for shape; volatile. */
-    JSC::JITCode extraStub;     /* Out-of-line generated stub. */
 
     int fastRejoinOffset : 16;  /* Offset from fastPathStart to rejoin. */
     int extraStoreOffset : 16;  /* Offset into store code. */
 
     /* SET only. */
     ValueRemat vr;              /* RHS value. */
 };
 
@@ -154,18 +155,18 @@ struct TraceICInfo {
     uint32 loopCounterStart;
 
     bool initialized : 1;
     bool hasSlowTraceHint : 1;
 };
 
 static const uint16 BAD_TRACEIC_INDEX = (uint16)0xffff;
 
-void JS_FASTCALL GetGlobalName(VMFrame &f, ic::MICInfo *ic);
-void JS_FASTCALL SetGlobalName(VMFrame &f, ic::MICInfo *ic);
+void JS_FASTCALL GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic);
+void JS_FASTCALL SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic);
 
 struct EqualityICInfo {
     typedef JSC::MacroAssembler::RegisterID RegisterID;
 
     JSC::CodeLocationLabel stubEntry;
     JSC::CodeLocationCall stubCall;
     BoolStub stub;
     JSC::CodeLocationLabel target;