Bug 994957 - Fix pseudostack update by Ion ICs in inlined scripts to use top-level script in the frame and the pc of the call it makes to the inlined script. r=jandem
☠☠ backed out by 7d352709614b ☠ ☠
authorKannan Vijayan <kvijayan@mozilla.com>
Thu, 01 May 2014 15:45:37 -0400
changeset 181642 af1cebf017fc9c8ac78ea63213f13a9a3b9b237a
parent 181641 9bca81260db48b5a1b92e1e505c99782db48dabc
child 181643 e5a6e3bfa4be4139be832c70db3959b61819edbe
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjandem
bugs994957
milestone32.0a1
Bug 994957 - Fix pseudostack update by Ion ICs in inlined scripts to use top-level script in the frame and the pc of the call it makes to the inlined script. r=jandem
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/CompileInfo.h
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/MIR.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6748,16 +6748,17 @@ CodeGenerator::visitStoreFixedSlotT(LSto
 bool
 CodeGenerator::visitCallsiteCloneCache(LCallsiteCloneCache *ins)
 {
     const MCallsiteCloneCache *mir = ins->mir();
     Register callee = ToRegister(ins->callee());
     Register output = ToRegister(ins->output());
 
     CallsiteCloneIC cache(callee, mir->block()->info().script(), mir->callPc(), output);
+    cache.setProfilerLeavePC(mir->profilerLeavePc());
     return addCache(ins, allocateCache(cache));
 }
 
 typedef JSObject *(*CallsiteCloneICFn)(JSContext *, size_t, HandleObject);
 const VMFunction CallsiteCloneIC::UpdateInfo =
     FunctionInfo<CallsiteCloneICFn>(CallsiteCloneIC::update);
 
 bool
@@ -6781,16 +6782,17 @@ bool
 CodeGenerator::visitGetNameCache(LGetNameCache *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register scopeChain = ToRegister(ins->scopeObj());
     TypedOrValueRegister output(GetValueOutput(ins));
     bool isTypeOf = ins->mir()->accessKind() != MGetNameCache::NAME;
 
     NameIC cache(liveRegs, isTypeOf, scopeChain, ins->mir()->name(), output);
+    cache.setProfilerLeavePC(ins->mir()->profilerLeavePc());
     return addCache(ins, allocateCache(cache));
 }
 
 typedef bool (*NameICFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
 const VMFunction NameIC::UpdateInfo = FunctionInfo<NameICFn>(NameIC::update);
 
 bool
 CodeGenerator::visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic)
@@ -6807,94 +6809,103 @@ CodeGenerator::visitNameIC(OutOfLineUpda
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                                    PropertyName *name, TypedOrValueRegister output,
-                                   bool monitoredResult)
+                                   bool monitoredResult, jsbytecode *profilerLeavePc)
 {
     switch (gen->info().executionMode()) {
       case SequentialExecution: {
         GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
+        cache.setProfilerLeavePC(profilerLeavePc);
         return addCache(ins, allocateCache(cache));
       }
       case ParallelExecution: {
         GetPropertyParIC cache(objReg, name, output);
+        cache.setProfilerLeavePC(profilerLeavePc);
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
     }
 }
 
 bool
 CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                                    PropertyName *name, ConstantOrRegister value, bool strict,
-                                   bool needsTypeBarrier)
+                                   bool needsTypeBarrier, jsbytecode *profilerLeavePc)
 {
     switch (gen->info().executionMode()) {
       case SequentialExecution: {
           SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
+            cache.setProfilerLeavePC(profilerLeavePc);
           return addCache(ins, allocateCache(cache));
       }
       case ParallelExecution: {
           SetPropertyParIC cache(objReg, name, value, strict, needsTypeBarrier);
+            cache.setProfilerLeavePC(profilerLeavePc);
           return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
     }
 }
 
 bool
 CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
                                   Register temp, FloatRegister tempFloat, ValueOperand index,
-                                  ConstantOrRegister value, bool strict, bool guardHoles)
+                                  ConstantOrRegister value, bool strict, bool guardHoles,
+                                  jsbytecode *profilerLeavePc)
 {
     switch (gen->info().executionMode()) {
       case SequentialExecution: {
         SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict,
                            guardHoles);
+        cache.setProfilerLeavePC(profilerLeavePc);
         return addCache(ins, allocateCache(cache));
       }
       case ParallelExecution: {
         SetElementParIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict,
                               guardHoles);
+        cache.setProfilerLeavePC(profilerLeavePc);
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
     }
 }
 
 bool
 CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     PropertyName *name = ins->mir()->name();
     bool monitoredResult = ins->mir()->monitoredResult();
     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
 
-    return addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult);
+    return addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult,
+                               ins->mir()->profilerLeavePc());
 }
 
 bool
 CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     PropertyName *name = ins->mir()->name();
     bool monitoredResult = ins->mir()->monitoredResult();
     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
 
-    return addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult);
+    return addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult,
+                               ins->mir()->profilerLeavePc());
 }
 
 typedef bool (*GetPropertyICFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
 const VMFunction GetPropertyIC::UpdateInfo =
     FunctionInfo<GetPropertyICFn>(GetPropertyIC::update);
 
 bool
 CodeGenerator::visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic)
@@ -6940,53 +6951,57 @@ CodeGenerator::visitGetPropertyParIC(Out
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
                                   TypedOrValueRegister output, bool monitoredResult,
-                                  bool allowDoubleResult)
+                                  bool allowDoubleResult, jsbytecode *profilerLeavePc)
 {
     switch (gen->info().executionMode()) {
       case SequentialExecution: {
         RegisterSet liveRegs = ins->safepoint()->liveRegs();
         GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
+        cache.setProfilerLeavePC(profilerLeavePc);
         return addCache(ins, allocateCache(cache));
       }
       case ParallelExecution: {
         GetElementParIC cache(obj, index, output, monitoredResult, allowDoubleResult);
+        cache.setProfilerLeavePC(profilerLeavePc);
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("No such execution mode");
     }
 }
 
 bool
 CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
 {
     Register obj = ToRegister(ins->object());
     ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
     const MGetElementCache *mir = ins->mir();
 
-    return addGetElementCache(ins, obj, index, output, mir->monitoredResult(), mir->allowDoubleResult());
+    return addGetElementCache(ins, obj, index, output, mir->monitoredResult(),
+                              mir->allowDoubleResult(), mir->profilerLeavePc());
 }
 
 bool
 CodeGenerator::visitGetElementCacheT(LGetElementCacheT *ins)
 {
     Register obj = ToRegister(ins->object());
     ConstantOrRegister index = TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()));
     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
     const MGetElementCache *mir = ins->mir();
 
-    return addGetElementCache(ins, obj, index, output, mir->monitoredResult(), mir->allowDoubleResult());
+    return addGetElementCache(ins, obj, index, output, mir->monitoredResult(),
+                              mir->allowDoubleResult(), mir->profilerLeavePc());
 }
 
 typedef bool (*GetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
 const VMFunction GetElementIC::UpdateInfo =
     FunctionInfo<GetElementICFn>(GetElementIC::update);
 
 bool
 CodeGenerator::visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic)
@@ -7012,17 +7027,18 @@ CodeGenerator::visitSetElementCacheV(LSe
     Register obj = ToRegister(ins->object());
     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
     Register temp = ToRegister(ins->temp());
     FloatRegister tempFloat = ToFloatRegister(ins->tempFloat());
     ValueOperand index = ToValue(ins, LSetElementCacheV::Index);
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetElementCacheV::Value));
 
     return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
-                              ins->mir()->strict(), ins->mir()->guardHoles());
+                              ins->mir()->strict(), ins->mir()->guardHoles(),
+                              ins->mir()->profilerLeavePc());
 }
 
 bool
 CodeGenerator::visitSetElementCacheT(LSetElementCacheT *ins)
 {
     Register obj = ToRegister(ins->object());
     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
     Register temp = ToRegister(ins->temp());
@@ -7031,17 +7047,18 @@ CodeGenerator::visitSetElementCacheT(LSe
     ConstantOrRegister value;
     const LAllocation *tmp = ins->value();
     if (tmp->isConstant())
         value = *tmp->toConstant();
     else
         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(tmp));
 
     return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
-                              ins->mir()->strict(), ins->mir()->guardHoles());
+                              ins->mir()->strict(), ins->mir()->guardHoles(),
+                              ins->mir()->profilerLeavePc());
 }
 
 typedef bool (*SetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, HandleValue);
 const VMFunction SetElementIC::UpdateInfo =
     FunctionInfo<SetElementICFn>(SetElementIC::update);
 
 bool
 CodeGenerator::visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic)
@@ -7107,16 +7124,17 @@ CodeGenerator::visitGetElementParIC(OutO
 }
 
 bool
 CodeGenerator::visitBindNameCache(LBindNameCache *ins)
 {
     Register scopeChain = ToRegister(ins->scopeChain());
     Register output = ToRegister(ins->output());
     BindNameIC cache(scopeChain, ins->mir()->name(), output);
+    cache.setProfilerLeavePC(ins->mir()->profilerLeavePc());
 
     return addCache(ins, allocateCache(cache));
 }
 
 typedef JSObject *(*BindNameICFn)(JSContext *, size_t, HandleObject);
 const VMFunction BindNameIC::UpdateInfo =
     FunctionInfo<BindNameICFn>(BindNameIC::update);
 
@@ -7201,33 +7219,35 @@ CodeGenerator::visitCallDeleteElement(LC
 bool
 CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
 
     return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
-                               ins->mir()->strict(), ins->mir()->needsTypeBarrier());
+                               ins->mir()->strict(), ins->mir()->needsTypeBarrier(),
+                               ins->mir()->profilerLeavePc());
 }
 
 bool
 CodeGenerator::visitSetPropertyCacheT(LSetPropertyCacheT *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value;
 
     if (ins->getOperand(1)->isConstant())
         value = ConstantOrRegister(*ins->getOperand(1)->toConstant());
     else
         value = TypedOrValueRegister(ins->valueType(), ToAnyRegister(ins->getOperand(1)));
 
     return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
-                               ins->mir()->strict(), ins->mir()->needsTypeBarrier());
+                               ins->mir()->strict(), ins->mir()->needsTypeBarrier(),
+                               ins->mir()->profilerLeavePc());
 }
 
 typedef bool (*SetPropertyICFn)(JSContext *, size_t, HandleObject, HandleValue);
 const VMFunction SetPropertyIC::UpdateInfo =
     FunctionInfo<SetPropertyICFn>(SetPropertyIC::update);
 
 bool
 CodeGenerator::visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic)
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -348,26 +348,26 @@ class CodeGenerator : public CodeGenerat
     bool visitAssertRangeF(LAssertRangeF *ins);
     bool visitAssertRangeV(LAssertRangeV *ins);
 
     bool visitRecompileCheck(LRecompileCheck *ins);
 
   private:
     bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, TypedOrValueRegister output,
-                             bool monitoredResult);
+                             bool monitoredResult, jsbytecode *profilerLeavePc);
     bool addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
                             TypedOrValueRegister output, bool monitoredResult,
-                            bool allowDoubleResult);
+                            bool allowDoubleResult, jsbytecode *profilerLeavePc);
     bool addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, ConstantOrRegister value, bool strict,
-                             bool needsTypeBarrier);
+                             bool needsTypeBarrier, jsbytecode *profilerLeavePc);
     bool addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
                             FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
-                            bool strict, bool guardHoles);
+                            bool strict, bool guardHoles, jsbytecode *profilerLeavePc);
     bool checkForAbortPar(LInstruction *lir);
 
     bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
 
     bool emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
                                 Register tempReg1, Register tempReg2,
                                 JSObject *templateObj);
 
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -75,16 +75,25 @@ class InlineScriptTree {
 
     InlineScriptTree *addCallee(TempAllocator *allocator, jsbytecode *callerPc,
                                  JSScript *calleeScript);
 
     InlineScriptTree *caller() const {
         return caller_;
     }
 
+    bool isOutermostCaller() const {
+        return caller_ == nullptr;
+    }
+    InlineScriptTree *outermostCaller() {
+        if (isOutermostCaller())
+            return this;
+        return caller_->outermostCaller();
+    }
+
     jsbytecode *callerPc() const {
         return callerPc_;
     }
 
     JSScript *script() const {
         return script_;
     }
 
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1190,33 +1190,34 @@ GetPropertyIC::allowArrayLength(Context 
         if (!bcTypes->hasType(types::Type::Int32Type()))
             return false;
     }
 
     return true;
 }
 
 bool
-GetPropertyIC::tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj,
+GetPropertyIC::tryAttachNative(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                                HandlePropertyName name, void *returnAddr, bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
+    JS_ASSERT(topScript->ionScript() == ion);
 
     RootedShape shape(cx);
     RootedObject holder(cx);
 
     NativeGetPropCacheability type =
         CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape);
     if (type == CanAttachNone)
         return true;
 
     *emitted = true;
 
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
 
     RepatchStubAppender attacher(*this);
     const char *attachKind;
 
     switch (type) {
       case CanAttachReadSlot:
         GenerateReadSlot(cx, ion, masm, attacher, obj, holder,
                          shape, object(), output());
@@ -1239,18 +1240,18 @@ GetPropertyIC::tryAttachNative(JSContext
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Bad NativeGetPropCacheability");
     }
     return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
 }
 
 bool
-GetPropertyIC::tryAttachTypedArrayLength(JSContext *cx, IonScript *ion, HandleObject obj,
-                                         HandlePropertyName name, bool *emitted)
+GetPropertyIC::tryAttachTypedArrayLength(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                         HandleObject obj, HandlePropertyName name, bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
 
     if (!obj->is<TypedArrayObject>())
         return true;
 
     if (cx->names().length != name)
@@ -1265,17 +1266,17 @@ GetPropertyIC::tryAttachTypedArrayLength
         return true;
     }
 
     if (idempotent())
         return true;
 
     *emitted = true;
 
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     GenerateTypedArrayLength(cx, masm, attacher, obj, object(), output());
 
     JS_ASSERT(!hasTypedArrayLengthStub_);
     hasTypedArrayLengthStub_ = true;
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array length");
 }
 
@@ -1348,33 +1349,33 @@ EmitCallProxyGet(JSContext *cx, MacroAss
     // masm.leaveExitFrame & pop locals
     masm.adjustStack(IonOOLProxyExitFrameLayout::Size());
 
     masm.icRestoreLive(liveRegs, aic);
     return true;
 }
 
 bool
-GetPropertyIC::tryAttachDOMProxyShadowed(JSContext *cx, IonScript *ion,
+GetPropertyIC::tryAttachDOMProxyShadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
                                          HandleObject obj, void *returnAddr,
                                          bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
     JS_ASSERT(IsCacheableDOMProxy(obj));
     JS_ASSERT(monitoredResult());
     JS_ASSERT(output().hasValue());
 
     if (idempotent())
         return true;
 
     *emitted = true;
 
     Label failures;
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard on the shape of the object.
     attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
                                    Address(object(), JSObject::offsetOfShape()),
                                    ImmGCPtr(obj->lastProperty()),
                                    &failures);
 
@@ -1394,19 +1395,19 @@ GetPropertyIC::tryAttachDOMProxyShadowed
     // Failure.
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "list base shadowed get");
 }
 
 bool
-GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                           HandlePropertyName name, bool resetNeeded,
-                                           void *returnAddr, bool *emitted)
+GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                           HandleObject obj, HandlePropertyName name,
+                                           bool resetNeeded, void *returnAddr, bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
     JS_ASSERT(IsCacheableDOMProxy(obj));
     JS_ASSERT(monitoredResult());
     JS_ASSERT(output().hasValue());
 
     RootedObject checkObj(cx, obj->getTaggedProto().toObjectOrNull());
@@ -1433,17 +1434,17 @@ GetPropertyIC::tryAttachDOMProxyUnshadow
         // (if there is one). The generation is a constant in the generated
         // code and we will not have the same generation again for this
         // object, so the generation check in the existing IC would always
         // fail anyway.
         reset();
     }
 
     Label failures;
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard on the shape of the object.
     attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
                                    Address(object(), JSObject::offsetOfShape()),
                                    ImmGCPtr(obj->lastProperty()),
                                    &failures);
 
@@ -1494,17 +1495,17 @@ GetPropertyIC::tryAttachDOMProxyUnshadow
     attacher.jumpRejoin(masm);
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "unshadowed proxy get");
 }
 
 bool
-GetPropertyIC::tryAttachProxy(JSContext *cx, IonScript *ion, HandleObject obj,
+GetPropertyIC::tryAttachProxy(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                               HandlePropertyName name, void *returnAddr,
                               bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
 
     if (!obj->is<ProxyObject>())
         return true;
@@ -1516,38 +1517,38 @@ GetPropertyIC::tryAttachProxy(JSContext 
 
     // Skim off DOM proxies.
     if (IsCacheableDOMProxy(obj)) {
         RootedId id(cx, NameToId(name));
         DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id);
         if (shadows == ShadowCheckFailed)
             return false;
         if (shadows == Shadows)
-            return tryAttachDOMProxyShadowed(cx, ion, obj, returnAddr, emitted);
-
-        return tryAttachDOMProxyUnshadowed(cx, ion, obj, name, shadows == DoesntShadowUnique,
-                                           returnAddr, emitted);
+            return tryAttachDOMProxyShadowed(cx, topScript, ion, obj, returnAddr, emitted);
+
+        return tryAttachDOMProxyUnshadowed(cx, topScript, ion, obj, name,
+                                           shadows == DoesntShadowUnique, returnAddr, emitted);
     }
 
-    return tryAttachGenericProxy(cx, ion, obj, name, returnAddr, emitted);
+    return tryAttachGenericProxy(cx, topScript, ion, obj, name, returnAddr, emitted);
 }
 
 static void
 GenerateProxyClassGuards(MacroAssembler &masm, Register object, Register scratchReg,
                          Label *failures)
 {
     masm.loadObjClass(object, scratchReg);
     masm.branchTest32(Assembler::Zero,
                       Address(scratchReg, Class::offsetOfFlags()),
                       Imm32(JSCLASS_IS_PROXY), failures);
 }
 
 bool
-GetPropertyIC::tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject obj,
-                                     HandlePropertyName name, void *returnAddr,
+GetPropertyIC::tryAttachGenericProxy(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                     HandleObject obj, HandlePropertyName name, void *returnAddr,
                                      bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
     JS_ASSERT(obj->is<ProxyObject>());
     JS_ASSERT(monitoredResult());
     JS_ASSERT(output().hasValue());
 
@@ -1555,17 +1556,17 @@ GetPropertyIC::tryAttachGenericProxy(JSC
         return true;
 
     if (idempotent())
         return true;
 
     *emitted = true;
 
     Label failures;
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     Register scratchReg = output().valueReg().scratchReg();
 
     GenerateProxyClassGuards(masm, object(), scratchReg, &failures);
 
     // Ensure that the incoming object is not a DOM proxy, so that we can get to
     // the specialized stubs
@@ -1585,18 +1586,18 @@ GetPropertyIC::tryAttachGenericProxy(JSC
 
     JS_ASSERT(!hasGenericProxyStub_);
     hasGenericProxyStub_ = true;
 
     return linkAndAttachStub(cx, masm, attacher, ion, "Generic Proxy get");
 }
 
 bool
-GetPropertyIC::tryAttachArgumentsLength(JSContext *cx, IonScript *ion, HandleObject obj,
-                                        HandlePropertyName name, bool *emitted)
+GetPropertyIC::tryAttachArgumentsLength(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                        HandleObject obj, HandlePropertyName name, bool *emitted)
 {
     JS_ASSERT(canAttachStub());
     JS_ASSERT(!*emitted);
 
     if (name != cx->names().length)
         return true;
     if (!IsOptimizableArgumentsObjectForLength(obj))
         return true;
@@ -1608,17 +1609,17 @@ GetPropertyIC::tryAttachArgumentsLength(
     if (hasArgumentsLengthStub(obj->is<StrictArgumentsObject>()))
         return true;
 
     *emitted = true;
 
     JS_ASSERT(!idempotent());
 
     Label failures;
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     Register tmpReg;
     if (output().hasValue()) {
         tmpReg = output().valueReg().scratchReg();
     } else {
         JS_ASSERT(output().type() == MIRType_Int32);
         tmpReg = output().typedReg().gpr();
@@ -1655,34 +1656,34 @@ GetPropertyIC::tryAttachArgumentsLength(
     }
 
     JS_ASSERT(!hasNormalArgumentsLengthStub_);
     hasNormalArgumentsLengthStub_ = true;
     return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (normal)");
 }
 
 bool
-GetPropertyIC::tryAttachStub(JSContext *cx, IonScript *ion, HandleObject obj,
+GetPropertyIC::tryAttachStub(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                              HandlePropertyName name, void *returnAddr, bool *emitted)
 {
     JS_ASSERT(!*emitted);
 
     if (!canAttachStub())
         return true;
 
-    if (!*emitted && !tryAttachArgumentsLength(cx, ion, obj, name, emitted))
+    if (!*emitted && !tryAttachArgumentsLength(cx, topScript, ion, obj, name, emitted))
         return false;
 
-    if (!*emitted && !tryAttachProxy(cx, ion, obj, name, returnAddr, emitted))
+    if (!*emitted && !tryAttachProxy(cx, topScript, ion, obj, name, returnAddr, emitted))
         return false;
 
-    if (!*emitted && !tryAttachNative(cx, ion, obj, name, returnAddr, emitted))
+    if (!*emitted && !tryAttachNative(cx, topScript, ion, obj, name, returnAddr, emitted))
         return false;
 
-    if (!*emitted && !tryAttachTypedArrayLength(cx, ion, obj, name, emitted))
+    if (!*emitted && !tryAttachTypedArrayLength(cx, topScript, ion, obj, name, emitted))
         return false;
 
     return true;
 }
 
 /* static */ bool
 GetPropertyIC::update(JSContext *cx, size_t cacheIndex,
                       HandleObject obj, MutableHandleValue vp)
@@ -1702,17 +1703,17 @@ GetPropertyIC::update(JSContext *cx, siz
     // If the cache is idempotent, we will redo the op in the interpreter.
     if (cache.idempotent())
         adi.disable();
 
     // For now, just stop generating new stubs once we hit the stub count
     // limit. Once we can make calls from within generated stubs, a new call
     // stub will be generated instead and the previous stubs unlinked.
     bool emitted = false;
-    if (!cache.tryAttachStub(cx, ion, obj, name, returnAddr, &emitted))
+    if (!cache.tryAttachStub(cx, topScript, ion, obj, name, returnAddr, &emitted))
         return false;
 
     if (cache.idempotent() && !emitted) {
         // Invalidate the cache if the property was not found, or was found on
         // a non-native object. This ensures:
         // 1) The property read has no observable side-effects.
         // 2) There's no need to dynamically monitor the return type. This would
         //    be complicated since (due to GVN) there can be multiple pc's
@@ -2000,20 +2001,20 @@ GenerateSetSlot(JSContext *cx, MacroAsse
         masm.pop(object);
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 }
 
 bool
-SetPropertyIC::attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj,
+SetPropertyIC::attachSetSlot(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                              HandleShape shape, bool checkTypeset)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     GenerateSetSlot(cx, masm, attacher, obj, shape, object(), value(), needsTypeBarrier(),
                     checkTypeset);
     return linkAndAttachStub(cx, masm, attacher, ion, "setting");
 }
 
 static bool
 IsCacheableSetPropCallNative(HandleObject obj, HandleObject holder, HandleShape shape)
@@ -2119,21 +2120,22 @@ EmitCallProxySet(JSContext *cx, MacroAss
     // masm.leaveExitFrame & pop locals
     masm.adjustStack(IonOOLProxyExitFrameLayout::Size());
 
     masm.icRestoreLive(liveRegs, aic);
     return true;
 }
 
 bool
-SetPropertyIC::attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr)
+SetPropertyIC::attachGenericProxy(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                  void *returnAddr)
 {
     JS_ASSERT(!hasGenericProxyStub());
 
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     Label failures;
     {
         Label proxyFailures;
         Label proxySuccess;
 
         RegisterSet regSet(RegisterSet::All());
@@ -2174,23 +2176,23 @@ SetPropertyIC::attachGenericProxy(JSCont
 
     JS_ASSERT(!hasGenericProxyStub_);
     hasGenericProxyStub_ = true;
 
     return linkAndAttachStub(cx, masm, attacher, ion, "generic proxy set");
 }
 
 bool
-SetPropertyIC::attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                        void *returnAddr)
+SetPropertyIC::attachDOMProxyShadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                      HandleObject obj, void *returnAddr)
 {
     JS_ASSERT(IsCacheableDOMProxy(obj));
 
     Label failures;
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard on the shape of the object.
     masm.branchPtr(Assembler::NotEqual,
                    Address(object(), JSObject::offsetOfShape()),
                    ImmGCPtr(obj->lastProperty()), &failures);
 
     // Make sure object is a DOMProxy
@@ -2401,23 +2403,23 @@ IsCacheableDOMProxyUnshadowedSetterCall(
         return true;
     }
 
     *isSetter = true;
     return true;
 }
 
 bool
-SetPropertyIC::attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                        void *returnAddr)
+SetPropertyIC::attachDOMProxyUnshadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                        HandleObject obj, void *returnAddr)
 {
     JS_ASSERT(IsCacheableDOMProxy(obj));
 
     Label failures;
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard on the shape of the object.
     masm.branchPtr(Assembler::NotEqual,
                    Address(object(), JSObject::offsetOfShape()),
                    ImmGCPtr(obj->lastProperty()), &failures);
 
     // Make sure object is a DOMProxy
@@ -2456,23 +2458,23 @@ SetPropertyIC::attachDOMProxyUnshadowed(
     // Failure.
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "DOM proxy unshadowed set");
 }
 
 bool
-SetPropertyIC::attachCallSetter(JSContext *cx, IonScript *ion,
+SetPropertyIC::attachCallSetter(JSContext *cx, JSScript *topScript, IonScript *ion,
                                 HandleObject obj, HandleObject holder, HandleShape shape,
                                 void *returnAddr)
 {
     JS_ASSERT(obj->isNative());
 
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     Label failure;
     masm.branchPtr(Assembler::NotEqual,
                    Address(object(), JSObject::offsetOfShape()),
                    ImmGCPtr(obj->lastProperty()),
                    &failure);
 
@@ -2569,22 +2571,22 @@ GenerateAddSlot(JSContext *cx, MacroAsse
     masm.bind(&failuresPopObject);
     masm.pop(object);
     masm.bind(&failures);
 
     attacher.jumpNextStub(masm);
 }
 
 bool
-SetPropertyIC::attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape,
-                             bool checkTypeset)
+SetPropertyIC::attachAddSlot(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *obj,
+                             HandleShape oldShape, bool checkTypeset)
 {
     JS_ASSERT_IF(!needsTypeBarrier(), !checkTypeset);
 
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     GenerateAddSlot(cx, masm, attacher, obj, oldShape, object(), value(), checkTypeset);
     return linkAndAttachStub(cx, masm, attacher, ion, "adding");
 }
 
 static bool
 CanInlineSetPropTypeCheck(JSObject *obj, jsid id, ConstantOrRegister val, bool *checkTypeset)
 {
@@ -2765,31 +2767,31 @@ SetPropertyIC::update(JSContext *cx, siz
     bool addedSetterStub = false;
     if (inlinable) {
         if (!addedSetterStub && obj->is<ProxyObject>()) {
             if (IsCacheableDOMProxy(obj)) {
                 DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id);
                 if (shadows == ShadowCheckFailed)
                     return false;
                 if (shadows == Shadows) {
-                    if (!cache.attachDOMProxyShadowed(cx, ion, obj, returnAddr))
+                    if (!cache.attachDOMProxyShadowed(cx, script, ion, obj, returnAddr))
                         return false;
                     addedSetterStub = true;
                 } else {
                     JS_ASSERT(shadows == DoesntShadow || shadows == DoesntShadowUnique);
                     if (shadows == DoesntShadowUnique)
                         cache.reset();
-                    if (!cache.attachDOMProxyUnshadowed(cx, ion, obj, returnAddr))
+                    if (!cache.attachDOMProxyUnshadowed(cx, script, ion, obj, returnAddr))
                         return false;
                     addedSetterStub = true;
                 }
             }
 
             if (!addedSetterStub && !cache.hasGenericProxyStub()) {
-                if (!cache.attachGenericProxy(cx, ion, returnAddr))
+                if (!cache.attachGenericProxy(cx, script, ion, returnAddr))
                     return false;
                 addedSetterStub = true;
             }
         }
 
         // Make sure the object de-lazifies its type. We do this here so that
         // the parallel IC can share code that assumes that native objects all
         // have a type object.
@@ -2798,23 +2800,23 @@ SetPropertyIC::update(JSContext *cx, siz
 
         RootedShape shape(cx);
         RootedObject holder(cx);
         bool checkTypeset;
         canCache = CanAttachNativeSetProp(obj, id, cache.value(), cache.needsTypeBarrier(),
                                           &holder, &shape, &checkTypeset);
 
         if (!addedSetterStub && canCache == CanAttachSetSlot) {
-            if (!cache.attachSetSlot(cx, ion, obj, shape, checkTypeset))
+            if (!cache.attachSetSlot(cx, script, ion, obj, shape, checkTypeset))
                 return false;
             addedSetterStub = true;
         }
 
         if (!addedSetterStub && canCache == CanAttachCallSetter) {
-            if (!cache.attachCallSetter(cx, ion, obj, holder, shape, returnAddr))
+            if (!cache.attachCallSetter(cx, script, ion, obj, holder, shape, returnAddr))
                 return false;
             addedSetterStub = true;
         }
     }
 
     uint32_t oldSlots = obj->numDynamicSlots();
     RootedShape oldShape(cx, obj->lastProperty());
 
@@ -2823,17 +2825,17 @@ SetPropertyIC::update(JSContext *cx, siz
         return false;
 
     // The property did not exist before, now we can try to inline the property add.
     bool checkTypeset;
     if (!addedSetterStub && canCache == MaybeCanAttachAddSlot &&
         IsPropertyAddInlineable(obj, id, cache.value(), oldSlots, oldShape, cache.needsTypeBarrier(),
                                 &checkTypeset))
     {
-        if (!cache.attachAddSlot(cx, ion, obj, oldShape, checkTypeset))
+        if (!cache.attachAddSlot(cx, script, ion, obj, oldShape, checkTypeset))
             return false;
     }
 
     return true;
 }
 
 void
 SetPropertyIC::reset()
@@ -2964,17 +2966,17 @@ EqualStringsHelper(JSString *str1, JSStr
 
     const jschar *chars = str2->getChars(nullptr);
     if (!chars)
         return false;
     return mozilla::PodEqual(str1->asAtom().chars(), chars, str1->length());
 }
 
 bool
-GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
+GetElementIC::attachGetProp(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                             const Value &idval, HandlePropertyName name,
                             void *returnAddr)
 {
     JS_ASSERT(index().reg().hasValue());
 
     RootedObject holder(cx);
     RootedShape shape(cx);
 
@@ -2990,17 +2992,17 @@ GetElementIC::attachGetProp(JSContext *c
         IonSpew(IonSpew_InlineCaches, "GETELEM uncacheable property");
         return true;
     }
 
     JS_ASSERT(idval.isString());
     JS_ASSERT(idval.toString()->length() == name->length());
 
     Label failures;
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
 
     // Ensure the index is a string.
     ValueOperand val = index().reg().valueReg();
     masm.branchTestString(Assembler::NotEqual, val, &failures);
 
     Register scratch = output().valueReg().scratchReg();
     masm.unboxString(val, scratch);
 
@@ -3123,19 +3125,20 @@ GenerateDenseElement(JSContext *cx, Macr
     masm.bind(&failures);
 
     attacher.jumpNextStub(masm);
 
     return true;
 }
 
 bool
-GetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
+GetElementIC::attachDenseElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                 JSObject *obj, const Value &idval)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     if (!GenerateDenseElement(cx, masm, attacher, obj, idval, object(), index(), output()))
         return false;
 
     setHasDenseStub();
     return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
 }
 
@@ -3277,33 +3280,34 @@ GenerateGetTypedArrayElement(JSContext *
     masm.bind(&popAndFail);
     masm.pop(object);
     masm.bind(&failures);
 
     attacher.jumpNextStub(masm);
 }
 
 bool
-GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
-                                      const Value &idval)
+GetElementIC::attachTypedArrayElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                      TypedArrayObject *tarr, const Value &idval)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output(),
                                  allowDoubleResult());
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
 }
 
 bool
-GetElementIC::attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj)
+GetElementIC::attachArgumentsElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                     JSObject *obj)
 {
     JS_ASSERT(obj->is<ArgumentsObject>());
 
     Label failures;
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     Register tmpReg = output().scratchReg().gpr();
     JS_ASSERT(tmpReg != InvalidReg);
 
     const Class *clasp = obj->is<StrictArgumentsObject>() ? &StrictArgumentsObject::class_
                                                           : &NormalArgumentsObject::class_;
 
@@ -3401,17 +3405,18 @@ GetElementIC::attachArgumentsElement(JSC
     return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (normal)");
 }
 
 bool
 GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                      HandleValue idval, MutableHandleValue res)
 {
     void *returnAddr;
-    IonScript *ion = GetTopIonJSScript(cx, &returnAddr)->ionScript();
+    RootedScript topScript(cx, GetTopIonJSScript(cx, &returnAddr));
+    IonScript *ion = topScript->ionScript();
     GetElementIC &cache = ion->getCache(cacheIndex).toGetElement();
     RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
 
     // Override the return value when the script is invalidated (bug 728188).
     AutoDetectInvalidation adi(cx, res.address(), ion);
 
@@ -3433,34 +3438,34 @@ GetElementIC::update(JSContext *cx, size
     if (cache.canAttachStub()) {
         if (IsOptimizableArgumentsObjectForGetElem(obj, idval) &&
             !cache.hasArgumentsStub(obj->is<StrictArgumentsObject>()) &&
             !cache.index().constant() &&
             (cache.index().reg().hasValue() ||
              cache.index().reg().type() == MIRType_Int32) &&
             (cache.output().hasValue() || !cache.output().typedReg().isFloat()))
         {
-            if (!cache.attachArgumentsElement(cx, ion, obj))
+            if (!cache.attachArgumentsElement(cx, topScript, ion, obj))
                 return false;
             attachedStub = true;
         }
         if (!attachedStub && cache.monitoredResult() && canAttachGetProp(obj, idval, id)) {
             RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
-            if (!cache.attachGetProp(cx, ion, obj, idval, name, returnAddr))
+            if (!cache.attachGetProp(cx, topScript, ion, obj, idval, name, returnAddr))
                 return false;
             attachedStub = true;
         }
         if (!attachedStub && !cache.hasDenseStub() && canAttachDenseElement(obj, idval)) {
-            if (!cache.attachDenseElement(cx, ion, obj, idval))
+            if (!cache.attachDenseElement(cx, topScript, ion, obj, idval))
                 return false;
             attachedStub = true;
         }
         if (!attachedStub && canAttachTypedArrayElement(obj, idval, cache.output())) {
             Rooted<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
-            if (!cache.attachTypedArrayElement(cx, ion, tarr, idval))
+            if (!cache.attachTypedArrayElement(cx, topScript, ion, tarr, idval))
                 return false;
             attachedStub = true;
         }
     }
 
     if (!GetObjectElementOperation(cx, JSOp(*pc), obj, /* wasObject = */true, idval, res))
         return false;
 
@@ -3672,19 +3677,20 @@ GenerateSetDenseElement(JSContext *cx, M
     masm.bind(&outOfBounds);
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     return true;
 }
 
 bool
-SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
+SetElementIC::attachDenseElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                 JSObject *obj, const Value &idval)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
                                  guardHoles(), object(), index(),
                                  value(), tempToUnboxIndex(),
                                  temp()))
     {
         return false;
     }
@@ -3775,47 +3781,49 @@ GenerateSetTypedArrayElement(JSContext *
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
     return true;
 }
 
 bool
-SetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr)
+SetElementIC::attachTypedArrayElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                      TypedArrayObject *tarr)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
                                       object(), index(), value(),
                                       tempToUnboxIndex(), temp(), tempFloat()))
     {
         return false;
     }
 
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
 }
 
 bool
 SetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                      HandleValue idval, HandleValue value)
 {
-    IonScript *ion = GetTopIonJSScript(cx)->ionScript();
+    RootedScript topScript(cx, GetTopIonJSScript(cx));
+    IonScript *ion = topScript->ionScript();
     SetElementIC &cache = ion->getCache(cacheIndex).toSetElement();
 
     bool attachedStub = false;
     if (cache.canAttachStub()) {
         if (!cache.hasDenseStub() && IsDenseElementSetInlineable(obj, idval)) {
-            if (!cache.attachDenseElement(cx, ion, obj, idval))
+            if (!cache.attachDenseElement(cx, topScript, ion, obj, idval))
                 return false;
             attachedStub = true;
         }
         if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
             TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-            if (!cache.attachTypedArrayElement(cx, ion, tarr))
+            if (!cache.attachTypedArrayElement(cx, topScript, ion, tarr))
                 return false;
         }
     }
 
     if (!SetObjectElement(cx, obj, idval, value, cache.strict()))
         return false;
     return true;
 }
