Bug 817107 - Mark stubcodes during compilation, mark TypeUpdate IC chain stubCodes, and move IC stub space allocation to custom LIFO alloc pools. r=jandem
authorKannan Vijayan <kvijayan@mozilla.com>
Tue, 04 Dec 2012 12:45:22 -0500
changeset 114953 d37fb0c8a33b1e348a3c6d9bce1b1be4e9e860bc
parent 114952 74dbf66a4181aade5ffcebe50535aba89dab6272
child 114954 57ac3802239e9792fac0d07ab0660e8ba84cae24
push id1388
push userkvijayan@mozilla.com
push dateTue, 04 Dec 2012 17:45:28 +0000
reviewersjandem
bugs817107
milestone20.0a1
Bug 817107 - Mark stubcodes during compilation, mark TypeUpdate IC chain stubCodes, and move IC stub space allocation to custom LIFO alloc pools. r=jandem
js/src/gc/RootMarking.cpp
js/src/ion/BaselineCompiler.cpp
js/src/ion/BaselineCompiler.h
js/src/ion/BaselineIC.cpp
js/src/ion/BaselineIC.h
js/src/ion/BaselineJIT.cpp
js/src/ion/BaselineJIT.h
js/src/ion/shared/BaselineCompiler-shared.cpp
js/src/ion/shared/BaselineCompiler-shared.h
js/src/jsapi.h
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -15,16 +15,17 @@
 #include "jswatchpoint.h"
 
 #include "frontend/Parser.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #ifdef JS_ION
 # include "ion/IonMacroAssembler.h"
 # include "ion/IonFrameIterator.h"
+# include "ion/BaselineCompiler.h"
 #endif
 #include "js/HashTable.h"
 #include "vm/Debugger.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
@@ -579,16 +580,23 @@ AutoGCRooter::trace(JSTracer *trc)
 
       case IONMASM: {
 #ifdef JS_ION
         static_cast<js::ion::MacroAssembler::AutoRooter *>(this)->masm()->trace(trc);
 #endif
         return;
       }
 
+      case BASELINECOMPILER: {
+#ifdef JS_ION
+        static_cast<js::ion::BaselineCompiler::AutoRooter *>(this)->compiler()->trace(trc);
+#endif
+        return;
+      }
+
       case IONALLOC: {
 #ifdef JS_ION
         static_cast<js::ion::AutoTempAllocatorRooter *>(this)->trace(trc);
 #endif
         return;
       }
 
       case WRAPPER: {
--- a/js/src/ion/BaselineCompiler.cpp
+++ b/js/src/ion/BaselineCompiler.cpp
@@ -15,17 +15,18 @@
 #include "VMFunctions.h"
 #include "IonFrames-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
 BaselineCompiler::BaselineCompiler(JSContext *cx, JSScript *script)
   : BaselineCompilerSpecific(cx, script),
-    return_(new HeapLabel())
+    return_(new HeapLabel()),
+    autoRooter_(cx, this)
 {
 }
 
 bool
 BaselineCompiler::init()
 {
     if (!labels_.init(script->length))
         return false;
@@ -45,16 +46,19 @@ BaselineCompiler::compile()
     IonSpew(IonSpew_Scripts, "Baseline compiling script %s:%d (%p)",
             script->filename, script->lineno, script);
 
     if (script->needsArgsObj()) {
         IonSpew(IonSpew_Abort, "Script needs arguments object");
         return Method_CantCompile;
     }
 
+    // Pin analysis info during compilation.
+    analyze::AutoEnterAnalysis autoEnterAnalysis(cx);
+
     if (!emitPrologue())
         return Method_Error;
 
     MethodStatus status = emitBody();
     if (status != Method_Compiled)
         return status;
 
     if (!emitEpilogue())
@@ -79,29 +83,46 @@ BaselineCompiler::compile()
             (void *) script->baseline, (void *) code->raw());
 
     script->baseline->setMethod(code);
 
     // Copy IC entries
     if (icEntries_.length())
         baselineScript->copyICEntries(&icEntries_[0], masm);
 
+    // Adopt fallback stubs from the compiler into the baseline script.
+    baselineScript->adoptFallbackStubs(&stubSpace_);
+
     // Patch IC loads using IC entries
     for (size_t i = 0; i < icLoadLabels_.length(); i++) {
         CodeOffsetLabel label = icLoadLabels_[i];
         label.fixup(&masm);
         ICEntry *entryAddr = &(baselineScript->icEntry(i));
         Assembler::patchDataWithValueCheck(CodeLocationLabel(code, label),
                                            ImmWord(uintptr_t(entryAddr)),
                                            ImmWord(uintptr_t(-1)));
     }
 
     return Method_Compiled;
 }
 
