Bug 996983 - Part 2: JIT-related changes. (r=jandem)
authorShu-yu Guo <shu@rfrn.org>
Wed, 30 Apr 2014 21:12:17 -0700
changeset 181535 3de709d633552254112ce6b923dfb48b7b40ff99
parent 181534 b7b2591a326de45ebfb70f354c55833e10391ca8
child 181536 ed3ea6cb5afeb1ec05fa2dd9ba41aa1acd4e9fdc
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjandem
bugs996983
milestone32.0a1
Bug 996983 - Part 2: JIT-related changes. (r=jandem)
js/src/jit/IonFrames.cpp
js/src/jit/JitFrameIterator-inl.h
js/src/jit/JitFrameIterator.h
js/src/jit/RematerializedFrame.cpp
js/src/jit/RematerializedFrame.h
js/src/vm/Debugger.cpp
js/src/vm/ForkJoin.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -70,35 +70,35 @@ ReadFrameInt32Slot(IonJSFrameLayout *fp,
 }
 
 static inline bool
 ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
 {
     return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
 }
 
-JitFrameIterator::JitFrameIterator(JSContext *cx)
-  : current_(cx->mainThread().ionTop),
+JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx)
+  : current_(cx->perThreadData->ionTop),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     cachedSafepointIndex_(nullptr),
     activation_(nullptr),
-    mode_(SequentialExecution)
+    mode_(cx->isForkJoinContext() ? ParallelExecution : SequentialExecution)
 {
 }
 
 JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
     : current_(activations.jitTop()),
       type_(JitFrame_Exit),
       returnAddressToFp_(nullptr),
       frameSize_(0),
       cachedSafepointIndex_(nullptr),
       activation_(activations->asJit()),
-      mode_(SequentialExecution)
+      mode_(activation_->cx()->isForkJoinContext() ? ParallelExecution : SequentialExecution)
 {
 }
 
 JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
   : current_((uint8_t *)fp),
     type_(JitFrame_IonJS),
     returnAddressToFp_(fp->returnAddress()),
     frameSize_(fp->prevFrameLocalSize()),
--- a/js/src/jit/JitFrameIterator-inl.h
+++ b/js/src/jit/JitFrameIterator-inl.h
@@ -14,18 +14,18 @@
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 
 namespace js {
 namespace jit {
 
 template <AllowGC allowGC>
 inline
-InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(
-                                                JSContext *cx, const IonBailoutIterator *iter)
+InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(ThreadSafeContext *cx,
+                                                                const IonBailoutIterator *iter)
   : frame_(iter),
     framesRead_(0),
     frameCount_(UINT32_MAX),
     callee_(cx),
     script_(cx)
 {
     if (iter) {
         start_ = SnapshotIterator(*iter);
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -102,17 +102,17 @@ class JitFrameIterator
         type_(JitFrame_Exit),
         returnAddressToFp_(nullptr),
         frameSize_(0),
         cachedSafepointIndex_(nullptr),
         activation_(nullptr),
         mode_(mode)
     { }
 
-    explicit JitFrameIterator(JSContext *cx);
+    explicit JitFrameIterator(ThreadSafeContext *cx);
     explicit JitFrameIterator(const ActivationIterator &activations);
     explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
 
     // Current frame information.
     FrameType type() const {
         return type_;
     }
     uint8_t *fp() const {
@@ -487,33 +487,33 @@ class InlineFrameIteratorMaybeGC
 
         // Ion does not handle scripts that are not compile-and-go.
         MOZ_ASSERT(!script()->isForEval());
         MOZ_ASSERT(script()->compileAndGo());
         return &script()->global();
     }
 
   public:
-    InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter)
+    InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const JitFrameIterator *iter)
       : callee_(cx),
         script_(cx)
     {
         resetOn(iter);
     }
 
     InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter)
       : callee_(rt),
         script_(rt)
     {
         resetOn(iter);
     }
 
-    InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter);
+    InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const IonBailoutIterator *iter);
 
-    InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter)
+    InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const InlineFrameIteratorMaybeGC *iter)
       : frame_(iter ? iter->frame_ : nullptr),
         framesRead_(0),
         frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
         callee_(cx),
         script_(cx)
     {
         if (frame_) {
             start_ = SnapshotIterator(*frame_);
@@ -543,17 +543,17 @@ class InlineFrameIteratorMaybeGC
         // js_fun_call or js_fun_apply.
         if (more())
             return numActualArgs_;
 
         return frame_->numActualArgs();
     }
 
     template <class ArgOp, class LocalOp>
-    void readFrameArgsAndLocals(JSContext *cx, ArgOp &argOp, LocalOp &localOp,
+    void readFrameArgsAndLocals(ThreadSafeContext *cx, ArgOp &argOp, LocalOp &localOp,
                                 JSObject **scopeChain, Value *rval,
                                 ArgumentsObject **argsObj, Value *thisv,
                                 ReadFrameArgsBehavior behavior) const
     {
         SnapshotIterator s(si_);
 
         // Read frame slots common to both function and global frames.
         Value scopeChainValue;
@@ -612,17 +612,19 @@ class InlineFrameIteratorMaybeGC
 
         // At this point we've read all the formals in s, and can read the
         // locals.
         for (unsigned i = 0; i < script()->nfixed(); i++)
             localOp(s.read());
     }
 
     template <class Op>
-    void unaliasedForEachActual(JSContext *cx, Op op, ReadFrameArgsBehavior behavior) const {
+    void unaliasedForEachActual(ThreadSafeContext *cx, Op op,
+                                ReadFrameArgsBehavior behavior) const
+    {
         Nop nop;
         readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior);
     }
 
     JSScript *script() const {
         return script_;
     }
     jsbytecode *pc() const {
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -23,30 +23,31 @@ struct CopyValueToRematerializedFrame
       : slots(slots)
     { }
 
     void operator()(const Value &v) {
         *slots++ = v;
     }
 };
 
-RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, InlineFrameIterator &iter)
+RematerializedFrame::RematerializedFrame(ThreadSafeContext *cx, uint8_t *top,
+                                         InlineFrameIterator &iter)
   : prevUpToDate_(false),
     top_(top),
     frameNo_(iter.frameNo()),
     numActualArgs_(iter.numActualArgs()),
     script_(iter.script())
 {
     CopyValueToRematerializedFrame op(slots_);
     iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &returnValue_,
                                 &argsObj_, &thisValue_, ReadFrame_Actuals);
 }
 
 /* static */ RematerializedFrame *
-RematerializedFrame::New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter)
+RematerializedFrame::New(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter)
 {
     unsigned numFormals = iter.isFunctionFrame() ? iter.callee()->nargs() : 0;
     size_t numBytes = sizeof(RematerializedFrame) +
         (Max(numFormals, iter.numActualArgs()) +
          iter.script()->nfixed()) * sizeof(Value) -
         sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
 
     void *buf = cx->calloc_(numBytes);
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -36,20 +36,21 @@ class RematerializedFrame
     JSScript *script_;
     JSObject *scopeChain_;
     ArgumentsObject *argsObj_;
 
     Value returnValue_;
     Value thisValue_;
     Value slots_[1];
 
-    RematerializedFrame(JSContext *cx, uint8_t *top, InlineFrameIterator &iter);
+    RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter);
 
   public:
-    static RematerializedFrame *New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter);
+    static RematerializedFrame *New(ThreadSafeContext *cx, uint8_t *top,
+                                    InlineFrameIterator &iter);
 
     bool prevUpToDate() const {
         return prevUpToDate_;
     }
     void setPrevUpToDate() {
         prevUpToDate_ = true;
     }
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2108,17 +2108,17 @@ Debugger::getNewestFrame(JSContext *cx, 
 {
     THIS_DEBUGGER(cx, argc, vp, "getNewestFrame", args, dbg);
 
     /* Since there may be multiple contexts, use AllFramesIter. */
     for (AllFramesIter i(cx); !i.done(); ++i) {
         if (dbg->observesFrame(i)) {
             // Ensure that Ion frames are rematerialized. Only rematerialized
             // Ion frames may be used as AbstractFramePtrs.
-            if (i.isIon() && !i.ensureHasRematerializedFrame())
+            if (i.isIon() && !i.ensureHasRematerializedFrame(cx))
                 return false;
             AbstractFramePtr frame = i.abstractFramePtr();
             ScriptFrameIter iter(i.activation()->cx(), ScriptFrameIter::GO_THROUGH_SAVED);
             while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != frame)
                 ++iter;
             return dbg->getScriptFrame(cx, iter, args.rval());
         }
     }
@@ -4113,17 +4113,17 @@ UpdateFrameIterPc(FrameIter &iter)
         // because when returning to debuggee code, we would have bailed out
         // to baseline.
         //
         // We walk the stack to assert that it doesn't need updating.
         jit::RematerializedFrame *frame = iter.abstractFramePtr().asRematerializedFrame();
         jit::IonJSFrameLayout *jsFrame = (jit::IonJSFrameLayout *)frame->top();
         jit::JitActivation *activation = iter.activation()->asJit();
 
-        ActivationIterator activationIter(activation->cx()->runtime());
+        ActivationIterator activationIter(activation->cx()->perThreadData);
         while (activationIter.activation() != activation)
             ++activationIter;
 
         jit::JitFrameIterator jitIter(activationIter);
         while (!jitIter.isIonJS() || jitIter.jsFrame() != jsFrame)
             ++jitIter;
 
         jit::InlineFrameIterator ionInlineIter(activation->cx(), &jitIter);
@@ -4365,17 +4365,17 @@ DebuggerFrame_getThis(JSContext *cx, uns
 static bool
 DebuggerFrame_getOlder(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_FRAME_ITER(cx, argc, vp, "get this", args, thisobj, _, iter);
     Debugger *dbg = Debugger::fromChildJSObject(thisobj);
 
     for (++iter; !iter.done(); ++iter) {
         if (dbg->observesFrame(iter)) {
-            if (iter.isIon() && !iter.ensureHasRematerializedFrame())
+            if (iter.isIon() && !iter.ensureHasRematerializedFrame(cx))
                 return false;
             return dbg->getScriptFrame(cx, iter, args.rval());
         }
     }
     args.rval().setNull();
     return true;
 }
 
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -482,17 +482,17 @@ ForkJoinActivation::ForkJoinActivation(J
     cx->runtime()->gcHelperThread.waitBackgroundSweepEnd();
 
     JS_ASSERT(!cx->runtime()->needsBarrier());
     JS_ASSERT(!cx->zone()->needsBarrier());
 }
 
 ForkJoinActivation::~ForkJoinActivation()
 {
-    cx_->mainThread().ionTop = prevIonTop_;
+    cx_->perThreadData->ionTop = prevIonTop_;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // js::ForkJoin() and ForkJoinOperation class
 //
 // These are the top-level objects that manage the parallel execution.
 // They handle parallel compilation (if necessary), triggering
 // parallel execution, and recovering from bailouts.
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -670,17 +670,17 @@ FrameIter::FrameIter(ThreadSafeContext *
 {
     settleOnActivation();
 }
 
 FrameIter::FrameIter(ThreadSafeContext *cx, ContextOption contextOption,
                      SavedOption savedOption)
   : data_(cx, savedOption, contextOption, nullptr)
 #ifdef JS_ION
-  , ionInlineFrames_(cx, (js::jit::IonFrameIterator*) nullptr)
+  , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 #endif
 {
     settleOnActivation();
 }
 
 FrameIter::FrameIter(JSContext *cx, ContextOption contextOption,
                      SavedOption savedOption, JSPrincipals *principals)
   : data_(cx, savedOption, contextOption, principals)
@@ -1076,21 +1076,21 @@ FrameIter::isConstructing() const
 #endif
       case INTERP:
         return interpFrame()->isConstructing();
     }
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
 
 bool
-FrameIter::ensureHasRematerializedFrame()
+FrameIter::ensureHasRematerializedFrame(ThreadSafeContext *cx)
 {
 #ifdef JS_ION
     MOZ_ASSERT(isIon());
-    return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_);
+    return !!activation()->asJit()->getRematerializedFrame(cx, data_.jitFrames_);
 #else
     return true;
 #endif
 }
 
 bool
 FrameIter::hasUsableAbstractFramePtr() const
 {
@@ -1520,38 +1520,39 @@ js::CheckLocalUnaliased(MaybeCheckAliasi
 }
 #endif
 
 jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active)
   : Activation(cx, Jit),
     firstFrameIsConstructing_(firstFrameIsConstructing),
     active_(active)
 #ifdef JS_ION
-  , rematerializedFrames_(cx)
+  , rematerializedFrames_(nullptr)
 #endif
 {
     if (active) {
         prevIonTop_ = cx->mainThread().ionTop;
         prevJitJSContext_ = cx->mainThread().jitJSContext;
         cx->mainThread().jitJSContext = cx;
     } else {
         prevIonTop_ = nullptr;
         prevJitJSContext_ = nullptr;
     }
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
-        cx_->mainThread().ionTop = prevIonTop_;
-        cx_->mainThread().jitJSContext = prevJitJSContext_;
+        cx_->perThreadData->ionTop = prevIonTop_;
+        cx_->perThreadData->jitJSContext = prevJitJSContext_;
     }
 
 #ifdef JS_ION
     clearRematerializedFrames();
+    js_delete(rematerializedFrames_);
 #endif
 }
 
 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
 // and disable activation instruction sequences.
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
@@ -1583,58 +1584,65 @@ jit::JitActivation::freeRematerializedFr
         js_free(f);
     }
     frames.clear();
 }
 
 void
 jit::JitActivation::removeRematerializedFrame(uint8_t *top)
 {
-    if (!rematerializedFrames_.initialized())
+    if (!rematerializedFrames_)
         return;
 
-    if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) {
+    if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
         freeRematerializedFramesInVector(p->value());
-        rematerializedFrames_.remove(p);
+        rematerializedFrames_->remove(p);
     }
 }
 
 void
 jit::JitActivation::clearRematerializedFrames()
 {
-    if (!rematerializedFrames_.initialized())
+    if (!rematerializedFrames_)
         return;
 
-    for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
+    for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
         freeRematerializedFramesInVector(e.front().value());
         e.removeFront();
     }
 }
 
 jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter,
+jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, JitFrameIterator &iter,
                                            size_t inlineDepth)
 {
+    // Only allow rematerializing from the same thread.
+    MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
     MOZ_ASSERT(iter.activation() == this);
     MOZ_ASSERT(iter.isIonJS());
 
-    if (!rematerializedFrames_.initialized() && !rematerializedFrames_.init())
-        return nullptr;
+    if (!rematerializedFrames_) {
+        rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
+        if (!rematerializedFrames_ || !rematerializedFrames_->init()) {
+            rematerializedFrames_ = nullptr;
+            return nullptr;
+        }
+    }
 
     // The unit of rematerialization is an uninlined frame and its inlined
     // frames. Since inlined frames do not exist outside of snapshots, it is
     // impossible to synchronize their rematerialized copies to preserve
     // identity. Therefore, we always rematerialize an uninlined frame and all
     // its inlined frames at once.
 
     uint8_t *top = iter.fp();
-    RematerializedFrameTable::AddPtr p = rematerializedFrames_.lookupForAdd(top);
+    RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
     if (!p) {
         RematerializedFrameVector empty(cx);
-        if (!rematerializedFrames_.add(p, top, Move(empty)))
+        if (!rematerializedFrames_->add(p, top, Move(empty)))
             return nullptr;
 
         InlineFrameIterator inlineIter(cx, &iter);
         if (!p->value().resize(inlineIter.frameCount()))
             return nullptr;
 
         while (true) {
             size_t frameNo = inlineIter.frameNo();
@@ -1649,29 +1657,29 @@ jit::JitActivation::getRematerializedFra
     }
 
     return p->value()[inlineDepth];
 }
 
 jit::RematerializedFrame *
 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
 {
-    if (!rematerializedFrames_.initialized())
+    if (!rematerializedFrames_)
         return nullptr;
-    if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top))
+    if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
     return nullptr;
 }
 
 void
 jit::JitActivation::markRematerializedFrames(JSTracer *trc)
 {
-    if (!rematerializedFrames_.initialized())
+    if (!rematerializedFrames_)
         return;
-    for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
+    for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
         RematerializedFrameVector &frames = e.front().value();
         for (size_t i = 0; i < frames.length(); i++)
             frames[i]->mark(trc);
     }
 }
 
 #endif // JS_ION
 
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1167,18 +1167,16 @@ class Activation
     }
     JSCompartment *compartment() const {
         return compartment_;
     }
     Activation *prev() const {
         return prev_;
     }
 
