diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index e5577217580b..65bae0710eac 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -376,7 +376,7 @@ class AutoFreeJSStack { public: AutoFreeJSStack(JSContext *ctx, void *aPtr) : mContext(ctx), mStack(aPtr) { } - ~AutoFreeJSStack() { + JS_REQUIRES_STACK ~AutoFreeJSStack() { if (mContext && mStack) js_FreeStack(mContext, mStack); } @@ -2523,6 +2523,8 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, { nsresult rv = NS_OK; + js_LeaveTrace(mContext); + // If the array implements nsIJSArgArray, just grab the values directly. nsCOMPtr fastArray = do_QueryInterface(aArgs); if (fastArray != nsnull) { diff --git a/dom/src/base/nsJSEnvironment.h b/dom/src/base/nsJSEnvironment.h index 4a3b7badb2d8..45d255bc3327 100644 --- a/dom/src/base/nsJSEnvironment.h +++ b/dom/src/base/nsJSEnvironment.h @@ -199,10 +199,11 @@ protected: nsresult FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder); // Helper to convert xpcom datatypes to jsvals. - nsresult ConvertSupportsTojsvals(nsISupports *aArgs, - void *aScope, - PRUint32 *aArgc, void **aArgv, - void **aMarkp); + JS_FORCES_STACK nsresult ConvertSupportsTojsvals(nsISupports *aArgs, + void *aScope, + PRUint32 *aArgc, + void **aArgv, + void **aMarkp); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/src/js-config.h.in b/js/src/js-config.h.in index c6954bb07a47..e0eb95a27a2c 100644 --- a/js/src/js-config.h.in +++ b/js/src/js-config.h.in @@ -79,4 +79,8 @@ #undef JS_INTPTR_TYPE #undef JS_BYTES_PER_WORD +/* Some mozilla code uses JS-friend APIs that depend on JS_TRACER being + correct. */ +#undef JS_TRACER + #endif /* js_config_h___ */ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index fce698e6582b..781c369d5755 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4587,7 +4587,7 @@ js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp) native = #ifdef JS_TRACER (fs->flags & JSFUN_TRACEABLE) - ? ((JSTraceableNative *) fs->call)->native + ? JS_FUNC_TO_DATA_PTR(JSTraceableNative *, fs->call)->native : #endif (JSFastNative) fs->call; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 960bc3489a8c..b52db8514f17 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1489,15 +1489,6 @@ js_InvokeOperationCallback(JSContext *cx) return !cb || cb(cx); } -#ifndef JS_TRACER -/* This is defined in jstracer.cpp in JS_TRACER builds. */ -extern JS_FORCES_STACK JSStackFrame * -js_GetTopStackFrame(JSContext *cx) -{ - return cx->fp; -} -#endif - JSStackFrame * js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 35164623291a..63afc64fe299 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1401,17 +1401,53 @@ extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; extern JSBool js_InvokeOperationCallback(JSContext *cx); +extern JSStackFrame * +js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp); + +#ifdef JS_TRACER +/* + * Reconstruct the JS stack and clear cx->onTrace. We must be currently + * executing a _FAIL builtin from trace on cx. The machine code for the trace + * remains on the C stack when js_DeepBail returns. + * + * Implemented in jstracer.cpp. + */ +JS_FORCES_STACK JS_FRIEND_API(void) +js_DeepBail(JSContext *cx); +#endif + +static JS_FORCES_STACK JS_INLINE void +js_LeaveTrace(JSContext *cx) +{ +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) + js_DeepBail(cx); +#endif +} + +static JS_INLINE JSBool +js_CanLeaveTrace(JSContext *cx) +{ + JS_ASSERT(JS_ON_TRACE(cx)); +#ifdef JS_TRACER + return cx->bailExit != NULL; +#else + return JS_FALSE; +#endif +} + /* * Get the current cx->fp, first lazily instantiating stack frames if needed. * (Do not access cx->fp directly except in JS_REQUIRES_STACK code.) * * Defined in jstracer.cpp if JS_TRACER is defined. */ -extern JS_FORCES_STACK JSStackFrame * -js_GetTopStackFrame(JSContext *cx); - -extern JSStackFrame * -js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp); +static JS_FORCES_STACK JS_INLINE JSStackFrame * +js_GetTopStackFrame(JSContext *cx) +{ + js_LeaveTrace(cx); + return cx->fp; +} JS_END_EXTERN_C diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index ecb1a7b1b75c..49add1c74e8b 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -435,7 +435,7 @@ js_TraceWatchPoints(JSTracer *trc, JSObject *obj) if (wp->object == obj) { TRACE_SCOPE_PROPERTY(trc, wp->sprop); if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) { - JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter, + JS_CALL_OBJECT_TRACER(trc, js_CastAsObject(wp->setter), "wp->setter"); } JS_SET_TRACING_NAME(trc, "wp->closure"); @@ -651,7 +651,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ok = !wp->setter || ((sprop->attrs & JSPROP_SETTER) ? js_InternalCall(cx, obj, - OBJECT_TO_JSVAL((JSObject *)wp->setter), + js_CastAsObjectJSVal(wp->setter), 1, vp, vp) : wp->setter(cx, obj, userid, vp)); if (injectFrame) { @@ -709,11 +709,11 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter) atom = NULL; } wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0, - OBJ_GET_PARENT(cx, (JSObject *)setter), + OBJ_GET_PARENT(cx, js_CastAsObject(setter)), atom); if (!wrapper) return NULL; - return (JSPropertyOp) FUN_OBJECT(wrapper); + return js_CastAsPropertyOp(FUN_OBJECT(wrapper)); } JS_PUBLIC_API(JSBool) @@ -1108,7 +1108,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp) * XXX ill-defined: null return here means error was reported, unlike a * null returned above or in the #else */ - return js_GetCallObject(cx, fp, NULL); + return js_GetCallObject(cx, fp); } JS_PUBLIC_API(JSObject *) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 660fc04f6649..04789ac2d107 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -590,9 +590,9 @@ JSClass js_ArgumentsClass = { #define CALL_CLASS_FIXED_RESERVED_SLOTS 2 JSObject * -js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent) +js_GetCallObject(JSContext *cx, JSStackFrame *fp) { - JSObject *callobj, *funobj; + JSObject *callobj; /* Create a call object for fp only if it lacks one. */ JS_ASSERT(fp->fun); @@ -600,15 +600,18 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent) if (callobj) return callobj; - /* The default call parent is its function's parent (static link). */ - if (!parent) { - funobj = fp->callee; - if (funobj) - parent = OBJ_GET_PARENT(cx, funobj); - } +#ifdef DEBUG + /* A call object should be a frame's outermost scope chain element. */ + JSClass *classp = OBJ_GET_CLASS(cx, fp->scopeChain); + if (classp == &js_WithClass || classp == &js_BlockClass || classp == &js_CallClass) + JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->scopeChain) != fp); +#endif - /* Create the call object and link it to its stack frame. */ - callobj = js_NewObject(cx, &js_CallClass, NULL, parent, 0); + /* + * Create the call object, using the frame's enclosing scope as + * its parent, and link the call to its stack frame. + */ + callobj = js_NewObject(cx, &js_CallClass, NULL, fp->scopeChain, 0); if (!callobj) return NULL; @@ -617,8 +620,10 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent) OBJECT_TO_JSVAL(FUN_OBJECT(fp->fun))); fp->callobj = callobj; - /* Make callobj be the scope chain and the variables object. */ - JS_ASSERT(fp->scopeChain == parent); + /* + * Push callobj on the top of the scope chain, and make it the + * variables object. + */ fp->scopeChain = callobj; fp->varobj = callobj; return callobj; @@ -2110,7 +2115,8 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, fun->u.n.spare = 0; if (flags & JSFUN_TRACEABLE) { #ifdef JS_TRACER - JSTraceableNative *trcinfo = (JSTraceableNative *) native; + JSTraceableNative *trcinfo = + JS_FUNC_TO_DATA_PTR(JSTraceableNative *, native); fun->u.n.native = (JSNative) trcinfo->native; FUN_TRCINFO(fun) = trcinfo; #else diff --git a/js/src/jsfun.h b/js/src/jsfun.h index e51e5c4b3f7d..b5b9c5c4f3b1 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -124,7 +124,7 @@ struct JSFunction { #ifdef JS_TRACER /* MSVC demands the intermediate (void *) cast here. */ # define JS_TN(name,fastcall,nargs,flags,trcinfo) \ - {name, (JSNative)(void *)(trcinfo), nargs, \ + {name, JS_DATA_TO_FUNC_PTR(JSNative, trcinfo), nargs, \ (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRACEABLE, 0} #else # define JS_TN(name,fastcall,nargs,flags,trcinfo) \ @@ -204,7 +204,7 @@ extern void js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags); extern JSObject * -js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent); +js_GetCallObject(JSContext *cx, JSStackFrame *fp); extern JS_FRIEND_API(JSBool) js_PutCallObject(JSContext *cx, JSStackFrame *fp); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 7abc53aaa07c..348529cb439b 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -189,7 +189,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, * Optimize the cached vword based on our parameters and the current pc's * opcode format flags. */ - op = (JSOp) *pc; + op = js_GetOpcode(cx, cx->fp->script, pc); cs = &js_CodeSpec[op]; do { @@ -318,7 +318,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code) < cx->fp->script->length); - op = (JSOp) *pc; + op = js_GetOpcode(cx, cx->fp->script, pc); cs = &js_CodeSpec[op]; if (op == JSOP_LENGTH) { atom = cx->runtime->atomState.lengthAtom; @@ -687,7 +687,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) if (fp->fun && !fp->callobj) { JS_ASSERT(OBJ_GET_CLASS(cx, fp->scopeChain) != &js_BlockClass || OBJ_GET_PRIVATE(cx, fp->scopeChain) != fp); - if (!js_GetCallObject(cx, fp, fp->scopeChain)) + if (!js_GetCallObject(cx, fp)) return NULL; } @@ -1326,7 +1326,7 @@ have_fun: frame.scopeChain = parent; if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) { /* Scope with a call object parented by the callee's parent. */ - if (!js_GetCallObject(cx, &frame, parent)) { + if (!js_GetCallObject(cx, &frame)) { ok = JS_FALSE; goto out; } @@ -3079,7 +3079,8 @@ js_Interpret(JSContext *cx) inlineCallCount--; if (JS_LIKELY(ok)) { TRACE_0(LeaveFrame); - JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH); + JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length + == JSOP_CALL_LENGTH); len = JSOP_CALL_LENGTH; DO_NEXT_OP(len); } @@ -3404,7 +3405,7 @@ js_Interpret(JSContext *cx) GET_ATOM_FROM_BYTECODE(script, regs.pc, pcoff, atom_); \ else \ atom_ = rt->atomState.lengthAtom; \ - if (JOF_OPMODE(*regs.pc) == JOF_NAME) { \ + if (JOF_OPMODE(op) == JOF_NAME) { \ ok = js_FindProperty(cx, ATOM_TO_JSID(atom_), &obj_, &pobj_, \ &prop_); \ } else { \ @@ -4932,7 +4933,7 @@ js_Interpret(JSContext *cx) /* Scope with a call object parented by callee's parent. */ if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) && - !js_GetCallObject(cx, &newifp->frame, parent)) { + !js_GetCallObject(cx, &newifp->frame)) { goto bad_inline_call; } @@ -5075,7 +5076,7 @@ js_Interpret(JSContext *cx) if (!ok) goto error; if (!cx->rval2set) { - op2 = (JSOp) regs.pc[JSOP_SETCALL_LENGTH]; + op2 = js_GetOpcode(cx, script, regs.pc + JSOP_SETCALL_LENGTH); if (op2 != JSOP_DELELEM) { JS_ASSERT(!(js_CodeSpec[op2].format & JOF_DEL)); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -5137,7 +5138,7 @@ js_Interpret(JSContext *cx) if (!prop) { /* Kludge to allow (typeof foo == "undefined") tests. */ endpc = script->code + script->length; - op2 = (JSOp) regs.pc[JSOP_NAME_LENGTH]; + op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH); if (op2 == JSOP_TYPEOF) { PUSH_OPND(JSVAL_VOID); len = JSOP_NAME_LENGTH; @@ -5786,9 +5787,9 @@ js_Interpret(JSContext *cx) attrs |= flags | JSPROP_SHARED; rval = JSVAL_VOID; if (flags == JSPROP_GETTER) - getter = JS_EXTENSION (JSPropertyOp) obj; + getter = js_CastAsPropertyOp(obj); else - setter = JS_EXTENSION (JSPropertyOp) obj; + setter = js_CastAsPropertyOp(obj); } /* @@ -6292,7 +6293,7 @@ js_Interpret(JSContext *cx) JS_ASSERT(OBJ_IS_ARRAY(cx, obj)); JS_ASSERT(JSID_IS_INT(id)); JS_ASSERT((jsuint) JSID_TO_INT(id) < ARRAY_INIT_LIMIT); - if ((JSOp) regs.pc[JSOP_INITELEM_LENGTH] == JSOP_ENDINIT && + if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT && !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) { goto error; } @@ -7041,7 +7042,7 @@ js_Interpret(JSContext *cx) switch (tn->kind) { case JSTRY_CATCH: - JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK); + JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENTERBLOCK); #if JS_HAS_GENERATORS /* Catch cannot intercept the closing of a generator. */ @@ -7076,7 +7077,7 @@ js_Interpret(JSContext *cx) * adjustment and regs.sp[1] after, to save and restore the * pending exception. */ - JS_ASSERT(*regs.pc == JSOP_ENDITER); + JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENDITER); regs.sp[-1] = cx->exception; cx->throwing = JS_FALSE; ok = js_CloseIterator(cx, regs.sp[-2]); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 59bc6423d14c..7509c339481d 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -71,7 +71,7 @@ #include "jsstaticcheck.h" #include "jsstr.h" #include "jstracer.h" -#include "jsdbgapi.h" /* whether or not JS_HAS_OBJ_WATCHPOINT */ +#include "jsdbgapi.h" #if JS_HAS_GENERATORS #include "jsiter.h" @@ -404,9 +404,10 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) if (ok) { if (OBJ_IS_NATIVE(obj2) && (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + JSScopeProperty *sprop = (JSScopeProperty *) prop; val = JSVAL_NULL; if (attrs & JSPROP_GETTER) - val = (jsval) ((JSScopeProperty*)prop)->getter; + val = js_CastAsObjectJSVal(sprop->getter); if (attrs & JSPROP_SETTER) { if (val != JSVAL_NULL) { /* Mark the getter, then set val to setter. */ @@ -414,7 +415,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) NULL) != NULL); } - val = (jsval) ((JSScopeProperty*)prop)->setter; + val = js_CastAsObjectJSVal(sprop->setter); } } else { ok = OBJ_GET_PROPERTY(cx, obj, id, &val); @@ -769,8 +770,9 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) } if (OBJ_IS_NATIVE(obj2) && (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { + JSScopeProperty *sprop = (JSScopeProperty *) prop; if (attrs & JSPROP_GETTER) { - val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter; + val[valcnt] = js_CastAsObjectJSVal(sprop->getter); gsopold[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.getterAtom); gsop[valcnt] = @@ -779,7 +781,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) valcnt++; } if (attrs & JSPROP_SETTER) { - val[valcnt] = (jsval) ((JSScopeProperty *)prop)->setter; + val[valcnt] = js_CastAsObjectJSVal(sprop->setter); gsopold[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.setterAtom); gsop[valcnt] = @@ -1192,9 +1194,10 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller, return principals->codebase; } - if (caller->regs && *caller->regs->pc == JSOP_EVAL) { - JS_ASSERT(caller->regs->pc[JSOP_EVAL_LENGTH] == JSOP_LINENO); - *linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH); + jsbytecode *pc = caller->regs->pc; + if (caller->regs && js_GetOpcode(cx, caller->script, pc) == JSOP_EVAL) { + JS_ASSERT(js_GetOpcode(cx, caller->script, pc + JSOP_EVAL_LENGTH) == JSOP_LINENO); + *linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH); } else { *linenop = js_FramePCToLineNumber(cx, caller); } @@ -1278,7 +1281,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * object, then we need to provide one for the compiler to stick any * declared (var) variables into. */ - if (caller && !caller->varobj && !js_GetCallObject(cx, caller, NULL)) + if (caller && !caller->varobj && !js_GetCallObject(cx, caller)) return JS_FALSE; /* Accept an optional trailing argument that overrides the scope object. */ @@ -1819,7 +1822,7 @@ js_obj_defineGetter(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = JSVAL_VOID; return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, - (JSPropertyOp) JSVAL_TO_OBJECT(fval), + js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)), JS_PropertyStub, JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED, NULL); @@ -1855,7 +1858,7 @@ js_obj_defineSetter(JSContext *cx, uintN argc, jsval *vp) *vp = JSVAL_VOID; return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, JS_PropertyStub, - (JSPropertyOp) JSVAL_TO_OBJECT(fval), + js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)), JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED, NULL); } @@ -1878,7 +1881,7 @@ obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp) if (OBJ_IS_NATIVE(pobj)) { sprop = (JSScopeProperty *) prop; if (sprop->attrs & JSPROP_GETTER) - *vp = OBJECT_TO_JSVAL((JSObject *) sprop->getter); + *vp = js_CastAsObjectJSVal(sprop->getter); } OBJ_DROP_PROPERTY(cx, pobj, prop); } @@ -1903,7 +1906,7 @@ obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp) if (OBJ_IS_NATIVE(pobj)) { sprop = (JSScopeProperty *) prop; if (sprop->attrs & JSPROP_SETTER) - *vp = OBJECT_TO_JSVAL((JSObject *) sprop->setter); + *vp = js_CastAsObjectJSVal(sprop->setter); } OBJ_DROP_PROPERTY(cx, pobj, prop); } @@ -2016,18 +2019,15 @@ static JS_REQUIRES_STACK JSBool Detecting(JSContext *cx, jsbytecode *pc) { JSScript *script; - jsbytecode *endpc; JSOp op; JSAtom *atom; if (!cx->fp) return JS_FALSE; script = cx->fp->script; - for (endpc = script->code + script->length; - pc < endpc; - pc += js_CodeSpec[op].length) { + for (;; pc += js_CodeSpec[op].length) { /* General case: a branch or equality op follows the access. */ - op = (JSOp) *pc; + op = js_GetOpcode(cx, script, pc); if (js_CodeSpec[op].format & JOF_DETECTING) return JS_TRUE; @@ -2037,9 +2037,9 @@ Detecting(JSContext *cx, jsbytecode *pc) * Special case #1: handle (document.all == null). Don't sweat * about JS1.2's revision of the equality operators here. */ - if (++pc < endpc) - return *pc == JSOP_EQ || *pc == JSOP_NE; - return JS_FALSE; + pc++; + op = js_GetOpcode(cx, script, pc); + return op == JSOP_EQ || op == JSOP_NE; case JSOP_NAME: /* @@ -2048,9 +2048,9 @@ Detecting(JSContext *cx, jsbytecode *pc) * Edition 3, so is read/write for backward compatibility. */ GET_ATOM_FROM_BYTECODE(script, pc, 0, atom); - if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] && - (pc += js_CodeSpec[op].length) < endpc) { - op = (JSOp) *pc; + if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID]) { + pc += js_CodeSpec[op].length; + op = js_GetOpcode(cx, script, pc); return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE; } @@ -2066,7 +2066,6 @@ Detecting(JSContext *cx, jsbytecode *pc) break; } } - return JS_FALSE; } /* @@ -2088,7 +2087,7 @@ InferFlags(JSContext *cx, uintN defaultFlags) if (!fp || !fp->regs) return defaultFlags; pc = fp->regs->pc; - cs = &js_CodeSpec[*pc]; + cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)]; format = cs->format; if (JOF_MODE(format) != JOF_NAME) flags |= JSRESOLVE_QUALIFIED; @@ -3945,8 +3944,11 @@ js_GetCurrentBytecodePC(JSContext* cx) pc = fp->regs->pc; // FIXME: Set pc to imacpc when recording JSOP_CALL inside the // JSOP_GETELEM imacro (bug 476559). - if (*pc == JSOP_CALL && fp->imacpc && *fp->imacpc == JSOP_GETELEM) + if (*pc == JSOP_CALL && + fp->imacpc && + js_GetOpcode(cx, fp->script, fp->imacpc) == JSOP_GETELEM) { pc = fp->imacpc; + } } else { pc = NULL; } @@ -3994,6 +3996,10 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, uintN flags; op = (JSOp) *pc; + if (op == JSOP_TRAP) { + JS_ASSERT_NOT_ON_TRACE(cx); + op = JS_GetTrapOpcode(cx, cx->fp->script, pc); + } if (op == JSOP_GETXPROP) { flags = JSREPORT_ERROR; } else { @@ -4009,10 +4015,15 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, if (id == ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom)) return JS_TRUE; - /* Kludge to allow (typeof foo == "undefined") tests. */ - pc += js_CodeSpec[op].length; - if (Detecting(cx, pc)) + /* Do not warn about tests like (obj[prop] == undefined). */ + if (cx->resolveFlags == JSRESOLVE_INFER) { + js_LeaveTrace(cx); + pc += js_CodeSpec[op].length; + if (Detecting(cx, pc)) + return JS_TRUE; + } else if (cx->resolveFlags & JSRESOLVE_DETECTING) { return JS_TRUE; + } flags = JSREPORT_WARNING | JSREPORT_STRICT; } @@ -5653,7 +5664,7 @@ dumpValue(jsval val) fprintf(stderr, "<%s%s at %p>", cls->name, cls == &js_ObjectClass ? "" : " object", - obj); + (void *) obj); } else if (JSVAL_IS_INT(val)) { fprintf(stderr, "%d", JSVAL_TO_INT(val)); } else if (JSVAL_IS_STRING(val)) { @@ -5749,7 +5760,7 @@ js_DumpObject(JSObject *obj) if (sharesScope) { if (proto) { fprintf(stderr, "no own properties - see proto (%s at %p)\n", - STOBJ_GET_CLASS(proto)->name, proto); + STOBJ_GET_CLASS(proto)->name, (void *) proto); } else { fprintf(stderr, "no own properties - null proto\n"); } diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 0e4b571121f0..468d49c80dc3 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -137,9 +137,7 @@ js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op; uintN span, base; - op = (JSOp)*pc; - if (op == JSOP_TRAP) - op = JS_GetTrapOpcode(cx, script, pc); + op = js_GetOpcode(cx, script, pc); JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN); /* @@ -5210,9 +5208,7 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target, LOCAL_ASSERT(script->main <= target && target < script->code + script->length); pcdepth = 0; for (pc = script->main; pc < target; pc += oplen) { - op = (JSOp) *pc; - if (op == JSOP_TRAP) - op = JS_GetTrapOpcode(cx, script, pc); + op = js_GetOpcode(cx, script, pc); cs = &js_CodeSpec[op]; oplen = cs->length; if (oplen < 0) @@ -5232,7 +5228,7 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target, jmpoff = js_GetSrcNoteOffset(sn, 0); if (pc + jmpoff < target) { pc += jmpoff; - op = (JSOp) *pc; + op = js_GetOpcode(cx, script, pc); JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX); cs = &js_CodeSpec[op]; oplen = cs->length; diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 710fa99a9877..a3ee7d2af456 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -55,6 +55,7 @@ */ #include "jspubtd.h" +#include "jsutil.h" /* Internal identifier (jsid) macros. */ @@ -260,4 +261,19 @@ struct JSTempValueRooter { extern JSBool js_CStringsAreUTF8; #endif +/* + * Helper macros to convert between function and data pointers assuming that + * they have the same size. + */ +JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)())); + +#ifdef __GNUC__ +# define JS_FUNC_TO_DATA_PTR(type, fun) (__extension__ (type) (fun)) +# define JS_DATA_TO_FUNC_PTR(type, ptr) (__extension__ (type) (ptr)) +#else +/* Use an extra (void *) cast for MSVC. */ +# define JS_FUNC_TO_DATA_PTR(type, fun) ((type) (void *) (fun)) +# define JS_DATA_TO_FUNC_PTR(type, ptr) ((type) (void *) (ptr)) +#endif + #endif /* jsprvtd_h___ */ diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 24f836ad7704..e5bc43253522 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -3903,7 +3903,7 @@ MatchRegExp(REGlobalData *gData, REMatchState *x) caller ? caller->script->filename : "", caller ? js_FramePCToLineNumber(gData->cx, caller) : 0, caller ? FramePCOffset(caller) : 0, - (void *) native); + JS_FUNC_TO_DATA_PTR(void *, native)); }) #endif diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index f00620d18a81..1ea766975f06 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -1559,16 +1559,12 @@ js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop) #if JS_HAS_GETTER_SETTER if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (sprop->attrs & JSPROP_GETTER) { - JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->getter)); JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 0); - JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->getter), - JSTRACE_OBJECT); + JS_CallTracer(trc, js_CastAsObject(sprop->getter), JSTRACE_OBJECT); } if (sprop->attrs & JSPROP_SETTER) { - JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->setter)); JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 1); - JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->setter), - JSTRACE_OBJECT); + JS_CallTracer(trc, js_CastAsObject(sprop->setter), JSTRACE_OBJECT); } } #endif /* JS_HAS_GETTER_SETTER */ diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 1935abebdd36..27b9295a43fa 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -271,6 +271,27 @@ JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap)); #define SCOPE_LAST_PROP(scope) ((scope)->lastProp) #define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \ (scope)->lastProp->parent) +/* + * Helpers for reinterpreting JSPropertyOp as JSObject* for scripted getters + * and setters. + */ +static inline JSObject * +js_CastAsObject(JSPropertyOp op) +{ + return JS_FUNC_TO_DATA_PTR(JSObject *, op); +} + +static inline jsval +js_CastAsObjectJSVal(JSPropertyOp op) +{ + return OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, op)); +} + +static inline JSPropertyOp +js_CastAsPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(JSPropertyOp, object); +} struct JSScopeProperty { jsid id; /* int-tagged jsval/untagged JSAtom* */ @@ -334,8 +355,8 @@ SPROP_GET(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, JSObject* obj2, JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop)); if (sprop->attrs & JSPROP_GETTER) { - return js_InternalGetOrSet(cx, obj, sprop->id, - OBJECT_TO_JSVAL((JSObject *) sprop->getter), JSACC_READ, + jsval fval = js_CastAsObjectJSVal(sprop->getter); + return js_InternalGetOrSet(cx, obj, sprop->id, fval, JSACC_READ, 0, 0, vp); } @@ -349,9 +370,9 @@ SPROP_SET(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, JSObject* obj2, !(sprop->attrs & JSPROP_GETTER))); if (sprop->attrs & JSPROP_SETTER) { - return js_InternalGetOrSet(cx, obj, (sprop)->id, - OBJECT_TO_JSVAL((JSObject *) sprop->setter), - JSACC_WRITE, 1, vp, vp); + jsval fval = js_CastAsObjectJSVal(sprop->setter); + return js_InternalGetOrSet(cx, obj, (sprop)->id, fval, JSACC_WRITE, + 1, vp, vp); } if (sprop->attrs & JSPROP_GETTER) { diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 06a361cea66f..a814fd692e32 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -310,7 +310,7 @@ static JSBool script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - JSObject *scopeobj, *parent; + JSObject *scopeobj; JSStackFrame *caller; JSPrincipals *principals; JSScript *script; @@ -343,9 +343,8 @@ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* Called from a lightweight function. */ JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags)); - /* Scope chain links from Call object to callee's parent. */ - parent = OBJ_GET_PARENT(cx, caller->callee); - if (!js_GetCallObject(cx, caller, parent)) + /* Scope chain links from Call object to caller's scope chain. */ + if (!js_GetCallObject(cx, caller)) return JS_FALSE; } @@ -362,7 +361,7 @@ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } else { /* * Called from native code, so we don't know what scope object to - * use. We could use parent (see above), but Script.prototype.exec + * use. We could use the caller's scope chain (see above), but Script.prototype.exec * might be a shared/sealed "superglobal" method. A more general * approach would use cx->globalObject, which will be the same as * exec.__parent__ in the non-superglobal case. In the superglobal @@ -1755,6 +1754,7 @@ js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp) uintN js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) { + JSOp op; JSFunction *fun; uintN lineno; ptrdiff_t offset, target; @@ -1769,8 +1769,9 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) * Special case: function definition needs no line number note because * the function's script contains its starting line number. */ - if (js_CodeSpec[*pc].format & JOF_INDEXBASE) - pc += js_CodeSpec[*pc].length; + op = js_GetOpcode(cx, script, pc); + if (js_CodeSpec[op].format & JOF_INDEXBASE) + pc += js_CodeSpec[op].length; if (*pc == JSOP_DEFFUN) { GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun); return fun->u.i.script->lineno; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 504570d1dffb..afd6f0222565 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -45,6 +45,7 @@ */ #include "jsatom.h" #include "jsprvtd.h" +#include "jsdbgapi.h" JS_BEGIN_EXTERN_C @@ -315,6 +316,15 @@ js_LineNumberToPC(JSScript *script, uintN lineno); extern JS_FRIEND_API(uintN) js_GetScriptLineExtent(JSScript *script); +static JS_INLINE JSOp +js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSOp op = (JSOp) *pc; + if (op == JSOP_TRAP) + op = JS_GetTrapOpcode(cx, script, pc); + return op; +} + /* * If magic is non-null, js_XDRScript succeeds on magic number mismatch but * returns false in *magic; it reflects a match via a true *magic out param. diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 9ed2166a0d4e..88086a6545b2 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -210,8 +210,9 @@ js_InitJITStatsClass(JSContext *cx, JSObject *glob) #define AUDIT(x) ((void)0) #endif /* JS_JIT_SPEW */ -#define INS_CONST(c) addName(lir->insImm(c), #c) -#define INS_CONSTPTR(p) addName(lir->insImmPtr((void*) (p)), #p) +#define INS_CONST(c) addName(lir->insImm(c), #c) +#define INS_CONSTPTR(p) addName(lir->insImmPtr((void*) (p)), #p) +#define INS_CONSTFUNPTR(p) addName(lir->insImmPtr(JS_FUNC_TO_DATA_PTR(void*, p)), #p) using namespace avmplus; using namespace nanojit; @@ -850,7 +851,7 @@ public: { } - JS_REQUIRES_STACK LInsp ins2(LOpcode v, LInsp s0, LInsp s1) + LInsp ins2(LOpcode v, LInsp s0, LInsp s1) { if (s0 == s1 && v == LIR_feq) { if (isPromote(s0)) { @@ -3204,7 +3205,7 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi) #ifdef DEBUG JSObject *obj = #endif - js_GetCallObject(cx, &newifp->frame, newifp->frame.scopeChain); + js_GetCallObject(cx, &newifp->frame); JS_ASSERT(obj); JS_TRACE_MONITOR(cx).useReservedObjects = JS_FALSE; } @@ -4637,22 +4638,21 @@ js_FlushJITCache(JSContext* cx) oracle.clearHitCounts(); } -JS_FORCES_STACK JSStackFrame * -js_GetTopStackFrame(JSContext *cx) +JS_FORCES_STACK JS_FRIEND_API(void) +js_DeepBail(JSContext *cx) { - if (JS_ON_TRACE(cx)) { - /* It's a bug if a non-FAIL_STATUS builtin gets here. */ - JS_ASSERT(cx->bailExit); + JS_ASSERT(JS_ON_TRACE(cx)); - JS_TRACE_MONITOR(cx).onTrace = false; - JS_TRACE_MONITOR(cx).prohibitRecording = true; - LeaveTree(*cx->interpState, cx->bailExit); + /* It's a bug if a non-FAIL_STATUS builtin gets here. */ + JS_ASSERT(cx->bailExit); + + JS_TRACE_MONITOR(cx).onTrace = false; + JS_TRACE_MONITOR(cx).prohibitRecording = true; + LeaveTree(*cx->interpState, cx->bailExit); #ifdef DEBUG - cx->bailExit = NULL; + cx->bailExit = NULL; #endif - cx->builtinStatus |= JSBUILTIN_BAILED; - } - return cx->fp; + cx->builtinStatus |= JSBUILTIN_BAILED; } JS_REQUIRES_STACK jsval& @@ -5547,7 +5547,7 @@ TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, si #define OP(ops) (*(JSObjectOp*) ((char*)(ops) + op_offset)) if (OP(map->ops) == OP(&js_ObjectOps)) { - guard(true, addName(lir->ins2(LIR_eq, n, INS_CONSTPTR(OP(&js_ObjectOps))), + guard(true, addName(lir->ins2(LIR_eq, n, INS_CONSTFUNPTR(OP(&js_ObjectOps))), "guard(native-map)"), MISMATCH_EXIT); return true; @@ -7060,7 +7060,8 @@ GetProperty(JSContext *cx, uintN argc, jsval *vp) jsval *argv; jsid id; - JS_ASSERT(!JS_ON_TRACE(cx) && cx->fp->imacpc && argc == 1); + JS_ASSERT_NOT_ON_TRACE(cx); + JS_ASSERT(cx->fp->imacpc && argc == 1); argv = JS_ARGV(cx, vp); JS_ASSERT(JSVAL_IS_STRING(argv[0])); if (!js_ValueToStringId(cx, argv[0], &id)) @@ -7091,7 +7092,8 @@ GetElement(JSContext *cx, uintN argc, jsval *vp) jsval *argv; jsid id; - JS_ASSERT(!JS_ON_TRACE(cx) && cx->fp->imacpc && argc == 1); + JS_ASSERT_NOT_ON_TRACE(cx); + JS_ASSERT(cx->fp->imacpc && argc == 1); argv = JS_ARGV(cx, vp); JS_ASSERT(JSVAL_IS_NUMBER(argv[0])); if (!JS_ValueToId(cx, argv[0], &id)) @@ -9250,10 +9252,12 @@ js_GetBuiltinFunction(JSContext *cx, uintN index) if (!funobj) { /* Use NULL parent and atom. Builtin functions never escape to scripts. */ + JS_ASSERT(index < JS_ARRAY_LENGTH(builtinFunctionInfo)); + const BuiltinFunctionInfo *bfi = &builtinFunctionInfo[index]; JSFunction *fun = js_NewFunction(cx, NULL, - (JSNative) builtinFunctionInfo[index].tn, - builtinFunctionInfo[index].nargs, + JS_DATA_TO_FUNC_PTR(JSNative, bfi->tn), + bfi->nargs, JSFUN_FAST_NATIVE | JSFUN_TRACEABLE, NULL, NULL); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 82926c7277b7..708f0e06356c 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -629,22 +629,4 @@ js_GetBuiltinFunction(JSContext *cx, uintN index); #endif /* !JS_TRACER */ -static JS_INLINE JS_FORCES_STACK void -js_LeaveTrace(JSContext *cx) -{ - if (JS_ON_TRACE(cx)) - js_GetTopStackFrame(cx); -} - -static JS_INLINE bool -js_CanLeaveTrace(JSContext *cx) -{ - JS_ASSERT(JS_ON_TRACE(cx)); -#ifdef JS_TRACER - return cx->bailExit; -#else - return false; -#endif -} - #endif /* jstracer_h___ */ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 346157802274..54b23b266c6e 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1399,7 +1399,7 @@ PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #ifdef DEBUG static void -UpdateSwitchTableBounds(JSScript *script, uintN offset, +UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset, uintN *start, uintN *end) { jsbytecode *pc; @@ -1408,7 +1408,7 @@ UpdateSwitchTableBounds(JSScript *script, uintN offset, jsint low, high, n; pc = script->code + offset; - op = (JSOp) *pc; + op = js_GetOpcode(cx, script, pc); switch (op) { case JSOP_TABLESWITCHX: jmplen = JUMPX_OFFSET_LEN; @@ -1471,7 +1471,7 @@ SrcNotes(JSContext *cx, JSScript *script) if (switchTableStart <= offset && offset < switchTableEnd) { name = "case"; } else { - JS_ASSERT(script->code[offset] == JSOP_NOP); + JS_ASSERT(js_GetOpcode(cx, script, script->code + offset) == JSOP_NOP); } } fprintf(gOutFile, "%3u: %5u [%4u] %-8s", @@ -1529,7 +1529,7 @@ SrcNotes(JSContext *cx, JSScript *script) caseOff = (uintN) js_GetSrcNoteOffset(sn, 1); if (caseOff) fprintf(gOutFile, " first case offset %u", caseOff); - UpdateSwitchTableBounds(script, offset, + UpdateSwitchTableBounds(cx, script, offset, &switchTableStart, &switchTableEnd); break; case SRC_CATCH: diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 3ef5e0e9cf26..ad24cda1c29d 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -1261,6 +1261,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, // prepare to do the function call. This adds a fair amount of complexity, // but is a good optimization compared to calling JS_AddRoot for each item. + js_LeaveTrace(cx); + // setup stack // if this isn't a function call then we don't need to push extra stuff