Bug 896529 - Move some methods from IonCompartment to IonRuntime. r=nbp
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 31 Jul 2013 14:19:00 +0200
changeset 153021 87571852c99ff3ba8d9438a79089829598ad2a42
parent 153020 3eef74151413ce2c3d40aa5c8b54632a73243fa2
child 153022 7d9b658f6840c3dad704a68899a6c6018878ab19
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs896529
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 896529 - Move some methods from IonCompartment to IonRuntime. r=nbp
js/src/ion/BaselineBailouts.cpp
js/src/ion/BaselineCompiler.cpp
js/src/ion/BaselineIC.cpp
js/src/ion/BaselineJIT.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/Ion.cpp
js/src/ion/IonCompartment.h
js/src/ion/IonMacroAssembler.h
js/src/ion/MIRGenerator.h
js/src/ion/arm/Bailouts-arm.cpp
js/src/ion/arm/CodeGenerator-arm.cpp
js/src/ion/arm/MacroAssembler-arm.cpp
js/src/ion/arm/Trampoline-arm.cpp
js/src/ion/shared/BaselineCompiler-shared.cpp
js/src/ion/shared/CodeGenerator-shared.cpp
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/x64/MacroAssembler-x64.cpp
js/src/ion/x64/Trampoline-x64.cpp
js/src/ion/x86/Bailouts-x86.cpp
js/src/ion/x86/MacroAssembler-x86.cpp
js/src/ion/x86/Trampoline-x86.cpp
js/src/vm/ForkJoin.cpp
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -1152,17 +1152,17 @@ InitFromBailout(JSContext *cx, HandleScr
         return false;
 
     // Push rectifier frame descriptor
     if (!builder.writeWord(rectifierFrameDescr, "Descriptor"))
         return false;
 
     // Push return address into the ArgumentsRectifier code, immediately after the ioncode
     // call.
-    void *rectReturnAddr = cx->compartment()->ionCompartment()->getArgumentsRectifierReturnAddr();
+    void *rectReturnAddr = cx->runtime()->ionRuntime()->getArgumentsRectifierReturnAddr();
     JS_ASSERT(rectReturnAddr);
     if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
         return false;
 
     return true;
 }
 
 uint32_t
--- a/js/src/ion/BaselineCompiler.cpp
+++ b/js/src/ion/BaselineCompiler.cpp
@@ -513,17 +513,17 @@ bool
 BaselineCompiler::emitDebugTrap()
 {
     JS_ASSERT(debugMode_);
     JS_ASSERT(frame.numUnsyncedSlots() == 0);
 
     bool enabled = script->stepModeEnabled() || script->hasBreakpointsAt(pc);
 
     // Emit patchable call to debug trap handler.
-    IonCode *handler = cx->compartment()->ionCompartment()->debugTrapHandler(cx);
+    IonCode *handler = cx->runtime()->ionRuntime()->debugTrapHandler(cx);
     mozilla::DebugOnly<CodeOffsetLabel> offset = masm.toggledCall(handler, enabled);
 
 #ifdef DEBUG
     // Patchable call offset has to match the pc mapping offset.
     PCMappingEntry &entry = pcMappingEntries_[pcMappingEntries_.length() - 1];
     JS_ASSERT((&offset)->offset() == entry.nativeOffset);
 #endif
 
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -557,43 +557,40 @@ ICStubCompiler::getStubCode()
     JS_ASSERT(entersStubFrame_ == ICStub::CanMakeCalls(kind));
 
     return newStubCode;
 }
 
 bool
 ICStubCompiler::tailCallVM(const VMFunction &fun, MacroAssembler &masm)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(fun);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
     uint32_t argSize = fun.explicitStackSlots() * sizeof(void *);
     EmitTailCallVM(code, masm, argSize);
     return true;
 }
 
 bool
 ICStubCompiler::callVM(const VMFunction &fun, MacroAssembler &masm)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(fun);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
     EmitCallVM(code, masm);
     return true;
 }
 
 bool
 ICStubCompiler::callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(DoTypeUpdateFallbackInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(DoTypeUpdateFallbackInfo);
     if (!code)
         return false;
 
     EmitCallTypeUpdateIC(masm, code, objectOffset);
     return true;
 }
 
 void
@@ -5746,17 +5743,17 @@ ICGetProp_CallScripted::Compiler::genera
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), scratch);
     masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != code);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
         masm.mov(Imm32(0), ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
 
@@ -6672,17 +6669,17 @@ ICSetProp_CallScripted::Compiler::genera
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), scratch);
     masm.branch32(Assembler::BelowOrEqual, scratch, Imm32(1), &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != code);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
         masm.mov(Imm32(1), ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
 
@@ -7430,17 +7427,17 @@ ICCallScriptedCompiler::generateStubCode
     masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), callee);
     masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != code);
         JS_ASSERT(ArgumentsRectifierReg != argcReg);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
         masm.mov(argcReg, ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
 
@@ -7689,17 +7686,17 @@ ICCall_ScriptedApplyArguments::Compiler:
     Label noUnderflow;
     masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
     {
         // Call the arguments rectifier.
         JS_ASSERT(ArgumentsRectifierReg != target);
         JS_ASSERT(ArgumentsRectifierReg != argcReg);
 
         IonCode *argumentsRectifier =
-            cx->compartment()->ionCompartment()->getArgumentsRectifier(SequentialExecution);
+            cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), target);
         masm.loadPtr(Address(target, IonCode::offsetOfCode()), target);
         masm.mov(argcReg, ArgumentsRectifierReg);
     }
     masm.bind(&noUnderflow);
     regs.add(argcReg);
 
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -80,17 +80,17 @@ IsJSDEnabled(JSContext *cx)
 
 static IonExecStatus
 EnterBaseline(JSContext *cx, EnterJitData &data)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Aborted);
     JS_ASSERT(ion::IsBaselineEnabled(cx));
     JS_ASSERT_IF(data.osrFrame, CheckFrame(data.osrFrame));
 
-    EnterIonCode enter = cx->compartment()->ionCompartment()->enterBaselineJIT();
+    EnterIonCode enter = cx->runtime()->ionRuntime()->enterBaseline();
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         IonContext ictx(cx, NULL);
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1294,17 +1294,17 @@ CodeGenerator::visitOutOfLineCallPostWri
         objreg = regs.takeAny();
         masm.movePtr(ImmGCPtr(&obj->toConstant()->toObject()), objreg);
     } else {
         objreg = ToRegister(obj);
         regs.takeUnchecked(objreg);
     }
 
     Register runtimereg = regs.takeAny();
-    masm.mov(ImmWord(GetIonContext()->compartment->rt), runtimereg);
+    masm.mov(ImmWord(gen->compartment->rt), runtimereg);
 
     masm.setupUnalignedABICall(2, regs.takeAny());
     masm.passABIArg(runtimereg);
     masm.passABIArg(objreg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier));
 
     restoreLive(ool->lir());
 
@@ -1316,17 +1316,17 @@ CodeGenerator::visitOutOfLineCallPostWri
 bool
 CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir)
 {
 #ifdef JSGC_GENERATIONAL
     OutOfLineCallPostWriteBarrier *ool = new OutOfLineCallPostWriteBarrier(lir, lir->object());
     if (!addOutOfLineCode(ool))
         return false;
 
-    Nursery &nursery = GetIonContext()->compartment->rt->gcNursery;
+    Nursery &nursery = gen->compartment->rt->gcNursery;
 
     if (lir->object()->isConstant()) {
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
     } else {
         Label tenured;
         Register objreg = ToRegister(lir->object());
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.start()), &tenured);
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.heapEnd()), ool->rejoin());
@@ -1348,17 +1348,17 @@ CodeGenerator::visitPostWriteBarrierV(LP
 #ifdef JSGC_GENERATIONAL
     OutOfLineCallPostWriteBarrier *ool = new OutOfLineCallPostWriteBarrier(lir, lir->object());
     if (!addOutOfLineCode(ool))
         return false;
 
     ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input);
     masm.branchTestObject(Assembler::NotEqual, value, ool->rejoin());
 
-    Nursery &nursery = GetIonContext()->compartment->rt->gcNursery;
+    Nursery &nursery = gen->compartment->rt->gcNursery;
 
     if (lir->object()->isConstant()) {
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
     } else {
         Label tenured;
         Register objreg = ToRegister(lir->object());
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.start()), &tenured);
         masm.branchPtr(Assembler::Below, objreg, ImmWord(nursery.heapEnd()), ool->rejoin());
@@ -1640,18 +1640,17 @@ CodeGenerator::visitCallGeneric(LCallGen
     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
     ExecutionMode executionMode = gen->info().executionMode();
     Label uncompiled, thunk, makeCall, end;
 
     // Known-target case is handled by LCallKnown.
     JS_ASSERT(!call->hasSingleTarget());
 
     // Generate an ArgumentsRectifier.
-    IonCompartment *ion = gen->ionCompartment();
-    IonCode *argumentsRectifier = ion->getArgumentsRectifier(executionMode);
+    IonCode *argumentsRectifier = gen->ionRuntime()->getArgumentsRectifier(executionMode);
 
     masm.checkStackAlignment();
 
     // Guard that calleereg is actually a function object.
     masm.loadObjClass(calleereg, nargsreg);
     masm.cmpPtr(nargsreg, ImmWord(&JSFunction::class_));
     if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
         return false;
@@ -2035,18 +2034,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
         // underflow.
         masm.jump(&rejoin);
 
         // Argument fixup needed. Get ready to call the argumentsRectifier.
         {
             masm.bind(&underflow);
 
             // Hardcode the address of the argumentsRectifier code.
-            IonCompartment *ion = gen->ionCompartment();
-            IonCode *argumentsRectifier = ion->getArgumentsRectifier(executionMode);
+            IonCode *argumentsRectifier = gen->ionRuntime()->getArgumentsRectifier(executionMode);
 
             JS_ASSERT(ArgumentsRectifierReg != objreg);
             masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
             masm.loadPtr(Address(objreg, IonCode::offsetOfCode()), objreg);
             masm.movePtr(argcreg, ArgumentsRectifierReg);
         }
 
         masm.bind(&rejoin);
@@ -5053,17 +5051,17 @@ CodeGenerator::visitIteratorStart(LItera
 #endif // !JSGC_GENERATIONAL
     }
 
     // Mark iterator as active.
     masm.storePtr(obj, Address(niTemp, offsetof(NativeIterator, obj)));
     masm.or32(Imm32(JSITER_ACTIVE), Address(niTemp, offsetof(NativeIterator, flags)));
 
     // Chain onto the active iterator stack.
-    masm.movePtr(ImmWord(GetIonContext()->compartment), temp1);
+    masm.movePtr(ImmWord(gen->compartment), temp1);
     masm.loadPtr(Address(temp1, offsetof(JSCompartment, enumerators)), temp1);
 
     // ni->next = list
     masm.storePtr(temp1, Address(niTemp, NativeIterator::offsetOfNext()));
 
     // ni->prev = list->prev
     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), temp2);
     masm.storePtr(temp2, Address(niTemp, NativeIterator::offsetOfPrev()));
@@ -5364,17 +5362,17 @@ CodeGenerator::generate()
 
     // Before generating any code, we generate type checks for all parameters.
     // This comes before deoptTable_, because we can't use deopt tables without
     // creating the actual frame.
     if (!generateArgumentsChecks())
         return false;
 
     if (frameClass_ != FrameSizeClass::None()) {
-        deoptTable_ = GetIonContext()->compartment->ionCompartment()->getBailoutTable(frameClass_);
+        deoptTable_ = gen->ionRuntime()->getBailoutTable(frameClass_);
         if (!deoptTable_)
             return false;
     }
 
 #if JS_TRACE_LOGGING
     Label skip;
     masm.jump(&skip);
 #endif
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -424,28 +424,28 @@ IonCompartment::sweep(FreeOp *fop)
     if (stringConcatStub_ && !IsIonCodeMarked(stringConcatStub_.unsafeGet()))
         stringConcatStub_ = NULL;
 
     if (parallelStringConcatStub_ && !IsIonCodeMarked(parallelStringConcatStub_.unsafeGet()))
         parallelStringConcatStub_ = NULL;
 }
 
 IonCode *
-IonCompartment::getBailoutTable(const FrameSizeClass &frameClass)
+IonRuntime::getBailoutTable(const FrameSizeClass &frameClass)
 {
     JS_ASSERT(frameClass != FrameSizeClass::None());
-    return rt->bailoutTables_[frameClass.classId()];
+    return bailoutTables_[frameClass.classId()];
 }
 
 IonCode *
-IonCompartment::getVMWrapper(const VMFunction &f)
+IonRuntime::getVMWrapper(const VMFunction &f)
 {
-    JS_ASSERT(rt->functionWrappers_);
-    JS_ASSERT(rt->functionWrappers_->initialized());
-    IonRuntime::VMWrapperMap::Ptr p = rt->functionWrappers_->readonlyThreadsafeLookup(&f);
+    JS_ASSERT(functionWrappers_);
+    JS_ASSERT(functionWrappers_->initialized());
+    IonRuntime::VMWrapperMap::Ptr p = functionWrappers_->readonlyThreadsafeLookup(&f);
     JS_ASSERT(p);
 
     return p->value;
 }
 
 IonCode *
 IonCode::New(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool)
 {
@@ -1785,17 +1785,17 @@ ion::CanEnterInParallel(JSContext *cx, H
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script, ParallelExecution);
         return status;
     }
 
     // This can GC, so afterward, script->parallelIon is
     // not guaranteed to be valid.
-    if (!cx->compartment()->ionCompartment()->enterJIT())
+    if (!cx->runtime()->ionRuntime()->enterIon())
         return Method_Error;
 
     // Subtle: it is possible for GC to occur during
     // compilation of one of the invoked functions, which
     // would cause the earlier functions (such as the
     // kernel itself) to be collected.  In this event, we
     // give up and fallback to sequential for now.
     if (!script->hasParallelIonScript()) {
@@ -1822,33 +1822,33 @@ ion::CanEnterUsingFastInvoke(JSContext *
     // missing arguments with |undefined|.
     if (numActualArgs < script->function()->nargs)
         return Method_Skipped;
 
     if (!cx->compartment()->ensureIonCompartmentExists(cx))
         return Method_Error;
 
     // This can GC, so afterward, script->ion is not guaranteed to be valid.
-    if (!cx->compartment()->ionCompartment()->enterJIT())
+    if (!cx->runtime()->ionRuntime()->enterIon())
         return Method_Error;
 
     if (!script->hasIonScript())
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
 static IonExecStatus
 EnterIon(JSContext *cx, EnterJitData &data)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Aborted);
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(!data.osrFrame);
 
-    EnterIonCode enter = cx->compartment()->ionCompartment()->enterJIT();
+    EnterIonCode enter = cx->runtime()->ionRuntime()->enterIon();
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         IonContext ictx(cx, NULL);
@@ -1955,17 +1955,17 @@ ion::FastInvoke(JSContext *cx, HandleFun
     IonCode *code = ion->method();
     void *jitcode = code->raw();
 
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(!ion->bailoutExpected());
 
     JitActivation activation(cx, /* firstFrameIsConstructing = */false);
 
-    EnterIonCode enter = cx->compartment()->ionCompartment()->enterJIT();
+    EnterIonCode enter = cx->runtime()->ionRuntime()->enterIon();
     void *calleeToken = CalleeToToken(fun);
 
     RootedValue result(cx, Int32Value(args.length()));
     JS_ASSERT(args.length() >= fun->nargs);
 
     JSAutoResolveFlags rf(cx, RESOLVE_INFER);
     enter(jitcode, args.length() + 1, args.array() - 1, NULL, calleeToken,
           /* scopeChain = */ NULL, 0, result.address());
--- a/js/src/ion/IonCompartment.h
+++ b/js/src/ion/IonCompartment.h
@@ -182,18 +182,16 @@ class IonRuntime
     IonCode *generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut);
     IonCode *generateBailoutTable(JSContext *cx, uint32_t frameClass);
     IonCode *generateBailoutHandler(JSContext *cx);
     IonCode *generateInvalidator(JSContext *cx);
     IonCode *generatePreBarrier(JSContext *cx, MIRType type);
     IonCode *generateDebugTrapHandler(JSContext *cx);
     IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
 
-    IonCode *debugTrapHandler(JSContext *cx);
-
   public:
     IonRuntime();
     ~IonRuntime();
     bool initialize(JSContext *cx);
 
     uint8_t *allocateOsrTempData(size_t size);
     void freeOsrTempData();
 
@@ -201,16 +199,65 @@ class IonRuntime
 
     AutoFlushCache *flusher() {
         return flusher_;
     }
     void setFlusher(AutoFlushCache *fl) {
         if (!flusher_ || !fl)
             flusher_ = fl;
     }
+
+    IonCode *getVMWrapper(const VMFunction &f);
+    IonCode *debugTrapHandler(JSContext *cx);
+
+    IonCode *getGenericBailoutHandler() const {
+        return bailoutHandler_;
+    }
+
+    IonCode *getExceptionTail() const {
+        return exceptionTail_;
+    }
+
+    IonCode *getBailoutTail() const {
+        return bailoutTail_;
+    }
+
+    IonCode *getBailoutTable(const FrameSizeClass &frameClass);
+
+    IonCode *getArgumentsRectifier(ExecutionMode mode) const {
+        switch (mode) {
+          case SequentialExecution: return argumentsRectifier_;
+          case ParallelExecution:   return parallelArgumentsRectifier_;
+          default:                  MOZ_ASSUME_UNREACHABLE("No such execution mode");
+        }
+    }
+
+    void *getArgumentsRectifierReturnAddr() const {
+        return argumentsRectifierReturnAddr_;
+    }
+
+    IonCode *getInvalidationThunk() const {
+        return invalidator_;
+    }
+
+    EnterIonCode enterIon() const {
+        return enterJIT_->as<EnterIonCode>();
+    }
+
+    EnterIonCode enterBaseline() const {
+        return enterBaselineJIT_->as<EnterIonCode>();
+    }
+
+    IonCode *valuePreBarrier() const {
+        return valuePreBarrier_;
+    }
+
+    IonCode *shapePreBarrier() const {
+        return shapePreBarrier_;
+    }
 };
 
 class IonCompartment
 {
     friend class JitActivation;
 
     // Ion state for the compartment's runtime.
     IonRuntime *rt;
@@ -239,18 +286,16 @@ class IonCompartment
     // pointers. This has to be a weak pointer to avoid keeping the whole
     // compartment alive.
     ReadBarriered<IonCode> stringConcatStub_;
     ReadBarriered<IonCode> parallelStringConcatStub_;
 
     IonCode *generateStringConcatStub(JSContext *cx, ExecutionMode mode);
 
   public:
-    IonCode *getVMWrapper(const VMFunction &f);
-
     OffThreadCompilationVector &finishedOffThreadCompilations() {
         return finishedOffThreadCompilations_;
     }
 
     IonCode *getStubCode(uint32_t key) {
         ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
         if (p)
             return p->value;
@@ -302,66 +347,16 @@ class IonCompartment
 
     void mark(JSTracer *trc, JSCompartment *compartment);
     void sweep(FreeOp *fop);
 
     JSC::ExecutableAllocator *execAlloc() {
         return rt->execAlloc_;
     }
 
-    IonCode *getGenericBailoutHandler() {
-        return rt->bailoutHandler_;
-    }
-
-    IonCode *getExceptionTail() {
-        return rt->exceptionTail_;
-    }
-
-    IonCode *getBailoutTail() {
-        return rt->bailoutTail_;
-    }
-
-    IonCode *getBailoutTable(const FrameSizeClass &frameClass);
-
-    IonCode *getArgumentsRectifier(ExecutionMode mode) {
-        switch (mode) {
-          case SequentialExecution: return rt->argumentsRectifier_;
-          case ParallelExecution:   return rt->parallelArgumentsRectifier_;
-          default:                  MOZ_ASSUME_UNREACHABLE("No such execution mode");
-        }
-    }
-
-    void *getArgumentsRectifierReturnAddr() {
-        return rt->argumentsRectifierReturnAddr_;
-    }
-
-    IonCode *getInvalidationThunk() {
-        return rt->invalidator_;
-    }
-
-    EnterIonCode enterJIT() {
-        return rt->enterJIT_->as<EnterIonCode>();
-    }
-
-    EnterIonCode enterBaselineJIT() {
-        return rt->enterBaselineJIT_->as<EnterIonCode>();
-    }
-
-    IonCode *valuePreBarrier() {
-        return rt->valuePreBarrier_;
-    }
-
-    IonCode *shapePreBarrier() {
-        return rt->shapePreBarrier_;
-    }
-
-    IonCode *debugTrapHandler(JSContext *cx) {
-        return rt->debugTrapHandler(cx);
-    }
-
     IonCode *stringConcatStub(ExecutionMode mode) {
         switch (mode) {
           case SequentialExecution: return stringConcatStub_;
           case ParallelExecution:   return parallelStringConcatStub_;
           default:                  MOZ_ASSUME_UNREACHABLE("No such execution mode");
         }
     }
 
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -493,20 +493,20 @@ class MacroAssembler : public MacroAssem
         Label done;
 
         if (type == MIRType_Value)
             branchTestGCThing(Assembler::NotEqual, address, &done);
 
         Push(PreBarrierReg);
         computeEffectiveAddress(address, PreBarrierReg);
 
-        JSCompartment *compartment = GetIonContext()->compartment;
+        JSRuntime *runtime = GetIonContext()->runtime;
         IonCode *preBarrier = (type == MIRType_Shape)
-                              ? compartment->ionCompartment()->shapePreBarrier()
-                              : compartment->ionCompartment()->valuePreBarrier();
+                              ? runtime->ionRuntime()->shapePreBarrier()
+                              : runtime->ionRuntime()->valuePreBarrier();
 
         call(preBarrier);
         Pop(PreBarrierReg);
 
         bind(&done);
     }
 
     template <typename T>
--- a/js/src/ion/MIRGenerator.h
+++ b/js/src/ion/MIRGenerator.h
@@ -54,16 +54,19 @@ class MIRGenerator
         return *graph_;
     }
     bool ensureBallast() {
         return temp().ensureBallast();
     }
     IonCompartment *ionCompartment() const {
         return compartment->ionCompartment();
     }
+    IonRuntime *ionRuntime() const {
+        return compartment->rt->ionRuntime();
+    }
     CompileInfo &info() {
         return *info_;
     }
 
     template <typename T>
     T * allocate(size_t count = 1) {
         return reinterpret_cast<T *>(temp().allocate(sizeof(T) * count));
     }
--- a/js/src/ion/arm/Bailouts-arm.cpp
+++ b/js/src/ion/arm/Bailouts-arm.cpp
@@ -127,19 +127,18 @@ IonBailoutIterator::IonBailoutIterator(c
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
     JitActivation *activation = activations.activation()->asJit();
-    JSCompartment *jsCompartment = activation->compartment();
-    IonCompartment *ionCompartment = jsCompartment->ionCompartment();
-    IonCode *code = ionCompartment->getBailoutTable(bailout->frameClass());
+    JSRuntime *rt = activation->compartment()->rt;
+    IonCode *code = rt->ionRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     JS_ASSERT(tableOffset >= tableStart &&
               tableOffset < tableStart + code->instructionsSize());
     JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -156,19 +156,17 @@ CodeGeneratorARM::generateOutOfLineCode(
 
     if (deoptLabel_.used()) {
         // All non-table-based bailouts will go here.
         masm.bind(&deoptLabel_);
 
         // Push the frame size, so the handler can recover the IonScript.
         masm.ma_mov(Imm32(frameSize()), lr);
 
-        IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
-        IonCode *handler = ion->getGenericBailoutHandler();
-
+        IonCode *handler = gen->ionRuntime()->getGenericBailoutHandler();
         masm.branch(handler);
     }
 
     return true;
 }
 
 bool
 CodeGeneratorARM::bailoutIf(Assembler::Condition condition, LSnapshot *snapshot)
@@ -1726,17 +1724,17 @@ CodeGeneratorARM::generateInvalidateEpil
 
     masm.bind(&invalidate_);
 
     // Push the return address of the point that we bailed out at onto the stack
     masm.Push(lr);
 
     // Push the Ion script onto the stack (when we determine what that pointer is).
     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
-    IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk();
+    IonCode *thunk = gen->ionRuntime()->getInvalidationThunk();
 
     masm.branch(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk should
     // pop the invalidated JS frame and return directly to its caller.
     masm.breakpoint();
     return true;
 }
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -3299,17 +3299,17 @@ MacroAssemblerARMCompat::handleFailureWi
     ma_sub(Imm32(size), sp);
     ma_mov(sp, r0);
 
     // Ask for an exception handler.
     setupUnalignedABICall(1, r1);
     passABIArg(r0);
     callWithABI(handler);
 
-    IonCode *excTail = GetIonContext()->compartment->ionCompartment()->getExceptionTail();
+    IonCode *excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail();
     branch(excTail);
 }
 
 void
 MacroAssemblerARMCompat::handleFailureWithHandlerTail()
 {
     Label entryFrame;
     Label catch_;
--- a/js/src/ion/arm/Trampoline-arm.cpp
+++ b/js/src/ion/arm/Trampoline-arm.cpp
@@ -344,17 +344,17 @@ IonRuntime::generateInvalidator(JSContex
     // Remove the return address, the IonScript, the register state
     // (InvaliationBailoutStack) and the space that was allocated for the return value
     masm.ma_add(sp, Imm32(sizeof(InvalidationBailoutStack) + sizeOfRetval + sizeOfBailoutInfo), sp);
     // remove the space that this frame was using before the bailout
     // (computed by InvalidationBailout)
     masm.ma_add(sp, r1, sp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.branch(bailoutTail);
 
     Linker linker(masm);
     IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
     IonSpew(IonSpew_Invalidate, "   invalidation thunk created at %p", (void *) code->raw());
     return code;
 }
 
@@ -548,17 +548,17 @@ GenerateBailoutThunk(JSContext *cx, Macr
         uint32_t frameSize = FrameSizeClass::FromClass(frameClass).frameSize();
         masm.ma_add(Imm32(frameSize // the frame that was added when we entered the most recent function
                           + sizeof(void*) // the size of the "return address" that was dumped on the stack
                           + bailoutFrameSize) // everything else that was pushed on the stack
                     , sp);
     }
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.branch(bailoutTail);
 }
 
 IonCode *
 IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MacroAssembler masm(cx);
 
@@ -801,18 +801,17 @@ IonRuntime::generateDebugTrapHandler(JSC
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
 
     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
     // the stub frame has a NULL ICStub pointer, since this pointer is marked
     // during GC.
     masm.movePtr(ImmWord((void *)NULL), BaselineStubReg);
     EmitEnterStubFrame(masm, scratch2);
 
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(HandleDebugTrapInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(HandleDebugTrapInfo);
     if (!code)
         return NULL;
 
     masm.push(lr);
     masm.push(scratch1);
     EmitCallVM(code, masm);
 
     EmitLeaveStubFrame(masm);
--- a/js/src/ion/shared/BaselineCompiler-shared.cpp
+++ b/js/src/ion/shared/BaselineCompiler-shared.cpp
@@ -28,18 +28,17 @@ BaselineCompilerShared::BaselineCompiler
     pushedBeforeCall_(0),
     inCall_(false),
     spsPushToggleOffset_()
 { }
 
 bool
 BaselineCompilerShared::callVM(const VMFunction &fun)
 {
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(fun);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
 #ifdef DEBUG
     // Assert prepareVMCall() has been called.
     JS_ASSERT(inCall_);
     inCall_ = false;
 #endif
--- a/js/src/ion/shared/CodeGenerator-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-shared.cpp
@@ -440,18 +440,17 @@ CodeGeneratorShared::callVM(const VMFunc
     //    ... frame ...
     //    [args]
 #ifdef DEBUG
     JS_ASSERT(pushedArgs_ == fun.explicitArgs);
     pushedArgs_ = 0;
 #endif
 
     // Get the wrapper of the VM function.
-    IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
-    IonCode *wrapper = ion->getVMWrapper(fun);
+    IonCode *wrapper = gen->ionRuntime()->getVMWrapper(fun);
     if (!wrapper)
         return false;
 
     // Call the wrapper function.  The wrapper is in charge to unwind the stack
     // when returning from the call.  Failures are handled with exceptions based
     // on the return value of the C functions.  To guard the outcome of the
     // returned value, use another LIR instruction.
     uint32_t callOffset;
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -240,19 +240,17 @@ CodeGeneratorX86Shared::generateOutOfLin
 
     if (deoptLabel_.used()) {
         // All non-table-based bailouts will go here.
         masm.bind(&deoptLabel_);
 
         // Push the frame size, so the handler can recover the IonScript.
         masm.push(Imm32(frameSize()));
 
-        IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
-        IonCode *handler = ion->getGenericBailoutHandler();
-
+        IonCode *handler = gen->ionRuntime()->getGenericBailoutHandler();
         masm.jmp(handler->raw(), Relocation::IONCODE);
     }
 
     return true;
 }
 
 class BailoutJump {
     Assembler::Condition cond_;
@@ -1471,17 +1469,17 @@ CodeGeneratorX86Shared::generateInvalida
     // epilogue.
     for (size_t i = 0; i < sizeof(void *); i+= Assembler::nopSize())
         masm.nop();
 
     masm.bind(&invalidate_);
 
     // Push the Ion script onto the stack (when we determine what that pointer is).
     invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
-    IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk();
+    IonCode *thunk = gen->ionRuntime()->getInvalidationThunk();
 
     masm.call(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk should
     // pop the invalidated JS frame and return directly to its caller.
     masm.breakpoint();
     return true;
 }
--- a/js/src/ion/x64/MacroAssembler-x64.cpp
+++ b/js/src/ion/x64/MacroAssembler-x64.cpp
@@ -237,17 +237,17 @@ MacroAssemblerX64::handleFailureWithHand
     subq(Imm32(sizeof(ResumeFromException)), rsp);
     movq(rsp, rax);
 
     // Ask for an exception handler.
     setupUnalignedABICall(1, rcx);
     passABIArg(rax);
     callWithABI(handler);
 
-    IonCode *excTail = GetIonContext()->compartment->ionCompartment()->getExceptionTail();
+    IonCode *excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail();
     jmp(excTail);
 }
 
 void
 MacroAssemblerX64::handleFailureWithHandlerTail()
 {
     Label entryFrame;
     Label catch_;
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -307,17 +307,17 @@ IonRuntime::generateInvalidator(JSContex
 
     masm.pop(r9); // Get the bailoutInfo outparam.
     masm.pop(rbx); // Get the frameSize outparam.
 
     // Pop the machine state and the dead frame.
     masm.lea(Operand(rsp, rbx, TimesOne, sizeof(InvalidationBailoutStack)), rsp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 
     Linker linker(masm);
     return linker.newCode(cx, JSC::OTHER_CODE);
 }
 
 IonCode *
 IonRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut)
@@ -441,17 +441,17 @@ GenerateBailoutThunk(JSContext *cx, Macr
     // Remove both the bailout frame and the topmost Ion frame's stack.
     static const uint32_t BailoutDataSize = sizeof(void *) * Registers::Total +
                                           sizeof(double) * FloatRegisters::Total;
     masm.addq(Imm32(BailoutDataSize), rsp);
     masm.pop(rcx);
     masm.lea(Operand(rsp, rcx, TimesOne, sizeof(void *)), rsp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in r9.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 }
 
 IonCode *
 IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MOZ_ASSUME_UNREACHABLE("x64 does not use bailout tables");
 }
@@ -693,18 +693,17 @@ IonRuntime::generateDebugTrapHandler(JSC
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
 
     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
     // the stub frame has a NULL ICStub pointer, since this pointer is marked
     // during GC.
     masm.movePtr(ImmWord((void *)NULL), BaselineStubReg);
     EmitEnterStubFrame(masm, scratch3);
 
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(HandleDebugTrapInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(HandleDebugTrapInfo);
     if (!code)
         return NULL;
 
     masm.push(scratch1);
     masm.push(scratch2);
     EmitCallVM(code, masm);
 
     EmitLeaveStubFrame(masm);
--- a/js/src/ion/x86/Bailouts-x86.cpp
+++ b/js/src/ion/x86/Bailouts-x86.cpp
@@ -80,19 +80,18 @@ IonBailoutIterator::IonBailoutIterator(c
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
     JitActivation *activation = activations.activation()->asJit();
-    JSCompartment *jsCompartment = activation->compartment();
-    IonCompartment *ionCompartment = jsCompartment->ionCompartment();
-    IonCode *code = ionCompartment->getBailoutTable(bailout->frameClass());
+    JSRuntime *rt = activation->compartment()->rt;
+    IonCode *code = rt->ionRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     JS_ASSERT(tableOffset >= tableStart &&
               tableOffset < tableStart + code->instructionsSize());
     JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
--- a/js/src/ion/x86/MacroAssembler-x86.cpp
+++ b/js/src/ion/x86/MacroAssembler-x86.cpp
@@ -209,17 +209,17 @@ MacroAssemblerX86::handleFailureWithHand
     subl(Imm32(sizeof(ResumeFromException)), esp);
     movl(esp, eax);
 
     // Ask for an exception handler.
     setupUnalignedABICall(1, ecx);
     passABIArg(eax);
     callWithABI(handler);
 
-    IonCode *excTail = GetIonContext()->compartment->ionCompartment()->getExceptionTail();
+    IonCode *excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail();
     jmp(excTail);
 }
 
 void
 MacroAssemblerX86::handleFailureWithHandlerTail()
 {
     Label entryFrame;
     Label catch_;
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -293,17 +293,17 @@ IonRuntime::generateInvalidator(JSContex
 
     masm.pop(ecx); // Get bailoutInfo outparam.
     masm.pop(ebx); // Get the frameSize outparam.
 
     // Pop the machine state and the dead frame.
     masm.lea(Operand(esp, ebx, TimesOne, sizeof(InvalidationBailoutStack)), esp);
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in ecx.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 
     Linker linker(masm);
     IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
     IonSpew(IonSpew_Invalidate, "   invalidation thunk created at %p", (void *) code->raw());
     return code;
 }
 
@@ -456,17 +456,17 @@ GenerateBailoutThunk(JSContext *cx, Macr
         //    ... frame ...
         //    bailoutId
         //    ... bailoutFrame ...
         uint32_t frameSize = FrameSizeClass::FromClass(frameClass).frameSize();
         masm.addl(Imm32(BailoutDataSize + sizeof(void *) + frameSize), esp);
     }
 
     // Jump to shared bailout tail. The BailoutInfo pointer has to be in ecx.
-    IonCode *bailoutTail = cx->compartment()->ionCompartment()->getBailoutTail();
+    IonCode *bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail();
     masm.jmp(bailoutTail);
 }
 
 IonCode *
 IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MacroAssembler masm;
 
@@ -719,18 +719,17 @@ IonRuntime::generateDebugTrapHandler(JSC
     masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
 
     // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
     // the stub frame has a NULL ICStub pointer, since this pointer is marked
     // during GC.
     masm.movePtr(ImmWord((void *)NULL), BaselineStubReg);
     EmitEnterStubFrame(masm, scratch3);
 
-    IonCompartment *ion = cx->compartment()->ionCompartment();
-    IonCode *code = ion->getVMWrapper(HandleDebugTrapInfo);
+    IonCode *code = cx->runtime()->ionRuntime()->getVMWrapper(HandleDebugTrapInfo);
     if (!code)
         return NULL;
 
     masm.push(scratch1);
     masm.push(scratch2);
     EmitCallVM(code, masm);
 
     EmitLeaveStubFrame(masm);
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1242,33 +1242,33 @@ class ParallelIonInvoke
     void *jitcode_;
     void *calleeToken_;
     Value argv_[maxArgc + 2];
     uint32_t argc_;
 
   public:
     Value *args;
 
-    ParallelIonInvoke(JSCompartment *compartment,
+    ParallelIonInvoke(JSRuntime *rt,
                       HandleFunction callee,
                       uint32_t argc)
       : argc_(argc),
         args(argv_ + 2)
     {
         JS_ASSERT(argc <= maxArgc + 2);
 
         // Set 'callee' and 'this'.
         argv_[0] = ObjectValue(*callee);
         argv_[1] = UndefinedValue();
 
         // Find JIT code pointer.
         IonScript *ion = callee->nonLazyScript()->parallelIonScript();
         IonCode *code = ion->method();
         jitcode_ = code->raw();
-        enter_ = compartment->ionCompartment()->enterJIT();
+        enter_ = rt->ionRuntime()->enterIon();
         calleeToken_ = CalleeToParallelToken(callee);
     }
 
     bool invoke(PerThreadData *perThread) {
         RootedValue result(perThread);
         enter_(jitcode_, argc_ + 1, argv_ + 1, NULL, calleeToken_, NULL, 0, result.address());
         return !result.isMagic();
     }
@@ -1465,17 +1465,17 @@ ForkJoinShared::executePortion(PerThread
         // script can be collected between starting the parallel
         // op and reaching this point.  In that case, we just fail
         // and fallback.
         Spew(SpewOps, "Down (Script no longer present)");
         slice.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent,
                                       NULL, NULL, NULL);
         setAbortFlag(false);
     } else {
-        ParallelIonInvoke<3> fii(cx_->compartment(), callee, 3);
+        ParallelIonInvoke<3> fii(cx_->runtime(), callee, 3);
 
         fii.args[0] = Int32Value(slice.sliceId);
         fii.args[1] = Int32Value(slice.numSlices);
         fii.args[2] = BooleanValue(false);
 
         bool ok = fii.invoke(perThread);
         JS_ASSERT(ok == !slice.bailoutRecord->topScript);
         if (!ok)