зеркало из https://github.com/mozilla/gecko-dev.git
Bug 394551: no JS frames for fast native calls. r=brendan
This commit is contained in:
Родитель
5459e4edd3
Коммит
d304927431
|
@ -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;
|
||||
|
|
111
js/src/jsarray.c
111
js/src/jsarray.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче