From c419e325d6fe11c29e83d37969aaaf8d96927e53 Mon Sep 17 00:00:00 2001 From: "igor%mir2.org" Date: Mon, 17 Sep 2007 19:28:14 +0000 Subject: [PATCH] Bug 394551: taking out the last patch as broke Windows build. git-svn-id: svn://10.0.0.236/trunk@236126 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/src/jsapi.c | 11 + mozilla/js/src/jsarray.c | 111 +++--- mozilla/js/src/jsdbgapi.c | 87 ++--- mozilla/js/src/jsfun.c | 75 +++- mozilla/js/src/jsgc.c | 37 +- mozilla/js/src/jsinterp.c | 367 +++++++++--------- mozilla/js/src/jsinterp.h | 40 +- mozilla/js/src/jsiter.c | 2 +- mozilla/js/src/jsstr.c | 19 +- .../src/xpconnect/src/xpcwrappedjsclass.cpp | 24 +- 10 files changed, 442 insertions(+), 331 deletions(-) diff --git a/mozilla/js/src/jsapi.c b/mozilla/js/src/jsapi.c index d046a4868fe..c3748b3bb3a 100644 --- a/mozilla/js/src/jsapi.c +++ b/mozilla/js/src/jsapi.c @@ -4136,6 +4136,7 @@ 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; @@ -4170,8 +4171,13 @@ 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| @@ -4191,6 +4197,8 @@ 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); @@ -4953,6 +4961,7 @@ 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); } @@ -4962,6 +4971,7 @@ 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)) @@ -4987,6 +4997,7 @@ 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; diff --git a/mozilla/js/src/jsarray.c b/mozilla/js/src/jsarray.c index d1fb5dfbede..8d0feafe2ad 100644 --- a/mozilla/js/src/jsarray.c +++ b/mozilla/js/src/jsarray.c @@ -1762,23 +1762,29 @@ 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; - jsuint length, newlen; - jsval *argv, *elemroot, *invokevp, *sp; JSBool ok, cond, hole; + jsuint length, newlen; 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]); - if (!js_GetLengthProperty(cx, obj, &length)) + ok = js_GetLengthProperty(cx, obj, &length); + if (!ok) 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; @@ -1792,6 +1798,8 @@ 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: @@ -1801,21 +1809,24 @@ 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); - return JS_FALSE; + ok = JS_FALSE; + goto early_out; } if (argc >= 2) { - *vp = argv[1]; + roots[RVAL] = argv[1]; } else { do { - if (!GetArrayElement(cx, obj, start, &hole, vp)) - return JS_FALSE; + ok = GetArrayElement(cx, obj, start, &hole, &roots[RVAL]); + if (!ok) + goto early_out; start += step; } while (hole && start != end); if (hole && start == end) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE); - return JS_FALSE; + ok = JS_FALSE; + goto early_out; } } break; @@ -1823,80 +1834,87 @@ 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) - return JS_FALSE; - *vp = OBJECT_TO_JSVAL(newarr); + if (!newarr) { + ok = JS_FALSE; + goto early_out; + } + roots[RVAL] = OBJECT_TO_JSVAL(newarr); break; case SOME: - *vp = JSVAL_FALSE; + roots[RVAL] = JSVAL_FALSE; break; case EVERY: - *vp = JSVAL_TRUE; + roots[RVAL] = JSVAL_TRUE; break; case FOREACH: - *vp = JSVAL_VOID; break; } if (length == 0) - return JS_TRUE; + goto early_out; if (argc > 1 && !REDUCE_MODE(mode)) { - if (!js_ValueToObject(cx, argv[1], &thisp)) - return JS_FALSE; + ok = js_ValueToObject(cx, argv[1], &thisp); + if (!ok) + goto early_out; argv[1] = OBJECT_TO_JSVAL(thisp); } else { thisp = NULL; } /* - * For all but REDUCE, we call with 3 args (value, index, array). REDUCE - * requires 4 args (accum, value, index, array). + * For all but REDUCE, we call with 3 args (value, index, array), plus + * room for rval. REDUCE requires 4 args (accum, value, index, array). */ argc = 3 + REDUCE_MODE(mode); - elemroot = js_AllocStack(cx, 1 + 2 + argc, &mark); - if (!elemroot) - return JS_FALSE; + origsp = js_AllocStack(cx, 2 + argc + 1, &mark); + if (!origsp) { + ok = JS_FALSE; + goto early_out; + } - /* From this point the control must flow through out:. */ - ok = JS_TRUE; - invokevp = elemroot + 1; + /* Lift current frame to include our args. */ + fp = cx->fp; + oldsp = fp->sp; for (i = start; i != end; i += step) { - ok = JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && - GetArrayElement(cx, obj, i, &hole, elemroot); + ok = (JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && + GetArrayElement(cx, obj, i, &hole, &roots[ELEM])); if (!ok) - goto out; + break; if (hole) continue; /* * Push callable and 'this', then args. We must do this for every - * iteration around the loop since js_Invoke uses spbase[0] for return - * value storage, while some native functions use spbase[1] for local + * iteration around the loop since js_Invoke uses origsp[0] for return + * value storage, while some native functions use origsp[1] for local * rooting. */ - sp = invokevp; + sp = origsp; *sp++ = OBJECT_TO_JSVAL(callable); *sp++ = OBJECT_TO_JSVAL(thisp); if (REDUCE_MODE(mode)) - *sp++ = *vp; - *sp++ = *elemroot; + *sp++ = roots[RVAL]; + *sp++ = roots[ELEM]; *sp++ = INT_TO_JSVAL(i); *sp++ = OBJECT_TO_JSVAL(obj); /* Do the call. */ - ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL); + fp->sp = sp; + ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL); + roots[TEMP] = fp->sp[-1]; + fp->sp = oldsp; if (!ok) break; if (mode > MAP) { - if (*invokevp == JSVAL_NULL) { + if (roots[TEMP] == JSVAL_NULL) { cond = JS_FALSE; - } else if (JSVAL_IS_BOOLEAN(*invokevp)) { - cond = JSVAL_TO_BOOLEAN(*invokevp); + } else if (JSVAL_IS_BOOLEAN(roots[TEMP])) { + cond = JSVAL_TO_BOOLEAN(roots[TEMP]); } else { - ok = js_ValueToBoolean(cx, *invokevp, &cond); + ok = js_ValueToBoolean(cx, roots[TEMP], &cond); if (!ok) goto out; } @@ -1907,30 +1925,30 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) break; case REDUCE: case REDUCE_RIGHT: - *vp = *invokevp; + roots[RVAL] = roots[TEMP]; break; case MAP: - ok = SetArrayElement(cx, newarr, i, *invokevp); + ok = SetArrayElement(cx, newarr, i, roots[TEMP]); if (!ok) goto out; break; case FILTER: if (!cond) break; - /* The filter passed *elemroot, so push it onto our result. */ - ok = SetArrayElement(cx, newarr, newlen++, *elemroot); + /* The filter passed roots[ELEM], so push it onto our result. */ + ok = SetArrayElement(cx, newarr, newlen++, roots[ELEM]); if (!ok) goto out; break; case SOME: if (cond) { - *vp = JSVAL_TRUE; + roots[RVAL] = JSVAL_TRUE; goto out; } break; case EVERY: if (!cond) { - *vp = JSVAL_FALSE; + roots[RVAL] = JSVAL_FALSE; goto out; } break; @@ -1941,6 +1959,9 @@ 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; } diff --git a/mozilla/js/src/jsdbgapi.c b/mozilla/js/src/jsdbgapi.c index 6d2f5330c1f..8e6ef2271e0 100644 --- a/mozilla/js/src/jsdbgapi.c +++ b/mozilla/js/src/jsdbgapi.c @@ -545,16 +545,11 @@ 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; @@ -574,66 +569,56 @@ 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; - injectFrame = !(fun->flags & JSFUN_FAST_NATIVE); + } + + 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; } } - 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; - } - } + argv[0] = OBJECT_TO_JSVAL(closure); + argv[1] = JSVAL_NULL; + memset(argv + 2, 0, (nslots - 2) * sizeof(jsval)); - 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; + 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; } -#ifdef __GNUC__ - else - argv = NULL; /* suppress bogus gcc warnings */ -#endif + frame.callee = closure; + frame.fun = fun; + frame.argv = argv + 2; + frame.down = cx->fp; + frame.scopeChain = OBJ_GET_PARENT(cx, closure); + + cx->fp = &frame; 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); - cx->fp = frame.down; - if (argv != smallv) - JS_free(cx, argv); - } + /* 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); } DBG_LOCK(rt); return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok; diff --git a/mozilla/js/src/jsfun.c b/mozilla/js/src/jsfun.c index 64f7be14db8..9bcdc918d85 100644 --- a/mozilla/js/src/jsfun.c +++ b/mozilla/js/src/jsfun.c @@ -1059,6 +1059,8 @@ 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 @@ -1588,9 +1590,11 @@ static JSBool fun_call(JSContext *cx, uintN argc, jsval *vp) { JSObject *obj; - jsval fval, *argv, *invokevp; + jsval fval, *argv, *sp, *oldsp; JSString *str; void *mark; + uintN i; + JSStackFrame *fp; JSBool ok; obj = JSVAL_TO_OBJECT(vp[1]); @@ -1628,17 +1632,28 @@ fun_call(JSContext *cx, uintN argc, jsval *vp) } /* Allocate stack space for fval, obj, and the args. */ - invokevp = js_AllocStack(cx, 2 + argc, &mark); - if (!invokevp) + sp = js_AllocStack(cx, 2 + argc, &mark); + if (!sp) return JS_FALSE; /* Push fval, obj, and the args. */ - invokevp[0] = fval; - invokevp[1] = OBJECT_TO_JSVAL(obj); - memcpy(invokevp + 2, argv, argc * sizeof *argv); + *sp++ = fval; + *sp++ = OBJECT_TO_JSVAL(obj); + for (i = 0; i < argc; i++) + *sp++ = argv[i]; - ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL); - *vp = *invokevp; + /* 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; js_FreeStack(cx, mark); return ok; } @@ -1647,12 +1662,13 @@ static JSBool fun_apply(JSContext *cx, uintN argc, jsval *vp) { JSObject *obj, *aobj; - jsval fval, *invokevp, *sp; + jsval fval, *sp, *oldsp; 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. */ @@ -1711,12 +1727,11 @@ 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); - invokevp = js_AllocStack(cx, 2 + argc, &mark); - if (!invokevp) + sp = js_AllocStack(cx, 2 + argc, &mark); + if (!sp) 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++) { @@ -1726,8 +1741,18 @@ fun_apply(JSContext *cx, uintN argc, jsval *vp) sp++; } - ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL); - *vp = *invokevp; + /* 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; out: js_FreeStack(cx, mark); return ok; @@ -1740,7 +1765,8 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) JSObject *aobj; uintN length, i; void *mark; - jsval *invokevp, *sp; + jsval *sp, *newsp, *oldsp; + JSStackFrame *fp; JSBool ok; if (JSVAL_IS_PRIMITIVE(vp[2]) || @@ -1757,11 +1783,12 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) if (length >= ARRAY_INIT_LIMIT) length = ARRAY_INIT_LIMIT - 1; - invokevp = js_AllocStack(cx, 2 + length, &mark); - if (!invokevp) + newsp = sp = js_AllocStack(cx, 2 + length, &mark); + if (!sp) return JS_FALSE; - sp = invokevp; + fp = cx->fp; + oldsp = fp->sp; *sp++ = vp[1]; *sp++ = JSVAL_NULL; /* This is filled automagically. */ for (i = 0; i < length; i++) { @@ -1771,8 +1798,12 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) sp++; } - ok = js_InvokeConstructor(cx, invokevp, length); - *vp = *invokevp; + oldsp = fp->sp; + fp->sp = sp; + ok = js_InvokeConstructor(cx, newsp, length); + + *vp = fp->sp[-1]; + fp->sp = oldsp; out: js_FreeStack(cx, mark); return ok; @@ -2327,7 +2358,9 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) } js_ReportValueError3(cx, error, - (fp && fp->spbase <= vp && vp < fp->sp) + (fp && + !(fp->flags & JSFRAME_IN_FAST_CALL) && + fp->spbase <= vp && vp < fp->sp) ? vp - fp->sp : (flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK diff --git a/mozilla/js/src/jsgc.c b/mozilla/js/src/jsgc.c index b1ee60c4e46..56d47516a43 100644 --- a/mozilla/js/src/jsgc.c +++ b/mozilla/js/src/jsgc.c @@ -2205,7 +2205,8 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) { - uintN nslots, minargs, skip; + uintN depth, nslots, minargs; + jsval *vp; if (fp->callobj) JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call"); @@ -2220,9 +2221,11 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) * Don't mark what has not been pushed yet, or what has been * popped already. */ - JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= - fp->script->depth * sizeof(jsval)); - nslots = (uintN) (fp->sp - fp->spbase); + depth = fp->script->depth; + nslots = (JS_UPTRDIFF(fp->sp, fp->spbase) + < depth * sizeof(jsval)) + ? (uintN)(fp->sp - fp->spbase) + : depth; TRACE_JSVALS(trc, nslots, fp->spbase, "operand"); } } @@ -2236,20 +2239,32 @@ 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)) { - JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE)); + if (!FUN_INTERPRETED(fp->fun)) nslots += fp->fun->u.n.extra; - } - if (fp->fun->flags & JSFRAME_ROOTED_ARGV) - skip = 2 + fp->argc; } - TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); + 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; + } + } + TRACE_JSVALS(trc, nslots, vp, "arg"); } JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); if (fp->vars) diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index e9765a3dc37..cff9d4b670b 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -81,9 +81,13 @@ */ #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) /* @@ -261,35 +265,6 @@ 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) { @@ -316,9 +291,10 @@ js_FreeRawStack(JSContext *cx, void *mark) JS_FRIEND_API(jsval *) js_AllocStack(JSContext *cx, uintN nslots, void **markp) { - jsval *sp; + jsval *sp, *vp, *end; JSArena *a; JSStackHeader *sh; + JSStackFrame *fp; /* Callers don't check for zero nslots: we do to avoid empty segments. */ if (nslots == 0) { @@ -340,9 +316,24 @@ js_AllocStack(JSContext *cx, uintN nslots, void **markp) a->avail -= 2 * sizeof(jsval); } else { /* - * Need a new stack segment, so allocate and push a stack segment - * header from the 2 extra slots. + * 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). */ + 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; @@ -613,9 +604,9 @@ js_ComputeThis(JSContext *cx, jsval *argv) #if JS_HAS_NO_SUCH_METHOD static JSBool -NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags) +NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags, + uintN argc) { - JSStackFrame *fp; JSObject *thisp, *argsobj; JSAtom *atom; jsval *sp, roots[3]; @@ -627,7 +618,6 @@ NoSuchMethod(JSContext *cx, uintN argc, 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. */ @@ -1039,6 +1029,11 @@ 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. @@ -1070,12 +1065,12 @@ static const uint16 PrimitiveTestFlags[] = { * when done. Then push the return value. */ JS_FRIEND_API(JSBool) -js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags) +js_Invoke(JSContext *cx, uintN argc, uintN flags) { void *mark; - JSStackFrame frame; - jsval *sp, *argv, *newvp; - jsval v; + JSStackFrame *fp, frame; + jsval *sp, *newsp, *limit; + jsval *vp, v; JSObject *funobj, *parent; JSBool ok; JSClass *clasp; @@ -1083,21 +1078,24 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags) JSNative native; JSFunction *fun; JSScript *script; - uintN nslots, nvars, i; - uint32 rootedArgsFlag; + uintN nslots, nvars, nalloc, surplus; JSInterpreterHook hook; void *hookData; - /* [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); + /* Mark the top of stack and load frequently-used registers. */ + mark = JS_ARENA_MARK(&cx->stackPool); + fp = cx->fp; + sp = fp->sp; /* - * Mark the top of stack and load frequently-used registers. After this - * point the control should flow through label out2: to return. + * 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 = JS_ARENA_MARK(&cx->stackPool); + vp = sp - (2 + argc); v = *vp; + frame.rval = JSVAL_VOID; /* * A callee must be an object reference, unless its 'this' parameter @@ -1112,8 +1110,10 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags) */ if (JSVAL_IS_PRIMITIVE(v)) { #if JS_HAS_NO_SUCH_METHOD - if (cx->fp && cx->fp->script && !(flags & JSINVOKE_INTERNAL)) { - ok = NoSuchMethod(cx, argc, vp, flags); + if (fp->script && !(flags & JSINVOKE_INTERNAL)) { + ok = NoSuchMethod(cx, fp, vp, flags, argc); + if (ok) + frame.rval = *vp; goto out2; } #endif @@ -1170,8 +1170,8 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags) have_fun: /* Get private data and set derived locals from it. */ fun = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj); - nslots = FUN_MINARGS(fun); - nslots = (nslots > argc) ? nslots - argc : 0; + nalloc = FUN_MINARGS(fun); + nslots = (nalloc > argc) ? nalloc - argc : 0; if (FUN_INTERPRETED(fun)) { native = NULL; script = fun->u.i.script; @@ -1189,12 +1189,14 @@ have_fun: } else if (!JSVAL_IS_OBJECT(vp[1])) { JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT)); if (PRIMITIVE_THIS_TEST(fun, vp[1])) - goto init_slots; + goto init_frame; } } 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 @@ -1206,80 +1208,9 @@ have_fun: goto out2; } - 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); - } - + init_frame: /* - * Initialize the frame, except for sp (set by SAVE_SP later). + * Initialize the rest of 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 @@ -1292,20 +1223,17 @@ have_fun: frame.callee = funobj; frame.fun = fun; frame.argc = argc; - frame.argv = argv; - - /* Default return value for a constructor is the new object. */ - frame.rval = (flags & JSINVOKE_CONSTRUCT) ? vp[1] : JSVAL_VOID; + frame.argv = sp - argc; frame.nvars = nvars; - frame.vars = sp - nvars; - frame.down = cx->fp; + frame.vars = sp; + frame.down = 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 | rootedArgsFlag; + frame.flags = flags; frame.dormantNext = NULL; frame.xmlNamespace = NULL; frame.blockChain = NULL; @@ -1317,6 +1245,77 @@ 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); @@ -1336,20 +1335,23 @@ have_fun: #endif /* If native, use caller varobj and scopeChain for eval. */ - if (cx->fp) { - frame.varobj = cx->fp->varobj; - frame.scopeChain = cx->fp->scopeChain; - } else { - frame.varobj = NULL; - frame.scopeChain = NULL; - } + frame.varobj = fp->varobj; + frame.scopeChain = fp->scopeChain; /* 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"); @@ -1372,9 +1374,9 @@ have_fun: ? JS_GetFunctionName(fun) : "???"); } - } #endif - ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval); + ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval); + } JS_RUNTIME_METER(cx->runtime, nativeCalls); #ifdef DEBUG_NOT_THROWING @@ -1416,16 +1418,24 @@ 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 = frame.down; + cx->fp = fp; out2: /* Pop everything we may have allocated off the stack. */ JS_ARENA_RELEASE(&cx->stackPool, mark); - if (!ok) - *vp = JSVAL_NULL; + + /* 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; return ok; bad: @@ -1438,20 +1448,33 @@ JSBool js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags, uintN argc, jsval *argv, jsval *rval) { - jsval *invokevp; + JSStackFrame *fp, *oldfp, frame; + jsval *oldsp, *sp; void *mark; + uintN i; JSBool ok; - invokevp = js_AllocStack(cx, 2 + argc, &mark); - if (!invokevp) - return JS_FALSE; + 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[0] = fval; - invokevp[1] = OBJECT_TO_JSVAL(obj); - memcpy(invokevp + 2, argv, argc * sizeof *argv); - - ok = js_Invoke(cx, argc, invokevp, flags | JSINVOKE_INTERNAL); + 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); 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 @@ -1459,7 +1482,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 = *invokevp; + *rval = POP_OPND(); if (JSVAL_IS_GCTHING(*rval) && *rval != JSVAL_NULL) { if (cx->localRootStack) { if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0) @@ -1471,6 +1494,11 @@ 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; } @@ -1928,7 +1956,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, vp, JSINVOKE_CONSTRUCT)) { + if (!js_Invoke(cx, argc, JSINVOKE_CONSTRUCT)) { cx->weakRoots.newborn[GCX_OBJECT] = NULL; return JS_FALSE; } @@ -3488,8 +3516,7 @@ interrupt: ok = js_InvokeConstructor(cx, vp, argc); if (!ok) goto out; - sp = vp + 1; - vp[-depth] = (jsval)pc; + RESTORE_SP(fp); LOAD_INTERRUPT_HANDLER(cx); obj = JSVAL_TO_OBJECT(*vp); len = js_CodeSpec[op].length; @@ -4061,12 +4088,7 @@ interrupt: if (sp + nargs > fp->spbase + depth) goto do_invoke; do { - /* - * Use PUSH_OPND to set the proper pc values for - * the extra arguments. The decompiler relies on - * this. - */ - PUSH_OPND(JSVAL_VOID); + PUSH(JSVAL_VOID); } while (--nargs != 0); SAVE_SP(fp); } @@ -4074,7 +4096,9 @@ 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; @@ -4084,9 +4108,8 @@ interrupt: } do_invoke: - ok = js_Invoke(cx, argc, vp, 0); - sp = vp + 1; - vp[-depth] = (jsval)pc; + ok = js_Invoke(cx, argc, 0); + RESTORE_SP(fp); LOAD_INTERRUPT_HANDLER(cx); if (!ok) goto out; @@ -4123,10 +4146,8 @@ interrupt: BEGIN_CASE(JSOP_SETCALL) argc = GET_ARGC(pc); SAVE_SP_AND_PC(fp); - vp = sp - argc - 2; - ok = js_Invoke(cx, argc, vp, 0); - sp = vp + 1; - vp[-depth] = (jsval)pc; + ok = js_Invoke(cx, argc, 0); + RESTORE_SP(fp); LOAD_INTERRUPT_HANDLER(cx); if (!ok) goto out; diff --git a/mozilla/js/src/jsinterp.h b/mozilla/js/src/jsinterp.h index 073d6da673b..65dd9983062 100644 --- a/mozilla/js/src/jsinterp.h +++ b/mozilla/js/src/jsinterp.h @@ -95,21 +95,24 @@ 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_ASSIGNING 0x04 /* a complex (not simplex JOF_ASSIGNING) op +#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 is currently assigning to a property */ -#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 +#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 references based on scope chain */ -#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_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_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */ #define JSFRAME_OVERRIDE_BITS 8 @@ -175,15 +178,11 @@ 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 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. + * is non-null), and that the callee, |this| parameter, and actual arguments + * are already pushed on the stack under cx->fp->sp. */ extern JS_FRIEND_API(JSBool) -js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags); +js_Invoke(JSContext *cx, uintN argc, uintN flags); /* * Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that @@ -200,6 +199,7 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags); */ #define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING #define JSINVOKE_INTERNAL JSFRAME_INTERNAL +#define JSINVOKE_SKIP_CALLER JSFRAME_SKIP_CALLER #define JSINVOKE_ITERATOR JSFRAME_ITERATOR /* diff --git a/mozilla/js/src/jsiter.c b/mozilla/js/src/jsiter.c index 54dcfa9d5a1..8fe22eddb84 100644 --- a/mozilla/js/src/jsiter.c +++ b/mozilla/js/src/jsiter.c @@ -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_ROOTED_ARGV) | JSFRAME_GENERATOR; + gen->frame.flags = fp->flags | JSFRAME_GENERATOR; gen->frame.dormantNext = NULL; gen->frame.xmlNamespace = NULL; gen->frame.blockChain = NULL; diff --git a/mozilla/js/src/jsstr.c b/mozilla/js/src/jsstr.c index b29ef44a301..9340390509d 100644 --- a/mozilla/js/src/jsstr.c +++ b/mozilla/js/src/jsstr.c @@ -1391,8 +1391,9 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep) lambda = rdata->lambda; if (lambda) { uintN argc, i, j, m, n, p; - jsval *invokevp, *sp; + jsval *sp, *oldsp, rval; void *mark; + JSStackFrame *fp; JSBool ok; /* @@ -1414,12 +1415,11 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep) */ p = rdata->base.regexp->parenCount; argc = 1 + p + 2; - invokevp = js_AllocStack(cx, 2 + argc, &mark); - if (!invokevp) + sp = js_AllocStack(cx, 2 + argc, &mark); + if (!sp) 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,14 +1463,21 @@ 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); - ok = js_Invoke(cx, argc, invokevp, JSINVOKE_INTERNAL); + /* 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; + 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, *invokevp); + repstr = js_ValueToString(cx, rval); if (!repstr) { ok = JS_FALSE; } else { diff --git a/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp index faacc2ba729..2bc60804485 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -1022,7 +1022,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, const XPTMethodDescriptor* info, nsXPTCMiniVariant* nativeParams) { - jsval* stackbase = nsnull; + jsval* stackbase; jsval* sp = nsnull; uint8 i; uint8 argc=0; @@ -1440,8 +1440,26 @@ pre_call_clean_up: { if(!JSVAL_IS_PRIMITIVE(fval)) { - success = js_Invoke(cx, argc, stackbase, JSINVOKE_INTERNAL); - result = *stackbase; + // 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; } else {