+void
+BaselineCompiler::trace(JSTracer *trc)
+{
+    // The stubcodes that have been allocated for the ICs that have been compiled
+    // so far need to marked.  There should only be fallback stubs in any IC chains.
+    for (size_t i = 0; i < icEntries_.length(); i++) {
+        ICEntry &entry = icEntries_[i];
+        JS_ASSERT(entry.firstStub() != NULL);
+        JS_ASSERT(entry.firstStub()->isFallback());
+        JS_ASSERT(entry.firstStub()->next() == NULL);
+        entry.firstStub()->trace(trc);
+    }
+}
+
 #ifdef DEBUG
 #define SPEW_OPCODE()                                                         \
     JS_BEGIN_MACRO                                                            \
         if (IsJaegerSpewChannelActive(JSpew_JSOps)) {                         \
             Sprinter sprinter(cx);                                            \
             sprinter.init();                                                  \
             RootedScript script_(cx, script);                                 \
             js_Disassemble1(cx, script_, pc, pc - script_->code,              \
@@ -256,17 +277,17 @@ BaselineCompiler::emit_JSOP_GOTO()
     return true;
 }
 
 bool
 BaselineCompiler::emitToBoolean()
 {
     // Allocate IC entry and stub.
     ICToBool_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // CODEGEN
 
     // Call IC
     CodeOffsetLabel patchOffset;
     EmitCallIC(&patchOffset, masm);
@@ -327,17 +348,17 @@ BaselineCompiler::emit_JSOP_OR()
     return emitAndOr(true);
 }
 
 bool
 BaselineCompiler::emit_JSOP_POS()
 {
     // Allocate IC entry and stub.
     ICToNumber_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // Keep top stack value in R0.
     frame.popRegsAndSync(1);
 
     // Inline path for int32 and double.
     Label done;
@@ -548,17 +569,17 @@ BaselineCompiler::emit_JSOP_MUL()
     return emitBinaryArith();
 }
 
 bool
 BaselineCompiler::emitBinaryArith()
 {
     // Allocate IC entry and stub.
     ICBinaryArith_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // Keep top JSStack value in R0 and R2
     frame.popRegsAndSync(2);
 
     // Call IC
     CodeOffsetLabel patchOffset;
@@ -572,17 +593,17 @@ BaselineCompiler::emitBinaryArith()
     return true;
 }
 
 bool
 BaselineCompiler::emitUnaryArith()
 {
     // Allocate IC entry and stub.
     ICUnaryArith_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // Keep top stack value in R0.
     frame.popRegsAndSync(1);
 
     // Call IC
     CodeOffsetLabel patchOffset;
@@ -644,17 +665,17 @@ BaselineCompiler::emit_JSOP_NE()
     return emitCompare();
 }
 
 bool
 BaselineCompiler::emitCompare()
 {
     // Allocate IC entry and stub.
     ICCompare_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // CODEGEN
 
     // Keep top JSStack value in R0 and R2.
     frame.popRegsAndSync(2);
 
@@ -670,17 +691,17 @@ BaselineCompiler::emitCompare()
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_GETELEM()
 {
     // Allocate IC entry and stub.
     ICGetElem_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // Keep top two stack values in R0 and R1.
     frame.popRegsAndSync(2);
 
     // Call IC.
     CodeOffsetLabel patchOffset;
@@ -694,17 +715,17 @@ BaselineCompiler::emit_JSOP_GETELEM()
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_SETELEM()
 {
     // Allocate IC entry and stub.
     ICSetElem_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // Store RHS in the scratch slot.
     storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
     frame.pop();
 
     // Keep object and index in R0 and R1.
@@ -740,17 +761,17 @@ BaselineCompiler::emit_JSOP_GETGNAME()
         frame.push(cx->runtime->positiveInfinityValue);
         return true;
     }
 
     frame.syncStack(0);
 
     // Allocate IC entry and stub.
     ICGetName_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     masm.movePtr(ImmGCPtr(&script->global()), R0.scratchReg());
 
     // Call IC.
     CodeOffsetLabel patchOffset;
     EmitCallIC(&patchOffset, masm);
@@ -842,17 +863,17 @@ BaselineCompiler::emitCall()
 
     uint32_t argc = GET_ARGC(pc);
 
     frame.syncStack(0);
     masm.mov(Imm32(argc), R0.scratchReg());
 
     // Allocate IC entry and stub.
     ICCall_Fallback::Compiler stubCompiler(cx);
-    ICEntry *entry = allocateICEntry(stubCompiler.getStub());
+    ICEntry *entry = allocateICEntry(stubCompiler.getStub(&stubSpace_));
     if (!entry)
         return false;
 
     // Call IC
     CodeOffsetLabel patchOffset;
     EmitCallIC(&patchOffset, masm);
     entry->setReturnOffset(masm.currentOffset());
     if (!addICLoadLabel(patchOffset))
@@ -888,16 +909,18 @@ BaselineCompiler::emit_JSOP_FUNAPPLY()
     return emitCall();
 }
 
 bool
 BaselineCompiler::emit_JSOP_RETURN()
 {
     JS_ASSERT(frame.stackDepth() == 1);
 
+    JS_GC(cx->runtime);
+
     frame.popValue(JSReturnOperand);
     masm.jump(return_);
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_STOP()
 {
--- a/js/src/ion/BaselineCompiler.h
+++ b/js/src/ion/BaselineCompiler.h
@@ -102,17 +102,36 @@ class BaselineCompiler : public Baseline
     }
 
   public:
     BaselineCompiler(JSContext *cx, JSScript *script);
     bool init();
 
     MethodStatus compile();
 
+    class AutoRooter : public AutoGCRooter
+    {
+        BaselineCompiler *compiler_;
+
+      public:
+        AutoRooter(JSContext *cx, BaselineCompiler *compiler)
+          : AutoGCRooter(cx, BASELINECOMPILER),
+            compiler_(compiler)
+        { }
+
+        BaselineCompiler *compiler() const {
+            return compiler_;
+        }
+    };
+
+    void trace(JSTracer *trc);
+
   private:
+    AutoRooter autoRooter_;
+
     MethodStatus emitBody();
 
     bool emitPrologue();
     bool emitEpilogue();
 
     void storeValue(const StackValue *source, const Address &dest,
                     const ValueOperand &scratch);
 
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -14,47 +14,106 @@
 #include "VMFunctions.h"
 #include "IonFrames-inl.h"
 
 #include "jsinterpinlines.h"
 
 namespace js {
 namespace ion {
 
+void
+ICStub::markCode(JSTracer *trc, const char *name)
+{
+    IonCode *stubIonCode = ionCode();
+    MarkIonCodeUnbarriered(trc, &stubIonCode, name);
+}
+
+/* static */ void
+ICStub::trace(JSTracer *trc)
+{
+    markCode(trc, "baseline-stub-ioncode");
+
+    // If the stub is a monitored fallback stub, then mark the monitor ICs hanging
+    // off of that stub.  We don't need to worry about the regular monitored stubs,
+    // because the regular monitored stubs will always have a monitored fallback stub
+    // that references the same stub chain.
+    if (isMonitoredFallback()) {
+        ICTypeMonitor_Fallback *lastMonStub = toMonitoredFallbackStub()->fallbackMonitorStub();
+        for (ICStub *monStub = lastMonStub->firstMonitorStub();
+             monStub != NULL;
+             monStub = monStub->next())
+        {
+            JS_ASSERT_IF(monStub->next() == NULL, monStub == lastMonStub);
+            monStub->markCode(trc, "baseline-monitor-stub-ioncode");
+        }
+    }
+
+    if (isUpdated()) {
+        for (ICStub *updateStub = toUpdatedStub()->firstUpdateStub();
+             updateStub != NULL;
+             updateStub = updateStub->next())
+        {
+            JS_ASSERT_IF(updateStub->next() == NULL, updateStub->isTypeUpdate_Fallback());
+            updateStub->markCode(trc, "baseline-update-stub-ioncode");
+        }
+    }
+
+    switch (kind()) {
+      case ICStub::Call_Scripted: {
+        ICCall_Scripted *callStub = toCall_Scripted();
+        MarkObject(trc, &callStub->callee(), "baseline-callstub-callee");
+        break;
+      }
+      case ICStub::SetElem_Dense: {
+        ICSetElem_Dense *setElemStub = toSetElem_Dense();
+        MarkTypeObject(trc, &setElemStub->type(), "baseline-setelem-dense-stub-type");
+        break;
+      }
+      case ICStub::TypeMonitor_TypeObject: {
+        ICTypeMonitor_TypeObject *monitorStub = toTypeMonitor_TypeObject();
+        MarkTypeObject(trc, &monitorStub->type(), "baseline-monitor-typeobject");
+        break;
+      }
+      default:
+        break;
+    }
+}
+
+
 ICMonitoredStub::ICMonitoredStub(Kind kind, IonCode *stubCode, ICStub *firstMonitorStub)
   : ICStub(kind, ICStub::Monitored, stubCode),
     firstMonitorStub_(firstMonitorStub)
 {
     // If the first monitored stub is a ICTypeMonitor_Fallback stub, then
     // double check that _its_ firstMonitorStub is the same as this one.
     JS_ASSERT_IF(firstMonitorStub_->isTypeMonitor_Fallback(),
                  firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() ==
                     firstMonitorStub_);
 }
 
 bool
-ICMonitoredFallbackStub::initMonitoringChain(JSContext *cx)
+ICMonitoredFallbackStub::initMonitoringChain(JSContext *cx, ICStubSpace *space)
 {
     JS_ASSERT(fallbackMonitorStub_ == NULL);
 
     ICTypeMonitor_Fallback::Compiler compiler(cx, this);
-    ICTypeMonitor_Fallback *stub = compiler.getStub();
+    ICTypeMonitor_Fallback *stub = compiler.getStub(space);
     if (!stub)
         return false;
     fallbackMonitorStub_ = stub;
     return true;
 }
 
 bool
-ICUpdatedStub::initUpdatingChain(JSContext *cx)
+ICUpdatedStub::initUpdatingChain(JSContext *cx, ICStubSpace *space)
 {
     JS_ASSERT(firstUpdateStub_ == NULL);
 
     ICTypeUpdate_Fallback::Compiler compiler(cx);
-    ICTypeUpdate_Fallback *stub = compiler.getStub();
+    ICTypeUpdate_Fallback *stub = compiler.getStub(space);
     if (!stub)
         return false;
 
     firstUpdateStub_ = stub;
     return true;
 }
 
 IonCode *
@@ -126,39 +185,39 @@ ICStubCompiler::callTypeUpdateIC(MacroAs
     return true;
 }
 
 //
 // TypeMonitor_Fallback
 //
 
 bool
-ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleValue val)
+ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, ICStubSpace *space, HandleValue val)
 {
     bool wasEmptyMonitorChain = (numOptimizedMonitorStubs_ == 0);
 
     if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS) {
         // TODO: if the TypeSet becomes unknown or has the AnyObject type,
         // replace stubs with a single stub to handle these.
         return true;
     }
 
     if (val.isPrimitive()) {
         JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
         ICTypeMonitor_Type::Compiler compiler(cx, type);
-        ICStub *stub = compiler.getStub();
+        ICStub *stub = compiler.getStub(space);
         if (!stub)
             return false;
         addOptimizedMonitorStub(stub);
     } else {
         RootedTypeObject type(cx, val.toObject().getType(cx));
         if (!type)
             return false;
         ICTypeMonitor_TypeObject::Compiler compiler(cx, type);
-        ICStub *stub = compiler.getStub();
+        ICStub *stub = compiler.getStub(space);
         if (!stub)
             return false;
         addOptimizedMonitorStub(stub);
     }
 
     bool firstMonitorStubAdded = wasEmptyMonitorChain && (numOptimizedMonitorStubs_ > 0);
 
     if (firstMonitorStubAdded) {
@@ -189,17 +248,17 @@ DoTypeMonitorFallback(JSContext *cx, ICT
                       MutableHandleValue res)
 {
     RootedScript script(cx, GetTopIonJSScript(cx));
 
     // Monitor the pc.
     jsbytecode *pc = stub->mainFallbackStub()->icEntry()->pc(script);
     types::TypeScript::Monitor(cx, script, pc, value);
 
-    if (!stub->addMonitorStubForValue(cx, value))
+    if (!stub->addMonitorStubForValue(cx, ICStubSpace::StubSpaceFor(script), value))
         return false;
 
     // Copy input value to res.
     res.set(value);
     return true;
 }
 
 typedef bool (*DoTypeMonitorFallbackFn)(JSContext *, ICTypeMonitor_Fallback *, HandleValue,
@@ -362,17 +421,17 @@ DoCompareFallback(JSContext *cx, ICCompa
         // But for now we just bail.
         return true;
     }
 
     // Try to generate new stubs.
     if (lhs.isInt32()) {
         if (rhs.isInt32()) {
             ICCompare_Int32::Compiler compilerInt32(cx, op);
-            ICStub *int32Stub = compilerInt32.getStub();
+            ICStub *int32Stub = compilerInt32.getStub(ICStubSpace::StubSpaceFor(script));
             if (!int32Stub)
                 return false;
 
             stub->addNewStub(int32Stub);
         }
     }
 
     return true;
@@ -399,41 +458,43 @@ ICCompare_Fallback::Compiler::generateSt
 
 //
 // ToBool_Fallback
 //
 
 static bool
 DoToBoolFallback(JSContext *cx, ICToBool_Fallback *stub, HandleValue arg, MutableHandleValue ret)
 {
+    RootedScript script(cx, GetTopIonJSScript(cx));
+
     bool cond = ToBoolean(arg);
     ret.setBoolean(cond);
 
     // Check to see if a new stub should be generated.
     if (stub->numOptimizedStubs() >= ICToBool_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
         // But for now we just bail.
         return true;
     }
 
     // Try to generate new stubs.
     if (arg.isBoolean()) {
         // Attach the new bool-specialized stub.
         ICToBool_Bool::Compiler compilerBool(cx);
-        ICStub *boolStub = compilerBool.getStub();
+        ICStub *boolStub = compilerBool.getStub(ICStubSpace::StubSpaceFor(script));
         if (!boolStub)
             return false;
 
         stub->addNewStub(boolStub);
         return true;
     }
 
     if (arg.isInt32()) {
         ICToBool_Int32::Compiler compiler(cx);
-        ICStub *int32Stub = compiler.getStub();
+        ICStub *int32Stub = compiler.getStub(ICStubSpace::StubSpaceFor(script));
         if (!int32Stub)
             return false;
 
         stub->addNewStub(int32Stub);
         return true;
     }
 
     return true;
@@ -535,18 +596,17 @@ ICToNumber_Fallback::Compiler::generateS
 //
 // BinaryArith_Fallback
 //
 
 static bool
 DoBinaryArithFallback(JSContext *cx, ICBinaryArith_Fallback *stub, HandleValue lhs,
                       HandleValue rhs, MutableHandleValue ret)
 {
-    uint8_t *returnAddr;
-    RootedScript script(cx, GetTopIonJSScript(cx, NULL, (void **)&returnAddr));
+    RootedScript script(cx, GetTopIonJSScript(cx));
 
     // Perform the compare operation.
     JSOp op = JSOp(*stub->icEntry()->pc(script));
     switch(op) {
       case JSOP_ADD:
         // Do an add.
         if (!AddValues(cx, script, stub->icEntry()->pc(script), lhs, rhs, ret.address()))
             return false;
@@ -613,17 +673,17 @@ DoBinaryArithFallback(JSContext *cx, ICB
 
     if (!lhs.isInt32() || !rhs.isInt32())
         return true;
 
     // Try to generate new stubs.
     // TODO: unlink previous !allowDouble stub.
     bool allowDouble = ret.isDouble();
     ICBinaryArith_Int32::Compiler compilerInt32(cx, op, allowDouble);
-    ICStub *int32Stub = compilerInt32.getStub();
+    ICStub *int32Stub = compilerInt32.getStub(ICStubSpace::StubSpaceFor(script));
     if (!int32Stub)
         return false;
     stub->addNewStub(int32Stub);
     return true;
 }
 
 typedef bool (*DoBinaryArithFallbackFn)(JSContext *, ICBinaryArith_Fallback *, HandleValue, HandleValue,
                                         MutableHandleValue);
@@ -679,17 +739,17 @@ DoUnaryArithFallback(JSContext *cx, ICUn
         // TODO: Discard/replace stubs.
         return true;
     }
 
     if (!val.isInt32() || !res.isInt32())
         return true;
 
     ICUnaryArith_Int32::Compiler compiler(cx, op);
-    ICStub *int32Stub = compiler.getStub();
+    ICStub *int32Stub = compiler.getStub(ICStubSpace::StubSpaceFor(script));
     if (!int32Stub)
         return false;
     stub->addNewStub(int32Stub);
     return true;
 }
 
 typedef bool (*DoUnaryArithFallbackFn)(JSContext *, ICUnaryArith_Fallback *, HandleValue,
                                        MutableHandleValue);
@@ -712,16 +772,18 @@ ICUnaryArith_Fallback::Compiler::generat
 
 //
 // GetElem_Fallback
 //
 
 static bool
 DoGetElemFallback(JSContext *cx, ICGetElem_Fallback *stub, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
 {
+    RootedScript script(cx, GetTopIonJSScript(cx));
+
     if (!GetElementMonitored(cx, lhs, rhs, res))
         return false;
 
     if (stub->numOptimizedStubs() >= ICGetElem_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
         // But for now we just bail.
         return true;
     }
@@ -732,17 +794,17 @@ DoGetElemFallback(JSContext *cx, ICGetEl
 
     RootedObject obj(cx, &lhs.toObject());
     if (obj->isDenseArray() && rhs.isInt32()) {
         // Don't attach multiple dense array stubs.
         if (stub->hasStub(ICStub::GetElem_Dense))
             return true;
 
         ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub());
-        ICStub *denseStub = compiler.getStub();
+        ICStub *denseStub = compiler.getStub(ICStubSpace::StubSpaceFor(script));
         if (!denseStub)
             return false;
 
         stub->addNewStub(denseStub);
     }
 
     return true;
 }
@@ -832,17 +894,17 @@ DoSetElemFallback(JSContext *cx, ICSetEl
         // But for now we just bail.
         return true;
     }
 
     // Try to generate new stubs.
     if (obj->isDenseArray() && index.isInt32()) {
         RootedTypeObject type(cx, obj->getType(cx));
         ICSetElem_Dense::Compiler compiler(cx, type);
-        ICStub *denseStub = compiler.getStub();
+        ICStub *denseStub = compiler.getStub(ICStubSpace::StubSpaceFor(script));
         if (!denseStub)
             return false;
 
         stub->addNewStub(denseStub);
     }
 
     return true;
 }
@@ -1035,17 +1097,17 @@ DoCallFallback(JSContext *cx, ICCall_Fal
 
     RootedFunction fun(cx, obj->toFunction());
     if (obj->toFunction()->hasScript()) {
         RootedScript script(cx, fun->nonLazyScript());
         if (!script->hasBaselineScript() && !script->hasIonScript())
             return true;
 
         ICCall_Scripted::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), fun);
-        ICStub *newStub = compiler.getStub();
+        ICStub *newStub = compiler.getStub(ICStubSpace::StubSpaceFor(script));
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         return true;
     }
 
     return true;
--- a/js/src/ion/BaselineIC.h
+++ b/js/src/ion/BaselineIC.h
@@ -6,20 +6,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(jsion_baseline_ic_h__) && defined(JS_ION)
 #define jsion_baseline_ic_h__
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsopcode.h"
-#include "gc/Heap.h"
 #include "BaselineJIT.h"
 #include "BaselineRegisters.h"
 
+#include "gc/Heap.h"
+
 namespace js {
 namespace ion {
 
 //
 // Baseline Inline Caches are polymorphic caches that aggressively
 // share their stub code.
 //
 // Every polymorphic site contains a linked list of stubs which are
@@ -182,17 +183,16 @@ namespace ion {
 //          |   \-------------.-----------------.
 //          |   |             |                 |
 //          v   |1            |1                |0
 //     +-----------+     +-----------+     +-----------+
 //     | Type 1.1  |---->| Type 1.2  |---->|   FB 1    |
 //     +-----------+     +-----------+     +-----------+
 //
 
-
 class ICStub;
 
 //
 // An entry in the Baseline IC descriptor table.
 //
 class ICEntry
 {
   private:
@@ -314,24 +314,38 @@ class ICStub
 #undef DEF_ENUM_KIND
         LIMIT
     };
 
     static inline bool IsValidKind(Kind k) {
         return (k > INVALID) && (k < LIMIT);
     }
 
+    static const char *KindString(Kind k) {
+        switch(k) {
+#define DEF_KIND_STR(kindName) case kindName: return #kindName;
+            IC_STUB_KIND_LIST(DEF_KIND_STR)
+#undef DEF_KIND_STR
+          default:
+            JS_NOT_REACHED("Invalid kind.");
+            return "INVALID_KIND";
+        }
+    }
+
     enum Trait {
         Regular             = 0x0,
         Fallback            = 0x1,
         Monitored           = 0x2,
         MonitoredFallback   = 0x3,
         Updated             = 0x4
     };
 
+    void markCode(JSTracer *trc, const char *name);
+    void trace(JSTracer *trc);
+
   protected:
     // The kind of the stub.
     //  High bit is 'isFallback' flag.
     //  Second high bit is 'isMonitored' flag.
     Trait   trait_ : 3;
     Kind    kind_  : 13;
 
     // The raw jitcode to call for this stub.
@@ -574,17 +588,17 @@ class ICMonitoredFallbackStub : public I
     // Pointer to the fallback monitor stub.
     ICTypeMonitor_Fallback *    fallbackMonitorStub_;
 
     ICMonitoredFallbackStub(Kind kind, IonCode *stubCode)
       : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
         fallbackMonitorStub_(NULL) {}
 
   public:
-    bool initMonitoringChain(JSContext *cx);
+    bool initMonitoringChain(JSContext *cx, ICStubSpace *space);
 
     inline ICTypeMonitor_Fallback *fallbackMonitorStub() const {
         return fallbackMonitorStub_;
     }
 };
 
 // Updated stubs are IC stubs that use a TypeUpdate IC to track
 // the status of heap typesets that need to be updated.
@@ -598,17 +612,17 @@ class ICUpdatedStub : public ICStub
 
     ICUpdatedStub(Kind kind, IonCode *stubCode)
       : ICStub(kind, ICStub::Updated, stubCode),
         firstUpdateStub_(NULL),
         numOptimizedStubs_(0)
     {}
 
   public:
-    bool initUpdatingChain(JSContext *cx);
+    bool initUpdatingChain(JSContext *cx, ICStubSpace *space);
 
     void addOptimizedUpdateStub(ICStub *stub) {
         if (firstUpdateStub_->isTypeUpdate_Fallback()) {
             stub->setNext(firstUpdateStub_);
             firstUpdateStub_ = stub;
         } else {
             ICStub *iter = firstUpdateStub_;
             JS_ASSERT(iter->next() != NULL);
@@ -689,17 +703,17 @@ class ICStubCompiler
           default:
             JS_NOT_REACHED("Invalid numInputs");
         }
 
         return regs;
     }
 
   public:
-    virtual ICStub *getStub() = 0;
+    virtual ICStub *getStub(ICStubSpace *space) = 0;
 };
 
 // Base class for stub compilers that can generate multiple stubcodes.
 // These compilers need access to the JSOp they are compiling for.
 class ICMultiStubCompiler : public ICStubCompiler
 {
   protected:
     JSOp            op;
@@ -717,16 +731,18 @@ class ICMultiStubCompiler : public ICStu
 // TypeMonitor
 
 // The TypeMonitor fallback stub is not a regular fallback stub.
 // It doesn't hold a pointer to the IC entry, but rather back to the
 // main fallback stub for the IC (from which a pointer to the IC entry
 // can be retreived).
 class ICTypeMonitor_Fallback : public ICStub
 {
+    friend class ICStubSpace;
+
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     // Pointer to the main fallback stub for the IC.
     ICMonitoredFallbackStub *   mainFallbackStub_;
 
     // Pointer to the first monitor stub.
     ICStub *                    firstMonitorStub_;
 
@@ -759,64 +775,68 @@ class ICTypeMonitor_Fallback : public IC
             *lastMonitorStubPtrAddr_ = stub;
         }
 
         lastMonitorStubPtrAddr_ = stub->addressOfNext();
         numOptimizedMonitorStubs_++;
     }
 
   public:
-    static inline ICTypeMonitor_Fallback *New(IonCode *code, ICMonitoredFallbackStub *mainFbStub) {
-        return new ICTypeMonitor_Fallback(code, mainFbStub);
+    static inline ICTypeMonitor_Fallback *New(
+        ICStubSpace *space, IonCode *code, ICMonitoredFallbackStub *mainFbStub)
+    {
+        return space->allocate<ICTypeMonitor_Fallback>(code, mainFbStub);
     }
 
     inline ICFallbackStub *mainFallbackStub() const {
         return mainFallbackStub_;
     }
 
     inline ICStub *firstMonitorStub() const {
         return firstMonitorStub_;
     }
 
     inline uint32_t numOptimizedMonitorStubs() const {
         return numOptimizedMonitorStubs_;
     }
 
     // Create a new monitor stub for the type of the given value, and
     // add it to this chain.
-    bool addMonitorStubForValue(JSContext *cx, HandleValue val);
+    bool addMonitorStubForValue(JSContext *cx, ICStubSpace *space, HandleValue val);
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
         ICMonitoredFallbackStub *mainFallbackStub_;
 
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, ICMonitoredFallbackStub *mainFallbackStub)
           : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
             mainFallbackStub_(mainFallbackStub)
         { }
 
-        ICTypeMonitor_Fallback *getStub() {
-            return ICTypeMonitor_Fallback::New(getStubCode(), mainFallbackStub_);
+        ICTypeMonitor_Fallback *getStub(ICStubSpace *space) {
+            return ICTypeMonitor_Fallback::New(space, getStubCode(), mainFallbackStub_);
         }
     };
 };
 
 class ICTypeMonitor_Type : public ICStub
 {
+    friend class ICStubSpace;
+
     ICTypeMonitor_Type(Kind kind, IonCode *stubCode)
         : ICStub(kind, stubCode)
     { }
 
   public:
-    static inline ICTypeMonitor_Type *New(Kind kind, IonCode *code) {
-        return new ICTypeMonitor_Type(kind, code);
+    static inline ICTypeMonitor_Type *New(ICStubSpace *space, Kind kind, IonCode *code) {
+        return space->allocate<ICTypeMonitor_Type>(kind, code);
     }
 
     static Kind KindFromType(JSValueType type) {
         switch (type) {
           case JSVAL_TYPE_INT32:     return TypeMonitor_Int32;
           case JSVAL_TYPE_DOUBLE:    return TypeMonitor_Double;
           case JSVAL_TYPE_BOOLEAN:   return TypeMonitor_Boolean;
           case JSVAL_TYPE_STRING:    return TypeMonitor_String;
@@ -832,34 +852,38 @@ class ICTypeMonitor_Type : public ICStub
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, JSValueType type)
           : ICStubCompiler(cx, ICTypeMonitor_Type::KindFromType(type)),
             type_(type)
         { }
 
-        ICTypeMonitor_Type *getStub() {
-            return ICTypeMonitor_Type::New(kind, getStubCode());
+        ICTypeMonitor_Type *getStub(ICStubSpace *space) {
+            return ICTypeMonitor_Type::New(space, kind, getStubCode());
         }
     };
 };
 
 class ICTypeMonitor_TypeObject : public ICStub
 {
+    friend class ICStubSpace;
+
     HeapPtrTypeObject type_;
 
     ICTypeMonitor_TypeObject(IonCode *stubCode, HandleTypeObject type)
       : ICStub(TypeMonitor_TypeObject, stubCode),
         type_(type)
     { }
 
   public:
-    static inline ICTypeMonitor_TypeObject *New(IonCode *code, HandleTypeObject type) {
-        return new ICTypeMonitor_TypeObject(code, type);
+    static inline ICTypeMonitor_TypeObject *New(
+            ICStubSpace *space, IonCode *code, HandleTypeObject type)
+    {
+        return space->allocate<ICTypeMonitor_TypeObject>(code, type);
     }
 
     HeapPtrTypeObject &type() {
         return type_;
     }
 
     static size_t offsetOfType() {
         return offsetof(ICTypeMonitor_TypeObject, type_);
@@ -871,259 +895,277 @@ class ICTypeMonitor_TypeObject : public 
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, HandleTypeObject type)
           : ICStubCompiler(cx, TypeMonitor_TypeObject),
             type_(type)
         { }
 
-        ICTypeMonitor_TypeObject *getStub() {
-            return ICTypeMonitor_TypeObject::New(getStubCode(), type_);
+        ICTypeMonitor_TypeObject *getStub(ICStubSpace *space) {
+            return ICTypeMonitor_TypeObject::New(space, getStubCode(), type_);
         }
     };
 };
 
 // TypeUpdate
 
 extern const VMFunction DoTypeUpdateFallbackInfo;
 
 // The TypeUpdate fallback is not a regular fallback, since it just
 // forwards to a different entry point in the main fallback stub.
 class ICTypeUpdate_Fallback : public ICStub
 {
+    friend class ICStubSpace;
+
     ICTypeUpdate_Fallback(IonCode *stubCode)
       : ICStub(ICStub::TypeUpdate_Fallback, stubCode)
     {}
 
   public:
-    static inline ICTypeUpdate_Fallback *New(IonCode *code) {
-        return new ICTypeUpdate_Fallback(code);
+    static inline ICTypeUpdate_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICTypeUpdate_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::TypeUpdate_Fallback)
         { }
 
-        ICTypeUpdate_Fallback *getStub() {
-            return ICTypeUpdate_Fallback::New(getStubCode());
+        ICTypeUpdate_Fallback *getStub(ICStubSpace *space) {
+            return ICTypeUpdate_Fallback::New(space, getStubCode());
         }
     };
 };
 
 // Compare
 //      JSOP_LT
 //      JSOP_GT
 
 class ICCompare_Fallback : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICCompare_Fallback(IonCode *stubCode)
       : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {}
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICCompare_Fallback *New(IonCode *code) {
-        return new ICCompare_Fallback(code);
+    static inline ICCompare_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICCompare_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::Compare_Fallback) {}
 
-        ICStub *getStub() {
-            return ICCompare_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICCompare_Fallback::New(space, getStubCode());
         }
     };
 };
 
 class ICCompare_Int32 : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICCompare_Int32(IonCode *stubCode)
       : ICFallbackStub(ICStub::Compare_Int32, stubCode) {}
 
   public:
-    static inline ICCompare_Int32 *New(IonCode *code) {
-        return new ICCompare_Int32(code);
+    static inline ICCompare_Int32 *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICCompare_Int32>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICMultiStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, JSOp op)
           : ICMultiStubCompiler(cx, ICStub::Compare_Int32, op) {}
 
-        ICStub *getStub() {
-            return ICCompare_Int32::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICCompare_Int32::New(space, getStubCode());
         }
     };
 };
 
 // ToBool
 //      JSOP_IFNE
 
 class ICToBool_Fallback : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICToBool_Fallback(IonCode *stubCode)
       : ICFallbackStub(ICStub::ToBool_Fallback, stubCode) {}
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICToBool_Fallback *New(IonCode *code) {
-        return new ICToBool_Fallback(code);
+    static inline ICToBool_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICToBool_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::ToBool_Fallback) {}
 
-        ICStub *getStub() {
-            return ICToBool_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICToBool_Fallback::New(space, getStubCode());
         }
     };
 };
 
 class ICToBool_Bool : public ICStub
 {
+    friend class ICStubSpace;
+
     ICToBool_Bool(IonCode *stubCode)
       : ICStub(ICStub::ToBool_Bool, stubCode) {}
 
   public:
-    static inline ICToBool_Bool *New(IonCode *code) {
-        return new ICToBool_Bool(code);
+    static inline ICToBool_Bool *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICToBool_Bool>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::ToBool_Bool) {}
 
-        ICStub *getStub() {
-            return ICToBool_Bool::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICToBool_Bool::New(space, getStubCode());
         }
     };
 };
 
 class ICToBool_Int32 : public ICStub
 {
+    friend class ICStubSpace;
+
     ICToBool_Int32(IonCode *stubCode)
       : ICStub(ICStub::ToBool_Int32, stubCode) {}
 
   public:
-    static inline ICToBool_Int32 *New(IonCode *code) {
-        return new ICToBool_Int32(code);
+    static inline ICToBool_Int32 *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICToBool_Int32>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::ToBool_Int32) {}
 
-        ICStub *getStub() {
-            return ICToBool_Int32::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICToBool_Int32::New(space, getStubCode());
         }
     };
 };
 
 // ToNumber
 //     JSOP_POS
 
 class ICToNumber_Fallback : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICToNumber_Fallback(IonCode *stubCode)
       : ICFallbackStub(ICStub::ToNumber_Fallback, stubCode) {}
 
   public:
-    static inline ICToNumber_Fallback *New(IonCode *code) {
-        return new ICToNumber_Fallback(code);
+    static inline ICToNumber_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICToNumber_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::ToNumber_Fallback) {}
 
-        ICStub *getStub() {
-            return ICToNumber_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICToNumber_Fallback::New(space, getStubCode());
         }
     };
 };
 
 // BinaryArith
 //      JSOP_ADD
 //      JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
 //      JSOP_LSH, JSOP_RSH, JSOP_URSH
 
 class ICBinaryArith_Fallback : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICBinaryArith_Fallback(IonCode *stubCode)
       : ICFallbackStub(BinaryArith_Fallback, stubCode) {}
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICBinaryArith_Fallback *New(IonCode *code) {
-        return new ICBinaryArith_Fallback(code);
+    static inline ICBinaryArith_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICBinaryArith_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {}
 
-        ICStub *getStub() {
-            return ICBinaryArith_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICBinaryArith_Fallback::New(space, getStubCode());
         }
     };
 };
 
 class ICBinaryArith_Int32 : public ICStub
 {
+    friend class ICStubSpace;
+
     ICBinaryArith_Int32(IonCode *stubCode)
       : ICStub(BinaryArith_Int32, stubCode) {}
 
   public:
-    static inline ICBinaryArith_Int32 *New(IonCode *code) {
-        return new ICBinaryArith_Int32(code);
+    static inline ICBinaryArith_Int32 *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICBinaryArith_Int32>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         JSOp op_;
         bool allowDouble_;
 
@@ -1135,187 +1177,201 @@ class ICBinaryArith_Int32 : public ICStu
                     (static_cast<int32_t>(allowDouble_) << 24));
         }
 
       public:
         Compiler(JSContext *cx, JSOp op, bool allowDouble)
           : ICStubCompiler(cx, ICStub::BinaryArith_Int32),
             op_(op), allowDouble_(allowDouble) {}
 
