Backout 589b6766b99a (bug 786146) due to test bustage on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 25 Oct 2012 20:05:13 -0400
changeset 111598 f5e702c39521bb6fb440664593d7dbcbd5bf3da8
parent 111597 b3a9ae0f6abfb48bbcbc7a51fb34c08dbd65df24
child 111599 795511f1212df5c254b47aae900137fbe085ffef
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
bugs786146
milestone19.0a1
backs out589b6766b99a4ba4674035201376f35fde602334
Backout 589b6766b99a (bug 786146) due to test bustage on a CLOSED TREE.
js/src/ion/CodeGenerator.cpp
js/src/ion/Ion.cpp
js/src/ion/IonCompartment.h
js/src/ion/IonFrames.cpp
js/src/ion/IonFrames.h
js/src/ion/IonMacroAssembler.h
js/src/ion/VMFunctions.cpp
js/src/ion/VMFunctions.h
js/src/ion/arm/CodeGenerator-arm.cpp
js/src/ion/arm/Trampoline-arm.cpp
js/src/ion/shared/CodeGenerator-shared.cpp
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/x64/CodeGenerator-x64.cpp
js/src/ion/x64/MacroAssembler-x64.h
js/src/ion/x64/Trampoline-x64.cpp
js/src/ion/x86/CodeGenerator-x86.cpp
js/src/ion/x86/Trampoline-x86.cpp
js/src/jsapi.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsgc.cpp
js/src/jsgcinlines.h
js/src/jsworkers.cpp
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -196,62 +196,60 @@ CodeGenerator::visitPolyInlineDispatch(L
                 // Don't generate guard for final case
                 masm.jump(target->label());
             }
         }
     }
     return true;
 }
 
-typedef JSFlatString *(*IntToStringFn)(JSContext *, int);
-static const VMFunction IntToStringInfo =
-    FunctionInfo<IntToStringFn>(Int32ToString);
-
 bool
 CodeGenerator::visitIntToString(LIntToString *lir)
 {
     Register input = ToRegister(lir->input());
     Register output = ToRegister(lir->output());
 
+    typedef JSFlatString *(*pf)(JSContext *, int);
+    static const VMFunction IntToStringInfo = FunctionInfo<pf>(Int32ToString);
+
     OutOfLineCode *ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input),
                                    StoreRegisterTo(output));
     if (!ool)
         return false;
 
     masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT),
                   ool->entry());
 
     masm.movePtr(ImmWord(&gen->compartment->rt->staticStrings.intStaticTable), output);
     masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*CloneRegExpObjectFn)(JSContext *, JSObject *, JSObject *);
-static const VMFunction CloneRegExpObjectInfo =
-    FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject);
-
 bool
 CodeGenerator::visitRegExp(LRegExp *lir)
 {
     JSObject *proto = lir->mir()->getRegExpPrototype();
 
+    typedef JSObject *(*pf)(JSContext *, JSObject *, JSObject *);
+    static const VMFunction CloneRegExpObjectInfo = FunctionInfo<pf>(CloneRegExpObject);
+
     pushArg(ImmGCPtr(proto));
     pushArg(ImmGCPtr(lir->mir()->source()));
     return callVM(CloneRegExpObjectInfo, lir);
 }
 
-typedef bool (*ExecuteRegExpFn)(JSContext *cx, RegExpExecType type, HandleObject regexp,
-                                HandleString string, MutableHandleValue rval);
-static const VMFunction ExecuteRegExpInfo = FunctionInfo<ExecuteRegExpFn>(ExecuteRegExp);
-
 bool
 CodeGenerator::visitRegExpTest(LRegExpTest *lir)
 {
+    typedef bool (*pf)(JSContext *cx, RegExpExecType type, HandleObject regexp,
+                       HandleString string, MutableHandleValue rval);
+    static const VMFunction ExecuteRegExpInfo = FunctionInfo<pf>(ExecuteRegExp);
+
     pushArg(ToRegister(lir->string()));
     pushArg(ToRegister(lir->regexp()));
     pushArg(Imm32(RegExpTest));
     if (!callVM(ExecuteRegExpInfo, lir))
         return false;
 
     Register output = ToRegister(lir->output());
     Label notBool, end;
@@ -259,36 +257,38 @@ CodeGenerator::visitRegExpTest(LRegExpTe
     masm.unboxBoolean(JSReturnOperand, output);
     masm.jump(&end);
     masm.bind(&notBool);
     masm.mov(Imm32(0), output);
     masm.bind(&end);
     return true;
 }
 
-typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
-static const VMFunction LambdaInfo =
-    FunctionInfo<LambdaFn>(js::Lambda);
-
 bool
 CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir)
 {
+    typedef JSObject *(*pf)(JSContext *, HandleFunction, HandleObject);
+    static const VMFunction Info = FunctionInfo<pf>(js::Lambda);
+
     pushArg(ToRegister(lir->scopeChain()));
     pushArg(ImmGCPtr(lir->mir()->fun()));
-    return callVM(LambdaInfo, lir);
+    return callVM(Info, lir);
 }
 
 bool
 CodeGenerator::visitLambda(LLambda *lir)
 {
     Register scopeChain = ToRegister(lir->scopeChain());
     Register output = ToRegister(lir->output());
     JSFunction *fun = lir->mir()->fun();
 
-    OutOfLineCode *ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(fun), scopeChain),
+    typedef JSObject *(*pf)(JSContext *, HandleFunction, HandleObject);
+    static const VMFunction Info = FunctionInfo<pf>(js::Lambda);
+
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), ImmGCPtr(fun), scopeChain),
                                    StoreRegisterTo(output));
     if (!ool)
         return false;
 
     JS_ASSERT(gen->compartment == fun->compartment());
     JS_ASSERT(!fun->hasSingletonType());
 
     masm.newGCThing(output, fun, ool->entry());
@@ -762,24 +762,24 @@ CodeGenerator::visitCallDOMNative(LCallD
     // Move the StackPointer back to its original location, unwinding the native exit frame.
     masm.adjustStack(IonDOMMethodExitFrameLayout::Size() - unusedStack);
     JS_ASSERT(masm.framePushed() == initialStack);
 
     dropArguments(call->numStackArgs() + 1);
     return true;
 }
 
-typedef bool (*InvokeFunctionFn)(JSContext *, JSFunction *, uint32, Value *, Value *);
-static const VMFunction InvokeFunctionInfo =
-    FunctionInfo<InvokeFunctionFn>(InvokeFunction);
 
 bool
 CodeGenerator::emitCallInvokeFunction(LInstruction *call, Register calleereg,
                                       uint32 argc, uint32 unusedStack)
 {
+    typedef bool (*pf)(JSContext *, JSFunction *, uint32, Value *, Value *);
+    static const VMFunction InvokeFunctionInfo = FunctionInfo<pf>(InvokeFunction);
+
     // Nestle %esp up to the argument vector.
     // Each path must account for framePushed_ separately, for callVM to be valid.
     masm.freeStack(unusedStack);
 
     pushArg(StackPointer); // argv.
     pushArg(Imm32(argc));  // argc.
     pushArg(calleereg);    // JSFunction *.
 
@@ -802,17 +802,19 @@ CodeGenerator::visitCallGeneric(LCallGen
 
     // Known-target case is handled by LCallKnown.
     JS_ASSERT(!call->hasSingleTarget());
     // Unknown constructor case is handled by LCallConstructor.
     JS_ASSERT(!call->mir()->isConstructing());
 
     // Generate an ArgumentsRectifier.
     IonCompartment *ion = gen->ionCompartment();
-    IonCode *argumentsRectifier = ion->getArgumentsRectifier();
+    IonCode *argumentsRectifier = ion->getArgumentsRectifier(GetIonContext()->cx);
+    if (!argumentsRectifier)
+        return false;
 
     masm.checkStackAlignment();
 
     // Guard that calleereg is actually a function object.
     masm.loadObjClass(calleereg, nargsreg);
     masm.cmpPtr(nargsreg, ImmWord(&js::FunctionClass));
     if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
         return false;
@@ -959,32 +961,31 @@ CodeGenerator::visitCallKnown(LCallKnown
         masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
         masm.bind(&notPrimitive);
     }
 
     dropArguments(call->numStackArgs() + 1);
     return true;
 }
 
-typedef bool (*InvokeConstructorFn)(JSContext *, JSObject *, uint32, Value *, Value *);
-static const VMFunction InvokeConstructorInfo =
-    FunctionInfo<InvokeConstructorFn>(ion::InvokeConstructor);
-
 bool
 CodeGenerator::visitCallConstructor(LCallConstructor *call)
 {
     JS_ASSERT(call->mir()->isConstructing());
 
     // Holds the function object.
     const LAllocation *callee = call->getFunction();
     Register calleereg = ToRegister(callee);
 
     uint32 callargslot = call->argslot();
     uint32 unusedStack = StackOffsetOfPassedArg(callargslot);
 
+    typedef bool (*pf)(JSContext *, JSObject *, uint32, Value *, Value *);
+    static const VMFunction InvokeConstructorInfo = FunctionInfo<pf>(ion::InvokeConstructor);
+
     // Nestle %esp up to the argument vector.
     masm.freeStack(unusedStack);
 
     pushArg(StackPointer);                  // argv.
     pushArg(Imm32(call->numActualArgs()));  // argc.
     pushArg(calleereg);                     // JSFunction *.
 
     if (!callVM(InvokeConstructorInfo, call))
@@ -998,16 +999,19 @@ CodeGenerator::visitCallConstructor(LCal
 }
 
 bool
 CodeGenerator::emitCallInvokeFunction(LApplyArgsGeneric *apply, Register extraStackSize)
 {
     Register objreg = ToRegister(apply->getTempObject());
     JS_ASSERT(objreg != extraStackSize);
 
+    typedef bool (*pf)(JSContext *, JSFunction *, uint32, Value *, Value *);
+    static const VMFunction InvokeFunctionInfo = FunctionInfo<pf>(InvokeFunction);
+
     // Push the space used by the arguments.
     masm.movePtr(StackPointer, objreg);
     masm.Push(extraStackSize);
 
     pushArg(objreg);                           // argv.
     pushArg(ToRegister(apply->getArgc()));     // argc.
     pushArg(ToRegister(apply->getFunction())); // JSFunction *.
 
@@ -1171,17 +1175,19 @@ CodeGenerator::visitApplyArgsGeneric(LAp
         }
 
         // 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();
+            IonCode *argumentsRectifier = ion->getArgumentsRectifier(GetIonContext()->cx);
+            if (!argumentsRectifier)
+                return false;
 
             JS_ASSERT(ArgumentsRectifierReg != objreg);
             masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
             masm.movePtr(Address(objreg, IonCode::offsetOfCode()), objreg);
             masm.movePtr(argcreg, ArgumentsRectifierReg);
         }
 
         masm.bind(&rejoin);
@@ -1307,48 +1313,47 @@ CodeGenerator::visitCheckOverRecursed(LC
 
     // Conditional forward (unlikely) branch to failure.
     masm.branchPtr(Assembler::BelowOrEqual, StackPointer, limitReg, ool->entry());
     masm.bind(ool->rejoin());
 
     return true;
 }
 
-typedef bool (*DefVarOrConstFn)(JSContext *, HandlePropertyName, unsigned, HandleObject);
-static const VMFunction DefVarOrConstInfo =
-    FunctionInfo<DefVarOrConstFn>(DefVarOrConst);
-
 bool
 CodeGenerator::visitDefVar(LDefVar *lir)
 {
     Register scopeChain = ToRegister(lir->getScopeChain());
     Register nameTemp   = ToRegister(lir->nameTemp());
 
+    typedef bool (*pf)(JSContext *, HandlePropertyName, unsigned, HandleObject);
+    static const VMFunction DefVarOrConstInfo = FunctionInfo<pf>(DefVarOrConst);
+
     masm.movePtr(ImmGCPtr(lir->mir()->name()), nameTemp);
 
     pushArg(scopeChain); // JSObject *
     pushArg(Imm32(lir->mir()->attrs())); // unsigned
     pushArg(nameTemp); // PropertyName *
 
     if (!callVM(DefVarOrConstInfo, lir))
         return false;
 
     return true;
 }
 
-typedef bool (*ReportOverRecursedFn)(JSContext *);
-static const VMFunction CheckOverRecursedInfo =
-    FunctionInfo<ReportOverRecursedFn>(CheckOverRecursed);
-
 bool
 CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool)
 {
     // The OOL path is hit if the recursion depth has been exceeded.
     // Throw an InternalError for over-recursion.
 
+    typedef bool (*pf)(JSContext *);
+    static const VMFunction CheckOverRecursedInfo =
+        FunctionInfo<pf>(CheckOverRecursed);
+
     // LFunctionEnvironment can appear before LCheckOverRecursed, so we have
     // to save all live registers to avoid crashes if CheckOverRecursed triggers
     // a GC.
     saveLive(ool->lir());
 
     if (!callVM(CheckOverRecursedInfo, ool->lir()))
         return false;
 
@@ -1394,25 +1399,24 @@ class OutOfLineNewArray : public OutOfLi
         return codegen->visitOutOfLineNewArray(this);
     }
 
     LNewArray *lir() const {
         return lir_;
     }
 };
 
-typedef JSObject *(*NewInitArrayFn)(JSContext *, uint32, types::TypeObject *);
-static const VMFunction NewInitArrayInfo =
-    FunctionInfo<NewInitArrayFn>(NewInitArray);
-
 bool
 CodeGenerator::visitNewArrayCallVM(LNewArray *lir)
 {
     Register objReg = ToRegister(lir->output());
 
+    typedef JSObject *(*pf)(JSContext *, uint32, types::TypeObject *);
+    static const VMFunction NewInitArrayInfo = FunctionInfo<pf>(NewInitArray);
+
     JS_ASSERT(!lir->isCall());
     saveLive(lir);
 
     JSObject *templateObject = lir->mir()->templateObject();
     types::TypeObject *type = templateObject->hasSingletonType() ? NULL : templateObject->type();
 
     pushArg(ImmGCPtr(type));
     pushArg(Imm32(lir->mir()->count()));
@@ -1505,29 +1509,29 @@ class OutOfLineNewObject : public OutOfL
         return codegen->visitOutOfLineNewObject(this);
     }
 
     LNewObject *lir() const {
         return lir_;
     }
 };
 
-typedef JSObject *(*NewInitObjectFn)(JSContext *, HandleObject);
-static const VMFunction NewInitObjectInfo = FunctionInfo<NewInitObjectFn>(NewInitObject);
-
 bool
 CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
 {
     Register objReg = ToRegister(lir->output());
 
+    typedef JSObject *(*pf)(JSContext *, HandleObject);
+    static const VMFunction Info = FunctionInfo<pf>(NewInitObject);
+
     JS_ASSERT(!lir->isCall());
     saveLive(lir);
 
     pushArg(ImmGCPtr(lir->mir()->templateObject()));
-    if (!callVM(NewInitObjectInfo, lir))
+    if (!callVM(Info, lir))
         return false;
 
     if (ReturnReg != objReg)
         masm.movePtr(ReturnReg, objReg);
 
     restoreLive(lir);
     return true;
 }
@@ -1557,26 +1561,24 @@ bool
 CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject *ool)
 {
     if (!visitNewObjectVMCall(ool->lir()))
         return false;
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape,
-                                     HandleTypeObject, HeapSlot *);
-static const VMFunction NewCallObjectInfo =
-    FunctionInfo<NewCallObjectFn>(NewCallObject);
-
 bool
 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
 {
     Register obj = ToRegister(lir->output());
 
+    typedef JSObject *(*pf)(JSContext *, HandleShape, HandleTypeObject, HeapSlot *);
+    static const VMFunction NewCallObjectInfo = FunctionInfo<pf>(NewCallObject);
+
     JSObject *templateObj = lir->mir()->templateObj();
 
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool;
     if (lir->slots()->isRegister()) {
         ool = oolCallVM(NewCallObjectInfo, lir,
                         (ArgList(), ImmGCPtr(templateObj->lastProperty()),
                                     ImmGCPtr(templateObj->type()),
@@ -1596,26 +1598,26 @@ CodeGenerator::visitNewCallObject(LNewCa
     masm.initGCThing(obj, templateObj);
 
     if (lir->slots()->isRegister())
         masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*NewStringObjectFn)(JSContext *, HandleString);
-static const VMFunction NewStringObjectInfo = FunctionInfo<NewStringObjectFn>(NewStringObject);
-
 bool
 CodeGenerator::visitNewStringObject(LNewStringObject *lir)
 {
     Register input = ToRegister(lir->input());
     Register output = ToRegister(lir->output());
     Register temp = ToRegister(lir->temp());
 
+    typedef JSObject *(*pf)(JSContext *, HandleString);
+    static const VMFunction NewStringObjectInfo = FunctionInfo<pf>(NewStringObject);
+
     StringObject *templateObj = lir->mir()->templateObj();
 
     OutOfLineCode *ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input),
                                    StoreRegisterTo(output));
     if (!ool)
         return false;
 
     masm.newGCThing(output, templateObj, ool->entry());
@@ -1625,73 +1627,70 @@ CodeGenerator::visitNewStringObject(LNew
 
     masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
     masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool(*InitPropFn)(JSContext *cx, HandleObject obj,
-                          HandlePropertyName name, HandleValue value);
-static const VMFunction InitPropInfo =
-    FunctionInfo<InitPropFn>(InitProp);
-
 bool
 CodeGenerator::visitInitProp(LInitProp *lir)
 {
     Register objReg = ToRegister(lir->getObject());
 
+    typedef bool(*pf)(JSContext *, HandleObject, HandlePropertyName, HandleValue);
+    static const VMFunction InitPropInfo = FunctionInfo<pf>(InitProp);
+
     pushArg(ToValue(lir, LInitProp::ValueIndex));
     pushArg(ImmGCPtr(lir->mir()->propertyName()));
     pushArg(objReg);
 
     return callVM(InitPropInfo, lir);
 }
 
-typedef JSObject *(*NewGCThingFn)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize);
-static const VMFunction NewGCThingInfo =
-    FunctionInfo<NewGCThingFn>(js::ion::NewGCThing);
-
 bool
 CodeGenerator::visitCreateThis(LCreateThis *lir)
 {
     JS_ASSERT(lir->mir()->hasTemplateObject());
 
     JSObject *templateObject = lir->mir()->getTemplateObject();
     gc::AllocKind allocKind = templateObject->getAllocKind();
     int thingSize = (int)gc::Arena::thingSize(allocKind);
     Register objReg = ToRegister(lir->output());
 
+    typedef JSObject *(*pf)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize);
+    static const VMFunction NewGCThingInfo = FunctionInfo<pf>(js::ion::NewGCThing);
+
     OutOfLineCode *ool = oolCallVM(NewGCThingInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(thingSize)),
                                    StoreRegisterTo(objReg));
     if (!ool)
         return false;
 
     // Allocate. If the FreeList is empty, call to VM, which may GC.
     masm.newGCThing(objReg, templateObject, ool->entry());
 
     // Initialize based on the templateObject.
     masm.bind(ool->rejoin());
     masm.initGCThing(objReg, templateObject);
 
     return true;
 }
 
-typedef JSObject *(*CreateThisFn)(JSContext *cx, HandleObject callee, JSObject *proto);
-static const VMFunction CreateThisInfo =
-    FunctionInfo<CreateThisFn>(js_CreateThisForFunctionWithProto);
-
 bool
 CodeGenerator::visitCreateThisVM(LCreateThisVM *lir)
 {
     const LAllocation *proto = lir->getPrototype();
     const LAllocation *callee = lir->getCallee();
 
+    typedef JSObject *(*pf)(JSContext *cx, HandleObject callee, JSObject *proto);
+    static const VMFunction CreateThisInfo =
+        FunctionInfo<pf>(js_CreateThisForFunctionWithProto);
+
     // Push arguments.
     if (proto->isConstant())
         pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
     else
         pushArg(ToRegister(proto));
 
     if (callee->isConstant())
         pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
@@ -1912,29 +1911,27 @@ CodeGenerator::visitModD(LModD *ins)
     masm.setupUnalignedABICall(2, temp);
     masm.passABIArg(lhs);
     masm.passABIArg(rhs);
 
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MacroAssembler::DOUBLE);
     return true;
 }
 
-typedef bool (*BinaryFn)(JSContext *, HandleScript, jsbytecode *,
-                         HandleValue, HandleValue, Value *);
-
-static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
-static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
-static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues);
-static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues);
-static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues);
-static const VMFunction UrshInfo = FunctionInfo<BinaryFn>(js::UrshValues);
-
 bool
 CodeGenerator::visitBinaryV(LBinaryV *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue, Value *);
+    static const VMFunction AddInfo = FunctionInfo<pf>(js::AddValues);
+    static const VMFunction SubInfo = FunctionInfo<pf>(js::SubValues);
+    static const VMFunction MulInfo = FunctionInfo<pf>(js::MulValues);
+    static const VMFunction DivInfo = FunctionInfo<pf>(js::DivValues);
+    static const VMFunction ModInfo = FunctionInfo<pf>(js::ModValues);
+    static const VMFunction UrshInfo = FunctionInfo<pf>(js::UrshValues);
+
     pushArg(ToValue(lir, LBinaryV::RhsInput));
     pushArg(ToValue(lir, LBinaryV::LhsInput));
     pushArg(ImmWord(lir->mirRaw()->toInstruction()->resumePoint()->pc()));
     pushArg(ImmGCPtr(current->mir()->info().script()));
 
     switch (lir->jsop()) {
       case JSOP_ADD:
         return callVM(AddInfo, lir);
@@ -1955,31 +1952,29 @@ CodeGenerator::visitBinaryV(LBinaryV *li
         return callVM(UrshInfo, lir);
 
       default:
         JS_NOT_REACHED("Unexpected binary op");
         return false;
     }
 }
 
-typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, JSBool *);
-static const VMFunction stringsEqualInfo =
-    FunctionInfo<StringCompareFn>(ion::StringsEqual<true>);
-static const VMFunction stringsNotEqualInfo =
-    FunctionInfo<StringCompareFn>(ion::StringsEqual<false>);
-
 bool
 CodeGenerator::visitCompareS(LCompareS *lir)
 {
     JSOp op = lir->mir()->jsop();
     Register left = ToRegister(lir->left());
     Register right = ToRegister(lir->right());
     Register output = ToRegister(lir->output());
     Register temp = ToRegister(lir->temp());
 
+    typedef bool (*pf)(JSContext *, HandleString, HandleString, JSBool *);
+    static const VMFunction stringsEqualInfo = FunctionInfo<pf>(ion::StringsEqual<true>);
+    static const VMFunction stringsNotEqualInfo = FunctionInfo<pf>(ion::StringsEqual<false>);
+
     OutOfLineCode *ool = NULL;
     if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
         ool = oolCallVM(stringsEqualInfo, lir, (ArgList(), left, right),  StoreRegisterTo(output));
     } else {
         JS_ASSERT(op == JSOP_NE || op == JSOP_STRICTNE);
         ool = oolCallVM(stringsNotEqualInfo, lir, (ArgList(), left, right), StoreRegisterTo(output));
     }
 
@@ -2013,29 +2008,29 @@ CodeGenerator::visitCompareS(LCompareS *
     masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp);
     masm.branchPtr(Assembler::Equal, output, temp, ool->entry());
     masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*CompareFn)(JSContext *, HandleValue, HandleValue, JSBool *);
-static const VMFunction EqInfo = FunctionInfo<CompareFn>(ion::LooselyEqual<true>);
-static const VMFunction NeInfo = FunctionInfo<CompareFn>(ion::LooselyEqual<false>);
-static const VMFunction StrictEqInfo = FunctionInfo<CompareFn>(ion::StrictlyEqual<true>);
-static const VMFunction StrictNeInfo = FunctionInfo<CompareFn>(ion::StrictlyEqual<false>);
-static const VMFunction LtInfo = FunctionInfo<CompareFn>(ion::LessThan);
-static const VMFunction LeInfo = FunctionInfo<CompareFn>(ion::LessThanOrEqual);
-static const VMFunction GtInfo = FunctionInfo<CompareFn>(ion::GreaterThan);
-static const VMFunction GeInfo = FunctionInfo<CompareFn>(ion::GreaterThanOrEqual);
-
 bool
 CodeGenerator::visitCompareV(LCompareV *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, HandleValue, JSBool *);
+    static const VMFunction EqInfo = FunctionInfo<pf>(ion::LooselyEqual<true>);
+    static const VMFunction NeInfo = FunctionInfo<pf>(ion::LooselyEqual<false>);
+    static const VMFunction StrictEqInfo = FunctionInfo<pf>(ion::StrictlyEqual<true>);
+    static const VMFunction StrictNeInfo = FunctionInfo<pf>(ion::StrictlyEqual<false>);
+    static const VMFunction LtInfo = FunctionInfo<pf>(ion::LessThan);
+    static const VMFunction LeInfo = FunctionInfo<pf>(ion::LessThanOrEqual);
+    static const VMFunction GtInfo = FunctionInfo<pf>(ion::GreaterThan);
+    static const VMFunction GeInfo = FunctionInfo<pf>(ion::GreaterThanOrEqual);
+
     pushArg(ToValue(lir, LBinaryV::RhsInput));
     pushArg(ToValue(lir, LBinaryV::LhsInput));
 
     switch (lir->mir()->jsop()) {
       case JSOP_EQ:
         return callVM(EqInfo, lir);
 
       case JSOP_NE:
@@ -2141,40 +2136,39 @@ CodeGenerator::visitIsNullOrUndefinedAnd
         cond = masm.testNull(cond, value);
     else
         cond = masm.testUndefined(cond, value);
 
     emitBranch(cond, lir->ifTrue(), lir->ifFalse());
     return true;
 }
 
-typedef JSString *(*ConcatStringsFn)(JSContext *, HandleString, HandleString);
-static const VMFunction ConcatStringsInfo = FunctionInfo<ConcatStringsFn>(js_ConcatStrings);
-
 bool
 CodeGenerator::visitConcat(LConcat *lir)
 {
+    typedef JSString *(*pf)(JSContext *, HandleString, HandleString);
+    static const VMFunction js_ConcatStringsInfo = FunctionInfo<pf>(js_ConcatStrings);
+
     pushArg(ToRegister(lir->rhs()));
     pushArg(ToRegister(lir->lhs()));
-    if (!callVM(ConcatStringsInfo, lir))
+    if (!callVM(js_ConcatStringsInfo, lir))
         return false;
     return true;
 }
 
-typedef bool (*EnsureLinearFn)(JSContext *, JSString *);
-static const VMFunction EnsureLinearInfo = FunctionInfo<EnsureLinearFn>(JSString::ensureLinear);
-
 bool
 CodeGenerator::visitCharCodeAt(LCharCodeAt *lir)
 {
     Register str = ToRegister(lir->str());
     Register index = ToRegister(lir->index());
     Register output = ToRegister(lir->output());
 
-    OutOfLineCode *ool = oolCallVM(EnsureLinearInfo, lir, (ArgList(), str), StoreNothing());
+    typedef bool (*pf)(JSContext *, JSString *);
+    static const VMFunction ensureLinearInfo = FunctionInfo<pf>(JSString::ensureLinear);
+    OutOfLineCode *ool = oolCallVM(ensureLinearInfo, lir, (ArgList(), str), StoreNothing());
     if (!ool)
         return false;
 
     Address lengthAndFlagsAddr(str, JSString::offsetOfLengthAndFlags());
     masm.loadPtr(lengthAndFlagsAddr, output);
 
     masm.branchTest32(Assembler::Zero, output, Imm32(JSString::FLAGS_MASK), ool->entry());
     masm.bind(ool->rejoin());
@@ -2182,26 +2176,25 @@ CodeGenerator::visitCharCodeAt(LCharCode
     // getChars
     Address charsAddr(str, JSString::offsetOfChars());
     masm.loadPtr(charsAddr, output);
     masm.load16ZeroExtend(BaseIndex(output, index, TimesTwo, 0), output);
 
     return true;
 }
 
-typedef JSFlatString *(*StringFromCharCodeFn)(JSContext *, int32_t);
-static const VMFunction StringFromCharCodeInfo = FunctionInfo<StringFromCharCodeFn>(ion::StringFromCharCode);
-
 bool
 CodeGenerator::visitFromCharCode(LFromCharCode *lir)
 {
     Register code = ToRegister(lir->code());
     Register output = ToRegister(lir->output());
 
-    OutOfLineCode *ool = oolCallVM(StringFromCharCodeInfo, lir, (ArgList(), code), StoreRegisterTo(output));
+    typedef JSFlatString *(*pf)(JSContext *, int32_t);
+    static const VMFunction Info = FunctionInfo<pf>(ion::StringFromCharCode);
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), code), StoreRegisterTo(output));
     if (!ool)
         return false;
 
     // OOL path if code >= UNIT_STATIC_LIMIT.
     masm.branch32(Assembler::AboveOrEqual, code, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
                   ool->entry());
 
     masm.movePtr(ImmWord(&gen->compartment->rt->staticStrings.unitStaticTable), output);
@@ -2436,21 +2429,16 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
     else
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*SetObjectElementFn)(JSContext *, HandleObject,
-                                   HandleValue, HandleValue, JSBool strict);
-static const VMFunction SetObjectElementInfo =
-    FunctionInfo<SetObjectElementFn>(SetObjectElement);
-
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
 {
     Register object, elements;
     LInstruction *ins = ool->ins();
     const LAllocation *index;
     MIRType valueType;
     ConstantOrRegister value;
@@ -2510,48 +2498,50 @@ CodeGenerator::visitOutOfLineStoreElemen
     } else {
         // Jump to the inline path where we will store the value.
         masm.jump(ool->rejoinStore());
     }
 
     masm.bind(&callStub);
     saveLive(ins);
 
