mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 535656 - remove JSStackFrame::dormantNext and varobj (r=waldo)
This commit is contained in:
parent
a20b5365ba
commit
742f31ca8a
@ -5186,16 +5186,10 @@ JS_IsConstructing(JSContext *cx)
|
||||
JS_PUBLIC_API(JSStackFrame *)
|
||||
JS_SaveFrameChain(JSContext *cx)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
||||
if (!fp)
|
||||
return fp;
|
||||
|
||||
JS_ASSERT(!fp->dormantNext);
|
||||
fp->dormantNext = cx->dormantFrameChain;
|
||||
cx->dormantFrameChain = fp;
|
||||
cx->fp = NULL;
|
||||
return NULL;
|
||||
cx->saveActiveCallStack();
|
||||
return fp;
|
||||
}
|
||||
|
||||
@ -5206,11 +5200,7 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
|
||||
JS_ASSERT(!cx->fp);
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
JS_ASSERT(fp == cx->dormantFrameChain);
|
||||
cx->fp = fp;
|
||||
cx->dormantFrameChain = fp->dormantNext;
|
||||
fp->dormantNext = NULL;
|
||||
cx->restoreCallStack();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -79,6 +79,27 @@ FreeContext(JSContext *cx);
|
||||
static void
|
||||
MarkLocalRoots(JSTracer *trc, JSLocalRootStack *lrs);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
CallStack::contains(JSStackFrame *fp)
|
||||
{
|
||||
JSStackFrame *start;
|
||||
JSStackFrame *stop;
|
||||
if (isSuspended()) {
|
||||
start = suspendedFrame;
|
||||
stop = initialFrame->down;
|
||||
} else {
|
||||
start = cx->fp;
|
||||
stop = cx->activeCallStack()->initialFrame->down;
|
||||
}
|
||||
for (JSStackFrame *f = start; f != stop; f = f->down) {
|
||||
if (f == fp)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
JSThreadData::init()
|
||||
{
|
||||
|
188
js/src/jscntxt.h
188
js/src/jscntxt.h
@ -194,6 +194,107 @@ struct GlobalState {
|
||||
SlotList* globalSlots;
|
||||
};
|
||||
|
||||
/*
|
||||
* A callstack contains a set of stack frames linked by fp->down. A callstack
|
||||
* is a member of a JSContext and all of a JSContext's callstacks are kept in a
|
||||
* list starting at cx->currentCallStack. A callstack may be active or
|
||||
* suspended. There are zero or one active callstacks for a context and any
|
||||
* number of suspended contexts. If there is an active context, it is the first
|
||||
* in the currentCallStack list, |cx->fp != NULL| and the callstack's newest
|
||||
* (top) stack frame is |cx->fp|. For all other (suspended) callstacks, the
|
||||
* newest frame is pointed to by suspendedFrame.
|
||||
*
|
||||
* While all frames in a callstack are down-linked, not all down-linked frames
|
||||
* are in the same callstack (e.g., calling js_Execute with |down != cx->fp|
|
||||
* will create a new frame in a new active callstack).
|
||||
*/
|
||||
class CallStack
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/* The context to which this callstack belongs. */
|
||||
JSContext *cx;
|
||||
#endif
|
||||
|
||||
/* If this callstack is suspended, the top of the callstack. */
|
||||
JSStackFrame *suspendedFrame;
|
||||
|
||||
/* This callstack was suspended by JS_SaveFrameChain. */
|
||||
bool saved;
|
||||
|
||||
/* Links members of the JSContext::currentCallStack list. */
|
||||
CallStack *previous;
|
||||
|
||||
/* The varobj on entry to initialFrame. */
|
||||
JSObject *initialVarObj;
|
||||
|
||||
/* The first frame executed in this callstack. */
|
||||
JSStackFrame *initialFrame;
|
||||
|
||||
public:
|
||||
CallStack(JSContext *cx)
|
||||
:
|
||||
#ifdef DEBUG
|
||||
cx(cx),
|
||||
#endif
|
||||
suspendedFrame(NULL), saved(false), previous(NULL),
|
||||
initialVarObj(NULL), initialFrame(NULL)
|
||||
{}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool contains(JSStackFrame *fp);
|
||||
#endif
|
||||
|
||||
void suspend(JSStackFrame *fp) {
|
||||
JS_ASSERT(fp && !isSuspended() && contains(fp));
|
||||
suspendedFrame = fp;
|
||||
}
|
||||
|
||||
void resume() {
|
||||
JS_ASSERT(suspendedFrame);
|
||||
suspendedFrame = NULL;
|
||||
}
|
||||
|
||||
JSStackFrame *getSuspendedFrame() const {
|
||||
JS_ASSERT(suspendedFrame);
|
||||
return suspendedFrame;
|
||||
}
|
||||
|
||||
bool isSuspended() const { return suspendedFrame; }
|
||||
|
||||
void setPrevious(CallStack *cs) { previous = cs; }
|
||||
CallStack *getPrevious() const { return previous; }
|
||||
|
||||
void setInitialVarObj(JSObject *o) { initialVarObj = o; }
|
||||
JSObject *getInitialVarObj() const { return initialVarObj; }
|
||||
|
||||
void setInitialFrame(JSStackFrame *f) { initialFrame = f; }
|
||||
JSStackFrame *getInitialFrame() const { return initialFrame; }
|
||||
|
||||
/*
|
||||
* Saving and restoring is a special case of suspending and resuming
|
||||
* whereby the active callstack becomes suspended without pushing a new
|
||||
* active callstack. This means that if a callstack c1 is pushed on top of a
|
||||
* saved callstack c2, when c1 is popped, c2 must not be made active. In
|
||||
* the normal case, where c2 is not saved, when c1 is popped, c2 is made
|
||||
* active. This distinction is indicated by the |saved| flag.
|
||||
*/
|
||||
|
||||
void save(JSStackFrame *fp) {
|
||||
suspend(fp);
|
||||
saved = true;
|
||||
}
|
||||
|
||||
void restore() {
|
||||
saved = false;
|
||||
resume();
|
||||
}
|
||||
|
||||
bool isSaved() const {
|
||||
JS_ASSERT_IF(saved, isSuspended());
|
||||
return saved;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
|
||||
* JS_THREADSAFE) has an associated trace monitor that keeps track of loop
|
||||
@ -1087,6 +1188,16 @@ typedef struct JSResolvingEntry {
|
||||
|
||||
extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */
|
||||
|
||||
/*
|
||||
* Wraps a stack frame which has been temporarily popped from its call stack
|
||||
* and needs to be GC-reachable. See JSContext::{push,pop}GCReachableFrame.
|
||||
*/
|
||||
struct JSGCReachableFrame
|
||||
{
|
||||
JSGCReachableFrame *next;
|
||||
JSStackFrame *frame;
|
||||
};
|
||||
|
||||
struct JSContext {
|
||||
/*
|
||||
* If this flag is set, we were asked to call back the operation callback
|
||||
@ -1204,8 +1315,67 @@ struct JSContext {
|
||||
void *data;
|
||||
void *data2;
|
||||
|
||||
/* GC and thread-safe state. */
|
||||
JSStackFrame *dormantFrameChain; /* dormant stack frame to scan */
|
||||
/* Linked list of frames temporarily popped from their chain. */
|
||||
JSGCReachableFrame *reachableFrames;
|
||||
|
||||
void pushGCReachableFrame(JSGCReachableFrame &gcrf, JSStackFrame *f) {
|
||||
gcrf.next = reachableFrames;
|
||||
gcrf.frame = f;
|
||||
reachableFrames = &gcrf;
|
||||
}
|
||||
|
||||
void popGCReachableFrame() {
|
||||
reachableFrames = reachableFrames->next;
|
||||
}
|
||||
|
||||
private:
|
||||
friend void js_TraceContext(JSTracer *, JSContext *);
|
||||
|
||||
/* Linked list of callstacks. See CallStack. */
|
||||
js::CallStack *currentCallStack;
|
||||
|
||||
public:
|
||||
/* Assuming there is an active callstack, return it. */
|
||||
js::CallStack *activeCallStack() const {
|
||||
JS_ASSERT(currentCallStack && !currentCallStack->isSaved());
|
||||
return currentCallStack;
|
||||
}
|
||||
|
||||
/* Add the given callstack to the list as the new active callstack. */
|
||||
void pushCallStack(js::CallStack *newcs) {
|
||||
if (fp)
|
||||
currentCallStack->suspend(fp);
|
||||
else
|
||||
JS_ASSERT_IF(currentCallStack, currentCallStack->isSaved());
|
||||
newcs->setPrevious(currentCallStack);
|
||||
currentCallStack = newcs;
|
||||
JS_ASSERT(!newcs->isSuspended() && !newcs->isSaved());
|
||||
}
|
||||
|
||||
/* Remove the active callstack and make the next callstack active. */
|
||||
void popCallStack() {
|
||||
JS_ASSERT(!currentCallStack->isSuspended() && !currentCallStack->isSaved());
|
||||
currentCallStack = currentCallStack->getPrevious();
|
||||
if (currentCallStack && !currentCallStack->isSaved()) {
|
||||
JS_ASSERT(fp);
|
||||
currentCallStack->resume();
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark the top callstack as suspended, without pushing a new one. */
|
||||
void saveActiveCallStack() {
|
||||
JS_ASSERT(fp && currentCallStack && !currentCallStack->isSuspended());
|
||||
currentCallStack->save(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
/* Undoes calls to suspendTopCallStack. */
|
||||
void restoreCallStack() {
|
||||
JS_ASSERT(!fp && currentCallStack && currentCallStack->isSuspended());
|
||||
fp = currentCallStack->getSuspendedFrame();
|
||||
currentCallStack->restore();
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThread *thread;
|
||||
jsrefcount requestDepth;
|
||||
@ -1428,6 +1598,20 @@ private:
|
||||
void checkMallocGCPressure(void *p);
|
||||
};
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
JSStackFrame::varobj(js::CallStack *cs)
|
||||
{
|
||||
JS_ASSERT(cs->contains(this));
|
||||
return fun ? callobj : cs->getInitialVarObj();
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
JSStackFrame::varobj(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(cx->activeCallStack()->contains(this));
|
||||
return fun ? callobj : cx->activeCallStack()->getInitialVarObj();
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
|
||||
#endif
|
||||
|
@ -1221,18 +1221,16 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
JSStackFrame *afp;
|
||||
|
||||
if (fp->flags & JSFRAME_COMPUTED_THIS)
|
||||
return JSVAL_TO_OBJECT(fp->thisv); /* JSVAL_COMPUTED_THIS invariant */
|
||||
|
||||
/* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
|
||||
if (js_GetTopStackFrame(cx) != fp) {
|
||||
afp = cx->fp;
|
||||
JSStackFrame *afp = js_GetTopStackFrame(cx);
|
||||
JSGCReachableFrame reachable;
|
||||
if (afp != fp) {
|
||||
if (afp) {
|
||||
afp->dormantNext = cx->dormantFrameChain;
|
||||
cx->dormantFrameChain = afp;
|
||||
cx->fp = fp;
|
||||
cx->pushGCReachableFrame(reachable, afp);
|
||||
}
|
||||
} else {
|
||||
afp = NULL;
|
||||
@ -1243,8 +1241,7 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
|
||||
|
||||
if (afp) {
|
||||
cx->fp = afp;
|
||||
cx->dormantFrameChain = afp->dormantNext;
|
||||
afp->dormantNext = NULL;
|
||||
cx->popGCReachableFrame();
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(fp->thisv);
|
||||
|
@ -2099,7 +2099,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
JSObject *scopeobj = (cg->flags & TCF_IN_FUNCTION)
|
||||
? STOBJ_GET_PARENT(FUN_OBJECT(cg->fun))
|
||||
: cg->scopeChain;
|
||||
if (scopeobj != caller->varobj)
|
||||
if (scopeobj != caller->varobj(cx))
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
@ -2194,7 +2194,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
|
||||
JS_ASSERT(evalcg->flags & TCF_COMPILE_N_GO);
|
||||
JS_ASSERT(caller->fun && caller->varobj == evalcg->scopeChain);
|
||||
JS_ASSERT(caller->fun && caller->varobj(cx) == evalcg->scopeChain);
|
||||
|
||||
/*
|
||||
* Don't generate upvars on the left side of a for loop. See
|
||||
|
@ -229,7 +229,9 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||
* We must be in a function activation; the function must be lightweight
|
||||
* or else fp must have a variable object.
|
||||
*/
|
||||
JS_ASSERT(fp->fun && (!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->varobj));
|
||||
JS_ASSERT(fp->fun);
|
||||
JS_ASSERT_IF(fp->fun->flags & JSFUN_HEAVYWEIGHT,
|
||||
fp->varobj(js_ContainingCallStack(cx, fp)));
|
||||
|
||||
/* Skip eval and debugger frames. */
|
||||
while (fp->flags & JSFRAME_SPECIAL)
|
||||
@ -851,7 +853,6 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||
* variables object.
|
||||
*/
|
||||
fp->scopeChain = callobj;
|
||||
fp->varobj = callobj;
|
||||
return callobj;
|
||||
}
|
||||
|
||||
|
@ -2282,8 +2282,6 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
|
||||
JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
|
||||
if (fp->argsobj)
|
||||
JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(fp->argsobj), "arguments");
|
||||
if (fp->varobj)
|
||||
JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables");
|
||||
if (fp->script) {
|
||||
js_TraceScript(trc, fp->script);
|
||||
|
||||
@ -2367,10 +2365,17 @@ JSWeakRoots::mark(JSTracer *trc)
|
||||
js_CallValueTracerIfGCThing(trc, lastInternalResult);
|
||||
}
|
||||
|
||||
static void inline
|
||||
TraceFrameChain(JSTracer *trc, JSStackFrame *fp)
|
||||
{
|
||||
do {
|
||||
js_TraceStackFrame(trc, fp);
|
||||
} while ((fp = fp->down) != NULL);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JS_FRIEND_API(void)
|
||||
js_TraceContext(JSTracer *trc, JSContext *acx)
|
||||
{
|
||||
JSStackFrame *fp, *nextChain;
|
||||
JSStackHeader *sh;
|
||||
JSTempValueRooter *tvr;
|
||||
|
||||
@ -2403,9 +2408,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx)
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate frame chain and dormant chains.
|
||||
*
|
||||
* (NB: see comment on this whole "dormant" thing in js_Execute.)
|
||||
* Trace active and suspended callstacks.
|
||||
*
|
||||
* Since js_GetTopStackFrame needs to dereference cx->thread to check for
|
||||
* JIT frames, we check for non-null thread here and avoid null checks
|
||||
@ -2415,26 +2418,29 @@ js_TraceContext(JSTracer *trc, JSContext *acx)
|
||||
if (acx->thread)
|
||||
#endif
|
||||
{
|
||||
fp = js_GetTopStackFrame(acx);
|
||||
nextChain = acx->dormantFrameChain;
|
||||
if (!fp)
|
||||
goto next_chain;
|
||||
/* If |cx->fp|, the active callstack has newest (top) frame |cx->fp|. */
|
||||
JSStackFrame *fp = js_GetTopStackFrame(acx);
|
||||
if (fp) {
|
||||
JS_ASSERT(!acx->activeCallStack()->isSuspended());
|
||||
TraceFrameChain(trc, fp);
|
||||
if (JSObject *o = acx->activeCallStack()->getInitialVarObj())
|
||||
JS_CALL_OBJECT_TRACER(trc, o, "variables");
|
||||
}
|
||||
|
||||
/* The top frame must not be dormant. */
|
||||
JS_ASSERT(!fp->dormantNext);
|
||||
for (;;) {
|
||||
do {
|
||||
js_TraceStackFrame(trc, fp);
|
||||
} while ((fp = fp->down) != NULL);
|
||||
|
||||
next_chain:
|
||||
if (!nextChain)
|
||||
break;
|
||||
fp = nextChain;
|
||||
nextChain = nextChain->dormantNext;
|
||||
/* Trace suspended frames. */
|
||||
CallStack *cur = acx->currentCallStack;
|
||||
CallStack *cs = fp ? cur->getPrevious() : cur;
|
||||
for (; cs; cs = cs->getPrevious()) {
|
||||
TraceFrameChain(trc, cs->getSuspendedFrame());
|
||||
if (cs->getInitialVarObj())
|
||||
JS_CALL_OBJECT_TRACER(trc, cs->getInitialVarObj(), "var env");
|
||||
}
|
||||
}
|
||||
|
||||
/* Trace frames that have been temporarily removed but need to be marked. */
|
||||
for (JSGCReachableFrame *rf = acx->reachableFrames; rf; rf = rf->next)
|
||||
TraceFrameChain(trc, rf->frame);
|
||||
|
||||
/* Mark other roots-by-definition in acx. */
|
||||
if (acx->globalObject && !JS_HAS_OPTION(acx, JSOPTION_UNROOTED_GLOBAL))
|
||||
JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object");
|
||||
|
@ -896,7 +896,6 @@ js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv)
|
||||
!OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) {
|
||||
thisp = cx->globalObject;
|
||||
} else {
|
||||
JSStackFrame *fp;
|
||||
jsid id;
|
||||
jsval v;
|
||||
uintN attrs;
|
||||
@ -912,24 +911,26 @@ js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv)
|
||||
* FIXME: 417851 -- this access check should not be required, as it
|
||||
* imposes a performance penalty on all js_ComputeGlobalThis calls,
|
||||
* and it represents a maintenance hazard.
|
||||
*
|
||||
* When the above FIXME is made fixed, the whole GC reachable frame
|
||||
* mechanism can be removed as well.
|
||||
*/
|
||||
fp = js_GetTopStackFrame(cx); /* quell GCC overwarning */
|
||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
||||
JSGCReachableFrame reachable;
|
||||
if (lazy) {
|
||||
JS_ASSERT(fp->argv == argv);
|
||||
fp->dormantNext = cx->dormantFrameChain;
|
||||
cx->dormantFrameChain = fp;
|
||||
cx->fp = fp->down;
|
||||
fp->down = NULL;
|
||||
cx->pushGCReachableFrame(reachable, fp);
|
||||
}
|
||||
thisp = JSVAL_TO_OBJECT(argv[-2]);
|
||||
id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
|
||||
|
||||
ok = thisp->checkAccess(cx, id, JSACC_PARENT, &v, &attrs);
|
||||
if (lazy) {
|
||||
cx->dormantFrameChain = fp->dormantNext;
|
||||
fp->dormantNext = NULL;
|
||||
fp->down = cx->fp;
|
||||
cx->fp = fp;
|
||||
cx->popGCReachableFrame();
|
||||
}
|
||||
if (!ok)
|
||||
return NULL;
|
||||
@ -1099,6 +1100,7 @@ JS_REQUIRES_STACK JS_FRIEND_API(JSBool)
|
||||
js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
|
||||
{
|
||||
void *mark;
|
||||
CallStack callStack(cx);
|
||||
JSStackFrame frame;
|
||||
jsval *sp, *argv, *newvp;
|
||||
jsval v;
|
||||
@ -1113,6 +1115,7 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
|
||||
uint32 rootedArgsFlag;
|
||||
JSInterpreterHook hook;
|
||||
void *hookData;
|
||||
bool pushCall;
|
||||
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
|
||||
@ -1303,7 +1306,6 @@ have_fun:
|
||||
* Initialize the frame.
|
||||
*/
|
||||
frame.thisv = vp[1];
|
||||
frame.varobj = NULL;
|
||||
frame.callobj = NULL;
|
||||
frame.argsobj = NULL;
|
||||
frame.script = script;
|
||||
@ -1321,10 +1323,18 @@ have_fun:
|
||||
frame.imacpc = NULL;
|
||||
frame.slots = NULL;
|
||||
frame.flags = flags | rootedArgsFlag;
|
||||
frame.dormantNext = NULL;
|
||||
frame.displaySave = NULL;
|
||||
|
||||
MUST_FLOW_THROUGH("out");
|
||||
pushCall = !cx->fp;
|
||||
if (pushCall) {
|
||||
/*
|
||||
* The initialVarObj is left NULL since fp->callobj is NULL and, for
|
||||
* interpreted functions, fp->varobj() == fp->callobj.
|
||||
*/
|
||||
callStack.setInitialFrame(&frame);
|
||||
cx->pushCallStack(&callStack);
|
||||
}
|
||||
cx->fp = &frame;
|
||||
|
||||
/* Init these now in case we goto out before first hook call. */
|
||||
@ -1332,15 +1342,13 @@ have_fun:
|
||||
hookData = NULL;
|
||||
|
||||
if (native) {
|
||||
/* If native, use caller varobj and scopeChain for eval. */
|
||||
JS_ASSERT(!frame.varobj);
|
||||
JS_ASSERT(!frame.scopeChain);
|
||||
/* Slow natives expect the caller's scopeChain as their scopeChain. */
|
||||
if (frame.down) {
|
||||
frame.varobj = frame.down->varobj;
|
||||
JS_ASSERT(!pushCall);
|
||||
frame.scopeChain = frame.down->scopeChain;
|
||||
}
|
||||
|
||||
/* But ensure that we have a scope chain. */
|
||||
/* Ensure that we have a scope chain. */
|
||||
if (!frame.scopeChain)
|
||||
frame.scopeChain = parent;
|
||||
} else {
|
||||
@ -1408,6 +1416,8 @@ out:
|
||||
*vp = frame.rval;
|
||||
|
||||
/* Restore cx->fp now that we're done releasing frame objects. */
|
||||
if (pushCall)
|
||||
cx->popCallStack();
|
||||
cx->fp = frame.down;
|
||||
|
||||
out2:
|
||||
@ -1480,16 +1490,37 @@ js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
|
||||
return js_InternalCall(cx, obj, fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
CallStack *
|
||||
js_ContainingCallStack(JSContext *cx, JSStackFrame *target)
|
||||
{
|
||||
JS_ASSERT(cx->fp);
|
||||
|
||||
/* The active callstack's top frame is cx->fp. */
|
||||
CallStack *cs = cx->activeCallStack();
|
||||
JSStackFrame *f = cx->fp;
|
||||
JSStackFrame *stop = cs->getInitialFrame()->down;
|
||||
for (; f != stop; f = f->down) {
|
||||
if (f == target)
|
||||
return cs;
|
||||
}
|
||||
|
||||
/* A suspended callstack's top frame is its suspended frame. */
|
||||
for (cs = cs->getPrevious(); cs; cs = cs->getPrevious()) {
|
||||
f = cs->getSuspendedFrame();
|
||||
stop = cs->getInitialFrame()->down;
|
||||
for (; f != stop; f = f->down) {
|
||||
if (f == target)
|
||||
return cs;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
JSStackFrame *down, uintN flags, jsval *result)
|
||||
{
|
||||
JSInterpreterHook hook;
|
||||
void *hookData, *mark;
|
||||
JSStackFrame *oldfp, frame;
|
||||
JSObject *obj, *tmp;
|
||||
JSBool ok;
|
||||
|
||||
if (script->isEmpty()) {
|
||||
if (result)
|
||||
*result = JSVAL_VOID;
|
||||
@ -1499,19 +1530,29 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
LeaveTrace(cx);
|
||||
|
||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
||||
if (JAVASCRIPT_EXECUTE_START_ENABLED())
|
||||
jsdtrace_execute_start(script);
|
||||
struct JSDNotifyGuard {
|
||||
JSScript *script;
|
||||
JSDNotifyGuard(JSScript *s) : script(s) {
|
||||
if (JAVASCRIPT_EXECUTE_START_ENABLED())
|
||||
jsdtrace_execute_start(script);
|
||||
}
|
||||
~JSDNotifyGuard() {
|
||||
if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
|
||||
jsdtrace_execute_done(script);
|
||||
}
|
||||
|
||||
} jsdNotifyGuard(script);
|
||||
#endif
|
||||
|
||||
hook = cx->debugHooks->executeHook;
|
||||
hookData = mark = NULL;
|
||||
oldfp = js_GetTopStackFrame(cx);
|
||||
JSInterpreterHook hook = cx->debugHooks->executeHook;
|
||||
void *hookData = NULL;
|
||||
JSStackFrame frame;
|
||||
CallStack callStack(cx);
|
||||
frame.script = script;
|
||||
if (down) {
|
||||
/* Propagate arg state for eval and the debugger API. */
|
||||
frame.callobj = down->callobj;
|
||||
frame.argsobj = down->argsobj;
|
||||
frame.varobj = down->varobj;
|
||||
frame.fun = (script->staticLevel > 0) ? down->fun : NULL;
|
||||
frame.thisv = down->thisv;
|
||||
if (down->flags & JSFRAME_COMPUTED_THIS)
|
||||
@ -1519,29 +1560,49 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
frame.argc = down->argc;
|
||||
frame.argv = down->argv;
|
||||
frame.annotation = down->annotation;
|
||||
|
||||
/*
|
||||
* We want to call |down->varobj()|, but this requires knowing the
|
||||
* CallStack of |down|. If |down == cx->fp|, the callstack is simply
|
||||
* the context's active callstack, so we can use |down->varobj(cx)|.
|
||||
* When |down != cx->fp|, we need to do a slow linear search. Luckily,
|
||||
* this only happens with eval and JS_EvaluateInStackFrame.
|
||||
*/
|
||||
if (down == cx->fp) {
|
||||
callStack.setInitialVarObj(down->varobj(cx));
|
||||
} else {
|
||||
CallStack *cs = js_ContainingCallStack(cx, down);
|
||||
callStack.setInitialVarObj(down->varobj(cs));
|
||||
}
|
||||
} else {
|
||||
frame.callobj = NULL;
|
||||
frame.argsobj = NULL;
|
||||
obj = chain;
|
||||
JSObject *obj = chain;
|
||||
if (cx->options & JSOPTION_VAROBJFIX) {
|
||||
while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
|
||||
while (JSObject *tmp = OBJ_GET_PARENT(cx, obj))
|
||||
obj = tmp;
|
||||
}
|
||||
frame.varobj = obj;
|
||||
frame.fun = NULL;
|
||||
frame.thisv = OBJECT_TO_JSVAL(chain);
|
||||
frame.argc = 0;
|
||||
frame.argv = NULL;
|
||||
frame.annotation = NULL;
|
||||
callStack.setInitialVarObj(obj);
|
||||
}
|
||||
|
||||
frame.imacpc = NULL;
|
||||
|
||||
struct RawStackGuard {
|
||||
JSContext *cx;
|
||||
void *mark;
|
||||
RawStackGuard(JSContext *cx) : cx(cx), mark(NULL) {}
|
||||
~RawStackGuard() { if (mark) js_FreeRawStack(cx, mark); }
|
||||
} rawStackGuard(cx);
|
||||
|
||||
if (script->nslots != 0) {
|
||||
frame.slots = js_AllocRawStack(cx, script->nslots, &mark);
|
||||
if (!frame.slots) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
frame.slots = js_AllocRawStack(cx, script->nslots, &rawStackGuard.mark);
|
||||
if (!frame.slots)
|
||||
return false;
|
||||
memset(frame.slots, 0, script->nfixed * sizeof(jsval));
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
@ -1556,10 +1617,8 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
int base = (down->fun && !(down->flags & JSFRAME_SPECIAL))
|
||||
? down->fun->sharpSlotBase(cx)
|
||||
: down->script->nfixed - SHARP_NSLOTS;
|
||||
if (base < 0) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
if (base < 0)
|
||||
return false;
|
||||
sharps[0] = down->slots[base];
|
||||
sharps[1] = down->slots[base + 1];
|
||||
} else {
|
||||
@ -1576,40 +1635,43 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
frame.scopeChain = chain;
|
||||
frame.regs = NULL;
|
||||
frame.flags = flags;
|
||||
frame.dormantNext = NULL;
|
||||
frame.blockChain = NULL;
|
||||
|
||||
/*
|
||||
* Here we wrap the call to js_Interpret with code to (conditionally)
|
||||
* save and restore the old stack frame chain into a chain of 'dormant'
|
||||
* frame chains. Since we are replacing cx->fp, we were running into
|
||||
* the problem that if GC was called under this frame, some of the GC
|
||||
* things associated with the old frame chain (available here only in
|
||||
* the C variable 'oldfp') were not rooted and were being collected.
|
||||
*
|
||||
* So, now we preserve the links to these 'dormant' frame chains in cx
|
||||
* before calling js_Interpret and cleanup afterwards. The GC walks
|
||||
* these dormant chains and marks objects in the same way that it marks
|
||||
* objects in the primary cx->fp chain.
|
||||
* We need to push/pop a new callstack if there is no existing callstack
|
||||
* or the current callstack needs to be suspended (so that its frames are
|
||||
* marked by GC).
|
||||
*/
|
||||
if (oldfp && oldfp != down) {
|
||||
JS_ASSERT(!oldfp->dormantNext);
|
||||
oldfp->dormantNext = cx->dormantFrameChain;
|
||||
cx->dormantFrameChain = oldfp;
|
||||
JSStackFrame *oldfp = cx->fp;
|
||||
bool newCallStack = !oldfp || oldfp != down;
|
||||
if (newCallStack) {
|
||||
callStack.setInitialFrame(&frame);
|
||||
cx->pushCallStack(&callStack);
|
||||
}
|
||||
|
||||
cx->fp = &frame;
|
||||
|
||||
struct FinishGuard {
|
||||
JSContext *cx;
|
||||
JSStackFrame *oldfp;
|
||||
bool newCallStack;
|
||||
FinishGuard(JSContext *cx, JSStackFrame *oldfp, bool newCallStack)
|
||||
: cx(cx), oldfp(oldfp), newCallStack(newCallStack) {}
|
||||
~FinishGuard() {
|
||||
if (newCallStack)
|
||||
cx->popCallStack();
|
||||
cx->fp = oldfp;
|
||||
}
|
||||
} finishGuard(cx, oldfp, newCallStack);
|
||||
|
||||
if (!down) {
|
||||
OBJ_TO_INNER_OBJECT(cx, chain);
|
||||
if (!chain)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
frame.scopeChain = chain;
|
||||
|
||||
JSObject *thisp = JSVAL_TO_OBJECT(frame.thisv)->thisObject(cx);
|
||||
if (!thisp) {
|
||||
ok = JS_FALSE;
|
||||
goto out2;
|
||||
}
|
||||
if (!thisp)
|
||||
return false;
|
||||
frame.thisv = OBJECT_TO_JSVAL(thisp);
|
||||
frame.flags |= JSFRAME_COMPUTED_THIS;
|
||||
}
|
||||
@ -1619,7 +1681,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
cx->debugHooks->executeHookData);
|
||||
}
|
||||
|
||||
ok = js_Interpret(cx);
|
||||
JSBool ok = js_Interpret(cx);
|
||||
if (result)
|
||||
*result = frame.rval;
|
||||
|
||||
@ -1629,22 +1691,6 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
hook(cx, &frame, JS_FALSE, &ok, hookData);
|
||||
}
|
||||
|
||||
out2:
|
||||
if (mark)
|
||||
js_FreeRawStack(cx, mark);
|
||||
cx->fp = oldfp;
|
||||
|
||||
if (oldfp && oldfp != down) {
|
||||
JS_ASSERT(cx->dormantFrameChain == oldfp);
|
||||
cx->dormantFrameChain = oldfp->dormantNext;
|
||||
oldfp->dormantNext = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
||||
if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
|
||||
jsdtrace_execute_done(script);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,7 @@ typedef struct JSFrameRegs {
|
||||
jsval *sp; /* stack pointer */
|
||||
} JSFrameRegs;
|
||||
|
||||
|
||||
/*
|
||||
* JS stack frame, may be allocated on the C stack by native callers. Always
|
||||
* allocated on cx->stackPool for calls from the interpreter to an interpreted
|
||||
@ -73,7 +74,6 @@ struct JSStackFrame {
|
||||
JSObject *callobj; /* lazily created Call object */
|
||||
jsval argsobj; /* lazily created arguments object, must be
|
||||
JSVAL_OBJECT */
|
||||
JSObject *varobj; /* variables object, where vars go */
|
||||
JSScript *script; /* script being interpreted */
|
||||
JSFunction *fun; /* function being called or null */
|
||||
jsval thisv; /* "this" pointer if in method */
|
||||
@ -123,7 +123,6 @@ struct JSStackFrame {
|
||||
JSObject *blockChain;
|
||||
|
||||
uint32 flags; /* frame flags -- see below */
|
||||
JSStackFrame *dormantNext; /* next dormant frame chain */
|
||||
JSStackFrame *displaySave; /* previous value of display entry for
|
||||
script->staticLevel */
|
||||
|
||||
@ -155,9 +154,26 @@ struct JSStackFrame {
|
||||
JSObject *callee() {
|
||||
return argv ? JSVAL_TO_OBJECT(argv[-2]) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the object associated with the Execution Context's
|
||||
* VariableEnvironment (ES5 10.3). The given CallStack must contain this
|
||||
* stack frame.
|
||||
*/
|
||||
JSObject *varobj(js::CallStack *cs);
|
||||
|
||||
/* Short for: varobj(cx->activeCallStack()). */
|
||||
JSObject *varobj(JSContext *cx);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
* Perform a linear search of all frames in all callstacks in the given context
|
||||
* for the given frame, returning the callstack, if found, and NULL otherwise.
|
||||
*/
|
||||
extern js::CallStack *
|
||||
js_ContainingCallStack(JSContext *cx, JSStackFrame *target);
|
||||
|
||||
static JS_INLINE uintN
|
||||
FramePCOffset(JSStackFrame* fp)
|
||||
{
|
||||
|
@ -714,8 +714,8 @@ JS_FRIEND_DATA(JSClass) js_GeneratorClass = {
|
||||
* from the activation in fp, so we can steal away fp->callobj and fp->argsobj
|
||||
* if they are non-null.
|
||||
*/
|
||||
JSObject *
|
||||
js_NewGenerator(JSContext *cx, JSStackFrame *fp)
|
||||
JS_REQUIRES_STACK JSObject *
|
||||
js_NewGenerator(JSContext *cx)
|
||||
{
|
||||
JSObject *obj;
|
||||
uintN argc, nargs, nslots;
|
||||
@ -727,6 +727,7 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp)
|
||||
return NULL;
|
||||
|
||||
/* Load and compute stack slot counts. */
|
||||
JSStackFrame *fp = cx->fp;
|
||||
argc = fp->argc;
|
||||
nargs = JS_MAX(argc, fp->fun->nargs);
|
||||
nslots = 2 + nargs + fp->script->nslots;
|
||||
@ -752,7 +753,6 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp)
|
||||
}
|
||||
|
||||
/* These two references can be shared with fp until it goes away. */
|
||||
gen->frame.varobj = fp->varobj;
|
||||
gen->frame.thisv = fp->thisv;
|
||||
|
||||
/* Copy call-invariant script and function references. */
|
||||
@ -786,7 +786,6 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp)
|
||||
gen->frame.regs = &gen->savedRegs;
|
||||
|
||||
gen->frame.flags = (fp->flags & ~JSFRAME_ROOTED_ARGV) | JSFRAME_GENERATOR;
|
||||
gen->frame.dormantNext = NULL;
|
||||
|
||||
/* JSOP_GENERATOR appears in the prologue, outside all blocks. */
|
||||
JS_ASSERT(!fp->blockChain);
|
||||
|
@ -117,7 +117,7 @@ struct JSGenerator {
|
||||
((JSGenerator *) ((uint8 *)(fp) - offsetof(JSGenerator, frame)))
|
||||
|
||||
extern JSObject *
|
||||
js_NewGenerator(JSContext *cx, JSStackFrame *fp);
|
||||
js_NewGenerator(JSContext *cx);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1256,11 +1256,11 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JSBool ok;
|
||||
JSScript **bucket = NULL; /* avoid GCC warning with early decl&init */
|
||||
#if JS_HAS_EVAL_THIS_SCOPE
|
||||
JSObject *callerScopeChain = NULL, *callerVarObj = NULL;
|
||||
JSObject *withObject = NULL;
|
||||
JSBool setCallerScopeChain = JS_FALSE, setCallerVarObj = JS_FALSE;
|
||||
JSTempValueRooter scopetvr, varobjtvr;
|
||||
JSObject *callerScopeChain = NULL;
|
||||
JSBool setCallerScopeChain = JS_FALSE;
|
||||
JSTempValueRooter scopetvr;
|
||||
#endif
|
||||
JSObject *withObject = NULL;
|
||||
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
caller = js_GetScriptedCaller(cx, fp);
|
||||
@ -1312,7 +1312,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
* object, then we need to provide one for the compiler to stick any
|
||||
* declared (var) variables into.
|
||||
*/
|
||||
if (!caller->varobj && !js_GetCallObject(cx, caller))
|
||||
if (caller->fun && !caller->callobj && !js_GetCallObject(cx, caller))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Accept an optional trailing argument that overrides the scope object. */
|
||||
@ -1361,22 +1361,11 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
||||
/* NB: We know obj is a global object here. */
|
||||
JS_ASSERT(!OBJ_GET_PARENT(cx, obj));
|
||||
scopeobj = obj;
|
||||
|
||||
/* Set fp->scopeChain too, for the compiler. */
|
||||
caller->scopeChain = fp->scopeChain = scopeobj;
|
||||
caller->scopeChain = scopeobj = obj;
|
||||
|
||||
/* Remember scopeobj so we can null its private when done. */
|
||||
setCallerScopeChain = JS_TRUE;
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, callerScopeChain, &scopetvr);
|
||||
|
||||
callerVarObj = caller->varobj;
|
||||
if (obj != callerVarObj) {
|
||||
/* Set fp->varobj too, for the compiler. */
|
||||
caller->varobj = fp->varobj = obj;
|
||||
setCallerVarObj = JS_TRUE;
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, callerVarObj, &varobjtvr);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Compile using the caller's current scope object.
|
||||
@ -1553,17 +1542,13 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
out:
|
||||
#if JS_HAS_EVAL_THIS_SCOPE
|
||||
/* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */
|
||||
if (setCallerVarObj) {
|
||||
caller->varobj = callerVarObj;
|
||||
JS_POP_TEMP_ROOT(cx, &varobjtvr);
|
||||
}
|
||||
if (setCallerScopeChain) {
|
||||
caller->scopeChain = callerScopeChain;
|
||||
JS_POP_TEMP_ROOT(cx, &scopetvr);
|
||||
}
|
||||
#endif
|
||||
if (withObject)
|
||||
withObject->setPrivate(NULL);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -7103,7 +7088,6 @@ js_DumpStackFrame(JSStackFrame *fp)
|
||||
fprintf(stderr, " argv: %p (argc: %u)\n", (void *) fp->argv, (unsigned) fp->argc);
|
||||
MaybeDumpObject("callobj", fp->callobj);
|
||||
MaybeDumpObject("argsobj", JSVAL_TO_OBJECT(fp->argsobj));
|
||||
MaybeDumpObject("varobj", fp->varobj);
|
||||
MaybeDumpValue("this", fp->thisv);
|
||||
fprintf(stderr, " rval: ");
|
||||
dumpValue(fp->rval);
|
||||
@ -7139,8 +7123,6 @@ js_DumpStackFrame(JSStackFrame *fp)
|
||||
if (fp->blockChain)
|
||||
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->blockChain);
|
||||
|
||||
if (fp->dormantNext)
|
||||
fprintf(stderr, " dormantNext: (JSStackFrame *) %p\n", (void *) fp->dormantNext);
|
||||
if (fp->displaySave)
|
||||
fprintf(stderr, " displaySave: (JSStackFrame *) %p\n", (void *) fp->displaySave);
|
||||
|
||||
|
@ -670,7 +670,7 @@ END_CASE(JSOP_PICK)
|
||||
|
||||
BEGIN_CASE(JSOP_SETCONST)
|
||||
LOAD_ATOM(0);
|
||||
obj = fp->varobj;
|
||||
obj = fp->varobj(cx);
|
||||
rval = FETCH_OPND(-1);
|
||||
if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), rval,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
@ -1441,7 +1441,8 @@ BEGIN_CASE(JSOP_GVARINC)
|
||||
DO_OP();
|
||||
}
|
||||
slot = JSVAL_TO_INT(lval);
|
||||
rval = OBJ_GET_SLOT(cx, fp->varobj, slot);
|
||||
JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj());
|
||||
rval = OBJ_GET_SLOT(cx, cx->activeCallStack()->getInitialVarObj(), slot);
|
||||
if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
|
||||
PUSH_OPND(rval + incr2);
|
||||
rval += incr;
|
||||
@ -1453,7 +1454,7 @@ BEGIN_CASE(JSOP_GVARINC)
|
||||
rval = regs.sp[-1];
|
||||
--regs.sp;
|
||||
}
|
||||
OBJ_SET_SLOT(cx, fp->varobj, slot, rval);
|
||||
OBJ_SET_SLOT(cx, fp->varobj(cx), slot, rval);
|
||||
len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */
|
||||
JS_ASSERT(len == js_CodeSpec[op].length);
|
||||
DO_NEXT_OP(len);
|
||||
@ -2152,7 +2153,6 @@ BEGIN_CASE(JSOP_APPLY)
|
||||
newsp += nframeslots;
|
||||
newifp->frame.callobj = NULL;
|
||||
newifp->frame.argsobj = NULL;
|
||||
newifp->frame.varobj = NULL;
|
||||
newifp->frame.script = script;
|
||||
newifp->frame.fun = fun;
|
||||
newifp->frame.argc = argc;
|
||||
@ -2162,7 +2162,6 @@ BEGIN_CASE(JSOP_APPLY)
|
||||
newifp->frame.annotation = NULL;
|
||||
newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj);
|
||||
newifp->frame.flags = flags;
|
||||
newifp->frame.dormantNext = NULL;
|
||||
newifp->frame.blockChain = NULL;
|
||||
if (script->staticLevel < JS_DISPLAY_SIZE) {
|
||||
JSStackFrame **disp = &cx->display[script->staticLevel];
|
||||
@ -2781,7 +2780,8 @@ BEGIN_CASE(JSOP_CALLGVAR)
|
||||
op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME;
|
||||
DO_OP();
|
||||
}
|
||||
obj = fp->varobj;
|
||||
JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj());
|
||||
obj = cx->activeCallStack()->getInitialVarObj();
|
||||
slot = JSVAL_TO_INT(lval);
|
||||
rval = OBJ_GET_SLOT(cx, obj, slot);
|
||||
PUSH_OPND(rval);
|
||||
@ -2794,7 +2794,8 @@ BEGIN_CASE(JSOP_SETGVAR)
|
||||
JS_ASSERT(slot < GlobalVarCount(fp));
|
||||
METER_SLOT_OP(op, slot);
|
||||
rval = FETCH_OPND(-1);
|
||||
obj = fp->varobj;
|
||||
JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj());
|
||||
obj = cx->activeCallStack()->getInitialVarObj();
|
||||
lval = fp->slots[slot];
|
||||
if (JSVAL_IS_NULL(lval)) {
|
||||
/*
|
||||
@ -2833,7 +2834,7 @@ BEGIN_CASE(JSOP_DEFVAR)
|
||||
* code below we need the absolute value.
|
||||
*/
|
||||
index += atoms - script->atomMap.vector;
|
||||
obj = fp->varobj;
|
||||
obj = fp->varobj(cx);
|
||||
JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
if (!(fp->flags & JSFRAME_EVAL))
|
||||
@ -2882,11 +2883,10 @@ BEGIN_CASE(JSOP_DEFVAR)
|
||||
SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
||||
SPROP_HAS_STUB_SETTER(sprop)) {
|
||||
/*
|
||||
* Fast globals use frame variables to map the global
|
||||
* name's atom index to the permanent fp->varobj slot
|
||||
* number, tagged as a jsval. The atom index for the
|
||||
* global's name literal is identical to its variable
|
||||
* index.
|
||||
* Fast globals use frame variables to map the global name's atom
|
||||
* index to the permanent varobj slot number, tagged as a jsval.
|
||||
* The atom index for the global's name literal is identical to its
|
||||
* variable index.
|
||||
*/
|
||||
fp->slots[index] = INT_TO_JSVAL(sprop->slot);
|
||||
}
|
||||
@ -2991,7 +2991,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
||||
* current scope chain even for the case of function expression statements
|
||||
* and functions defined by eval inside let or with blocks.
|
||||
*/
|
||||
parent = fp->varobj;
|
||||
parent = fp->varobj(cx);
|
||||
JS_ASSERT(parent);
|
||||
|
||||
/*
|
||||
@ -3039,7 +3039,7 @@ BEGIN_CASE(JSOP_DEFFUN)
|
||||
: parent->defineProperty(cx, id, rval, getter, setter, attrs);
|
||||
|
||||
restore_scope:
|
||||
/* Restore fp->scopeChain now that obj is defined in fp->varobj. */
|
||||
/* Restore fp->scopeChain now that obj is defined in fp->callobj. */
|
||||
fp->scopeChain = obj2;
|
||||
if (!ok)
|
||||
goto error;
|
||||
@ -3067,7 +3067,7 @@ BEGIN_CASE(JSOP_DEFFUN_DBGFC)
|
||||
rval = JSVAL_VOID;
|
||||
}
|
||||
|
||||
parent = fp->varobj;
|
||||
parent = fp->varobj(cx);
|
||||
JS_ASSERT(parent);
|
||||
|
||||
id = ATOM_TO_JSID(fun->atom);
|
||||
@ -4109,7 +4109,7 @@ END_CASE(JSOP_CALLBUILTIN)
|
||||
BEGIN_CASE(JSOP_GENERATOR)
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
regs.pc += JSOP_GENERATOR_LENGTH;
|
||||
obj = js_NewGenerator(cx, fp);
|
||||
obj = js_NewGenerator(cx);
|
||||
if (!obj)
|
||||
goto error;
|
||||
JS_ASSERT(!fp->callobj && !fp->argsobj);
|
||||
|
@ -148,6 +148,7 @@ namespace js {
|
||||
|
||||
class TraceRecorder;
|
||||
class TraceMonitor;
|
||||
class CallStack;
|
||||
|
||||
class ContextAllocPolicy;
|
||||
class SystemAllocPolicy;
|
||||
|
@ -330,12 +330,12 @@ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
*
|
||||
* Unlike eval, which the compiler detects, Script.prototype.exec may be
|
||||
* called from a lightweight function, or even from native code (in which
|
||||
* case fp->varobj and fp->scopeChain are null). If exec is called from
|
||||
* a lightweight function, we will need to get a Call object representing
|
||||
* its frame, to act as the var object and scope chain head.
|
||||
* fp->scopeChain is null). If exec is called from a lightweight function,
|
||||
* we will need to get a Call object representing its frame, to act as the
|
||||
* var object and scope chain head.
|
||||
*/
|
||||
caller = js_GetScriptedCaller(cx, NULL);
|
||||
if (caller && !caller->varobj) {
|
||||
if (caller && !caller->varobj(cx)) {
|
||||
/* Called from a lightweight function. */
|
||||
JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags));
|
||||
|
||||
@ -349,7 +349,7 @@ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
if (caller) {
|
||||
/*
|
||||
* Load caller->scopeChain after the conditional js_GetCallObject
|
||||
* call above, which resets scopeChain as well as varobj.
|
||||
* call above, which resets scopeChain as well as the callobj.
|
||||
*/
|
||||
scopeobj = js_GetScopeChain(cx, caller);
|
||||
if (!scopeobj)
|
||||
|
@ -3519,8 +3519,6 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, do
|
||||
// we need to update the frame fields.
|
||||
if (!fp->callobj)
|
||||
fp->callobj = fp->scopeChain;
|
||||
if (!fp->varobj)
|
||||
fp->varobj = fp->scopeChain;
|
||||
|
||||
// Iff scope chain's private is NULL, then |fp->scopeChain| was created
|
||||
// on trace for a call, so we set the private field now. (Call objects
|
||||
@ -5627,7 +5625,6 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
|
||||
|
||||
newifp->frame.callobj = NULL;
|
||||
newifp->frame.argsobj = NULL;
|
||||
newifp->frame.varobj = NULL;
|
||||
newifp->frame.script = script;
|
||||
newifp->frame.fun = fun;
|
||||
|
||||
@ -5659,7 +5656,6 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
|
||||
newifp->frame.annotation = NULL;
|
||||
newifp->frame.scopeChain = NULL; // will be updated in FlushNativeStackFrame
|
||||
newifp->frame.flags = constructing ? JSFRAME_CONSTRUCTING : 0;
|
||||
newifp->frame.dormantNext = NULL;
|
||||
newifp->frame.blockChain = NULL;
|
||||
newifp->mark = newmark;
|
||||
newifp->frame.thisv = JSVAL_NULL; // will be updated in FlushNativeStackFrame
|
||||
@ -5729,7 +5725,6 @@ SynthesizeSlowNativeFrame(InterpState& state, JSContext *cx, VMSideExit *exit)
|
||||
fp->slots = NULL;
|
||||
fp->callobj = NULL;
|
||||
fp->argsobj = NULL;
|
||||
fp->varobj = cx->fp->varobj;
|
||||
fp->script = NULL;
|
||||
fp->thisv = state.nativeVp[1];
|
||||
fp->argc = state.nativeVpLen - 2;
|
||||
@ -5742,7 +5737,6 @@ SynthesizeSlowNativeFrame(InterpState& state, JSContext *cx, VMSideExit *exit)
|
||||
fp->scopeChain = cx->fp->scopeChain;
|
||||
fp->blockChain = NULL;
|
||||
fp->flags = exit->constructing() ? JSFRAME_CONSTRUCTING : 0;
|
||||
fp->dormantNext = NULL;
|
||||
fp->displaySave = NULL;
|
||||
|
||||
ifp->mark = mark;
|
||||
|
@ -7506,8 +7506,8 @@ js_GetFunctionNamespace(JSContext *cx, jsval *vp)
|
||||
* Note the asymmetry between js_GetDefaultXMLNamespace and js_SetDefaultXML-
|
||||
* Namespace. Get searches fp->scopeChain for JS_DEFAULT_XML_NAMESPACE_ID,
|
||||
* while Set sets JS_DEFAULT_XML_NAMESPACE_ID in fp->varobj. There's no
|
||||
* requirement that fp->varobj lie directly on fp->scopeChain, although it
|
||||
* should be reachable using the prototype chain from a scope object (cf.
|
||||
* requirement that fp->varobj lie directly on fp->scopeChain, although
|
||||
* it should be reachable using the prototype chain from a scope object (cf.
|
||||
* JSOPTION_VAROBJFIX in jsapi.h).
|
||||
*
|
||||
* If Get can't find JS_DEFAULT_XML_NAMESPACE_ID along the scope chain, it
|
||||
@ -7567,9 +7567,10 @@ js_SetDefaultXMLNamespace(JSContext *cx, jsval v)
|
||||
v = OBJECT_TO_JSVAL(ns);
|
||||
|
||||
fp = js_GetTopStackFrame(cx);
|
||||
varobj = fp->varobj;
|
||||
varobj = fp->varobj(cx);
|
||||
if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, v,
|
||||
JS_PropertyStub, JS_PropertyStub, JSPROP_PERMANENT)) {
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JSPROP_PERMANENT)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
|
Loading…
Reference in New Issue
Block a user