-        ICStub *getStub() {
-            return ICBinaryArith_Int32::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICBinaryArith_Int32::New(space, getStubCode());
         }
     };
 };
 
 // UnaryArith
 //     JSOP_BITNOT
 //     JSOP_NEG
 
 class ICUnaryArith_Fallback : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICUnaryArith_Fallback(IonCode *stubCode)
       : ICFallbackStub(UnaryArith_Fallback, stubCode) {}
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICUnaryArith_Fallback *New(IonCode *code) {
-        return new ICUnaryArith_Fallback(code);
+    static inline ICUnaryArith_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICUnaryArith_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::UnaryArith_Fallback)
         {}
 
-        ICStub *getStub() {
-            return ICUnaryArith_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICUnaryArith_Fallback::New(space, getStubCode());
         }
     };
 };
 
 class ICUnaryArith_Int32 : public ICStub
 {
+    friend class ICStubSpace;
+
     ICUnaryArith_Int32(IonCode *stubCode)
       : ICStub(UnaryArith_Int32, stubCode)
     {}
 
   public:
-    static inline ICUnaryArith_Int32 *New(IonCode *code) {
-        return new ICUnaryArith_Int32(code);
+    static inline ICUnaryArith_Int32 *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICUnaryArith_Int32>(code);
     }
 
     class Compiler : public ICMultiStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, JSOp op)
           : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op)
         {}
 
