Bug 394551: no JS frames for fast native calls. r=brendan

This commit is contained in:
igor@mir2.org 2007-09-17 12:08:46 -07:00
parent d480384b48
commit 065a93dd1c
10 changed files with 330 additions and 441 deletions

View File

@ -4136,7 +4136,6 @@ js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp)
jsval fsv;
JSFunctionSpec *fs;
JSObject *tmp;
JSStackFrame *fp;
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(*vp), 0, &fsv))
return JS_FALSE;
@ -4171,13 +4170,8 @@ js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp)
* Follow Function.prototype.apply and .call by using the global object as
* the 'this' param if no args.
*/
fp = cx->fp;
JS_ASSERT((fp->flags & JSFRAME_IN_FAST_CALL) || fp->argv == vp + 2);
if (!js_ComputeThis(cx, vp + 2))
return JS_FALSE;
if (!(fp->flags & JSFRAME_IN_FAST_CALL))
fp->thisp = JSVAL_TO_OBJECT(vp[1]);
/*
* Protect against argc underflowing. By calling js_ComputeThis, we made
* it as if the static was called with one parameter, the explicit |this|
@ -4197,8 +4191,6 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
JSFunctionSpec *fs;
JSObject *tmp;
JS_ASSERT(!(cx->fp->flags & JSFRAME_IN_FAST_CALL));
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
return JS_FALSE;
fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
@ -4961,7 +4953,6 @@ JS_IsRunning(JSContext *cx)
JS_PUBLIC_API(JSBool)
JS_IsConstructing(JSContext *cx)
{
JS_ASSERT(!cx->fp || !(cx->fp->flags & JSFRAME_IN_FAST_CALL));
return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
}
@ -4971,7 +4962,6 @@ JS_IsAssigning(JSContext *cx)
JSStackFrame *fp;
jsbytecode *pc;
JS_ASSERT(!cx->fp || !(cx->fp->flags & JSFRAME_IN_FAST_CALL));
for (fp = cx->fp; fp && !fp->script; fp = fp->down)
continue;
if (!fp || !(pc = fp->pc))
@ -4997,7 +4987,6 @@ JS_SaveFrameChain(JSContext *cx)
if (!fp)
return fp;
JS_ASSERT(!(fp->flags & JSFRAME_IN_FAST_CALL));
JS_ASSERT(!fp->dormantNext);
fp->dormantNext = cx->dormantFrameChain;
cx->dormantFrameChain = fp;

View File

@ -1762,29 +1762,23 @@ typedef enum ArrayExtraMode {
static JSBool
array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp)
{
enum { ELEM, TEMP, RVAL, NROOTS };
jsval *argv, roots[NROOTS], *sp, *origsp, *oldsp;
JSObject *obj;
JSBool ok, cond, hole;
jsuint length, newlen;
jsval *argv, *elemroot, *invokevp, *sp;
JSBool ok, cond, hole;
JSObject *callable, *thisp, *newarr;
jsint start, end, step, i;
JSTempValueRooter tvr;
void *mark;
JSStackFrame *fp;
/* Hoist the explicit local root address computation. */
argv = vp + 2;
obj = JSVAL_TO_OBJECT(vp[1]);
ok = js_GetLengthProperty(cx, obj, &length);
if (!ok)
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
/*
* First, get or compute our callee, so that we error out consistently
* when passed a non-callable object.
*/
argv = vp + 2;
callable = js_ValueToCallableObject(cx, &argv[0], JSV2F_SEARCH_STACK);
if (!callable)
return JS_FALSE;
@ -1798,8 +1792,6 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp)
newarr = NULL;
#endif
start = 0, end = length, step = 1;
memset(roots, 0, sizeof roots);
JS_PUSH_TEMP_ROOT(cx, NROOTS, roots, &tvr);
switch (mode) {
case REDUCE_RIGHT:
@ -1809,24 +1801,21 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp)
if (length == 0 && argc == 1) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_EMPTY_ARRAY_REDUCE);
ok = JS_FALSE;
goto early_out;
return JS_FALSE;
}
if (argc >= 2) {
roots[RVAL] = argv[1];
*vp = argv[1];
} else {
do {
ok = GetArrayElement(cx, obj, start, &hole, &roots[RVAL]);
if (!ok)
goto early_out;
if (!GetArrayElement(cx, obj, start, &hole, vp))
return JS_FALSE;
start += step;
} while (hole && start != end);
if (hole && start == end) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_EMPTY_ARRAY_REDUCE);
ok = JS_FALSE;
goto early_out;
return JS_FALSE;
}
}
break;
@ -1834,87 +1823,80 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp)
case FILTER:
newlen = (mode == MAP) ? length : 0;
newarr = js_NewArrayObject(cx, newlen, NULL);
if (!newarr) {
ok = JS_FALSE;
goto early_out;
}
roots[RVAL] = OBJECT_TO_JSVAL(newarr);
if (!newarr)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(newarr);
break;
case SOME:
roots[RVAL] = JSVAL_FALSE;
*vp = JSVAL_FALSE;
break;
case EVERY:
roots[RVAL] = JSVAL_TRUE;
*vp = JSVAL_TRUE;
break;
case FOREACH:
*vp = JSVAL_VOID;
break;
}
if (length == 0)
goto early_out;
return JS_TRUE;
if (argc > 1 && !REDUCE_MODE(mode)) {
ok = js_ValueToObject(cx, argv[1], &thisp);
if (!ok)
goto early_out;
if (!js_ValueToObject(cx, argv[1], &thisp))
return JS_FALSE;
argv[1] = OBJECT_TO_JSVAL(thisp);
} else {
thisp = NULL;
}
/*
* For all but REDUCE, we call with 3 args (value, index, array), plus
* room for rval. REDUCE requires 4 args (accum, value, index, array).
* For all but REDUCE, we call with 3 args (value, index, array). REDUCE
* requires 4 args (accum, value, index, array).
*/
argc = 3 + REDUCE_MODE(mode);
origsp = js_AllocStack(cx, 2 + argc + 1, &mark);
if (!origsp) {
ok = JS_FALSE;
goto early_out;
}
elemroot = js_AllocStack(cx, 1 + 2 + argc, &mark);
if (!elemroot)
return JS_FALSE;
/* Lift current frame to include our args. */
fp = cx->fp;
oldsp = fp->sp;
/* From this point the control must flow through out:. */
ok = JS_TRUE;
invokevp = elemroot + 1;
for (i = start; i != end; i += step) {
ok = (JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) &&
GetArrayElement(cx, obj, i, &hole, &roots[ELEM]));
ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) &&
GetArrayElement(cx, obj, i, &hole, elemroot);
if (!ok)
break;
goto out;
if (hole)
continue;
/*
* Push callable and 'this', then args. We must do this for every
* iteration around the loop since js_Invoke uses origsp[0] for return
* value storage, while some native functions use origsp[1] for local
* iteration around the loop since js_Invoke uses spbase[0] for return
* value storage, while some native functions use spbase[1] for local
* rooting.
*/
sp = origsp;
sp = invokevp;
*sp++ = OBJECT_TO_JSVAL(callable);
*sp++ = OBJECT_TO_JSVAL(thisp);
if (REDUCE_MODE(mode))
*sp++ = roots[RVAL];
*sp++ = roots[ELEM];
*sp++ = *vp;
*sp++ = *elemroot;
*sp++ = INT_TO_JSVAL(i);
*sp++ = OBJECT_TO_JSVAL(obj);
/* Do the call. */
fp->sp = sp;
ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
roots[TEMP] = fp->sp[-1];
fp->sp = oldsp;
ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL);
if (!ok)
break;
if (mode > MAP) {
if (roots[TEMP] == JSVAL_NULL) {
if (*invokevp == JSVAL_NULL) {
cond = JS_FALSE;
} else if (JSVAL_IS_BOOLEAN(roots[TEMP])) {
cond = JSVAL_TO_BOOLEAN(roots[TEMP]);
} else if (JSVAL_IS_BOOLEAN(*invokevp)) {
cond = JSVAL_TO_BOOLEAN(*invokevp);
} else {
ok = js_ValueToBoolean(cx, roots[TEMP], &cond);
ok = js_ValueToBoolean(cx, *invokevp, &cond);
if (!ok)
goto out;
}
@ -1925,30 +1907,30 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp)
break;
case REDUCE:
case REDUCE_RIGHT:
roots[RVAL] = roots[TEMP];
*vp = *invokevp;
break;
case MAP:
ok = SetArrayElement(cx, newarr, i, roots[TEMP]);
ok = SetArrayElement(cx, newarr, i, *invokevp);
if (!ok)
goto out;
break;
case FILTER:
if (!cond)
break;
/* The filter passed roots[ELEM], so push it onto our result. */
ok = SetArrayElement(cx, newarr, newlen++, roots[ELEM]);
/* The filter passed *elemroot, so push it onto our result. */
ok = SetArrayElement(cx, newarr, newlen++, *elemroot);
if (!ok)
goto out;
break;
case SOME:
if (cond) {
roots[RVAL] = JSVAL_TRUE;
*vp = JSVAL_TRUE;
goto out;
}
break;
case EVERY:
if (!cond) {
roots[RVAL] = JSVAL_FALSE;
*vp = JSVAL_FALSE;
goto out;
}
break;
@ -1959,9 +1941,6 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp)
js_FreeStack(cx, mark);
if (ok && mode == FILTER)
ok = js_SetLengthProperty(cx, newarr, newlen);
early_out:
*vp = roots[RVAL];
JS_POP_TEMP_ROOT(cx, &tvr);
return ok;
}

View File

@ -545,11 +545,16 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
* identify the guilty party. So that the watcher appears to
* be active to obj_eval and other such code, point frame.pc
* at the JSOP_STOP at the end of the script.
*
* The pseudo-frame is not created for fast natives as they
* are treated as interpreter frame extensions and always
* trusted.
*/
JSObject *closure;
JSClass *clasp;
JSFunction *fun;
JSScript *script;
JSBool injectFrame;
uintN nslots;
jsval smallv[5];
jsval *argv;
@ -569,56 +574,66 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
}
nslots = 2;
injectFrame = JS_TRUE;
if (fun) {
nslots += FUN_MINARGS(fun);
if (!FUN_INTERPRETED(fun))
if (!FUN_INTERPRETED(fun)) {
nslots += fun->u.n.extra;
}
if (nslots <= JS_ARRAY_LENGTH(smallv)) {
argv = smallv;
} else {
argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval));
if (!argv) {
DBG_LOCK(rt);
DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
return JS_FALSE;
injectFrame = !(fun->flags & JSFUN_FAST_NATIVE);
}
}
argv[0] = OBJECT_TO_JSVAL(closure);
argv[1] = JSVAL_NULL;
memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
if (injectFrame) {
if (nslots <= JS_ARRAY_LENGTH(smallv)) {
argv = smallv;
} else {
argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval));
if (!argv) {
DBG_LOCK(rt);
DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
return JS_FALSE;
}
}
memset(&frame, 0, sizeof(frame));
frame.script = script;
if (script) {
JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
frame.pc = script->code + script->length
- JSOP_STOP_LENGTH;
argv[0] = OBJECT_TO_JSVAL(closure);
argv[1] = JSVAL_NULL;
memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
memset(&frame, 0, sizeof(frame));
frame.script = script;
if (script) {
JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
frame.pc = script->code + script->length
- JSOP_STOP_LENGTH;
}
frame.callee = closure;
frame.fun = fun;
frame.argv = argv + 2;
frame.down = cx->fp;
frame.scopeChain = OBJ_GET_PARENT(cx, closure);
cx->fp = &frame;
}
frame.callee = closure;
frame.fun = fun;
frame.argv = argv + 2;
frame.down = cx->fp;
frame.scopeChain = OBJ_GET_PARENT(cx, closure);
cx->fp = &frame;
#ifdef __GNUC__
else
argv = NULL; /* suppress bogus gcc warnings */
#endif
ok = !wp->setter ||
((sprop->attrs & JSPROP_SETTER)
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
1, vp, vp)
: wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
if (injectFrame) {
/* Evil code can cause us to have an arguments object. */
if (frame.callobj)
ok &= js_PutCallObject(cx, &frame);
if (frame.argsobj)
ok &= js_PutArgsObject(cx, &frame);
/* Evil code can cause us to have an arguments object. */
if (frame.callobj)
ok &= js_PutCallObject(cx, &frame);
if (frame.argsobj)
ok &= js_PutArgsObject(cx, &frame);
cx->fp = frame.down;
if (argv != smallv)
JS_free(cx, argv);
cx->fp = frame.down;
if (argv != smallv)
JS_free(cx, argv);
}
}
DBG_LOCK(rt);
return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;

View File

@ -1059,8 +1059,6 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
break;
case FUN_CALLER:
while (fp && (fp->flags & JSFRAME_SKIP_CALLER) && fp->down)
fp = fp->down;
if (fp && fp->down && fp->down->fun)
*vp = OBJECT_TO_JSVAL(fp->down->callee);
else
@ -1590,11 +1588,9 @@ static JSBool
fun_call(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj;
jsval fval, *argv, *sp, *oldsp;
jsval fval, *argv, *invokevp;
JSString *str;
void *mark;
uintN i;
JSStackFrame *fp;
JSBool ok;
obj = JSVAL_TO_OBJECT(vp[1]);
@ -1632,28 +1628,17 @@ fun_call(JSContext *cx, uintN argc, jsval *vp)
}
/* Allocate stack space for fval, obj, and the args. */
sp = js_AllocStack(cx, 2 + argc, &mark);
if (!sp)
invokevp = js_AllocStack(cx, 2 + argc, &mark);
if (!invokevp)
return JS_FALSE;
/* Push fval, obj, and the args. */
*sp++ = fval;
*sp++ = OBJECT_TO_JSVAL(obj);
for (i = 0; i < argc; i++)
*sp++ = argv[i];
invokevp[0] = fval;
invokevp[1] = OBJECT_TO_JSVAL(obj);
memcpy(invokevp + 2, argv, argc * sizeof *argv);
/* Lift current frame to include the args and do the call. */
fp = cx->fp;
oldsp = fp->sp;
fp->sp = sp;
ok = js_Invoke(cx, argc,
(fp->flags & JSFRAME_IN_FAST_CALL)
? JSINVOKE_INTERNAL
: JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
/* Store rval and pop stack back to our frame's sp. */
*vp = fp->sp[-1];
fp->sp = oldsp;
ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL);
*vp = *invokevp;
js_FreeStack(cx, mark);
return ok;
}
@ -1662,13 +1647,12 @@ static JSBool
fun_apply(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj, *aobj;
jsval fval, *sp, *oldsp;
jsval fval, *invokevp, *sp;
JSString *str;
jsuint length;
JSBool arraylike, ok;
void *mark;
uintN i;
JSStackFrame *fp;
if (argc == 0) {
/* Will get globalObject as 'this' and no other arguments. */
@ -1727,11 +1711,12 @@ fun_apply(JSContext *cx, uintN argc, jsval *vp)
/* Allocate stack space for fval, obj, and the args. */
argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1);
sp = js_AllocStack(cx, 2 + argc, &mark);
if (!sp)
invokevp = js_AllocStack(cx, 2 + argc, &mark);
if (!invokevp)
return JS_FALSE;
/* Push fval, obj, and aobj's elements as args. */
sp = invokevp;
*sp++ = fval;
*sp++ = OBJECT_TO_JSVAL(obj);
for (i = 0; i < argc; i++) {
@ -1741,18 +1726,8 @@ fun_apply(JSContext *cx, uintN argc, jsval *vp)
sp++;
}
/* Lift current frame to include the args and do the call. */
fp = cx->fp;
oldsp = fp->sp;
fp->sp = sp;
ok = js_Invoke(cx, argc,
(fp->flags & JSFRAME_IN_FAST_CALL)
? JSINVOKE_INTERNAL
: JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
/* Store rval and pop stack back to our frame's sp. */
*vp = fp->sp[-1];
fp->sp = oldsp;
ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL);
*vp = *invokevp;
out:
js_FreeStack(cx, mark);
return ok;
@ -1765,8 +1740,7 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
JSObject *aobj;
uintN length, i;
void *mark;
jsval *sp, *newsp, *oldsp;
JSStackFrame *fp;
jsval *invokevp, *sp;
JSBool ok;
if (JSVAL_IS_PRIMITIVE(vp[2]) ||
@ -1783,12 +1757,11 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
if (length >= ARRAY_INIT_LIMIT)
length = ARRAY_INIT_LIMIT - 1;
newsp = sp = js_AllocStack(cx, 2 + length, &mark);
if (!sp)
invokevp = js_AllocStack(cx, 2 + length, &mark);
if (!invokevp)
return JS_FALSE;
fp = cx->fp;
oldsp = fp->sp;
sp = invokevp;
*sp++ = vp[1];
*sp++ = JSVAL_NULL; /* This is filled automagically. */
for (i = 0; i < length; i++) {
@ -1798,12 +1771,8 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
sp++;
}
oldsp = fp->sp;
fp->sp = sp;
ok = js_InvokeConstructor(cx, newsp, length);
*vp = fp->sp[-1];
fp->sp = oldsp;
ok = js_InvokeConstructor(cx, invokevp, length);
*vp = *invokevp;
out:
js_FreeStack(cx, mark);
return ok;
@ -2358,9 +2327,7 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
}
js_ReportValueError3(cx, error,
(fp &&
!(fp->flags & JSFRAME_IN_FAST_CALL) &&
fp->spbase <= vp && vp < fp->sp)
(fp && fp->spbase <= vp && vp < fp->sp)
? vp - fp->sp
: (flags & JSV2F_SEARCH_STACK)
? JSDVG_SEARCH_STACK

View File

@ -2205,8 +2205,7 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num,
void
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
{
uintN depth, nslots, minargs;
jsval *vp;
uintN nslots, minargs, skip;
if (fp->callobj)
JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
@ -2221,11 +2220,9 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
* Don't mark what has not been pushed yet, or what has been
* popped already.
*/
depth = fp->script->depth;
nslots = (JS_UPTRDIFF(fp->sp, fp->spbase)
< depth * sizeof(jsval))
? (uintN)(fp->sp - fp->spbase)
: depth;
JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <=
fp->script->depth * sizeof(jsval));
nslots = (uintN) (fp->sp - fp->spbase);
TRACE_JSVALS(trc, nslots, fp->spbase, "operand");
}
}
@ -2239,32 +2236,20 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
JS_CALL_OBJECT_TRACER(trc, fp->callee, "callee");
if (fp->argv) {
/* Trace argv including callee and thisp slots. */
nslots = fp->argc;
skip = 0;
if (fp->fun) {
minargs = FUN_MINARGS(fp->fun);
if (minargs > nslots)
nslots = minargs;
if (!FUN_INTERPRETED(fp->fun))
if (!FUN_INTERPRETED(fp->fun)) {
JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE));
nslots += fp->fun->u.n.extra;
}
nslots += 2;
vp = fp->argv - 2;
if (fp->down && fp->down->spbase) {
/*
* Avoid unnecessary tracing in the common case when args overlaps
* with the stack segment of the previous frame. That segment is
* traced via the above spbase code and, when sp > spbase + depth,
* during tracing of the stack headers in js_TraceContext.
*/
if (JS_UPTRDIFF(vp, fp->down->spbase) <
JS_UPTRDIFF(fp->down->sp, fp->down->spbase)) {
JS_ASSERT((size_t)nslots >= (size_t)(fp->down->sp - vp));
nslots -= (uintN)(fp->down->sp - vp);
vp = fp->down->sp;
}
if (fp->fun->flags & JSFRAME_ROOTED_ARGV)
skip = 2 + fp->argc;
}
TRACE_JSVALS(trc, nslots, vp, "arg");
TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand");
}
JS_CALL_VALUE_TRACER(trc, fp->rval, "rval");
if (fp->vars)