@@ -4010,21 +4018,21 @@ GetElementParIC::update(ForkJoinContext 
             }
         }
     }
 
     return true;
 }
 
 bool
-BindNameIC::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain)
+BindNameIC::attachGlobal(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *scopeChain)
 {
     JS_ASSERT(scopeChain->is<GlobalObject>());
 
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard on the scope chain.
     attacher.branchNextStub(masm, Assembler::NotEqual, scopeChainReg(),
                             ImmGCPtr(scopeChain));
     masm.movePtr(ImmGCPtr(scopeChain), outputReg());
 
     attacher.jumpRejoin(masm);
@@ -4085,21 +4093,22 @@ GenerateScopeChainGuards(MacroAssembler 
 
         // Load the next link.
         tobj = &tobj->as<ScopeObject>().enclosingScope();
         masm.extractObject(Address(outputReg, ScopeObject::offsetOfEnclosingScope()), outputReg);
     }
 }
 
 bool
-BindNameIC::attachNonGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain, JSObject *holder)
+BindNameIC::attachNonGlobal(JSContext *cx, JSScript *topScript, IonScript *ion,
+                            JSObject *scopeChain, JSObject *holder)
 {
     JS_ASSERT(IsCacheableNonGlobalScope(scopeChain));
 
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard on the shape of the scope chain.
     Label failures;
     attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
                                    Address(scopeChainReg(), JSObject::offsetOfShape()),
                                    ImmGCPtr(scopeChain->lastProperty()),
                                    holder != scopeChain ? &failures : nullptr);
@@ -4148,51 +4157,52 @@ IsCacheableScopeChain(JSObject *scopeCha
     MOZ_ASSUME_UNREACHABLE("Invalid scope chain");
 }
 
 JSObject *
 BindNameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain)
 {
     AutoFlushCache afc ("BindNameCache", cx->runtime()->jitRuntime());
 
-    IonScript *ion = GetTopIonJSScript(cx)->ionScript();
+    RootedScript topScript(cx, GetTopIonJSScript(cx));
+    IonScript *ion = topScript->ionScript();
     BindNameIC &cache = ion->getCache(cacheIndex).toBindName();
     HandlePropertyName name = cache.name();
 
     RootedObject holder(cx);
     if (scopeChain->is<GlobalObject>()) {
         holder = scopeChain;
     } else {
         if (!LookupNameWithGlobalDefault(cx, name, scopeChain, &holder))
             return nullptr;
     }
 
     // Stop generating new stubs once we hit the stub count limit, see
     // GetPropertyCache.
     if (cache.canAttachStub()) {
         if (scopeChain->is<GlobalObject>()) {
-            if (!cache.attachGlobal(cx, ion, scopeChain))
+            if (!cache.attachGlobal(cx, topScript, ion, scopeChain))
                 return nullptr;
         } else if (IsCacheableScopeChain(scopeChain, holder)) {
-            if (!cache.attachNonGlobal(cx, ion, scopeChain, holder))
+            if (!cache.attachNonGlobal(cx, topScript, ion, scopeChain, holder))
                 return nullptr;
         } else {
             IonSpew(IonSpew_InlineCaches, "BINDNAME uncacheable scope chain");
         }
     }
 
     return holder;
 }
 
 bool
-NameIC::attachReadSlot(JSContext *cx, IonScript *ion, HandleObject scopeChain,
+NameIC::attachReadSlot(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject scopeChain,
                        HandleObject holderBase, HandleObject holder,
                        HandleShape shape)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     Label failures;
     RepatchStubAppender attacher(*this);
 
     Register scratchReg = outputReg().valueReg().scratchReg();
 
     // Don't guard the base of the proto chain the name was found on. It will be guarded
     // by GenerateReadSlot().
     masm.mov(scopeChainReg(), scratchReg);
@@ -4242,20 +4252,20 @@ IsCacheableNameReadSlot(JSContext *cx, H
 
         obj2 = obj2->enclosingScope();
     }
 
     return obj == obj2;
 }
 
 bool
-NameIC::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
-                         HandleShape shape, void *returnAddr)
+NameIC::attachCallGetter(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *obj,
+                         JSObject *holder, HandleShape shape, void *returnAddr)
 {
-    MacroAssembler masm(cx, ion, script_, pc_);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
 
     RepatchStubAppender attacher(*this);
     if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name(), holder, shape, liveRegs_,
                             scopeChainReg(), outputReg(), returnAddr))
     {
          return false;
     }
 
@@ -4278,37 +4288,38 @@ IsCacheableNameCallGetter(JSObject *scop
 
 bool
 NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
                MutableHandleValue vp)
 {
     AutoFlushCache afc ("GetNameCache", cx->runtime()->jitRuntime());
 
     void *returnAddr;
-    IonScript *ion = GetTopIonJSScript(cx, &returnAddr)->ionScript();
+    RootedScript topScript(cx, GetTopIonJSScript(cx, &returnAddr));
+    IonScript *ion = topScript->ionScript();
 
     NameIC &cache = ion->getCache(cacheIndex).toName();
     RootedPropertyName name(cx, cache.name());
 
     RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
 
     RootedObject obj(cx);
     RootedObject holder(cx);
     RootedShape shape(cx);
     if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
         return false;
 
     if (cache.canAttachStub()) {
         if (IsCacheableNameReadSlot(cx, scopeChain, obj, holder, shape, pc, cache.outputReg())) {
-            if (!cache.attachReadSlot(cx, ion, scopeChain, obj, holder, shape))
+            if (!cache.attachReadSlot(cx, topScript, ion, scopeChain, obj, holder, shape))
                 return false;
         } else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
-            if (!cache.attachCallGetter(cx, ion, obj, holder, shape, returnAddr))
+            if (!cache.attachCallGetter(cx, topScript, ion, obj, holder, shape, returnAddr))
                 return false;
         }
     }
 
     if (cache.isTypeOf()) {
         if (!FetchName<true>(cx, obj, holder, name, shape, vp))
             return false;
     } else {
@@ -4318,20 +4329,20 @@ NameIC::update(JSContext *cx, size_t cac
 
     // Monitor changes to cache entry.
     types::TypeScript::Monitor(cx, script, pc, vp);
 
     return true;
 }
 
 bool
-CallsiteCloneIC::attach(JSContext *cx, IonScript *ion, HandleFunction original,
+CallsiteCloneIC::attach(JSContext *cx, JSScript *topScript, IonScript *ion, HandleFunction original,
                         HandleFunction clone)
 {
-    MacroAssembler masm(cx, ion);
+    MacroAssembler masm(cx, ion, topScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
 
     // Guard against object identity on the original.
     attacher.branchNextStub(masm, Assembler::NotEqual, calleeReg(), ImmGCPtr(original));
 
     // Load the clone.
     masm.movePtr(ImmGCPtr(clone), outputReg());
 
@@ -4346,22 +4357,23 @@ CallsiteCloneIC::update(JSContext *cx, s
     AutoFlushCache afc ("CallsiteCloneCache", cx->runtime()->jitRuntime());
 
     // Act as the identity for functions that are not clone-at-callsite, as we
     // generate this cache as long as some callees are clone-at-callsite.
     RootedFunction fun(cx, &callee->as<JSFunction>());
     if (!fun->hasScript() || !fun->nonLazyScript()->shouldCloneAtCallsite())
         return fun;
 
-    IonScript *ion = GetTopIonJSScript(cx)->ionScript();
+    RootedScript topScript(cx, GetTopIonJSScript(cx));
+    IonScript *ion = topScript->ionScript();
     CallsiteCloneIC &cache = ion->getCache(cacheIndex).toCallsiteClone();
 
     RootedFunction clone(cx, CloneFunctionAtCallsite(cx, fun, cache.callScript(), cache.callPc()));
     if (!clone)
         return nullptr;
 
     if (cache.canAttachStub()) {
-        if (!cache.attach(cx, ion, fun, clone))
+        if (!cache.attach(cx, topScript, ion, fun, clone))
             return nullptr;
     }
 
     return clone;
 }
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -163,16 +163,20 @@ class IonCache
     size_t stubCount_ : 5;
 
     CodeLocationLabel fallbackLabel_;
 
     // Location of this operation, nullptr for idempotent caches.
     JSScript *script_;
     jsbytecode *pc_;
 
+    // Location to use when updating profiler pseudostack when leaving this
+    // IC code to enter a callee.
+    jsbytecode *profilerLeavePc_;
+
   private:
     static const size_t MAX_STUBS;
     void incrementStubCount() {
         // The IC should stop generating stubs before wrapping stubCount.
         stubCount_++;
         JS_ASSERT(stubCount_);
     }
 
@@ -180,32 +184,38 @@ class IonCache
 
     IonCache()
       : pure_(false),
         idempotent_(false),
         disabled_(false),
         stubCount_(0),
         fallbackLabel_(),
         script_(nullptr),
-        pc_(nullptr)
+        pc_(nullptr),
+        profilerLeavePc_(nullptr)
     {
     }
 
     virtual void disable();
     inline bool isDisabled() const {
         return disabled_;
     }
 
     // Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is
     // the location of the out-of-line update (slow) path.  This location will
     // be set to the exitJump of the last generated stub.
     void setFallbackLabel(CodeOffsetLabel fallbackLabel) {
         fallbackLabel_ = fallbackLabel;
     }
 
+    void setProfilerLeavePC(jsbytecode *pc) {
+        JS_ASSERT(pc != nullptr);
+        profilerLeavePc_ = pc;
+    }
+
     virtual void emitInitialJump(MacroAssembler &masm, AddCacheState &addState) = 0;
     virtual void bindInitialJump(MacroAssembler &masm, AddCacheState &addState) = 0;
     virtual void updateBaseAddress(JitCode *code, MacroAssembler &masm);
 
     // Initialize the AddCacheState depending on the kind of cache, like
     // setting a scratch register. Defaults to doing nothing.
     virtual void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
 
@@ -609,34 +619,34 @@ class GetPropertyIC : public RepatchIonC
     // Helpers for CanAttachNativeGetProp
     typedef JSContext * Context;
     bool allowArrayLength(Context cx, HandleObject obj) const;
     bool allowGetters() const {
         return monitoredResult() && !idempotent();
     }
 
     // Attach the proper stub, if possible
-    bool tryAttachStub(JSContext *cx, IonScript *ion, HandleObject obj,
+    bool tryAttachStub(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                        HandlePropertyName name, void *returnAddr, bool *emitted);
-    bool tryAttachProxy(JSContext *cx, IonScript *ion, HandleObject obj,
+    bool tryAttachProxy(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                         HandlePropertyName name, void *returnAddr, bool *emitted);
-    bool tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject obj,
+    bool tryAttachGenericProxy(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                                HandlePropertyName name, void *returnAddr, bool *emitted);
-    bool tryAttachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                   void *returnAddr, bool *emitted);
-    bool tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                     HandlePropertyName name, bool resetNeeded,
+    bool tryAttachDOMProxyShadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                   HandleObject obj, void *returnAddr, bool *emitted);
+    bool tryAttachDOMProxyUnshadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                     HandleObject obj, HandlePropertyName name, bool resetNeeded,
                                      void *returnAddr, bool *emitted);
-    bool tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj,
+    bool tryAttachNative(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                          HandlePropertyName name, void *returnAddr, bool *emitted);
-    bool tryAttachTypedArrayLength(JSContext *cx, IonScript *ion, HandleObject obj,
-                                   HandlePropertyName name, bool *emitted);
+    bool tryAttachTypedArrayLength(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                   HandleObject obj, HandlePropertyName name, bool *emitted);
 
-    bool tryAttachArgumentsLength(JSContext *cx, IonScript *ion, HandleObject obj,
-                                  HandlePropertyName name, bool *emitted);
+    bool tryAttachArgumentsLength(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                  HandleObject obj, HandlePropertyName name, bool *emitted);
 
     static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
 };
 
 class SetPropertyIC : public RepatchIonCache
 {
   protected:
     // Registers live after the cache, excluding output registers. The initial
@@ -689,27 +699,27 @@ class SetPropertyIC : public RepatchIonC
 
     enum NativeSetPropCacheability {
         CanAttachNone,
         CanAttachSetSlot,
         MaybeCanAttachAddSlot,
         CanAttachCallSetter
     };
 
-    bool attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape,
-                       bool checkTypeset);
-    bool attachCallSetter(JSContext *cx, IonScript *ion, HandleObject obj,
+    bool attachSetSlot(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
+                       HandleShape shape, bool checkTypeset);
+    bool attachCallSetter(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
                           HandleObject holder, HandleShape shape, void *returnAddr);
-    bool attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape,
-                       bool checkTypeset);
-    bool attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr);
-    bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                void *returnAddr);
-    bool attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
-                                  void *returnAddr);
+    bool attachAddSlot(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *obj,
+                       HandleShape oldShape, bool checkTypeset);
+    bool attachGenericProxy(JSContext *cx, JSScript *topScript, IonScript *ion, void *returnAddr);
+    bool attachDOMProxyShadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                HandleObject obj, void *returnAddr);
+    bool attachDOMProxyUnshadowed(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                  HandleObject obj, void *returnAddr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
 };
 
 class GetElementIC : public RepatchIonCache
 {
   protected:
@@ -783,22 +793,23 @@ class GetElementIC : public RepatchIonCa
         return monitoredResult();
     }
 
     static bool canAttachGetProp(JSObject *obj, const Value &idval, jsid id);
     static bool canAttachDenseElement(JSObject *obj, const Value &idval);
     static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
                                            TypedOrValueRegister output);
 