-        ICStub *getStub() {
-            return ICUnaryArith_Int32::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICUnaryArith_Int32::New(space, getStubCode());
         }
     };
 };
 
 // GetElem
 //      JSOP_GETELEM
 
 class ICGetElem_Fallback : public ICMonitoredFallbackStub
 {
+    friend class ICStubSpace;
+
     ICGetElem_Fallback(IonCode *stubCode)
       : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode)
     { }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICGetElem_Fallback *New(IonCode *code) {
-        return new ICGetElem_Fallback(code);
+    static inline ICGetElem_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICGetElem_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::GetElem_Fallback)
         { }
 
-        ICStub *getStub() {
-            ICGetElem_Fallback *stub = ICGetElem_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            ICGetElem_Fallback *stub = ICGetElem_Fallback::New(space, getStubCode());
             if (!stub)
                 return NULL;
-            if (!stub->initMonitoringChain(cx))
+            if (!stub->initMonitoringChain(cx, space))
                 return NULL;
             return stub;
         }
     };
 };
 
 class ICGetElem_Dense : public ICMonitoredStub
 {
+    friend class ICStubSpace;
+
     ICGetElem_Dense(IonCode *stubCode, ICStub *firstMonitorStub)
       : ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub) {}
 
   public:
-    static inline ICGetElem_Dense *New(IonCode *code, ICStub *firstMonitorStub) {
-        return new ICGetElem_Dense(code, firstMonitorStub);
+    static inline ICGetElem_Dense *New(
+            ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub)
+    {
+        return space->allocate<ICGetElem_Dense>(code, firstMonitorStub);
     }
 
     class Compiler : public ICStubCompiler {
       ICStub *firstMonitorStub_;
 
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, ICStub *firstMonitorStub)
           : ICStubCompiler(cx, ICStub::GetElem_Dense),
             firstMonitorStub_(firstMonitorStub) {}
 
-        ICStub *getStub() {
-            return ICGetElem_Dense::New(getStubCode(), firstMonitorStub_);
+        ICStub *getStub(ICStubSpace *space) {
+            return ICGetElem_Dense::New(space, getStubCode(), firstMonitorStub_);
         }
     };
 };
 
 // SetElem
 //      JSOP_SETELEM
 
 class ICSetElem_Fallback : public ICFallbackStub
 {
+    friend class ICStubSpace;
+
     ICSetElem_Fallback(IonCode *stubCode)
       : ICFallbackStub(ICStub::SetElem_Fallback, stubCode)
     { }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICSetElem_Fallback *New(IonCode *code) {
-        return new ICSetElem_Fallback(code);
+    static inline ICSetElem_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICSetElem_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::SetElem_Fallback)
         { }
 
-        ICStub *getStub() {
-            return ICSetElem_Fallback::New(getStubCode());
+        ICStub *getStub(ICStubSpace *space) {
+            return ICSetElem_Fallback::New(space, getStubCode());
         }
     };
 };
 
 class ICSetElem_Dense : public ICUpdatedStub
 {
+    friend class ICStubSpace;
+
     HeapPtrTypeObject type_;
 
     ICSetElem_Dense(IonCode *stubCode, HandleTypeObject type)
       : ICUpdatedStub(SetElem_Dense, stubCode),
         type_(type) {}
 
   public:
-    static inline ICSetElem_Dense *New(IonCode *code, HandleTypeObject type) {
-        return new ICSetElem_Dense(code, type);
+    static inline ICSetElem_Dense *New(ICStubSpace *space, IonCode *code, HandleTypeObject type) {
+        return space->allocate<ICSetElem_Dense>(code, type);
     }
 
     static size_t offsetOfType() {
         return offsetof(ICSetElem_Dense, type_);
     }
 
     HeapPtrTypeObject &type() {
         return type_;
@@ -1330,61 +1386,55 @@ class ICSetElem_Dense : public ICUpdated
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx, HandleTypeObject type)
           : ICStubCompiler(cx, ICStub::SetElem_Dense),
             type_(type) {}
 
-        ICStub *getStub() {
-            ICSetElem_Dense *stub = ICSetElem_Dense::New(getStubCode(), type_);
-            if (!stub)
+        ICStub *getStub(ICStubSpace *space) {
+            ICSetElem_Dense *stub = ICSetElem_Dense::New(space, getStubCode(), type_);
+            if (!stub || !stub->initUpdatingChain(cx, space))
                 return NULL;
-            if (!stub->initUpdatingChain(cx)) {
-                delete stub;
-                return NULL;
-            }
             return stub;
         }
     };
 };
 
 // GetName
 //      JSOP_GETGNAME
 class ICGetName_Fallback : public ICMonitoredFallbackStub
 {
+    friend class ICStubSpace;
+
     ICGetName_Fallback(IonCode *stubCode)
       : ICMonitoredFallbackStub(ICStub::GetName_Fallback, stubCode)
     { }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICGetName_Fallback *New(IonCode *code) {
-        return new ICGetName_Fallback(code);
+    static inline ICGetName_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICGetName_Fallback>(code);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::GetName_Fallback)
         { }
 
-        ICStub *getStub() {
-            ICGetName_Fallback *stub = ICGetName_Fallback::New(getStubCode());
-            if (!stub)
+        ICStub *getStub(ICStubSpace *space) {
+            ICGetName_Fallback *stub = ICGetName_Fallback::New(space, getStubCode());
+            if (!stub || !stub->initMonitoringChain(cx, space))
                 return NULL;
-            if (!stub->initMonitoringChain(cx)) {
-                delete stub;
-                return NULL;
-            }
             return stub;
         }
     };
 };
 
 // Call
 //      JSOP_CALL
 //      JSOP_FUNAPPLY
@@ -1398,62 +1448,64 @@ class ICCallStubCompiler : public ICStub
       : ICStubCompiler(cx, kind)
     { }
 
     void pushCallArguments(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg);
 };
 
 class ICCall_Fallback : public ICMonitoredFallbackStub
 {
+    friend class ICStubSpace;
+
     ICCall_Fallback(IonCode *stubCode)
       : ICMonitoredFallbackStub(ICStub::Call_Fallback, stubCode)
     { }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
-    static inline ICCall_Fallback *New(IonCode *code) {
-        return new ICCall_Fallback(code);
+    static inline ICCall_Fallback *New(ICStubSpace *space, IonCode *code) {
+        return space->allocate<ICCall_Fallback>(code);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICCallStubCompiler(cx, ICStub::Call_Fallback)
         { }
 
-        ICStub *getStub() {
-            ICCall_Fallback *stub = ICCall_Fallback::New(getStubCode());
-            if (!stub)
+        ICStub *getStub(ICStubSpace *space) {
+            ICCall_Fallback *stub = ICCall_Fallback::New(space, getStubCode());
+            if (!stub || !stub->initMonitoringChain(cx, space))
                 return NULL;
-            if (!stub->initMonitoringChain(cx)) {
-                delete stub;
-                return NULL;
-            }
             return stub;
         }
     };
 };
 
 class ICCall_Scripted : public ICMonitoredStub
 {
+    friend class ICStubSpace;
+
     HeapPtrFunction callee_;
 
     ICCall_Scripted(IonCode *stubCode, ICStub *firstMonitorStub, HandleFunction callee)
       : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
         callee_(callee)
     { }
 
   public:
-    static inline ICCall_Scripted *New(IonCode *code, ICStub *firstMonitorStub, HandleFunction callee) {
-        return new ICCall_Scripted(code, firstMonitorStub, callee);
+    static inline ICCall_Scripted *New(
+            ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub, HandleFunction callee)
+    {
+        return space->allocate<ICCall_Scripted>(code, firstMonitorStub, callee);
     }
 
     static size_t offsetOfCallee() {
         return offsetof(ICCall_Scripted, callee_);
     }
     HeapPtrFunction &callee() {
         return callee_;
     }
@@ -1467,18 +1519,18 @@ class ICCall_Scripted : public ICMonitor
 
       public:
         Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleFunction callee)
           : ICCallStubCompiler(cx, ICStub::Call_Scripted),
             firstMonitorStub_(firstMonitorStub),
             callee_(cx, callee)
         { }
 
-        ICStub *getStub() {
-            return ICCall_Scripted::New(getStubCode(), firstMonitorStub_, callee_);
+        ICStub *getStub(ICStubSpace *space) {
+            return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_, callee_);
         }
     };
 };
 
 } // namespace ion
 } // namespace js
 
 #endif
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -11,18 +11,35 @@
 #include "CompileInfo.h"
 #include "IonSpewer.h"
 
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
+/* static */ ICStubSpace *
+ICStubSpace::FallbackStubSpaceFor(JSScript *script)
+{
+    JS_ASSERT(script->hasBaselineScript());
+    return script->baselineScript()->fallbackStubSpace();
+}
+
+/* static */ ICStubSpace *
+ICStubSpace::StubSpaceFor(JSScript *script)
+{
+    JS_ASSERT(script->hasBaselineScript());
+    return script->baselineScript()->optimizedStubSpace();
+}
+
+
 BaselineScript::BaselineScript()