View File

@ -81,13 +81,9 @@
*/
#define PUSH(v) (*sp++ = (v))
#define POP() (*--sp)
#ifdef DEBUG
#define SAVE_SP(fp) \
(JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase), \
(fp)->sp = sp)
#else
#define SAVE_SP(fp) ((fp)->sp = sp)
#endif
#define RESTORE_SP(fp) (sp = (fp)->sp)
/*
@ -265,6 +261,35 @@
v = sp[n]; \
JS_END_MACRO
/*
* Check if the current arena has enough space to fit nslots after sp and, if
* so, reserve the necessary space.
*/
static JSBool
AllocateAfterSP(JSContext *cx, jsval *sp, uintN nslots)
{
uintN surplus;
jsval *sp2;
JS_ASSERT((jsval *) cx->stackPool.current->base <= sp);
JS_ASSERT(sp <= (jsval *) cx->stackPool.current->avail);
surplus = (jsval *) cx->stackPool.current->avail - sp;
if (nslots <= surplus)
return JS_TRUE;
/*
* No room before current->avail, check if the arena has enough space to
* fit the missing slots before the limit.
*/
if (nslots > (size_t) ((jsval *) cx->stackPool.current->limit - sp))
return JS_FALSE;
JS_ARENA_ALLOCATE_CAST(sp2, jsval *, &cx->stackPool,
(nslots - surplus) * sizeof(jsval));
JS_ASSERT(sp2 == sp + surplus);
return JS_TRUE;
}
JS_FRIEND_API(jsval *)
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
{
@ -291,10 +316,9 @@ js_FreeRawStack(JSContext *cx, void *mark)
JS_FRIEND_API(jsval *)
js_AllocStack(JSContext *cx, uintN nslots, void **markp)
{
jsval *sp, *vp, *end;
jsval *sp;
JSArena *a;
JSStackHeader *sh;
JSStackFrame *fp;
/* Callers don't check for zero nslots: we do to avoid empty segments. */
if (nslots == 0) {
@ -316,24 +340,9 @@ js_AllocStack(JSContext *cx, uintN nslots, void **markp)
a->avail -= 2 * sizeof(jsval);
} else {
/*
* Need a new stack segment, so we must initialize unused slots in the
* current frame. See js_GC, just before marking the "operand" jsvals,
* where we scan from fp->spbase to fp->sp or through fp->script->depth
* (whichever covers fewer slots).
* Need a new stack segment, so allocate and push a stack segment
* header from the 2 extra slots.
*/
fp = cx->fp;
if (fp && fp->script && fp->spbase) {
#ifdef DEBUG
jsuword depthdiff = fp->script->depth * sizeof(jsval);
JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff);
JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);
#endif
end = fp->spbase + fp->script->depth;
for (vp = fp->sp; vp < end; vp++)
*vp = JSVAL_VOID;
}
/* Allocate and push a stack segment header from the 2 extra slots. */
sh = (JSStackHeader *)sp;
sh->nslots = nslots;
sh->down = cx->stackHeaders;
@ -604,9 +613,9 @@ js_ComputeThis(JSContext *cx, jsval *argv)
#if JS_HAS_NO_SUCH_METHOD
static JSBool
NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags,
uintN argc)
NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags)
{
JSStackFrame *fp;
JSObject *thisp, *argsobj;
JSAtom *atom;
jsval *sp, roots[3];
@ -618,6 +627,7 @@ NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags,
/* NB: js_ComputeThis or equivalent must have been called already. */
JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0]));
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
fp = cx->fp;
RESTORE_SP(fp);
/* From here on, control must flow through label out: to return. */
@ -1029,11 +1039,6 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
# define ASSERT_NOT_THROWING(cx) /* nothing */
#endif
#define START_FAST_CALL(fp) (JS_ASSERT(!((fp)->flags & JSFRAME_IN_FAST_CALL)),\
(fp)->flags |= JSFRAME_IN_FAST_CALL)
#define END_FAST_CALL(fp) (JS_ASSERT((fp)->flags & JSFRAME_IN_FAST_CALL), \
(fp)->flags &= ~JSFRAME_IN_FAST_CALL)
/*
* We check if the function accepts a primitive value as |this|. For that we
* use a table that maps value's tag into the corresponding function flag.
@ -1065,12 +1070,12 @@ static const uint16 PrimitiveTestFlags[] = {
* when done. Then push the return value.
*/
JS_FRIEND_API(JSBool)
js_Invoke(JSContext *cx, uintN argc, uintN flags)
js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
{
void *mark;
JSStackFrame *fp, frame;
jsval *sp, *newsp, *limit;
jsval *vp, v;
JSStackFrame frame;
jsval *sp, *argv, *newvp;
jsval v;
JSObject *funobj, *parent;
JSBool ok;
JSClass *clasp;
@ -1078,24 +1083,21 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
JSNative native;
JSFunction *fun;
JSScript *script;
uintN nslots, nvars, nalloc, surplus;
uintN nslots, nvars, i;
uint32 rootedArgsFlag;
JSInterpreterHook hook;
void *hookData;
/* Mark the top of stack and load frequently-used registers. */
mark = JS_ARENA_MARK(&cx->stackPool);
fp = cx->fp;
sp = fp->sp;
/* [vp .. vp + 2 + argc) must belong to the last JS stack arena. */
JS_ASSERT((jsval *) cx->stackPool.current->base <= vp);
JS_ASSERT(vp + 2 + argc <= (jsval *) cx->stackPool.current->avail);
/*
* Set vp to the callee value's stack slot (it's where rval goes).
* Once vp is set, control should flow through label out2: to return.
* Set frame.rval early so native class and object ops can throw and
* return false, causing a goto out2 with ok set to false.
* Mark the top of stack and load frequently-used registers. After this
* point the control should flow through label out2: to return.
*/
vp = sp - (2 + argc);
mark = JS_ARENA_MARK(&cx->stackPool);
v = *vp;
frame.rval = JSVAL_VOID;
/*
* A callee must be an object reference, unless its 'this' parameter
@ -1110,10 +1112,8 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
*/
if (JSVAL_IS_PRIMITIVE(v)) {
#if JS_HAS_NO_SUCH_METHOD
if (fp->script && !(flags & JSINVOKE_INTERNAL)) {
ok = NoSuchMethod(cx, fp, vp, flags, argc);
if (ok)
frame.rval = *vp;
if (cx->fp && cx->fp->script && !(flags & JSINVOKE_INTERNAL)) {
ok = NoSuchMethod(cx, argc, vp, flags);
goto out2;
}
#endif
@ -1170,8 +1170,8 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
have_fun:
/* Get private data and set derived locals from it. */
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj);
nalloc = FUN_MINARGS(fun);
nslots = (nalloc > argc) ? nalloc - argc : 0;
nslots = FUN_MINARGS(fun);
nslots = (nslots > argc) ? nslots - argc : 0;
if (FUN_INTERPRETED(fun)) {
native = NULL;
script = fun->u.i.script;
@ -1189,14 +1189,12 @@ have_fun:
} else if (!JSVAL_IS_OBJECT(vp[1])) {
JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT));
if (PRIMITIVE_THIS_TEST(fun, vp[1]))
goto init_frame;
goto init_slots;
}
}
if (flags & JSINVOKE_CONSTRUCT) {
/* Default return value for a constructor is the new object. */
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
frame.rval = vp[1];
} else {
/*
* We must call js_ComputeThis in case we are not called from the
@ -1208,9 +1206,80 @@ have_fun:
goto out2;
}
init_frame:
init_slots:
argv = vp + 2;
sp = argv + argc;
rootedArgsFlag = JSFRAME_ROOTED_ARGV;
if (nslots != 0) {
/*
* The extra slots required by the function must be continues with the
* arguments. Thus, when the last arena does not have room to fit
* nslots right after sp and AllocateAfterSP fails, we have to copy
* [vp..vp+2+argc) slots and clear rootedArgsFlag to root the copy.
*/
if (!AllocateAfterSP(cx, sp, nslots)) {
rootedArgsFlag = 0;
newvp = js_AllocRawStack(cx, 2 + argc + nslots, NULL);
if (!newvp) {
ok = JS_FALSE;
goto out2;
}
memcpy(newvp, vp, (2 + argc) * sizeof(jsval));
argv = newvp + 2;
sp = argv + argc;
}
/* Push void to initialize missing args. */
i = nslots;
do {
PUSH(JSVAL_VOID);
} while (--i != 0);
}
if (native && fun && (fun->flags & JSFUN_FAST_NATIVE)) {
JSTempValueRooter tvr;
#ifdef DEBUG_NOT_THROWING
JSBool alreadyThrowing = cx->throwing;
#endif
#if JS_HAS_LVALUE_RETURN
/* Set by JS_SetCallReturnValue2, used to return reference types. */
cx->rval2set = JS_FALSE;
#endif
/* Root the extra slots that are not covered by [vp..vp+2+argc). */
i = rootedArgsFlag ? 2 + argc : 0;
JS_PUSH_TEMP_ROOT(cx, 2 + argc + nslots - i, argv - 2 + i, &tvr);
ok = ((JSFastNative) native)(cx, argc, argv - 2);
JS_POP_TEMP_ROOT(cx, &tvr);
JS_RUNTIME_METER(cx->runtime, nativeCalls);
#ifdef DEBUG_NOT_THROWING
if (ok && !alreadyThrowing)
ASSERT_NOT_THROWING(cx);
#endif
goto out2;
}
/* Now allocate stack space for local variables of interpreted function. */
if (nvars) {
if (!AllocateAfterSP(cx, sp, nvars)) {
/* NB: Discontinuity between argv and vars. */
sp = js_AllocRawStack(cx, nvars, NULL);
if (!sp) {
ok = JS_FALSE;
goto out2;
}
}
/* Push void to initialize local variables. */
i = nvars;
do {
PUSH(JSVAL_VOID);
} while (--i != 0);
}
/*
* Initialize the rest of frame, except for sp (set by SAVE_SP later).
* Initialize the frame, except for sp (set by SAVE_SP later).
*
* To set thisp we use an explicit cast and not JSVAL_TO_OBJECT, as vp[1]
* can be a primitive value here for those native functions specified with
@ -1223,17 +1292,20 @@ have_fun:
frame.callee = funobj;
frame.fun = fun;
frame.argc = argc;
frame.argv = sp - argc;
frame.argv = argv;
/* Default return value for a constructor is the new object. */
frame.rval = (flags & JSINVOKE_CONSTRUCT) ? vp[1] : JSVAL_VOID;
frame.nvars = nvars;
frame.vars = sp;
frame.down = fp;
frame.vars = sp - nvars;
frame.down = cx->fp;
frame.annotation = NULL;
frame.scopeChain = NULL; /* set below for real, after cx->fp is set */
frame.pc = NULL;
frame.spbase = NULL;
frame.sharpDepth = 0;
frame.sharpArray = NULL;
frame.flags = flags;
frame.flags = flags | rootedArgsFlag;
frame.dormantNext = NULL;
frame.xmlNamespace = NULL;
frame.blockChain = NULL;
@ -1245,77 +1317,6 @@ have_fun:
hook = cx->debugHooks->callHook;
hookData = NULL;
/* Check for argument slots required by the function. */
if (nslots) {
/* All arguments must be contiguous, so we may have to copy actuals. */
nalloc = nslots;
limit = (jsval *) cx->stackPool.current->limit;
JS_ASSERT((jsval *) cx->stackPool.current->base <= sp && sp <= limit);
if (sp + nslots > limit) {
/* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
nalloc += 2 + argc;
} else {
/* Take advantage of surplus slots in the caller's frame depth. */
JS_ASSERT((jsval *)mark >= sp);
surplus = (jsval *)mark - sp;
nalloc -= surplus;
}
/* Check whether we have enough space in the caller's frame. */
if ((intN)nalloc > 0) {
/* Need space for actuals plus missing formals minus surplus. */
newsp = js_AllocRawStack(cx, nalloc, NULL);
if (!newsp) {
ok = JS_FALSE;
goto out;
}
/* If we couldn't allocate contiguous args, copy actuals now. */
if (newsp != mark) {
JS_ASSERT(sp + nslots > limit);
JS_ASSERT(2 + argc + nslots == nalloc);
*newsp++ = vp[0];
*newsp++ = vp[1];
if (argc)
memcpy(newsp, frame.argv, argc * sizeof(jsval));
frame.argv = newsp;
sp = frame.vars = newsp + argc;
}
}
/* Advance frame.vars to make room for the missing args. */
frame.vars += nslots;
/* Push void to initialize missing args. */
do {
PUSH(JSVAL_VOID);
} while (--nslots != 0);
}
JS_ASSERT(nslots == 0);
/* Now allocate stack space for local variables. */
if (nvars) {
JS_ASSERT((jsval *)cx->stackPool.current->avail >= frame.vars);
surplus = (jsval *)cx->stackPool.current->avail - frame.vars;
if (surplus < nvars) {
newsp = js_AllocRawStack(cx, nvars, NULL);
if (!newsp) {
ok = JS_FALSE;
goto out;
}
if (newsp != sp) {
/* NB: Discontinuity between argv and vars. */
sp = frame.vars = newsp;
}
}
/* Push void to initialize local variables. */
do {
PUSH(JSVAL_VOID);
} while (--nvars != 0);
}
JS_ASSERT(nvars == 0);
/* Store the current sp in frame before calling fun. */
SAVE_SP(&frame);
@ -1335,23 +1336,20 @@ have_fun:
#endif
/* If native, use caller varobj and scopeChain for eval. */
frame.varobj = fp->varobj;
frame.scopeChain = fp->scopeChain;
if (cx->fp) {
frame.varobj = cx->fp->varobj;
frame.scopeChain = cx->fp->scopeChain;
} else {
frame.varobj = NULL;
frame.scopeChain = NULL;
}
/* But ensure that we have a scope chain. */
if (!frame.scopeChain)
frame.scopeChain = parent;
if (fun && (fun->flags & JSFUN_FAST_NATIVE)) {
/*
* Note the lack of START/END_FAST_CALL bracketing here. Unlike
* the other JSFastNative call (see the JSOP_CALL special case in
* js_Interpret), we have a full stack frame for this call.
*/
ok = ((JSFastNative) native)(cx, argc, frame.argv - 2);
frame.rval = frame.argv[-2];
} else {
#ifdef DEBUG_brendan
{
static FILE *fp;
if (!fp) {
fp = fopen("/tmp/slow-natives.dump", "w");
@ -1374,9 +1372,9 @@ have_fun:
? JS_GetFunctionName(fun)
: "???");
}
#endif
ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
}
#endif
ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
JS_RUNTIME_METER(cx->runtime, nativeCalls);
#ifdef DEBUG_NOT_THROWING
@ -1418,24 +1416,16 @@ out:
if (frame.argsobj)
ok &= js_PutArgsObject(cx, &frame);
*vp = frame.rval;
/* Restore cx->fp now that we're done releasing frame objects. */
cx->fp = fp;
cx->fp = frame.down;
out2:
/* Pop everything we may have allocated off the stack. */
JS_ARENA_RELEASE(&cx->stackPool, mark);
/* Store the return value and restore sp just above it. */
*vp = frame.rval;
fp->sp = vp + 1;
/*
* Store the location of the JSOP_CALL or JSOP_EVAL that generated the
* return value, but only if this is an external (compiled from script
* source) call that has stack budget for the generating pc.
*/
if (fp->script && !(flags & JSINVOKE_INTERNAL))
vp[-(intN)fp->script->depth] = (jsval)fp->pc;
if (!ok)
*vp = JSVAL_NULL;
return ok;
bad:
@ -1448,33 +1438,20 @@ JSBool
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
uintN argc, jsval *argv, jsval *rval)
{
JSStackFrame *fp, *oldfp, frame;
jsval *oldsp, *sp;
jsval *invokevp;
void *mark;
uintN i;
JSBool ok;
fp = oldfp = cx->fp;
if (!fp) {
memset(&frame, 0, sizeof frame);
cx->fp = fp = &frame;
}
oldsp = fp->sp;
sp = js_AllocStack(cx, 2 + argc, &mark);
if (!sp) {
ok = JS_FALSE;
goto out;
}
invokevp = js_AllocStack(cx, 2 + argc, &mark);
if (!invokevp)
return JS_FALSE;
PUSH(fval);
PUSH(OBJECT_TO_JSVAL(obj));
for (i = 0; i < argc; i++)
PUSH(argv[i]);
SAVE_SP(fp);
ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL);
invokevp[0] = fval;
invokevp[1] = OBJECT_TO_JSVAL(obj);
memcpy(invokevp + 2, argv, argc * sizeof *argv);
ok = js_Invoke(cx, argc, invokevp, flags | JSINVOKE_INTERNAL);
if (ok) {
RESTORE_SP(fp);
/*
* Store *rval in the a scoped local root if a scope is open, else in
* the lastInternalResult pigeon-hole GC root, solely so users of
@ -1482,7 +1459,7 @@ js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
* example) callers do not need to manage roots for local, temporary
* references to such results.
*/
*rval = POP_OPND();
*rval = *invokevp;
if (JSVAL_IS_GCTHING(*rval) && *rval != JSVAL_NULL) {
if (cx->localRootStack) {
if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0)
@ -1494,11 +1471,6 @@ js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
}
js_FreeStack(cx, mark);
out:
fp->sp = oldsp;
if (oldfp != fp)
cx->fp = oldfp;
return ok;
}
@ -1956,7 +1928,7 @@ js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc)
/* Now we have an object with a constructor method; call it. */
vp[1] = OBJECT_TO_JSVAL(obj);
if (!js_Invoke(cx, argc, JSINVOKE_CONSTRUCT)) {
if (!js_Invoke(cx, argc, vp, JSINVOKE_CONSTRUCT)) {
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
return JS_FALSE;
}
@ -3516,7 +3488,8 @@ interrupt:
ok = js_InvokeConstructor(cx, vp, argc);
if (!ok)
goto out;
RESTORE_SP(fp);
sp = vp + 1;
vp[-depth] = (jsval)pc;
LOAD_INTERRUPT_HANDLER(cx);
obj = JSVAL_TO_OBJECT(*vp);
len = js_CodeSpec[op].length;
@ -4088,7 +4061,12 @@ interrupt:
if (sp + nargs > fp->spbase + depth)
goto do_invoke;
do {
PUSH(JSVAL_VOID);
/*
* Use PUSH_OPND to set the proper pc values for
* the extra arguments. The decompiler relies on
* this.
*/
PUSH_OPND(JSVAL_VOID);
} while (--nargs != 0);
SAVE_SP(fp);
}
@ -4096,9 +4074,7 @@ interrupt:
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]) ||
PRIMITIVE_THIS_TEST(fun, vp[1]));
START_FAST_CALL(fp);
ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp);
END_FAST_CALL(fp);
if (!ok)
goto out;
sp = vp + 1;
@ -4108,8 +4084,9 @@ interrupt:
}
do_invoke:
ok = js_Invoke(cx, argc, 0);
RESTORE_SP(fp);
ok = js_Invoke(cx, argc, vp, 0);
sp = vp + 1;
vp[-depth] = (jsval)pc;
LOAD_INTERRUPT_HANDLER(cx);
if (!ok)
goto out;
@ -4146,8 +4123,10 @@ interrupt:
BEGIN_CASE(JSOP_SETCALL)
argc = GET_ARGC(pc);
SAVE_SP_AND_PC(fp);
ok = js_Invoke(cx, argc, 0);
RESTORE_SP(fp);
vp = sp - argc - 2;
ok = js_Invoke(cx, argc, vp, 0);
sp = vp + 1;
vp[-depth] = (jsval)pc;
LOAD_INTERRUPT_HANDLER(cx);
if (!ok)
goto out;