+    typedef bool (*pf)(JSContext *, HandleObject, HandleValue, HandleValue, JSBool strict);
+    static const VMFunction Info = FunctionInfo<pf>(SetObjectElement);
+
     pushArg(Imm32(current->mir()->strictModeCode()));
     pushArg(value);
     if (index->isConstant())
         pushArg(*index->toConstant());
     else
         pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(index)));
     pushArg(object);
-    if (!callVM(SetObjectElementInfo, ins))
+    if (!callVM(Info, ins))
         return false;
 
     restoreLive(ins);
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue);
-static const VMFunction ArrayPopDenseInfo = FunctionInfo<ArrayPopShiftFn>(ion::ArrayPopDense);
-static const VMFunction ArrayShiftDenseInfo = FunctionInfo<ArrayPopShiftFn>(ion::ArrayShiftDense);
-
 bool
 CodeGenerator::emitArrayPopShift(LInstruction *lir, const MArrayPopShift *mir, Register obj,
                                  Register elementsTemp, Register lengthTemp, TypedOrValueRegister out)
 {
     OutOfLineCode *ool;
+    typedef bool (*pf)(JSContext *, HandleObject, MutableHandleValue);
 
     if (mir->mode() == MArrayPopShift::Pop) {
-        ool = oolCallVM(ArrayPopDenseInfo, lir, (ArgList(), obj), StoreValueTo(out));
+        static const VMFunction Info = FunctionInfo<pf>(ion::ArrayPopDense);
+        ool = oolCallVM(Info, lir, (ArgList(), obj), StoreValueTo(out));
         if (!ool)
             return false;
     } else {
         JS_ASSERT(mir->mode() == MArrayPopShift::Shift);
-        ool = oolCallVM(ArrayShiftDenseInfo, lir, (ArgList(), obj), StoreValueTo(out));
+        static const VMFunction Info = FunctionInfo<pf>(ion::ArrayShiftDense);
+        ool = oolCallVM(Info, lir, (ArgList(), obj), StoreValueTo(out));
         if (!ool)
             return false;
     }
 
     // VM call if a write barrier is necessary.
     masm.branchTestNeedsBarrier(Assembler::NonZero, lengthTemp, ool->entry());
 
     // Load elements and length.
@@ -2624,25 +2614,23 @@ CodeGenerator::visitArrayPopShiftT(LArra
 {
     Register obj = ToRegister(lir->object());
     Register elements = ToRegister(lir->temp0());
     Register length = ToRegister(lir->temp1());
     TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
     return emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
 }
 
-typedef bool (*ArrayPushDenseFn)(JSContext *, HandleObject, HandleValue, uint32_t *);
-static const VMFunction ArrayPushDenseInfo =
-    FunctionInfo<ArrayPushDenseFn>(ion::ArrayPushDense);
-
 bool
 CodeGenerator::emitArrayPush(LInstruction *lir, const MArrayPush *mir, Register obj,
                              ConstantOrRegister value, Register elementsTemp, Register length)
 {
-    OutOfLineCode *ool = oolCallVM(ArrayPushDenseInfo, lir, (ArgList(), obj, value), StoreRegisterTo(length));
+    typedef bool (*pf)(JSContext *, HandleObject, HandleValue, uint32_t *);
+    static const VMFunction Info = FunctionInfo<pf>(ion::ArrayPushDense);
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj, value), StoreRegisterTo(length));
     if (!ool)
         return false;
 
     // Load elements and length.
     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), elementsTemp);
     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
 
     Int32Key key = Int32Key(length);
@@ -2684,19 +2672,16 @@ CodeGenerator::visitArrayPushT(LArrayPus
     ConstantOrRegister value;
     if (lir->value()->isConstant())
         value = ConstantOrRegister(*lir->value()->toConstant());
     else
         value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
     return emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
 }
 
-typedef JSObject *(*ArrayConcatDenseFn)(JSContext *, HandleObject, HandleObject, HandleObject);
-static const VMFunction ArrayConcatDenseInfo = FunctionInfo<ArrayConcatDenseFn>(ArrayConcatDense);
-
 bool
 CodeGenerator::visitArrayConcat(LArrayConcat *lir)
 {
     Register lhs = ToRegister(lir->lhs());
     Register rhs = ToRegister(lir->rhs());
     Register temp1 = ToRegister(lir->temp1());
     Register temp2 = ToRegister(lir->temp2());
 
@@ -2718,43 +2703,48 @@ CodeGenerator::visitArrayConcat(LArrayCo
     masm.initGCThing(temp1, templateObj);
     masm.jump(&call);
     {
         masm.bind(&fail);
         masm.movePtr(ImmWord((void *)NULL), temp1);
     }
     masm.bind(&call);
 
+    typedef JSObject *(*pf)(JSContext *, HandleObject, HandleObject, HandleObject);
+    static const VMFunction Info = FunctionInfo<pf>(ArrayConcatDense);
+
     pushArg(temp1);
     pushArg(ToRegister(lir->rhs()));
     pushArg(ToRegister(lir->lhs()));
-    return callVM(ArrayConcatDenseInfo, lir);
+    return callVM(Info, lir);
 }
 
-typedef JSObject *(*GetIteratorObjectFn)(JSContext *, HandleObject, uint32_t);
-static const VMFunction GetIteratorObjectInfo = FunctionInfo<GetIteratorObjectFn>(GetIteratorObject);
-
 bool
 CodeGenerator::visitCallIteratorStart(LCallIteratorStart *lir)
 {
+    typedef JSObject *(*pf)(JSContext *, HandleObject, uint32_t);
+    static const VMFunction Info = FunctionInfo<pf>(GetIteratorObject);
+
     pushArg(Imm32(lir->mir()->flags()));
     pushArg(ToRegister(lir->object()));
-    return callVM(GetIteratorObjectInfo, lir);
+    return callVM(Info, lir);
 }
 
 bool
 CodeGenerator::visitIteratorStart(LIteratorStart *lir)
 {
     const Register obj = ToRegister(lir->object());
     const Register output = ToRegister(lir->output());
 
     uint32_t flags = lir->mir()->flags();
 
-    OutOfLineCode *ool = oolCallVM(GetIteratorObjectInfo, lir,
-                                   (ArgList(), obj, Imm32(flags)), StoreRegisterTo(output));
+    typedef JSObject *(*pf)(JSContext *, HandleObject, uint32_t);
+    static const VMFunction Info = FunctionInfo<pf>(GetIteratorObject);
+
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj, Imm32(flags)), StoreRegisterTo(output));
     if (!ool)
         return false;
 
     const Register temp1 = ToRegister(lir->temp1());
     const Register temp2 = ToRegister(lir->temp2());
     const Register niTemp = ToRegister(lir->temp3()); // Holds the NativeIterator object.
 
     // Iterators other than for-in should use LCallIteratorStart.
@@ -2823,27 +2813,27 @@ LoadNativeIterator(MacroAssembler &masm,
 
     // Test class.
     masm.branchTestObjClass(Assembler::NotEqual, obj, dest, &PropertyIteratorObject::class_, failures);
 
     // Load NativeIterator object.
     masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, dest);
 }
 
-typedef bool (*IteratorNextFn)(JSContext *, HandleObject, MutableHandleValue);
-static const VMFunction IteratorNextInfo = FunctionInfo<IteratorNextFn>(js_IteratorNext);
-
 bool
 CodeGenerator::visitIteratorNext(LIteratorNext *lir)
 {
     const Register obj = ToRegister(lir->object());
     const Register temp = ToRegister(lir->temp());
     const ValueOperand output = ToOutValue(lir);
 
-    OutOfLineCode *ool = oolCallVM(IteratorNextInfo, lir, (ArgList(), obj), StoreValueTo(output));
+    typedef bool (*pf)(JSContext *, HandleObject, MutableHandleValue);
+    static const VMFunction Info = FunctionInfo<pf>(js_IteratorNext);
+
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj), StoreValueTo(output));
     if (!ool)
         return false;
 
     LoadNativeIterator(masm, obj, temp, ool->entry());
 
     masm.branchTest32(Assembler::NonZero, Address(temp, offsetof(NativeIterator, flags)),
                       Imm32(JSITER_FOREACH), ool->entry());
 
@@ -2854,28 +2844,26 @@ CodeGenerator::visitIteratorNext(LIterat
 
     // Increase the cursor.
     masm.addPtr(Imm32(sizeof(JSString *)), Address(temp, offsetof(NativeIterator, props_cursor)));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*IteratorMoreFn)(JSContext *, HandleObject, JSBool *);
-static const VMFunction IteratorMoreInfo = FunctionInfo<IteratorMoreFn>(ion::IteratorMore);
-
 bool
 CodeGenerator::visitIteratorMore(LIteratorMore *lir)
 {
     const Register obj = ToRegister(lir->object());
     const Register output = ToRegister(lir->output());
     const Register temp = ToRegister(lir->temp());
 
-    OutOfLineCode *ool = oolCallVM(IteratorMoreInfo, lir,
-                                   (ArgList(), obj), StoreRegisterTo(output));
+    typedef bool (*pf)(JSContext *, HandleObject, JSBool *);
+    static const VMFunction Info = FunctionInfo<pf>(ion::IteratorMore);
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj), StoreRegisterTo(output));
     if (!ool)
         return false;
 
     LoadNativeIterator(masm, obj, output, ool->entry());
 
     masm.branchTest32(Assembler::NonZero, Address(output, offsetof(NativeIterator, flags)),
                       Imm32(JSITER_FOREACH), ool->entry());
 
@@ -2883,27 +2871,27 @@ CodeGenerator::visitIteratorMore(LIterat
     masm.loadPtr(Address(output, offsetof(NativeIterator, props_end)), temp);
     masm.cmpPtr(Address(output, offsetof(NativeIterator, props_cursor)), temp);
     emitSet(Assembler::LessThan, output);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*CloseIteratorFn)(JSContext *, HandleObject);
-static const VMFunction CloseIteratorInfo = FunctionInfo<CloseIteratorFn>(CloseIterator);
-
 bool
 CodeGenerator::visitIteratorEnd(LIteratorEnd *lir)
 {
     const Register obj = ToRegister(lir->object());
     const Register temp1 = ToRegister(lir->temp1());
     const Register temp2 = ToRegister(lir->temp2());
 
-    OutOfLineCode *ool = oolCallVM(CloseIteratorInfo, lir, (ArgList(), obj), StoreNothing());
+    typedef bool (*pf)(JSContext *, HandleObject);
+    static const VMFunction Info = FunctionInfo<pf>(CloseIterator);
+
+    OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj), StoreNothing());
     if (!ool)
         return false;
 
     LoadNativeIterator(masm, obj, temp1, ool->entry());
 
     masm.branchTest32(Assembler::Zero, Address(temp1, offsetof(NativeIterator, flags)),
                       Imm32(JSITER_ENUMERATE), ool->entry());
 
@@ -2966,17 +2954,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_ = cx->compartment->ionCompartment()->getBailoutTable(frameClass_);
+        deoptTable_ = cx->compartment->ionCompartment()->getBailoutTable(cx, frameClass_);
         if (!deoptTable_)
             return false;
     }
 
     if (!generatePrologue())
         return false;
     if (!generateBody())
         return false;
@@ -3107,50 +3095,55 @@ CodeGenerator::visitOutOfLineUnboxDouble
         if (!bailoutIf(cond, ins->snapshot()))
             return false;
     }
     masm.int32ValueToDouble(value, ToFloatRegister(ins->output()));
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef bool (*GetPropertyFn)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue);
-static const VMFunction GetPropertyInfo = FunctionInfo<GetPropertyFn>(GetProperty);
+typedef bool (*GetPropertyOrNameFn)(JSContext *, HandleObject, HandlePropertyName, Value *);
 
 bool
 CodeGenerator::visitCallGetProperty(LCallGetProperty *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue);
+    static const VMFunction Info = FunctionInfo<pf>(GetProperty);
+
     pushArg(ImmGCPtr(lir->mir()->name()));
     pushArg(ToValue(lir, LCallGetProperty::Value));
-    return callVM(GetPropertyInfo, lir);
+    return callVM(Info, lir);
 }
 
-typedef bool (*GetOrCallElementFn)(JSContext *, HandleValue, HandleValue, MutableHandleValue);
-static const VMFunction GetElementInfo = FunctionInfo<GetOrCallElementFn>(js::GetElement);
-static const VMFunction CallElementInfo = FunctionInfo<GetOrCallElementFn>(js::CallElement);
-
 bool
 CodeGenerator::visitCallGetElement(LCallGetElement *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, HandleValue, MutableHandleValue);
+    static const VMFunction GetElementInfo = FunctionInfo<pf>(js::GetElement);
+    static const VMFunction CallElementInfo = FunctionInfo<pf>(js::CallElement);
+
     pushArg(ToValue(lir, LCallGetElement::RhsInput));
     pushArg(ToValue(lir, LCallGetElement::LhsInput));
 
     JSOp op = JSOp(*lir->mir()->resumePoint()->pc());
 
     if (op == JSOP_GETELEM) {
         return callVM(GetElementInfo, lir);
     } else {
         JS_ASSERT(op == JSOP_CALLELEM);
         return callVM(CallElementInfo, lir);
     }
 }
 
 bool
 CodeGenerator::visitCallSetElement(LCallSetElement *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleObject, HandleValue, HandleValue, JSBool strict);
+    static const VMFunction SetObjectElementInfo = FunctionInfo<pf>(js::SetObjectElement);
+
     pushArg(Imm32(current->mir()->strictModeCode()));
     pushArg(ToValue(lir, LCallSetElement::Value));
     pushArg(ToValue(lir, LCallSetElement::Index));
     pushArg(ToRegister(lir->getOperand(0)));
     return callVM(SetObjectElementInfo, lir);
 }
 
 bool
@@ -3292,20 +3285,16 @@ CodeGenerator::visitCache(LInstruction *
     CodeOffsetJump jump = masm.jumpWithPatch(ool->repatchEntry());
     CodeOffsetLabel label = masm.labelForPatch();
     masm.bind(ool->rejoin());
 
     ool->setInlineJump(jump, label);
     return true;
 }
 
-typedef bool (*GetNameCacheFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
-static const VMFunction GetNameCacheInfo =
-    FunctionInfo<GetNameCacheFn>(GetNameCache);
-
 bool
 CodeGenerator::visitOutOfLineGetNameCache(OutOfLineCache *ool)
 {
     LGetNameCache *lir = ool->cache()->toGetNameCache();
     const MGetNameCache *mir = lir->mir();
     Register scopeChain = ToRegister(lir->scopeObj());
     RegisterSet liveRegs = lir->safepoint()->liveRegs();
     TypedOrValueRegister output(GetValueOutput(lir));
@@ -3317,32 +3306,31 @@ CodeGenerator::visitOutOfLineGetNameCach
                        masm.labelForPatch(), liveRegs,
                        scopeChain, mir->name(), output);
 
     cache.setScriptedLocation(mir->block()->info().script(), mir->resumePoint()->pc());
     size_t cacheIndex = allocateCache(cache);
 
     saveLive(lir);
 
+    typedef bool (*pf)(JSContext *, size_t, HandleObject, MutableHandleValue);
+    static const VMFunction GetNameCacheInfo = FunctionInfo<pf>(GetNameCache);
+
     pushArg(scopeChain);
     pushArg(Imm32(cacheIndex));
     if (!callVM(GetNameCacheInfo, lir))
         return false;
 
     masm.storeCallResultValue(output);
     restoreLive(lir);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef bool (*GetPropertyCacheFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
-static const VMFunction GetPropertyCacheInfo =
-    FunctionInfo<GetPropertyCacheFn>(GetPropertyCache);
-
 bool
 CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool)
 {
     RegisterSet liveRegs = ool->cache()->safepoint()->liveRegs();
 
     LInstruction *ins = ool->cache();
     MInstruction *mir = ins->mirRaw()->toInstruction();
 
@@ -3389,32 +3377,32 @@ CodeGenerator::visitOutOfLineCacheGetPro
     if (mir->resumePoint())
         cache.setScriptedLocation(mir->block()->info().script(), mir->resumePoint()->pc());
     else
         cache.setIdempotent();
     size_t cacheIndex = allocateCache(cache);
 
     saveLive(ins);
 
+    typedef bool (*pf)(JSContext *, size_t, HandleObject, MutableHandleValue);
+    static const VMFunction GetPropertyCacheInfo = FunctionInfo<pf>(GetPropertyCache);
+
     pushArg(objReg);
     pushArg(Imm32(cacheIndex));
     if (!callVM(GetPropertyCacheInfo, ins))
         return false;
 
     masm.storeCallResultValue(output);
     restoreLive(ins);
 
     masm.jump(ool->rejoin());
 
     return true;
 }
 
-typedef bool (*GetElementCacheFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
-static const VMFunction GetElementCacheInfo = FunctionInfo<GetElementCacheFn>(GetElementCache);
-
 bool
 CodeGenerator::visitOutOfLineGetElementCache(OutOfLineCache *ool)
 {
     LGetElementCacheV *ins = ool->cache()->toGetElementCacheV();
     const MGetElementCache *mir = ins->mir();
 
     Register obj = ToRegister(ins->object());
     ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
@@ -3427,33 +3415,32 @@ CodeGenerator::visitOutOfLineGetElementC
                              obj, index, output,
                              mir->monitoredResult());
 
     cache.setScriptedLocation(mir->block()->info().script(), mir->resumePoint()->pc());
     size_t cacheIndex = allocateCache(cache);
 
     saveLive(ins);
 
+    typedef bool (*pf)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
+    static const VMFunction Info = FunctionInfo<pf>(GetElementCache);
+
     pushArg(index);
     pushArg(obj);
     pushArg(Imm32(cacheIndex));
-    if (!callVM(GetElementCacheInfo, ins))
+    if (!callVM(Info, ins))
         return false;
 
     masm.storeCallResultValue(output);
     restoreLive(ins);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*BindNameCacheFn)(JSContext *, size_t, HandleObject);
-static const VMFunction BindNameCacheInfo =
-    FunctionInfo<BindNameCacheFn>(BindNameCache);
-
 bool
 CodeGenerator::visitOutOfLineBindNameCache(OutOfLineCache *ool)
 {
     LBindNameCache *ins = ool->cache()->toBindNameCache();
     Register scopeChain = ToRegister(ins->scopeChain());
     Register output = ToRegister(ins->output());
 
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
@@ -3462,16 +3449,19 @@ CodeGenerator::visitOutOfLineBindNameCac
     IonCacheBindName cache(ool->getInlineJump(), ool->getInlineLabel(),
                            masm.labelForPatch(), liveRegs,
                            scopeChain, mir->name(), output);
     cache.setScriptedLocation(mir->script(), mir->pc());
     size_t cacheIndex = allocateCache(cache);
 
     saveLive(ins);
 
+    typedef JSObject *(*pf)(JSContext *, size_t, HandleObject);
+    static const VMFunction BindNameCacheInfo = FunctionInfo<pf>(BindNameCache);
+
     pushArg(scopeChain);
     pushArg(Imm32(cacheIndex));
     if (!callVM(BindNameCacheInfo, ins))
         return false;
 
     masm.storeCallResult(output);
     restoreLive(ins);
 
@@ -3497,61 +3487,54 @@ CodeGenerator::getSetPropertyValue(LInst
         return TypedOrValueRegister(ins_->valueType(), ToAnyRegister(ins->getOperand(1)));
       }
       default:
         JS_NOT_REACHED("Bad opcode");
         return ConstantOrRegister(UndefinedValue());
     }
 }
 
-typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
-                              HandlePropertyName, const HandleValue, bool, bool);
-static const VMFunction SetPropertyInfo =
-    FunctionInfo<SetPropertyFn>(SetProperty);
-
 bool
 CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
 {
     ConstantOrRegister value = getSetPropertyValue(ins);
 
     const Register objReg = ToRegister(ins->getOperand(0));
     bool isSetName = JSOp(*ins->mir()->resumePoint()->pc()) == JSOP_SETNAME;
 
     pushArg(Imm32(isSetName));
     pushArg(Imm32(ins->mir()->strict()));
 
     pushArg(value);
     pushArg(ImmGCPtr(ins->mir()->name()));
     pushArg(objReg);
 
-    return callVM(SetPropertyInfo, ins);
+    typedef bool (*pf)(JSContext *, HandleObject, HandlePropertyName, const HandleValue, bool, bool);
+    static const VMFunction info = FunctionInfo<pf>(SetProperty);
+
+    return callVM(info, ins);
 }
 
-typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, JSBool *);
-static const VMFunction DeletePropertyStrictInfo =
-    FunctionInfo<DeletePropertyFn>(DeleteProperty<true>);
-static const VMFunction DeletePropertyNonStrictInfo =
-    FunctionInfo<DeletePropertyFn>(DeleteProperty<false>);
-
 bool
 CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, HandlePropertyName, JSBool *);
+
     pushArg(ImmGCPtr(lir->mir()->name()));
     pushArg(ToValue(lir, LCallDeleteProperty::Value));
 
-    if (lir->mir()->block()->info().script()->strictModeCode)
-        return callVM(DeletePropertyStrictInfo, lir);
-    else
-        return callVM(DeletePropertyNonStrictInfo, lir);
+    if (lir->mir()->block()->info().script()->strictModeCode) {
+        static const VMFunction Info = FunctionInfo<pf>(DeleteProperty<true>);
+        return callVM(Info, lir);
+    } else {
+        static const VMFunction Info = FunctionInfo<pf>(DeleteProperty<false>);
+        return callVM(Info, lir);
+    }
 }
 
-typedef bool (*SetPropertyCacheFn)(JSContext *, size_t, HandleObject, HandleValue, bool);
-static const VMFunction SetPropertyCacheInfo =
-    FunctionInfo<SetPropertyCacheFn>(ion::SetPropertyCache);
-
 bool
 CodeGenerator::visitOutOfLineSetPropertyCache(OutOfLineCache *ool)
 {
     LInstruction *ins = ool->cache();
 
     Register objReg = ToRegister(ins->getOperand(0));
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
 
@@ -3568,56 +3551,59 @@ CodeGenerator::visitOutOfLineSetProperty
 
     saveLive(ins);
 
     pushArg(Imm32(isSetName));
     pushArg(value);
     pushArg(objReg);
     pushArg(Imm32(cacheIndex));
 
-    if (!callVM(SetPropertyCacheInfo, ool->cache()))
+    typedef bool (*pf)(JSContext *, size_t, HandleObject, HandleValue, bool);
+    static const VMFunction info = FunctionInfo<pf>(ion::SetPropertyCache);
+
+    if (!callVM(info, ool->cache()))
         return false;
 
     restoreLive(ins);
 
     masm.jump(ool->rejoin());
 
     return true;
 }
 
-typedef bool (*ThrowFn)(JSContext *, HandleValue);
-static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw);
-
 bool
 CodeGenerator::visitThrow(LThrow *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue);
+    static const VMFunction ThrowInfo = FunctionInfo<pf>(js::Throw);
+
     pushArg(ToValue(lir, LThrow::Value));
     return callVM(ThrowInfo, lir);
 }
 
-typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
-static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot);
-
 bool
 CodeGenerator::visitBitNotV(LBitNotV *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, int *p);
+    static const VMFunction info = FunctionInfo<pf>(BitNot);
+
     pushArg(ToValue(lir, LBitNotV::Input));
-    return callVM(BitNotInfo, lir);
+    return callVM(info, lir);
 }
 
-typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
-static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd);
-static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr);
-static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor);
-static const VMFunction BitLhsInfo = FunctionInfo<BitopFn>(BitLsh);
-static const VMFunction BitRhsInfo = FunctionInfo<BitopFn>(BitRsh);
-
 bool
 CodeGenerator::visitBitOpV(LBitOpV *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, HandleValue, int *p);
+    static const VMFunction BitAndInfo = FunctionInfo<pf>(BitAnd);
+    static const VMFunction BitOrInfo = FunctionInfo<pf>(BitOr);
+    static const VMFunction BitXorInfo = FunctionInfo<pf>(BitXor);
+    static const VMFunction BitLhsInfo = FunctionInfo<pf>(BitLsh);
+    static const VMFunction BitRhsInfo = FunctionInfo<pf>(BitRsh);
+
     pushArg(ToValue(lir, LBitOpV::RhsInput));
     pushArg(ToValue(lir, LBitOpV::LhsInput));
 
     switch (lir->jsop()) {
       case JSOP_BITAND:
         return callVM(BitAndInfo, lir);
       case JSOP_BITOR:
         return callVM(BitOrInfo, lir);
@@ -3696,48 +3682,48 @@ CodeGenerator::visitTypeOfV(LTypeOfV *li
 
     masm.movePtr(ImmGCPtr(rt->atomState.string), output);
 
     masm.bind(&done);
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef JSString *(*TypeOfFn)(JSContext *, HandleValue);
-static const VMFunction TypeOfInfo = FunctionInfo<TypeOfFn>(TypeOfOperation);
-
 bool
 CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool)
 {
+    typedef JSString *(*pf)(JSContext *, HandleValue);
+    static const VMFunction Info = FunctionInfo<pf>(TypeOfOperation);
+
     LTypeOfV *ins = ool->ins();
     saveLive(ins);
 
     pushArg(ToValue(ins, LTypeOfV::Input));
-    if (!callVM(TypeOfInfo, ins))
+    if (!callVM(Info, ins))
         return false;
 
     masm.storeCallResult(ToRegister(ins->output()));
     restoreLive(ins);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef bool (*ToIdFn)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue,
-                       MutableHandleValue);
-static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation);
-
 bool
 CodeGenerator::visitToIdV(LToIdV *lir)
 {
+    typedef bool (*pf)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue,
+                       MutableHandleValue);
+    static const VMFunction Info = FunctionInfo<pf>(ToIdOperation);
+
     pushArg(ToValue(lir, LToIdV::Index));
     pushArg(ToValue(lir, LToIdV::Object));
     pushArg(ImmWord(lir->mir()->resumePoint()->pc()));
     pushArg(ImmGCPtr(current->mir()->info().script()));
-    return callVM(ToIdInfo, lir);
+    return callVM(Info, lir);
 }
 
 bool
 CodeGenerator::visitLoadElementV(LLoadElementV *load)
 {
     Register elements = ToRegister(load->elements());
     const ValueOperand out = ToOutValue(load);
 
@@ -3864,35 +3850,34 @@ CodeGenerator::visitLoadTypedArrayElemen
 
     if (fail.used() && !bailoutFrom(&fail, lir->snapshot()))
         return false;
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*GetElementMonitoredFn)(JSContext *, HandleValue, HandleValue, MutableHandleValue);
-static const VMFunction GetElementMonitoredInfo =
-    FunctionInfo<GetElementMonitoredFn>(js::GetElementMonitored);
-
 bool
 CodeGenerator::visitOutOfLineLoadTypedArray(OutOfLineLoadTypedArray *ool)
 {
     LLoadTypedArrayElementHole *ins = ool->ins();
     saveLive(ins);
 
     Register object = ToRegister(ins->object());
     ValueOperand out = ToOutValue(ins);
 
+    typedef bool (*pf)(JSContext *, HandleValue, HandleValue, MutableHandleValue);
+    static const VMFunction Info = FunctionInfo<pf>(js::GetElementMonitored);
+
     if (ins->index()->isConstant())
         pushArg(*ins->index()->toConstant());
     else
         pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index())));
     pushArg(TypedOrValueRegister(MIRType_Object, AnyRegister(object)));
-    if (!callVM(GetElementMonitoredInfo, ins))
+    if (!callVM(Info, ins))
         return false;
 
     masm.storeCallResultValue(out);
     restoreLive(ins);
 
     masm.jump(ool->rejoin());
     return true;
 }
@@ -3990,22 +3975,22 @@ CodeGenerator::visitClampVToUint8(LClamp
 
     masm.bind(&isZero);
     masm.move32(Imm32(0), output);
 
     masm.bind(&done);
     return true;
 }
 
-typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, JSBool *);
-static const VMFunction OperatorInInfo = FunctionInfo<OperatorInFn>(OperatorIn);
-
 bool
 CodeGenerator::visitIn(LIn *ins)
 {
+    typedef bool (*pf)(JSContext *, HandleValue, HandleObject, JSBool *);
+    static const VMFunction OperatorInInfo = FunctionInfo<pf>(OperatorIn);
+
     pushArg(ToRegister(ins->rhs()));
     pushArg(ToValue(ins, LIn::LHS));
 
     return callVM(OperatorInInfo, ins);
 }
 
 bool
 CodeGenerator::visitInstanceOfO(LInstanceOfO *ins)
@@ -4016,19 +4001,16 @@ CodeGenerator::visitInstanceOfO(LInstanc
 
 bool
 CodeGenerator::visitInstanceOfV(LInstanceOfV *ins)
 {
     Register rhs = ToRegister(ins->getOperand(LInstanceOfV::RHS));
     return emitInstanceOf(ins, rhs);
 }
 
-typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, JSBool *);
-static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance);
-
 bool
 CodeGenerator::emitInstanceOf(LInstruction *ins, Register rhs)
 {
     Register rhsTmp = ToRegister(ins->getTemp(1));
     Register output = ToRegister(ins->getDef(0));
 
     // This temporary is used in other parts of the code.
     // Different names are used so the purpose is clear.
@@ -4036,16 +4018,19 @@ CodeGenerator::emitInstanceOf(LInstructi
     Register lhsTmp = ToRegister(ins->getTemp(0));
 
     Label callHasInstance;
     Label boundFunctionCheck;
     Label boundFunctionDone;
     Label done;
     Label loopPrototypeChain;
 
+    typedef bool (*pf)(JSContext *, HandleObject, HandleValue, JSBool *);
+    static const VMFunction HasInstanceInfo = FunctionInfo<pf>(js::HasInstance);
+
     OutOfLineCode *call = oolCallVM(HasInstanceInfo, ins, (ArgList(), rhs, ToValue(ins, 0)),
                                    StoreRegisterTo(output));
     if (!call)
         return false;
 
     // 1. CODE FOR HASINSTANCE_BOUND_FUNCTION
 
     // ASM-equivalent of following code
@@ -4273,20 +4258,16 @@ CodeGenerator::visitSetDOMProperty(LSetD
     }
     masm.bind(&success);
     masm.adjustStack(IonDOMExitFrameLayout::Size());
 
     JS_ASSERT(masm.framePushed() == initialStack);
     return true;
 }
 
-typedef bool(*SPSFn)(JSContext *, HandleScript);
-static const VMFunction SPSEnterInfo = FunctionInfo<SPSFn>(SPSEnter);
-static const VMFunction SPSExitInfo = FunctionInfo<SPSFn>(SPSExit);
-
 bool
 CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
 {
     AssertCanGC();
     Register temp = ToRegister(lir->temp()->output());
 
     switch (lir->type()) {
         case MFunctionBoundary::Inline_Enter:
@@ -4307,16 +4288,19 @@ CodeGenerator::visitFunctionBoundary(LFu
 
             sps_.leave(masm, temp);
             if (!sps_.enterInlineFrame())
                 return false;
             // fallthrough
 
         case MFunctionBoundary::Enter:
             if (sps_.slowAssertions()) {
+                typedef bool(*pf)(JSContext *, HandleScript);
+                static const VMFunction SPSEnterInfo = FunctionInfo<pf>(SPSEnter);
+
                 saveLive(lir);
                 pushArg(ImmGCPtr(lir->script()));
                 if (!callVM(SPSEnterInfo, lir))
                     return false;
                 restoreLive(lir);
                 sps_.pushManual(lir->script(), masm, temp);
                 return true;
             }
@@ -4328,16 +4312,19 @@ CodeGenerator::visitFunctionBoundary(LFu
             // maintain the state of inline frames currently active and then
             // reenter the caller
             sps_.leaveInlineFrame();
             sps_.reenter(masm, temp);
             return true;
 
         case MFunctionBoundary::Exit:
             if (sps_.slowAssertions()) {
+                typedef bool(*pf)(JSContext *, HandleScript);
+                static const VMFunction SPSExitInfo = FunctionInfo<pf>(SPSExit);
+
                 saveLive(lir);
                 pushArg(ImmGCPtr(lir->script()));
                 // Once we've exited, then we shouldn't emit instrumentation for
                 // the corresponding reenter() because we no longer have a
                 // frame.
                 sps_.skipNextReenter();
                 if (!callVM(SPSExitInfo, lir))
                     return false;
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -117,94 +117,41 @@ ion::InitializeIon()
             return false;
         IonTLSInitialized = true;
     }
 #endif
     CheckLogging();
     return true;
 }
 
-IonRuntime::IonRuntime()
+IonCompartment::IonCompartment()
   : execAlloc_(NULL),
     enterJIT_(NULL),
     bailoutHandler_(NULL),
     argumentsRectifier_(NULL),
     invalidator_(NULL),
-    functionWrappers_(NULL)
+    functionWrappers_(NULL),
+    flusher_(NULL)
 {
 }
 
-IonRuntime::~IonRuntime()
+bool
+IonCompartment::initialize(JSContext *cx)
 {
-    js_delete(functionWrappers_);
-}
-
-bool
-IonRuntime::initialize(JSContext *cx)
-{
-    AutoEnterAtomsCompartment ac(cx);
-
-    if (!cx->compartment->ensureIonCompartmentExists(cx))
-        return false;
-
     execAlloc_ = cx->runtime->getExecAlloc(cx);
     if (!execAlloc_)
         return false;
 
     functionWrappers_ = cx->new_<VMWrapperMap>(cx);
     if (!functionWrappers_ || !functionWrappers_->init())
         return false;
 
-    if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId()))
-        return false;
-
-    for (uint32 id = 0;; id++) {
-        FrameSizeClass class_ = FrameSizeClass::FromClass(id);
-        if (class_ == FrameSizeClass::ClassLimit())
-            break;
-        bailoutTables_.infallibleAppend(NULL);
-        bailoutTables_[id] = generateBailoutTable(cx, id);
-        if (!bailoutTables_[id])
-            return false;
-    }
-
-    bailoutHandler_ = generateBailoutHandler(cx);
-    if (!bailoutHandler_)
-        return false;
-
-    argumentsRectifier_ = generateArgumentsRectifier(cx);
-    if (!argumentsRectifier_)
-        return false;
-
-    invalidator_ = generateInvalidator(cx);
-    if (!invalidator_)
-        return false;
-
-    enterJIT_ = generateEnterJIT(cx);
-    if (!enterJIT_)
-        return false;
-
-    preBarrier_ = generatePreBarrier(cx);
-    if (!preBarrier_)
-        return false;
-
-    for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) {
-        if (!generateVMWrapper(cx, *fun))
-            return false;
-    }
-
     return true;
 }
 
-IonCompartment::IonCompartment(IonRuntime *rt)
-  : rt(rt),
-    flusher_(NULL)
-{
-}
-
 void
 ion::FinishOffThreadBuilder(IonBuilder *builder)
 {
     if (builder->script()->isIonCompilingOffThread()) {
         types::TypeCompartment &types = builder->script()->compartment()->types;
         builder->recompileInfo.compilerOutput(types)->invalidate();
         builder->script()->ion = NULL;
     }
@@ -239,47 +186,81 @@ IonCompartment::mark(JSTracer *trc, JSCo
         if (activation->compartment() != compartment)
             continue;
 
         // Both OSR and normal function calls depend on the EnterJIT code
         // existing for entrance and exit.
         mustMarkEnterJIT = true;
     }
 
+    // These must be available if we could be running JIT code; they are not
+    // traced as normal through IonCode or IonScript objects
+    if (mustMarkEnterJIT)
+        MarkIonCodeRoot(trc, enterJIT_.unsafeGet(), "enterJIT");
+
     // functionWrappers_ are not marked because this is a WeakCache of VM
     // function implementations.
 
     // Cancel any active or pending off thread compilations.
     CancelOffThreadIonCompile(compartment, NULL);
     FinishAllOffThreadCompilations(this);
 }
 
 void
 IonCompartment::sweep(FreeOp *fop)
 {
+    if (enterJIT_ && !IsIonCodeMarked(enterJIT_.unsafeGet()))
+        enterJIT_ = NULL;
+    if (bailoutHandler_ && !IsIonCodeMarked(bailoutHandler_.unsafeGet()))
+        bailoutHandler_ = NULL;
+    if (argumentsRectifier_ && !IsIonCodeMarked(argumentsRectifier_.unsafeGet()))
+        argumentsRectifier_ = NULL;
+    if (invalidator_ && !IsIonCodeMarked(invalidator_.unsafeGet()))
+        invalidator_ = NULL;
+    if (preBarrier_ && !IsIonCodeMarked(preBarrier_.unsafeGet()))
+        preBarrier_ = NULL;
+
+    for (size_t i = 0; i < bailoutTables_.length(); i++) {
+        if (bailoutTables_[i] && !IsIonCodeMarked(bailoutTables_[i].unsafeGet()))
+            bailoutTables_[i] = NULL;
+    }
+
+    // Sweep cache of VM function implementations.
+    functionWrappers_->sweep(fop);
 }
 
 IonCode *
 IonCompartment::getBailoutTable(const FrameSizeClass &frameClass)
 {
     JS_ASSERT(frameClass != FrameSizeClass::None());
-    return rt->bailoutTables_[frameClass.classId()];
+    return bailoutTables_[frameClass.classId()];
 }
 
 IonCode *
-IonCompartment::getVMWrapper(const VMFunction &f)
+IonCompartment::getBailoutTable(JSContext *cx, const FrameSizeClass &frameClass)
 {
-    typedef MoveResolver::MoveOperand MoveOperand;
+    uint32 id = frameClass.classId();
 
-    JS_ASSERT(rt->functionWrappers_);
-    JS_ASSERT(rt->functionWrappers_->initialized());
-    IonRuntime::VMWrapperMap::Ptr p = rt->functionWrappers_->lookup(&f);
-    JS_ASSERT(p);
+    if (id >= bailoutTables_.length()) {
+        size_t numToPush = id - bailoutTables_.length() + 1;
+        if (!bailoutTables_.reserve(bailoutTables_.length() + numToPush))
+            return NULL;
+        for (size_t i = 0; i < numToPush; i++)
+            bailoutTables_.infallibleAppend(NULL);
+    }
 
-    return p->value;
+    if (!bailoutTables_[id])
+        bailoutTables_[id] = generateBailoutTable(cx, id);
+
+    return bailoutTables_[id];
+}
+
+IonCompartment::~IonCompartment()
+{
+    js_delete(functionWrappers_);
 }
 
 IonActivation::IonActivation(JSContext *cx, StackFrame *fp)
   : cx_(cx),
     compartment_(cx->compartment),
     prev_(cx->runtime->ionActivation),
     entryfp_(fp),
     bailout_(NULL),
@@ -341,18 +322,25 @@ IonCode::copyFrom(MacroAssembler &masm)
     masm.processCodeLabels(this);
 }
 
 void
 IonCode::trace(JSTracer *trc)
 {
     // Note that we cannot mark invalidated scripts, since we've basically
     // corrupted the code stream by injecting bailouts.
-    if (invalidated())
+    if (invalidated()) {
+        // Note that since we're invalidated, we won't mark the precious
+        // invalidator thunk referenced in the epilogue. We don't move
+        // executable code so the actual reference is okay, we just need to
+        // make sure it says alive before we return.
+        IonCompartment *ion = compartment()->ionCompartment();
+        MarkIonCodeUnbarriered(trc, ion->getInvalidationThunkAddr(), "invalidator");
         return;
+    }
 
     if (jumpRelocTableBytes_) {
         uint8 *start = code_ + jumpRelocTableOffset();
         CompactBufferReader reader(start, start + jumpRelocTableBytes_);
         MacroAssembler::TraceJumpRelocations(trc, this, reader);
     }
     if (dataRelocTableBytes_) {
         uint8 *start = code_ + dataRelocTableOffset();
@@ -996,17 +984,16 @@ AttachFinishedCompilations(JSContext *cx
         IonBuilder *builder = compilations.popCopy();
 
         if (builder->backgroundCompiledLir) {
             RootedScript script(cx, builder->script());
             IonContext ictx(cx, cx->compartment, &builder->temp());
 
             CodeGenerator codegen(builder, *builder->backgroundCompiledLir);
 
-            types::AutoEnterTypeInference enterTypes(cx);
             types::AutoEnterCompilation enterCompiler(cx, types::AutoEnterCompilation::Ion);
             enterCompiler.initExisting(builder->recompileInfo);
 
             bool success;
             {
                 // Release the worker thread lock and root the compiler for GC.
                 AutoTempAllocatorRooter root(cx, &builder->temp());
                 AutoUnlockWorkerThreadState unlock(cx->runtime);
@@ -1289,16 +1276,23 @@ ion::CanEnterAtBranch(JSContext *cx, Han
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
     if (script->ion->osrPc() != pc)
         return Method_Skipped;
 
+    // This can GC, so afterward, script->ion is not guaranteed to be valid.
+    if (!cx->compartment->ionCompartment()->enterJIT(cx))
+        return Method_Error;
+
+    if (!script->ion)
+        return Method_Skipped;
+
     return Method_Compiled;
 }
 
 MethodStatus
 ion::CanEnter(JSContext *cx, HandleScript script, StackFrame *fp, bool newType)
 {
     JS_ASSERT(ion::IsEnabled(cx));
 
@@ -1335,16 +1329,23 @@ ion::CanEnter(JSContext *cx, HandleScrip
     JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
     MethodStatus status = Compile(cx, script, fun, NULL, fp->isConstructing());
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
+    // This can GC, so afterward, script->ion is not guaranteed to be valid.
+    if (!cx->compartment->ionCompartment()->enterJIT(cx))
+        return Method_Error;
+
+    if (!script->ion)
+        return Method_Skipped;
+
     return Method_Compiled;
 }
 
 MethodStatus
 ion::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script)
 {
     JS_ASSERT(ion::IsEnabled(cx));
 
@@ -1352,17 +1353,17 @@ ion::CanEnterUsingFastInvoke(JSContext *
     if (!script->hasIonScript() || script->ion->bailoutExpected())
         return Method_Skipped;
 
     if (!cx->compartment->ensureIonCompartmentExists(cx))
         return Method_Error;
 
     // This can GC, so afterward, script->ion is not guaranteed to be valid.
     AssertCanGC();
-    if (!cx->compartment->ionCompartment()->enterJIT())
+    if (!cx->compartment->ionCompartment()->enterJIT(cx))
         return Method_Error;
 
     if (!script->ion)
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
@@ -1370,17 +1371,17 @@ static IonExecStatus
 EnterIon(JSContext *cx, StackFrame *fp, void *jitcode)
 {
     AssertCanGC();
     JS_CHECK_RECURSION(cx, return IonExec_Error);
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(CheckFrame(fp));
     JS_ASSERT(!fp->script()->ion->bailoutExpected());
 
-    EnterIonCode enter = cx->compartment->ionCompartment()->enterJIT();
+    EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible();
 
     // maxArgc is the maximum of arguments between the number of actual
     // arguments and the number of formal arguments. It accounts for |this|.
     int maxArgc = 0;
     Value *maxArgv = NULL;
     int numActualArgs = 0;
 
     void *calleeToken;
@@ -1544,17 +1545,17 @@ ion::FastInvoke(JSContext *cx, HandleFun
         clearCallingIntoIon = true;
         activation.setEntryFp(fp);
     } else {
         JS_ASSERT(!activation.entryfp());
     }
 
     activation.setPrevPc(cx->regs().pc);
 
-    EnterIonCode enter = cx->compartment->ionCompartment()->enterJIT();
+    EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible();
     void *calleeToken = CalleeToToken(fun);
 
     Value result = Int32Value(fun->nargs);
 
     JSAutoResolveFlags rf(cx, RESOLVE_INFER);
     enter(jitcode, args.length() + 1, &args[0] - 1, fp, calleeToken, &result);
 
     if (clearCallingIntoIon)
--- a/js/src/ion/IonCompartment.h
+++ b/js/src/ion/IonCompartment.h
@@ -22,116 +22,144 @@ class FrameSizeClass;
 typedef void (*EnterIonCode)(void *code, int argc, Value *argv, StackFrame *fp,
                              CalleeToken calleeToken, Value *vp);
 
 class IonActivation;
 class IonBuilder;
 
 typedef Vector<IonBuilder*, 0, SystemAllocPolicy> OffThreadCompilationVector;
 
-class IonRuntime
+class IonCompartment
 {
-    friend class IonCompartment;
+    typedef WeakCache<const VMFunction *, ReadBarriered<IonCode> > VMWrapperMap;
 
-    // Executable allocator.
+    friend class IonActivation;
+
+    // Executable allocator (owned by the runtime).
     JSC::ExecutableAllocator *execAlloc_;
 
     // Trampoline for entering JIT code. Contains OSR prologue.
-    IonCode *enterJIT_;
+    ReadBarriered<IonCode> enterJIT_;
 
     // Vector mapping frame class sizes to bailout tables.
-    Vector<IonCode*, 4, SystemAllocPolicy> bailoutTables_;
+    Vector<ReadBarriered<IonCode>, 4, SystemAllocPolicy> bailoutTables_;
 
     // Generic bailout table; used if the bailout table overflows.
-    IonCode *bailoutHandler_;
+    ReadBarriered<IonCode> bailoutHandler_;
 
     // Argument-rectifying thunk, in the case of insufficient arguments passed
     // to a function call site. Pads with |undefined|.
-    IonCode *argumentsRectifier_;
+    ReadBarriered<IonCode> argumentsRectifier_;
 
     // Thunk that invalides an (Ion compiled) caller on the Ion stack.
-    IonCode *invalidator_;
+    ReadBarriered<IonCode> invalidator_;
 
     // Thunk that calls the GC pre barrier.
-    IonCode *preBarrier_;
+    ReadBarriered<IonCode> preBarrier_;
 
     // Map VMFunction addresses to the IonCode of the wrapper.
-    typedef WeakCache<const VMFunction *, IonCode *> VMWrapperMap;
     VMWrapperMap *functionWrappers_;
 
-  private:
-    IonCode *generateEnterJIT(JSContext *cx);
-    IonCode *generateArgumentsRectifier(JSContext *cx);
-    IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass);
-    IonCode *generateBailoutHandler(JSContext *cx);
-    IonCode *generateInvalidator(JSContext *cx);
-    IonCode *generatePreBarrier(JSContext *cx);
-    IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
-
-  public:
-    IonRuntime();
-    ~IonRuntime();
-    bool initialize(JSContext *cx);
-};
-
-class IonCompartment
-{
-    friend class IonActivation;
-
-    // Ion state for the compartment's runtime.
-    IonRuntime *rt;
-
     // Any scripts for which off thread compilation has successfully finished,
     // failed, or been cancelled. All off thread compilations which are started
     // will eventually appear in this list asynchronously. Protected by the
     // runtime's analysis lock.
     OffThreadCompilationVector finishedOffThreadCompilations_;
 
     // Keep track of memoryregions that are going to be flushed.
     AutoFlushCache *flusher_;
 
+  private:
+    IonCode *generateEnterJIT(JSContext *cx);
+    IonCode *generateReturnError(JSContext *cx);
+    IonCode *generateArgumentsRectifier(JSContext *cx);
+    IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass);
+    IonCode *generateBailoutHandler(JSContext *cx);
+    IonCode *generateInvalidator(JSContext *cx);
+    IonCode *generatePreBarrier(JSContext *cx);
+
   public:
-    IonCode *getVMWrapper(const VMFunction &f);
+    IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
 
     OffThreadCompilationVector &finishedOffThreadCompilations() {
         return finishedOffThreadCompilations_;
     }
 
   public:
-    IonCompartment(IonRuntime *rt);
+    bool initialize(JSContext *cx);
+    IonCompartment();
+    ~IonCompartment();
 
     void mark(JSTracer *trc, JSCompartment *compartment);
     void sweep(FreeOp *fop);
 
     JSC::ExecutableAllocator *execAlloc() {
-        return rt->execAlloc_;
+        return execAlloc_;
+    }
+
+    IonCode *getBailoutTable(JSContext *cx, const FrameSizeClass &frameClass);
+    IonCode *getGenericBailoutHandler(JSContext *cx) {
+        if (!bailoutHandler_) {
+            bailoutHandler_ = generateBailoutHandler(cx);
+            if (!bailoutHandler_)
+                return NULL;
+        }
+        return bailoutHandler_;
     }
 
-    IonCode *getGenericBailoutHandler() {
-        return rt->bailoutHandler_;
-    }
-
+    // Infallible; does not generate a table.
     IonCode *getBailoutTable(const FrameSizeClass &frameClass);
 
-    IonCode *getArgumentsRectifier() {
-        return rt->argumentsRectifier_;
+    // Fallible; generates a thunk and returns the target.
+    IonCode *getArgumentsRectifier(JSContext *cx) {
+        if (!argumentsRectifier_) {
+            argumentsRectifier_ = generateArgumentsRectifier(cx);
+            if (!argumentsRectifier_)
+                return NULL;
+        }
+        return argumentsRectifier_;
+    }
+    IonCode **getArgumentsRectifierAddr() {
+        return argumentsRectifier_.unsafeGet();
     }
 
-    IonCode *getInvalidationThunk() {
-        return rt->invalidator_;
+    IonCode *getOrCreateInvalidationThunk(JSContext *cx) {
+        if (!invalidator_) {
+            invalidator_ = generateInvalidator(cx);
+            if (!invalidator_)
+                return NULL;
+        }
+        return invalidator_;
+    }
+    IonCode **getInvalidationThunkAddr() {
+        return invalidator_.unsafeGet();
+    }
+
+    EnterIonCode enterJITInfallible() {
+        JS_ASSERT(enterJIT_);
+        return enterJIT_.get()->as<EnterIonCode>();
     }
 
-    EnterIonCode enterJIT() {
-        return rt->enterJIT_->as<EnterIonCode>();
+    EnterIonCode enterJIT(JSContext *cx) {
+        if (!enterJIT_) {
+            enterJIT_ = generateEnterJIT(cx);
+            if (!enterJIT_)
+                return NULL;
+        }
+        return enterJIT_.get()->as<EnterIonCode>();
     }
 
-    IonCode *preBarrier() {
-        return rt->preBarrier_;
+    IonCode *preBarrier(JSContext *cx) {
+        if (!preBarrier_) {
+            preBarrier_ = generatePreBarrier(cx);
+            if (!preBarrier_)
+                return NULL;
+        }
+        return preBarrier_;
     }
-
     AutoFlushCache *flusher() {
         return flusher_;
     }
     void setFlusher(AutoFlushCache *fl) {
         if (!flusher_ || !fl)
             flusher_ = fl;
     }
 
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -647,18 +647,21 @@ MarkIonActivation(JSTracer *trc, const I
             break;
           case IonFrame_JS:
             MarkIonJSFrame(trc, frames);
             break;
           case IonFrame_Bailed_JS:
             JS_NOT_REACHED("invalid");
             break;
           case IonFrame_Rectifier:
-          case IonFrame_Bailed_Rectifier:
+          case IonFrame_Bailed_Rectifier: {
+            IonCompartment *ionCompartment = activations.activation()->compartment()->ionCompartment();
+            MarkIonCodeRoot(trc, ionCompartment->getArgumentsRectifierAddr(), "Arguments Rectifier");
             break;
+          }
           case IonFrame_Osr:
             // The callee token will be marked by the callee JS frame;
             // otherwise, it does not need to be marked, since the frame is
             // dead.
             break;
           default:
             JS_NOT_REACHED("unexpected frame type");
             break;
--- a/js/src/ion/IonFrames.h
+++ b/js/src/ion/IonFrames.h
@@ -203,19 +203,18 @@ class FrameSizeClass
 
     static FrameSizeClass None() {
         return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID);
     }
     static FrameSizeClass FromClass(uint32 class_) {
         return FrameSizeClass(class_);
     }
 
-    // These functions are implemented in specific CodeGenerator-* files.
+    // These two functions are implemented in specific CodeGenerator-* files.
     static FrameSizeClass FromDepth(uint32 frameDepth);
-    static FrameSizeClass ClassLimit();
     uint32 frameSize() const;
 
     uint32 classId() const {
         JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
         return class_;
     }
 
     bool operator ==(const FrameSizeClass &other) const {
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -362,25 +362,28 @@ class MacroAssembler : public MacroAssem
         branchTest32(cond, needsBarrierAddr, Imm32(0x1), label);
     }
 
     template <typename T>
     void callPreBarrier(const T &address, MIRType type) {
         JS_ASSERT(type == MIRType_Value || type == MIRType_String || type == MIRType_Object);
         Label done;
 
+        JSContext *cx = GetIonContext()->cx;
+        IonCode *preBarrier = cx->compartment->ionCompartment()->preBarrier(cx);
+        if (!preBarrier) {
+            enoughMemory_ = false;
+            return;
+        }
+
         if (type == MIRType_Value)
             branchTestGCThing(Assembler::NotEqual, address, &done);
 
         Push(PreBarrierReg);
         computeEffectiveAddress(address, PreBarrierReg);
-
-        JSCompartment *compartment = GetIonContext()->compartment;
-        IonCode *preBarrier = compartment->ionCompartment()->preBarrier();
-
         call(preBarrier);
         Pop(PreBarrierReg);
 
         bind(&done);
     }
 
     template <typename T>
     CodeOffsetLabel patchableCallPreBarrier(const T &address, MIRType type) {
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -16,32 +16,16 @@
 #include "jsinterpinlines.h"
 
 using namespace js;
 using namespace js::ion;
 
 namespace js {
 namespace ion {
 
-// Don't explicitly initialize, it's not guaranteed that this initializer will
-// run before the constructors for static VMFunctions.
-/* static */ VMFunction *VMFunction::functions;
-
-void
-VMFunction::addToFunctions()
-{
-    static bool initialized = false;
-    if (!initialized) {
-        initialized = true;
-        functions = NULL;
-    }
-    this->next = functions;
-    functions = this;
-}
-
 static inline bool
 ShouldMonitorReturnType(JSFunction *fun)
 {
     return fun->isInterpreted() &&
            (!fun->script()->hasAnalysis() ||
             !fun->script()->analysis()->ranInference());
 }
 
--- a/js/src/ion/VMFunctions.h
+++ b/js/src/ion/VMFunctions.h
@@ -29,20 +29,16 @@ enum DataType {
 // a value that does not meet this requirement - such as object-or-NULL, or an
 // integer, an optional, final outParam can be specified. In this case, the
 // return type must be boolean to indicate failure.
 //
 // All functions described by VMFunction take a JSContext * as a first
 // argument, and are treated as re-entrant into the VM and therefore fallible.
 struct VMFunction
 {
-    // Global linked list of all VMFunctions.
-    static VMFunction *functions;
-    VMFunction *next;
-
     // Address of the C function.
     void *wrapped;
 
     // Number of arguments expected, excluding JSContext * as an implicit
     // first argument and an outparam as a possible implicit final argument.
     uint32 explicitArgs;
 
     enum ArgProperties {
@@ -167,26 +163,16 @@ struct VMFunction
         outParam(outParam),
         returnType(returnType),
         argumentRootTypes(argRootTypes)
     {
         // Check for valid failure/return type.
         JS_ASSERT_IF(outParam != Type_Void, returnType == Type_Bool);
         JS_ASSERT(returnType == Type_Bool || returnType == Type_Object);
     }
-
-    VMFunction(const VMFunction &o)
-    {
-        *this = o;
-        addToFunctions();
-    }
-
-  private:
-    // Add this to the global list of VMFunctions.
-    void addToFunctions();
 };
 
 template <class> struct TypeToDataType { /* Unexpected return type for a VMFunction. */ };
 template <> struct TypeToDataType<bool> { static const DataType result = Type_Bool; };
 template <> struct TypeToDataType<JSObject *> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<JSString *> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<JSFlatString *> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -171,19 +171,21 @@ CodeGeneratorARM::generateOutOfLineCode(
 
     if (deoptLabel_) {
         // 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();
-
+        JSContext *cx = GetIonContext()->cx;
+        IonCompartment *ion = cx->compartment->ionCompartment();
+        IonCode *handler = ion->getGenericBailoutHandler(cx);
+        if (!handler)
+            return false;
         masm.branch(handler);
     }
 
     return true;
 }
 
 bool
 CodeGeneratorARM::bailoutIf(Assembler::Condition condition, LSnapshot *snapshot)
@@ -975,42 +977,45 @@ CodeGeneratorARM::emitRoundDouble(const 
 }
 
 bool
 CodeGeneratorARM::visitTruncateDToInt32(LTruncateDToInt32 *ins)
 {
     return emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()));
 }
 
-static const uint32 FrameSizes[] = { 128, 256, 512, 1024 };
+// The first two size classes are 128 and 256 bytes respectively. After that we
+// increment by 512.
+static const uint32 LAST_FRAME_SIZE = 512;
+static const uint32 LAST_FRAME_INCREMENT = 512;
+static const uint32 FrameSizes[] = { 128, 256, LAST_FRAME_SIZE };
 
 FrameSizeClass
 FrameSizeClass::FromDepth(uint32 frameDepth)
 {
     for (uint32 i = 0; i < JS_ARRAY_LENGTH(FrameSizes); i++) {
         if (frameDepth < FrameSizes[i])
             return FrameSizeClass(i);
     }
 
-    return FrameSizeClass::None();
-}
+    uint32 newFrameSize = frameDepth - LAST_FRAME_SIZE;
+    uint32 sizeClass = (newFrameSize / LAST_FRAME_INCREMENT) + 1;
 
-FrameSizeClass
-FrameSizeClass::ClassLimit()
-{
-    return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes));
+    return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes) + sizeClass);
 }
-
 uint32
 FrameSizeClass::frameSize() const
 {
     JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
-    JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes));
 
-    return FrameSizes[class_];
+    if (class_ < JS_ARRAY_LENGTH(FrameSizes))
+        return FrameSizes[class_];
+
+    uint32 step = class_ - JS_ARRAY_LENGTH(FrameSizes);
+    return LAST_FRAME_SIZE + step * LAST_FRAME_INCREMENT;
 }
 
 ValueOperand
 CodeGeneratorARM::ToValue(LInstruction *ins, size_t pos)
 {
     Register typeReg = ToRegister(ins->getOperand(pos + TYPE_INDEX));
     Register payloadReg = ToRegister(ins->getOperand(pos + PAYLOAD_INDEX));
     return ValueOperand(typeReg, payloadReg);
@@ -1450,23 +1455,23 @@ CodeGeneratorARM::visitRecompileCheck(LR
 
     // Bailout if the script is hot.
     masm.ma_cmp(tmp, Imm32(lir->mir()->minUses()));
     if (!bailoutIf(Assembler::AboveOrEqual, lir->snapshot()))
         return false;
     return true;
 }
 
-typedef bool (*InterruptCheckFn)(JSContext *);
-static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
-
 bool
 CodeGeneratorARM::visitInterruptCheck(LInterruptCheck *lir)
 {
-    OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
+    typedef bool (*pf)(JSContext *);
+    static const VMFunction interruptCheckInfo = FunctionInfo<pf>(InterruptCheck);
+
+    OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing());
     if (!ool)
         return false;
 
     void *interrupt = (void*)&gen->compartment->rt->interrupt;
     masm.load32(AbsoluteAddress(interrupt), lr);
     masm.ma_cmp(lr, Imm32(0));
     masm.ma_b(ool->entry(), Assembler::NonZero);
     masm.bind(ool->rejoin());
@@ -1482,19 +1487,23 @@ CodeGeneratorARM::generateInvalidateEpil
     for (size_t i = 0; i < sizeof(void *); i+= Assembler::nopSize())
         masm.nop();
 
     masm.bind(&invalidate_);
 
     // Push the return address of the point that we bailed out at onto the stack
     masm.Push(lr);
 
+    JSContext *cx = GetIonContext()->cx;
+
     // 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 = cx->compartment->ionCompartment()->getOrCreateInvalidationThunk(cx);
+    if (!thunk)
+        return false;
 
     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/Trampoline-arm.cpp
+++ b/js/src/ion/arm/Trampoline-arm.cpp
@@ -65,17 +65,17 @@ struct EnterJITStack
 /*
  * This method generates a trampoline on x86 for a c++ function with
  * the following signature:
  *   void enter(void *code, int argc, Value *argv, StackFrame *fp, CalleeToken
  *              calleeToken, Value *vp)
  *   ...using standard EABI calling convention
  */
 IonCode *
-IonRuntime::generateEnterJIT(JSContext *cx)
+IonCompartment::generateEnterJIT(JSContext *cx)
 {
     AutoFlushCache afc("GenerateEnterJIT", cx->compartment->ionCompartment());
 
     const Register reg_code  = r0;
     const Register reg_argc  = r1;
     const Register reg_argv  = r2;
     const Register reg_frame = r3;
 
@@ -194,19 +194,32 @@ IonRuntime::generateEnterJIT(JSContext *
     // Restore non-volatile registers and return.
     GenerateReturn(masm, JS_TRUE);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateInvalidator(JSContext *cx)
+IonCompartment::generateReturnError(JSContext *cx)
 {
-    // See large comment in x86's IonRuntime::generateInvalidator.
+    MacroAssembler masm(cx);
+    // This is where the stack size is stored on x86. where is it stored here?
+    masm.ma_pop(r0);
+    masm.ma_add(r0, sp, sp);
+
+    GenerateReturn(masm, JS_FALSE);
+    Linker linker(masm);
+    return linker.newCode(cx);
+}
+
+IonCode *
+IonCompartment::generateInvalidator(JSContext *cx)
+{
+    // See large comment in x86's IonCompartment::generateInvalidator.
     AutoIonContextAlloc aica(cx);
     MacroAssembler masm(cx);
     //masm.as_bkpt();
     // At this point, one of two things has happened.
     // 1) Execution has just returned from C code, which left the stack aligned
     // 2) Execution has just returned from Ion code, which left the stack unaligned.
     // The old return address should not matter, but we still want the
     // stack to be aligned, and there is no good reason to automatically align it with
@@ -243,17 +256,17 @@ IonRuntime::generateInvalidator(JSContex
     masm.generateBailoutTail(r1);
     Linker linker(masm);
     IonCode *code = linker.newCode(cx);
     IonSpew(IonSpew_Invalidate, "   invalidation thunk created at %p", (void *) code->raw());
     return code;
 }
 
 IonCode *
-IonRuntime::generateArgumentsRectifier(JSContext *cx)
+IonCompartment::generateArgumentsRectifier(JSContext *cx)
 {
     MacroAssembler masm(cx);
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == r8);
 
     // Copy number of actual arguments into r0
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfNumActualArgs())), r0);
@@ -430,43 +443,43 @@ GenerateBailoutThunk(MacroAssembler &mas
                           + sizeof(void*) // the size of the "return address" that was dumped on the stack
                           + bailoutFrameSize) // everything else that was pushed on the stack
                     , sp);
     }
     masm.generateBailoutTail(r1);
 }
 
 IonCode *
-IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
+IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass)
 {
     MacroAssembler masm;
 
     Label bailout;
     for (size_t i = 0; i < BAILOUT_TABLE_SIZE; i++)
         masm.ma_bl(&bailout);
     masm.bind(&bailout);
 
     GenerateBailoutThunk(masm, frameClass);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateBailoutHandler(JSContext *cx)
+IonCompartment::generateBailoutHandler(JSContext *cx)
 {
     MacroAssembler masm;
     GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
+IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f)
 {
     typedef MoveResolver::MoveOperand MoveOperand;
 
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
     if (p)
         return p->value;
@@ -606,17 +619,17 @@ IonRuntime::generateVMWrapper(JSContext 
     // use relookupOrAdd instead of add.
     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
         return NULL;
 
     return wrapper;
 }
 
 IonCode *
-IonRuntime::generatePreBarrier(JSContext *cx)
+IonCompartment::generatePreBarrier(JSContext *cx)
 {
     MacroAssembler masm;
 
     RegisterSet save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
                                    FloatRegisterSet(FloatRegisters::VolatileMask));
     masm.PushRegsInMask(save);
 
     JS_ASSERT(PreBarrierReg == r1);
--- a/js/src/ion/shared/CodeGenerator-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-shared.cpp
@@ -211,18 +211,17 @@ CodeGeneratorShared::encode(LSnapshot *s
         uint32 exprStack = mir->stackDepth() - block->info().ninvoke();
         snapshots_.startFrame(fun, script, pc, exprStack);
 
         // Ensure that all snapshot which are encoded can safely be used for
         // bailouts.
         DebugOnly<jsbytecode *> bailPC = pc;
         if (mir->mode() == MResumePoint::ResumeAfter)
           bailPC = GetNextPc(pc);
-        JS_ASSERT_IF(GetIonContext()->cx,
-                     exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC));
+        JS_ASSERT(exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC));
 
 #ifdef TRACK_SNAPSHOTS
         LInstruction *ins = instruction();
 
         uint32 pcOpcode = 0;
         uint32 lirOpcode = 0;
         uint32 lirId = 0;
         uint32 mirOpcode = 0;
@@ -367,19 +366,20 @@ CodeGeneratorShared::callVM(const VMFunc
     // Stack is:
     //    ... 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);
+    // Generate the wrapper of the VM function.
+    JSContext *cx = GetIonContext()->cx;
+    IonCompartment *ion = cx->compartment->ionCompartment();
+    IonCode *wrapper = ion->generateVMWrapper(cx, 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 callOffset;
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -288,18 +288,21 @@ CodeGeneratorX86Shared::generateOutOfLin
 
     if (deoptLabel_) {
         // 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();
+        JSContext *cx = GetIonContext()->cx;
+        IonCompartment *ion = cx->compartment->ionCompartment();
+        IonCode *handler = ion->getGenericBailoutHandler(cx);
+        if (!handler)
+            return false;
 
         masm.jmp(handler->raw(), Relocation::IONCODE);
     }
 
     return true;
 }
 
 class BailoutJump {
@@ -1306,19 +1309,23 @@ CodeGeneratorX86Shared::generateInvalida
     // Ensure that there is enough space in the buffer for the OsiPoint
     // patching to occur. Otherwise, we could overwrite the invalidation
     // epilogue.
     for (size_t i = 0; i < sizeof(void *); i+= Assembler::nopSize())
         masm.nop();
 
     masm.bind(&invalidate_);
 
+    JSContext *cx = GetIonContext()->cx;
+
     // 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 = cx->compartment->ionCompartment()->getOrCreateInvalidationThunk(cx);
+    if (!thunk)
+        return false;
 
     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/CodeGenerator-x64.cpp
+++ b/js/src/ion/x64/CodeGenerator-x64.cpp
@@ -42,22 +42,16 @@ CodeGeneratorX64::visitDouble(LDouble *i
 }
 
 FrameSizeClass
 FrameSizeClass::FromDepth(uint32 frameDepth)
 {
     return FrameSizeClass::None();
 }
 
-FrameSizeClass
-FrameSizeClass::ClassLimit()
-{
-    return FrameSizeClass(0);
-}
-
 uint32
 FrameSizeClass::frameSize() const
 {
     JS_NOT_REACHED("x64 does not use frame size classes");
     return 0;
 }
 
 bool
@@ -288,23 +282,23 @@ CodeGeneratorX64::visitRecompileCheck(LR
     Operand addr(ScratchReg, 0);
     masm.addl(Imm32(1), addr);
     masm.cmpl(addr, Imm32(lir->mir()->minUses()));
     if (!bailoutIf(Assembler::AboveOrEqual, lir->snapshot()))
         return false;
     return true;
 }
 
-typedef bool (*InterruptCheckFn)(JSContext *);
-static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
-
 bool
 CodeGeneratorX64::visitInterruptCheck(LInterruptCheck *lir)
 {
-    OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
+    typedef bool (*pf)(JSContext *);
+    static const VMFunction interruptCheckInfo = FunctionInfo<pf>(InterruptCheck);
+
+    OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing());
     if (!ool)
         return false;
 
     void *interrupt = (void*)&gen->compartment->rt->interrupt;
     masm.movq(ImmWord(interrupt), ScratchReg);
     masm.cmpl(Operand(ScratchReg, 0), Imm32(0));
     masm.j(Assembler::NonZero, ool->entry());
     masm.bind(ool->rejoin());
--- a/js/src/ion/x64/MacroAssembler-x64.h
+++ b/js/src/ion/x64/MacroAssembler-x64.h
@@ -859,17 +859,17 @@ class MacroAssemblerX64 : public MacroAs
     void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
         shlq(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
         orq(Imm32(type), frameSizeReg);
     }
 
     // Save an exit frame (which must be aligned to the stack pointer) to
     // ThreadData::ionTop.
     void linkExitFrame() {
-        mov(ImmWord(GetIonContext()->compartment->rt), ScratchReg);
+        mov(ImmWord(GetIonContext()->cx->runtime), ScratchReg);
         mov(StackPointer, Operand(ScratchReg, offsetof(JSRuntime, ionTop)));
     }
 
     void callWithExitFrame(IonCode *target, Register dynStack) {
         addPtr(Imm32(framePushed()), dynStack);
         makeFrameDescriptor(dynStack, IonFrame_JS);
         Push(dynStack);
         call(target);
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -20,17 +20,17 @@ using namespace js;
 using namespace js::ion;
 
 /* This method generates a trampoline on x64 for a c++ function with
  * the following signature:
  *   JSBool blah(void *code, int argc, Value *argv, Value *vp)
  *   ...using standard x64 fastcall calling convention
  */
 IonCode *
-IonRuntime::generateEnterJIT(JSContext *cx)
+IonCompartment::generateEnterJIT(JSContext *cx)
 {
     MacroAssembler masm(cx);
 
     const Register reg_code  = IntArgReg0;
     const Register reg_argc  = IntArgReg1;
     const Register reg_argv  = IntArgReg2;
     JS_ASSERT(OsrFrameReg == IntArgReg3);
 
@@ -175,22 +175,36 @@ IonRuntime::generateEnterJIT(JSContext *
     masm.pop(rbp);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateInvalidator(JSContext *cx)
+IonCompartment::generateReturnError(JSContext *cx)
+{
+    MacroAssembler masm(cx);
+
+    masm.pop(r14);              // sizeDescriptor.
+    masm.xorl(Imm32(0x1), r14); // Unmark EntryFrame.
+    masm.addq(r14, rsp);        // Remove arguments.
+    masm.pop(r11);              // Discard |vp|: returning from error.
+
+    Linker linker(masm);
+    return linker.newCode(cx);
+}
+
+IonCode *
+IonCompartment::generateInvalidator(JSContext *cx)
 {
     AutoIonContextAlloc aica(cx);
     MacroAssembler masm(cx);
 
-    // See explanatory comment in x86's IonRuntime::generateInvalidator.
+    // See explanatory comment in x86's IonCompartment::generateInvalidator.
 
     masm.addq(Imm32(sizeof(uintptr_t)), rsp);
 
     // Push registers such that we can access them from [base + code].
     masm.reserveStack(Registers::Total * sizeof(void *));
     for (uint32 i = 0; i < Registers::Total; i++)
         masm.movq(Register::FromCode(i), Operand(rsp, i * sizeof(void *)));
 
@@ -217,17 +231,17 @@ IonRuntime::generateInvalidator(JSContex
 
     masm.generateBailoutTail(rdx);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateArgumentsRectifier(JSContext *cx)
+IonCompartment::generateArgumentsRectifier(JSContext *cx)
 {
     // Do not erase the frame pointer in this function.
 
     MacroAssembler masm(cx);
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == r8);
@@ -340,35 +354,35 @@ GenerateBailoutThunk(JSContext *cx, Macr
     masm.addq(Imm32(BailoutDataSize), rsp);
     masm.pop(rcx);
     masm.lea(Operand(rsp, rcx, TimesOne, sizeof(void *)), rsp);
 
     masm.generateBailoutTail(rdx);
 }
 
 IonCode *
-IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
+IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass)
 {
     JS_NOT_REACHED("x64 does not use bailout tables");
     return NULL;
 }
 
 IonCode *
-IonRuntime::generateBailoutHandler(JSContext *cx)
+IonCompartment::generateBailoutHandler(JSContext *cx)
 {
     MacroAssembler masm;
 
     GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
+IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f)
 {
     typedef MoveResolver::MoveOperand MoveOperand;
 
     JS_ASSERT(!StackKeptAligned);
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
     if (p)
@@ -512,17 +526,17 @@ IonRuntime::generateVMWrapper(JSContext 
     // use relookupOrAdd instead of add.
     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
         return NULL;
 
     return wrapper;
 }
 
 IonCode *
-IonRuntime::generatePreBarrier(JSContext *cx)
+IonCompartment::generatePreBarrier(JSContext *cx)
 {
     MacroAssembler masm;
 
     RegisterSet regs = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
                                    FloatRegisterSet(FloatRegisters::VolatileMask));
     masm.PushRegsInMask(regs);
 
     JS_ASSERT(PreBarrierReg == rdx);
--- a/js/src/ion/x86/CodeGenerator-x86.cpp
+++ b/js/src/ion/x86/CodeGenerator-x86.cpp
@@ -16,42 +16,45 @@
 using namespace js;
 using namespace js::ion;
 
 CodeGeneratorX86::CodeGeneratorX86(MIRGenerator *gen, LIRGraph &graph)
   : CodeGeneratorX86Shared(gen, graph)
 {
 }
 
-static const uint32 FrameSizes[] = { 128, 256, 512, 1024 };
+// The first two size classes are 128 and 256 bytes respectively. After that we
+// increment by 512.
+static const uint32 LAST_FRAME_SIZE = 512;
+static const uint32 LAST_FRAME_INCREMENT = 512;
+static const uint32 FrameSizes[] = { 128, 256, LAST_FRAME_SIZE };
 
 FrameSizeClass
 FrameSizeClass::FromDepth(uint32 frameDepth)
 {
     for (uint32 i = 0; i < JS_ARRAY_LENGTH(FrameSizes); i++) {
         if (frameDepth < FrameSizes[i])
             return FrameSizeClass(i);
     }
 
-    return FrameSizeClass::None();
-}
+    uint32 newFrameSize = frameDepth - LAST_FRAME_SIZE;
+    uint32 sizeClass = (newFrameSize / LAST_FRAME_INCREMENT) + 1;
 
-FrameSizeClass
-FrameSizeClass::ClassLimit()
-{
-    return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes));
+    return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes) + sizeClass);
 }
-
 uint32
 FrameSizeClass::frameSize() const
 {
     JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
-    JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes));
 
-    return FrameSizes[class_];
+    if (class_ < JS_ARRAY_LENGTH(FrameSizes))
+        return FrameSizes[class_];
+
+    uint32 step = class_ - JS_ARRAY_LENGTH(FrameSizes);
+    return LAST_FRAME_SIZE + step * LAST_FRAME_INCREMENT;
 }
 
 ValueOperand
 CodeGeneratorX86::ToValue(LInstruction *ins, size_t pos)
 {
     Register typeReg = ToRegister(ins->getOperand(pos + TYPE_INDEX));
     Register payloadReg = ToRegister(ins->getOperand(pos + PAYLOAD_INDEX));
     return ValueOperand(typeReg, payloadReg);
@@ -280,23 +283,23 @@ CodeGeneratorX86::visitRecompileCheck(LR
     Operand addr(gen->info().script()->addressOfUseCount());
     masm.addl(Imm32(1), addr);
     masm.cmpl(addr, Imm32(lir->mir()->minUses()));
     if (!bailoutIf(Assembler::AboveOrEqual, lir->snapshot()))
         return false;
     return true;
 }
 
-typedef bool (*InterruptCheckFn)(JSContext *);
-static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
-
 bool
 CodeGeneratorX86::visitInterruptCheck(LInterruptCheck *lir)
 {
-    OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
+    typedef bool (*pf)(JSContext *);
+    static const VMFunction interruptCheckInfo = FunctionInfo<pf>(InterruptCheck);
+
+    OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing());
     if (!ool)
         return false;
 
     void *interrupt = (void*)&gen->compartment->rt->interrupt;
     masm.cmpl(Operand(interrupt), Imm32(0));
     masm.j(Assembler::NonZero, ool->entry());
     masm.bind(ool->rejoin());
     return true;
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -28,17 +28,17 @@ enum EnterJitEbpArgumentOffset {
     ARG_RESULT      = 7 * sizeof(void *)
 };
 
 /*
  * Generates a trampoline for a C++ function with the EnterIonCode signature,
  * using the standard cdecl calling convention.
  */
 IonCode *
-IonRuntime::generateEnterJIT(JSContext *cx)
+IonCompartment::generateEnterJIT(JSContext *cx)
 {
     MacroAssembler masm(cx);
 
     // Save old stack frame pointer, set new stack frame pointer.
     masm.push(ebp);
     masm.movl(esp, ebp);
 
     // Save non-volatile registers. These must be saved by the trampoline,
@@ -156,17 +156,17 @@ IonRuntime::generateEnterJIT(JSContext *
     masm.pop(ebp);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateInvalidator(JSContext *cx)
+IonCompartment::generateInvalidator(JSContext *cx)
 {
     AutoIonContextAlloc aica(cx);
     MacroAssembler masm(cx);
 
     // We do the minimum amount of work in assembly and shunt the rest
     // off to InvalidationBailout. Assembly does:
     //
     // - Pop the return address from the invalidation epilogue call.
@@ -206,17 +206,17 @@ IonRuntime::generateInvalidator(JSContex
 
     Linker linker(masm);
     IonCode *code = linker.newCode(cx);
     IonSpew(IonSpew_Invalidate, "   invalidation thunk created at %p", (void *) code->raw());
     return code;
 }
 
 IonCode *
-IonRuntime::generateArgumentsRectifier(JSContext *cx)
+IonCompartment::generateArgumentsRectifier(JSContext *cx)
 {
     MacroAssembler masm(cx);
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == esi);
 
     // Load the number of |undefined|s to push into %ecx.
@@ -352,44 +352,44 @@ GenerateBailoutThunk(JSContext *cx, Macr
         uint32 frameSize = FrameSizeClass::FromClass(frameClass).frameSize();
         masm.addl(Imm32(BailoutDataSize + sizeof(void *) + frameSize), esp);
     }
 
     masm.generateBailoutTail(edx);
 }
 
 IonCode *
-IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
+IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass)
 {
     MacroAssembler masm;
 
     Label bailout;
     for (size_t i = 0; i < BAILOUT_TABLE_SIZE; i++)
         masm.call(&bailout);
     masm.bind(&bailout);
 
     GenerateBailoutThunk(cx, masm, frameClass);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateBailoutHandler(JSContext *cx)
+IonCompartment::generateBailoutHandler(JSContext *cx)
 {
     MacroAssembler masm;
 
     GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
-IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
+IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f)
 {
     AssertCanGC();
     typedef MoveResolver::MoveOperand MoveOperand;
 
     JS_ASSERT(!StackKeptAligned);
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
@@ -539,17 +539,17 @@ IonRuntime::generateVMWrapper(JSContext 
     // use relookupOrAdd instead of add.
     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
         return NULL;
 
     return wrapper;
 }
 
 IonCode *
-IonRuntime::generatePreBarrier(JSContext *cx)
+IonCompartment::generatePreBarrier(JSContext *cx)
 {
     MacroAssembler masm;
 
     RegisterSet save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
                                    FloatRegisterSet(FloatRegisters::VolatileMask));
     masm.PushRegsInMask(save);
 
     JS_ASSERT(PreBarrierReg == edx);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -679,36 +679,30 @@ static JSBool js_NewRuntimeWasCalled = J
  */
 namespace JS {
 mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
 
 #ifdef DEBUG
 JS_FRIEND_API(void)
 EnterAssertNoGCScope()
 {
-    JSRuntime *rt = TlsRuntime.get();
-    if (rt)
-        ++rt->gcAssertNoGCDepth;
+    ++TlsRuntime.get()->gcAssertNoGCDepth;
 }
 
 JS_FRIEND_API(void)
 LeaveAssertNoGCScope()
 {
-    JSRuntime *rt = TlsRuntime.get();
-    if (rt) {
-        --rt->gcAssertNoGCDepth;
-        JS_ASSERT(rt->gcAssertNoGCDepth >= 0);
-    }
+    --TlsRuntime.get()->gcAssertNoGCDepth;
+    JS_ASSERT(TlsRuntime.get()->gcAssertNoGCDepth >= 0);
 }
 
 JS_FRIEND_API(bool)
 InNoGCScope()
 {
-    JSRuntime *rt = TlsRuntime.get();
-    return !rt || rt->gcAssertNoGCDepth > 0;
+    return TlsRuntime.get()->gcAssertNoGCDepth > 0;
 }
 
 JS_FRIEND_API(bool)
 NeedRelaxedRootChecks()
 {
     return TlsRuntime.get()->gcRelaxRootChecks;
 }
 #else
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -87,17 +87,16 @@ TraceCycleDetectionSet(JSTracer *trc, Ob
 
 namespace mjit {
 class JaegerRuntime;
 }
 
 class MathCache;
 
 namespace ion {
-class IonRuntime;
 class IonActivation;
 }
 
 class WeakMapBase;
 class InterpreterFrames;
 class DebugScopes;
 class WorkerThreadState;
 
@@ -434,24 +433,22 @@ struct JSRuntime : js::RuntimeFriendFiel
      * Both of these allocators are used for regular expression code which is shared at the
      * thread-data level.
      */
     JSC::ExecutableAllocator *execAlloc_;
     WTF::BumpPointerAllocator *bumpAlloc_;
 #ifdef JS_METHODJIT
     js::mjit::JaegerRuntime *jaegerRuntime_;
 #endif
-    js::ion::IonRuntime *ionRuntime_;
 
     JSObject *selfHostedGlobal_;
 
     JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
     WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
     js::mjit::JaegerRuntime *createJaegerRuntime(JSContext *cx);
-    js::ion::IonRuntime *createIonRuntime(JSContext *cx);
 
   public:
     JSC::ExecutableAllocator *getExecAlloc(JSContext *cx) {
         return execAlloc_ ? execAlloc_ : createExecutableAllocator(cx);
     }
     JSC::ExecutableAllocator &execAlloc() {
         JS_ASSERT(execAlloc_);
         return *execAlloc_;
@@ -466,19 +463,16 @@ struct JSRuntime : js::RuntimeFriendFiel
     bool hasJaegerRuntime() const {
         return jaegerRuntime_;
     }
     js::mjit::JaegerRuntime &jaegerRuntime() {
         JS_ASSERT(hasJaegerRuntime());
         return *jaegerRuntime_;
     }
 #endif
-    js::ion::IonRuntime *getIonRuntime(JSContext *cx) {
-        return ionRuntime_ ? ionRuntime_ : createIonRuntime(cx);
-    }
 
     bool initSelfHosting(JSContext *cx);
     void markSelfHostedGlobal(JSTracer *trc);
     bool isSelfHostedGlobal(js::HandleObject global) {
         return global == selfHostedGlobal_;
     }
     JSFunction *getSelfHostedFunction(JSContext *cx, const char *name);
     bool cloneSelfHostedValueById(JSContext *cx, js::HandleId id, js::HandleObject holder,
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -144,55 +144,32 @@ JSCompartment::setNeedsBarrier(bool need
     if (needsBarrier_ != needs)
         ion::ToggleBarriers(this, needs);
 #endif
 
     needsBarrier_ = needs;
 }
 
 #ifdef JS_ION
-ion::IonRuntime *
-JSRuntime::createIonRuntime(JSContext *cx)
-{
-    ionRuntime_ = cx->new_<ion::IonRuntime>();
-
-    if (!ionRuntime_)
-        return NULL;
-
-    if (!ionRuntime_->initialize(cx)) {
-        js_delete(ionRuntime_);
-        ionRuntime_ = NULL;
-
-        if (cx->runtime->atomsCompartment->ionCompartment_) {
-            js_delete(cx->runtime->atomsCompartment->ionCompartment_);
-            cx->runtime->atomsCompartment->ionCompartment_ = NULL;
-        }
-
-        return NULL;
-    }
-
-    return ionRuntime_;
-}
-
 bool
 JSCompartment::ensureIonCompartmentExists(JSContext *cx)
 {
     using namespace js::ion;
     if (ionCompartment_)
         return true;
 
-    IonRuntime *ionRuntime = cx->runtime->getIonRuntime(cx);
-    if (!ionRuntime)
-        return false;
+    /* Set the compartment early, so linking works. */
+    ionCompartment_ = cx->new_<IonCompartment>();
 
-    /* Set the compartment early, so linking works. */
-    ionCompartment_ = cx->new_<IonCompartment>(ionRuntime);
-
-    if (!ionCompartment_)
+    if (!ionCompartment_ || !ionCompartment_->initialize(cx)) {
+        if (ionCompartment_)
+            delete ionCompartment_;
+        ionCompartment_ = NULL;
         return false;
+    }
 
     return true;
 }
 #endif
 
 static bool
 WrapForSameCompartment(JSContext *cx, HandleObject obj, Value *vp)
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -116,17 +116,16 @@ class AutoDebugModeGC;
 }
 
 struct JSCompartment
 {
     JSRuntime                    *rt;
     JSPrincipals                 *principals;
 
   private:
-    friend struct JSRuntime;
     friend struct JSContext;
     js::GlobalObject             *global_;
   public:
     // Nb: global_ might be NULL, if (a) it's the atoms compartment, or (b) the
     // compartment's global has been collected.  The latter can happen if e.g.
     // a string in a compartment is rooted but no object is, and thus the
     // global isn't rooted, and thus the global can be finalized while the
     // compartment lives on.
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3890,24 +3890,16 @@ BeginSweepPhase(JSRuntime *rt)
     for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
         if (c->isGCSweeping()) {
             gcstats::AutoSCC scc(rt->gcStats, partition.getSCC(c));
             c->arenas.queueShapesForSweep(&fop);
         }
     }
 #ifdef JS_ION
     for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
-        /*
-         * Don't sweep IonCode objects from the atoms compartment. These are
-         * stubs and wrappers allocated when the IonRuntime is created and
-         * must persist until the runtime is destroyed.
-         */
-        if (c == rt->atomsCompartment)
-            continue;
-
         if (c->isGCSweeping()) {
             gcstats::AutoSCC scc(rt->gcStats, partition.getSCC(c));
             c->arenas.queueIonCodeForSweep(&fop);
         }
     }
 #endif
 
     rt->gcSweepPhase = 0;
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -432,19 +432,17 @@ class GCCompartmentsIter {
 
 template <typename T>
 inline T *
 NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
 {
     AssertCanGC();
     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
     JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment,
-                 kind == FINALIZE_STRING ||
-                 kind == FINALIZE_SHORT_STRING ||
-                 kind == FINALIZE_IONCODE);
+                 kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
     JS_ASSERT(!cx->runtime->isHeapBusy());
     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
 
     /* For testing out of memory conditions */
     JS_OOM_POSSIBLY_FAIL_REPORT(cx);
 
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -12,17 +12,18 @@
 
 using namespace js;
 
 #ifdef JS_PARALLEL_COMPILATION
 
 bool
 js::OffThreadCompilationAvailable(JSContext *cx)
 {
-    return cx->runtime->useHelperThreads();
+    WorkerThreadState &state = *cx->runtime->workerThreadState;
+    return state.numThreads > 0;
 }
 
 bool
 js::StartOffThreadIonCompile(JSContext *cx, ion::IonBuilder *builder)
 {
     JSRuntime *rt = cx->runtime;
     if (!rt->workerThreadState) {
         rt->workerThreadState = rt->new_<WorkerThreadState>();
@@ -68,18 +69,16 @@ CompiledScriptMatches(JSCompartment *com
     if (script)
         return target == script;
     return target->compartment() == compartment;
 }
 
 void
 js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script)
 {
-    AutoAssertNoGC nogc;
-
     if (!compartment->rt->workerThreadState)
         return;
 
     WorkerThreadState &state = *compartment->rt->workerThreadState;
 
     ion::IonCompartment *ion = compartment->ionCompartment();
     if (!ion)
         return;