mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
Remove JSOP_TRAP, bug 707454. r=jorendorff
This commit is contained in:
parent
870029947d
commit
16bb64e5ea
@ -90,9 +90,6 @@ ScriptAnalysis::addJump(JSContext *cx, unsigned offset,
|
||||
code->jumpTarget = true;
|
||||
|
||||
if (offset < *currentOffset) {
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
/* Scripts containing loops are never inlined. */
|
||||
isInlineable = false;
|
||||
|
||||
@ -282,8 +279,6 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
Bytecode *code = maybeCode(offset);
|
||||
jsbytecode *pc = script->code + offset;
|
||||
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
JSOp op = (JSOp)*pc;
|
||||
JS_ASSERT(op < JSOP_LIMIT);
|
||||
|
||||
@ -311,7 +306,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
if (forwardCatch)
|
||||
code->inTryBlock = true;
|
||||
|
||||
if (untrap.trap) {
|
||||
if (script->hasBreakpointsAt(pc)) {
|
||||
code->safePoint = true;
|
||||
isInlineable = canTrackVars = false;
|
||||
}
|
||||
@ -663,7 +658,6 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
loop->hasSafePoints = true;
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
JSOp op = (JSOp) *pc;
|
||||
|
||||
@ -814,7 +808,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
|
||||
#ifdef DEBUG
|
||||
JSOp nop = JSOp(script->code[targetOffset]);
|
||||
JS_ASSERT(nop == JSOP_LOOPHEAD || nop == JSOP_TRAP);
|
||||
JS_ASSERT(nop == JSOP_LOOPHEAD);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -855,7 +849,6 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
} while (!maybeCode(entry));
|
||||
|
||||
jsbytecode *entrypc = script->code + entry;
|
||||
UntrapOpcode untrap(cx, script, entrypc);
|
||||
|
||||
if (JSOp(*entrypc) == JSOP_GOTO || JSOp(*entrypc) == JSOP_GOTOX)
|
||||
loop->entry = entry + GetJumpOffset(entrypc, entrypc);
|
||||
@ -1156,7 +1149,6 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
uint32 offset = 0;
|
||||
while (offset < script->length) {
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
JSOp op = (JSOp)*pc;
|
||||
|
||||
uint32 successorOffset = offset + GetBytecodeLength(pc);
|
||||
@ -1749,7 +1741,6 @@ CrossScriptSSA::foldValue(const CrossSSAValue &cv)
|
||||
|
||||
if (v.kind() == SSAValue::PUSHED) {
|
||||
jsbytecode *pc = frame.script->code + v.pushedOffset();
|
||||
UntrapOpcode untrap(cx, frame.script, pc);
|
||||
|
||||
switch (JSOp(*pc)) {
|
||||
case JSOP_THIS:
|
||||
@ -1780,7 +1771,6 @@ CrossScriptSSA::foldValue(const CrossSSAValue &cv)
|
||||
uint32 offset = 0;
|
||||
while (offset < callee->length) {
|
||||
jsbytecode *pc = callee->code + offset;
|
||||
UntrapOpcode untrap(cx, callee, pc);
|
||||
if (analysis->maybeCode(pc) && JSOp(*pc) == JSOP_RETURN)
|
||||
return foldValue(CrossSSAValue(calleeFrame, analysis->poppedValue(pc, 0)));
|
||||
offset += GetBytecodeLength(pc);
|
||||
@ -1839,7 +1829,6 @@ ScriptAnalysis::printSSA(JSContext *cx)
|
||||
continue;
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
PrintBytecode(cx, script, pc);
|
||||
|
||||
|
@ -197,24 +197,11 @@ class Bytecode
|
||||
types::TypeBarrier *typeBarriers;
|
||||
};
|
||||
|
||||
static inline unsigned
|
||||
GetBytecodeLength(jsbytecode *pc)
|
||||
{
|
||||
JSOp op = (JSOp)*pc;
|
||||
JS_ASSERT(op < JSOP_LIMIT);
|
||||
JS_ASSERT(op != JSOP_TRAP);
|
||||
|
||||
if (js_CodeSpec[op].length != -1)
|
||||
return js_CodeSpec[op].length;
|
||||
return js_GetVariableBytecodeLength(pc);
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
GetDefCount(JSScript *script, unsigned offset)
|
||||
{
|
||||
JS_ASSERT(offset < script->length);
|
||||
jsbytecode *pc = script->code + offset;
|
||||
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
|
||||
|
||||
if (js_CodeSpec[*pc].ndefs == -1)
|
||||
return js_GetEnterBlockStackDefs(NULL, script, pc);
|
||||
@ -249,7 +236,6 @@ GetUseCount(JSScript *script, unsigned offset)
|
||||
{
|
||||
JS_ASSERT(offset < script->length);
|
||||
jsbytecode *pc = script->code + offset;
|
||||
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
|
||||
|
||||
if (JSOp(*pc) == JSOP_PICK)
|
||||
return (pc[1] + 1);
|
||||
@ -265,8 +251,6 @@ GetUseCount(JSScript *script, unsigned offset)
|
||||
static inline bool
|
||||
ExtendedDef(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
|
||||
|
||||
switch ((JSOp)*pc) {
|
||||
case JSOP_SETARG:
|
||||
case JSOP_INCARG:
|
||||
@ -310,8 +294,6 @@ ExtendedUse(jsbytecode *pc)
|
||||
static inline ptrdiff_t
|
||||
GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
|
||||
{
|
||||
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
|
||||
|
||||
uint32 type = JOF_OPTYPE(*pc);
|
||||
if (JOF_TYPE_IS_EXTENDED_JUMP(type))
|
||||
return GET_JUMPX_OFFSET(pc2);
|
||||
@ -336,33 +318,6 @@ ReverseCompareOp(JSOp op)
|
||||
}
|
||||
}
|
||||
|
||||
/* Untrap a single PC, and retrap it at scope exit. */
|
||||
struct UntrapOpcode
|
||||
{
|
||||
jsbytecode *pc;
|
||||
bool trap;
|
||||
|
||||
UntrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
: pc(pc), trap(JSOp(*pc) == JSOP_TRAP)
|
||||
{
|
||||
if (trap)
|
||||
*pc = JS_GetTrapOpcode(cx, script, pc);
|
||||
}
|
||||
|
||||
void retrap()
|
||||
{
|
||||
if (trap) {
|
||||
*pc = JSOP_TRAP;
|
||||
trap = false;
|
||||
}
|
||||
}
|
||||
|
||||
~UntrapOpcode()
|
||||
{
|
||||
retrap();
|
||||
}
|
||||
};
|
||||
|
||||
static inline unsigned
|
||||
FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
|
||||
{
|
||||
@ -375,7 +330,6 @@ FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
|
||||
unsigned targetOffset = offset + GetJumpOffset(pc, pc);
|
||||
if (targetOffset < offset) {
|
||||
jsbytecode *target = script->code + targetOffset;
|
||||
UntrapOpcode untrap(cx, script, target);
|
||||
JSOp nop = JSOp(*target);
|
||||
if (nop == JSOP_GOTO || nop == JSOP_GOTOX)
|
||||
return targetOffset + GetJumpOffset(target, target);
|
||||
@ -971,15 +925,14 @@ class ScriptAnalysis
|
||||
}
|
||||
|
||||
types::TypeSet *bytecodeTypes(const jsbytecode *pc) {
|
||||
JS_ASSERT(JSOp(*pc) == JSOP_TRAP || (js_CodeSpec[*pc].format & JOF_TYPESET));
|
||||
JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
|
||||
return getCode(pc).observedTypes;
|
||||
}
|
||||
|
||||
const SSAValue &poppedValue(uint32 offset, uint32 which) {
|
||||
JS_ASSERT(offset < script->length);
|
||||
JS_ASSERT_IF(script->code[offset] != JSOP_TRAP,
|
||||
which < GetUseCount(script, offset) +
|
||||
(ExtendedUse(script->code + offset) ? 1 : 0));
|
||||
JS_ASSERT(which < GetUseCount(script, offset) +
|
||||
(ExtendedUse(script->code + offset) ? 1 : 0));
|
||||
return getCode(offset).poppedValues[which];
|
||||
}
|
||||
const SSAValue &poppedValue(const jsbytecode *pc, uint32 which) {
|
||||
@ -994,9 +947,8 @@ class ScriptAnalysis
|
||||
|
||||
types::TypeSet *pushedTypes(uint32 offset, uint32 which = 0) {
|
||||
JS_ASSERT(offset < script->length);
|
||||
JS_ASSERT_IF(script->code[offset] != JSOP_TRAP,
|
||||
which < GetDefCount(script, offset) +
|
||||
(ExtendedDef(script->code + offset) ? 1 : 0));
|
||||
JS_ASSERT(which < GetDefCount(script, offset) +
|
||||
(ExtendedDef(script->code + offset) ? 1 : 0));
|
||||
types::TypeSet *array = getCode(offset).pushedTypes;
|
||||
JS_ASSERT(array);
|
||||
return array + which;
|
||||
|
@ -617,7 +617,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
|
||||
/* Clear debugging state to remove GC roots. */
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
c->clearTraps(cx, NULL);
|
||||
c->clearTraps(cx);
|
||||
JS_ClearAllWatchPoints(cx);
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
emptyTypeObject(NULL),
|
||||
debugModeBits(rt->debugMode ? DebugFromC : 0),
|
||||
mathCache(NULL),
|
||||
breakpointSites(rt),
|
||||
watchpointMap(NULL)
|
||||
{
|
||||
PodArrayZero(evalCache);
|
||||
@ -122,7 +121,7 @@ JSCompartment::init(JSContext *cx)
|
||||
if (!scriptFilenameTable.init())
|
||||
return false;
|
||||
|
||||
return debuggees.init() && breakpointSites.init();
|
||||
return debuggees.init();
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
@ -687,107 +686,50 @@ JSCompartment::removeDebuggee(JSContext *cx,
|
||||
}
|
||||
}
|
||||
|
||||
BreakpointSite *
|
||||
JSCompartment::getBreakpointSite(jsbytecode *pc)
|
||||
{
|
||||
BreakpointSiteMap::Ptr p = breakpointSites.lookup(pc);
|
||||
return p ? p->value : NULL;
|
||||
}
|
||||
|
||||
BreakpointSite *
|
||||
JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
GlobalObject *scriptGlobal)
|
||||
{
|
||||
JS_ASSERT(script->code <= pc);
|
||||
JS_ASSERT(pc < script->code + script->length);
|
||||
|
||||
BreakpointSiteMap::AddPtr p = breakpointSites.lookupForAdd(pc);
|
||||
if (!p) {
|
||||
BreakpointSite *site = cx->runtime->new_<BreakpointSite>(script, pc);
|
||||
if (!site || !breakpointSites.add(p, pc, site)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BreakpointSite *site = p->value;
|
||||
if (site->scriptGlobal)
|
||||
JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
|
||||
else
|
||||
site->scriptGlobal = scriptGlobal;
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script,
|
||||
JSObject *handler)
|
||||
JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
|
||||
{
|
||||
JS_ASSERT_IF(script, script->compartment() == this);
|
||||
|
||||
for (BreakpointSiteMap::Enum e(breakpointSites); !e.empty(); e.popFront()) {
|
||||
BreakpointSite *site = e.front().value;
|
||||
if (!script || site->script == script) {
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
|
||||
bp->destroy(cx, &e);
|
||||
}
|
||||
}
|
||||
for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasAnyBreakpointsOrStepMode())
|
||||
script->clearBreakpointsIn(cx, dbg, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::clearTraps(JSContext *cx, JSScript *script)
|
||||
JSCompartment::clearTraps(JSContext *cx)
|
||||
{
|
||||
for (BreakpointSiteMap::Enum e(breakpointSites); !e.empty(); e.popFront()) {
|
||||
BreakpointSite *site = e.front().value;
|
||||
if (!script || site->script == script)
|
||||
site->clearTrap(cx, &e);
|
||||
for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasAnyBreakpointsOrStepMode())
|
||||
script->clearTraps(cx);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::markTrapClosuresIteratively(JSTracer *trc)
|
||||
{
|
||||
bool markedAny = false;
|
||||
JSContext *cx = trc->context;
|
||||
for (BreakpointSiteMap::Range r = breakpointSites.all(); !r.empty(); r.popFront()) {
|
||||
BreakpointSite *site = r.front().value;
|
||||
|
||||
// Put off marking trap state until we know the script is live.
|
||||
if (site->trapHandler && !IsAboutToBeFinalized(cx, site->script)) {
|
||||
if (site->trapClosure.isMarkable() &&
|
||||
IsAboutToBeFinalized(cx, site->trapClosure))
|
||||
{
|
||||
markedAny = true;
|
||||
}
|
||||
MarkValue(trc, site->trapClosure, "trap closure");
|
||||
}
|
||||
}
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::sweepBreakpoints(JSContext *cx)
|
||||
{
|
||||
for (BreakpointSiteMap::Enum e(breakpointSites); !e.empty(); e.popFront()) {
|
||||
BreakpointSite *site = e.front().value;
|
||||
// clearTrap and nextbp are necessary here to avoid possibly
|
||||
// reading *site or *bp after destroying it.
|
||||
bool scriptGone = IsAboutToBeFinalized(cx, site->script);
|
||||
bool clearTrap = scriptGone && site->hasTrap();
|
||||
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
if (scriptGone || IsAboutToBeFinalized(cx, bp->debugger->toJSObject()))
|
||||
bp->destroy(cx, &e);
|
||||
if (JS_CLIST_IS_EMPTY(&cx->runtime->debuggerList))
|
||||
return;
|
||||
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasAnyBreakpointsOrStepMode())
|
||||
continue;
|
||||
bool scriptGone = IsAboutToBeFinalized(cx, script);
|
||||
for (unsigned i = 0; i < script->length; i++) {
|
||||
BreakpointSite *site = script->getBreakpointSite(script->code + i);
|
||||
if (!site)
|
||||
continue;
|
||||
// nextbp is necessary here to avoid possibly reading *bp after
|
||||
// destroying it.
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
if (scriptGone || IsAboutToBeFinalized(cx, bp->debugger->toJSObject()))
|
||||
bp->destroy(cx);
|
||||
}
|
||||
}
|
||||
|
||||
if (clearTrap)
|
||||
site->clearTrap(cx, &e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,9 +323,6 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
*/
|
||||
js::GlobalObjectSet debuggees;
|
||||
|
||||
public:
|
||||
js::BreakpointSiteMap breakpointSites;
|
||||
|
||||
private:
|
||||
JSCompartment *thisForCtor() { return this; }
|
||||
|
||||
@ -361,12 +358,8 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
js::GlobalObjectSet::Enum *debuggeesEnum = NULL);
|
||||
bool setDebugModeFromC(JSContext *cx, bool b);
|
||||
|
||||
js::BreakpointSite *getBreakpointSite(jsbytecode *pc);
|
||||
js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
js::GlobalObject *scriptGlobal);
|
||||
void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script, JSObject *handler);
|
||||
void clearTraps(JSContext *cx, JSScript *script);
|
||||
bool markTrapClosuresIteratively(JSTracer *trc);
|
||||
void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
|
||||
void clearTraps(JSContext *cx);
|
||||
|
||||
private:
|
||||
void sweepBreakpoints(JSContext *cx);
|
||||
|
@ -198,29 +198,24 @@ JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep)
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handler, jsval closure)
|
||||
{
|
||||
assertSameCompartment(cx, script, closure);
|
||||
|
||||
if (!CheckDebugMode(cx))
|
||||
return false;
|
||||
|
||||
BreakpointSite *site = script->compartment()->getOrCreateBreakpointSite(cx, script, pc, NULL);
|
||||
BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, NULL);
|
||||
if (!site)
|
||||
return false;
|
||||
site->setTrap(cx, handler, closure);
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSOp)
|
||||
JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
BreakpointSite *site = script->compartment()->getBreakpointSite(pc);
|
||||
return site ? site->realOpcode : JSOp(*pc);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JSTrapHandler *handlerp, jsval *closurep)
|
||||
{
|
||||
if (BreakpointSite *site = script->compartment()->getBreakpointSite(pc)) {
|
||||
site->clearTrap(cx, NULL, handlerp, closurep);
|
||||
if (BreakpointSite *site = script->getBreakpointSite(pc)) {
|
||||
site->clearTrap(cx, handlerp, closurep);
|
||||
} else {
|
||||
if (handlerp)
|
||||
*handlerp = NULL;
|
||||
@ -232,13 +227,13 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ClearScriptTraps(JSContext *cx, JSScript *script)
|
||||
{
|
||||
script->compartment()->clearTraps(cx, script);
|
||||
script->clearTraps(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ClearAllTrapsForCompartment(JSContext *cx)
|
||||
{
|
||||
cx->compartment->clearTraps(cx, NULL);
|
||||
cx->compartment->clearTraps(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -147,9 +147,6 @@ extern JS_PUBLIC_API(JSBool)
|
||||
JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JSTrapHandler handler, jsval closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSOp)
|
||||
JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JSTrapHandler *handlerp, jsval *closurep);
|
||||
|
@ -959,6 +959,9 @@ MarkChildren(JSTracer *trc, JSScript *script)
|
||||
|
||||
if (script->types)
|
||||
script->types->trace(trc);
|
||||
|
||||
if (script->hasAnyBreakpointsOrStepMode())
|
||||
script->markTrapClosures(trc);
|
||||
}
|
||||
|
||||
const Shape *
|
||||
|
@ -606,7 +606,6 @@ TypeSet::addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid i
|
||||
* outright ignored.
|
||||
*/
|
||||
jsbytecode *callpc = script->analysis()->getCallPC(pc);
|
||||
UntrapOpcode untrap(cx, script, callpc);
|
||||
if (JSOp(*callpc) == JSOP_NEW)
|
||||
return;
|
||||
|
||||
@ -740,7 +739,6 @@ TypeSet::addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc, Type
|
||||
{
|
||||
/* Don't add constraints when the call will be 'new' (see addCallProperty). */
|
||||
jsbytecode *callpc = script->analysis()->getCallPC(pc);
|
||||
UntrapOpcode untrap(cx, script, callpc);
|
||||
if (JSOp(*callpc) == JSOP_NEW)
|
||||
return;
|
||||
|
||||
@ -1067,8 +1065,6 @@ UnknownPropertyAccess(JSScript *script, Type type)
|
||||
void
|
||||
TypeConstraintProp::newType(JSContext *cx, TypeSet *source, Type type)
|
||||
{
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
if (UnknownPropertyAccess(script, type)) {
|
||||
/*
|
||||
* Access on an unknown object. Reads produce an unknown result, writes
|
||||
@ -1101,8 +1097,6 @@ TypeConstraintProp::newType(JSContext *cx, TypeSet *source, Type type)
|
||||
void
|
||||
TypeConstraintCallProp::newType(JSContext *cx, TypeSet *source, Type type)
|
||||
{
|
||||
UntrapOpcode untrap(cx, script, callpc);
|
||||
|
||||
/*
|
||||
* For CALLPROP, we need to update not just the pushed types but also the
|
||||
* 'this' types of possible callees. If we can't figure out that set of
|
||||
@ -2014,7 +2008,6 @@ TypeCompartment::newAllocationSiteTypeObject(JSContext *cx, const AllocationSite
|
||||
}
|
||||
|
||||
jsbytecode *pc = key.script->code + key.offset;
|
||||
UntrapOpcode untrap(cx, key.script, pc);
|
||||
|
||||
if (JSOp(*pc) == JSOP_NEWOBJECT) {
|
||||
/*
|
||||
@ -2062,8 +2055,6 @@ types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
/*
|
||||
* Make a heuristic guess at a use of JSOP_NEW that the constructed object
|
||||
* should have a fresh type object. We do this when the NEW is immediately
|
||||
@ -2246,7 +2237,6 @@ TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32 offset,
|
||||
JS_ASSERT(analysis->ranInference());
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
JS_ASSERT_IF(returnOnly, js_CodeSpec[*pc].format & JOF_INVOKE);
|
||||
|
||||
@ -2325,7 +2315,6 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
|
||||
if (!script->analysis()->maybeCode(i))
|
||||
continue;
|
||||
jsbytecode *pc = script->code + i;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
|
||||
continue;
|
||||
unsigned defCount = GetDefCount(script, i);
|
||||
@ -3210,8 +3199,6 @@ GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
if (!script->hasGlobal())
|
||||
return NULL;
|
||||
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
|
||||
|
||||
@ -3272,7 +3259,7 @@ ScriptAnalysis::resolveNameAccess(JSContext *cx, jsid id, bool addDependency)
|
||||
* active frame counts for such scripts.
|
||||
*/
|
||||
if (script->analysis()->addsScopeObjects() ||
|
||||
js_GetOpcode(cx, script, script->code) == JSOP_GENERATOR) {
|
||||
JSOp(*script->code) == JSOP_GENERATOR) {
|
||||
return access;
|
||||
}
|
||||
|
||||
@ -4193,7 +4180,7 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
|
||||
*/
|
||||
if (!detached &&
|
||||
(nesting->parent->analysis()->addsScopeObjects() ||
|
||||
js_GetOpcode(cx, nesting->parent, nesting->parent->code) == JSOP_GENERATOR)) {
|
||||
JSOp(*nesting->parent->code) == JSOP_GENERATOR)) {
|
||||
DetachNestingParent(script);
|
||||
detached = true;
|
||||
}
|
||||
@ -4206,7 +4193,6 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
|
||||
Bytecode *code = maybeCode(offset);
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
if (code && !analyzeTypesBytecode(cx, offset, state)) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
@ -4324,7 +4310,6 @@ ScriptAnalysis::followEscapingArguments(JSContext *cx, SSAUseChain *use, Vector<
|
||||
uint32 which = use->u.which;
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
JS_ASSERT(op != JSOP_TRAP);
|
||||
|
||||
if (op == JSOP_POP || op == JSOP_POPN)
|
||||
return true;
|
||||
@ -4502,7 +4487,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
|
||||
while (nextOffset < script->length) {
|
||||
unsigned offset = nextOffset;
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
|
||||
@ -4560,8 +4544,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
|
||||
return false;
|
||||
|
||||
pc = script->code + uses->offset;
|
||||
UntrapOpcode untrapUse(cx, script, pc);
|
||||
|
||||
op = JSOp(*pc);
|
||||
|
||||
JSObject *obj = *pbaseobj;
|
||||
@ -4643,7 +4625,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
|
||||
if (calleev.kind() != SSAValue::PUSHED)
|
||||
return false;
|
||||
jsbytecode *calleepc = script->code + calleev.pushedOffset();
|
||||
UntrapOpcode untrapCallee(cx, script, calleepc);
|
||||
if (JSOp(*calleepc) != JSOP_CALLPROP || calleev.pushedIndex() != 0)
|
||||
return false;
|
||||
|
||||
@ -4805,7 +4786,6 @@ ScriptAnalysis::printTypes(JSContext *cx)
|
||||
continue;
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
|
||||
continue;
|
||||
@ -4884,7 +4864,6 @@ ScriptAnalysis::printTypes(JSContext *cx)
|
||||
continue;
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
PrintBytecode(cx, script, pc);
|
||||
|
||||
@ -4942,8 +4921,6 @@ MarkIteratorUnknownSlow(JSContext *cx)
|
||||
if (!script || !pc)
|
||||
return;
|
||||
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
if (JSOp(*pc) != JSOP_ITER)
|
||||
return;
|
||||
|
||||
@ -4987,7 +4964,7 @@ MarkIteratorUnknownSlow(JSContext *cx)
|
||||
jsbytecode *pc = script->code + i;
|
||||
if (!analysis->maybeCode(pc))
|
||||
continue;
|
||||
if (js_GetOpcode(cx, script, pc) == JSOP_ITERNEXT)
|
||||
if (JSOp(*pc) == JSOP_ITERNEXT)
|
||||
analysis->pushedTypes(pc, 0)->addType(cx, Type::UnknownType());
|
||||
}
|
||||
|
||||
@ -5033,8 +5010,6 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
AutoEnterTypeInference enter(cx);
|
||||
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
/* Directly update associated type sets for applicable bytecodes. */
|
||||
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
|
||||
if (!script->ensureRanAnalysis(cx, NULL)) {
|
||||
@ -5137,8 +5112,6 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
|
||||
void
|
||||
TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
|
||||
{
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
/* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
|
||||
if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
|
||||
return;
|
||||
@ -5415,8 +5388,6 @@ NestingEpilogue(StackFrame *fp)
|
||||
static inline bool
|
||||
IgnorePushed(const jsbytecode *pc, unsigned index)
|
||||
{
|
||||
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
|
||||
|
||||
switch (JSOp(*pc)) {
|
||||
/* We keep track of the scopes pushed by BINDNAME separately. */
|
||||
case JSOP_BINDNAME:
|
||||
@ -5593,7 +5564,6 @@ JSScript::typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton)
|
||||
TypeScript::CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp)
|
||||
{
|
||||
AutoEnterTypeInference enter(cx);
|
||||
UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
|
||||
return;
|
||||
|
@ -161,13 +161,13 @@ js::GetBlockChain(JSContext *cx, StackFrame *fp)
|
||||
* If the debugger asks for the scope chain at a pc where we are about to
|
||||
* fix it up, advance target past the fixup. See bug 672804.
|
||||
*/
|
||||
JSOp op = js_GetOpcode(cx, script, target);
|
||||
JSOp op = JSOp(*target);
|
||||
while (op == JSOP_NOP || op == JSOP_INDEXBASE || op == JSOP_INDEXBASE1 ||
|
||||
op == JSOP_INDEXBASE2 || op == JSOP_INDEXBASE3 ||
|
||||
op == JSOP_BLOCKCHAIN || op == JSOP_NULLBLOCKCHAIN)
|
||||
{
|
||||
target += js_CodeSpec[op].length;
|
||||
op = js_GetOpcode(cx, script, target);
|
||||
op = JSOp(*target);
|
||||
}
|
||||
JS_ASSERT(target >= start && target < start + script->length);
|
||||
|
||||
@ -175,7 +175,7 @@ js::GetBlockChain(JSContext *cx, StackFrame *fp)
|
||||
uintN indexBase = 0;
|
||||
ptrdiff_t oplen;
|
||||
for (jsbytecode *pc = start; pc < target; pc += oplen) {
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
oplen = cs->length;
|
||||
if (oplen < 0)
|
||||
@ -212,12 +212,12 @@ js::GetBlockChainFast(JSContext *cx, StackFrame *fp, JSOp op, size_t oplen)
|
||||
{
|
||||
/* Assume that we're in a script frame. */
|
||||
jsbytecode *pc = fp->pcQuadratic(cx->stack);
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
|
||||
JS_ASSERT(JSOp(*pc) == op);
|
||||
|
||||
pc += oplen;
|
||||
op = JSOp(*pc);
|
||||
|
||||
/* The fast paths assume no JSOP_RESETBASE/INDEXBASE or JSOP_TRAP noise. */
|
||||
/* The fast paths assume no JSOP_RESETBASE/INDEXBASE noise. */
|
||||
if (op == JSOP_NULLBLOCKCHAIN)
|
||||
return NULL;
|
||||
if (op == JSOP_BLOCKCHAIN)
|
||||
@ -1535,8 +1535,7 @@ TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRe
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (cx->typeInferenceEnabled() &&
|
||||
*regs.pc != JSOP_TRAP &&
|
||||
n == analyze::GetBytecodeLength(regs.pc)) {
|
||||
n == GetBytecodeLength(regs.pc)) {
|
||||
TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
|
||||
}
|
||||
#endif
|
||||
@ -1672,16 +1671,15 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
|
||||
#define CHECK_PARTIAL_METHODJIT(status) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (status == mjit::Jaeger_Unfinished) { \
|
||||
switch (status) { \
|
||||
case mjit::Jaeger_UnfinishedAtTrap: \
|
||||
interpMode = JSINTERP_SKIP_TRAP; \
|
||||
/* FALLTHROUGH */ \
|
||||
case mjit::Jaeger_Unfinished: \
|
||||
op = (JSOp) *regs.pc; \
|
||||
RESTORE_INTERP_VARS_CHECK_EXCEPTION(); \
|
||||
DO_OP(); \
|
||||
} else if (status == mjit::Jaeger_UnfinishedAtTrap) { \
|
||||
interpMode = JSINTERP_SKIP_TRAP; \
|
||||
JS_ASSERT(JSOp(*regs.pc) == JSOP_TRAP); \
|
||||
op = JSOP_TRAP; \
|
||||
RESTORE_INTERP_VARS_CHECK_EXCEPTION(); \
|
||||
DO_OP(); \
|
||||
default:; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
@ -1729,10 +1727,12 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
#define SET_SCRIPT(s) \
|
||||
JS_BEGIN_MACRO \
|
||||
script = (s); \
|
||||
if (script->stepModeEnabled()) \
|
||||
if (script->hasAnyBreakpointsOrStepMode()) \
|
||||
ENABLE_INTERRUPTS(); \
|
||||
if (script->pcCounters) \
|
||||
if (script->pcCounters) \
|
||||
ENABLE_INTERRUPTS(); \
|
||||
JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, \
|
||||
script->hasAnyBreakpointsOrStepMode()); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define CHECK_INTERRUPT_HANDLER() \
|
||||
@ -1815,8 +1815,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
if (interpMode == JSINTERP_REJOIN)
|
||||
interpMode = JSINTERP_NORMAL;
|
||||
|
||||
JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, JSOp(*regs.pc) == JSOP_TRAP);
|
||||
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
|
||||
RESET_USE_METHODJIT();
|
||||
@ -1903,6 +1901,32 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
moreInterrupts = true;
|
||||
}
|
||||
|
||||
if (script->hasAnyBreakpointsOrStepMode())
|
||||
moreInterrupts = true;
|
||||
|
||||
if (script->hasBreakpointsAt(regs.pc) && interpMode != JSINTERP_SKIP_TRAP) {
|
||||
Value rval;
|
||||
JSTrapStatus status = Debugger::onTrap(cx, &rval);
|
||||
switch (status) {
|
||||
case JSTRAP_ERROR:
|
||||
goto error;
|
||||
case JSTRAP_RETURN:
|
||||
regs.fp()->setReturnValue(rval);
|
||||
interpReturnOK = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
goto error;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
JS_ASSERT(status == JSTRAP_CONTINUE);
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
|
||||
}
|
||||
|
||||
interpMode = JSINTERP_NORMAL;
|
||||
|
||||
#if JS_THREADED_INTERP
|
||||
jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
|
||||
JS_EXTENSION_(goto *normalJumpTable[op]);
|
||||
@ -1916,6 +1940,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
/* No-ops for ease of decompilation. */
|
||||
ADD_EMPTY_CASE(JSOP_NOP)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED0)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED1)
|
||||
ADD_EMPTY_CASE(JSOP_CONDSWITCH)
|
||||
ADD_EMPTY_CASE(JSOP_TRY)
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -2064,7 +2089,7 @@ BEGIN_CASE(JSOP_STOP)
|
||||
|
||||
RESTORE_INTERP_VARS();
|
||||
|
||||
JS_ASSERT(*regs.pc == JSOP_TRAP || *regs.pc == JSOP_NEW || *regs.pc == JSOP_CALL ||
|
||||
JS_ASSERT(*regs.pc == JSOP_NEW || *regs.pc == JSOP_CALL ||
|
||||
*regs.pc == JSOP_FUNCALL || *regs.pc == JSOP_FUNAPPLY);
|
||||
|
||||
/* Resume execution in the calling frame. */
|
||||
@ -3600,7 +3625,7 @@ BEGIN_CASE(JSOP_CALLNAME)
|
||||
goto error;
|
||||
if (!prop) {
|
||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||
JSOp op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH);
|
||||
JSOp op2 = JSOp(regs.pc[JSOP_NAME_LENGTH]);
|
||||
if (op2 == JSOP_TYPEOF) {
|
||||
PUSH_UNDEFINED();
|
||||
TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
|
||||
@ -3879,37 +3904,6 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
|
||||
END_VARLEN_CASE
|
||||
}
|
||||
|
||||
BEGIN_CASE(JSOP_TRAP)
|
||||
{
|
||||
if (interpMode == JSINTERP_SKIP_TRAP) {
|
||||
interpMode = JSINTERP_NORMAL;
|
||||
op = JS_GetTrapOpcode(cx, script, regs.pc);
|
||||
DO_OP();
|
||||
}
|
||||
|
||||
Value rval;
|
||||
JSTrapStatus status = Debugger::onTrap(cx, &rval);
|
||||
switch (status) {
|
||||
case JSTRAP_ERROR:
|
||||
goto error;
|
||||
case JSTRAP_RETURN:
|
||||
regs.fp()->setReturnValue(rval);
|
||||
interpReturnOK = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
goto error;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
JS_ASSERT(status == JSTRAP_CONTINUE);
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
JS_ASSERT(rval.isInt32());
|
||||
op = (JSOp) rval.toInt32();
|
||||
JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
|
||||
DO_OP();
|
||||
}
|
||||
|
||||
BEGIN_CASE(JSOP_ARGUMENTS)
|
||||
{
|
||||
Value rval;
|
||||
@ -4277,7 +4271,7 @@ BEGIN_CASE(JSOP_LAMBDA)
|
||||
|
||||
if (op2 == JSOP_SETMETHOD) {
|
||||
#ifdef DEBUG
|
||||
op2 = js_GetOpcode(cx, script, pc2 + JSOP_SETMETHOD_LENGTH);
|
||||
op2 = JSOp(pc2[JSOP_SETMETHOD_LENGTH]);
|
||||
JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV);
|
||||
#endif
|
||||
const Value &lref = regs.sp[-1];
|
||||
@ -4360,7 +4354,7 @@ BEGIN_CASE(JSOP_GETTER)
|
||||
BEGIN_CASE(JSOP_SETTER)
|
||||
{
|
||||
do_getter_setter:
|
||||
JSOp op2 = js_GetOpcode(cx, script, ++regs.pc);
|
||||
JSOp op2 = JSOp(*++regs.pc);
|
||||
jsid id;
|
||||
Value rval;
|
||||
jsint i;
|
||||
@ -4618,7 +4612,7 @@ BEGIN_CASE(JSOP_INITELEM)
|
||||
JS_ASSERT(obj->isArray());
|
||||
JS_ASSERT(JSID_IS_INT(id));
|
||||
JS_ASSERT(jsuint(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
|
||||
if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT &&
|
||||
if (JSOp(regs.pc[JSOP_INITELEM_LENGTH]) == JSOP_ENDINIT &&
|
||||
!js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) {
|
||||
goto error;
|
||||
}
|
||||
@ -5510,7 +5504,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
||||
|
||||
case JSTRY_ITER: {
|
||||
/* This is similar to JSOP_ENDITER in the interpreter loop. */
|
||||
JS_ASSERT(js_GetOpcode(cx, regs.fp()->script(), regs.pc) == JSOP_ENDITER);
|
||||
JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
|
||||
Value v = cx->getPendingException();
|
||||
cx->clearPendingException();
|
||||
ok = js_CloseIterator(cx, ®s.sp[-1].toObject());
|
||||
|
@ -1169,7 +1169,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
|
||||
|
||||
#ifdef DEBUG
|
||||
jsbytecode *callerPC = caller->pcQuadratic(cx);
|
||||
JS_ASSERT(callerPC && js_GetOpcode(cx, caller->script(), callerPC) == JSOP_EVAL);
|
||||
JS_ASSERT(callerPC && JSOp(*callerPC) == JSOP_EVAL);
|
||||
#endif
|
||||
} else {
|
||||
JS_ASSERT(args.callee().getGlobal() == &scopeobj);
|
||||
@ -1308,7 +1308,7 @@ DirectEval(JSContext *cx, const CallArgs &args)
|
||||
StackFrame *caller = cx->fp();
|
||||
JS_ASSERT(caller->isScriptFrame());
|
||||
JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), args.calleev()));
|
||||
JS_ASSERT(js_GetOpcode(cx, cx->fp()->script(), cx->regs().pc) == JSOP_EVAL);
|
||||
JS_ASSERT(JSOp(*cx->regs().pc) == JSOP_EVAL);
|
||||
|
||||
AutoFunctionCallProbe callProbe(cx, args.callee().toFunction(), caller->script());
|
||||
|
||||
@ -3173,7 +3173,7 @@ Detecting(JSContext *cx, jsbytecode *pc)
|
||||
JS_ASSERT(script->code <= pc && pc < endpc);
|
||||
|
||||
/* General case: a branch or equality op follows the access. */
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
op = JSOp(*pc);
|
||||
if (js_CodeSpec[op].format & JOF_DETECTING)
|
||||
return JS_TRUE;
|
||||
|
||||
@ -3184,7 +3184,7 @@ Detecting(JSContext *cx, jsbytecode *pc)
|
||||
* about JS1.2's revision of the equality operators here.
|
||||
*/
|
||||
if (++pc < endpc) {
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
op = JSOp(*pc);
|
||||
return *pc == JSOP_EQ || *pc == JSOP_NE;
|
||||
}
|
||||
return JS_FALSE;
|
||||
@ -3199,7 +3199,7 @@ Detecting(JSContext *cx, jsbytecode *pc)
|
||||
GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
|
||||
if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
|
||||
(pc += js_CodeSpec[op].length) < endpc) {
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
op = JSOp(*pc);
|
||||
return op == JSOP_EQ || op == JSOP_NE ||
|
||||
op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
|
||||
}
|
||||
@ -3235,7 +3235,7 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
|
||||
if (!script || !pc)
|
||||
return defaultFlags;
|
||||
|
||||
cs = &js_CodeSpec[js_GetOpcode(cx, script, pc)];
|
||||
cs = &js_CodeSpec[*pc];
|
||||
format = cs->format;
|
||||
if (JOF_MODE(format) != JOF_NAME)
|
||||
flags |= JSRESOLVE_QUALIFIED;
|
||||
@ -5920,8 +5920,6 @@ js_GetPropertyHelperInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsi
|
||||
uintN flags;
|
||||
|
||||
op = (JSOp) *pc;
|
||||
if (op == JSOP_TRAP)
|
||||
op = JS_GetTrapOpcode(cx, cx->fp()->script(), pc);
|
||||
if (op == JSOP_GETXPROP) {
|
||||
flags = JSREPORT_ERROR;
|
||||
} else {
|
||||
|
@ -162,7 +162,7 @@ uintN
|
||||
js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
ptrdiff_t pcoff)
|
||||
{
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);
|
||||
|
||||
/*
|
||||
@ -172,12 +172,12 @@ js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
uintN span = js_CodeSpec[op].length;
|
||||
uintN base = 0;
|
||||
if (pc - script->code + span < script->length) {
|
||||
JSOp next = js_GetOpcode(cx, script, pc + span);
|
||||
JSOp next = JSOp(pc[span]);
|
||||
if (next == JSOP_RESETBASE) {
|
||||
JS_ASSERT(js_GetOpcode(cx, script, pc - JSOP_INDEXBASE_LENGTH) == JSOP_INDEXBASE);
|
||||
JS_ASSERT(JSOp(pc[-JSOP_INDEXBASE_LENGTH]) == JSOP_INDEXBASE);
|
||||
base = GET_INDEXBASE(pc - JSOP_INDEXBASE_LENGTH);
|
||||
} else if (next == JSOP_RESETBASE0) {
|
||||
JSOp prev = js_GetOpcode(cx, script, pc - 1);
|
||||
JSOp prev = JSOp(pc[-1]);
|
||||
JS_ASSERT(JSOP_INDEXBASE1 <= prev && prev <= JSOP_INDEXBASE3);
|
||||
base = (prev - JSOP_INDEXBASE1 + 1) << 16;
|
||||
}
|
||||
@ -186,11 +186,12 @@ js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
}
|
||||
|
||||
size_t
|
||||
js_GetVariableBytecodeLength(JSOp op, jsbytecode *pc)
|
||||
js_GetVariableBytecodeLength(jsbytecode *pc)
|
||||
{
|
||||
uintN jmplen, ncases;
|
||||
jsint low, high;
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
JS_ASSERT(js_CodeSpec[op].length == -1);
|
||||
switch (op) {
|
||||
case JSOP_TABLESWITCHX:
|
||||
@ -224,7 +225,7 @@ js_GetVariableBytecodeLength(JSOp op, jsbytecode *pc)
|
||||
uintN
|
||||
js_GetVariableStackUses(JSOp op, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(*pc == op || *pc == JSOP_TRAP);
|
||||
JS_ASSERT(*pc == op);
|
||||
JS_ASSERT(js_CodeSpec[op].nuses == -1);
|
||||
switch (op) {
|
||||
case JSOP_POPN:
|
||||
@ -246,63 +247,11 @@ js_GetEnterBlockStackDefs(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
JS_ASSERT(*pc == JSOP_ENTERBLOCK || *pc == JSOP_TRAP);
|
||||
JS_ASSERT(*pc == JSOP_ENTERBLOCK);
|
||||
GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj);
|
||||
return OBJ_BLOCK_COUNT(cx, obj);
|
||||
}
|
||||
|
||||
AutoScriptUntrapper::AutoScriptUntrapper()
|
||||
: origScript(NULL), origCode(NULL)
|
||||
{}
|
||||
|
||||
bool
|
||||
AutoScriptUntrapper::untrap(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(!origScript && !origCode);
|
||||
|
||||
BreakpointSiteMap &sites = script->compartment()->breakpointSites;
|
||||
for (BreakpointSiteMap::Range r = sites.all(); !r.empty(); r.popFront()) {
|
||||
BreakpointSite *site = r.front().value;
|
||||
if (site->script == script) {
|
||||
JS_ASSERT(size_t(site->pc - script->code) < script->length);
|
||||
if (size_t(site->pc - script->code) >= script->length)
|
||||
continue;
|
||||
ptrdiff_t off = site->pc - script->code;
|
||||
if (script->code[off] == site->realOpcode)
|
||||
continue;
|
||||
if (!origCode && !saveOriginal(script))
|
||||
return false;
|
||||
script->code[site->pc - script->code] = site->realOpcode;
|
||||
}
|
||||
}
|
||||
if (origCode)
|
||||
GetGSNCache(cx)->purge();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AutoScriptUntrapper::saveOriginal(JSScript *script)
|
||||
{
|
||||
nbytes = script->length * sizeof(jsbytecode);
|
||||
|
||||
origCode = (jsbytecode *) OffTheBooks::malloc_(nbytes);
|
||||
if (!origCode)
|
||||
return false;
|
||||
|
||||
memcpy(origCode, script->code, nbytes);
|
||||
origScript = script;
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoScriptUntrapper::~AutoScriptUntrapper()
|
||||
{
|
||||
JS_ASSERT(!!origCode == !!origScript);
|
||||
if (origCode) {
|
||||
memcpy(origScript->code, origCode, nbytes);
|
||||
Foreground::free_(origCode);
|
||||
}
|
||||
}
|
||||
|
||||
static const char * countBaseNames[] = {
|
||||
"interp",
|
||||
"mjit",
|
||||
@ -401,7 +350,7 @@ js_DumpPCCounts(JSContext *cx, JSScript *script, js::Sprinter *sp)
|
||||
|
||||
jsbytecode *pc = script->code;
|
||||
while (pc < script->code + script->length) {
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
|
||||
int len = js_CodeSpec[op].length;
|
||||
jsbytecode *next = (len != -1) ? pc + len : pc + js_GetVariableBytecodeLength(pc);
|
||||
@ -578,10 +527,6 @@ JS_FRIEND_API(uintN)
|
||||
js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
uintN loc, JSBool lines, Sprinter *sp)
|
||||
{
|
||||
AutoScriptUntrapper untrapper;
|
||||
if (!untrapper.untrap(cx, script))
|
||||
return 0;
|
||||
|
||||
JSOp op = (JSOp)*pc;
|
||||
if (op >= JSOP_LIMIT) {
|
||||
char numBuf1[12], numBuf2[12];
|
||||
@ -4561,18 +4506,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
goto do_function;
|
||||
break;
|
||||
|
||||
case JSOP_TRAP:
|
||||
saveop = op = JS_GetTrapOpcode(cx, jp->script, pc);
|
||||
*pc = op;
|
||||
cs = &js_CodeSpec[op];
|
||||
len = cs->length;
|
||||
DECOMPILE_CODE(pc, len);
|
||||
if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
|
||||
len += GetDecomposeLength(pc, js_CodeSpec[*pc].length);
|
||||
*pc = JSOP_TRAP;
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_HOLE:
|
||||
todo = SprintPut(&ss->sprinter, "", 0);
|
||||
break;
|
||||
@ -4936,9 +4869,6 @@ DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
|
||||
uintN pcdepth)
|
||||
{
|
||||
JSContext *cx = jp->sprinter.context;
|
||||
AutoScriptUntrapper untrapper;
|
||||
if (!untrapper.untrap(cx, script))
|
||||
return false;
|
||||
|
||||
uintN depth = StackDepth(script);
|
||||
JS_ASSERT(pcdepth <= depth);
|
||||
@ -5093,9 +5023,6 @@ js_DecompileFunction(JSPrinter *jp)
|
||||
|
||||
/* Print the parameters. */
|
||||
jsbytecode *pc = script->main();
|
||||
AutoScriptUntrapper untrapper;
|
||||
if (!untrapper.untrap(jp->sprinter.context, script))
|
||||
return JS_FALSE;;
|
||||
jsbytecode *endpc = pc + script->length;
|
||||
JSBool ok = JS_TRUE;
|
||||
|
||||
@ -5294,9 +5221,6 @@ DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun,
|
||||
jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(script->code <= pc && pc < script->code + script->length);
|
||||
AutoScriptUntrapper untrapper;
|
||||
if (!untrapper.untrap(cx, script))
|
||||
return NULL;
|
||||
|
||||
JSOp op = (JSOp) *pc;
|
||||
|
||||
@ -5468,7 +5392,7 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
|
||||
uintN pcdepth = 0;
|
||||
ptrdiff_t oplen;
|
||||
for (; pc < target; pc += oplen) {
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
oplen = cs->length;
|
||||
if (oplen < 0)
|
||||
@ -5492,7 +5416,7 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
|
||||
ptrdiff_t jmpoff = js_GetSrcNoteOffset(sn, 0);
|
||||
if (pc + jmpoff < target) {
|
||||
pc += jmpoff;
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
op = JSOp(*pc);
|
||||
JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX);
|
||||
cs = &js_CodeSpec[op];
|
||||
oplen = cs->length;
|
||||
@ -5555,22 +5479,11 @@ CallResultEscapes(jsbytecode *pc)
|
||||
return (*pc != JSOP_IFEQ);
|
||||
}
|
||||
|
||||
size_t
|
||||
GetBytecodeLength(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JS_ASSERT(op < JSOP_LIMIT);
|
||||
JS_ASSERT(op != JSOP_TRAP);
|
||||
if (js_CodeSpec[op].length != -1)
|
||||
return js_CodeSpec[op].length;
|
||||
return js_GetVariableBytecodeLength(op, pc);
|
||||
}
|
||||
|
||||
extern bool
|
||||
IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset)
|
||||
{
|
||||
// This could be faster (by following jump instructions if the target is <= offset).
|
||||
for (BytecodeRange r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRange r(script); !r.empty(); r.popFront()) {
|
||||
size_t here = r.frontOffset();
|
||||
if (here >= offset)
|
||||
return here == offset;
|
||||
|
@ -219,8 +219,7 @@ typedef enum JSOp {
|
||||
#define GET_INDEX(pc) GET_UINT16(pc)
|
||||
#define SET_INDEX(pc,i) ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i))
|
||||
|
||||
#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE \
|
||||
|| *(pc) == JSOP_TRAP), \
|
||||
#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE), \
|
||||
((uintN)((pc)[1])) << 16)
|
||||
#define INDEXBASE_LEN 1
|
||||
|
||||
@ -472,14 +471,7 @@ JS_END_EXTERN_C
|
||||
* Get the length of variable-length bytecode like JSOP_TABLESWITCH.
|
||||
*/
|
||||
extern size_t
|
||||
js_GetVariableBytecodeLength(JSOp op, jsbytecode *pc);
|
||||
|
||||
inline size_t
|
||||
js_GetVariableBytecodeLength(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(*pc != JSOP_TRAP);
|
||||
return js_GetVariableBytecodeLength(JSOp(*pc), pc);
|
||||
}
|
||||
js_GetVariableBytecodeLength(jsbytecode *pc);
|
||||
|
||||
namespace js {
|
||||
|
||||
@ -536,12 +528,20 @@ GetDecomposeLength(jsbytecode *pc, size_t len)
|
||||
* The last byte of a DECOMPOSE op stores the decomposed length. This can
|
||||
* vary across different instances of an opcode due to INDEXBASE ops.
|
||||
*/
|
||||
JS_ASSERT_IF(JSOp(*pc) != JSOP_TRAP, size_t(js_CodeSpec[*pc].length) == len);
|
||||
JS_ASSERT(size_t(js_CodeSpec[*pc].length) == len);
|
||||
return (uintN) pc[len - 1];
|
||||
}
|
||||
|
||||
extern size_t
|
||||
GetBytecodeLength(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
static inline uintN
|
||||
GetBytecodeLength(jsbytecode *pc)
|
||||
{
|
||||
JSOp op = (JSOp)*pc;
|
||||
JS_ASSERT(op < JSOP_LIMIT);
|
||||
|
||||
if (js_CodeSpec[op].length != -1)
|
||||
return js_CodeSpec[op].length;
|
||||
return js_GetVariableBytecodeLength(pc);
|
||||
}
|
||||
|
||||
extern bool
|
||||
IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset);
|
||||
@ -554,24 +554,6 @@ FlowsIntoNext(JSOp op)
|
||||
op != JSOP_GOTO && op != JSOP_GOTOX && op != JSOP_RETSUB;
|
||||
}
|
||||
|
||||
/*
|
||||
* AutoScriptUntrapper mutates the given script in place to replace JSOP_TRAP
|
||||
* opcodes with the original opcode they replaced. The destructor mutates the
|
||||
* script back into its original state.
|
||||
*/
|
||||
class AutoScriptUntrapper
|
||||
{
|
||||
JSContext *cx;
|
||||
JSScript *origScript;
|
||||
jsbytecode *origCode;
|
||||
size_t nbytes;
|
||||
bool saveOriginal(JSScript *script);
|
||||
public:
|
||||
AutoScriptUntrapper();
|
||||
bool untrap(JSContext *cx, JSScript *script);
|
||||
~AutoScriptUntrapper();
|
||||
};
|
||||
|
||||
/*
|
||||
* Counts accumulated for a single opcode in a script. The counts tracked vary
|
||||
* between opcodes, and this structure ensures that counts are accessed in
|
||||
@ -622,7 +604,6 @@ class OpcodeCounts
|
||||
* Access ops include all name, element and property reads, as well as
|
||||
* SETELEM and SETPROP (for ElementCounts/PropertyCounts alignment).
|
||||
*/
|
||||
JS_ASSERT(op != JSOP_TRAP);
|
||||
if (op == JSOP_SETELEM || op == JSOP_SETPROP || op == JSOP_SETMETHOD)
|
||||
return true;
|
||||
int format = js_CodeSpec[op].format;
|
||||
@ -670,7 +651,6 @@ class OpcodeCounts
|
||||
};
|
||||
|
||||
static bool arithOp(JSOp op) {
|
||||
JS_ASSERT(op != JSOP_TRAP);
|
||||
return !!(js_CodeSpec[op].format & (JOF_INCDEC | JOF_ARITH));
|
||||
}
|
||||
|
||||
|
@ -232,8 +232,7 @@ OPDEF(JSOP_POP, 81, "pop", NULL, 1, 1, 0, 2, JOF_BYTE)
|
||||
/* Call a function as a constructor; operand is argc. */
|
||||
OPDEF(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, 17, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
|
||||
|
||||
/* Trap into debugger for breakpoint, etc. */
|
||||
OPDEF(JSOP_TRAP, 83, "trap", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_UNUSED1, 83, "unused1", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/* Fast get/set ops for function arguments and local variables. */
|
||||
OPDEF(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, 19, JOF_QARG |JOF_NAME)
|
||||
|
@ -42,16 +42,15 @@ namespace js {
|
||||
|
||||
class BytecodeRange {
|
||||
public:
|
||||
BytecodeRange(JSContext *cx, JSScript *script)
|
||||
: cx(cx), script(script), pc(script->code), end(pc + script->length) {}
|
||||
BytecodeRange(JSScript *script)
|
||||
: script(script), pc(script->code), end(pc + script->length) {}
|
||||
bool empty() const { return pc == end; }
|
||||
jsbytecode *frontPC() const { return pc; }
|
||||
JSOp frontOpcode() const { return js_GetOpcode(cx, script, pc); }
|
||||
JSOp frontOpcode() const { return JSOp(*pc); }
|
||||
size_t frontOffset() const { return pc - script->code; }
|
||||
void popFront() { pc += GetBytecodeLength(cx, script, pc); }
|
||||
void popFront() { pc += GetBytecodeLength(pc); }
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
JSScript *script;
|
||||
jsbytecode *pc, *end;
|
||||
};
|
||||
|
@ -120,7 +120,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *po
|
||||
*/
|
||||
jsbytecode *pc;
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
op = JSOp(*pc);
|
||||
cs = &js_CodeSpec[op];
|
||||
|
||||
if ((cs->format & JOF_SET) && obj->watched())
|
||||
@ -190,7 +190,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
|
||||
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
|
||||
JS_ASSERT(uint32(pc - script->code) < script->length);
|
||||
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
const JSCodeSpec &cs = js_CodeSpec[op];
|
||||
|
||||
obj = *objp;
|
||||
|
@ -234,8 +234,6 @@ typedef Vector<UpvarCookie, 8> UpvarCookies;
|
||||
|
||||
class Breakpoint;
|
||||
class BreakpointSite;
|
||||
typedef HashMap<jsbytecode *, BreakpointSite *, DefaultHasher<jsbytecode *>, RuntimeAllocPolicy>
|
||||
BreakpointSiteMap;
|
||||
class Debugger;
|
||||
class WatchpointMap;
|
||||
|
||||
|
@ -570,10 +570,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
*/
|
||||
oldscript = xdr->script;
|
||||
|
||||
AutoScriptUntrapper untrapper;
|
||||
if (xdr->mode == JSXDR_ENCODE && !untrapper.untrap(cx, script))
|
||||
goto error;
|
||||
|
||||
xdr->script = script;
|
||||
ok = JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode));
|
||||
|
||||
@ -746,9 +742,8 @@ JSScript::initCounts(JSContext *cx)
|
||||
|
||||
jsbytecode *pc, *next;
|
||||
for (pc = code; pc < code + length; pc = next) {
|
||||
analyze::UntrapOpcode untrap(cx, this, pc);
|
||||
count += OpcodeCounts::numCounts(JSOp(*pc));
|
||||
next = pc + analyze::GetBytecodeLength(pc);
|
||||
next = pc + GetBytecodeLength(pc);
|
||||
}
|
||||
|
||||
size_t bytes = (length * sizeof(OpcodeCounts)) + (count * sizeof(double));
|
||||
@ -762,14 +757,13 @@ JSScript::initCounts(JSContext *cx)
|
||||
cursor += length * sizeof(OpcodeCounts);
|
||||
|
||||
for (pc = code; pc < code + length; pc = next) {
|
||||
analyze::UntrapOpcode untrap(cx, this, pc);
|
||||
pcCounters.counts[pc - code].counts = (double *) cursor;
|
||||
size_t capacity = OpcodeCounts::numCounts(JSOp(*pc));
|
||||
#ifdef DEBUG
|
||||
pcCounters.counts[pc - code].capacity = capacity;
|
||||
#endif
|
||||
cursor += capacity * sizeof(double);
|
||||
next = pc + analyze::GetBytecodeLength(pc);
|
||||
next = pc + GetBytecodeLength(pc);
|
||||
}
|
||||
|
||||
JS_ASSERT(size_t(cursor - base) == bytes);
|
||||
@ -1356,6 +1350,19 @@ JSScript::finalize(JSContext *cx, bool background)
|
||||
if (sourceMap)
|
||||
cx->free_(sourceMap);
|
||||
|
||||
if (debug) {
|
||||
jsbytecode *end = code + length;
|
||||
for (jsbytecode *pc = code; pc < end; pc++) {
|
||||
if (BreakpointSite *site = getBreakpointSite(pc)) {
|
||||
/* Breakpoints are swept before finalization. */
|
||||
JS_ASSERT(site->firstBreakpoint() == NULL);
|
||||
site->clearTrap(cx, NULL, NULL);
|
||||
JS_ASSERT(getBreakpointSite(pc) == NULL);
|
||||
}
|
||||
}
|
||||
cx->free_(debug);
|
||||
}
|
||||
|
||||
#if JS_SCRIPT_INLINE_DATA_LIMIT
|
||||
if (data != inlineData)
|
||||
#endif
|
||||
@ -1452,7 +1459,7 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
* Special case: function definition needs no line number note because
|
||||
* the function's script contains its starting line number.
|
||||
*/
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
if (js_CodeSpec[op].format & JOF_INDEXBASE)
|
||||
pc += js_CodeSpec[op].length;
|
||||
if (*pc == JSOP_DEFFUN) {
|
||||
@ -1678,6 +1685,29 @@ JSScript::copyClosedSlotsTo(JSScript *other)
|
||||
memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::ensureHasDebug(JSContext *cx)
|
||||
{
|
||||
if (debug)
|
||||
return true;
|
||||
|
||||
size_t nbytes = offsetof(DebugScript, breakpoints) + length * sizeof(BreakpointSite*);
|
||||
debug = (DebugScript *) cx->calloc_(nbytes);
|
||||
if (!debug)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Ensure that any Interpret() instances running on this script have
|
||||
* interrupts enabled. The interrupts must stay enabled until the
|
||||
* debug state is destroyed.
|
||||
*/
|
||||
InterpreterFrames *frames;
|
||||
for (frames = JS_THREAD_DATA(cx)->interpreterFrames; frames; frames = frames->older)
|
||||
frames->enableInterruptsIfRunning(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::recompileForStepMode(JSContext *cx)
|
||||
{
|
||||
@ -1694,41 +1724,139 @@ JSScript::recompileForStepMode(JSContext *cx)
|
||||
bool
|
||||
JSScript::tryNewStepMode(JSContext *cx, uint32 newValue)
|
||||
{
|
||||
uint32 prior = stepMode;
|
||||
stepMode = newValue;
|
||||
JS_ASSERT(debug);
|
||||
|
||||
uint32 prior = debug->stepMode;
|
||||
debug->stepMode = newValue;
|
||||
|
||||
if (!prior != !newValue) {
|
||||
/* Step mode has been enabled or disabled. Alert the methodjit. */
|
||||
if (!recompileForStepMode(cx)) {
|
||||
stepMode = prior;
|
||||
debug->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);
|
||||
if (!stepModeEnabled() && !debug->numSites) {
|
||||
cx->free_(debug);
|
||||
debug = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::setStepModeFlag(JSContext *cx, bool step)
|
||||
{
|
||||
return tryNewStepMode(cx, (stepMode & stepCountMask) | (step ? stepFlagMask : 0));
|
||||
if (!ensureHasDebug(cx))
|
||||
return false;
|
||||
|
||||
return tryNewStepMode(cx, (debug->stepMode & stepCountMask) | (step ? stepFlagMask : 0));
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::changeStepModeCount(JSContext *cx, int delta)
|
||||
{
|
||||
if (!ensureHasDebug(cx))
|
||||
return false;
|
||||
|
||||
assertSameCompartment(cx, this);
|
||||
JS_ASSERT_IF(delta > 0, cx->compartment->debugMode());
|
||||
|
||||
uint32 count = stepMode & stepCountMask;
|
||||
uint32 count = debug->stepMode & stepCountMask;
|
||||
JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
|
||||
return tryNewStepMode(cx,
|
||||
(stepMode & stepFlagMask) |
|
||||
(debug->stepMode & stepFlagMask) |
|
||||
((count + delta) & stepCountMask));
|
||||
}
|
||||
|
||||
BreakpointSite *
|
||||
JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
|
||||
GlobalObject *scriptGlobal)
|
||||
{
|
||||
JS_ASSERT(size_t(pc - code) < length);
|
||||
|
||||
if (!ensureHasDebug(cx))
|
||||
return NULL;
|
||||
|
||||
BreakpointSite *&site = debug->breakpoints[pc - code];
|
||||
|
||||
if (!site) {
|
||||
site = cx->runtime->new_<BreakpointSite>(this, pc);
|
||||
if (!site) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
debug->numSites++;
|
||||
}
|
||||
|
||||
if (site->scriptGlobal)
|
||||
JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
|
||||
else
|
||||
site->scriptGlobal = scriptGlobal;
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::destroyBreakpointSite(JSRuntime *rt, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(unsigned(pc - code) < length);
|
||||
|
||||
BreakpointSite *&site = debug->breakpoints[pc - code];
|
||||
JS_ASSERT(site);
|
||||
|
||||
rt->delete_(site);
|
||||
site = NULL;
|
||||
|
||||
if (--debug->numSites == 0 && !stepModeEnabled()) {
|
||||
rt->free_(debug);
|
||||
debug = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
|
||||
{
|
||||
if (!hasAnyBreakpointsOrStepMode())
|
||||
return;
|
||||
|
||||
jsbytecode *end = code + length;
|
||||
for (jsbytecode *pc = code; pc < end; pc++) {
|
||||
BreakpointSite *site = getBreakpointSite(pc);
|
||||
if (site) {
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
|
||||
bp->destroy(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::clearTraps(JSContext *cx)
|
||||
{
|
||||
if (!hasAnyBreakpointsOrStepMode())
|
||||
return;
|
||||
|
||||
jsbytecode *end = code + length;
|
||||
for (jsbytecode *pc = code; pc < end; pc++) {
|
||||
BreakpointSite *site = getBreakpointSite(pc);
|
||||
if (site)
|
||||
site->clearTrap(cx);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::markTrapClosures(JSTracer *trc)
|
||||
{
|
||||
JS_ASSERT(hasAnyBreakpointsOrStepMode());
|
||||
|
||||
for (unsigned i = 0; i < length; i++) {
|
||||
BreakpointSite *site = debug->breakpoints[i];
|
||||
if (site && site->trapHandler)
|
||||
MarkValue(trc, site->trapClosure, "trap closure");
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +359,29 @@ class ScriptOpcodeCounts
|
||||
}
|
||||
};
|
||||
|
||||
class DebugScript
|
||||
{
|
||||
friend struct ::JSScript;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* Number of breakpoint sites at opcodes in the script. */
|
||||
uint32 numSites;
|
||||
|
||||
/*
|
||||
* Array with all breakpoints installed at opcodes in the script, indexed
|
||||
* by the offset of the opcode into the script.
|
||||
*/
|
||||
BreakpointSite *breakpoints[1];
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
static const uint32 JS_SCRIPT_COOKIE = 0xc00cee;
|
||||
@ -418,15 +441,6 @@ struct JSScript : public js::gc::Cell {
|
||||
uint16 nTypeSets; /* number of type sets used in this script for
|
||||
dynamic type monitoring */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
uint32 lineno; /* base line number of script */
|
||||
|
||||
uint32 mainOffset; /* offset of main entry point from code, after
|
||||
@ -513,6 +527,7 @@ struct JSScript : public js::gc::Cell {
|
||||
js::ScriptOpcodeCounts pcCounters;
|
||||
|
||||
private:
|
||||
js::DebugScript *debug;
|
||||
JSFunction *function_;
|
||||
public:
|
||||
|
||||
@ -632,7 +647,7 @@ struct JSScript : public js::gc::Cell {
|
||||
|
||||
/* Counter accessors. */
|
||||
js::OpcodeCounts getCounts(jsbytecode *pc) {
|
||||
JS_ASSERT(unsigned(pc - code) < length);
|
||||
JS_ASSERT(size_t(pc - code) < length);
|
||||
return pcCounters.counts[pc - code];
|
||||
}
|
||||
|
||||
@ -746,7 +761,28 @@ struct JSScript : public js::gc::Cell {
|
||||
/* Attempt to change this->stepMode to |newValue|. */
|
||||
bool tryNewStepMode(JSContext *cx, uint32 newValue);
|
||||
|
||||
bool ensureHasDebug(JSContext *cx);
|
||||
|
||||
public:
|
||||
bool hasBreakpointsAt(jsbytecode *pc) { return !!getBreakpointSite(pc); }
|
||||
bool hasAnyBreakpointsOrStepMode() { return !!debug; }
|
||||
|
||||
js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(size_t(pc - code) < length);
|
||||
return debug ? debug->breakpoints[pc - code] : NULL;
|
||||
}
|
||||
|
||||
js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
|
||||
js::GlobalObject *scriptGlobal);
|
||||
|
||||
void destroyBreakpointSite(JSRuntime *rt, jsbytecode *pc);
|
||||
|
||||
void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
|
||||
void clearTraps(JSContext *cx);
|
||||
|
||||
void markTrapClosures(JSTracer *trc);
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -763,10 +799,10 @@ struct JSScript : public js::gc::Cell {
|
||||
*/
|
||||
bool changeStepModeCount(JSContext *cx, int delta);
|
||||
|
||||
bool stepModeEnabled() { return !!stepMode; }
|
||||
bool stepModeEnabled() { return debug && !!debug->stepMode; }
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32 stepModeCount() { return stepMode & stepCountMask; }
|
||||
uint32 stepModeCount() { return debug ? (debug->stepMode & stepCountMask) : 0; }
|
||||
#endif
|
||||
|
||||
void finalize(JSContext *cx, bool background);
|
||||
@ -889,15 +925,6 @@ CurrentScriptFileAndLine(JSContext *cx, uintN *linenop, LineOption = NOT_CALLED_
|
||||
|
||||
}
|
||||
|
||||
static JS_INLINE JSOp
|
||||
js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JSOp op = (JSOp) *pc;
|
||||
if (op == JSOP_TRAP)
|
||||
op = JS_GetTrapOpcode(cx, script, pc);
|
||||
return op;
|
||||
}
|
||||
|
||||
extern JSScript *
|
||||
js_CloneScript(JSContext *cx, JSScript *script);
|
||||
|
||||
|
@ -119,7 +119,7 @@ inline const char *
|
||||
CurrentScriptFileAndLine(JSContext *cx, uintN *linenop, LineOption opt)
|
||||
{
|
||||
if (opt == CALLED_FROM_JSOP_EVAL) {
|
||||
JS_ASSERT(js_GetOpcode(cx, cx->fp()->script(), cx->regs().pc) == JSOP_EVAL);
|
||||
JS_ASSERT(JSOp(*cx->regs().pc) == JSOP_EVAL);
|
||||
JS_ASSERT(*(cx->regs().pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||
*linenop = GET_UINT16(cx->regs().pc + JSOP_EVAL_LENGTH);
|
||||
return cx->fp()->script()->filename;
|
||||
|
@ -2161,8 +2161,8 @@ js::str_replace(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
if (table.isObject() &&
|
||||
JSOp(*pc) == JSOP_GETARG && GET_SLOTNO(pc) == 0 &&
|
||||
JSOp(*(pc + JSOP_GETARG_LENGTH)) == JSOP_GETELEM &&
|
||||
JSOp(*(pc + JSOP_GETARG_LENGTH + JSOP_GETELEM_LENGTH)) == JSOP_RETURN) {
|
||||
JSOp(pc[JSOP_GETARG_LENGTH]) == JSOP_GETELEM &&
|
||||
JSOp(pc[JSOP_GETARG_LENGTH + JSOP_GETELEM_LENGTH]) == JSOP_RETURN) {
|
||||
Class *clasp = table.toObject().getClass();
|
||||
if (clasp->isNative() &&
|
||||
!clasp->ops.lookupProperty &&
|
||||
|
@ -242,7 +242,7 @@ mjit::Compiler::scanInlineCalls(uint32 index, uint32 depth)
|
||||
while (nextOffset < script->length) {
|
||||
uint32 offset = nextOffset;
|
||||
jsbytecode *pc = script->code + offset;
|
||||
nextOffset = offset + analyze::GetBytecodeLength(pc);
|
||||
nextOffset = offset + GetBytecodeLength(pc);
|
||||
|
||||
Bytecode *code = analysis->maybeCode(pc);
|
||||
if (!code)
|
||||
@ -958,12 +958,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
size_t nNmapLive = loopEntries.length();
|
||||
for (size_t i = 0; i < script->length; i++) {
|
||||
Bytecode *opinfo = analysis->maybeCode(i);
|
||||
if (opinfo && opinfo->safePoint) {
|
||||
/* loopEntries cover any safe points which are at loop heads. */
|
||||
JSOp op = js_GetOpcode(cx, script, script->code + i);
|
||||
if (!cx->typeInferenceEnabled() || op != JSOP_LOOPHEAD)
|
||||
nNmapLive++;
|
||||
}
|
||||
if (opinfo && opinfo->safePoint)
|
||||
nNmapLive++;
|
||||
}
|
||||
|
||||
/* Please keep in sync with JITScript::scriptDataSize! */
|
||||
@ -1024,9 +1020,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
for (size_t i = 0; i < script->length; i++) {
|
||||
Bytecode *opinfo = analysis->maybeCode(i);
|
||||
if (opinfo && opinfo->safePoint) {
|
||||
JSOp op = js_GetOpcode(cx, script, script->code + i);
|
||||
if (cx->typeInferenceEnabled() && op == JSOP_LOOPHEAD)
|
||||
continue;
|
||||
Label L = jumpMap[i];
|
||||
JS_ASSERT(L.isSet());
|
||||
jitNmap[ix].bcOff = i;
|
||||
@ -1511,7 +1504,6 @@ FixDouble(Value &val)
|
||||
CompileStatus
|
||||
mjit::Compiler::generateMethod()
|
||||
{
|
||||
mjit::AutoScriptRetrapper trapper(cx, script);
|
||||
SrcNoteLineScanner scanner(script->notes(), script->lineno);
|
||||
|
||||
/* For join points, whether there was fallthrough from the previous opcode. */
|
||||
@ -1523,12 +1515,9 @@ mjit::Compiler::generateMethod()
|
||||
for (;;) {
|
||||
JSOp op = JSOp(*PC);
|
||||
int trap = stubs::JSTRAP_NONE;
|
||||
if (op == JSOP_TRAP) {
|
||||
if (!trapper.untrap(PC))
|
||||
return Compile_Error;
|
||||
op = JSOp(*PC);
|
||||
|
||||
if (script->hasBreakpointsAt(PC))
|
||||
trap |= stubs::JSTRAP_TRAP;
|
||||
}
|
||||
|
||||
Bytecode *opinfo = analysis->maybeCode(PC);
|
||||
|
||||
@ -1737,7 +1726,7 @@ mjit::Compiler::generateMethod()
|
||||
*/
|
||||
jsbytecode *next = PC + js_CodeSpec[op].length;
|
||||
if (cx->typeInferenceEnabled() && analysis->maybeCode(next) &&
|
||||
js_GetOpcode(cx, script, next) == JSOP_LOOPHEAD) {
|
||||
JSOp(*next) == JSOP_LOOPHEAD) {
|
||||
frame.syncAndForgetEverything();
|
||||
Jump j = masm.jump();
|
||||
if (!startLoop(next, j, target))
|
||||
@ -2845,7 +2834,7 @@ mjit::Compiler::generateMethod()
|
||||
* END COMPILER OPS *
|
||||
**********************/
|
||||
|
||||
if (cx->typeInferenceEnabled() && PC == lastPC + analyze::GetBytecodeLength(lastPC)) {
|
||||
if (cx->typeInferenceEnabled() && PC == lastPC + GetBytecodeLength(lastPC)) {
|
||||
/*
|
||||
* Inform the frame of the type sets for values just pushed. Skip
|
||||
* this if we did any opcode fusions, we don't keep track of the
|
||||
@ -2869,7 +2858,7 @@ mjit::Compiler::generateMethod()
|
||||
/* Update information about the type of value pushed by arithmetic ops. */
|
||||
if ((js_CodeSpec[op].format & JOF_ARITH) && !arithUpdated) {
|
||||
FrameEntry *pushed = NULL;
|
||||
if (PC == lastPC + analyze::GetBytecodeLength(lastPC))
|
||||
if (PC == lastPC + GetBytecodeLength(lastPC))
|
||||
pushed = frame.peek(-1);
|
||||
updateArithCounters(lastPC, pushed, arithFirstUseType, arithSecondUseType);
|
||||
typesUpdated = true;
|
||||
@ -3413,7 +3402,7 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
||||
bool endOfScript =
|
||||
(JSOp(*PC) == JSOP_STOP) ||
|
||||
(JSOp(*PC) == JSOP_RETURN &&
|
||||
(JSOp(*(PC + JSOP_RETURN_LENGTH)) == JSOP_STOP &&
|
||||
(JSOp(PC[JSOP_RETURN_LENGTH]) == JSOP_STOP &&
|
||||
!analysis->maybeCode(PC + JSOP_RETURN_LENGTH)));
|
||||
if (!endOfScript)
|
||||
a->returnJumps->append(masm.jump());
|
||||
|
@ -580,7 +580,7 @@ FrameState::computeAllocation(jsbytecode *target)
|
||||
return NULL;
|
||||
|
||||
if (a->analysis->getCode(target).exceptionEntry || a->analysis->getCode(target).switchTarget ||
|
||||
JSOp(*target) == JSOP_TRAP) {
|
||||
a->script->hasBreakpointsAt(target)) {
|
||||
/* State must be synced at exception and switch targets, and at traps. */
|
||||
#ifdef DEBUG
|
||||
if (IsJaegerSpewChannelActive(JSpew_Regalloc)) {
|
||||
|
@ -118,7 +118,7 @@ top:
|
||||
|
||||
switch (tn->kind) {
|
||||
case JSTRY_CATCH:
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK);
|
||||
JS_ASSERT(JSOp(*pc) == JSOP_ENTERBLOCK);
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
/* Catch cannot intercept the closing of a generator. */
|
||||
@ -154,7 +154,7 @@ top:
|
||||
* pending exception.
|
||||
*/
|
||||
Value v = cx->getPendingException();
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER);
|
||||
JS_ASSERT(JSOp(*pc) == JSOP_ENDITER);
|
||||
cx->clearPendingException();
|
||||
ok = !!js_CloseIterator(cx, &cx->regs().sp[-1].toObject());
|
||||
cx->regs().sp -= 1;
|
||||
@ -179,7 +179,7 @@ InlineReturn(VMFrame &f)
|
||||
JS_ASSERT(!IsActiveWithOrBlock(f.cx, f.fp()->scopeChain(), 0));
|
||||
f.cx->stack.popInlineFrame(f.regs);
|
||||
|
||||
DebugOnly<JSOp> op = js_GetOpcode(f.cx, f.fp()->script(), f.regs.pc);
|
||||
DebugOnly<JSOp> op = JSOp(*f.regs.pc);
|
||||
JS_ASSERT(op == JSOP_CALL ||
|
||||
op == JSOP_NEW ||
|
||||
op == JSOP_EVAL ||
|
||||
@ -628,12 +628,12 @@ js_InternalThrow(VMFrame &f)
|
||||
* it to immediately rethrow.
|
||||
*/
|
||||
if (cx->isExceptionPending()) {
|
||||
JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK);
|
||||
JS_ASSERT(JSOp(*pc) == JSOP_ENTERBLOCK);
|
||||
JSObject *obj = script->getObject(GET_SLOTNO(pc));
|
||||
Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj);
|
||||
SetValueRangeToUndefined(cx->regs().sp, vp);
|
||||
cx->regs().sp = vp;
|
||||
JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION);
|
||||
JS_ASSERT(JSOp(pc[JSOP_ENTERBLOCK_LENGTH]) == JSOP_EXCEPTION);
|
||||
cx->regs().sp[0] = cx->getPendingException();
|
||||
cx->clearPendingException();
|
||||
cx->regs().sp++;
|
||||
@ -715,7 +715,7 @@ FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp)
|
||||
|
||||
JSContext *cx = f.cx;
|
||||
|
||||
JSOp op = js_GetOpcode(cx, f.script(), f.pc());
|
||||
JSOp op = JSOp(*f.pc());
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
|
||||
unsigned i = GET_SLOTNO(f.pc());
|
||||
@ -752,7 +752,6 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
JSScript *script = fp->script();
|
||||
|
||||
jsbytecode *pc = f.regs.pc;
|
||||
analyze::UntrapOpcode untrap(cx, script, pc);
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
@ -773,7 +772,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
Value *oldsp = f.regs.sp;
|
||||
f.regs.sp = fp->base() + analysis->getCode(pc).stackDepth;
|
||||
|
||||
jsbytecode *nextpc = pc + analyze::GetBytecodeLength(pc);
|
||||
jsbytecode *nextpc = pc + GetBytecodeLength(pc);
|
||||
Value *nextsp = NULL;
|
||||
if (nextpc != script->code + script->length && analysis->maybeCode(nextpc))
|
||||
nextsp = fp->base() + analysis->getCode(nextpc).stackDepth;
|
||||
@ -798,7 +797,6 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
JS_ASSERT(cs->format & (JOF_LOCAL | JOF_QARG));
|
||||
|
||||
nextDepth = analysis->getCode(nextpc).stackDepth;
|
||||
untrap.retrap();
|
||||
enter.leave();
|
||||
|
||||
if (rejoin != REJOIN_BINARY || !analysis->incrementInitialValueObserved(pc)) {
|
||||
@ -842,9 +840,9 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
case REJOIN_TRAP:
|
||||
/*
|
||||
* Make sure when resuming in the interpreter we do not execute the
|
||||
* trap again. Watch out for the case where the TRAP removed itself.
|
||||
* trap again. Watch out for the case where the trap removed itself.
|
||||
*/
|
||||
if (untrap.trap)
|
||||
if (script->hasBreakpointsAt(pc))
|
||||
skipTrap = true;
|
||||
break;
|
||||
|
||||
@ -1010,7 +1008,6 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
case REJOIN_CALL_SPLAT: {
|
||||
/* Leave analysis early and do the Invoke which SplatApplyArgs prepared. */
|
||||
nextDepth = analysis->getCode(nextpc).stackDepth;
|
||||
untrap.retrap();
|
||||
enter.leave();
|
||||
f.regs.sp = nextsp + 2 + f.u.call.dynamicArgc;
|
||||
if (!InvokeKernel(cx, CallArgsFromSp(f.u.call.dynamicArgc, f.regs.sp)))
|
||||
@ -1101,7 +1098,6 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
* cannot trigger recompilation.
|
||||
*/
|
||||
bool takeBranch = false;
|
||||
analyze::UntrapOpcode untrap(cx, script, nextpc);
|
||||
switch (JSOp(*nextpc)) {
|
||||
case JSOP_IFNE:
|
||||
case JSOP_IFNEX:
|
||||
@ -1117,7 +1113,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
if (takeBranch)
|
||||
f.regs.pc = nextpc + analyze::GetJumpOffset(nextpc, nextpc);
|
||||
else
|
||||
f.regs.pc = nextpc + analyze::GetBytecodeLength(nextpc);
|
||||
f.regs.pc = nextpc + GetBytecodeLength(nextpc);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1788,7 +1788,7 @@ LoopState::analyzeLoopBody(unsigned frame)
|
||||
unsigned offset = start;
|
||||
while (offset < end) {
|
||||
jsbytecode *pc = script->code + offset;
|
||||
uint32 successorOffset = offset + analyze::GetBytecodeLength(pc);
|
||||
uint32 successorOffset = offset + GetBytecodeLength(pc);
|
||||
|
||||
analyze::Bytecode *opinfo = analysis->maybeCode(offset);
|
||||
if (!opinfo) {
|
||||
|
@ -1740,7 +1740,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||
if (!prop) {
|
||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||
if (kind == ic::PICInfo::NAME) {
|
||||
JSOp op2 = js_GetOpcode(cx, f.script(), f.pc() + JSOP_NAME_LENGTH);
|
||||
JSOp op2 = JSOp(f.pc()[JSOP_NAME_LENGTH]);
|
||||
if (op2 == JSOP_TYPEOF) {
|
||||
vp->setUndefined();
|
||||
return true;
|
||||
|
@ -60,24 +60,6 @@ using namespace js::mjit;
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
AutoScriptRetrapper::~AutoScriptRetrapper()
|
||||
{
|
||||
while (!traps.empty()) {
|
||||
jsbytecode *pc = traps.back();
|
||||
traps.popBack();
|
||||
*pc = JSOP_TRAP;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AutoScriptRetrapper::untrap(jsbytecode *pc)
|
||||
{
|
||||
if (!traps.append(pc))
|
||||
return false;
|
||||
*pc = JS_GetTrapOpcode(traps.allocPolicy().context(), script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline JSRejoinState ScriptedRejoin(uint32 pcOffset)
|
||||
{
|
||||
return REJOIN_SCRIPTED | (pcOffset << 1);
|
||||
|
@ -54,26 +54,6 @@
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
/*
|
||||
* A problem often arises where, for one reason or another, a piece of code
|
||||
* wants to touch the script->code, but isn't expecting JSOP_TRAP. This allows
|
||||
* one to temporarily remove JSOP_TRAPs from the instruction stream (without
|
||||
* copying) and automatically re-add them on scope exit.
|
||||
*/
|
||||
class AutoScriptRetrapper
|
||||
{
|
||||
public:
|
||||
AutoScriptRetrapper(JSContext *cx, JSScript *script1) :
|
||||
script(script1), traps(cx) {};
|
||||
~AutoScriptRetrapper();
|
||||
|
||||
bool untrap(jsbytecode *pc);
|
||||
|
||||
private:
|
||||
JSScript *script;
|
||||
Vector<jsbytecode*> traps;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class is responsible for sanely destroying a JITed script while frames
|
||||
* for it are still on the stack, removing all references in the world to it
|
||||
|
@ -300,7 +300,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname)
|
||||
return NULL;
|
||||
if (!prop) {
|
||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||
JSOp op2 = js_GetOpcode(cx, f.script(), f.pc() + JSOP_NAME_LENGTH);
|
||||
JSOp op2 = JSOp(f.pc()[JSOP_NAME_LENGTH]);
|
||||
if (op2 == JSOP_TYPEOF) {
|
||||
f.regs.sp++;
|
||||
f.regs.sp[-1].setUndefined();
|
||||
@ -1467,7 +1467,7 @@ InlineGetProp(VMFrame &f)
|
||||
Value *vp = &f.regs.sp[-1];
|
||||
|
||||
if (vp->isMagic(JS_LAZY_ARGUMENTS)) {
|
||||
JS_ASSERT(js_GetOpcode(cx, f.script(), f.pc()) == JSOP_LENGTH);
|
||||
JS_ASSERT(JSOp(*f.pc()) == JSOP_LENGTH);
|
||||
regs.sp[-1] = Int32Value(regs.fp()->numActualArgs());
|
||||
return true;
|
||||
}
|
||||
|
@ -1812,7 +1812,7 @@ UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset,
|
||||
jsint low, high, n;
|
||||
|
||||
pc = script->code + offset;
|
||||
op = js_GetOpcode(cx, script, pc);
|
||||
op = JSOp(*pc);
|
||||
switch (op) {
|
||||
case JSOP_TABLESWITCHX:
|
||||
jmplen = JUMPX_OFFSET_LEN;
|
||||
@ -1871,7 +1871,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
|
||||
if (switchTableStart <= offset && offset < switchTableEnd) {
|
||||
name = "case";
|
||||
} else {
|
||||
JSOp op = js_GetOpcode(cx, script, script->code + offset);
|
||||
JSOp op = JSOp(script->code[offset]);
|
||||
JS_ASSERT(op == JSOP_LABEL || op == JSOP_LABELX);
|
||||
}
|
||||
}
|
||||
@ -1930,7 +1930,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
|
||||
break;
|
||||
}
|
||||
case SRC_SWITCH: {
|
||||
JSOp op = js_GetOpcode(cx, script, script->code + offset);
|
||||
JSOp op = JSOp(script->code[offset]);
|
||||
if (op == JSOP_GOTO || op == JSOP_GOTOX)
|
||||
break;
|
||||
Sprint(sp, " length %u", uintN(js_GetSrcNoteOffset(sn, 0)));
|
||||
|
@ -125,10 +125,10 @@ ReportObjectRequired(JSContext *cx)
|
||||
/*** Breakpoints *********************************************************************************/
|
||||
|
||||
BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc)
|
||||
: script(script), pc(pc), realOpcode(JSOp(*pc)), scriptGlobal(NULL), enabledCount(0),
|
||||
: script(script), pc(pc), scriptGlobal(NULL), enabledCount(0),
|
||||
trapHandler(NULL), trapClosure(UndefinedValue())
|
||||
{
|
||||
JS_ASSERT(realOpcode != JSOP_TRAP);
|
||||
JS_ASSERT(!script->hasBreakpointsAt(pc));
|
||||
JS_INIT_CLIST(&breakpoints);
|
||||
}
|
||||
|
||||
@ -176,12 +176,8 @@ bool
|
||||
BreakpointSite::inc(JSContext *cx)
|
||||
{
|
||||
if (enabledCount == 0 && !trapHandler) {
|
||||
JS_ASSERT(*pc == realOpcode);
|
||||
*pc = JSOP_TRAP;
|
||||
if (!recompile(cx, false)) {
|
||||
*pc = realOpcode;
|
||||
if (!recompile(cx, false))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
enabledCount++;
|
||||
return true;
|
||||
@ -191,23 +187,17 @@ void
|
||||
BreakpointSite::dec(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(enabledCount > 0);
|
||||
JS_ASSERT(*pc == JSOP_TRAP);
|
||||
enabledCount--;
|
||||
if (enabledCount == 0 && !trapHandler) {
|
||||
*pc = realOpcode;
|
||||
if (enabledCount == 0 && !trapHandler)
|
||||
recompile(cx, false); /* ignore failure */
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BreakpointSite::setTrap(JSContext *cx, JSTrapHandler handler, const Value &closure)
|
||||
{
|
||||
if (enabledCount == 0) {
|
||||
*pc = JSOP_TRAP;
|
||||
if (!recompile(cx, true)) {
|
||||
*pc = realOpcode;
|
||||
if (!recompile(cx, true))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
trapHandler = handler;
|
||||
trapClosure = closure;
|
||||
@ -215,8 +205,7 @@ BreakpointSite::setTrap(JSContext *cx, JSTrapHandler handler, const Value &closu
|
||||
}
|
||||
|
||||
void
|
||||
BreakpointSite::clearTrap(JSContext *cx, BreakpointSiteMap::Enum *e,
|
||||
JSTrapHandler *handlerp, Value *closurep)
|
||||
BreakpointSite::clearTrap(JSContext *cx, JSTrapHandler *handlerp, Value *closurep)
|
||||
{
|
||||
if (handlerp)
|
||||
*handlerp = trapHandler;
|
||||
@ -226,25 +215,19 @@ BreakpointSite::clearTrap(JSContext *cx, BreakpointSiteMap::Enum *e,
|
||||
trapHandler = NULL;
|
||||
trapClosure = UndefinedValue();
|
||||
if (enabledCount == 0) {
|
||||
*pc = realOpcode;
|
||||
if (!cx->runtime->gcRunning) {
|
||||
/* If the GC is running then the script is being destroyed. */
|
||||
recompile(cx, true); /* ignore failure */
|
||||
}
|
||||
destroyIfEmpty(cx->runtime, e);
|
||||
destroyIfEmpty(cx->runtime);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BreakpointSite::destroyIfEmpty(JSRuntime *rt, BreakpointSiteMap::Enum *e)
|
||||
BreakpointSite::destroyIfEmpty(JSRuntime *rt)
|
||||
{
|
||||
if (JS_CLIST_IS_EMPTY(&breakpoints) && !trapHandler) {
|
||||
if (e)
|
||||
e->removeFront();
|
||||
else
|
||||
script->compartment()->breakpointSites.remove(pc);
|
||||
rt->delete_(this);
|
||||
}
|
||||
if (JS_CLIST_IS_EMPTY(&breakpoints) && !trapHandler)
|
||||
script->destroyBreakpointSite(rt, pc);
|
||||
}
|
||||
|
||||
Breakpoint *
|
||||
@ -284,14 +267,14 @@ Breakpoint::fromSiteLinks(JSCList *links)
|
||||
}
|
||||
|
||||
void
|
||||
Breakpoint::destroy(JSContext *cx, BreakpointSiteMap::Enum *e)
|
||||
Breakpoint::destroy(JSContext *cx)
|
||||
{
|
||||
if (debugger->enabled)
|
||||
site->dec(cx);
|
||||
JS_REMOVE_LINK(&debuggerLinks);
|
||||
JS_REMOVE_LINK(&siteLinks);
|
||||
JSRuntime *rt = cx->runtime;
|
||||
site->destroyIfEmpty(rt, e);
|
||||
site->destroyIfEmpty(rt);
|
||||
rt->delete_(this);
|
||||
}
|
||||
|
||||
@ -482,7 +465,7 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx)
|
||||
*/
|
||||
if (fp->isEvalFrame()) {
|
||||
JSScript *script = fp->script();
|
||||
script->compartment()->clearBreakpointsIn(cx, NULL, script, NULL);
|
||||
script->clearBreakpointsIn(cx, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -861,10 +844,11 @@ JSTrapStatus
|
||||
Debugger::onTrap(JSContext *cx, Value *vp)
|
||||
{
|
||||
StackFrame *fp = cx->fp();
|
||||
JSScript *script = fp->script();
|
||||
GlobalObject *scriptGlobal = fp->scopeChain().getGlobal();
|
||||
jsbytecode *pc = cx->regs().pc;
|
||||
BreakpointSite *site = cx->compartment->getBreakpointSite(pc);
|
||||
JSOp op = site->realOpcode;
|
||||
BreakpointSite *site = script->getBreakpointSite(pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
|
||||
/* Build list of breakpoint handlers. */
|
||||
Vector<Breakpoint *> triggered(cx);
|
||||
@ -896,7 +880,7 @@ Debugger::onTrap(JSContext *cx, Value *vp)
|
||||
return st;
|
||||
|
||||
/* Calling JS code invalidates site. Reload it. */
|
||||
site = cx->compartment->getBreakpointSite(pc);
|
||||
site = script->getBreakpointSite(pc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1104,10 +1088,6 @@ Debugger::markAllIteratively(GCMarker *trc)
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
|
||||
JSCompartment *dc = *c;
|
||||
|
||||
/* If dc is being collected, mark jsdbgapi.h trap closures in it. */
|
||||
if (!comp || dc == comp)
|
||||
markedAny = markedAny | dc->markTrapClosuresIteratively(trc);
|
||||
|
||||
/*
|
||||
* If this is a single-compartment GC, no compartment can debug itself, so skip
|
||||
* |comp|. If it's a global GC, then search every compartment.
|
||||
@ -1571,7 +1551,7 @@ Debugger::clearAllBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "clearAllBreakpoints", args, dbg);
|
||||
for (GlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront())
|
||||
r.front()->compartment()->clearBreakpointsIn(cx, dbg, NULL, NULL);
|
||||
r.front()->compartment()->clearBreakpointsIn(cx, dbg, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1988,8 +1968,8 @@ class BytecodeRangeWithLineNumbers : private BytecodeRange
|
||||
using BytecodeRange::frontOpcode;
|
||||
using BytecodeRange::frontOffset;
|
||||
|
||||
BytecodeRangeWithLineNumbers(JSContext *cx, JSScript *script)
|
||||
: BytecodeRange(cx, script), lineno(script->lineno), sn(script->notes()), snpc(script->code)
|
||||
BytecodeRangeWithLineNumbers(JSScript *script)
|
||||
: BytecodeRange(script), lineno(script->lineno), sn(script->notes()), snpc(script->code)
|
||||
{
|
||||
if (!SN_IS_TERMINATOR(sn))
|
||||
snpc += SN_DELTA(sn);
|
||||
@ -2076,7 +2056,7 @@ class FlowGraphSummary : public Vector<size_t> {
|
||||
|
||||
size_t prevLine = script->lineno;
|
||||
JSOp prevOp = JSOP_NOP;
|
||||
for (BytecodeRangeWithLineNumbers r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRangeWithLineNumbers r(script); !r.empty(); r.popFront()) {
|
||||
size_t lineno = r.frontLineNumber();
|
||||
JSOp op = r.frontOpcode();
|
||||
|
||||
@ -2145,7 +2125,7 @@ DebuggerScript_getAllOffsets(JSContext *cx, uintN argc, Value *vp)
|
||||
JSObject *result = NewDenseEmptyArray(cx);
|
||||
if (!result)
|
||||
return false;
|
||||
for (BytecodeRangeWithLineNumbers r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRangeWithLineNumbers r(script); !r.empty(); r.popFront()) {
|
||||
size_t offset = r.frontOffset();
|
||||
size_t lineno = r.frontLineNumber();
|
||||
|
||||
@ -2217,7 +2197,7 @@ DebuggerScript_getLineOffsets(JSContext *cx, uintN argc, Value *vp)
|
||||
JSObject *result = NewDenseEmptyArray(cx);
|
||||
if (!result)
|
||||
return false;
|
||||
for (BytecodeRangeWithLineNumbers r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRangeWithLineNumbers r(script); !r.empty(); r.popFront()) {
|
||||
size_t offset = r.frontOffset();
|
||||
|
||||
/* If the op at offset is an entry point, append offset to result. */
|
||||
@ -2255,9 +2235,8 @@ DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!handler)
|
||||
return false;
|
||||
|
||||
JSCompartment *comp = script->compartment();
|
||||
jsbytecode *pc = script->code + offset;
|
||||
BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, scriptGlobal);
|
||||
BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, scriptGlobal);
|
||||
if (!site)
|
||||
return false;
|
||||
if (site->inc(cx)) {
|
||||
@ -2267,7 +2246,7 @@ DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
}
|
||||
site->dec(cx);
|
||||
}
|
||||
site->destroyIfEmpty(cx->runtime, NULL);
|
||||
site->destroyIfEmpty(cx->runtime);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2290,10 +2269,10 @@ DebuggerScript_getBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
JSObject *arr = NewDenseEmptyArray(cx);
|
||||
if (!arr)
|
||||
return false;
|
||||
JSCompartment *comp = script->compartment();
|
||||
for (BreakpointSiteMap::Range r = comp->breakpointSites.all(); !r.empty(); r.popFront()) {
|
||||
BreakpointSite *site = r.front().value;
|
||||
if (site->script == script && (!pc || site->pc == pc)) {
|
||||
|
||||
for (unsigned i = 0; i < script->length; i++) {
|
||||
BreakpointSite *site = script->getBreakpointSite(script->code + i);
|
||||
if (site && (!pc || site->pc == pc)) {
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = bp->nextInSite()) {
|
||||
if (bp->debugger == dbg &&
|
||||
!js_NewbornArrayPush(cx, arr, ObjectValue(*bp->getHandler())))
|
||||
@ -2318,7 +2297,7 @@ DebuggerScript_clearBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!handler)
|
||||
return false;
|
||||
|
||||
script->compartment()->clearBreakpointsIn(cx, dbg, script, handler);
|
||||
script->clearBreakpointsIn(cx, dbg, handler);
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
@ -2328,7 +2307,7 @@ DebuggerScript_clearAllBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "clearAllBreakpoints", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
script->compartment()->clearBreakpointsIn(cx, dbg, script, NULL);
|
||||
script->clearBreakpointsIn(cx, dbg, NULL);
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
@ -345,12 +345,12 @@ class Debugger {
|
||||
class BreakpointSite {
|
||||
friend class Breakpoint;
|
||||
friend struct ::JSCompartment;
|
||||
friend struct ::JSScript;
|
||||
friend class Debugger;
|
||||
|
||||
public:
|
||||
JSScript * const script;
|
||||
jsbytecode * const pc;
|
||||
const JSOp realOpcode;
|
||||
|
||||
private:
|
||||
/*
|
||||
@ -377,9 +377,8 @@ class BreakpointSite {
|
||||
bool inc(JSContext *cx);
|
||||
void dec(JSContext *cx);
|
||||
bool setTrap(JSContext *cx, JSTrapHandler handler, const Value &closure);
|
||||
void clearTrap(JSContext *cx, BreakpointSiteMap::Enum *e = NULL,
|
||||
JSTrapHandler *handlerp = NULL, Value *closurep = NULL);
|
||||
void destroyIfEmpty(JSRuntime *rt, BreakpointSiteMap::Enum *e);
|
||||
void clearTrap(JSContext *cx, JSTrapHandler *handlerp = NULL, Value *closurep = NULL);
|
||||
void destroyIfEmpty(JSRuntime *rt);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -416,7 +415,7 @@ class Breakpoint {
|
||||
static Breakpoint *fromDebuggerLinks(JSCList *links);
|
||||
static Breakpoint *fromSiteLinks(JSCList *links);
|
||||
Breakpoint(Debugger *debugger, BreakpointSite *site, JSObject *handler);
|
||||
void destroy(JSContext *cx, BreakpointSiteMap::Enum *e = NULL);
|
||||
void destroy(JSContext *cx);
|
||||
Breakpoint *nextInDebugger();
|
||||
Breakpoint *nextInSite();
|
||||
const HeapPtrObject &getHandler() const { return handler; }
|
||||
@ -486,7 +485,10 @@ Debugger::onEnterFrame(JSContext *cx, Value *vp)
|
||||
void
|
||||
Debugger::onLeaveFrame(JSContext *cx)
|
||||
{
|
||||
if (!cx->compartment->getDebuggees().empty() || !cx->compartment->breakpointSites.empty())
|
||||
/* Traps must be cleared from eval frames, see slowPathOnLeaveFrame. */
|
||||
bool evalTraps = cx->fp()->isEvalFrame() &&
|
||||
cx->fp()->script()->hasAnyBreakpointsOrStepMode();
|
||||
if (!cx->compartment->getDebuggees().empty() || evalTraps)
|
||||
slowPathOnLeaveFrame(cx);
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1042,7 @@ StackIter::settleOnNewState()
|
||||
* (see SplatApplyArgs), there is no efficient way to know how to
|
||||
* find the callee. Thus, calls to apply are lost completely.
|
||||
*/
|
||||
JSOp op = js_GetOpcode(cx_, fp_->script(), pc_);
|
||||
JSOp op = JSOp(*pc_);
|
||||
if (op == JSOP_CALL || op == JSOP_FUNCALL) {
|
||||
uintN argc = GET_ARGC(pc_);
|
||||
DebugOnly<uintN> spoff = sp_ - fp_->base();
|
||||
|
Loading…
Reference in New Issue
Block a user