Bug 903754 - Remove InterpreterFrames class and use InterpreterActivation instead. r=luke

This commit is contained in:
Jan de Mooij 2013-08-13 14:06:30 +02:00
parent 71bd813c02
commit d9611e136b
8 changed files with 50 additions and 114 deletions

View File

@ -267,8 +267,12 @@ JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
{ {
rt->debugHooks.interruptHook = hook; rt->debugHooks.interruptHook = hook;
rt->debugHooks.interruptHookData = closure; rt->debugHooks.interruptHookData = closure;
for (InterpreterFrames *f = rt->interpreterFrames; f; f = f->older)
f->enableInterruptsUnconditionally(); for (ActivationIterator iter(rt); !iter.done(); ++iter) {
if (iter.activation()->isInterpreter())
iter.activation()->asInterpreter()->enableInterruptsUnconditionally();
}
return true; return true;
} }

View File

@ -864,9 +864,10 @@ JSScript::initScriptCounts(JSContext *cx)
JS_ASSERT(size_t(cursor - base) == bytes); JS_ASSERT(size_t(cursor - base) == bytes);
/* Enable interrupts in any interpreter frames running on this script. */ /* Enable interrupts in any interpreter frames running on this script. */
InterpreterFrames *frames; for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
for (frames = cx->runtime()->interpreterFrames; frames; frames = frames->older) if (iter.activation()->isInterpreter())
frames->enableInterruptsIfRunning(this); iter.activation()->asInterpreter()->enableInterruptsIfRunning(this);
}
return true; return true;
} }
@ -2611,9 +2612,10 @@ JSScript::ensureHasDebugScript(JSContext *cx)
* interrupts enabled. The interrupts must stay enabled until the * interrupts enabled. The interrupts must stay enabled until the
* debug state is destroyed. * debug state is destroyed.
*/ */
InterpreterFrames *frames; for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
for (frames = cx->runtime()->interpreterFrames; frames; frames = frames->older) if (iter.activation()->isInterpreter())
frames->enableInterruptsIfRunning(this); iter.activation()->asInterpreter()->enableInterruptsIfRunning(this);
}
return true; return true;
} }

View File

@ -975,30 +975,6 @@ TryNoteIter::settle()
goto error; \ goto error; \
JS_END_MACRO JS_END_MACRO
template<typename T>
class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
public:
GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
void enable() const { *variable = value; }
private:
T *variable;
T value;
};
inline InterpreterFrames::InterpreterFrames(JSContext *cx, FrameRegs *regs,
const InterruptEnablerBase &enabler)
: context(cx), regs(regs), enabler(enabler)
{
older = cx->runtime()->interpreterFrames;
cx->runtime()->interpreterFrames = this;
}
inline InterpreterFrames::~InterpreterFrames()
{
context->runtime()->interpreterFrames = older;
}
/* /*
* Ensure that the interpreter switch can close call-bytecode cases in the * Ensure that the interpreter switch can close call-bytecode cases in the
* same way as non-call bytecodes. * same way as non-call bytecodes.
@ -1287,10 +1263,19 @@ Interpret(JSContext *cx, RunState &state)
#define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->hasScriptCounts, switchMask == -1) #define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->hasScriptCounts, switchMask == -1)
/*
* When Debugger puts a script in single-step mode, all js::Interpret
* invocations that might be presently running that script must have
* interrupts enabled. It's not practical to simply check
* script->stepModeEnabled() at each point some callee could have changed
* it, because there are so many places js::Interpret could possibly cause
* JavaScript to run: each place an object might be coerced to a primitive
* or a number, for example. So instead, we expose a simple mechanism to
* let Debugger tweak the affected js::Interpret frames when an onStep
* handler is added: setting switchMask to -1 will enable interrupts.
*/
register int switchMask = 0; register int switchMask = 0;
int switchOp; int switchOp;
typedef GenericInterruptEnabler<int> InterruptEnabler;
InterruptEnabler interrupts(&switchMask, -1);
# define DO_OP() goto do_op # define DO_OP() goto do_op
@ -1345,7 +1330,7 @@ Interpret(JSContext *cx, RunState &state)
JS_BEGIN_MACRO \ JS_BEGIN_MACRO \
script = (s); \ script = (s); \
if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \ if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \
interrupts.enable(); \ switchMask = -1; /* Enable interrupts. */ \
JS_END_MACRO JS_END_MACRO
FrameRegs regs; FrameRegs regs;
@ -1364,13 +1349,7 @@ Interpret(JSContext *cx, RunState &state)
JS_ASSERT_IF(entryFrame->isEvalFrame(), state.script()->isActiveEval); JS_ASSERT_IF(entryFrame->isEvalFrame(), state.script()->isActiveEval);
InterpreterActivation activation(cx, entryFrame, regs); InterpreterActivation activation(cx, entryFrame, regs, &switchMask);
/*
* Help Debugger find frames running scripts that it has put in
* single-step mode.
*/
InterpreterFrames interpreterFrame(cx, &regs, interrupts);
/* Copy in hot values that change infrequently. */ /* Copy in hot values that change infrequently. */
JSRuntime *const rt = cx->runtime(); JSRuntime *const rt = cx->runtime();
@ -1450,7 +1429,7 @@ Interpret(JSContext *cx, RunState &state)
len = 0; len = 0;
if (rt->profilingScripts || cx->runtime()->debugHooks.interruptHook) if (rt->profilingScripts || cx->runtime()->debugHooks.interruptHook)
interrupts.enable(); switchMask = -1; /* Enable interrupts. */
goto advanceAndDoOp; goto advanceAndDoOp;

View File

@ -315,54 +315,6 @@ TypeOfValue(JSContext *cx, const Value &v);
extern bool extern bool
HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp); HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
/*
* A linked list of the |FrameRegs regs;| variables belonging to all
* js::Interpret C++ frames on this thread's stack.
*
* Note that this is *not* a list of all JS frames running under the
* interpreter; that would include inlined frames, whose FrameRegs are
* saved in various pieces in various places. Rather, this lists each
* js::Interpret call's live 'regs'; when control returns to that call, it
* will resume execution with this 'regs' instance.
*
* When Debugger puts a script in single-step mode, all js::Interpret
* invocations that might be presently running that script must have
* interrupts enabled. It's not practical to simply check
* script->stepModeEnabled() at each point some callee could have changed
* it, because there are so many places js::Interpret could possibly cause
* JavaScript to run: each place an object might be coerced to a primitive
* or a number, for example. So instead, we simply expose a list of the
* 'regs' those frames are using, and let Debugger tweak the affected
* js::Interpret frames when an onStep handler is established.
*
* Elements of this list are allocated within the js::Interpret stack
* frames themselves; the list is headed by this thread's js::ThreadData.
*/
class InterpreterFrames {
public:
class InterruptEnablerBase {
public:
virtual void enable() const = 0;
};
InterpreterFrames(JSContext *cx, FrameRegs *regs, const InterruptEnablerBase &enabler);
~InterpreterFrames();
/* If this js::Interpret frame is running |script|, enable interrupts. */
void enableInterruptsIfRunning(JSScript *script) {
if (regs->fp()->script() == script)
enabler.enable();
}
void enableInterruptsUnconditionally() { enabler.enable(); }
InterpreterFrames *older;
private:
JSContext *context;
FrameRegs *regs;
const InterruptEnablerBase &enabler;
};
/* Unwind block and scope chains to match the given depth. */ /* Unwind block and scope chains to match the given depth. */
extern void extern void
UnwindScope(JSContext *cx, AbstractFramePtr frame, uint32_t stackDepth); UnwindScope(JSContext *cx, AbstractFramePtr frame, uint32_t stackDepth);

View File

@ -127,7 +127,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
selfHostingGlobal_(NULL), selfHostingGlobal_(NULL),
nativeStackBase(0), nativeStackBase(0),
nativeStackQuota(0), nativeStackQuota(0),
interpreterFrames(NULL),
cxCallback(NULL), cxCallback(NULL),
destroyCompartmentCallback(NULL), destroyCompartmentCallback(NULL),
compartmentNameCallback(NULL), compartmentNameCallback(NULL),

View File

@ -76,7 +76,6 @@ typedef Rooted<JSLinearString*> RootedLinearString;
class Activation; class Activation;
class ActivationIterator; class ActivationIterator;
class AsmJSActivation; class AsmJSActivation;
class InterpreterFrames;
class MathCache; class MathCache;
class WorkerThreadState; class WorkerThreadState;
@ -917,12 +916,6 @@ struct JSRuntime : public JS::shadow::Runtime,
/* The native stack size limit that runtime should not exceed. */ /* The native stack size limit that runtime should not exceed. */
size_t nativeStackQuota; size_t nativeStackQuota;
/*
* Frames currently running in js::Interpret. See InterpreterFrames for
* details.
*/
js::InterpreterFrames *interpreterFrames;
/* Context create/destroy callback. */ /* Context create/destroy callback. */
JSContextCallback cxCallback; JSContextCallback cxCallback;
void *cxCallbackData; void *cxCallbackData;

View File

@ -833,11 +833,12 @@ Activation::~Activation()
cx_->mainThread().activation_ = prev_; cx_->mainThread().activation_ = prev_;
} }
InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs) InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs,
int *const switchMask)
: Activation(cx, Interpreter), : Activation(cx, Interpreter),
entry_(entry), entry_(entry),
current_(entry), regs_(regs),
regs_(regs) switchMask_(switchMask)
#ifdef DEBUG #ifdef DEBUG
, oldFrameCount_(cx_->runtime()->interpreterStack().frameCount_) , oldFrameCount_(cx_->runtime()->interpreterStack().frameCount_)
#endif #endif
@ -846,8 +847,8 @@ InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, F
InterpreterActivation::~InterpreterActivation() InterpreterActivation::~InterpreterActivation()
{ {
// Pop all inline frames. // Pop all inline frames.
while (current_ != entry_) while (regs_.fp() != entry_)
popInlineFrame(current_); popInlineFrame(regs_.fp());
JS_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_); JS_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_);
JS_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0); JS_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0);
@ -860,18 +861,15 @@ InterpreterActivation::pushInlineFrame(const CallArgs &args, HandleScript script
if (!cx_->runtime()->interpreterStack().pushInlineFrame(cx_, regs_, args, script, initial)) if (!cx_->runtime()->interpreterStack().pushInlineFrame(cx_, regs_, args, script, initial))
return false; return false;
JS_ASSERT(regs_.fp()->script()->compartment() == compartment_); JS_ASSERT(regs_.fp()->script()->compartment() == compartment_);
current_ = regs_.fp();
return true; return true;
} }
inline void inline void
InterpreterActivation::popInlineFrame(StackFrame *frame) InterpreterActivation::popInlineFrame(StackFrame *frame)
{ {
JS_ASSERT(current_ == frame); (void)frame; // Quell compiler warning.
JS_ASSERT(current_ != entry_); JS_ASSERT(regs_.fp() == frame);
JS_ASSERT(regs_.fp() != entry_);
current_ = frame->prev();
JS_ASSERT(current_);
cx_->runtime()->interpreterStack().popInlineFrame(regs_); cx_->runtime()->interpreterStack().popInlineFrame(regs_);
} }

View File

@ -1226,15 +1226,16 @@ class InterpreterActivation : public Activation
friend class js::InterpreterFrameIterator; friend class js::InterpreterFrameIterator;
StackFrame *const entry_; // Entry frame for this activation. StackFrame *const entry_; // Entry frame for this activation.
StackFrame *current_; // The most recent frame.
FrameRegs &regs_; FrameRegs &regs_;
int *const switchMask_; // For debugger interrupts, see js::Interpret.
#ifdef DEBUG #ifdef DEBUG
size_t oldFrameCount_; size_t oldFrameCount_;
#endif #endif
public: public:
inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs); inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs,
int *const switchMask);
inline ~InterpreterActivation(); inline ~InterpreterActivation();
inline bool pushInlineFrame(const CallArgs &args, HandleScript script, inline bool pushInlineFrame(const CallArgs &args, HandleScript script,
@ -1242,12 +1243,20 @@ class InterpreterActivation : public Activation
inline void popInlineFrame(StackFrame *frame); inline void popInlineFrame(StackFrame *frame);
StackFrame *current() const { StackFrame *current() const {
JS_ASSERT(current_); return regs_.fp();
return current_;
} }
FrameRegs &regs() const { FrameRegs &regs() const {
return regs_; return regs_;
} }
// If this js::Interpret frame is running |script|, enable interrupts.
void enableInterruptsIfRunning(JSScript *script) {
if (regs_.fp()->script() == script)
enableInterruptsUnconditionally();
}
void enableInterruptsUnconditionally() {
*switchMask_ = -1;
}
}; };
// Iterates over a runtime's activation list. // Iterates over a runtime's activation list.