зеркало из https://github.com/mozilla/gecko-dev.git
Bug 673125: Maintain a list of active js::Interrupt frames, their FrameRegs, and their interruptors. r=jorendorff.
The comment atop InterpreterFrames explains why this is needed, although it is only used by later patches in the series. --HG-- extra : rebase_source : 8cef90aea28f4fd71091a7bb6effcfcc7c8b5aa0
This commit is contained in:
Родитель
3bf81dfa04
Коммит
3ae77c8181
|
@ -111,7 +111,8 @@ ThreadData::ThreadData()
|
|||
waiveGCQuota(false),
|
||||
dtoaState(NULL),
|
||||
nativeStackBase(GetNativeStackBase()),
|
||||
pendingProxyOperation(NULL)
|
||||
pendingProxyOperation(NULL),
|
||||
interpreterFrames(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -226,6 +226,12 @@ struct ThreadData {
|
|||
|
||||
/* This must be called with the GC lock held. */
|
||||
void triggerOperationCallback(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Frames currently running in js::Interpret. See InterpreterFrames for
|
||||
* details.
|
||||
*/
|
||||
InterpreterFrames *interpreterFrames;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -1518,6 +1518,30 @@ CanIncDecWithoutOverflow(int32_t i)
|
|||
# endif
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
|
||||
public:
|
||||
GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
|
||||
void enableInterrupts() 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 = JS_THREAD_DATA(cx)->interpreterFrames;
|
||||
JS_THREAD_DATA(cx)->interpreterFrames = this;
|
||||
}
|
||||
|
||||
inline InterpreterFrames::~InterpreterFrames()
|
||||
{
|
||||
JS_THREAD_DATA(context)->interpreterFrames = older;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deadlocks or else bad races are likely if JS_THREADSAFE, so we must rely on
|
||||
* single-thread DEBUG js shell testing to verify property cache hits.
|
||||
|
@ -1705,7 +1729,8 @@ Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
|||
|
||||
register void * const *jumpTable = normalJumpTable;
|
||||
|
||||
# define ENABLE_INTERRUPTS() ((void) (jumpTable = interruptJumpTable))
|
||||
typedef GenericInterruptEnabler<void * const *> InterruptEnabler;
|
||||
InterruptEnabler interruptEnabler(&jumpTable, interruptJumpTable);
|
||||
|
||||
# ifdef JS_TRACER
|
||||
# define CHECK_RECORDER() \
|
||||
|
@ -1738,8 +1763,8 @@ Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
|||
|
||||
register intN switchMask = 0;
|
||||
intN switchOp;
|
||||
|
||||
# define ENABLE_INTERRUPTS() ((void) (switchMask = -1))
|
||||
typedef GenericInterruptEnabler<intN> InterruptEnabler;
|
||||
InterruptEnabler interruptEnabler(&switchMask, -1);
|
||||
|
||||
# ifdef JS_TRACER
|
||||
# define CHECK_RECORDER() \
|
||||
|
@ -1774,6 +1799,8 @@ Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
|||
|
||||
#endif /* !JS_THREADED_INTERP */
|
||||
|
||||
#define ENABLE_INTERRUPTS() (interruptEnabler.enableInterrupts())
|
||||
|
||||
#define LOAD_ATOM(PCOFF, atom) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_ASSERT(regs.fp()->hasImacropc() \
|
||||
|
@ -1955,6 +1982,12 @@ Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
|||
|
||||
FrameRegs regs = cx->regs();
|
||||
|
||||
/*
|
||||
* Help Debugger find frames running scripts that it has put in
|
||||
* single-step mode.
|
||||
*/
|
||||
InterpreterFrames interpreterFrame(cx, ®s, interruptEnabler);
|
||||
|
||||
/* Repoint cx->regs to a local variable for faster access. */
|
||||
struct InterpExitGuard {
|
||||
JSContext *cx;
|
||||
|
|
|
@ -306,6 +306,52 @@ GetUpvar(JSContext *cx, uintN level, UpvarCookie cookie);
|
|||
extern StackFrame *
|
||||
FindUpvarFrame(JSContext *cx, uintN targetLevel);
|
||||
|
||||
/*
|
||||
* 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 enableInterrupts() 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 (script == regs->fp()->script())
|
||||
enabler.enableInterrupts();
|
||||
}
|
||||
|
||||
private:
|
||||
JSContext *context;
|
||||
FrameRegs *regs;
|
||||
const InterruptEnablerBase &enabler;
|
||||
InterpreterFrames *older;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче