зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3ae77c8181
Коммит
f695eb8158
|
@ -81,9 +81,6 @@
|
||||||
|
|
||||||
#include "jsautooplen.h"
|
#include "jsautooplen.h"
|
||||||
|
|
||||||
#include "methodjit/MethodJIT.h"
|
|
||||||
#include "methodjit/Retcon.h"
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include "sharkctl.h"
|
#include "sharkctl.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -154,34 +151,6 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
|
||||||
return comp->setDebugModeFromC(cx, !!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
|
static JSBool
|
||||||
CheckDebugMode(JSContext *cx)
|
CheckDebugMode(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -205,7 +174,7 @@ JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
|
||||||
if (!CheckDebugMode(cx))
|
if (!CheckDebugMode(cx))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
return js_SetSingleStepMode(cx, script, singleStep);
|
return script->setStepModeFlag(cx, singleStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsbytecode *
|
jsbytecode *
|
||||||
|
|
|
@ -131,10 +131,6 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug);
|
||||||
JS_FRIEND_API(JSBool)
|
JS_FRIEND_API(JSBool)
|
||||||
JS_SetDebugMode(JSContext *cx, JSBool debug);
|
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. */
|
/* Turn on single step mode. */
|
||||||
extern JS_PUBLIC_API(JSBool)
|
extern JS_PUBLIC_API(JSBool)
|
||||||
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
|
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
|
||||||
|
|
|
@ -345,11 +345,12 @@ class InterpreterFrames {
|
||||||
enabler.enableInterrupts();
|
enabler.enableInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InterpreterFrames *older;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSContext *context;
|
JSContext *context;
|
||||||
FrameRegs *regs;
|
FrameRegs *regs;
|
||||||
const InterruptEnablerBase &enabler;
|
const InterruptEnablerBase &enabler;
|
||||||
InterpreterFrames *older;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
#include "jsxdrapi.h"
|
#include "jsxdrapi.h"
|
||||||
#endif
|
#endif
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
|
#include "methodjit/Retcon.h"
|
||||||
#include "vm/Debugger.h"
|
#include "vm/Debugger.h"
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
@ -1829,3 +1830,58 @@ JSScript::copyClosedSlotsTo(JSScript *other)
|
||||||
{
|
{
|
||||||
memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
|
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:
|
private:
|
||||||
size_t callCount_; /* Number of times the script has been called. */
|
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
|
* Offsets to various array structures from the end of this script, or
|
||||||
* JSScript::INVALID_OFFSET if the array has length 0.
|
* JSScript::INVALID_OFFSET if the array has length 0.
|
||||||
|
@ -492,7 +501,6 @@ struct JSScript {
|
||||||
bool hasSingletons:1; /* script has singleton objects */
|
bool hasSingletons:1; /* script has singleton objects */
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
bool debugMode:1; /* script was compiled in debug mode */
|
bool debugMode:1; /* script was compiled in debug mode */
|
||||||
bool singleStepMode:1; /* compile script in single-step mode */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
jsbytecode *main; /* main entry point, after predef'ing prolog */
|
jsbytecode *main; /* main entry point, after predef'ing prolog */
|
||||||
|
@ -679,6 +687,42 @@ struct JSScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyClosedSlotsTo(JSScript *other);
|
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
|
#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->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
|
||||||
jit->invokeEntry = result;
|
jit->invokeEntry = result;
|
||||||
jit->singleStepMode = script->singleStepMode;
|
jit->singleStepMode = script->stepModeEnabled();
|
||||||
if (fun) {
|
if (fun) {
|
||||||
jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
|
jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
|
||||||
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
|
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
|
||||||
|
@ -903,7 +903,7 @@ mjit::Compiler::generateMethod()
|
||||||
op = JSOp(*PC);
|
op = JSOp(*PC);
|
||||||
trap |= stubs::JSTRAP_TRAP;
|
trap |= stubs::JSTRAP_TRAP;
|
||||||
}
|
}
|
||||||
if (script->singleStepMode && scanner.firstOpInLine(PC - script->code))
|
if (script->stepModeEnabled() && scanner.firstOpInLine(PC - script->code))
|
||||||
trap |= stubs::JSTRAP_SINGLESTEP;
|
trap |= stubs::JSTRAP_SINGLESTEP;
|
||||||
|
|
||||||
if (cx->hasRunOption(JSOPTION_PCCOUNT) && script->pcCounters) {
|
if (cx->hasRunOption(JSOPTION_PCCOUNT) && script->pcCounters) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче