Remove JSOP_TRAP, bug 707454. r=jorendorff

This commit is contained in:
Brian Hackett 2011-12-07 13:15:48 -08:00
parent 870029947d
commit 16bb64e5ea
33 changed files with 407 additions and 602 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -959,6 +959,9 @@ MarkChildren(JSTracer *trc, JSScript *script)
if (script->types)
script->types->trace(trc);
if (script->hasAnyBreakpointsOrStepMode())
script->markTrapClosures(trc);
}
const Shape *

View File

@ -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;

View File

@ -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, &regs.sp[-1].toObject());

View File

@ -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 {

View File

@ -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;

View File

@ -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));
}

View File

@ -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)

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -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");
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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 &&

View File

@ -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());

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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)));

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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();