michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_JitFrameIterator_h michael@0: #define jit_JitFrameIterator_h michael@0: michael@0: #ifdef JS_ION michael@0: michael@0: #include "jsfun.h" michael@0: #include "jsscript.h" michael@0: #include "jstypes.h" michael@0: michael@0: #include "jit/IonCode.h" michael@0: #include "jit/Snapshots.h" michael@0: michael@0: namespace js { michael@0: class ActivationIterator; michael@0: }; michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: enum FrameType michael@0: { michael@0: // A JS frame is analagous to a js::InterpreterFrame, representing one scripted michael@0: // functon activation. IonJS frames are used by the optimizing compiler. michael@0: JitFrame_IonJS, michael@0: michael@0: // JS frame used by the baseline JIT. michael@0: JitFrame_BaselineJS, michael@0: michael@0: // Frame pushed for baseline JIT stubs that make non-tail calls, so that the michael@0: // return address -> ICEntry mapping works. michael@0: JitFrame_BaselineStub, michael@0: michael@0: // The entry frame is the initial prologue block transitioning from the VM michael@0: // into the Ion world. michael@0: JitFrame_Entry, michael@0: michael@0: // A rectifier frame sits in between two JS frames, adapting argc != nargs michael@0: // mismatches in calls. michael@0: JitFrame_Rectifier, michael@0: michael@0: // An unwound JS frame is a JS frame signalling that its callee frame has been michael@0: // turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and michael@0: // Baseline exception unwinding. michael@0: JitFrame_Unwound_IonJS, michael@0: michael@0: // Like Unwound_IonJS, but the caller is a baseline stub frame. michael@0: JitFrame_Unwound_BaselineStub, michael@0: michael@0: // An unwound rectifier frame is a rectifier frame signalling that its callee michael@0: // frame has been turned into an exit frame (see EnsureExitFrame). michael@0: JitFrame_Unwound_Rectifier, michael@0: michael@0: // An exit frame is necessary for transitioning from a JS frame into C++. michael@0: // From within C++, an exit frame is always the last frame in any michael@0: // JitActivation. michael@0: JitFrame_Exit michael@0: }; michael@0: michael@0: enum ReadFrameArgsBehavior { michael@0: // Only read formals (i.e. [0 ... callee()->nargs] michael@0: ReadFrame_Formals, michael@0: michael@0: // Only read overflown args (i.e. [callee()->nargs ... numActuals()] michael@0: ReadFrame_Overflown, michael@0: michael@0: // Read all args (i.e. [0 ... numActuals()]) michael@0: ReadFrame_Actuals michael@0: }; michael@0: michael@0: class IonCommonFrameLayout; michael@0: class IonJSFrameLayout; michael@0: class IonExitFrameLayout; michael@0: michael@0: class BaselineFrame; michael@0: michael@0: class JitActivation; michael@0: michael@0: class JitFrameIterator michael@0: { michael@0: protected: michael@0: uint8_t *current_; michael@0: FrameType type_; michael@0: uint8_t *returnAddressToFp_; michael@0: size_t frameSize_; michael@0: michael@0: private: michael@0: mutable const SafepointIndex *cachedSafepointIndex_; michael@0: const JitActivation *activation_; michael@0: ExecutionMode mode_; michael@0: michael@0: void dumpBaseline() const; michael@0: michael@0: public: michael@0: explicit JitFrameIterator(uint8_t *top, ExecutionMode mode) michael@0: : current_(top), michael@0: type_(JitFrame_Exit), michael@0: returnAddressToFp_(nullptr), michael@0: frameSize_(0), michael@0: cachedSafepointIndex_(nullptr), michael@0: activation_(nullptr), michael@0: mode_(mode) michael@0: { } michael@0: michael@0: explicit JitFrameIterator(JSContext *cx); michael@0: explicit JitFrameIterator(const ActivationIterator &activations); michael@0: explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode); michael@0: michael@0: // Current frame information. michael@0: FrameType type() const { michael@0: return type_; michael@0: } michael@0: uint8_t *fp() const { michael@0: return current_; michael@0: } michael@0: const JitActivation *activation() const { michael@0: return activation_; michael@0: } michael@0: michael@0: IonCommonFrameLayout *current() const { michael@0: return (IonCommonFrameLayout *)current_; michael@0: } michael@0: michael@0: inline uint8_t *returnAddress() const; michael@0: michael@0: IonJSFrameLayout *jsFrame() const { michael@0: JS_ASSERT(isScripted()); michael@0: return (IonJSFrameLayout *) fp(); michael@0: } michael@0: michael@0: // Returns true iff this exit frame was created using EnsureExitFrame. michael@0: inline bool isFakeExitFrame() const; michael@0: michael@0: inline IonExitFrameLayout *exitFrame() const; michael@0: michael@0: // Returns whether the JS frame has been invalidated and, if so, michael@0: // places the invalidated Ion script in |ionScript|. michael@0: bool checkInvalidation(IonScript **ionScript) const; michael@0: bool checkInvalidation() const; michael@0: michael@0: bool isScripted() const { michael@0: return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS; michael@0: } michael@0: bool isBaselineJS() const { michael@0: return type_ == JitFrame_BaselineJS; michael@0: } michael@0: bool isIonJS() const { michael@0: return type_ == JitFrame_IonJS; michael@0: } michael@0: bool isBaselineStub() const { michael@0: return type_ == JitFrame_BaselineStub; michael@0: } michael@0: bool isNative() const; michael@0: bool isOOLNative() const; michael@0: bool isOOLPropertyOp() const; michael@0: bool isOOLProxy() const; michael@0: bool isDOMExit() const; michael@0: bool isEntry() const { michael@0: return type_ == JitFrame_Entry; michael@0: } michael@0: bool isFunctionFrame() const; michael@0: michael@0: bool isConstructing() const; michael@0: michael@0: void *calleeToken() const; michael@0: JSFunction *callee() const; michael@0: JSFunction *maybeCallee() const; michael@0: unsigned numActualArgs() const; michael@0: JSScript *script() const; michael@0: void baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const; michael@0: Value *actualArgs() const; michael@0: michael@0: // Returns the return address of the frame above this one (that is, the michael@0: // return address that returns back to the current frame). michael@0: uint8_t *returnAddressToFp() const { michael@0: return returnAddressToFp_; michael@0: } michael@0: michael@0: // Previous frame information extracted from the current frame. michael@0: inline size_t prevFrameLocalSize() const; michael@0: inline FrameType prevType() const; michael@0: uint8_t *prevFp() const; michael@0: michael@0: // Returns the stack space used by the current frame, in bytes. This does michael@0: // not include the size of its fixed header. michael@0: size_t frameSize() const { michael@0: JS_ASSERT(type_ != JitFrame_Exit); michael@0: return frameSize_; michael@0: } michael@0: michael@0: // Functions used to iterate on frames. When prevType is JitFrame_Entry, michael@0: // the current frame is the last frame. michael@0: inline bool done() const { michael@0: return type_ == JitFrame_Entry; michael@0: } michael@0: JitFrameIterator &operator++(); michael@0: michael@0: // Returns the IonScript associated with this JS frame. michael@0: IonScript *ionScript() const; michael@0: michael@0: // Returns the Safepoint associated with this JS frame. Incurs a lookup michael@0: // overhead. michael@0: const SafepointIndex *safepoint() const; michael@0: michael@0: // Returns the OSI index associated with this JS frame. Incurs a lookup michael@0: // overhead. michael@0: const OsiIndex *osiIndex() const; michael@0: michael@0: uintptr_t *spillBase() const; michael@0: MachineState machineState() const; michael@0: michael@0: template michael@0: void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const { michael@0: JS_ASSERT(isBaselineJS()); michael@0: michael@0: unsigned nactual = numActualArgs(); michael@0: unsigned start, end; michael@0: switch (behavior) { michael@0: case ReadFrame_Formals: michael@0: start = 0; michael@0: end = callee()->nargs(); michael@0: break; michael@0: case ReadFrame_Overflown: michael@0: start = callee()->nargs(); michael@0: end = nactual; michael@0: break; michael@0: case ReadFrame_Actuals: michael@0: start = 0; michael@0: end = nactual; michael@0: } michael@0: michael@0: Value *argv = actualArgs(); michael@0: for (unsigned i = start; i < end; i++) michael@0: op(argv[i]); michael@0: } michael@0: michael@0: void dump() const; michael@0: michael@0: inline BaselineFrame *baselineFrame() const; michael@0: }; michael@0: michael@0: class IonJSFrameLayout; michael@0: class IonBailoutIterator; michael@0: michael@0: class RResumePoint; michael@0: michael@0: // Reads frame information in snapshot-encoding order (that is, outermost frame michael@0: // to innermost frame). michael@0: class SnapshotIterator michael@0: { michael@0: SnapshotReader snapshot_; michael@0: RecoverReader recover_; michael@0: IonJSFrameLayout *fp_; michael@0: MachineState machine_; michael@0: IonScript *ionScript_; michael@0: michael@0: private: michael@0: // Read a spilled register from the machine state. michael@0: bool hasRegister(Register reg) const { michael@0: return machine_.has(reg); michael@0: } michael@0: uintptr_t fromRegister(Register reg) const { michael@0: return machine_.read(reg); michael@0: } michael@0: michael@0: bool hasRegister(FloatRegister reg) const { michael@0: return machine_.has(reg); michael@0: } michael@0: double fromRegister(FloatRegister reg) const { michael@0: return machine_.read(reg); michael@0: } michael@0: michael@0: // Read an uintptr_t from the stack. michael@0: bool hasStack(int32_t offset) const { michael@0: return true; michael@0: } michael@0: uintptr_t fromStack(int32_t offset) const; michael@0: michael@0: Value allocationValue(const RValueAllocation &a); michael@0: bool allocationReadable(const RValueAllocation &a); michael@0: void warnUnreadableAllocation(); michael@0: michael@0: public: michael@0: // Handle iterating over RValueAllocations of the snapshots. michael@0: inline RValueAllocation readAllocation() { michael@0: MOZ_ASSERT(moreAllocations()); michael@0: return snapshot_.readAllocation(); michael@0: } michael@0: Value skip() { michael@0: snapshot_.skipAllocation(); michael@0: return UndefinedValue(); michael@0: } michael@0: michael@0: const RResumePoint *resumePoint() const; michael@0: const RInstruction *instruction() const { michael@0: return recover_.instruction(); michael@0: } michael@0: michael@0: uint32_t numAllocations() const; michael@0: inline bool moreAllocations() const { michael@0: return snapshot_.numAllocationsRead() < numAllocations(); michael@0: } michael@0: michael@0: public: michael@0: // Exhibits frame properties contained in the snapshot. michael@0: uint32_t pcOffset() const; michael@0: inline bool resumeAfter() const { michael@0: // Inline frames are inlined on calls, which are considered as being michael@0: // resumed on the Call as baseline will push the pc once we return from michael@0: // the call. michael@0: if (moreFrames()) michael@0: return false; michael@0: return recover_.resumeAfter(); michael@0: } michael@0: inline BailoutKind bailoutKind() const { michael@0: return snapshot_.bailoutKind(); michael@0: } michael@0: michael@0: public: michael@0: // Read the next instruction available and get ready to either skip it or michael@0: // evaluate it. michael@0: inline void nextInstruction() { michael@0: MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations()); michael@0: recover_.nextInstruction(); michael@0: snapshot_.resetNumAllocationsRead(); michael@0: } michael@0: michael@0: // Skip an Instruction by walking to the next instruction and by skipping michael@0: // all the allocations corresponding to this instruction. michael@0: void skipInstruction(); michael@0: michael@0: inline bool moreInstructions() const { michael@0: return recover_.moreInstructions(); michael@0: } michael@0: michael@0: public: michael@0: // Handle iterating over frames of the snapshots. michael@0: void nextFrame(); michael@0: michael@0: inline bool moreFrames() const { michael@0: // The last instruction is recovering the innermost frame, so as long as michael@0: // there is more instruction there is necesseray more frames. michael@0: return moreInstructions(); michael@0: } michael@0: michael@0: public: michael@0: // Connect all informations about the current script in order to recover the michael@0: // content of baseline frames. michael@0: michael@0: SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset, michael@0: IonJSFrameLayout *fp, const MachineState &machine); michael@0: SnapshotIterator(const JitFrameIterator &iter); michael@0: SnapshotIterator(const IonBailoutIterator &iter); michael@0: SnapshotIterator(); michael@0: michael@0: Value read() { michael@0: return allocationValue(readAllocation()); michael@0: } michael@0: Value maybeRead(bool silentFailure = false) { michael@0: RValueAllocation a = readAllocation(); michael@0: if (allocationReadable(a)) michael@0: return allocationValue(a); michael@0: if (!silentFailure) michael@0: warnUnreadableAllocation(); michael@0: return UndefinedValue(); michael@0: } michael@0: michael@0: void readCommonFrameSlots(Value *scopeChain, Value *rval) { michael@0: if (scopeChain) michael@0: *scopeChain = read(); michael@0: else michael@0: skip(); michael@0: michael@0: if (rval) michael@0: *rval = read(); michael@0: else michael@0: skip(); michael@0: } michael@0: michael@0: template michael@0: void readFunctionFrameArgs(Op &op, ArgumentsObject **argsObj, Value *thisv, michael@0: unsigned start, unsigned end, JSScript *script) michael@0: { michael@0: // Assumes that the common frame arguments have already been read. michael@0: if (script->argumentsHasVarBinding()) { michael@0: if (argsObj) { michael@0: Value v = read(); michael@0: if (v.isObject()) michael@0: *argsObj = &v.toObject().as(); michael@0: } else { michael@0: skip(); michael@0: } michael@0: } michael@0: michael@0: if (thisv) michael@0: *thisv = read(); michael@0: else michael@0: skip(); michael@0: michael@0: unsigned i = 0; michael@0: if (end < start) michael@0: i = start; michael@0: michael@0: for (; i < start; i++) michael@0: skip(); michael@0: for (; i < end; i++) { michael@0: // We are not always able to read values from the snapshots, some values michael@0: // such as non-gc things may still be live in registers and cause an michael@0: // error while reading the machine state. michael@0: Value v = maybeRead(); michael@0: op(v); michael@0: } michael@0: } michael@0: michael@0: Value maybeReadAllocByIndex(size_t index) { michael@0: while (index--) { michael@0: JS_ASSERT(moreAllocations()); michael@0: skip(); michael@0: } michael@0: michael@0: Value s = maybeRead(true); michael@0: michael@0: while (moreAllocations()) michael@0: skip(); michael@0: michael@0: return s; michael@0: } michael@0: }; michael@0: michael@0: // Reads frame information in callstack order (that is, innermost frame to michael@0: // outermost frame). michael@0: template michael@0: class InlineFrameIteratorMaybeGC michael@0: { michael@0: const JitFrameIterator *frame_; michael@0: SnapshotIterator start_; michael@0: SnapshotIterator si_; michael@0: uint32_t framesRead_; michael@0: michael@0: // When the inline-frame-iterator is created, this variable is defined to michael@0: // UINT32_MAX. Then the first iteration of findNextFrame, which settle on michael@0: // the innermost frame, is used to update this counter to the number of michael@0: // frames contained in the recover buffer. michael@0: uint32_t frameCount_; michael@0: michael@0: typename MaybeRooted::RootType callee_; michael@0: typename MaybeRooted::RootType script_; michael@0: jsbytecode *pc_; michael@0: uint32_t numActualArgs_; michael@0: michael@0: struct Nop { michael@0: void operator()(const Value &v) { } michael@0: }; michael@0: michael@0: private: michael@0: void findNextFrame(); michael@0: michael@0: JSObject *computeScopeChain(Value scopeChainValue) const { michael@0: if (scopeChainValue.isObject()) michael@0: return &scopeChainValue.toObject(); michael@0: michael@0: if (isFunctionFrame()) { michael@0: // Heavyweight functions should always have a scope chain. michael@0: MOZ_ASSERT(!callee()->isHeavyweight()); michael@0: return callee()->environment(); michael@0: } michael@0: michael@0: // Ion does not handle scripts that are not compile-and-go. michael@0: MOZ_ASSERT(!script()->isForEval()); michael@0: MOZ_ASSERT(script()->compileAndGo()); michael@0: return &script()->global(); michael@0: } michael@0: michael@0: public: michael@0: InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter) michael@0: : callee_(cx), michael@0: script_(cx) michael@0: { michael@0: resetOn(iter); michael@0: } michael@0: michael@0: InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter) michael@0: : callee_(rt), michael@0: script_(rt) michael@0: { michael@0: resetOn(iter); michael@0: } michael@0: michael@0: InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter); michael@0: michael@0: InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter) michael@0: : frame_(iter ? iter->frame_ : nullptr), michael@0: framesRead_(0), michael@0: frameCount_(iter ? iter->frameCount_ : UINT32_MAX), michael@0: callee_(cx), michael@0: script_(cx) michael@0: { michael@0: if (frame_) { michael@0: start_ = SnapshotIterator(*frame_); michael@0: // findNextFrame will iterate to the next frame and init. everything. michael@0: // Therefore to settle on the same frame, we report one frame less readed. michael@0: framesRead_ = iter->framesRead_ - 1; michael@0: findNextFrame(); michael@0: } michael@0: } michael@0: michael@0: bool more() const { michael@0: return frame_ && framesRead_ < frameCount_; michael@0: } michael@0: JSFunction *callee() const { michael@0: JS_ASSERT(callee_); michael@0: return callee_; michael@0: } michael@0: JSFunction *maybeCallee() const { michael@0: return callee_; michael@0: } michael@0: michael@0: unsigned numActualArgs() const { michael@0: // The number of actual arguments of inline frames is recovered by the michael@0: // iteration process. It is recovered from the bytecode because this michael@0: // property still hold since the for inlined frames. This property does not michael@0: // hold for the parent frame because it can have optimize a call to michael@0: // js_fun_call or js_fun_apply. michael@0: if (more()) michael@0: return numActualArgs_; michael@0: michael@0: return frame_->numActualArgs(); michael@0: } michael@0: michael@0: template michael@0: void readFrameArgsAndLocals(JSContext *cx, ArgOp &argOp, LocalOp &localOp, michael@0: JSObject **scopeChain, Value *rval, michael@0: ArgumentsObject **argsObj, Value *thisv, michael@0: ReadFrameArgsBehavior behavior) const michael@0: { michael@0: SnapshotIterator s(si_); michael@0: michael@0: // Read frame slots common to both function and global frames. michael@0: Value scopeChainValue; michael@0: s.readCommonFrameSlots(&scopeChainValue, rval); michael@0: michael@0: if (scopeChain) michael@0: *scopeChain = computeScopeChain(scopeChainValue); michael@0: michael@0: // Read arguments, which only function frames have. michael@0: if (isFunctionFrame()) { michael@0: unsigned nactual = numActualArgs(); michael@0: unsigned nformal = callee()->nargs(); michael@0: michael@0: // Get the non overflown arguments, which are taken from the inlined michael@0: // frame, because it will have the updated value when JSOP_SETARG is michael@0: // done. michael@0: if (behavior != ReadFrame_Overflown) michael@0: s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, nformal, script()); michael@0: michael@0: if (behavior != ReadFrame_Formals) { michael@0: if (more()) { michael@0: // There is still a parent frame of this inlined frame. All michael@0: // arguments (also the overflown) are the last pushed values michael@0: // in the parent frame. To get the overflown arguments, we michael@0: // need to take them from there. michael@0: michael@0: // The overflown arguments are not available in current frame. michael@0: // They are the last pushed arguments in the parent frame of michael@0: // this inlined frame. michael@0: InlineFrameIteratorMaybeGC it(cx, this); michael@0: ++it; michael@0: unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0; michael@0: SnapshotIterator parent_s(it.snapshotIterator()); michael@0: michael@0: // Skip over all slots until we get to the last slots michael@0: // (= arguments slots of callee) the +3 is for [this], [returnvalue], michael@0: // [scopechain], and maybe +1 for [argsObj] michael@0: JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj); michael@0: unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj; michael@0: for (unsigned j = 0; j < skip; j++) michael@0: parent_s.skip(); michael@0: michael@0: // Get the overflown arguments michael@0: parent_s.readCommonFrameSlots(nullptr, nullptr); michael@0: parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr, michael@0: nformal, nactual, it.script()); michael@0: } else { michael@0: // There is no parent frame to this inlined frame, we can read michael@0: // from the frame's Value vector directly. michael@0: Value *argv = frame_->actualArgs(); michael@0: for (unsigned i = nformal; i < nactual; i++) michael@0: argOp(argv[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // At this point we've read all the formals in s, and can read the michael@0: // locals. michael@0: for (unsigned i = 0; i < script()->nfixed(); i++) michael@0: localOp(s.read()); michael@0: } michael@0: michael@0: template michael@0: void unaliasedForEachActual(JSContext *cx, Op op, ReadFrameArgsBehavior behavior) const { michael@0: Nop nop; michael@0: readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior); michael@0: } michael@0: michael@0: JSScript *script() const { michael@0: return script_; michael@0: } michael@0: jsbytecode *pc() const { michael@0: return pc_; michael@0: } michael@0: SnapshotIterator snapshotIterator() const { michael@0: return si_; michael@0: } michael@0: bool isFunctionFrame() const; michael@0: bool isConstructing() const; michael@0: michael@0: JSObject *scopeChain() const { michael@0: SnapshotIterator s(si_); michael@0: michael@0: // scopeChain michael@0: Value v = s.read(); michael@0: return computeScopeChain(v); michael@0: } michael@0: michael@0: JSObject *thisObject() const { michael@0: // In strict modes, |this| may not be an object and thus may not be michael@0: // readable which can either segv in read or trigger the assertion. michael@0: Value v = thisValue(); michael@0: JS_ASSERT(v.isObject()); michael@0: return &v.toObject(); michael@0: } michael@0: michael@0: Value thisValue() const { michael@0: // JS_ASSERT(isConstructing(...)); michael@0: SnapshotIterator s(si_); michael@0: michael@0: // scopeChain michael@0: s.skip(); michael@0: michael@0: // return value michael@0: s.skip(); michael@0: michael@0: // Arguments object. michael@0: if (script()->argumentsHasVarBinding()) michael@0: s.skip(); michael@0: michael@0: return s.read(); michael@0: } michael@0: michael@0: InlineFrameIteratorMaybeGC &operator++() { michael@0: findNextFrame(); michael@0: return *this; michael@0: } michael@0: michael@0: void dump() const; michael@0: michael@0: void resetOn(const JitFrameIterator *iter); michael@0: michael@0: const JitFrameIterator &frame() const { michael@0: return *frame_; michael@0: } michael@0: michael@0: // Inline frame number, 0 for the outermost (non-inlined) frame. michael@0: size_t frameNo() const { michael@0: return frameCount() - framesRead_; michael@0: } michael@0: size_t frameCount() const { michael@0: MOZ_ASSERT(frameCount_ != UINT32_MAX); michael@0: return frameCount_; michael@0: } michael@0: michael@0: private: michael@0: InlineFrameIteratorMaybeGC() MOZ_DELETE; michael@0: InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE; michael@0: }; michael@0: typedef InlineFrameIteratorMaybeGC InlineFrameIterator; michael@0: typedef InlineFrameIteratorMaybeGC InlineFrameIteratorNoGC; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif // JS_ION michael@0: michael@0: #endif /* jit_JitFrameIterator_h */