Add IsConstructing and thisObject to Ion frames (Bug 744253, r=dvander)

This commit is contained in:
Nicolas Pierron 2012-05-01 17:40:31 -07:00
parent 0a66b9d72b
commit 2a49f16bc0
9 changed files with 87 additions and 34 deletions

View File

@ -1022,7 +1022,7 @@ InvalidateActivation(FreeOp *fop, uint8 *ionTop, bool invalidateAll)
size_t frameno = 1;
for (IonFrameIterator it(ionTop); it.more(); ++it, ++frameno) {
for (IonFrameIterator it(ionTop); !it.done(); ++it, ++frameno) {
JS_ASSERT_IF(frameno == 1, it.type() == IonFrame_Exit);
#ifdef DEBUG

View File

@ -113,6 +113,8 @@ class IonFrameIterator
}
bool isFunctionFrame() const;
bool isConstructing(IonActivation *activation) const;
void *calleeToken() const;
JSFunction *callee() const;
JSFunction *maybeCallee() const;
@ -135,8 +137,8 @@ class IonFrameIterator
// Functions used to iterate on frames. When prevType is IonFrame_Entry,
// the current frame is the last frame.
inline bool more() const {
return type_ != IonFrame_Entry;
inline bool done() const {
return type_ == IonFrame_Entry;
}
IonFrameIterator &operator++();
@ -165,7 +167,7 @@ class IonActivationIterator
IonActivationIterator &operator++();
IonActivation *activation() {
IonActivation *activation() const {
return activation_;
}
uint8 *top() const {
@ -240,6 +242,8 @@ class InlineFrameIterator
return si_;
}
bool isFunctionFrame() const;
bool isConstructing(IonActivation *activation) const;
JSObject *thisObject() const;
InlineFrameIterator operator++();
};

View File

@ -451,7 +451,7 @@ MarkIonJSFrame(JSTracer *trc, const IonFrameIterator &frame)
static void
MarkIonActivation(JSTracer *trc, uint8 *top)
{
for (IonFrameIterator frames(top); frames.more(); ++frames) {
for (IonFrameIterator frames(top); !frames.done(); ++frames) {
switch (frames.type()) {
case IonFrame_Exit:
// The exit frame gets ignored.
@ -730,3 +730,57 @@ MachineState::FromBailout(uintptr_t regs[Registers::Total],
return machine;
}
bool
InlineFrameIterator::isConstructing(IonActivation *activation) const
{
// Skip the current frame and look at the caller's.
if (more()) {
InlineFrameIterator parent(*this);
++parent;
// In the case of a JS frame, look up the pc from the snapshot.
JS_ASSERT(js_CodeSpec[*parent.pc()].format & JOF_INVOKE);
return (JSOp)*parent.pc() == JSOP_NEW;
}
return frame_->isConstructing(activation);
}
bool
IonFrameIterator::isConstructing(IonActivation *activation) const
{
IonFrameIterator parent(*this);
// Skip the current frame and look at the caller's.
do {
++parent;
} while (!parent.done() && !parent.isScripted());
if (parent.isScripted()) {
// In the case of a JS frame, look up the pc from the snapshot.
InlineFrameIterator inlinedParent(&parent);
JS_ASSERT(js_CodeSpec[*inlinedParent.pc()].format & JOF_INVOKE);
return (JSOp)*inlinedParent.pc() == JSOP_NEW;
}
JS_ASSERT(parent.done());
return activation->entryfp()->isConstructing();
}
JSObject *
InlineFrameIterator::thisObject() const
{
// JS_ASSERT(isConstructing(...));
SnapshotIterator s(si_);
// scopeChain
s.skip();
// In strict modes, |this| may not be an object and thus may not be
// readable which can either segv in read or trigger the assertion.
Value v = s.read();
JS_ASSERT(v.isObject());
return &v.toObject();
}

View File

@ -158,9 +158,6 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
return true;
}
StackIter prev(iter);
++prev;
#ifdef JS_METHODJIT
if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom) && fp && fp->prev()) {
/*

View File

@ -1119,7 +1119,7 @@ MarkRangeConservativelyAndSkipIon(JSTracer *trc, JSRuntime *rt, const uintptr_t
// that the conservative scanner will still see them.
for (ion::IonActivationIterator ion(rt); ion.more(); ++ion) {
ion::IonFrameIterator frames(ion.top());
while (frames.more())
while (!frames.done())
++frames;
uintptr_t *ionMin = (uintptr_t *)ion.top();

View File

@ -3082,11 +3082,10 @@ TypeObject::clearNewScript(JSContext *cx)
pcOffsets.append(uint32_t(iter.pc() - iter.script()->code));
if (iter.isConstructing() &&
iter.callee() == newScript->fun &&
iter.thisv().isObject() &&
!iter.thisv().toObject().hasLazyType() &&
iter.thisv().toObject().type() == this)
!iter.thisObject()->hasLazyType() &&
iter.thisObject()->type() == this)
{
JSObject *obj = &iter.thisv().toObject();
JSObject *obj = iter.thisObject();
/* Whether all identified 'new' properties have been initialized. */
bool finished = false;

View File

@ -6307,7 +6307,7 @@ js_DumpBacktrace(JSContext *cx)
const char *filename = JS_GetScriptFilename(cx, i.script());
unsigned line = JS_PCToLineNumber(cx, i.script(), i.pc());
sprinter.printf("#%d %14p %s:%d (%p @ %d)\n",
depth, i.fp(), filename, line,
depth, (i.isIon() ? 0 : i.fp()), filename, line,
i.script(), i.pc() - i.script()->code);
} else {
sprinter.printf("#%d ???\n", depth);

View File

@ -1176,10 +1176,10 @@ StackIter::settleOnNewState()
if (fp_->runningInIon()) {
ionFrames_ = ion::IonFrameIterator(ionActivations_.top());
while (ionFrames_.more() && !ionFrames_.isScripted())
while (!ionFrames_.done() && !ionFrames_.isScripted())
++ionFrames_;
if (!ionFrames_.more()) {
if (ionFrames_.done()) {
// In this case, we bailed out the last frame, so we
// shouldn't really transition to Ion code.
++ionActivations_;
@ -1273,9 +1273,7 @@ StackIter::StackIter(JSContext *cx, SavedOption savedOption)
#endif
{
#ifdef JS_METHODJIT
CompartmentVector &v = cx->runtime->compartments;
for (size_t i = 0; i < v.length(); i++)
mjit::ExpandInlineFrames(v[i]);
mjit::ExpandInlineFrames(cx->compartment);
#endif
if (StackSegment *seg = cx->stack.seg_) {
@ -1298,10 +1296,10 @@ StackIter::popIonFrame()
script_ = ionInlineFrames_.script();
} else {
++ionFrames_;
while (ionFrames_.more() && !ionFrames_.isScripted())
while (!ionFrames_.done() && !ionFrames_.isScripted())
++ionFrames_;
if (ionFrames_.more()) {
if (!ionFrames_.done()) {
ionInlineFrames_ = ion::InlineFrameIterator(&ionFrames_);
pc_ = ionInlineFrames_.pc();
script_ = ionInlineFrames_.script();
@ -1410,6 +1408,8 @@ StackIter::isConstructing() const
case DONE:
JS_NOT_REACHED("Unexpected state");
return false;
case ION:
return ionInlineFrames_.isConstructing(ionActivations_.activation());
case SCRIPTED:
case NATIVE:
case IMPLICIT_NATIVE:
@ -1456,20 +1456,21 @@ StackIter::calleev() const
return Value();
}
Value
StackIter::thisv() const
JSObject *
StackIter::thisObject() const
{
switch (state_) {
case DONE:
MOZ_NOT_REACHED("Unexpected state");
return Value();
break;
case ION:
return ionInlineFrames_.thisObject();
case SCRIPTED:
case NATIVE:
case IMPLICIT_NATIVE:
return fp()->thisValue();
return &fp()->thisValue().toObject();
}
MOZ_NOT_REACHED("unexpected state");
return Value();
JS_NOT_REACHED("Unexpected state");
return NULL;
}
/*****************************************************************************/

View File

@ -1838,11 +1838,7 @@ class StackIter
private:
SavedOption savedOption_;
enum State { DONE, SCRIPTED, NATIVE, IMPLICIT_NATIVE
#ifdef JS_ION
, ION
#endif
};
enum State { DONE, SCRIPTED, NATIVE, IMPLICIT_NATIVE, ION };
State state_;
@ -1881,6 +1877,7 @@ class StackIter
bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
bool isScript() const { JS_ASSERT(!done()); return state_ == SCRIPTED || state_ == ION; }
bool isIon() const { JS_ASSERT(!done()); return state_ == ION; }
bool isImplicitNativeCall() const {
JS_ASSERT(!done());
return state_ == IMPLICIT_NATIVE;
@ -1895,13 +1892,14 @@ class StackIter
bool isNonEvalFunctionFrame() const;
bool isConstructing() const;
// :TODO: Add && !isIon() in JS_ASSERT of fp() and sp().
StackFrame *fp() const { JS_ASSERT(isScript()); return fp_; }
Value *sp() const { JS_ASSERT(isScript()); return sp_; }
jsbytecode *pc() const { JS_ASSERT(isScript()); return pc_; }
JSScript *script() const { JS_ASSERT(isScript()); return script_; }
JSFunction *callee() const;
Value calleev() const;
Value thisv() const;
JSObject *thisObject() const;
CallArgs nativeArgs() const { JS_ASSERT(isNativeCall()); return args_; }
};