-    inline JSCompartment *compartment() const;
-
     bool isInterpreter() const {
         return kind_ == Interpreter;
     }
     bool isJit() const {
         return kind_ == Jit;
     }
     bool isForkJoin() const {
         return kind_ == ForkJoin;
@@ -1337,17 +1335,17 @@ class JitActivation : public Activation
 #ifdef JS_ION
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
     // frame pointers (i.e. ionTop) to a vector of rematerializations of all
     // inline frames associated with that frame.
     //
     // This table is lazily initialized by calling getRematerializedFrame.
     typedef Vector<RematerializedFrame *, 1> RematerializedFrameVector;
     typedef HashMap<uint8_t *, RematerializedFrameVector> RematerializedFrameTable;
-    RematerializedFrameTable rematerializedFrames_;
+    RematerializedFrameTable *rematerializedFrames_;
 
     void freeRematerializedFramesInVector(RematerializedFrameVector &frames);
     void clearRematerializedFrames();
 #endif
 
 #ifdef CHECK_OSIPOINT_REGISTERS
   protected:
     // Used to verify that live registers don't change between a VM call and
@@ -1396,17 +1394,17 @@ class JitActivation : public Activation
 
 #ifdef JS_ION
     // Look up a rematerialized frame keyed by the fp, rematerializing the
     // frame if one doesn't already exist. A frame can only be rematerialized
     // if an IonFrameIterator pointing to the nearest uninlined frame can be
     // provided, as values need to be read out of snapshots.
     //
     // The inlineDepth must be within bounds of the frame pointed to by iter.
-    RematerializedFrame *getRematerializedFrame(JSContext *cx, JitFrameIterator &iter,
+    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, JitFrameIterator &iter,
                                                 size_t inlineDepth = 0);
 
     // Look up a rematerialized frame by the fp. If inlineDepth is out of
     // bounds of what has been rematerialized, nullptr is returned.
     RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
 
     bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
         return !!lookupRematerializedFrame(top, inlineDepth);
@@ -1429,16 +1427,22 @@ class JitActivationIterator : public Act
 
   public:
     explicit JitActivationIterator(JSRuntime *rt)
       : ActivationIterator(rt)
     {
         settle();
     }
 
+    explicit JitActivationIterator(PerThreadData *perThreadData)
+      : ActivationIterator(perThreadData)
+    {
+        settle();
+    }
+
     JitActivationIterator &operator++() {
         ActivationIterator::operator++();
         settle();
         return *this;
     }
 
     // Returns the bottom and top addresses of the current JitActivation.
     void jitStackRange(uintptr_t *&min, uintptr_t *&end);
@@ -1675,17 +1679,17 @@ class FrameIter
     }
 
     // These are only valid for the top frame.
     size_t      numFrameSlots() const;
     Value       frameSlotValue(size_t index) const;
 
     // Ensures that we have rematerialized the top frame and its associated
     // inline frames. Can only be called when isIon().
-    bool ensureHasRematerializedFrame();
+    bool ensureHasRematerializedFrame(ThreadSafeContext *cx);
 
     // True when isInterp() or isBaseline(). True when isIon() if it
     // has a rematerialized frame. False otherwise false otherwise.
     bool hasUsableAbstractFramePtr() const;
 
     // -----------------------------------------------------------
     // The following functions can only be called when isInterp(),
     // isBaseline(), or isIon(). Further, abstractFramePtr() can