View File

@ -95,24 +95,21 @@ typedef struct JSInlineFrame {
/* JS stack frame flags. */
#define JSFRAME_CONSTRUCTING 0x01 /* frame is for a constructor invocation */
#define JSFRAME_INTERNAL 0x02 /* internal call, not invoked by a script */
#define JSFRAME_SKIP_CALLER 0x04 /* skip one link when evaluating f.caller
for this invocation of f */
#define JSFRAME_ASSIGNING 0x08 /* a complex (not simplex JOF_ASSIGNING) op
#define JSFRAME_ASSIGNING 0x04 /* a complex (not simplex JOF_ASSIGNING) op
is currently assigning to a property */
#define JSFRAME_DEBUGGER 0x10 /* frame for JS_EvaluateInStackFrame */
#define JSFRAME_EVAL 0x20 /* frame for obj_eval */
#define JSFRAME_SPECIAL 0x30 /* special evaluation frame flags */
#define JSFRAME_COMPILING 0x40 /* frame is being used by compiler */
#define JSFRAME_COMPILE_N_GO 0x80 /* compiler-and-go mode, can optimize name
#define JSFRAME_DEBUGGER 0x08 /* frame for JS_EvaluateInStackFrame */
#define JSFRAME_EVAL 0x10 /* frame for obj_eval */
#define JSFRAME_SPECIAL 0x18 /* special evaluation frame flags */
#define JSFRAME_COMPILING 0x20 /* frame is being used by compiler */
#define JSFRAME_COMPILE_N_GO 0x40 /* compiler-and-go mode, can optimize name
references based on scope chain */
#define JSFRAME_SCRIPT_OBJECT 0x100 /* compiling source for a Script object */
#define JSFRAME_YIELDING 0x200 /* js_Interpret dispatched JSOP_YIELD */
#define JSFRAME_FILTERING 0x400 /* XML filtering predicate expression */
#define JSFRAME_ITERATOR 0x800 /* trying to get an iterator for for-in */
#define JSFRAME_POP_BLOCKS 0x1000 /* scope chain contains blocks to pop */
#define JSFRAME_GENERATOR 0x2000 /* frame belongs to generator-iterator */
#define JSFRAME_IN_FAST_CALL 0x4000 /* calling frame is calling a fast native */
#define JSFRAME_DID_SET_RVAL 0x8000 /* fast native used JS_SET_RVAL(cx, vp) */
#define JSFRAME_SCRIPT_OBJECT 0x80 /* compiling source for a Script object */
#define JSFRAME_YIELDING 0x100 /* js_Interpret dispatched JSOP_YIELD */
#define JSFRAME_FILTERING 0x200 /* XML filtering predicate expression */
#define JSFRAME_ITERATOR 0x400 /* trying to get an iterator for for-in */
#define JSFRAME_POP_BLOCKS 0x800 /* scope chain contains blocks to pop */
#define JSFRAME_GENERATOR 0x1000 /* frame belongs to generator-iterator */
#define JSFRAME_ROOTED_ARGV 0x2000 /* frame.argv is rooted by the caller */
#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */
#define JSFRAME_OVERRIDE_BITS 8
@ -178,11 +175,15 @@ js_ComputeThis(JSContext *cx, jsval *argv);
/*
* NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp
* is non-null), and that the callee, |this| parameter, and actual arguments
* are already pushed on the stack under cx->fp->sp.
* is non-null), and that vp points to the callee, |this| parameter, and
* actual arguments of the call. [vp .. vp + 2 + argc) must belong to the last
* JS stack segment that js_AllocStack or js_AllocRawStack allocated. The
* function may use the space available after vp + 2 + argc in the stack
* segment for temporaries so the caller should not use that space for values
* that must be preserved across the call.
*/
extern JS_FRIEND_API(JSBool)
js_Invoke(JSContext *cx, uintN argc, uintN flags);
js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags);
/*
* Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that
@ -199,7 +200,6 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags);
*/
#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING
#define JSINVOKE_INTERNAL JSFRAME_INTERNAL
#define JSINVOKE_SKIP_CALLER JSFRAME_SKIP_CALLER
#define JSINVOKE_ITERATOR JSFRAME_ITERATOR
/*

View File

@ -802,7 +802,7 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp)
/* Copy remaining state (XXX sharp* and xml* should be local vars). */
gen->frame.sharpDepth = 0;
gen->frame.sharpArray = NULL;
gen->frame.flags = fp->flags | JSFRAME_GENERATOR;
gen->frame.flags = (fp->flags & ~JSFRAME_ROOTED_ARGV) | JSFRAME_GENERATOR;
gen->frame.dormantNext = NULL;
gen->frame.xmlNamespace = NULL;
gen->frame.blockChain = NULL;

View File

@ -1391,9 +1391,8 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
lambda = rdata->lambda;
if (lambda) {
uintN argc, i, j, m, n, p;
jsval *sp, *oldsp, rval;
jsval *invokevp, *sp;
void *mark;
JSStackFrame *fp;
JSBool ok;
/*
@ -1415,11 +1414,12 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
*/
p = rdata->base.regexp->parenCount;
argc = 1 + p + 2;
sp = js_AllocStack(cx, 2 + argc, &mark);
if (!sp)
invokevp = js_AllocStack(cx, 2 + argc, &mark);
if (!invokevp)
return JS_FALSE;
/* Push lambda and its 'this' parameter. */
sp = invokevp;
*sp++ = OBJECT_TO_JSVAL(lambda);
*sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));
@ -1463,21 +1463,14 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
*sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
*sp++ = STRING_TO_JSVAL(rdata->base.str);
/* Lift current frame to include the args and do the call. */
fp = cx->fp;
oldsp = fp->sp;
fp->sp = sp;
ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
rval = fp->sp[-1];
fp->sp = oldsp;
ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL);
if (ok) {
/*
* NB: we count on the newborn string root to hold any string
* created by this js_ValueToString that would otherwise be GC-
* able, until we use rdata->repstr in do_replace.
*/
repstr = js_ValueToString(cx, rval);
repstr = js_ValueToString(cx, *invokevp);
if (!repstr) {
ok = JS_FALSE;
} else {

View File

@ -1022,7 +1022,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
const XPTMethodDescriptor* info,
nsXPTCMiniVariant* nativeParams)
{
jsval* stackbase;
jsval* stackbase = nsnull;
jsval* sp = nsnull;
uint8 i;
uint8 argc=0;
@ -1440,26 +1440,8 @@ pre_call_clean_up:
{
if(!JSVAL_IS_PRIMITIVE(fval))
{
// Lift current frame (or make new one) to include the args
// and do the call.
JSStackFrame *fp, *oldfp, frame;
jsval *oldsp;
fp = oldfp = cx->fp;
if(!fp)
{
memset(&frame, 0, sizeof frame);
cx->fp = fp = &frame;
}
oldsp = fp->sp;
fp->sp = sp;
success = js_Invoke(cx, argc, JSINVOKE_INTERNAL);
result = fp->sp[-1];
fp->sp = oldsp;
if(oldfp != fp)
cx->fp = oldfp;
success = js_Invoke(cx, argc, stackbase, JSINVOKE_INTERNAL);
result = *stackbase;
}
else
{