-  : method_(NULL)
+  : method_(NULL),
+    fallbackStubSpace_(),
+    optimizedStubSpace_()
 { }
 
 static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12; //XXX
 
 // XXX copied from Ion.cpp
 class AutoDestroyAllocator
 {
     LifoAlloc *alloc;
@@ -215,91 +232,48 @@ ion::CanEnterBaselineJIT(JSContext *cx, 
 }
 
 // Be safe, align IC entry list to 8 in all cases.
 static const unsigned DataAlignment = sizeof(uintptr_t);
 
 BaselineScript *
 BaselineScript::New(JSContext *cx, size_t icEntries)
 {
+    size_t paddedBaselineScriptSize = AlignBytes(sizeof(BaselineScript), DataAlignment);
+
     size_t icEntriesSize = icEntries * sizeof(ICEntry);
     size_t paddedICEntriesSize = AlignBytes(icEntriesSize, DataAlignment);
 
-    size_t allocBytes = sizeof(BaselineScript) + paddedICEntriesSize;
+    size_t allocBytes = paddedBaselineScriptSize + paddedICEntriesSize;
 
     uint8_t *buffer = (uint8_t *)cx->malloc_(allocBytes);
     if (!buffer)
         return NULL;
 
     BaselineScript *script = reinterpret_cast<BaselineScript *>(buffer);
     new (script) BaselineScript();
 
-    uint8_t *scriptEnd = buffer + sizeof(BaselineScript);
-    uint8_t *icEntryStart = (uint8_t *) AlignBytes((uintptr_t) scriptEnd, DataAlignment);
+    uint8_t *icEntryStart = buffer + paddedBaselineScriptSize;
 
     script->icEntriesOffset_ = (uint32_t) (icEntryStart - buffer);
     script->icEntries_ = icEntries;
 
     return script;
 }
 
-static void
-TraceStub(JSTracer *trc, ICStub *stub)
-{
-    IonCode *stubIonCode = stub->ionCode();
-    MarkIonCodeUnbarriered(trc, &stubIonCode, "baseline-stub-ioncode");
-
-    // If the stub is a monitored fallback stub, then mark the monitor ICs hanging
-    // off of that stub.  We don't need to worry about the regular monitored stubs,
-    // because the regular monitored stubs will always have a monitored fallback stub
-    // that references the same stub chain.
-    if (stub->isMonitoredFallback()) {
-        ICTypeMonitor_Fallback *lastMonStub =
-            stub->toMonitoredFallbackStub()->fallbackMonitorStub();
-        for (ICStub *monStub = lastMonStub->firstMonitorStub();
-             monStub != NULL;
-             monStub = monStub->next())
-        {
-            JS_ASSERT_IF(monStub->next() == NULL, monStub == lastMonStub);
-            IonCode *monStubIonCode = monStub->ionCode();
-            MarkIonCodeUnbarriered(trc, &monStubIonCode, "baseline-monitor-stub-ioncode");
-        }
-    }
-
-    switch (stub->kind()) {
-      case ICStub::Call_Scripted: {
-        ICCall_Scripted *callStub = stub->toCall_Scripted();
-        MarkObject(trc, &callStub->callee(), "baseline-callstub-callee");
-        break;
-      }
-      case ICStub::SetElem_Dense: {
-        ICSetElem_Dense *setElemStub = stub->toSetElem_Dense();
-        MarkTypeObject(trc, &setElemStub->type(), "baseline-setelem-dense-stub-type");
-        break;
-      }
-      case ICStub::TypeMonitor_TypeObject: {
-        ICTypeMonitor_TypeObject *monitorStub = stub->toTypeMonitor_TypeObject();
-        MarkTypeObject(trc, &monitorStub->type(), "baseline-monitor-typeobject");
-        break;
-      }
-      default:
-        break;
-    }
-}
-
 void
 BaselineScript::trace(JSTracer *trc)
 {
     MarkIonCode(trc, &method_, "baseline-method");
 
     // Mark all IC stub codes hanging off the IC stub entries.
     for (size_t i = 0; i < numICEntries(); i++) {
         ICEntry &ent = icEntry(i);
         for (ICStub *stub = ent.firstStub(); stub; stub = stub->next())
-            TraceStub(trc, stub);
+            stub->trace(trc);
     }
 }
 
 void
 BaselineScript::Trace(JSTracer *trc, BaselineScript *script)
 {
     script->trace(trc);
 }
@@ -347,8 +321,14 @@ BaselineScript::copyICEntries(const ICEn
         // a pointer to the (now available) realEntry.
         // We use a slightly hackish measure here: since we don't have a
         // static KIND to use as the template argument for BaselineICFallbackStub,
         // we just use a bogus one (0).
         if (realEntry.firstStub()->isFallback())
             realEntry.firstStub()->toFallbackStub()->fixupICEntry(&realEntry);
     }
 }
