Bug 829554 - Abstract ScopeIter/DebugScopeProxy frame access. r=luke

--HG--
extra : rebase_source : 18cc0baea68fb9b91b32c54bedcac6eb805449e3
This commit is contained in:
Jan de Mooij 2013-01-12 10:40:46 +01:00
parent cf1257b075
commit 3f4c90b945
8 changed files with 378 additions and 190 deletions

View File

@ -282,6 +282,11 @@ class CompartmentChecker
if (fp)
check(fp->scopeChain());
}
void check(TaggedFramePtr frame) {
if (frame)
check(frame.scopeChain());
}
};
#endif /* JS_CRASH_DIAGNOSTICS */

View File

@ -2714,9 +2714,9 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
*/
if (i.isIon())
continue;
StackFrame *fp = i.interpFrame();
if (fp->isFunctionFrame() && fp->script() == script) {
ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, fp);
TaggedFramePtr frame = i.taggedFramePtr();
if (frame.isFunctionFrame() && frame.script() == script) {
ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, frame);
if (!argsobj) {
/*
* We can't leave stack frames with script->needsArgsObj but no
@ -2728,8 +2728,8 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
}
/* Note: 'arguments' may have already been overwritten. */
if (fp->unaliasedLocal(var).isMagic(JS_OPTIMIZED_ARGUMENTS))
fp->unaliasedLocal(var) = ObjectValue(*argsobj);
if (frame.unaliasedLocal(var).isMagic(JS_OPTIMIZED_ARGUMENTS))
frame.unaliasedLocal(var) = ObjectValue(*argsobj);
}
}

View File

@ -23,22 +23,22 @@ using namespace js;
using namespace js::gc;
static void
CopyStackFrameArguments(const StackFrame *fp, HeapValue *dst)
CopyStackFrameArguments(const TaggedFramePtr frame, HeapValue *dst)
{
JS_ASSERT(!fp->runningInIon());
JS_ASSERT_IF(frame.isStackFrame(), !frame.asStackFrame()->runningInIon());
unsigned numActuals = fp->numActualArgs();
unsigned numFormals = fp->callee().nargs;
unsigned numActuals = frame.numActualArgs();
unsigned numFormals = frame.callee().nargs;
/* Copy formal arguments. */
Value *src = fp->formals();
Value *src = frame.formals();
Value *end = src + numFormals;
while (src != end)
(dst++)->init(*src++);
/* Copy actual argument which are not contignous. */
if (numFormals < numActuals) {
src = fp->actuals() + numFormals;
src = frame.actuals() + numFormals;
end = src + (numActuals - numFormals);
while (src != end)
(dst++)->init(*src++);
@ -46,26 +46,26 @@ CopyStackFrameArguments(const StackFrame *fp, HeapValue *dst)
}
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(StackFrame *fp, JSObject *obj, ArgumentsData *data)
ArgumentsObject::MaybeForwardToCallObject(TaggedFramePtr frame, JSObject *obj, ArgumentsData *data)
{
UnrootedScript script = fp->script();
if (fp->fun()->isHeavyweight() && script->argsObjAliasesFormals()) {
obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(fp->callObj()));
UnrootedScript script = frame.script();
if (frame.fun()->isHeavyweight() && script->argsObjAliasesFormals()) {
obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
for (AliasedFormalIter fi(script); fi; fi++)
data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
}
}
struct CopyStackFrameArgs
struct CopyFrameArgs
{
StackFrame *fp_;
TaggedFramePtr frame_;
CopyStackFrameArgs(StackFrame *fp)
: fp_(fp)
CopyFrameArgs(TaggedFramePtr frame)
: frame_(frame)
{ }
void copyArgs(HeapValue *dst) const {
CopyStackFrameArguments(fp_, dst);
CopyStackFrameArguments(frame_, dst);
}
/*
@ -73,7 +73,7 @@ struct CopyStackFrameArgs
* call object is the canonical location for formals.
*/
void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
ArgumentsObject::MaybeForwardToCallObject(fp_, obj, data);
ArgumentsObject::MaybeForwardToCallObject(frame_, obj, data);
}
};
@ -87,7 +87,7 @@ struct CopyStackIterArgs
void copyArgs(HeapValue *dstBase) const {
if (!iter_.isIon()) {
CopyStackFrameArguments(iter_.interpFrame(), dstBase);
CopyStackFrameArguments(iter_.taggedFramePtr(), dstBase);
return;
}
@ -110,7 +110,7 @@ struct CopyStackIterArgs
*/
void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
if (!iter_.isIon())
ArgumentsObject::MaybeForwardToCallObject(iter_.interpFrame(), obj, data);
ArgumentsObject::MaybeForwardToCallObject(iter_.taggedFramePtr(), obj, data);
}
};
@ -176,17 +176,17 @@ ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction calle
}
ArgumentsObject *
ArgumentsObject::createExpected(JSContext *cx, StackFrame *fp)
ArgumentsObject::createExpected(JSContext *cx, TaggedFramePtr frame)
{
JS_ASSERT(fp->script()->needsArgsObj());
RootedScript script(cx, fp->script());
RootedFunction callee(cx, &fp->callee());
CopyStackFrameArgs copy(fp);
ArgumentsObject *argsobj = create(cx, script, callee, fp->numActualArgs(), copy);
JS_ASSERT(frame.script()->needsArgsObj());
RootedScript script(cx, frame.script());
RootedFunction callee(cx, &frame.callee());
CopyFrameArgs copy(frame);
ArgumentsObject *argsobj = create(cx, script, callee, frame.numActualArgs(), copy);
if (!argsobj)
return NULL;
fp->initArgsObj(*argsobj);
frame.initArgsObj(*argsobj);
return argsobj;
}
@ -200,12 +200,12 @@ ArgumentsObject::createUnexpected(JSContext *cx, StackIter &iter)
}
ArgumentsObject *
ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp)
ArgumentsObject::createUnexpected(JSContext *cx, TaggedFramePtr frame)
{
RootedScript script(cx, fp->script());
RootedFunction callee(cx, &fp->callee());
CopyStackFrameArgs copy(fp);
return create(cx, script, callee, fp->numActualArgs(), copy);
RootedScript script(cx, frame.script());
RootedFunction callee(cx, &frame.callee());
CopyFrameArgs copy(frame);
return create(cx, script, callee, frame.numActualArgs(), copy);
}
static JSBool

View File

@ -114,7 +114,7 @@ class ArgumentsObject : public JSObject
static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4;
/* Create an arguments object for a frame that is expecting them. */
static ArgumentsObject *createExpected(JSContext *cx, StackFrame *fp);
static ArgumentsObject *createExpected(JSContext *cx, TaggedFramePtr frame);
/*
* Purposefully disconnect the returned arguments object from the frame
@ -123,7 +123,7 @@ class ArgumentsObject : public JSObject
* not aliased and generally simplifies arguments objects.
*/
static ArgumentsObject *createUnexpected(JSContext *cx, StackIter &iter);
static ArgumentsObject *createUnexpected(JSContext *cx, StackFrame *fp);
static ArgumentsObject *createUnexpected(JSContext *cx, TaggedFramePtr frame);
/*
* Return the initial length of the arguments. This may differ from the
@ -202,7 +202,7 @@ class ArgumentsObject : public JSObject
return getFixedSlotOffset(DATA_SLOT);
}
static void MaybeForwardToCallObject(StackFrame *fp, JSObject *obj, ArgumentsData *data);
static void MaybeForwardToCallObject(TaggedFramePtr frame, JSObject *obj, ArgumentsData *data);
};
class NormalArgumentsObject : public ArgumentsObject

View File

@ -3360,7 +3360,7 @@ DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
Rooted<Env*> env(cx);
{
AutoCompartment ac(cx, iter.scopeChain());
env = GetDebugScopeForFrame(cx, iter.interpFrame());
env = GetDebugScopeForFrame(cx, iter.taggedFramePtr());
if (!env)
return false;
}
@ -3777,7 +3777,7 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
if (!iter->computeThis())
return false;
thisv = iter->thisv();
env = GetDebugScopeForFrame(cx, iter->interpFrame());
env = GetDebugScopeForFrame(cx, iter->taggedFramePtr());
if (!env)
return false;
} else {

View File

@ -220,22 +220,22 @@ CallObject::createForFunction(JSContext *cx, HandleObject enclosing, HandleFunct
}
CallObject *
CallObject::createForFunction(JSContext *cx, StackFrame *fp)
CallObject::createForFunction(JSContext *cx, TaggedFramePtr frame)
{
AssertCanGC();
JS_ASSERT(fp->isNonEvalFunctionFrame());
assertSameCompartment(cx, fp);
JS_ASSERT(frame.isNonEvalFunctionFrame());
assertSameCompartment(cx, frame);
RootedObject scopeChain(cx, fp->scopeChain());
RootedFunction callee(cx, &fp->callee());
RootedObject scopeChain(cx, frame.scopeChain());
RootedFunction callee(cx, &frame.callee());
CallObject *callobj = createForFunction(cx, scopeChain, callee);
if (!callobj)
return NULL;
/* Copy in the closed-over formal arguments. */
for (AliasedFormalIter i(fp->script()); i; i++)
callobj->setAliasedVar(i, fp->unaliasedFormal(i.frameIndex(), DONT_CHECK_ALIASING));
for (AliasedFormalIter i(frame.script()); i; i++)
callobj->setAliasedVar(i, frame.unaliasedFormal(i.frameIndex(), DONT_CHECK_ALIASING));
return callobj;
}
@ -611,9 +611,9 @@ Class js::WithClass = {
/*****************************************************************************/
ClonedBlockObject *
ClonedBlockObject::create(JSContext *cx, Handle<StaticBlockObject *> block, StackFrame *fp)
ClonedBlockObject::create(JSContext *cx, Handle<StaticBlockObject *> block, TaggedFramePtr frame)
{
assertSameCompartment(cx, fp);
assertSameCompartment(cx, frame);
RootedTypeObject type(cx, block->getNewType(cx));
if (!type)
@ -630,9 +630,9 @@ ClonedBlockObject::create(JSContext *cx, Handle<StaticBlockObject *> block, Stac
return NULL;
/* Set the parent if necessary, as for call objects. */
if (&fp->global() != obj->getParent()) {
if (&frame.scopeChain()->global() != obj->getParent()) {
JS_ASSERT(obj->getParent() == NULL);
Rooted<GlobalObject*> global(cx, &fp->global());
Rooted<GlobalObject*> global(cx, &frame.scopeChain()->global());
if (!JSObject::setParent(cx, obj, global))
return NULL;
}
@ -640,18 +640,18 @@ ClonedBlockObject::create(JSContext *cx, Handle<StaticBlockObject *> block, Stac
JS_ASSERT(!obj->inDictionaryMode());
JS_ASSERT(obj->slotSpan() >= block->slotCount() + RESERVED_SLOTS);
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*fp->scopeChain()));
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*frame.scopeChain()));
obj->setReservedSlot(DEPTH_SLOT, PrivateUint32Value(block->stackDepth()));
/*
* Copy in the closed-over locals. Closed-over locals don't need
* any fixup since the initial value is 'undefined'.
*/
Value *src = fp->base() + block->stackDepth();
unsigned nslots = block->slotCount();
for (unsigned i = 0; i < nslots; ++i, ++src) {
unsigned base = frame.script()->nfixed + block->stackDepth();
for (unsigned i = 0; i < nslots; ++i) {
if (block->isAliased(i))
obj->asClonedBlock().setVar(i, *src);
obj->asClonedBlock().setVar(i, frame.unaliasedLocal(base + i));
}
JS_ASSERT(obj->isDelegate());
@ -660,14 +660,14 @@ ClonedBlockObject::create(JSContext *cx, Handle<StaticBlockObject *> block, Stac
}
void
ClonedBlockObject::copyUnaliasedValues(StackFrame *fp)
ClonedBlockObject::copyUnaliasedValues(TaggedFramePtr frame)
{
AutoAssertNoGC nogc;
StaticBlockObject &block = staticBlock();
unsigned base = fp->script()->nfixed + block.stackDepth();
unsigned base = frame.script()->nfixed + block.stackDepth();
for (unsigned i = 0; i < slotCount(); ++i) {
if (!block.isAliased(i))
setVar(i, fp->unaliasedLocal(base + i), DONT_CHECK_ALIASING);
setVar(i, frame.unaliasedLocal(base + i), DONT_CHECK_ALIASING);
}
}
@ -881,7 +881,7 @@ js::CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handle<St
ScopeIter::ScopeIter(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: fp_(NULL),
: frame_(),
cur_(cx, reinterpret_cast<JSObject *>(-1)),
block_(cx, reinterpret_cast<StaticBlockObject *>(-1)),
type_(Type(-1))
@ -891,7 +891,7 @@ ScopeIter::ScopeIter(JSContext *cx
ScopeIter::ScopeIter(const ScopeIter &si, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: fp_(si.fp_),
: frame_(si.frame_),
cur_(cx, si.cur_),
block_(cx, si.block_),
type_(si.type_),
@ -902,7 +902,7 @@ ScopeIter::ScopeIter(const ScopeIter &si, JSContext *cx
ScopeIter::ScopeIter(JSObject &enclosingScope, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: fp_(NULL),
: frame_(),
cur_(cx, &enclosingScope),
block_(cx, reinterpret_cast<StaticBlockObject *>(-1)),
type_(Type(-1))
@ -910,20 +910,20 @@ ScopeIter::ScopeIter(JSObject &enclosingScope, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
ScopeIter::ScopeIter(StackFrame *fp, JSContext *cx
ScopeIter::ScopeIter(TaggedFramePtr frame, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: fp_(fp),
cur_(cx, fp->scopeChain()),
block_(cx, fp->maybeBlockChain())
: frame_(frame),
cur_(cx, frame.scopeChain()),
block_(cx, frame.maybeBlockChain())
{
assertSameCompartment(cx, fp);
assertSameCompartment(cx, frame);
settle();
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
ScopeIter::ScopeIter(const ScopeIter &si, StackFrame *fp, JSContext *cx
ScopeIter::ScopeIter(const ScopeIter &si, TaggedFramePtr frame, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: fp_(fp),
: frame_(frame),
cur_(cx, si.cur_),
block_(cx, si.block_),
type_(si.type_),
@ -932,9 +932,9 @@ ScopeIter::ScopeIter(const ScopeIter &si, StackFrame *fp, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
ScopeIter::ScopeIter(StackFrame *fp, ScopeObject &scope, JSContext *cx
ScopeIter::ScopeIter(TaggedFramePtr frame, ScopeObject &scope, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: fp_(fp),
: frame_(frame),
cur_(cx, &scope),
block_(cx)
{
@ -954,7 +954,7 @@ ScopeIter::ScopeIter(StackFrame *fp, ScopeObject &scope, JSContext *cx
* determine the block (if any) that encloses 'scope'.
*/
if (cur_->isNestedScope()) {
block_ = fp->maybeBlockChain();
block_ = frame.maybeBlockChain();
while (block_) {
if (block_->stackDepth() <= cur_->asNestedScope().stackDepth())
break;
@ -983,10 +983,10 @@ ScopeIter::operator++()
case Call:
if (hasScopeObject_) {
cur_ = &cur_->asCall().enclosingScope();
if (CallObjectLambdaName(*fp_->fun()))
if (CallObjectLambdaName(*frame_.fun()))
cur_ = &cur_->asDeclEnv().enclosingScope();
}
fp_ = NULL;
frame_ = TaggedFramePtr();
break;
case Block:
block_ = block_->enclosingBlock();
@ -1002,7 +1002,7 @@ ScopeIter::operator++()
case StrictEvalScope:
if (hasScopeObject_)
cur_ = &cur_->asCall().enclosingScope();
fp_ = NULL;
frame_ = TaggedFramePtr();
break;
}
return *this;
@ -1035,7 +1035,7 @@ ScopeIter::settle()
* ever introduced as the *enclosing* scope of a frame, they should never
* show up in scope iteration and fall into the final non-scope case.
*/
if (fp_->isNonEvalFunctionFrame() && !fp_->fun()->isHeavyweight()) {
if (frame_.isNonEvalFunctionFrame() && !frame_.fun()->isHeavyweight()) {
if (block_) {
type_ = Block;
hasScopeObject_ = block_->needsClone();
@ -1043,22 +1043,22 @@ ScopeIter::settle()
type_ = Call;
hasScopeObject_ = false;
}
} else if (fp_->isNonStrictDirectEvalFrame() && cur_ == fp_->prev()->scopeChain()) {
} else if (frame_.isNonStrictDirectEvalFrame() && cur_ == frame_.evalPrev().scopeChain()) {
if (block_) {
JS_ASSERT(!block_->needsClone());
type_ = Block;
hasScopeObject_ = false;
} else {
fp_ = NULL;
frame_ = TaggedFramePtr();
}
} else if (fp_->isNonEvalFunctionFrame() && !fp_->hasCallObj()) {
JS_ASSERT(cur_ == fp_->fun()->environment());
fp_ = NULL;
} else if (fp_->isStrictEvalFrame() && !fp_->hasCallObj()) {
JS_ASSERT(cur_ == fp_->prev()->scopeChain());
fp_ = NULL;
} else if (frame_.isNonEvalFunctionFrame() && !frame_.hasCallObj()) {
JS_ASSERT(cur_ == frame_.fun()->environment());
frame_ = TaggedFramePtr();
} else if (frame_.isStrictEvalFrame() && !frame_.hasCallObj()) {
JS_ASSERT(cur_ == frame_.evalPrev().scopeChain());
frame_ = TaggedFramePtr();
} else if (cur_->isWith()) {
JS_ASSERT_IF(fp_->isFunctionFrame(), fp_->fun()->isHeavyweight());
JS_ASSERT_IF(frame_.isFunctionFrame(), frame_.fun()->isHeavyweight());
JS_ASSERT_IF(block_, block_->needsClone());
JS_ASSERT_IF(block_, block_->stackDepth() < cur_->asWith().stackDepth());
type_ = With;
@ -1071,11 +1071,11 @@ ScopeIter::settle()
CallObject &callobj = cur_->asCall();
type_ = callobj.isForEval() ? StrictEvalScope : Call;
hasScopeObject_ = true;
JS_ASSERT_IF(type_ == Call, callobj.callee().nonLazyScript() == fp_->script());
JS_ASSERT_IF(type_ == Call, callobj.callee().nonLazyScript() == frame_.script());
} else {
JS_ASSERT(!cur_->isScope());
JS_ASSERT(fp_->isGlobalFrame() || fp_->isDebuggerFrame());
fp_ = NULL;
JS_ASSERT(frame_.isGlobalFrame() || frame_.isDebuggerFrame());
frame_ = TaggedFramePtr();
}
}
@ -1083,15 +1083,15 @@ ScopeIter::settle()
ScopeIterKey::hash(ScopeIterKey si)
{
/* hasScopeObject_ is determined by the other fields. */
return size_t(si.fp_) ^ size_t(si.cur_) ^ size_t(si.block_) ^ si.type_;
return size_t(si.frame_.raw()) ^ size_t(si.cur_) ^ size_t(si.block_) ^ si.type_;
}
/* static */ bool
ScopeIterKey::match(ScopeIterKey si1, ScopeIterKey si2)
{
/* hasScopeObject_ is determined by the other fields. */
return si1.fp_ == si2.fp_ &&
(!si1.fp_ ||
return si1.frame_ == si2.frame_ &&
(!si1.frame_ ||
(si1.cur_ == si2.cur_ &&
si1.block_ == si2.block_ &&
si1.type_ == si2.type_));
@ -1148,7 +1148,7 @@ class DebugScopeProxy : public BaseProxyHandler
jsid id, Action action, Value *vp)
{
JS_ASSERT(&debugScope->scope() == scope);
StackFrame *maybefp = DebugScopes::hasLiveFrame(*scope);
TaggedFramePtr maybeframe = DebugScopes::hasLiveFrame(*scope);
/* Handle unaliased formals, vars, and consts at function scope. */
if (scope->isCall() && !scope->asCall().isForEval()) {
@ -1169,11 +1169,11 @@ class DebugScopeProxy : public BaseProxyHandler
if (script->varIsAliased(i))
return false;
if (maybefp) {
if (maybeframe) {
if (action == GET)
*vp = maybefp->unaliasedVar(i);
*vp = maybeframe.unaliasedVar(i);
else
maybefp->unaliasedVar(i) = *vp;
maybeframe.unaliasedVar(i) = *vp;
} else if (JSObject *snapshot = debugScope->maybeSnapshot()) {
if (action == GET)
*vp = snapshot->getDenseElement(bindings.numArgs() + i);
@ -1194,17 +1194,17 @@ class DebugScopeProxy : public BaseProxyHandler
if (script->formalIsAliased(i))
return false;
if (maybefp) {
if (script->argsObjAliasesFormals() && maybefp->hasArgsObj()) {
if (maybeframe) {
if (script->argsObjAliasesFormals() && maybeframe.hasArgsObj()) {
if (action == GET)
*vp = maybefp->argsObj().arg(i);
*vp = maybeframe.argsObj().arg(i);
else
maybefp->argsObj().setArg(i, *vp);
maybeframe.argsObj().setArg(i, *vp);
} else {
if (action == GET)
*vp = maybefp->unaliasedFormal(i, DONT_CHECK_ALIASING);
*vp = maybeframe.unaliasedFormal(i, DONT_CHECK_ALIASING);
else
maybefp->unaliasedFormal(i, DONT_CHECK_ALIASING) = *vp;
maybeframe.unaliasedFormal(i, DONT_CHECK_ALIASING) = *vp;
}
} else if (JSObject *snapshot = debugScope->maybeSnapshot()) {
if (action == GET)
@ -1236,13 +1236,13 @@ class DebugScopeProxy : public BaseProxyHandler
if (block->staticBlock().isAliased(i))
return false;
if (maybefp) {
UnrootedScript script = maybefp->script();
if (maybeframe) {
UnrootedScript script = maybeframe.script();
unsigned local = block->slotToLocalIndex(script->bindings, shape->slot());
if (action == GET)
*vp = maybefp->unaliasedLocal(local);
*vp = maybeframe.unaliasedLocal(local);
else
maybefp->unaliasedLocal(local) = *vp;
maybeframe.unaliasedLocal(local) = *vp;
JS_ASSERT(analyze::LocalSlot(script, local) >= analyze::TotalSlots(script));
} else {
if (action == GET)
@ -1299,14 +1299,14 @@ class DebugScopeProxy : public BaseProxyHandler
if (scope.asCall().callee().nonLazyScript()->needsArgsObj())
return true;
StackFrame *maybefp = DebugScopes::hasLiveFrame(scope);
if (!maybefp) {
TaggedFramePtr maybeframe = DebugScopes::hasLiveFrame(scope);
if (!maybeframe) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_LIVE,
"Debugger scope");
return false;
}
*maybeArgsObj = ArgumentsObject::createUnexpected(cx, maybefp);
*maybeArgsObj = ArgumentsObject::createUnexpected(cx, maybeframe);
return true;
}
@ -1597,7 +1597,7 @@ DebugScopes::sweep(JSRuntime *rt)
for (LiveScopeMap::Enum e(liveScopes); !e.empty(); e.popFront()) {
ScopeObject *scope = e.front().key;
StackFrame *fp = e.front().value;
TaggedFramePtr frame = e.front().value;
/*
* Scopes can be finalized when a debugger-synthesized ScopeObject is
@ -1613,7 +1613,7 @@ DebugScopes::sweep(JSRuntime *rt)
* suspended generator frames. Since a generator can be finalized while
* its scope is live, we must explicitly detect finalized generators.
*/
if (JSGenerator *gen = fp->maybeSuspendedGenerator(rt)) {
if (JSGenerator *gen = frame.maybeSuspendedGenerator(rt)) {
JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
if (IsObjectAboutToBeFinalized(&gen->obj)) {
e.removeFront();
@ -1725,7 +1725,7 @@ DebugScopes::addDebugScope(JSContext *cx, const ScopeIter &si, DebugScopeObject
}
JS_ASSERT(!scopes->liveScopes.has(&debugScope.scope()));
if (!scopes->liveScopes.put(&debugScope.scope(), si.fp())) {
if (!scopes->liveScopes.put(&debugScope.scope(), si.frame())) {
js_ReportOutOfMemory(cx);
return false;
}
@ -1734,10 +1734,10 @@ DebugScopes::addDebugScope(JSContext *cx, const ScopeIter &si, DebugScopeObject
}
void
DebugScopes::onPopCall(StackFrame *fp, JSContext *cx)
DebugScopes::onPopCall(TaggedFramePtr frame, JSContext *cx)
{
JS_ASSERT(!fp->isYielding());
assertSameCompartment(cx, fp);
JS_ASSERT(!frame.isYielding());
assertSameCompartment(cx, frame);
DebugScopes *scopes = cx->compartment->debugScopes;
if (!scopes)
@ -1745,20 +1745,20 @@ DebugScopes::onPopCall(StackFrame *fp, JSContext *cx)
Rooted<DebugScopeObject*> debugScope(cx, NULL);
if (fp->fun()->isHeavyweight()) {
if (frame.fun()->isHeavyweight()) {
/*
* The StackFrame may be observed before the prologue has created the
* CallObject. See ScopeIter::settle.
*/
if (!fp->hasCallObj())
if (!frame.hasCallObj())
return;
CallObject &callobj = fp->scopeChain()->asCall();
CallObject &callobj = frame.scopeChain()->asCall();
scopes->liveScopes.remove(&callobj);
if (ObjectWeakMap::Ptr p = scopes->proxiedScopes.lookup(&callobj))
debugScope = &p->value->asDebugScope();
} else {
ScopeIter si(fp, cx);
ScopeIter si(frame, cx);
if (MissingScopeMap::Ptr p = scopes->missingScopes.lookup(si)) {
debugScope = p->value;
scopes->liveScopes.remove(&debugScope->scope().asCall());
@ -1783,18 +1783,18 @@ DebugScopes::onPopCall(StackFrame *fp, JSContext *cx)
* but it simplifies later indexing logic.
*/
AutoValueVector vec(cx);
if (!fp->copyRawFrameSlots(&vec) || vec.length() == 0)
if (!frame.copyRawFrameSlots(&vec) || vec.length() == 0)
return;
/*
* Copy in formals that are not aliased via the scope chain
* but are aliased via the arguments object.
*/
RootedScript script(cx, fp->script());
if (script->needsArgsObj() && fp->hasArgsObj()) {
for (unsigned i = 0; i < fp->numFormalArgs(); ++i) {
RootedScript script(cx, frame.script());
if (script->needsArgsObj() && frame.hasArgsObj()) {
for (unsigned i = 0; i < frame.numFormalArgs(); ++i) {
if (script->formalLivesInArgumentsObject(i))
vec[i] = fp->argsObj().arg(i);
vec[i] = frame.argsObj().arg(i);
}
}
@ -1813,24 +1813,24 @@ DebugScopes::onPopCall(StackFrame *fp, JSContext *cx)
}
void
DebugScopes::onPopBlock(JSContext *cx, StackFrame *fp)
DebugScopes::onPopBlock(JSContext *cx, TaggedFramePtr frame)
{
assertSameCompartment(cx, fp);
assertSameCompartment(cx, frame);
DebugScopes *scopes = cx->compartment->debugScopes;
if (!scopes)
return;
StaticBlockObject &staticBlock = *fp->maybeBlockChain();
StaticBlockObject &staticBlock = *frame.maybeBlockChain();
if (staticBlock.needsClone()) {
ClonedBlockObject &clone = fp->scopeChain()->asClonedBlock();
clone.copyUnaliasedValues(fp);
ClonedBlockObject &clone = frame.scopeChain()->asClonedBlock();
clone.copyUnaliasedValues(frame);
scopes->liveScopes.remove(&clone);
} else {
ScopeIter si(fp, cx);
ScopeIter si(frame, cx);
if (MissingScopeMap::Ptr p = scopes->missingScopes.lookup(si)) {
ClonedBlockObject &clone = p->value->scope().asClonedBlock();
clone.copyUnaliasedValues(fp);
clone.copyUnaliasedValues(frame);
scopes->liveScopes.remove(&clone);
scopes->missingScopes.remove(p);
}
@ -1838,17 +1838,17 @@ DebugScopes::onPopBlock(JSContext *cx, StackFrame *fp)
}
void
DebugScopes::onPopWith(StackFrame *fp)
DebugScopes::onPopWith(TaggedFramePtr frame)
{
DebugScopes *scopes = fp->compartment()->debugScopes;
DebugScopes *scopes = frame.compartment()->debugScopes;
if (scopes)
scopes->liveScopes.remove(&fp->scopeChain()->asWith());
scopes->liveScopes.remove(&frame.scopeChain()->asWith());
}
void
DebugScopes::onPopStrictEvalScope(StackFrame *fp)
DebugScopes::onPopStrictEvalScope(TaggedFramePtr frame)
{
DebugScopes *scopes = fp->compartment()->debugScopes;
DebugScopes *scopes = frame.compartment()->debugScopes;
if (!scopes)
return;
@ -1856,12 +1856,12 @@ DebugScopes::onPopStrictEvalScope(StackFrame *fp)
* The StackFrame may be observed before the prologue has created the
* CallObject. See ScopeIter::settle.
*/
if (fp->hasCallObj())
scopes->liveScopes.remove(&fp->scopeChain()->asCall());
if (frame.hasCallObj())
scopes->liveScopes.remove(&frame.scopeChain()->asCall());
}
void
DebugScopes::onGeneratorFrameChange(StackFrame *from, StackFrame *to, JSContext *cx)
DebugScopes::onGeneratorFrameChange(TaggedFramePtr from, TaggedFramePtr to, JSContext *cx)
{
for (ScopeIter toIter(to, cx); !toIter.done(); ++toIter) {
DebugScopes *scopes = ensureCompartmentData(cx);
@ -1884,7 +1884,7 @@ DebugScopes::onGeneratorFrameChange(StackFrame *from, StackFrame *to, JSContext
scopes->liveScopes.add(livePtr, &toIter.scope(), to); // OOM here?
} else {
ScopeIter si(toIter, from, cx);
JS_ASSERT(si.fp()->compartment() == cx->compartment);
JS_ASSERT(si.frame().scopeChain()->compartment() == cx->compartment);
if (MissingScopeMap::Ptr p = scopes->missingScopes.lookup(si)) {
DebugScopeObject &debugScope = *p->value;
scopes->liveScopes.lookup(&debugScope.scope())->value = to;
@ -1930,39 +1930,39 @@ DebugScopes::updateLiveScopes(JSContext *cx)
if (i.isIon())
continue;
StackFrame *fp = i.interpFrame();
if (fp->scopeChain()->compartment() != cx->compartment)
TaggedFramePtr frame = i.taggedFramePtr();
if (frame.scopeChain()->compartment() != cx->compartment)
continue;
for (ScopeIter si(fp, cx); !si.done(); ++si) {
for (ScopeIter si(frame, cx); !si.done(); ++si) {
if (si.hasScopeObject()) {
JS_ASSERT(si.scope().compartment() == cx->compartment);
DebugScopes *scopes = ensureCompartmentData(cx);
if (!scopes)
return false;
if (!scopes->liveScopes.put(&si.scope(), fp))
if (!scopes->liveScopes.put(&si.scope(), frame))
return false;
}
}
if (fp->prevUpToDate())
if (frame.prevUpToDate())
return true;
JS_ASSERT(fp->compartment()->debugMode());
fp->setPrevUpToDate();
JS_ASSERT(frame.scopeChain()->compartment()->debugMode());
frame.setPrevUpToDate();
}
return true;
}
StackFrame *
TaggedFramePtr
DebugScopes::hasLiveFrame(ScopeObject &scope)
{
DebugScopes *scopes = scope.compartment()->debugScopes;
if (!scopes)
return NULL;
return TaggedFramePtr();
if (LiveScopeMap::Ptr p = scopes->liveScopes.lookup(&scope)) {
StackFrame *fp = p->value;
TaggedFramePtr frame = p->value;
/*
* Since liveScopes is effectively a weak pointer, we need a read
@ -1975,12 +1975,12 @@ DebugScopes::hasLiveFrame(ScopeObject &scope)
* 4. GC completes, live objects may now point to values that weren't
* marked and thus may point to swept GC things
*/
if (JSGenerator *gen = fp->maybeSuspendedGenerator(scope.compartment()->rt))
if (JSGenerator *gen = frame.maybeSuspendedGenerator(scope.compartment()->rt))
JSObject::readBarrier(gen->obj);
return fp;
return frame;
}
return NULL;
return TaggedFramePtr();
}
/*****************************************************************************/
@ -2041,7 +2041,7 @@ GetDebugScopeForMissing(JSContext *cx, const ScopeIter &si)
DebugScopeObject *debugScope = NULL;
switch (si.type()) {
case ScopeIter::Call: {
Rooted<CallObject*> callobj(cx, CallObject::createForFunction(cx, si.fp()));
Rooted<CallObject*> callobj(cx, CallObject::createForFunction(cx, si.frame()));
if (!callobj)
return NULL;
@ -2058,7 +2058,7 @@ GetDebugScopeForMissing(JSContext *cx, const ScopeIter &si)
}
case ScopeIter::Block: {
Rooted<StaticBlockObject *> staticBlock(cx, &si.staticBlock());
ClonedBlockObject *block = ClonedBlockObject::create(cx, staticBlock, si.fp());
ClonedBlockObject *block = ClonedBlockObject::create(cx, staticBlock, si.frame());
if (!block)
return NULL;
@ -2097,8 +2097,8 @@ GetDebugScope(JSContext *cx, JSObject &obj)
}
Rooted<ScopeObject*> scope(cx, &obj.asScope());
if (StackFrame *fp = DebugScopes::hasLiveFrame(*scope)) {
ScopeIter si(fp, *scope, cx);
if (TaggedFramePtr frame = DebugScopes::hasLiveFrame(*scope)) {
ScopeIter si(frame, *scope, cx);
return GetDebugScope(cx, si);
}
ScopeIter si(scope->enclosingScope(), cx);
@ -2133,11 +2133,11 @@ js::GetDebugScopeForFunction(JSContext *cx, JSFunction *fun)
}
JSObject *
js::GetDebugScopeForFrame(JSContext *cx, StackFrame *fp)
js::GetDebugScopeForFrame(JSContext *cx, TaggedFramePtr frame)
{
assertSameCompartment(cx, fp);
assertSameCompartment(cx, frame);
if (CanUseDebugScopeMaps(cx) && !DebugScopes::updateLiveScopes(cx))
return NULL;
ScopeIter si(fp, cx);
ScopeIter si(frame, cx);
return GetDebugScope(cx, si);
}

View File

@ -197,7 +197,7 @@ class CallObject : public ScopeObject
static CallObject *createForFunction(JSContext *cx, HandleObject enclosing, HandleFunction callee);
static CallObject *createForFunction(JSContext *cx, StackFrame *fp);
static CallObject *createForFunction(JSContext *cx, TaggedFramePtr frame);
static CallObject *createForStrictEval(JSContext *cx, StackFrame *fp);
/* True if this is for a strict mode eval frame. */
@ -356,7 +356,7 @@ class ClonedBlockObject : public BlockObject
{
public:
static ClonedBlockObject *create(JSContext *cx, Handle<StaticBlockObject *> block,
StackFrame *fp);
TaggedFramePtr frame);
/* The static block from which this block was cloned. */
StaticBlockObject &staticBlock() const;
@ -366,7 +366,7 @@ class ClonedBlockObject : public BlockObject
void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
/* Copy in all the unaliased formals and locals. */
void copyUnaliasedValues(StackFrame *fp);
void copyUnaliasedValues(TaggedFramePtr frame);
};
template<XDRMode mode>
@ -402,7 +402,7 @@ class ScopeIter
enum Type { Call, Block, With, StrictEvalScope };
private:
StackFrame *fp_;
TaggedFramePtr frame_;
RootedObject cur_;
Rooted<StaticBlockObject *> block_;
Type type_;
@ -423,7 +423,7 @@ class ScopeIter
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
/* Constructing from StackFrame places ScopeIter on the innermost scope. */
explicit ScopeIter(StackFrame *fp, JSContext *cx
explicit ScopeIter(TaggedFramePtr frame, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
/*
@ -437,14 +437,14 @@ class ScopeIter
* For the special case of generators, copy the given ScopeIter, with 'fp'
* as the StackFrame instead of si.fp(). Not for general use.
*/
ScopeIter(const ScopeIter &si, StackFrame *fp, JSContext *cx
ScopeIter(const ScopeIter &si, TaggedFramePtr frame, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
/* Like ScopeIter(StackFrame *) except start at 'scope'. */
ScopeIter(StackFrame *fp, ScopeObject &scope, JSContext *cx
ScopeIter(TaggedFramePtr frame, ScopeObject &scope, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
bool done() const { return !fp_; }
bool done() const { return !frame_; }
/* If done(): */
@ -454,7 +454,7 @@ class ScopeIter
ScopeIter &operator++();
StackFrame *fp() const { JS_ASSERT(!done()); return fp_; }
TaggedFramePtr frame() const { JS_ASSERT(!done()); return frame_; }
Type type() const { JS_ASSERT(!done()); return type_; }
bool hasScopeObject() const { JS_ASSERT(!done()); return hasScopeObject_; }
ScopeObject &scope() const;
@ -466,18 +466,18 @@ class ScopeIter
class ScopeIterKey
{
StackFrame *fp_;
TaggedFramePtr frame_;
JSObject *cur_;
StaticBlockObject *block_;
ScopeIter::Type type_;
public:
ScopeIterKey() : fp_(NULL), cur_(NULL), block_(NULL), type_() {}
ScopeIterKey() : frame_(), cur_(NULL), block_(NULL), type_() {}
ScopeIterKey(const ScopeIter &si)
: fp_(si.fp_), cur_(si.cur_), block_(si.block_), type_(si.type_)
: frame_(si.frame_), cur_(si.cur_), block_(si.block_), type_(si.type_)
{}
StackFrame *fp() const { return fp_; }
TaggedFramePtr frame() const { return frame_; }
ScopeIter::Type type() const { return type_; }
/* For use as hash policy */
@ -517,7 +517,7 @@ extern JSObject *
GetDebugScopeForFunction(JSContext *cx, JSFunction *fun);
extern JSObject *
GetDebugScopeForFrame(JSContext *cx, StackFrame *fp);
GetDebugScopeForFrame(JSContext *cx, TaggedFramePtr frame);
/* Provides debugger access to a scope. */
class DebugScopeObject : public JSObject
@ -573,7 +573,7 @@ class DebugScopes
* updates of liveScopes need only fill in the new scopes.
*/
typedef HashMap<ScopeObject *,
StackFrame *,
TaggedFramePtr,
DefaultHasher<ScopeObject *>,
RuntimeAllocPolicy> LiveScopeMap;
LiveScopeMap liveScopes;
@ -598,17 +598,17 @@ class DebugScopes
static bool addDebugScope(JSContext *cx, const ScopeIter &si, DebugScopeObject &debugScope);
static bool updateLiveScopes(JSContext *cx);
static StackFrame *hasLiveFrame(ScopeObject &scope);
static TaggedFramePtr hasLiveFrame(ScopeObject &scope);
/*
* In debug-mode, these must be called whenever exiting a call/block or
* when activating/yielding a generator.
*/
static void onPopCall(StackFrame *fp, JSContext *cx);
static void onPopBlock(JSContext *cx, StackFrame *fp);
static void onPopWith(StackFrame *fp);
static void onPopStrictEvalScope(StackFrame *fp);
static void onGeneratorFrameChange(StackFrame *from, StackFrame *to, JSContext *cx);
static void onPopCall(TaggedFramePtr frame, JSContext *cx);
static void onPopBlock(JSContext *cx, TaggedFramePtr frame);
static void onPopWith(TaggedFramePtr frame);
static void onPopStrictEvalScope(TaggedFramePtr frame);
static void onGeneratorFrameChange(TaggedFramePtr from, TaggedFramePtr to, JSContext *cx);
static void onCompartmentLeaveDebugMode(JSCompartment *c);
};

View File

@ -1712,6 +1712,17 @@ class TaggedFramePtr
{
uintptr_t ptr_;
public:
TaggedFramePtr()
: ptr_(0)
{}
TaggedFramePtr(StackFrame *fp)
: ptr_(uintptr_t(fp) | 0x1)
{
JS_ASSERT(fp);
}
bool isStackFrame() const {
return ptr_ & 0x1;
}
@ -1723,28 +1734,200 @@ class TaggedFramePtr
return res;
}
public:
TaggedFramePtr()
: ptr_(0)
{}
explicit TaggedFramePtr(StackFrame *fp)
: ptr_(uintptr_t(fp) | 0x1)
{
JS_ASSERT(fp);
}
void *raw() const { return reinterpret_cast<void *>(ptr_); }
bool operator ==(const TaggedFramePtr &other) const { return ptr_ == other.ptr_; }
bool operator !=(const TaggedFramePtr &other) const { return ptr_ != other.ptr_; }
operator bool() const { return !!ptr_; }
JSGenerator *maybeSuspendedGenerator(JSRuntime *rt) const {
if (isStackFrame())
return asStackFrame()->maybeSuspendedGenerator(rt);
return NULL;
}
JSObject *scopeChain() const {
if (isStackFrame())
return asStackFrame()->scopeChain();
return NULL;
}
JSCompartment *compartment() const {
return scopeChain()->compartment();
}
StaticBlockObject *maybeBlockChain() const {
if (isStackFrame())
return asStackFrame()->maybeBlockChain();
return NULL;
}
bool hasCallObj() const {
if (isStackFrame())
return asStackFrame()->hasCallObj();
JS_NOT_REACHED("Invalid frame");
return false;
}
CallObject &callObj() const {
if (isStackFrame())
return asStackFrame()->callObj();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->callObj();
}
bool isGeneratorFrame() const {
if (isStackFrame())
return asStackFrame()->isGeneratorFrame();
return false;
}
bool isYielding() const {
if (isStackFrame())
return asStackFrame()->isYielding();
return false;
}
bool isFunctionFrame() const {
if (isStackFrame())
return asStackFrame()->isFunctionFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isGlobalFrame() const {
if (isStackFrame())
return asStackFrame()->isGlobalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isEvalFrame() const {
if (isStackFrame())
return asStackFrame()->isEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isDebuggerFrame() const {
if (isStackFrame())
return asStackFrame()->isDebuggerFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
JSScript *script() const {
if (isStackFrame())
return asStackFrame()->script();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
UnrootedFunction fun() const {
if (isStackFrame())
return asStackFrame()->fun();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
JSFunction &callee() const {
if (isStackFrame())
return asStackFrame()->callee();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->callee();
}
bool isNonEvalFunctionFrame() const {
if (isStackFrame())
return asStackFrame()->isNonEvalFunctionFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isNonStrictDirectEvalFrame() const {
if (isStackFrame())
return asStackFrame()->isNonStrictDirectEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isStrictEvalFrame() const {
if (isStackFrame())
return asStackFrame()->isStrictEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
unsigned numActualArgs() const {
if (isStackFrame())
return asStackFrame()->numActualArgs();
JS_NOT_REACHED("Invalid frame");
return 0;
}
unsigned numFormalArgs() const {
if (isStackFrame())
return asStackFrame()->numFormalArgs();
JS_NOT_REACHED("Invalid frame");
return 0;
}
Value *formals() const {
if (isStackFrame())
return asStackFrame()->formals();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
Value *actuals() const {
if (isStackFrame())
return asStackFrame()->actuals();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
bool hasArgsObj() const {
if (isStackFrame())
return asStackFrame()->hasArgsObj();
JS_NOT_REACHED("Invalid frame");
return false;
}
ArgumentsObject &argsObj() const {
if (isStackFrame())
return asStackFrame()->argsObj();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->argsObj();
}
void initArgsObj(ArgumentsObject &argsobj) const {
if (isStackFrame()) {
asStackFrame()->initArgsObj(argsobj);
return;
}
JS_NOT_REACHED("Invalid frame");
}
bool copyRawFrameSlots(AutoValueVector *vec) const {
if (isStackFrame())
return asStackFrame()->copyRawFrameSlots(vec);
JS_NOT_REACHED("Invalid frame");
return false;
}
Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
if (isStackFrame())
return asStackFrame()->unaliasedVar(i, checkAliasing);
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->unaliasedVar(i);
}
Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
if (isStackFrame())
return asStackFrame()->unaliasedLocal(i, checkAliasing);
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->unaliasedLocal(i);
}
Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
if (isStackFrame())
return asStackFrame()->unaliasedFormal(i, checkAliasing);
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->unaliasedFormal(i);
}
bool prevUpToDate() const {
if (isStackFrame())
return asStackFrame()->prevUpToDate();
JS_NOT_REACHED("Invalid frame");
return false;
}
void setPrevUpToDate() const {
if (isStackFrame()) {
asStackFrame()->setPrevUpToDate();
return;
}
JS_NOT_REACHED("Invalid frame");
}
TaggedFramePtr evalPrev() const {
JS_ASSERT(isEvalFrame());
if (isStackFrame())
return TaggedFramePtr(asStackFrame()->prev());
JS_NOT_REACHED("Invalid frame");
return TaggedFramePtr();
}
};
template <>