Bug 673125: Have each JSScript maintain both a count and a flag indicating whether it should be in single-step mode. r=jorendorff.

The rationale is explained in the comments in jsscript.h.

--HG--
extra : rebase_source : 0d537b172ce70c049269b1f09380f0eeabec9c92
This commit is contained in:
Jim Blandy 2011-08-23 14:44:22 -05:00
Родитель 3ae77c8181
Коммит f695eb8158
6 изменённых файлов: 106 добавлений и 40 удалений

Просмотреть файл

@ -81,9 +81,6 @@
#include "jsautooplen.h"
#include "methodjit/MethodJIT.h"
#include "methodjit/Retcon.h"
#ifdef __APPLE__
#include "sharkctl.h"
#endif
@ -154,34 +151,6 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
return comp->setDebugModeFromC(cx, !!debug);
}
JS_FRIEND_API(JSBool)
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
{
assertSameCompartment(cx, script);
#ifdef JS_METHODJIT
if (!script->singleStepMode == !singleStep)
return JS_TRUE;
#endif
JS_ASSERT_IF(singleStep, cx->compartment->debugMode());
#ifdef JS_METHODJIT
/* request the next recompile to inject single step interrupts */
script->singleStepMode = !!singleStep;
js::mjit::JITScript *jit = script->jitNormal ? script->jitNormal : script->jitCtor;
if (jit && script->singleStepMode != jit->singleStepMode) {
js::mjit::Recompiler recompiler(cx, script);
if (!recompiler.recompile()) {
script->singleStepMode = !singleStep;
return JS_FALSE;
}
}
#endif
return JS_TRUE;
}
static JSBool
CheckDebugMode(JSContext *cx)
{
@ -205,7 +174,7 @@ JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
if (!CheckDebugMode(cx))
return JS_FALSE;
return js_SetSingleStepMode(cx, script, singleStep);
return script->setStepModeFlag(cx, singleStep);
}
jsbytecode *

Просмотреть файл

@ -131,10 +131,6 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug);
JS_FRIEND_API(JSBool)
JS_SetDebugMode(JSContext *cx, JSBool debug);
/* Turn on single step mode. Requires debug mode. */
extern JS_FRIEND_API(JSBool)
js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
/* Turn on single step mode. */
extern JS_PUBLIC_API(JSBool)
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);

Просмотреть файл

@ -345,11 +345,12 @@ class InterpreterFrames {
enabler.enableInterrupts();
}
InterpreterFrames *older;
private:
JSContext *context;
FrameRegs *regs;
const InterruptEnablerBase &enabler;
InterpreterFrames *older;
};
} /* namespace js */

Просмотреть файл

@ -69,6 +69,7 @@
#include "jsxdrapi.h"
#endif
#include "methodjit/MethodJIT.h"
#include "methodjit/Retcon.h"
#include "vm/Debugger.h"
#include "jsobjinlines.h"
@ -1829,3 +1830,58 @@ JSScript::copyClosedSlotsTo(JSScript *other)
{
memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
}
bool
JSScript::recompileForStepMode(JSContext *cx)
{
#ifdef JS_METHODJIT
js::mjit::JITScript *jit = jitNormal ? jitNormal : jitCtor;
if (jit && stepModeEnabled() != jit->singleStepMode) {
js::mjit::Recompiler recompiler(cx, this);
return recompiler.recompile();
}
#endif
return true;
}
bool
JSScript::tryNewStepMode(JSContext *cx, uint32 newValue)
{
uint32 prior = stepMode;
stepMode = newValue;
if (!prior != !newValue) {
/* Step mode has been enabled or disabled. Alert the methodjit. */
if (!recompileForStepMode(cx)) {
stepMode = prior;
return false;
}
if (newValue) {
/* Step mode has been enabled. Alert the interpreter. */
InterpreterFrames *frames;
for (frames = JS_THREAD_DATA(cx)->interpreterFrames; frames; frames = frames->older)
frames->enableInterruptsIfRunning(this);
}
}
return true;
}
bool
JSScript::setStepModeFlag(JSContext *cx, bool step)
{
return tryNewStepMode(cx, (stepMode & stepCountMask) | (step ? stepFlagMask : 0));
}
bool
JSScript::changeStepModeCount(JSContext *cx, int delta)
{
assertSameCompartment(cx, this);
JS_ASSERT_IF(delta > 0, cx->compartment->debugMode());
uint32 count = stepMode & stepCountMask;
JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
return tryNewStepMode(cx,
(stepMode & stepFlagMask) |
((count + delta) & stepCountMask));
}

Просмотреть файл

@ -462,6 +462,15 @@ struct JSScript {
private:
size_t callCount_; /* Number of times the script has been called. */
/*
* When non-zero, compile script in single-step mode. The top bit is set and
* cleared by setStepMode, as used by JSD. The lower bits are a count,
* adjusted by changeStepModeCount, used by the Debugger object. Only
* when the bit is clear and the count is zero may we compile the script
* without single-step support.
*/
uint32 stepMode;
/*
* Offsets to various array structures from the end of this script, or
* JSScript::INVALID_OFFSET if the array has length 0.
@ -492,7 +501,6 @@ struct JSScript {
bool hasSingletons:1; /* script has singleton objects */
#ifdef JS_METHODJIT
bool debugMode:1; /* script was compiled in debug mode */
bool singleStepMode:1; /* compile script in single-step mode */
#endif
jsbytecode *main; /* main entry point, after predef'ing prolog */
@ -679,6 +687,42 @@ struct JSScript {
}
void copyClosedSlotsTo(JSScript *other);
private:
static const uint32 stepFlagMask = 0x80000000U;
static const uint32 stepCountMask = 0x7fffffffU;
/*
* Attempt to recompile with or without single-stepping support, as directed
* by stepModeEnabled().
*/
bool recompileForStepMode(JSContext *cx);
/* Attempt to change this->stepMode to |newValue|. */
bool tryNewStepMode(JSContext *cx, uint32 newValue);
public:
/*
* Set or clear the single-step flag. If the flag is set or the count
* (adjusted by changeStepModeCount) is non-zero, then the script is in
* single-step mode. (JSD uses an on/off-style interface; Debugger uses a
* count-style interface.)
*/
bool setStepModeFlag(JSContext *cx, bool step);
/*
* Increment or decrement the single-step count. If the count is non-zero or
* the flag (set by setStepModeFlag) is set, then the script is in
* single-step mode. (JSD uses an on/off-style interface; Debugger uses a
* count-style interface.)
*/
bool changeStepModeCount(JSContext *cx, int delta);
bool stepModeEnabled() { return !!stepMode; }
#ifdef DEBUG
uint32 stepModeCount() { return stepMode & stepCountMask; }
#endif
};
#define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script

Просмотреть файл

@ -474,7 +474,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
jit->invokeEntry = result;
jit->singleStepMode = script->singleStepMode;
jit->singleStepMode = script->stepModeEnabled();
if (fun) {
jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
@ -903,7 +903,7 @@ mjit::Compiler::generateMethod()
op = JSOp(*PC);
trap |= stubs::JSTRAP_TRAP;
}
if (script->singleStepMode && scanner.firstOpInLine(PC - script->code))
if (script->stepModeEnabled() && scanner.firstOpInLine(PC - script->code))
trap |= stubs::JSTRAP_SINGLESTEP;
if (cx->hasRunOption(JSOPTION_PCCOUNT) && script->pcCounters) {