+
+void
+BaselineScript::adoptFallbackStubs(ICStubSpace *stubSpace)
+{
+    fallbackStubSpace_.adoptFrom(stubSpace);
+}
--- a/js/src/ion/BaselineJIT.h
+++ b/js/src/ion/BaselineJIT.h
@@ -5,30 +5,64 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(jsion_baseline_jit_h__) && defined(JS_ION)
 #define jsion_baseline_jit_h__
 
 #include "jscntxt.h"
 #include "jscompartment.h"
+
 #include "IonCode.h"
 #include "ion/IonMacroAssembler.h"
 
+#include "ds/LifoAlloc.h"
+
 namespace js {
 namespace ion {
 
 struct ICEntry;
 
+// ICStubSpace is an abstraction for allocation policy and storage for stub data.
+struct ICStubSpace
+{
+  private:
+    const static size_t STUB_DEFAULT_CHUNK_SIZE = 256;
+    LifoAlloc allocator_;
+
+    inline void *alloc_(size_t size) {
+        return allocator_.alloc(size);
+    }
+
+  public:
+    inline ICStubSpace()
+      : allocator_(STUB_DEFAULT_CHUNK_SIZE) {}
+
+    JS_DECLARE_NEW_METHODS(allocate, alloc_, inline)
+
+    inline void adoptFrom(ICStubSpace *other) {
+        allocator_.transferFrom(&(other->allocator_));
+    }
+
+    static ICStubSpace *FallbackStubSpaceFor(JSScript *script);
+    static ICStubSpace *StubSpaceFor(JSScript *script);
+};
+
 struct BaselineScript
 {
   private:
     // Code pointer containing the actual method.
     HeapPtr<IonCode> method_;
 
+    // Allocated space for fallback stubs.
+    ICStubSpace fallbackStubSpace_;
+
+    // Allocated space for optimized stubs.
+    ICStubSpace optimizedStubSpace_;
+
   private:
     void trace(JSTracer *trc);
 
     uint32_t icEntriesOffset_;
     uint32_t icEntries_;
 
   public:
     // Do not call directly, use BaselineScript::New. This is public for cx->new_.
@@ -41,16 +75,24 @@ struct BaselineScript
     static inline size_t offsetOfMethod() {
         return offsetof(BaselineScript, method_);
     }
 
     ICEntry *icEntryList() {
         return (ICEntry *)(reinterpret_cast<uint8_t *>(this) + icEntriesOffset_);
     }
 
+    ICStubSpace *fallbackStubSpace() {
+        return &fallbackStubSpace_;
+    }
+
+    ICStubSpace *optimizedStubSpace() {
+        return &optimizedStubSpace_;
+    }
+
     IonCode *method() const {
         return method_;
     }
     void setMethod(IonCode *code) {
         //JS_ASSERT(!invalidated());
         method_ = code;
     }
 
@@ -58,16 +100,17 @@ struct BaselineScript
     ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset);
     ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr);
 
     size_t numICEntries() const {
         return icEntries_;
     }
 
     void copyICEntries(const ICEntry *entries, MacroAssembler &masm);
+    void adoptFallbackStubs(ICStubSpace *stubSpace);
 };
 
 MethodStatus
 CanEnterBaselineJIT(JSContext *cx, HandleScript script, StackFrame *fp);
 
 IonExecStatus
 EnterBaselineMethod(JSContext *cx, StackFrame *fp);
 
--- a/js/src/ion/shared/BaselineCompiler-shared.cpp
+++ b/js/src/ion/shared/BaselineCompiler-shared.cpp
@@ -11,12 +11,13 @@
 using namespace js;
 using namespace js::ion;
 
 BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, JSScript *script)
   : cx(cx),
     script(script),
     pc(NULL),
     frame(cx, script, masm),
+    stubSpace_(),
     icEntries_(),
     icLoadLabels_()
 {
 }
--- a/js/src/ion/shared/BaselineCompiler-shared.h
+++ b/js/src/ion/shared/BaselineCompiler-shared.h
@@ -21,16 +21,17 @@ class BaselineCompilerShared
   protected:
     JSContext *cx;
     JSScript *script;
     jsbytecode *pc;
     MacroAssembler masm;
 
     FrameInfo frame;
 
+    ICStubSpace stubSpace_;
     js::Vector<ICEntry, 16, SystemAllocPolicy> icEntries_;
 
     // Labels for the 'movWithPatch' for loading IC entry pointers in
     // the generated IC-calling code in the main jitcode.  These need
     // to be patched with the actual icEntry offsets after the BaselineScript
     // has been allocated.
     js::Vector<CodeOffsetLabel, 16, SystemAllocPolicy> icLoadLabels_;
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1082,17 +1082,18 @@ class JS_PUBLIC_API(AutoGCRooter) {
         STACKBASESHAPE=-22,/* js::StackBaseShape::AutoRooter */
         GETTERSETTER =-24, /* js::AutoRooterGetterSetter */
         REGEXPSTATICS=-25, /* js::RegExpStatics::AutoRooter */
         NAMEVECTOR =  -26, /* js::AutoNameVector */
         HASHABLEVALUE=-27,
         IONMASM =     -28, /* js::ion::MacroAssembler */
         IONALLOC =    -29, /* js::ion::AutoTempAllocatorRooter */
         WRAPVECTOR =  -30, /* js::AutoWrapperVector */
-        WRAPPER =     -31  /* js::AutoWrapperRooter */
+        WRAPPER =     -31, /* js::AutoWrapperRooter */
+        BASELINECOMPILER=-32, /* js::ion::BaselineCompiler */
     };
 
   private:
     AutoGCRooter ** const stackTop;
 
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
     void operator=(AutoGCRooter &ida) MOZ_DELETE;