-    bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval,
-                       HandlePropertyName name, void *returnAddr);
-    bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
-    bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
-                                 const Value &idval);
-    bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
+    bool attachGetProp(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject obj,
+                       const Value &idval, HandlePropertyName name, void *returnAddr);
+    bool attachDenseElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                            JSObject *obj, const Value &idval);
+    bool attachTypedArrayElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                 TypedArrayObject *tarr, const Value &idval);
+    bool attachArgumentsElement(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *obj);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
            MutableHandleValue vp);
 
     void incFailedUpdates() {
         failedUpdates_++;
     }
@@ -873,18 +884,20 @@ class SetElementIC : public RepatchIonCa
     bool hasDenseStub() const {
         return hasDenseStub_;
     }
     void setHasDenseStub() {
         JS_ASSERT(!hasDenseStub());
         hasDenseStub_ = true;
     }
 
-    bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
-    bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr);
+    bool attachDenseElement(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *obj,
+                            const Value &idval);
+    bool attachTypedArrayElement(JSContext *cx, JSScript *topScript, IonScript *ion,
+                                 TypedArrayObject *tarr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
            HandleValue value);
 };
 
 class BindNameIC : public RepatchIonCache
 {
@@ -908,18 +921,19 @@ class BindNameIC : public RepatchIonCach
     }
     HandlePropertyName name() const {
         return HandlePropertyName::fromMarkedLocation(&name_);
     }
     Register outputReg() const {
         return output_;
     }
 
-    bool attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain);
-    bool attachNonGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain, JSObject *holder);
+    bool attachGlobal(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *scopeChain);
+    bool attachNonGlobal(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *scopeChain,
+                         JSObject *holder);
 
     static JSObject *
     update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain);
 };
 
 class NameIC : public RepatchIonCache
 {
   protected:
@@ -954,20 +968,20 @@ class NameIC : public RepatchIonCache
     }
     TypedOrValueRegister outputReg() const {
         return output_;
     }
     bool isTypeOf() const {
         return typeOf_;
     }
 
-    bool attachReadSlot(JSContext *cx, IonScript *ion, HandleObject scopeChain,
+    bool attachReadSlot(JSContext *cx, JSScript *topScript, IonScript *ion, HandleObject scopeChain,
                         HandleObject holderBase, HandleObject holder, HandleShape shape);
-    bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
-                          HandleShape shape, void *returnAddr);
+    bool attachCallGetter(JSContext *cx, JSScript *topScript, IonScript *ion, JSObject *obj,
+                          JSObject *holder, HandleShape shape, void *returnAddr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
 };
 
 class CallsiteCloneIC : public RepatchIonCache
 {
   protected:
@@ -995,17 +1009,18 @@ class CallsiteCloneIC : public RepatchIo
     }
     jsbytecode *callPc() const {
         return callPc_;
     }
     Register outputReg() const {
         return output_;
     }
 
-    bool attach(JSContext *cx, IonScript *ion, HandleFunction original, HandleFunction clone);
+    bool attach(JSContext *cx, JSScript *topScript, IonScript *ion,
+                HandleFunction original, HandleFunction clone);
 
     static JSObject *update(JSContext *cx, size_t cacheIndex, HandleObject callee);
 };
 
 class ParallelIonCache : public DispatchIonCache
 {
   protected:
     // A set of all objects that are stubbed. Used to detect duplicates in
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -373,23 +373,44 @@ class MDefinition : public MNode
     virtual bool possiblyCalls() const { return false; }
 
     void setTrackedSite(const BytecodeSite &site) {
         trackedSite_ = site;
     }
     const BytecodeSite &trackedSite() const {
         return trackedSite_;
     }
-    jsbytecode *trackedPc() {
+    jsbytecode *trackedPc() const {
         return trackedSite_.pc();
     }
-    InlineScriptTree *trackedTree() {
+    InlineScriptTree *trackedTree() const {
         return trackedSite_.tree();
     }
 
+    JSScript *profilerLeaveScript() const {
+        return trackedTree()->outermostCaller()->script();
+    }
+
+    jsbytecode *profilerLeavePc() const {
+        // If this is in a top-level function, use the pc directly.
+        if (trackedTree()->isOutermostCaller())
+            return trackedPc();
+
+        // Walk up the InlineScriptTree chain to find the top-most callPC
+        InlineScriptTree *curTree = trackedTree();
+        InlineScriptTree *callerTree = curTree->caller();
+        while (!callerTree->isOutermostCaller()) {
+            curTree = callerTree;
+            callerTree = curTree->caller();
+        }
+
+        // Return the callPc of the topmost inlined script.
+        return curTree->callerPc();
+    }
+
     // Return the range of this value, *before* any bailout checks. Contrast
     // this with the type() method, and the Range constructor which takes an
     // MDefinition*, which describe the value *after* any bailout checks.
     //
     // Warning: Range analysis is removing the bit-operations such as '| 0' at
     // the end of the transformations. Using this function to analyse any
     // operands after the truncate phase of the range analysis will lead to
     // errors. Instead, one should define the collectRangeInfoPreTrunc() to set