From 4509038fa539a7fe0c6982ed6ac124c6dcedc84c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 11 Jan 2010 11:52:21 -0600 Subject: [PATCH 001/213] Bug 548702 - Temporary value-rooting scheme should be C++- and RAII-based, not macro-based. r=igor --HG-- extra : rebase_source : c7bb34662dbd70df49d40880227139537c60356e --- content/canvas/src/CustomQS_WebGL.h | 30 +- dom/base/nsJSEnvironment.cpp | 11 +- dom/base/nsJSEnvironment.h | 9 +- js/ctypes/Function.cpp | 2 +- js/src/jsapi.cpp | 111 +++-- js/src/jsarray.cpp | 463 ++++++++---------- js/src/jscntxt.h | 462 ++++++++++------- js/src/jscntxtinlines.h | 147 ++++++ js/src/jsdbgapi.cpp | 4 +- js/src/jsexn.cpp | 265 +++++----- js/src/jsfun.cpp | 58 +-- js/src/jsgc.cpp | 103 ++-- js/src/jsgc.h | 19 + js/src/jsinterp.cpp | 4 +- js/src/jsiter.cpp | 49 +- js/src/jsnum.cpp | 6 +- js/src/jsobj.cpp | 122 ++--- js/src/jsobj.h | 4 +- js/src/jsobjinlines.h | 30 ++ js/src/json.cpp | 119 ++--- js/src/json.h | 2 +- js/src/jsopcode.cpp | 4 +- js/src/jsparse.cpp | 22 +- js/src/jsparse.h | 13 +- js/src/jsprvtd.h | 25 - js/src/jsregexp.cpp | 9 +- js/src/jsregexp.h | 6 +- js/src/jsscript.cpp | 8 +- js/src/jsstr.cpp | 4 +- js/src/jstracer.cpp | 23 +- js/src/jstypedarray.cpp | 10 +- js/src/jsutil.h | 4 +- js/src/jsvector.h | 5 +- js/src/jsxml.cpp | 444 ++++++----------- js/src/jsxml.h | 54 +- .../xpconnect/src/XPCChromeObjectWrapper.cpp | 15 +- .../xpconnect/src/XPCCrossOriginWrapper.cpp | 6 +- js/src/xpconnect/src/XPCNativeWrapper.cpp | 2 +- .../xpconnect/src/XPCSafeJSObjectWrapper.cpp | 6 +- js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp | 8 +- js/src/xpconnect/src/XPCWrapper.cpp | 6 +- js/src/xpconnect/src/qsgen.py | 2 +- js/src/xpconnect/src/xpcconvert.cpp | 10 +- js/src/xpconnect/src/xpcquickstubs.cpp | 4 +- js/src/xpconnect/src/xpcquickstubs.h | 2 +- .../xpconnect/src/xpcwrappednativejsops.cpp | 7 +- js/src/xpconnect/tests/TestXPC.cpp | 2 +- modules/plugin/base/src/nsJSNPRuntime.cpp | 48 +- modules/plugin/base/src/nsNPAPIPlugin.cpp | 2 +- xpinstall/src/nsXPITriggerInfo.cpp | 2 +- 50 files changed, 1384 insertions(+), 1389 deletions(-) create mode 100644 js/src/jscntxtinlines.h diff --git a/content/canvas/src/CustomQS_WebGL.h b/content/canvas/src/CustomQS_WebGL.h index 2d479060e59d..abde159d3ffa 100644 --- a/content/canvas/src/CustomQS_WebGL.h +++ b/content/canvas/src/CustomQS_WebGL.h @@ -68,7 +68,7 @@ nsICanvasRenderingContextWebGL_BufferData(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -134,7 +134,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -204,7 +204,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -306,7 +306,7 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -407,7 +407,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -427,7 +427,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -477,7 +477,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -497,7 +497,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -547,7 +547,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -571,7 +571,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -618,7 +618,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -638,7 +638,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -780,7 +780,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -835,7 +835,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -890,7 +890,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj return JSVAL_VOID; } - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 4c1ad2506d53..1044d6bccf65 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2111,14 +2111,13 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler return NS_OK; } - jsval targetVal = JSVAL_VOID; - JSAutoTempValueRooter tvr(mContext, 1, &targetVal); + js::AutoValueRooter targetVal(mContext, JSVAL_VOID); JSObject* target = nsnull; nsresult rv = JSObjectFromInterface(aTarget, aScope, &target); NS_ENSURE_SUCCESS(rv, rv); - targetVal = OBJECT_TO_JSVAL(target); + targetVal.setObject(target); jsval rval = JSVAL_VOID; @@ -2143,7 +2142,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval *argv = nsnull; js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget @@ -2655,7 +2654,7 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg JSAutoRequest ar(mContext); js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, @@ -2690,7 +2689,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter) + js::LazilyConstructed &aRooter) { nsresult rv = NS_OK; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index 785d53c109e3..c7080ae51821 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -49,8 +49,11 @@ class nsIXPConnectJSObjectHolder; class nsAutoPoolRelease; -class JSAutoTempValueRooter; -namespace js { template class LazilyConstructed; } +namespace js { +class AutoValueRooter; +class AutoArrayRooter; +template class LazilyConstructed; +} class nsJSContext : public nsIScriptContext, public nsIXPCScriptNotify @@ -215,7 +218,7 @@ protected: PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter); + js::LazilyConstructed &aRooter); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/ctypes/Function.cpp b/js/ctypes/Function.cpp index c30efc5cf964..45e69f43f16c 100644 --- a/js/ctypes/Function.cpp +++ b/js/ctypes/Function.cpp @@ -624,7 +624,7 @@ Function::Create(JSContext* aContext, return NULL; JSObject* fnObj = JS_GetFunctionObject(fn); - JSAutoTempValueRooter fnRoot(aContext, fnObj); + js::AutoValueRooter fnRoot(aContext, fnObj); // stash a pointer to self, which Function::Call will need at call time if (!JS_SetReservedSlot(aContext, fnObj, 0, PRIVATE_TO_JSVAL(self.get()))) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d47ccec6bcee..cb697a8bcc15 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -438,7 +438,7 @@ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *dp = js_ValueToNumber(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -454,7 +454,7 @@ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToECMAInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -464,7 +464,7 @@ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToECMAUint32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -474,7 +474,7 @@ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -484,7 +484,7 @@ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToUint16(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -3059,7 +3059,7 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->isMethod()) { - JSAutoTempValueRooter root(cx, sprop); + AutoScopePropertyRooter root(cx, sprop); JS_UNLOCK_OBJ(cx, obj2); *vp = sprop->methodValue(); return OBJ_SCOPE(obj2)->methodReadBarrier(cx, sprop, vp); @@ -3810,7 +3810,6 @@ JS_PUBLIC_API(JSIdArray *) JS_Enumerate(JSContext *cx, JSObject *obj) { jsint i, n; - jsval iter_state, num_properties; jsid id; JSIdArray *ida; jsval *vector; @@ -3818,11 +3817,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) CHECK_REQUEST(cx); ida = NULL; - iter_state = JSVAL_NULL; - JSAutoEnumStateRooter tvr(cx, obj, &iter_state); + AutoEnumStateRooter iterState(cx, obj); /* Get the number of properties to enumerate. */ - if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties)) + jsval num_properties; + if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) goto error; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); @@ -3842,11 +3841,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) i = 0; vector = &ida->vector[0]; for (;;) { - if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id)) + if (!obj->enumerate(cx, JSENUMERATE_NEXT, iterState.addr(), &id)) goto error; /* No more jsid's to enumerate ? */ - if (iter_state == JSVAL_NULL) + if (iterState.state() == JSVAL_NULL) break; if (i == ida->length) { @@ -3860,8 +3859,6 @@ JS_Enumerate(JSContext *cx, JSObject *obj) return SetIdArrayLength(cx, ida, i); error: - if (!JSVAL_IS_NULL(iter_state)) - obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); if (ida) JS_DestroyIdArray(cx, ida); return NULL; @@ -3945,7 +3942,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) * Note: we have to make sure that we root obj around the call to * JS_Enumerate to protect against multiple allocations under it. */ - JSAutoTempValueRooter tvr(cx, iterobj); + AutoValueRooter tvr(cx, iterobj); ida = JS_Enumerate(cx, obj); if (!ida) return NULL; @@ -4595,7 +4592,6 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, JS_PUBLIC_API(JSObject *) JS_NewScriptObject(JSContext *cx, JSScript *script) { - JSTempValueRooter tvr; JSObject *obj; CHECK_REQUEST(cx); @@ -4604,16 +4600,19 @@ JS_NewScriptObject(JSContext *cx, JSScript *script) JS_ASSERT(!script->u.object); - JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); - obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); - if (obj) { - obj->setPrivate(script); - script->u.object = obj; + { + AutoScriptRooter root(cx, script); + + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + if (obj) { + obj->setPrivate(script); + script->u.object = obj; #ifdef CHECK_SCRIPT_OWNER - script->owner = NULL; + script->owner = NULL; #endif + } } - JS_POP_TEMP_ROOT(cx, &tvr); + return obj; } @@ -4691,7 +4690,6 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, const char *filename, uintN lineno) { JSFunction *fun; - JSTempValueRooter tvr; JSAtom *funAtom, *argAtom; uintN i; @@ -4709,47 +4707,48 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, if (!fun) goto out2; - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); - for (i = 0; i < nargs; i++) { - argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); - if (!argAtom) { + { + AutoValueRooter tvr(cx, FUN_OBJECT(fun)); + MUST_FLOW_THROUGH("out"); + + for (i = 0; i < nargs; i++) { + argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); + if (!argAtom) { + fun = NULL; + goto out; + } + if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { + fun = NULL; + goto out; + } + } + + if (!JSCompiler::compileFunctionBody(cx, fun, principals, + chars, length, filename, lineno)) { fun = NULL; goto out; } - if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { + + if (obj && funAtom && + !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + NULL, NULL, JSPROP_ENUMERATE)) { fun = NULL; - goto out; } - } - - if (!JSCompiler::compileFunctionBody(cx, fun, principals, - chars, length, filename, lineno)) { - fun = NULL; - goto out; - } - - if (obj && - funAtom && - !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), - NULL, NULL, JSPROP_ENUMERATE)) { - fun = NULL; - } #ifdef JS_SCOPE_DEPTH_METER - if (fun && obj) { - JSObject *pobj = obj; - uintN depth = 1; + if (fun && obj) { + JSObject *pobj = obj; + uintN depth = 1; - while ((pobj = pobj->getParent()) != NULL) - ++depth; - JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); - } + while ((pobj = pobj->getParent()) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } #endif - out: - cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; - JS_POP_TEMP_ROOT(cx, &tvr); + out: + cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; + } out2: LAST_FRAME_CHECKS(cx, fun); @@ -4937,7 +4936,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); JSBool ok = atom && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index edf0b43348c3..d288561df8e0 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -231,7 +231,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) return JS_TRUE; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr())) return JS_FALSE; @@ -405,7 +405,7 @@ EnsureCapacity(JSContext *cx, JSObject *obj, uint32 newcap, static bool ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp) { - JSAutoTempValueRooter dval(cx); + AutoValueRooter dval(cx); if (!js_NewDoubleInRootedValue(cx, index, dval.addr()) || !js_ValueToStringId(cx, dval.value(), idp)) { return JS_FALSE; @@ -450,7 +450,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, return JS_TRUE; } - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); *hole = JS_FALSE; if (!IndexToId(cx, obj, index, hole, idr.addr())) @@ -505,7 +505,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v) return JS_FALSE; } - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE)) return JS_FALSE; @@ -531,7 +531,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index) return JS_TRUE; } - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!IndexToId(cx, obj, index, NULL, idr.addr())) return JS_FALSE; @@ -573,7 +573,7 @@ JSBool js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) { JSErrorReporter older = JS_SetErrorReporter(cx, NULL); - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); JSBool ok = obj->getProperty(cx, id, tvr.addr()); JS_SetErrorReporter(cx, older); @@ -626,9 +626,6 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { jsuint newlen, oldlen, gap, index; jsval junk; - JSObject *iter; - JSTempValueRooter tvr; - JSBool ok; if (!obj->isArray()) { jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); @@ -638,32 +635,30 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) newlen = ValueIsLength(cx, vp); if (JSVAL_IS_NULL(*vp)) - return JS_FALSE; + return false; oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH]; if (oldlen == newlen) - return JS_TRUE; + return true; if (!IndexToValue(cx, newlen, vp)) - return JS_FALSE; + return false; if (oldlen < newlen) { obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; - return JS_TRUE; + return true; } if (obj->isDenseArray()) { /* Don't reallocate if we're not actually shrinking our slots. */ jsuint capacity = js_DenseArrayCapacity(obj); if (capacity > newlen && !ResizeSlots(cx, obj, capacity, newlen)) - return JS_FALSE; + return false; } else if (oldlen - newlen < (1 << 24)) { do { --oldlen; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !DeleteArrayElement(cx, obj, oldlen)) { - return JS_FALSE; - } + if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, oldlen)) + return false; } while (oldlen != newlen); } else { /* @@ -673,33 +668,28 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) * correspond to indexes in the half-open range [newlen, oldlen). See * bug 322135. */ - iter = JS_NewPropertyIterator(cx, obj); + JSObject *iter = JS_NewPropertyIterator(cx, obj); if (!iter) - return JS_FALSE; + return false; /* Protect iter against GC under JSObject::deleteProperty. */ - JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr); + AutoValueRooter tvr(cx, iter); + gap = oldlen - newlen; for (;;) { - ok = (JS_CHECK_OPERATION_LIMIT(cx) && - JS_NextProperty(cx, iter, &id)); - if (!ok) - break; + if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id)) + return false; if (JSVAL_IS_VOID(id)) break; - if (js_IdIsIndex(id, &index) && index - newlen < gap) { - ok = obj->deleteProperty(cx, id, &junk); - if (!ok) - break; + if (js_IdIsIndex(id, &index) && index - newlen < gap && + !obj->deleteProperty(cx, id, &junk)) { + return false; } } - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - return JS_FALSE; } obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; - return JS_TRUE; + return true; } /* @@ -1518,7 +1508,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, return true; } - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); /* After this point, all paths exit through the 'out' label. */ MUST_FLOW_THROUGH("out"); @@ -1652,7 +1642,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva #ifdef DEBUG_jwalden { /* Verify that overwriteType and writeType were accurate. */ - JSAutoTempIdRooter idr(cx, JSVAL_ZERO); + AutoIdRooter idr(cx); for (jsuint i = 0; i < count; i++) { JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE); @@ -1718,12 +1708,12 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva JS_ASSERT(start == MAXINDEX); jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL}; - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); if (!js_NewDoubleInRootedValue(cx, MAXINDEX, &tmp[0])) return JS_FALSE; jsdouble *dp = JSVAL_TO_DOUBLE(tmp[0]); JS_ASSERT(*dp == MAXINDEX); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); do { tmp[1] = *vector++; if (!js_ValueToStringId(cx, tmp[0], idr.addr()) || @@ -1769,7 +1759,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector, static JSString* FASTCALL Array_p_join(JSContext* cx, JSObject* obj, JSString *str) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (!array_toString_sub(cx, obj, JS_FALSE, str, tvr.addr())) { SetBuiltinError(cx); return NULL; @@ -1780,7 +1770,7 @@ Array_p_join(JSContext* cx, JSObject* obj, JSString *str) static JSString* FASTCALL Array_p_toString(JSContext* cx, JSObject* obj) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) { SetBuiltinError(cx); return NULL; @@ -1852,7 +1842,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); for (jsuint i = 0, half = len / 2; i < half; i++) { JSBool hole, hole2; if (!JS_CHECK_OPERATION_LIMIT(cx) || @@ -2102,40 +2092,28 @@ JS_STATIC_ASSERT(JSVAL_NULL == 0); static JSBool array_sort(JSContext *cx, uintN argc, jsval *vp) { - jsval *argv, fval, *vec, *mergesort_tmp, v; - JSObject *obj; - CompareArgs ca; + jsval fval; jsuint len, newlen, i, undefs; - JSTempValueRooter tvr; - JSBool hole; - JSBool ok; size_t elemsize; JSString *str; - /* - * Optimize the default compare function case if all of obj's elements - * have values of type string. - */ - JSBool all_strings; - - argv = JS_ARGV(cx, vp); + jsval *argv = JS_ARGV(cx, vp); if (argc > 0) { if (JSVAL_IS_PRIMITIVE(argv[0])) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_SORT_ARG); - return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); + return false; } fval = argv[0]; /* non-default compare function */ } else { fval = JSVAL_NULL; } - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = JS_THIS_OBJECT(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &len)) - return JS_FALSE; + return false; if (len == 0) { *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; + return true; } /* @@ -2145,19 +2123,16 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * malloc'd vector. */ #if JS_BITS_PER_WORD == 32 - if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) { + if (size_t(len) > SIZE_MAX / (2 * sizeof(jsval))) { js_ReportAllocationOverflow(cx); - return JS_FALSE; + return false; } #endif - vec = (jsval *) cx->malloc(2 * (size_t) len * sizeof(jsval)); - if (!vec) - return JS_FALSE; /* * Initialize vec as a root. We will clear elements of vec one by - * one while increasing tvr.count when we know that the property at - * the corresponding index exists and its value must be rooted. + * one while increasing the rooted amount of vec when we know that the + * property at the corresponding index exists and its value must be rooted. * * In this way when sorting a huge mostly sparse array we will not * access the tail of vec corresponding to properties that do not @@ -2165,204 +2140,196 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * * After this point control must flow through label out: to exit. */ - JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr); + { + jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval)); + if (!vec) + return false; - /* - * By ECMA 262, 15.4.4.11, a property that does not exist (which we - * call a "hole") is always greater than an existing property with - * value undefined and that is always greater than any other property. - * Thus to sort holes and undefs we simply count them, sort the rest - * of elements, append undefs after them and then make holes after - * undefs. - */ - undefs = 0; - newlen = 0; - all_strings = JS_TRUE; - for (i = 0; i < len; i++) { - ok = JS_CHECK_OPERATION_LIMIT(cx); - if (!ok) - goto out; + struct AutoFreeVector { + AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { } + ~AutoFreeVector() { + cx->free(vec); + } + JSContext * const cx; + jsval *&vec; + } free(cx, vec); - /* Clear vec[newlen] before including it in the rooted set. */ - vec[newlen] = JSVAL_NULL; - tvr.count = newlen + 1; - ok = GetArrayElement(cx, obj, i, &hole, &vec[newlen]); - if (!ok) - goto out; + AutoArrayRooter tvr(cx, 0, vec); - if (hole) - continue; + /* + * By ECMA 262, 15.4.4.11, a property that does not exist (which we + * call a "hole") is always greater than an existing property with + * value undefined and that is always greater than any other property. + * Thus to sort holes and undefs we simply count them, sort the rest + * of elements, append undefs after them and then make holes after + * undefs. + */ + undefs = 0; + newlen = 0; + bool allStrings = true; + for (i = 0; i < len; i++) { + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; - if (JSVAL_IS_VOID(vec[newlen])) { - ++undefs; - continue; + /* Clear vec[newlen] before including it in the rooted set. */ + JSBool hole; + vec[newlen] = JSVAL_NULL; + tvr.changeLength(newlen + 1); + if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen])) + return false; + + if (hole) + continue; + + if (JSVAL_IS_VOID(vec[newlen])) { + ++undefs; + continue; + } + + allStrings = allStrings && JSVAL_IS_STRING(vec[newlen]); + + ++newlen; } - /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */ - all_strings &= JSVAL_IS_STRING(vec[newlen]); + if (newlen == 0) + return true; /* The array has only holes and undefs. */ - ++newlen; - } - - if (newlen == 0) { - /* The array has only holes and undefs. */ - ok = JS_TRUE; - goto out; - } - - /* - * The first newlen elements of vec are copied from the array object - * (above). The remaining newlen positions are used as GC-rooted scratch - * space for mergesort. We must clear the space before including it to - * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize - * initialization using memset. - */ - mergesort_tmp = vec + newlen; - memset(mergesort_tmp, 0, newlen * sizeof(jsval)); - tvr.count = newlen * 2; - - /* Here len == 2 * (newlen + undefs + number_of_holes). */ - if (fval == JSVAL_NULL) { /* - * Sort using the default comparator converting all elements to - * strings. + * The first newlen elements of vec are copied from the array object + * (above). The remaining newlen positions are used as GC-rooted scratch + * space for mergesort. We must clear the space before including it to + * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize + * initialization using memset. */ - if (all_strings) { - elemsize = sizeof(jsval); - } else { + jsval *mergesort_tmp = vec + newlen; + memset(mergesort_tmp, 0, newlen * sizeof(jsval)); + tvr.changeLength(newlen * 2); + + /* Here len == 2 * (newlen + undefs + number_of_holes). */ + if (fval == JSVAL_NULL) { /* - * To avoid string conversion on each compare we do it only once - * prior to sorting. But we also need the space for the original - * values to recover the sorting result. To reuse - * sort_compare_strings we move the original values to the odd - * indexes in vec, put the string conversion results in the even - * indexes and pass 2 * sizeof(jsval) as an element size to the - * sorting function. In this way sort_compare_strings will only - * see the string values when it casts the compare arguments as - * pointers to jsval. - * - * This requires doubling the temporary storage including the - * scratch space for the merge sort. Since vec already contains - * the rooted scratch space for newlen elements at the tail, we - * can use it to rearrange and convert to strings first and try - * realloc only when we know that we successfully converted all - * the elements. + * Sort using the default comparator converting all elements to + * strings. */ + if (allStrings) { + elemsize = sizeof(jsval); + } else { + /* + * To avoid string conversion on each compare we do it only once + * prior to sorting. But we also need the space for the original + * values to recover the sorting result. To reuse + * sort_compare_strings we move the original values to the odd + * indexes in vec, put the string conversion results in the even + * indexes and pass 2 * sizeof(jsval) as an element size to the + * sorting function. In this way sort_compare_strings will only + * see the string values when it casts the compare arguments as + * pointers to jsval. + * + * This requires doubling the temporary storage including the + * scratch space for the merge sort. Since vec already contains + * the rooted scratch space for newlen elements at the tail, we + * can use it to rearrange and convert to strings first and try + * realloc only when we know that we successfully converted all + * the elements. + */ #if JS_BITS_PER_WORD == 32 - if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) { - js_ReportAllocationOverflow(cx); - ok = JS_FALSE; - goto out; - } + if (size_t(newlen) > SIZE_MAX / (4 * sizeof(jsval))) { + js_ReportAllocationOverflow(cx); + return false; + } #endif - /* - * Rearrange and string-convert the elements of the vector from - * the tail here and, after sorting, move the results back - * starting from the start to prevent overwrite the existing - * elements. - */ - i = newlen; - do { - --i; - ok = JS_CHECK_OPERATION_LIMIT(cx); - if (!ok) - goto out; - v = vec[i]; - str = js_ValueToString(cx, v); - if (!str) { - ok = JS_FALSE; - goto out; + /* + * Rearrange and string-convert the elements of the vector from + * the tail here and, after sorting, move the results back + * starting from the start to prevent overwrite the existing + * elements. + */ + i = newlen; + do { + --i; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + jsval v = vec[i]; + str = js_ValueToString(cx, v); + if (!str) + return false; + vec[2 * i] = STRING_TO_JSVAL(str); + vec[2 * i + 1] = v; + } while (i != 0); + + JS_ASSERT(tvr.array == vec); + vec = (jsval *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(jsval)); + if (!vec) { + vec = tvr.array; + return false; } - vec[2 * i] = STRING_TO_JSVAL(str); - vec[2 * i + 1] = v; - } while (i != 0); - - JS_ASSERT(tvr.u.array == vec); - vec = (jsval *) cx->realloc(vec, - 4 * (size_t) newlen * sizeof(jsval)); - if (!vec) { - vec = tvr.u.array; - ok = JS_FALSE; - goto out; + mergesort_tmp = vec + 2 * newlen; + memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval)); + tvr.changeArray(vec, newlen * 4); + elemsize = 2 * sizeof(jsval); } - tvr.u.array = vec; - mergesort_tmp = vec + 2 * newlen; - memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval)); - tvr.count = newlen * 4; - elemsize = 2 * sizeof(jsval); - } - ok = js_MergeSort(vec, (size_t) newlen, elemsize, - sort_compare_strings, cx, mergesort_tmp); - if (!ok) - goto out; - if (!all_strings) { - /* - * We want to make the following loop fast and to unroot the - * cached results of toString invocations before the operation - * callback has a chance to run the GC. For this reason we do - * not call JS_CHECK_OPERATION_LIMIT in the loop. - */ - i = 0; - do { - vec[i] = vec[2 * i + 1]; - } while (++i != newlen); - } - } else { - void *mark; + if (!js_MergeSort(vec, size_t(newlen), elemsize, + sort_compare_strings, cx, mergesort_tmp)) { + return false; + } + if (!allStrings) { + /* + * We want to make the following loop fast and to unroot the + * cached results of toString invocations before the operation + * callback has a chance to run the GC. For this reason we do + * not call JS_CHECK_OPERATION_LIMIT in the loop. + */ + i = 0; + do { + vec[i] = vec[2 * i + 1]; + } while (++i != newlen); + } + } else { + void *mark; - LeaveTrace(cx); + LeaveTrace(cx); - ca.context = cx; - ca.fval = fval; - ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); - if (!ca.elemroot) { - ok = JS_FALSE; - goto out; + CompareArgs ca; + ca.context = cx; + ca.fval = fval; + ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); + if (!ca.elemroot) + return false; + bool ok = js_MergeSort(vec, size_t(newlen), sizeof(jsval), + comparator_stack_cast(sort_compare), + &ca, mergesort_tmp); + js_FreeStack(cx, mark); + if (!ok) + return false; + } + + /* + * We no longer need to root the scratch space for the merge sort, so + * unroot it now to make the job of a potential GC under + * InitArrayElements easier. + */ + tvr.changeLength(newlen); + if (!InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues, + SourceVectorAllValues)) { + return false; } - ok = js_MergeSort(vec, (size_t) newlen, sizeof(jsval), - comparator_stack_cast(sort_compare), - &ca, mergesort_tmp); - js_FreeStack(cx, mark); - if (!ok) - goto out; } - /* - * We no longer need to root the scratch space for the merge sort, so - * unroot it now to make the job of a potential GC under InitArrayElements - * easier. - */ - tvr.count = newlen; - ok = InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues, - SourceVectorAllValues); - if (!ok) - goto out; - - out: - JS_POP_TEMP_ROOT(cx, &tvr); - cx->free(vec); - if (!ok) - return JS_FALSE; - /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) { - return JS_FALSE; - } + if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) + return false; } /* Re-create any holes that sorted to the end of the array. */ while (len > newlen) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !DeleteArrayElement(cx, obj, --len)) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len)) return JS_FALSE; - } } *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; + return true; } /* @@ -2436,7 +2403,7 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0, static jsval FASTCALL Array_p_push1(JSContext* cx, JSObject* obj, jsval v) { - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); if (obj->isDenseArray() ? array_push1_dense(cx, obj, v, tvr.addr()) : array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) { @@ -2508,7 +2475,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp) static jsval FASTCALL Array_p_pop(JSContext* cx, JSObject* obj) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (obj->isDenseArray() ? array_pop_dense(cx, obj, tvr.addr()) : array_pop_slowly(cx, obj, tvr.addr())) { @@ -2572,7 +2539,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; /* Slide down the array above the first element. */ - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); for (i = 0; i != length; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) || @@ -2617,7 +2584,7 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp) } else { last = length; jsdouble upperIndex = last + argc; - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); do { --last, --upperIndex; if (!JS_CHECK_OPERATION_LIMIT(cx) || @@ -2707,7 +2674,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) argv++; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); /* If there are elements to remove, put them into the return value. */ if (count > 0) { @@ -2846,7 +2813,7 @@ array_concat(JSContext *cx, uintN argc, jsval *vp) length = 0; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ for (i = 0; i <= argc; i++) { @@ -2960,7 +2927,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = OBJECT_TO_JSVAL(nobj); - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); for (slot = begin; slot < end; slot++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, slot, &hole, tvr.addr())) { @@ -3470,10 +3437,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj) JSObject * js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) { - JSTempValueRooter tvr; - JSObject *obj; - - obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL); + JSObject *obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL); if (!obj) return NULL; @@ -3483,10 +3447,11 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) */ JS_ASSERT(obj->getProto()); - JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); - if (!InitArrayObject(cx, obj, length, vector, holey)) - obj = NULL; - JS_POP_TEMP_ROOT(cx, &tvr); + { + AutoValueRooter tvr(cx, obj); + if (!InitArrayObject(cx, obj, length, vector, holey)) + obj = NULL; + } /* Set/clear newborn root, in case we lost it. */ cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj; @@ -3602,7 +3567,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector) if (!obj) return NULL; - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); if (!EnsureCapacity(cx, obj, capacity, JS_FALSE)) obj = NULL; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index f96e701acd6b..02833fcee675 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1161,97 +1161,6 @@ typedef struct JSResolvingEntry { #define JSRESFLAG_LOOKUP 0x1 /* resolving id from lookup */ #define JSRESFLAG_WATCH 0x2 /* resolving id from watch */ - -/* - * Macros to push/pop JSTempValueRooter instances to context-linked stack of - * temporary GC roots. If you need to protect a result value that flows out of - * a C function across several layers of other functions, use the - * js_LeaveLocalRootScopeWithResult internal API (see further below) instead. - * - * The macros also provide a simple way to get a single rooted pointer via - * JS_PUSH_TEMP_ROOT_(cx, NULL, &tvr). Then &tvr.u. gives the - * necessary pointer. - * - * JSTempValueRooter.count defines the type of the rooted value referenced by - * JSTempValueRooter.u union of type JSTempValueUnion. When count is positive - * or zero, u.array points to a vector of jsvals. Otherwise it must be one of - * the following constants: - */ -#define JSTVU_SINGLE (-1) /* u.value or u. is single jsval - or non-JSString GC-thing pointer */ -#define JSTVU_TRACE (-2) /* u.trace is a hook to trace a custom - * structure */ -#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */ -#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */ -#define JSTVU_COMPILER (-5) /* u.compiler roots JSCompiler* */ -#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */ -#define JSTVU_ENUMERATOR (-7) /* a pointer to JSTempValueRooter points - to an instance of JSAutoEnumStateRooter - with u.object storing the enumeration - object */ - -/* - * Here single JSTVU_SINGLE covers both jsval and pointers to almost (see note - * below) any GC-thing via reinterpreting the thing as JSVAL_OBJECT. This works - * because the GC-thing is aligned on a 0 mod 8 boundary, and object has the 0 - * jsval tag. So any GC-heap-allocated thing pointer may be tagged as if it - * were an object and untagged, if it's then used only as an opaque pointer - * until discriminated by other means than tag bits. This is how, for example, - * js_GetGCThingTraceKind uses its |thing| parameter -- it consults GC-thing - * flags stored separately from the thing to decide the kind of thing. - * - * Note well that JSStrings may be statically allocated (see the intStringTable - * and unitStringTable static arrays), so this hack does not work for arbitrary - * GC-thing pointers. - */ -#define JS_PUSH_TEMP_ROOT_COMMON(cx,x,tvr,cnt,kind) \ - JS_BEGIN_MACRO \ - JS_ASSERT((cx)->tempValueRooters != (tvr)); \ - (tvr)->count = (cnt); \ - (tvr)->u.kind = (x); \ - (tvr)->down = (cx)->tempValueRooters; \ - (cx)->tempValueRooters = (tvr); \ - JS_END_MACRO - -#define JS_POP_TEMP_ROOT(cx,tvr) \ - JS_BEGIN_MACRO \ - JS_ASSERT((cx)->tempValueRooters == (tvr)); \ - (cx)->tempValueRooters = (tvr)->down; \ - JS_END_MACRO - -#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \ - JS_BEGIN_MACRO \ - JS_ASSERT((int)(cnt) >= 0); \ - JS_PUSH_TEMP_ROOT_COMMON(cx, arr, tvr, (ptrdiff_t) (cnt), array); \ - JS_END_MACRO - -#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, val, tvr, JSTVU_SINGLE, value) - -#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, obj, tvr, JSTVU_SINGLE, object) - -#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr) \ - JS_PUSH_SINGLE_TEMP_ROOT(cx, str ? STRING_TO_JSVAL(str) : JSVAL_NULL, tvr) - -#define JS_PUSH_TEMP_ROOT_XML(cx,xml_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, xml_, tvr, JSTVU_SINGLE, xml) - -#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, trace_, tvr, JSTVU_TRACE, trace) - -#define JS_PUSH_TEMP_ROOT_SPROP(cx,sprop_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, sprop_, tvr, JSTVU_SPROP, sprop) - -#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots) - -#define JS_PUSH_TEMP_ROOT_COMPILER(cx,pc,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_COMPILER, compiler) - -#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script) - #define JSRESOLVE_INFER 0xffff /* infer bits from current bytecode */ extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ @@ -1265,6 +1174,10 @@ struct JSGCReachableFrame { JSStackFrame *frame; }; +namespace js { +class AutoGCRooter; +} + struct JSContext { explicit JSContext(JSRuntime *rt) : runtime(rt), busyArrays(this) {} @@ -1466,8 +1379,8 @@ struct JSContext /* PDL of stack headers describing stack slots not rooted by argv, etc. */ JSStackHeader *stackHeaders; - /* Stack of thread-stack-allocated temporary GC roots. */ - JSTempValueRooter *tempValueRooters; + /* Stack of thread-stack-allocated GC roots. */ + js::AutoGCRooter *autoGCRooters; /* Debug hooks associated with the current context. */ const JSDebugHooks *debugHooks; @@ -1704,93 +1617,258 @@ FrameAtomBase(JSContext *cx, JSStackFrame *fp) : fp->script->atomMap.vector; } -/* FIXME(bug 332648): Move this into a public header. */ -class JSAutoTempValueRooter -{ +namespace js { + +class AutoGCRooter { public: - JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr); - } - explicit JSAutoTempValueRooter(JSContext *cx, jsval v = JSVAL_NULL - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, JSString *str - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT_STRING(mContext, str, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT_OBJECT(mContext, obj, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, JSScopeProperty *sprop - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT_SPROP(mContext, sprop, &mTvr); + AutoGCRooter(JSContext *cx, ptrdiff_t tag) + : down(cx->autoGCRooters), tag(tag), context(cx) + { + JS_ASSERT(this != cx->autoGCRooters); + cx->autoGCRooters = this; } - ~JSAutoTempValueRooter() { - JS_POP_TEMP_ROOT(mContext, &mTvr); + ~AutoGCRooter() { + JS_ASSERT(this == context->autoGCRooters); + context->autoGCRooters = down; } - jsval value() { return mTvr.u.value; } - jsval *addr() { return &mTvr.u.value; } + inline void trace(JSTracer *trc); + + friend void ::js_TraceContext(JSTracer *trc, JSContext *acx); protected: - JSContext *mContext; + AutoGCRooter * const down; - private: - JSTempValueRooter mTvr; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER + /* + * Discriminates actual subclass of this being used. If non-negative, the + * subclass roots an array of jsvals of the length stored in this field. + * If negative, meaning is indicated by the corresponding value in the enum + * below. Any other negative value indicates some deeper problem such as + * memory corruption. + */ + ptrdiff_t tag; + + JSContext * const context; + + enum { + JSVAL = -1, /* js::AutoValueRooter */ + SPROP = -2, /* JSAutoScopePropertyTreeRooter */ + WEAKROOTS = -3, /* AutoSaveWeakRoots */ + COMPILER = -4, /* JSCompiler */ + SCRIPT = -5, /* JSAutoScriptRooter */ + ENUMERATOR = -6, /* JSAutoEnumStateRooter */ + IDARRAY = -7, /* JSAutoIdArray */ + DESCRIPTORS = -8, /* AutoDescriptorArray */ + NAMESPACES = -9, /* AutoNamespaceArray */ + XML = -10, /* JSAutoXML */ + OBJECT = -11, /* JSAutoObjectRooter */ + ID = -12 /* JSAutoTempIdRooter */ + }; }; -class JSAutoTempIdRooter +class AutoSaveWeakRoots : private AutoGCRooter { public: - explicit JSAutoTempIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { + explicit AutoSaveWeakRoots(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, WEAKROOTS), savedRoots(cx->weakRoots) + { JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_SINGLE_TEMP_ROOT(mContext, ID_TO_VALUE(id), &mTvr); } - ~JSAutoTempIdRooter() { - JS_POP_TEMP_ROOT(mContext, &mTvr); - } - - jsid id() { return (jsid) mTvr.u.value; } - jsid * addr() { return (jsid *) &mTvr.u.value; } + friend void AutoGCRooter::trace(JSTracer *trc); private: - JSContext *mContext; - JSTempValueRooter mTvr; + JSWeakRoots savedRoots; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -class JSAutoIdArray { +/* FIXME(bug 332648): Move this into a public header. */ +class AutoValueRooter : private AutoGCRooter +{ public: - JSAutoIdArray(JSContext *cx, JSIdArray *ida - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : cx(cx), idArray(ida) { + explicit AutoValueRooter(JSContext *cx, jsval v = JSVAL_NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(v) + { JS_GUARD_OBJECT_NOTIFIER_INIT; - if (ida) - JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr); } - ~JSAutoIdArray() { - if (idArray) { - JS_POP_TEMP_ROOT(cx, &tvr); - JS_DestroyIdArray(cx, idArray); - } + AutoValueRooter(JSContext *cx, JSString *str + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(STRING_TO_JSVAL(str)) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + AutoValueRooter(JSContext *cx, JSObject *obj + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(OBJECT_TO_JSVAL(obj)) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setObject(JSObject *obj) { + JS_ASSERT(tag == JSVAL); + val = OBJECT_TO_JSVAL(obj); + } + + void setString(JSString *str) { + JS_ASSERT(tag == JSVAL); + JS_ASSERT(str); + val = STRING_TO_JSVAL(str); + } + + void setDouble(jsdouble *dp) { + JS_ASSERT(tag == JSVAL); + JS_ASSERT(dp); + val = DOUBLE_TO_JSVAL(dp); + } + + jsval value() const { + JS_ASSERT(tag == JSVAL); + return val; + } + + jsval *addr() { + JS_ASSERT(tag == JSVAL); + return &val; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + jsval val; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoObjectRooter : private AutoGCRooter { + public: + AutoObjectRooter(JSContext *cx, JSObject *obj = NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, OBJECT), obj(obj) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setObject(JSObject *obj) { + this->obj = obj; + } + + JSObject * object() const { + return obj; + } + + JSObject ** addr() { + return &obj; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSObject *obj; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoArrayRooter : private AutoGCRooter { + public: + AutoArrayRooter(JSContext *cx, size_t len, jsval *vec + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, len), array(vec) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_ASSERT(tag >= 0); + } + + void changeLength(size_t newLength) { + tag = ptrdiff_t(newLength); + JS_ASSERT(tag >= 0); + } + + void changeArray(jsval *newArray, size_t newLength) { + changeLength(newLength); + array = newArray; + } + + jsval *array; + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoScopePropertyRooter : private AutoGCRooter { + public: + AutoScopePropertyRooter(JSContext *cx, JSScopeProperty *sprop + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, SPROP), sprop(sprop) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSScopeProperty * const sprop; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoScriptRooter : private AutoGCRooter { + public: + AutoScriptRooter(JSContext *cx, JSScript *script + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, SCRIPT), script(script) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setScript(JSScript *script) { + this->script = script; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSScript *script; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoIdRooter : private AutoGCRooter +{ + public: + explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, ID), idval(id) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + jsid id() { + return idval; + } + + jsid * addr() { + return &idval; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + jsid idval; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoIdArray : private AutoGCRooter { + public: + AutoIdArray(JSContext *cx, JSIdArray *ida + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, ida ? ida->length : 0), idArray(ida) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoIdArray() { + if (idArray) + JS_DestroyIdArray(context, idArray); } bool operator!() { return idArray == NULL; @@ -1803,52 +1881,86 @@ class JSAutoIdArray { size_t length() const { return idArray->length; } + + friend void AutoGCRooter::trace(JSTracer *trc); + + protected: + inline void trace(JSTracer *trc); + private: - JSContext * const cx; JSIdArray * const idArray; - JSTempValueRooter tvr; JS_DECL_USE_GUARD_OBJECT_NOTIFIER /* No copy or assignment semantics. */ - JSAutoIdArray(JSAutoIdArray &); - void operator=(JSAutoIdArray &); + AutoIdArray(AutoIdArray &ida); + void operator=(AutoIdArray &ida); }; /* The auto-root for enumeration object and its state. */ -class JSAutoEnumStateRooter : public JSTempValueRooter +class AutoEnumStateRooter : private AutoGCRooter { public: - JSAutoEnumStateRooter(JSContext *cx, JSObject *obj, jsval *statep - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx), mStatep(statep) + AutoEnumStateRooter(JSContext *cx, JSObject *obj + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue(JSVAL_NULL) { JS_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(obj); - JS_ASSERT(statep); - JS_PUSH_TEMP_ROOT_COMMON(cx, obj, this, JSTVU_ENUMERATOR, object); } - ~JSAutoEnumStateRooter() { - JS_POP_TEMP_ROOT(mContext, this); + ~AutoEnumStateRooter() { + if (!JSVAL_IS_NULL(stateValue)) { +#ifdef DEBUG + JSBool ok = +#endif + obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0); + JS_ASSERT(ok); + } } - void mark(JSTracer *trc) { - JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj"); - js_MarkEnumeratorState(trc, u.object, *mStatep); + friend void AutoGCRooter::trace(JSTracer *trc); + + jsval state() const { return stateValue; } + jsval * addr() { return &stateValue; } + + protected: + void trace(JSTracer *trc) { + JS_CALL_OBJECT_TRACER(trc, obj, "js::AutoEnumStateRooter.obj"); + js_MarkEnumeratorState(trc, obj, stateValue); } + JSObject * const obj; + private: - JSContext *mContext; - jsval *mStatep; + jsval stateValue; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; +#ifdef JS_HAS_XML_SUPPORT +class AutoXMLRooter : private AutoGCRooter { + public: + AutoXMLRooter(JSContext *cx, JSXML *xml) + : AutoGCRooter(cx, XML), xml(xml) + { + JS_ASSERT(xml); + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSXML * const xml; +}; +#endif /* JS_HAS_XML_SUPPORT */ + +} + class JSAutoResolveFlags { public: JSAutoResolveFlags(JSContext *cx, uintN flags JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx), mSaved(cx->resolveFlags) { + : mContext(cx), mSaved(cx->resolveFlags) + { JS_GUARD_OBJECT_NOTIFIER_INIT; cx->resolveFlags = flags; } diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h new file mode 100644 index 000000000000..ca28d7682f2f --- /dev/null +++ b/js/src/jscntxtinlines.h @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Walden (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscntxtinlines_h___ +#define jscntxtinlines_h___ + +#include "jscntxt.h" +#include "jsxml.h" + +#include "jsobjinlines.h" + +namespace js { + +void +AutoIdArray::trace(JSTracer *trc) { + JS_ASSERT(tag == IDARRAY); + js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); +} + +class AutoNamespaces : protected AutoGCRooter { + protected: + AutoNamespaces(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) { + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + public: + JSXMLArray array; +}; + +inline void +AutoGCRooter::trace(JSTracer *trc) +{ + switch (tag) { + case JSVAL: + JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val"); + js_CallValueTracerIfGCThing(trc, static_cast(this)->val); + return; + + case SPROP: + static_cast(this)->sprop->trace(trc); + return; + + case WEAKROOTS: + static_cast(this)->savedRoots.mark(trc); + return; + + case COMPILER: + static_cast(this)->trace(trc); + return; + + case SCRIPT: + if (JSScript *script = static_cast(this)->script) + js_TraceScript(trc, script); + return; + + case ENUMERATOR: + static_cast(this)->trace(trc); + return; + + case IDARRAY: { + JSIdArray *ida = static_cast(this)->idArray; + TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); + return; + } + + case DESCRIPTORS: { + PropertyDescriptorArray &descriptors = + static_cast(this)->descriptors; + for (size_t i = 0, len = descriptors.length(); i < len; i++) { + PropertyDescriptor &desc = descriptors[i]; + + JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); + JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); + JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); + js_TraceId(trc, desc.id); + } + return; + } + + case NAMESPACES: { + JSXMLArray &array = static_cast(this)->array; + TraceObjectVector(trc, reinterpret_cast(array.vector), array.length); + array.cursors->trace(trc); + return; + } + + case XML: + js_TraceXML(trc, static_cast(this)->xml); + return; + + case OBJECT: + if (JSObject *obj = static_cast(this)->obj) { + JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj"); + js_CallGCMarker(trc, obj, JSTRACE_OBJECT); + } + return; + + case ID: + JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val"); + js_CallValueTracerIfGCThing(trc, static_cast(this)->idval); + return; + } + + JS_ASSERT(tag >= 0); + TraceValues(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); +} + +} + +#endif /* jscntxtinlines_h___ */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index a964851f3649..05ba1230a0e6 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1465,8 +1465,8 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, { pd->id = ID_TO_VALUE(sprop->id); - JSBool wasThrowing = cx->throwing; - JSAutoTempValueRooter lastException(cx, cx->exception); + bool wasThrowing = cx->throwing; + AutoValueRooter lastException(cx, cx->exception); cx->throwing = JS_FALSE; if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 670efd3196a6..fea99f3133f6 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -63,6 +63,8 @@ #include "jsscript.h" #include "jsstaticcheck.h" +using namespace js; + /* Forward declarations for js_ErrorClass's initializer. */ static JSBool Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); @@ -824,131 +826,119 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) JSObject *obj; JSString *name, *message, *filename, *lineno_as_str, *result; jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; - JSTempValueRooter tvr; - JSBool ok; uint32 lineno; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; obj = JS_THIS_OBJECT(cx, vp); if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) - return JS_FALSE; + return false; name = js_ValueToString(cx, *vp); if (!name) - return JS_FALSE; + return false; *vp = STRING_TO_JSVAL(name); - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); + { + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots); #ifdef __GNUC__ - message = filename = NULL; + message = filename = NULL; #endif - ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) && - (message = js_ValueToSource(cx, localroots[0])); - if (!ok) - goto out; - localroots[0] = STRING_TO_JSVAL(message); - - ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) && - (filename = js_ValueToSource(cx, localroots[1])); - if (!ok) - goto out; - localroots[1] = STRING_TO_JSVAL(filename); - - ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]); - if (!ok) - goto out; - lineno = js_ValueToECMAUint32 (cx, &localroots[2]); - ok = !JSVAL_IS_NULL(localroots[2]); - if (!ok) - goto out; - - if (lineno != 0) { - lineno_as_str = js_ValueToString(cx, localroots[2]); - if (!lineno_as_str) { - ok = JS_FALSE; - goto out; + if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || + !(message = js_ValueToSource(cx, localroots[0]))) { + return false; } - lineno_length = lineno_as_str->length(); - } else { - lineno_as_str = NULL; - lineno_length = 0; - } + localroots[0] = STRING_TO_JSVAL(message); - /* Magic 8, for the characters in ``(new ())''. */ - name_length = name->length(); - message_length = message->length(); - length = 8 + name_length + message_length; + if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || + !(filename = js_ValueToSource(cx, localroots[1]))) { + return false; + } + localroots[1] = STRING_TO_JSVAL(filename); - filename_length = filename->length(); - if (filename_length != 0) { - /* append filename as ``, {filename}'' */ - length += 2 + filename_length; + if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2])) + return false; + lineno = js_ValueToECMAUint32 (cx, &localroots[2]); + if (JSVAL_IS_NULL(localroots[2])) + return false; + + if (lineno != 0) { + lineno_as_str = js_ValueToString(cx, localroots[2]); + if (!lineno_as_str) + return false; + lineno_length = lineno_as_str->length(); + } else { + lineno_as_str = NULL; + lineno_length = 0; + } + + /* Magic 8, for the characters in ``(new ())''. */ + name_length = name->length(); + message_length = message->length(); + length = 8 + name_length + message_length; + + filename_length = filename->length(); + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + length += 2 + filename_length; + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + length += 2 + lineno_length; + } + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + length += 6 + lineno_length; + } + } + + cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!chars) + return false; + + *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; + js_strncpy(cp, name->chars(), name_length); + cp += name_length; + *cp++ = '('; + if (message_length != 0) { + js_strncpy(cp, message->chars(), message_length); + cp += message_length; + } + + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, filename->chars(), filename_length); + cp += filename_length; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; + } + } if (lineno_as_str) { /* append lineno as ``, {lineno_as_str}'' */ - length += 2 + lineno_length; + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, lineno_as_str->chars(), lineno_length); + cp += lineno_length; } - } else { - if (lineno_as_str) { - /* - * no filename, but have line number, - * need to append ``, "", {lineno_as_str}'' - */ - length += 6 + lineno_length; + + *cp++ = ')'; *cp++ = ')'; *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + cx->free(chars); + return false; } + *vp = STRING_TO_JSVAL(result); + return true; } - - cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); - if (!chars) { - ok = JS_FALSE; - goto out; - } - - *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; - js_strncpy(cp, name->chars(), name_length); - cp += name_length; - *cp++ = '('; - if (message_length != 0) { - js_strncpy(cp, message->chars(), message_length); - cp += message_length; - } - - if (filename_length != 0) { - /* append filename as ``, {filename}'' */ - *cp++ = ','; *cp++ = ' '; - js_strncpy(cp, filename->chars(), filename_length); - cp += filename_length; - } else { - if (lineno_as_str) { - /* - * no filename, but have line number, - * need to append ``, "", {lineno_as_str}'' - */ - *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; - } - } - if (lineno_as_str) { - /* append lineno as ``, {lineno_as_str}'' */ - *cp++ = ','; *cp++ = ' '; - js_strncpy(cp, lineno_as_str->chars(), lineno_length); - cp += lineno_length; - } - - *cp++ = ')'; *cp++ = ')'; *cp = 0; - - result = js_NewString(cx, chars, length); - if (!result) { - cx->free(chars); - ok = JS_FALSE; - goto out; - } - *vp = STRING_TO_JSVAL(result); - ok = JS_TRUE; - -out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; } #endif @@ -999,7 +989,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) return NULL; memset(roots, 0, sizeof(roots)); - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); #ifdef __GNUC__ error_proto = NULL; /* quell GCC overwarning */ @@ -1109,7 +1099,6 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, const JSErrorFormatString *errorString; JSExnType exn; jsval tv[4]; - JSTempValueRooter tvr; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; @@ -1158,7 +1147,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, /* Protect the newly-created strings below from nesting GCs. */ memset(tv, 0, sizeof tv); - JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv); /* * Try to get an appropriate prototype by looking up the corresponding @@ -1202,7 +1191,6 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, reportp->flags |= JSREPORT_EXCEPTION; out: - JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; } @@ -1213,20 +1201,18 @@ js_ReportUncaughtException(JSContext *cx) jsval exn; JSObject *exnObject; jsval roots[5]; - JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; - JSBool ok; if (!JS_IsExceptionPending(cx)) - return JS_TRUE; + return true; if (!JS_GetPendingException(cx, &exn)) - return JS_FALSE; + return false; memset(roots, 0, sizeof roots); - JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); /* * Because js_ValueToString below could error and an exception object @@ -1251,51 +1237,36 @@ js_ReportUncaughtException(JSContext *cx) } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); - if (!bytes) { - ok = JS_FALSE; - goto out; - } + if (!bytes) + return false; } - ok = JS_TRUE; - if (!reportp && - exnObject && - OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { + if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; - ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); - if (!ok) - goto out; + if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) + return false; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); - if (!bytes) { - ok = JS_FALSE; - goto out; - } + if (!bytes) + return false; } - ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); - if (!ok) - goto out; + if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) + return false; str = js_ValueToString(cx, roots[3]); - if (!str) { - ok = JS_FALSE; - goto out; - } + if (!str) + return false; filename = StringToFilename(cx, str); - if (!filename) { - ok = JS_FALSE; - goto out; - } + if (!filename) + return false; - ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); - if (!ok) - goto out; + if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) + return false; lineno = js_ValueToECMAUint32 (cx, &roots[4]); - ok = !JSVAL_IS_NULL(roots[4]); - if (!ok) - goto out; + if (JSVAL_IS_NULL(roots[4])) + return false; reportp = &report; memset(&report, 0, sizeof report); @@ -1316,7 +1287,5 @@ js_ReportUncaughtException(JSContext *cx) JS_ClearPendingException(cx); } -out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; + return true; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index d4c0cefc077c..ccd61484a105 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -351,7 +351,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio funobj, scopeChain); if (!wfunobj) return NULL; - JSAutoTempValueRooter tvr(cx, wfunobj); + AutoValueRooter tvr(cx, wfunobj); JSFunction *wfun = (JSFunction *) wfunobj; wfunobj->setPrivate(wfun); @@ -599,7 +599,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) if (!JS_ValueToId(cx, idval, &id)) return false; - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); return js_DeleteProperty(cx, obj, id, tvr.addr()) && js_SetProperty(cx, obj, id, vp); } @@ -1584,8 +1584,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) uintN nargs, nvars, nupvars, n; uint32 localsword; /* word for argument and variable counts */ uint32 flagsword; /* word for fun->u.i.nupvars and fun->flags */ - JSTempValueRooter tvr; - JSBool ok; cx = xdr->cx; if (xdr->mode == JSXDR_ENCODE) { @@ -1594,13 +1592,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, JS_GetFunctionName(fun)); - return JS_FALSE; + return false; } if (fun->u.i.wrapper) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, JS_GetFunctionName(fun)); - return JS_FALSE; + return false; } JS_ASSERT((fun->u.i.wrapper & ~1U) == 0); firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom; @@ -1612,7 +1610,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } else { fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); if (!fun) - return JS_FALSE; + return false; FUN_OBJECT(fun)->clearParent(); FUN_OBJECT(fun)->clearProto(); #ifdef __GNUC__ @@ -1620,18 +1618,15 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) #endif } - /* From here on, control flow must flow through label out. */ - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); - ok = JS_TRUE; + AutoValueRooter tvr(cx, FUN_OBJECT(fun)); if (!JS_XDRUint32(xdr, &firstword)) - goto bad; + return false; if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom)) - goto bad; + return false; if (!JS_XDRUint32(xdr, &localsword) || !JS_XDRUint32(xdr, &flagsword)) { - goto bad; + return false; } if (xdr->mode == JSXDR_DECODE) { @@ -1655,6 +1650,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JSAtom *name; JSLocalKind localKind; + bool ok = true; mark = JS_ARENA_MARK(&xdr->cx->tempPool); /* @@ -1673,13 +1669,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) bitmapLength * sizeof *bitmap); if (!bitmap) { js_ReportOutOfScriptQuota(xdr->cx); - ok = JS_FALSE; + ok = false; goto release_mark; } if (xdr->mode == JSXDR_ENCODE) { names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool); if (!names) { - ok = JS_FALSE; + ok = false; goto release_mark; } memset(bitmap, 0, bitmapLength * sizeof *bitmap); @@ -1734,19 +1730,18 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) goto release_mark; } } - ok = JS_TRUE; release_mark: JS_ARENA_RELEASE(&xdr->cx->tempPool, mark); if (!ok) - goto out; + return false; if (xdr->mode == JSXDR_DECODE) js_FreezeLocalNames(cx, fun); } if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL)) - goto bad; + return false; if (xdr->mode == JSXDR_DECODE) { *objp = FUN_OBJECT(fun); @@ -1758,13 +1753,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } } -out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; - -bad: - ok = JS_FALSE; - goto out; + return true; } #else /* !JS_HAS_XDR */ @@ -2681,26 +2670,26 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) JSStackFrame *fp; uintN error; const char *name, *source; - JSTempValueRooter tvr; for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down) continue; name = source = NULL; - JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr); + + AutoValueRooter tvr(cx); if (flags & JSV2F_ITERATOR) { error = JSMSG_BAD_ITERATOR; name = js_iterator_str; JSString *src = js_ValueToSource(cx, *vp); if (!src) - goto out; - tvr.u.value = STRING_TO_JSVAL(src); + return; + tvr.setString(src); JSString *qsrc = js_QuoteString(cx, src, 0); if (!qsrc) - goto out; - tvr.u.value = STRING_TO_JSVAL(qsrc); + return; + tvr.setString(qsrc); source = js_GetStringBytes(cx, qsrc); if (!source) - goto out; + return; } else if (flags & JSV2F_CONSTRUCT) { error = JSMSG_NOT_CONSTRUCTOR; } else { @@ -2716,9 +2705,6 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) : JSDVG_IGNORE_STACK, *vp, NULL, name, source); - - out: - JS_POP_TEMP_ROOT(cx, &tvr); } /* diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 422260b931fe..f604570d8d4e 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -87,6 +87,7 @@ #include "jsdtracef.h" #endif +#include "jscntxtinlines.h" #include "jsobjinlines.h" /* @@ -109,14 +110,6 @@ using namespace js; -/* - * Check JSTempValueUnion has the size of jsval and void * so we can - * reinterpret jsval as void* GC-thing pointer and use JSTVU_SINGLE for - * different GC-things. - */ -JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval)); -JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *)); - /* * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and * JSTRACE_STRING. @@ -2259,19 +2252,20 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, return JS_DHASH_NEXT; } -#define TRACE_JSVALS(trc, len, vec, name) \ - JS_BEGIN_MACRO \ - jsval _v, *_vp, *_end; \ - \ - for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \ - _v = *_vp; \ - if (JSVAL_IS_TRACEABLE(_v)) { \ - JS_SET_TRACING_INDEX(trc, name, _vp - (vec)); \ - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(_v), \ - JSVAL_TRACE_KIND(_v)); \ - } \ - } \ - JS_END_MACRO +namespace js { + +void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) +{ + for (uint32 i = 0; i < len; i++) { + if (JSObject *obj = vec[i]) { + JS_SET_TRACING_INDEX(trc, "vector", i); + js_CallGCMarker(trc, obj, JSTRACE_OBJECT); + } + } +} + +} void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) @@ -2297,7 +2291,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) } else { nslots = fp->script->nfixed; } - TRACE_JSVALS(trc, nslots, fp->slots, "slot"); + js::TraceValues(trc, nslots, fp->slots, "slot"); } } else { JS_ASSERT(!fp->slots); @@ -2322,7 +2316,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) if (fp->fun->flags & JSFRAME_ROOTED_ARGV) skip = 2 + fp->argc; } - TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); + js::TraceValues(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); } JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); @@ -2377,7 +2371,6 @@ JS_REQUIRES_STACK JS_FRIEND_API(void) js_TraceContext(JSTracer *trc, JSContext *acx) { JSStackHeader *sh; - JSTempValueRooter *tvr; /* * Trace active and suspended callstacks. @@ -2427,38 +2420,11 @@ js_TraceContext(JSTracer *trc, JSContext *acx) for (sh = acx->stackHeaders; sh; sh = sh->down) { METER(trc->context->runtime->gcStats.stackseg++); METER(trc->context->runtime->gcStats.segslots += sh->nslots); - TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); + js::TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); } - for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { - switch (tvr->count) { - case JSTVU_SINGLE: - JS_SET_TRACING_NAME(trc, "tvr->u.value"); - js_CallValueTracerIfGCThing(trc, tvr->u.value); - break; - case JSTVU_TRACE: - tvr->u.trace(trc, tvr); - break; - case JSTVU_SPROP: - tvr->u.sprop->trace(trc); - break; - case JSTVU_WEAK_ROOTS: - tvr->u.weakRoots->mark(trc); - break; - case JSTVU_COMPILER: - tvr->u.compiler->trace(trc); - break; - case JSTVU_SCRIPT: - js_TraceScript(trc, tvr->u.script); - break; - case JSTVU_ENUMERATOR: - static_cast(tvr)->mark(trc); - break; - default: - JS_ASSERT(tvr->count >= 0); - TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array"); - } - } + for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) + gcr->trace(trc); if (acx->sharpObjectMap.depth > 0) js_TraceSharpMap(trc, &acx->sharpObjectMap); @@ -2469,7 +2435,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) InterpState* state = acx->interpState; while (state) { if (state->nativeVp) - TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); + js::TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); state = state->prev; } #endif @@ -3365,33 +3331,30 @@ out: * interlock mechanism here. */ if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) { - JSWeakRoots savedWeakRoots; - JSTempValueRooter tvr; + if (!(gckind & GC_KEEP_ATOMS)) { + (void) callback(cx, JSGC_END); - if (gckind & GC_KEEP_ATOMS) { + /* + * On shutdown iterate until JSGC_END callback stops creating + * garbage. + */ + if (gckind == GC_LAST_CONTEXT && rt->gcPoke) + goto restart_at_beginning; + } else { /* * We allow JSGC_END implementation to force a full GC or allocate * new GC things. Thus we must protect the weak roots from garbage * collection and overwrites. */ - savedWeakRoots = cx->weakRoots; - JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr); + AutoSaveWeakRoots save(cx); + JS_KEEP_ATOMS(rt); JS_UNLOCK_GC(rt); - } - (void) callback(cx, JSGC_END); + (void) callback(cx, JSGC_END); - if (gckind & GC_KEEP_ATOMS) { JS_LOCK_GC(rt); JS_UNKEEP_ATOMS(rt); - JS_POP_TEMP_ROOT(cx, &tvr); - } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) { - /* - * On shutdown iterate until JSGC_END callback stops creating - * garbage. - */ - goto restart_at_beginning; } } } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 058dafdb49cd..dbf645feeb29 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -454,4 +454,23 @@ js_MarkTraps(JSTracer *trc); JS_END_EXTERN_C +namespace js { + +void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len); + +inline void +TraceValues(JSTracer *trc, size_t len, jsval *vec, const char *name) +{ + for (jsval *vp = vec, *end = vp + len; vp < end; vp++) { + jsval v = *vp; + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_INDEX(trc, name, vp - vec); + js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + } + } +} + +} + #endif /* jsgc_h___ */ diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 19115c6b2a09..72cc90bf21d6 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -800,7 +800,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp); if (!innermostNewChild) return NULL; - JSAutoTempValueRooter tvr(cx, innermostNewChild); + AutoValueRooter tvr(cx, innermostNewChild); /* * Clone our way towards outer scopes until we reach the innermost @@ -1005,7 +1005,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[1]); jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) return false; if (JSVAL_IS_PRIMITIVE(tvr.value())) { diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index eaa3c872cd6e..619f895274ad 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -215,18 +215,11 @@ Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) static JSBool NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) { - jsval vec[2]; - JSTempValueRooter tvr; - JSObject *aobj; + jsval vec[2] = { ID_TO_VALUE(key), val }; + AutoArrayRooter tvr(cx, 2, vec); - vec[0] = ID_TO_VALUE(key); - vec[1] = val; - - JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); - aobj = js_NewArrayObject(cx, 2, vec); + JSObject *aobj = js_NewArrayObject(cx, 2, vec); *rval = OBJECT_TO_JSVAL(aobj); - JS_POP_TEMP_ROOT(cx, &tvr); - return aobj != NULL; } @@ -347,21 +340,19 @@ JS_FRIEND_API(JSBool) js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) { JSObject *obj; - JSTempValueRooter tvr; JSAtom *atom; JSClass *clasp; JSExtendedClass *xclasp; - JSBool ok; JSObject *iterobj; jsval arg; - JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | - JSITER_FOREACH | - JSITER_KEYVALUE))); + JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE))); /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); + AutoValueRooter tvr(cx); + /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(*vp)) { obj = JSVAL_TO_OBJECT(*vp); @@ -374,30 +365,29 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ if ((flags & JSITER_ENUMERATE)) { if (!js_ValueToObject(cx, *vp, &obj)) - return JS_FALSE; + return false; if (!obj) goto default_iter; } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) - return JS_FALSE; + return false; } } - JS_ASSERT(obj); - JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + tvr.setObject(obj); clasp = OBJ_GET_CLASS(cx, obj); if ((clasp->flags & JSCLASS_IS_EXTENDED) && (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) - goto bad; + return false; *vp = OBJECT_TO_JSVAL(iterobj); } else { atom = cx->runtime->atomState.iteratorAtom; if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp)) - goto bad; + return false; if (JSVAL_IS_VOID(*vp)) { default_iter: /* @@ -410,36 +400,29 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL); if (!iterobj) - goto bad; + return false; /* Store in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); if (!InitNativeIterator(cx, iterobj, obj, flags)) - goto bad; + return false; } else { LeaveTrace(cx); arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, vp)) { - goto bad; + return false; } if (JSVAL_IS_PRIMITIVE(*vp)) { js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN, JSDVG_SEARCH_STACK, *vp, NULL); - goto bad; + return false; } } } - ok = JS_TRUE; - out: - if (obj) - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; - bad: - ok = JS_FALSE; - goto out; + return true; } JS_FRIEND_API(JSBool) JS_FASTCALL diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 91e69fd3cfe4..119a0705c7bb 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -989,11 +989,11 @@ js_ValueToNumber(JSContext *cx, jsval *vp) * vp roots obj so we cannot use it as an extra root for * obj->defaultValue result when calling the hook. */ - JSAutoTempValueRooter tvr(cx, v); - if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr())) + AutoValueRooter gcr(cx, v); + if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr())) obj = NULL; else - v = *vp = tvr.value(); + v = *vp = gcr.value(); if (!obj) { *vp = JSVAL_NULL; return 0.0; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 498c6357e26a..c9b766820f26 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -245,32 +245,24 @@ obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp) static JSBool obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - jsval iter_state; jsid num_properties; - JSBool ok; if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT)) - return JS_FALSE; - - iter_state = JSVAL_NULL; - JSAutoEnumStateRooter tvr(cx, obj, &iter_state); + return false; /* Get the number of properties to enumerate. */ - ok = obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties); - if (!ok) - goto out; + AutoEnumStateRooter iterState(cx, obj); + if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) + return false; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); *vp = JSVAL_ZERO; - goto out; + return true; } *vp = num_properties; -out: - if (!JSVAL_IS_NULL(iter_state)) - ok &= obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); - return ok; + return true; } #else /* !JS_HAS_OBJ_PROTO_PROP */ @@ -664,15 +656,13 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) #endif jsval *val; jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; - JSTempValueRooter tvr; JSString *gsopold[2]; JSString *gsop[2]; JSString *idstr, *valstr, *str; JS_CHECK_RECURSION(cx, return JS_FALSE); - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot); /* If outermost, we need parentheses to be an expression, not a block. */ outermost = (cx->sharpObjectMap.depth == 0); @@ -1037,7 +1027,6 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) *vp = STRING_TO_JSVAL(str); ok = JS_TRUE; out: - JS_POP_TEMP_ROOT(cx, &tvr); return ok; overflow: @@ -1966,7 +1955,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[2]); - JSAutoTempIdRooter nameidr(cx); + AutoIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; @@ -1986,7 +1975,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) } jsval roots[] = { JSVAL_VOID, JSVAL_VOID }; - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (OBJ_IS_NATIVE(obj)) { JSScopeProperty *sprop = reinterpret_cast(prop); @@ -2047,7 +2036,7 @@ obj_keys(JSContext *cx, uintN argc, jsval *vp) } JSObject *obj = JSVAL_TO_OBJECT(v); - JSAutoIdArray ida(cx, JS_Enumerate(cx, obj)); + AutoIdArray ida(cx, JS_Enumerate(cx, obj)); if (!ida) return JS_FALSE; @@ -2212,50 +2201,6 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) return true; } -typedef js::Vector PropertyDescriptorArray; - -class AutoDescriptorArray : private JSTempValueRooter -{ - private: - JSContext *cx; - PropertyDescriptorArray descriptors; - - public: - AutoDescriptorArray(JSContext *cx) - : cx(cx), descriptors(cx) - { - JS_PUSH_TEMP_ROOT_TRACE(cx, trace, this); - } - ~AutoDescriptorArray() { - JS_POP_TEMP_ROOT(cx, this); - } - - PropertyDescriptor *append() { - if (!descriptors.append(PropertyDescriptor())) - return NULL; - return &descriptors.back(); - } - - PropertyDescriptor& operator[](size_t i) { - JS_ASSERT(i < descriptors.length()); - return descriptors[i]; - } - - private: - static void trace(JSTracer *trc, JSTempValueRooter *tvr) { - PropertyDescriptorArray &descs = - static_cast(tvr)->descriptors; - for (size_t i = 0, len = descs.length(); i < len; i++) { - PropertyDescriptor &desc = descs[i]; - - JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); - JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); - JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); - js_TraceId(trc, desc.id); - } - } -}; - static JSBool Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval) { @@ -2639,7 +2584,7 @@ obj_defineProperty(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(*vp); /* 15.2.3.6 step 2. */ - JSAutoTempIdRooter nameidr(cx); + AutoIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; @@ -2676,7 +2621,7 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; vp[3] = OBJECT_TO_JSVAL(props); - JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); + AutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2740,7 +2685,7 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) } JSObject *props = JSVAL_TO_OBJECT(vp[3]); - JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); + AutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2938,7 +2883,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, * builtin. See bug 481444. */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); JS_KEEP_ATOMS(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); @@ -3614,7 +3559,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) obj->setParent(parent); } - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); if (!JS_XDRUint32(xdr, &tmp)) return false; @@ -3707,7 +3652,6 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSAtom *atom; JSProtoKey key; JSObject *proto, *ctor; - JSTempValueRooter tvr; jsval cval, rval; JSBool named; JSFunction *fun; @@ -3743,7 +3687,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, return NULL; /* After this point, control must exit via label bad or out. */ - JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr); + AutoValueRooter tvr(cx, proto); if (!constructor) { /* @@ -3833,7 +3777,6 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, goto bad; out: - JS_POP_TEMP_ROOT(cx, &tvr); return proto; bad: @@ -4141,7 +4084,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, jsval cval, rval; JSObject *obj, *ctor; - JSAutoTempValueRooter argtvr(cx, argc, argv); + AutoArrayRooter argtvr(cx, argc, argv); JSProtoKey protoKey = GetClassProtoKey(clasp); if (!js_FindClassObject(cx, parent, protoKey, &cval, clasp)) @@ -4153,7 +4096,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, } /* Protect cval in case a crazy getter for .prototype uproots it. */ - JSAutoTempValueRooter tvr(cx, cval); + AutoValueRooter tvr(cx, cval); /* * If proto or parent are NULL, set them to Constructor.prototype and/or @@ -4953,8 +4896,6 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, JSScope *scope; uint32 slot; int32 sample; - JSTempValueRooter tvr, tvr2; - JSBool ok; JS_ASSERT(OBJ_IS_NATIVE(pobj)); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj)); @@ -4974,15 +4915,14 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); - JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); - JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2); - ok = sprop->get(cx, obj, pobj, vp); - JS_POP_TEMP_ROOT(cx, &tvr2); - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - return false; - + { + AutoScopePropertyRooter tvr(cx, sprop); + AutoValueRooter tvr2(cx, pobj); + if (!sprop->get(cx, obj, pobj, vp)) + return false; + } JS_LOCK_SCOPE(cx, scope); + if (SLOT_IN_SCOPE(slot, scope) && (JS_LIKELY(cx->runtime->propertyRemovals == sample) || scope->hasProperty(sprop))) { @@ -5006,8 +4946,6 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, JSScope *scope; uint32 slot; int32 sample; - JSTempValueRooter tvr; - JSBool ok; JS_ASSERT(OBJ_IS_NATIVE(obj)); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj)); @@ -5039,11 +4977,11 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); - JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); - ok = sprop->set(cx, obj, vp); - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - return false; + { + AutoScopePropertyRooter tvr(cx, sprop); + if (!sprop->set(cx, obj, vp)) + return false; + } JS_LOCK_SCOPE(cx, scope); if (SLOT_IN_SCOPE(slot, scope) && diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 512cbaef7e56..00223a9408e4 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -52,12 +52,14 @@ #include "jspubtd.h" #include "jsprvtd.h" +namespace js { class AutoDescriptorArray; } + /* * A representation of ECMA-262 ed. 5's internal property descriptor data * structure. */ struct PropertyDescriptor { - friend class AutoDescriptorArray; + friend class js::AutoDescriptorArray; private: PropertyDescriptor(); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 376bca893339..b8a21d864a3e 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -83,4 +83,34 @@ JSObject::unbrand(JSContext *cx) return true; } +namespace js { + +typedef Vector PropertyDescriptorArray; + +class AutoDescriptorArray : private AutoGCRooter +{ + public: + AutoDescriptorArray(JSContext *cx) + : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) + { } + + PropertyDescriptor *append() { + if (!descriptors.append(PropertyDescriptor())) + return NULL; + return &descriptors.back(); + } + + PropertyDescriptor& operator[](size_t i) { + JS_ASSERT(i < descriptors.length()); + return descriptors[i]; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + PropertyDescriptorArray descriptors; +}; + +} + #endif /* jsobjinlines_h___ */ diff --git a/js/src/json.cpp b/js/src/json.cpp index af0c1bfd9dfc..44897ba6d41c 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -65,6 +65,8 @@ #include "jsatominlines.h" +using namespace js; + #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4351) @@ -106,10 +108,9 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) { JSString *s = NULL; jsval *argv = vp + 2; - jsval reviver = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &reviver); + AutoValueRooter reviver(cx, JSVAL_NULL); - if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver)) + if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr())) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); @@ -119,7 +120,7 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); - ok &= js_FinishJSONParse(cx, jp, reviver); + ok &= js_FinishJSONParse(cx, jp, reviver.value()); } return ok; @@ -129,18 +130,16 @@ JSBool js_json_stringify(JSContext *cx, uintN argc, jsval *vp) { jsval *argv = vp + 2; - JSObject *replacer = NULL; - jsval space = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, replacer); - JSAutoTempValueRooter tvr2(cx, 1, &space); + AutoValueRooter space(cx, JSVAL_NULL); + AutoObjectRooter replacer(cx); // Must throw an Error if there isn't a first arg - if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, &replacer, &space)) + if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr())) return JS_FALSE; JSCharBuffer cb(cx); - if (!js_Stringify(cx, vp, replacer, space, cb)) + if (!js_Stringify(cx, vp, replacer.object(), space.value(), cb)) return JS_FALSE; // XXX This can never happen to nsJSON.cpp, but the JSON object @@ -258,7 +257,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) return JS_FALSE; jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; - JSAutoTempValueRooter tvr(cx, 3, vec); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); jsval& key = vec[0]; jsval& outputValue = vec[1]; @@ -307,7 +306,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) if (!ks) goto error_break; } - JSAutoTempValueRooter keyStringRoot(cx, ks); + AutoValueRooter keyStringRoot(cx, ks); // Don't include prototype properties, since this operation is // supposed to be implemented as if by ES3.1 Object.keys() @@ -393,21 +392,20 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; - jsval outputValue = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &outputValue); + AutoValueRooter outputValue(cx, JSVAL_NULL); jsid id; jsuint i; for (i = 0; i < length; i++) { id = INT_TO_JSID(i); - if (!obj->getProperty(cx, id, &outputValue)) + if (!obj->getProperty(cx, id, outputValue.addr())) return JS_FALSE; - if (!Str(cx, id, obj, scx, &outputValue)) + if (!Str(cx, id, obj, scx, outputValue.addr())) return JS_FALSE; - if (outputValue == JSVAL_VOID) { + if (outputValue.value() == JSVAL_VOID) { if (!js_AppendLiteral(scx->cb, "null")) return JS_FALSE; } @@ -570,63 +568,54 @@ static JSBool IsNumChar(jschar c) static JSBool HandleData(JSContext *cx, JSONParser *jp, JSONDataType type); static JSBool PopState(JSContext *cx, JSONParser *jp); -static JSBool -DestroyIdArrayOnError(JSContext *cx, JSIdArray *ida) { - JS_DestroyIdArray(cx, ida); - return JS_FALSE; -} - -static JSBool +static bool Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) { - JS_CHECK_RECURSION(cx, return JS_FALSE); + JS_CHECK_RECURSION(cx, return false); if (!holder->getProperty(cx, id, vp)) - return JS_FALSE; + return false; JSObject *obj; if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) { - jsval propValue = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &propValue); + AutoValueRooter propValue(cx, JSVAL_NULL); if(obj->isArray()) { jsuint length = 0; if (!js_GetLengthProperty(cx, obj, &length)) - return JS_FALSE; + return false; for (jsuint i = 0; i < length; i++) { jsid index; if (!js_IndexToId(cx, i, &index)) - return JS_FALSE; + return false; - if (!Walk(cx, index, obj, reviver, &propValue)) - return JS_FALSE; + if (!Walk(cx, index, obj, reviver, propValue.addr())) + return false; - if (!obj->defineProperty(cx, index, propValue, NULL, NULL, JSPROP_ENUMERATE)) - return JS_FALSE; + if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE)) + return false; } } else { - JSIdArray *ida = JS_Enumerate(cx, obj); + AutoIdArray ida(cx, JS_Enumerate(cx, obj)); if (!ida) - return JS_FALSE; + return false; - JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)ida); - - for(jsint i = 0; i < ida->length; i++) { - jsid idName = ida->vector[i]; - if (!Walk(cx, idName, obj, reviver, &propValue)) - return DestroyIdArrayOnError(cx, ida); - if (propValue == JSVAL_VOID) { - if (!js_DeleteProperty(cx, obj, idName, &propValue)) - return DestroyIdArrayOnError(cx, ida); + for (jsint i = 0, len = ida.length(); i < len; i++) { + jsid idName = ida[i]; + if (!Walk(cx, idName, obj, reviver, propValue.addr())) + return false; + if (propValue.value() == JSVAL_VOID) { + if (!js_DeleteProperty(cx, obj, idName, propValue.addr())) + return false; } else { - if (!obj->defineProperty(cx, idName, propValue, NULL, NULL, JSPROP_ENUMERATE)) - return DestroyIdArrayOnError(cx, ida); + if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL, + JSPROP_ENUMERATE)) { + return false; + } } } - - JS_DestroyIdArray(cx, ida); } } @@ -634,31 +623,29 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) jsval value = *vp; JSString *key = js_ValueToString(cx, ID_TO_VALUE(id)); if (!key) - return JS_FALSE; + return false; jsval vec[2] = {STRING_TO_JSVAL(key), value}; jsval reviverResult; if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult)) - return JS_FALSE; + return false; *vp = reviverResult; - - return JS_TRUE; + return true; } -static JSBool +static bool Revive(JSContext *cx, jsval reviver, jsval *vp) { JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL); if (!obj) - return JS_FALSE; + return false; - jsval v = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter tvr(cx, 1, &v); + AutoValueRooter tvr(cx, obj); if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), *vp, NULL, NULL, JSPROP_ENUMERATE)) { - return JS_FALSE; + return false; } return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp); @@ -693,11 +680,11 @@ bad: return NULL; } -JSBool +bool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) { if (!jp) - return JS_TRUE; + return true; JSBool early_ok = JS_TRUE; @@ -718,20 +705,20 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) /* This internal API is infallible, in spite of its JSBool return type. */ js_RemoveRoot(cx->runtime, &jp->objectStack); - JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; + bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; jsval *vp = jp->rootVal; cx->destroy(jp); if (!early_ok) - return JS_FALSE; + return false; if (!ok) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); - return JS_FALSE; + return false; } - if (!JSVAL_IS_PRIMITIVE(reviver) && js_IsCallable(reviver)) + if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable()) ok = Revive(cx, reviver, vp); return ok; @@ -809,7 +796,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) } jsval v = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); // Check if this is the root object if (len == 0) { @@ -882,7 +869,7 @@ CloseArray(JSContext *cx, JSONParser *jp) static JSBool PushPrimitive(JSContext *cx, JSONParser *jp, jsval value) { - JSAutoTempValueRooter tvr(cx, 1, &value); + AutoValueRooter tvr(cx, value); jsuint len; if (!js_GetLengthProperty(cx, jp->objectStack, &len)) diff --git a/js/src/json.h b/js/src/json.h index 84f392419d90..e384863e1604 100644 --- a/js/src/json.h +++ b/js/src/json.h @@ -89,7 +89,7 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal); extern JSBool js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); -extern JSBool +extern bool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver); JS_END_EXTERN_C diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 9fa44d4d1a3a..ce2a168e3aa5 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -79,6 +79,8 @@ #include "jsautooplen.h" +using namespace js; + /* * Index limit must stay within 32 bits. */ @@ -307,7 +309,7 @@ ToDisassemblySource(JSContext *cx, jsval v) } if (clasp == &js_RegExpClass) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (!js_regexp_toString(cx, obj, tvr.addr())) return NULL; return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value())); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 391d4b67ae41..4f279295dad4 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -88,6 +88,8 @@ #include "jsdhash.h" #endif +using namespace js; + /* * Asserts to verify assumptions behind pn_ macros. */ @@ -222,7 +224,6 @@ JSCompiler::init(const jschar *base, size_t length, /* Root atoms and objects allocated for the parsed tree. */ JS_KEEP_ATOMS(cx->runtime); - JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot); return true; } @@ -232,8 +233,6 @@ JSCompiler::~JSCompiler() if (principals) JSPRINCIPALS_DROP(cx, principals); - JS_ASSERT(tempRoot.u.compiler == this); - JS_POP_TEMP_ROOT(cx, &tempRoot); JS_UNKEEP_ATOMS(cx->runtime); tokenStream.close(cx); JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); @@ -338,10 +337,7 @@ JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const void JSCompiler::trace(JSTracer *trc) { - JSObjectBox *objbox; - - JS_ASSERT(tempRoot.u.compiler == this); - objbox = traceListHead; + JSObjectBox *objbox = traceListHead; while (objbox) { JS_CALL_OBJECT_TRACER(trc, objbox->object, "parser.object"); objbox = objbox->traceLink; @@ -8830,7 +8826,6 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; - JSTempValueRooter tvr; JS_ASSERT(pn->pn_arity == PN_LIST); tt = PN_TYPE(pn); @@ -8921,11 +8916,12 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) } if (accum) { - JS_PUSH_TEMP_ROOT_STRING(cx, accum, &tvr); - str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) - ? js_AddAttributePart(cx, i & 1, accum, str) - : js_ConcatStrings(cx, accum, str); - JS_POP_TEMP_ROOT(cx, &tvr); + { + AutoValueRooter tvr(cx, accum); + str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) + ? js_AddAttributePart(cx, i & 1, accum, str) + : js_ConcatStrings(cx, accum, str); + } if (!str) return JS_FALSE; #ifdef DEBUG_brendanXXX diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 704583192761..04b15ff675dd 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -832,8 +832,10 @@ struct JSFunctionBoxQueue { #define NUM_TEMP_FREELISTS 6U /* 32 to 2048 byte size classes (32 bit) */ -struct JSCompiler { - JSContext *context; +class JSTreeContext; + +struct JSCompiler : private js::AutoGCRooter { + JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; JSTokenStream tokenStream; @@ -843,10 +845,10 @@ struct JSCompiler { JSParseNode *nodeList; /* list of recyclable parse-node structs */ uint32 functionCount; /* number of functions in current unit */ JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ - JSTempValueRooter tempRoot; /* root to trace traceListHead */ JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) - : context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL), + : js::AutoGCRooter(cx, COMPILER), context(cx), + aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL) { memset(tempFreeList, 0, sizeof tempFreeList); @@ -856,6 +858,9 @@ struct JSCompiler { ~JSCompiler(); + friend void js::AutoGCRooter::trace(JSTracer *trc); + friend class JSTreeContext; + /* * Initialize a compiler. Parameters are passed on to init tokenStream. * The compiler owns the arena pool "tops-of-stack" space above the current diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index cd78b67bb7a1..664a80206a94 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -281,31 +281,6 @@ typedef struct JSDebugHooks { void *debugErrorHookData; } JSDebugHooks; -/* - * Type definitions for temporary GC roots that register with GC local C - * variables. See jscntxt.h for details. - */ -typedef void -(* JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr); - -typedef union JSTempValueUnion { - jsval value; - JSObject *object; - JSXML *xml; - JSTempValueTrace trace; - JSScopeProperty *sprop; - JSWeakRoots *weakRoots; - JSCompiler *compiler; - JSScript *script; - jsval *array; -} JSTempValueUnion; - -struct JSTempValueRooter { - JSTempValueRooter *down; - ptrdiff_t count; - JSTempValueUnion u; -}; - /* JSObjectOps function pointer typedefs. */ /* diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 6642ae5a558a..e02ce42cf838 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5232,10 +5232,10 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr) + AutoValueRooter *tvr) { *statics = cx->regExpStatics; - JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr); + tvr->setString(statics->input); /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). @@ -5246,12 +5246,11 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr) + AutoValueRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ JS_ClearRegExpStatics(cx); cx->regExpStatics = *statics; - JS_POP_TEMP_ROOT(cx, tvr); } void @@ -5844,7 +5843,7 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - JSAutoTempValueRooter tvr(cx, str); + AutoValueRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index cc30304ac466..af08f9843dec 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -65,13 +65,15 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; +namespace js { class AutoValueRooter; } + extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr); + js::AutoValueRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr); + js::AutoValueRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 01aa5877adf9..4e38b4434c51 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -94,7 +94,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, uint32 length, lineno, nslots, magic; uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i; uint32 prologLength, version; - JSTempValueRooter tvr; JSPrincipals *principals; uint32 encodeable; JSBool filenameWasSaved; @@ -212,6 +211,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, if (!JS_XDRUint32(xdr, &nregexps)) return JS_FALSE; + AutoScriptRooter tvr(cx, NULL); + if (xdr->mode == JSXDR_DECODE) { script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, nregexps, ntrynotes); @@ -225,7 +226,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, /* If we know nsrcnotes, we allocated space for notes in script. */ notes = script->notes(); *scriptp = script; - JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); + tvr.setScript(script); } /* @@ -368,13 +369,10 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, } xdr->script = oldscript; - if (xdr->mode == JSXDR_DECODE) - JS_POP_TEMP_ROOT(cx, &tvr); return JS_TRUE; error: if (xdr->mode == JSXDR_DECODE) { - JS_POP_TEMP_ROOT(cx, &tvr); if (script->filename && !filenameWasSaved) { cx->free((void *) script->filename); script->filename = NULL; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index ca9893f3960a..28f763c84969 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1603,7 +1603,7 @@ str_match(JSContext *cx, uintN argc, jsval *vp) if (!g.normalizeRegExp(false, 1, argc, vp)) return false; - JSAutoTempValueRooter array(cx, JSVAL_NULL); + AutoValueRooter array(cx, JSVAL_NULL); if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS)) return false; @@ -3384,7 +3384,7 @@ js_ValueToSource(JSContext *cx, jsval v) } JSAtom *atom = cx->runtime->atomState.toSourceAtom; - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), atom, 0, NULL, tvr.addr())) return NULL; return js_ValueToString(cx, tvr.value()); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 6c137c4966d7..e39d20c38948 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8814,13 +8814,12 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) } } { - jsval tmp = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &tmp); + AutoValueRooter tvr(cx); - tmp = l; - lnum = js_ValueToNumber(cx, &tmp); - tmp = r; - rnum = js_ValueToNumber(cx, &tmp); + *tvr.addr() = l; + lnum = js_ValueToNumber(cx, tvr.addr()); + *tvr.addr() = r; + rnum = js_ValueToNumber(cx, tvr.addr()); } cond = EvalCmp(op, lnum, rnum); fp = true; @@ -11210,7 +11209,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, static JSBool FASTCALL MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - JSAutoTempValueRooter tvr(cx, funobj); + AutoValueRooter tvr(cx, funobj); return OBJ_SCOPE(obj)->methodWriteBarrier(cx, sprop, tvr.value()); } @@ -11574,7 +11573,7 @@ GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11913,7 +11912,7 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11928,7 +11927,7 @@ InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval val) { LeaveTraceIfGlobalObject(cx, obj); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(cx); @@ -12747,7 +12746,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) static JSObject* FASTCALL MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - JSAutoTempValueRooter tvr(cx, funobj); + AutoValueRooter tvr(cx, funobj); if (!OBJ_SCOPE(obj)->methodReadBarrier(cx, sprop, tvr.addr())) return NULL; @@ -14868,7 +14867,7 @@ CallIteratorNext(JSContext *cx, uintN argc, jsval *vp) static jsval FASTCALL CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr()); if (!ok) { diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 0f5a8930e3e9..e2959ef3e652 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1320,10 +1320,10 @@ js_IsTypedArray(JSObject *obj) JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr()); - JSAutoTempValueRooter rval(cx); + AutoValueRooter rval(cx); if (!ArrayBuffer::class_constructor(cx, cx->globalObject, 1, tvr.addr(), rval.addr())) @@ -1375,7 +1375,7 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - JSAutoTempValueRooter tvr(cx, 2, vals); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); if (!js_NewNumberInRootedValue(cx, jsdouble(nelements), &vals[0])) return NULL; @@ -1392,7 +1392,7 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - JSAutoTempValueRooter tvr(cx, 2, vals); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); vals[0] = OBJECT_TO_JSVAL(arrayArg); @@ -1412,7 +1412,7 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_ASSERT(length < 0 || byteoffset >= 0); jsval vals[4]; - JSAutoTempValueRooter tvr(cx, 4, vals); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); int argc = 1; vals[0] = OBJECT_TO_JSVAL(bufArg); diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 56029438cc76..82e2f6bccd58 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -211,9 +211,9 @@ JS_END_EXTERN_C * when we have a guard object whose only purpose is its constructor and * destructor (and is never otherwise referenced), the intended use * might be: - * JSAutoTempValueRooter tvr(cx, 1, &val); + * js::AutoValueRooter tvr(cx, 1, &val); * but is is easy to accidentally write: - * JSAutoTempValueRooter(cx, 1, &val); + * js::AutoValueRooter(cx, 1, &val); * which compiles just fine, but runs the destructor well before the * intended time. * diff --git a/js/src/jsvector.h b/js/src/jsvector.h index 7c051f7005e7..bdd6ec1d813b 100644 --- a/js/src/jsvector.h +++ b/js/src/jsvector.h @@ -359,7 +359,10 @@ class Vector : AllocPolicy /* mutators */ - /* If reserve(N) succeeds, the N next appends are guaranteed to succeed. */ + /* + * If reserve(N) succeeds, additions to this vector which increase its size + * up to and including N are guaranteed to succeed. + */ bool reserve(size_t capacity); /* Destroy elements in the range [begin() + incr, end()). */ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 673b2d3abf9c..2908d205794d 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -70,10 +70,14 @@ #include "jsstaticcheck.h" #include "jsvector.h" +#include "jscntxtinlines.h" + #ifdef DEBUG #include /* for #ifdef DEBUG memset calls */ #endif +using namespace js; + /* * NOTES * - in the js shell, you must use the -x command line option, or call @@ -866,60 +870,10 @@ attr_identity(const void *a, const void *b) return qname_identity(xmla->name, xmlb->name); } -struct JSXMLArrayCursor -{ - JSXMLArray *array; - uint32 index; - JSXMLArrayCursor *next; - JSXMLArrayCursor **prevp; - void *root; - - JSXMLArrayCursor(JSXMLArray *array) - : array(array), index(0), next(array->cursors), prevp(&array->cursors), - root(NULL) - { - if (next) - next->prevp = &next; - array->cursors = this; - } - - ~JSXMLArrayCursor() { disconnect(); } - - void disconnect() { - if (!array) - return; - if (next) - next->prevp = prevp; - *prevp = next; - array = NULL; - } - - void *getNext() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index++]; - } - - void *getCurrent() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index]; - } -}; - static void XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor) { - void *root; -#ifdef DEBUG - size_t index = 0; -#endif - - for (; cursor; cursor = cursor->next) { - root = cursor->root; - JS_SET_TRACING_INDEX(trc, "cursor_root", index++); - js_CallValueTracerIfGCThing(trc, (jsval)root); - } + cursor->trace(trc); } /* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */ @@ -3848,12 +3802,10 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *kidobj, *listobj; JSObject *nameqn; jsid funid; - jsval roots[2]; - JSTempValueRooter tvr; xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) - return JS_TRUE; + return true; if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -3870,18 +3822,18 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); if (!kid) { *vp = JSVAL_VOID; - return JS_TRUE; + return true; } kidobj = js_GetXMLObject(cx, kid); if (!kidobj) - return JS_FALSE; + return false; *vp = OBJECT_TO_JSVAL(kidobj); } else { *vp = JSVAL_VOID; } } - return JS_TRUE; + return true; } /* @@ -3889,37 +3841,34 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) */ nameqn = ToXMLName(cx, id, &funid); if (!nameqn) - return JS_FALSE; + return false; if (funid) return GetXMLFunction(cx, obj, funid, vp); - roots[0] = OBJECT_TO_JSVAL(nameqn); - JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr); + jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (listobj) { - roots[1] = OBJECT_TO_JSVAL(listobj); - tvr.count++; + if (!listobj) + return false; - list = (JSXML *) listobj->getPrivate(); - if (!GetNamedProperty(cx, xml, nameqn, list)) { - listobj = NULL; - } else { - /* - * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the - * given list's [[TargetProperty]] to the property that is being - * appended. This means that any use of the internal [[Get]] - * property returns a list which, when used by e.g. [[Insert]] - * duplicates the last element matched by id. See bug 336921. - */ - list->xml_target = xml; - list->xml_targetprop = nameqn; - *vp = OBJECT_TO_JSVAL(listobj); - } - } + roots[1] = OBJECT_TO_JSVAL(listobj); - JS_POP_TEMP_ROOT(cx, &tvr); - return listobj != NULL; + list = (JSXML *) listobj->getPrivate(); + if (!GetNamedProperty(cx, xml, nameqn, list)) + return false; + + /* + * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the + * given list's [[TargetProperty]] to the property that is being + * appended. This means that any use of the internal [[Get]] + * property returns a list which, when used by e.g. [[Insert]] + * duplicates the last element matched by id. See bug 336921. + */ + list->xml_target = xml; + list->xml_targetprop = nameqn; + *vp = OBJECT_TO_JSVAL(listobj); + return true; } static JSXML * @@ -3963,8 +3912,6 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSBool ok, primitiveAssign; enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; - jsval roots[3]; - JSTempValueRooter tvr; JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; JSObject *targetprop, *nameqn, *attrqn; @@ -3993,11 +3940,13 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ok = js_EnterLocalRootScope(cx); if (!ok) return JS_FALSE; + MUST_FLOW_THROUGH("out"); + jsval roots[3]; roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); roots[ID_ROOT] = id; roots[VAL_ROOT] = *vp; - JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -4584,7 +4533,6 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } out: - JS_POP_TEMP_ROOT(cx, &tvr); js_LeaveLocalRootScope(cx); return ok; @@ -4716,38 +4664,34 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) JSObject *pobj; JSProperty *prop; JSXML *xml; - JSTempValueRooter tvr; - JSBool ok; JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass); if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) - return JS_FALSE; + return false; if (prop) { pobj->dropProperty(cx, prop); } else { xml = (JSXML *) obj->getPrivate(); if (HasSimpleContent(xml)) { + AutoObjectRooter tvr(cx); + /* * Search in String.prototype to set found whenever * GetXMLFunction returns existing function. */ - JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); - ok = js_GetClassPrototype(cx, NULL, JSProto_String, - &tvr.u.object); - JS_ASSERT(tvr.u.object); - if (ok) { - ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop); - if (ok && prop) - pobj->dropProperty(cx, prop); - } - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - return JS_FALSE; + if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + return false; + + JS_ASSERT(tvr.object()); + if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop)) + return false; + if (prop) + pobj->dropProperty(cx, prop); } } *found = (prop != NULL); - return JS_TRUE; + return true; } /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ @@ -5014,18 +4958,22 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - cursor = NULL; + *statep = JSVAL_ZERO; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; + *statep = PRIVATE_TO_JSVAL(cursor); } - *statep = PRIVATE_TO_JSVAL(cursor); if (idp) *idp = INT_TO_JSID(length); break; case JSENUMERATE_NEXT: + if (*statep == JSVAL_ZERO) { + *statep = JSVAL_NULL; + break; + } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { *idp = INT_TO_JSID(index); @@ -5035,9 +4983,11 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) - cx->destroy(cursor); + if (*statep != JSVAL_ZERO) { + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) + cx->destroy(cursor); + } *statep = JSVAL_NULL; break; } @@ -5126,7 +5076,7 @@ js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * As our callers have a bad habit of passing a pointer to an unrooted * local value as vp, we use a proper root here. */ - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr()); *vp = tvr.value(); return ok; @@ -5149,20 +5099,22 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - cursor = NULL; + *statep = JSVAL_ZERO; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; + *statep = PRIVATE_TO_JSVAL(cursor); } - *statep = PRIVATE_TO_JSVAL(cursor); - if (idp) - *idp = INT_TO_JSID(length); - if (vp) - *vp = JSVAL_VOID; + JS_ASSERT(!idp); + JS_ASSERT(!vp); break; case JSENUMERATE_NEXT: + if (*statep == JSVAL_ZERO) { + *statep = JSVAL_NULL; + break; + } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) { @@ -5181,10 +5133,12 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) { - destroy: - cx->destroy(cursor); + if (*statep != JSVAL_ZERO) { + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) { + destroy: + cx->destroy(cursor); + } } *statep = JSVAL_NULL; break; @@ -5477,7 +5431,7 @@ xml_attributes(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; name = OBJECT_TO_JSVAL(qn); - JSAutoTempValueRooter tvr(cx, name); + AutoValueRooter tvr(cx, name); return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); } @@ -5883,81 +5837,6 @@ xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } -typedef struct JSTempRootedNSArray { - JSTempValueRooter tvr; - JSXMLArray array; - jsval value; /* extra root for temporaries */ -} JSTempRootedNSArray; - -static void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) -{ - uint32 i; - JSObject *obj; - - for (i = 0; i < len; i++) { - obj = vec[i]; - if (obj) { - JS_SET_TRACING_INDEX(trc, "vector", i); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - } -} - -static void -trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr) -{ - JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr; - - TraceObjectVector(trc, - (JSObject **) tmp->array.vector, - tmp->array.length); - XMLArrayCursorTrace(trc, tmp->array.cursors); - JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value"); -} - -static void -InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) -{ - XMLArrayInit(cx, &tmp->array, 0); - tmp->value = JSVAL_NULL; - JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr); -} - -static void -FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) -{ - JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array); - JS_POP_TEMP_ROOT(cx, &tmp->tvr); - XMLArrayFinish(cx, &tmp->array); -} - -/* - * Populate a new JS array with elements of JSTempRootedNSArray.array and - * place the result into rval. rval must point to a rooted location. - */ -static JSBool -TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval) -{ - JSObject *arrayobj; - uint32 i, n; - JSObject *ns; - - arrayobj = js_NewArrayObject(cx, 0, NULL); - if (!arrayobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(arrayobj); - for (i = 0, n = tmp->array.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&tmp->array, i, JSObject); - if (!ns) - continue; - tmp->value = OBJECT_TO_JSVAL(ns); - if (!arrayobj->setProperty(cx, INT_TO_JSID(i), &tmp->value)) - return JS_FALSE; - } - return JS_TRUE; -} - static JSBool FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) { @@ -5999,19 +5878,48 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) return JS_TRUE; } +class AutoNamespaceArray : public js::AutoNamespaces { + public: + AutoNamespaceArray(JSContext *cx) + : js::AutoNamespaces(cx) + { + XMLArrayInit(cx, &array, 0); + } + + ~AutoNamespaceArray() { + XMLArrayFinish(context, &array); + } + + /* + * Populate a new JS array with elements of array and place the result into + * rval. rval must point to a rooted location. + */ + bool toJSArray(jsval *rval) { + JSObject *arrayobj = js_NewArrayObject(context, 0, NULL); + if (!arrayobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(arrayobj); + + AutoValueRooter tvr(context); + for (uint32 i = 0, n = array.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&array, i, JSObject); + if (!ns) + continue; + *tvr.addr() = OBJECT_TO_JSVAL(ns); + if (!arrayobj->setProperty(context, INT_TO_JSID(i), tvr.addr())) + return JS_FALSE; + } + return JS_TRUE; + } +}; + static JSBool xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) { - JSTempRootedNSArray namespaces; - JSBool ok; - NON_LIST_XML_METHOD_PROLOG; - InitTempNSArray(cx, &namespaces); - ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && - TempNSArrayToJSArray(cx, &namespaces, vp); - FinishTempNSArray(cx, &namespaces); - return ok; + AutoNamespaceArray namespaces(cx); + return FindInScopeNamespaces(cx, xml, &namespaces.array) && namespaces.toJSArray(vp); } static JSBool @@ -6111,15 +6019,13 @@ static JSBool xml_namespace(JSContext *cx, uintN argc, jsval *vp) { JSString *prefix, *nsprefix; - JSTempRootedNSArray inScopeNSes; - JSBool ok; jsuint i, length; JSObject *ns; NON_LIST_XML_METHOD_PROLOG; if (argc == 0 && !JSXML_HAS_NAME(xml)) { *vp = JSVAL_NULL; - return JS_TRUE; + return true; } if (argc == 0) { @@ -6127,22 +6033,18 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } else { prefix = js_ValueToString(cx, vp[2]); if (!prefix) - return JS_FALSE; + return false; vp[2] = STRING_TO_JSVAL(prefix); /* local root */ } - InitTempNSArray(cx, &inScopeNSes); - MUST_FLOW_THROUGH("out"); - ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array); - if (!ok) - goto out; + AutoNamespaceArray inScopeNSes(cx); + if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array)) + return false; if (!prefix) { ns = GetNamespace(cx, xml->name, &inScopeNSes.array); - if (!ns) { - ok = JS_FALSE; - goto out; - } + if (!ns) + return false; } else { ns = NULL; for (i = 0, length = inScopeNSes.array.length; i < length; i++) { @@ -6157,64 +6059,44 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns); - - out: - FinishTempNSArray(cx, &inScopeNSes); - return JS_TRUE; + return true; } static JSBool xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) { - JSBool ok; - JSTempRootedNSArray ancestors, declared; - JSXML *yml; - uint32 i, n; - JSObject *ns; - NON_LIST_XML_METHOD_PROLOG; if (JSXML_HAS_VALUE(xml)) - return JS_TRUE; + return true; - /* From here, control flow must goto out to finish these arrays. */ - ok = JS_TRUE; - InitTempNSArray(cx, &ancestors); - InitTempNSArray(cx, &declared); - yml = xml; + AutoNamespaceArray ancestors(cx); + AutoNamespaceArray declared(cx); + JSXML *yml = xml; while ((yml = yml->parent) != NULL) { JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); - for (i = 0, n = yml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); - if (ns && - !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - ok = XMLARRAY_APPEND(cx, &ancestors.array, ns); - if (!ok) - goto out; + for (uint32 i = 0, n = yml->xml_namespaces.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); + if (ns && !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + if (!XMLARRAY_APPEND(cx, &ancestors.array, ns)) + return false; } } } - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + for (uint32 i = 0, n = xml->xml_namespaces.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); if (!ns) continue; if (!IsDeclared(ns)) continue; if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - ok = XMLARRAY_APPEND(cx, &declared.array, ns); - if (!ok) - goto out; + if (!XMLARRAY_APPEND(cx, &declared.array, ns)) + return false; } } - ok = TempNSArrayToJSArray(cx, &declared, vp); - -out: - /* Finishing must be in reverse order of initialization to follow LIFO. */ - FinishTempNSArray(cx, &declared); - FinishTempNSArray(cx, &ancestors); - return ok; + return declared.toJSArray(vp); } static const char js_attribute_str[] = "attribute"; @@ -7247,9 +7129,9 @@ js_TraceXML(JSTracer *trc, JSXML *xml) if (xml->xml_targetprop) JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop"); } else { - TraceObjectVector(trc, - (JSObject **) xml->xml_namespaces.vector, - xml->xml_namespaces.length); + js::TraceObjectVector(trc, + (JSObject **) xml->xml_namespaces.vector, + xml->xml_namespaces.length); XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); if (IS_GC_MARKING_TRACER(trc)) XMLArrayTrim(&xml->xml_namespaces); @@ -7282,17 +7164,12 @@ js_FinalizeXML(JSContext *cx, JSXML *xml) JSObject * js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) { - JSXML *xml; - JSObject *obj; - JSTempValueRooter tvr; - - xml = js_NewXML(cx, xml_class); + JSXML *xml = js_NewXML(cx, xml_class); if (!xml) return NULL; - JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr); - obj = js_GetXMLObject(cx, xml); - JS_POP_TEMP_ROOT(cx, &tvr); - return obj; + + AutoXMLRooter root(cx, xml); + return js_GetXMLObject(cx, xml); } static JSObject * @@ -7809,48 +7686,35 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) static JSBool GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - JSObject *target; - JSXML *xml; - JSTempValueRooter tvr; - JSBool ok; - JS_ASSERT(OBJECT_IS_XML(cx, obj)); - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); - /* * See comments before xml_lookupProperty about the need for the proto * chain lookup. */ - target = obj; + JSObject *target = obj; + AutoObjectRooter tvr(cx); for (;;) { - ok = js_GetProperty(cx, target, id, vp); - if (!ok) - goto out; - if (VALUE_IS_FUNCTION(cx, *vp)) { - ok = JS_TRUE; - goto out; - } + if (!js_GetProperty(cx, target, id, vp)) + return false; + if (VALUE_IS_FUNCTION(cx, *vp)) + return true; target = target->getProto(); if (target == NULL) break; - tvr.u.object = target; + tvr.setObject(target); } - xml = (JSXML *) obj->getPrivate(); - if (HasSimpleContent(xml)) { - /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ - ok = js_GetClassPrototype(cx, NULL, JSProto_String, &tvr.u.object); - if (!ok) - goto out; - JS_ASSERT(tvr.u.object); - ok = tvr.u.object->getProperty(cx, id, vp); - } + JSXML *xml = (JSXML *) obj->getPrivate(); + if (!HasSimpleContent(xml)) + return true; - out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; + /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ + if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + return false; + + JS_ASSERT(tvr.object()); + return tvr.object()->getProperty(cx, id, vp); } static JSXML * diff --git a/js/src/jsxml.h b/js/src/jsxml.h index cb7198f59860..37724757e267 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -39,7 +39,7 @@ #ifndef jsxml_h___ #define jsxml_h___ -#include "jspubtd.h" +#include "jsarray.h" JS_BEGIN_EXTERN_C @@ -63,6 +63,58 @@ struct JSXMLArray { JSXMLArrayCursor *cursors; }; +struct JSXMLArrayCursor +{ + JSXMLArray *array; + uint32 index; + JSXMLArrayCursor *next; + JSXMLArrayCursor **prevp; + void *root; + + JSXMLArrayCursor(JSXMLArray *array) + : array(array), index(0), next(array->cursors), prevp(&array->cursors), + root(NULL) + { + if (next) + next->prevp = &next; + array->cursors = this; + } + + ~JSXMLArrayCursor() { disconnect(); } + + void disconnect() { + if (!array) + return; + if (next) + next->prevp = prevp; + *prevp = next; + array = NULL; + } + + void *getNext() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index++]; + } + + void *getCurrent() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index]; + } + + void trace(JSTracer *trc) { +#ifdef DEBUG + size_t index = 0; +#endif + for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) { + void *root = cursor->root; + JS_SET_TRACING_INDEX(trc, "cursor_root", index++); + js_CallValueTracerIfGCThing(trc, jsval(root)); + } + } +}; + #define JSXML_PRESET_CAPACITY JS_BIT(31) #define JSXML_CAPACITY_MASK JS_BITMASK(31) #define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp index 70724cadeb6e..8444c1359947 100644 --- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For JSAutoTempValueRooter. +#include "jscntxt.h" // For js::AutoValueRooter. #include "jsobj.h" #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -283,17 +283,16 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) *vp = OBJECT_TO_JSVAL(wrapperObj); - jsval exposedProps = JSVAL_VOID; - JSAutoTempValueRooter tvr(cx, 1, &exposedProps); + js::AutoValueRooter exposedProps(cx, JSVAL_VOID); - if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) { + if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) || - !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, - JSVAL_ZERO) || - !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) { + !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || + !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, + exposedProps.value())) { return JS_FALSE; } @@ -778,7 +777,7 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our COW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 9a9631482783..3b9f5f608025 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For JSAutoTempValueRooter. +#include "jscntxt.h" // For js::AutoValueRooter. #include "XPCWrapper.h" #include "nsIDOMWindow.h" #include "nsIDOMWindowCollection.h" @@ -830,7 +830,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj) return nsnull; } - JSAutoTempValueRooter tvr(cx, uxpco); + js::AutoValueRooter tvr(cx, uxpco); jsval wrappedObj, parentScope; if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) || @@ -1206,7 +1206,7 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our XOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 72daa9079c5a..c3fe67645fd7 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1118,7 +1118,7 @@ XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our native wrapper. XPCWrappedNative *wn = static_cast(JS_GetPrivate(cx, obj)); diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index a0ec10566de1..074cb8e4594e 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -478,7 +478,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NS_STACK_CLASS class SafeCallGuard { public: SafeCallGuard(JSContext *cx, nsIPrincipal *principal) - : cx(cx) { + : cx(cx), tvr(cx) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (ssm) { // Note: We pass null as the target frame pointer because we know that @@ -517,7 +517,7 @@ public: private: JSContext *cx; JSRegExpStatics statics; - JSTempValueRooter tvr; + js::AutoValueRooter tvr; uint32 options; JSStackFrame *fp; }; @@ -957,7 +957,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index 406adb39c320..b4c62f09aeac 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For JSAutoTempValueRooter. +#include "jscntxt.h" // For js::AutoValueRooter. #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -137,7 +137,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) } *vp = OBJECT_TO_JSVAL(wrapperObj); - JSAutoTempValueRooter tvr(cx, *vp); + js::AutoValueRooter tvr(cx, *vp); if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { @@ -437,7 +437,7 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - JSAutoTempValueRooter tvr(cx, 1, vp); + js::AutoArrayRooter tvr(cx, 1, vp); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { @@ -649,7 +649,7 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our SOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index b6fc00c21d7d..2d3beb3a714c 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -153,7 +153,7 @@ IteratorNext(JSContext *cx, uintN argc, jsval *vp) } jsval vec[2] = { STRING_TO_JSVAL(str), v }; - JSAutoTempValueRooter tvr(cx, 2, vec); + js::AutoArrayRooter tvr(cx, 2, vec); JSObject *array = JS_NewArrayObject(cx, 2, vec); if (!array) { return JS_FALSE; @@ -192,7 +192,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); // Do this sooner rather than later to avoid complications in // IteratorFinalize. @@ -213,7 +213,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, // call enumerate, and then re-set the prototype. As we do this, we have // to protec the temporary wrapper from garbage collection. - JSAutoTempValueRooter tvr(cx, tempWrapper); + js::AutoValueRooter tvr(cx, tempWrapper); if (!JS_SetPrototype(cx, iterObj, wrapperObj) || !XPCWrapper::Enumerate(cx, iterObj, wrapperObj) || !JS_SetPrototype(cx, iterObj, tempWrapper)) { diff --git a/js/src/xpconnect/src/qsgen.py b/js/src/xpconnect/src/qsgen.py index a3021f15b574..0f7c90d485b1 100644 --- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -833,7 +833,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): if isGetter: pthisval = 'vp' elif isSetter: - f.write(" JSAutoTempValueRooter tvr(cx);\n") + f.write(" js::AutoValueRooter tvr(cx);\n") pthisval = 'tvr.addr()' else: pthisval = '&vp[1]' # as above, ok to overwrite vp[1] diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index 544990da4c67..d4417a050bcb 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1582,23 +1582,23 @@ XPCConvert::ConstructException(nsresult rv, const char* message, /********************************/ -class AutoExceptionRestorer : public JSAutoTempValueRooter +class AutoExceptionRestorer { public: AutoExceptionRestorer(JSContext *cx, jsval v) - : JSAutoTempValueRooter(cx, v), - mVal(v) + : mContext(cx), tvr(cx, v) { JS_ClearPendingException(mContext); } ~AutoExceptionRestorer() { - JS_SetPendingException(mContext, mVal); + JS_SetPendingException(mContext, tvr.value()); } private: - jsval mVal; + JSContext * const mContext; + js::AutoValueRooter tvr; }; // static diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index cc26a2220217..d30e2ef68012 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -173,7 +173,7 @@ GeneratePropertyOp(JSContext *cx, JSObject *obj, jsval idval, uintN argc, JSObject *funobj = JS_GetFunctionObject(fun); - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); // Unfortunately, we cannot guarantee that JSPropertyOp is aligned. Use a // second object to work around this. @@ -198,7 +198,7 @@ ReifyPropertyOps(JSContext *cx, JSObject *obj, jsval idval, jsid interned_id, { // Generate both getter and setter and stash them in the prototype. jsval roots[2] = { JSVAL_NULL, JSVAL_NULL }; - JSAutoTempValueRooter tvr(cx, 2, roots); + js::AutoArrayRooter tvr(cx, 2, roots); uintN attrs = JSPROP_SHARED; JSObject *getterobj; diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index de2446cd243b..0943aab68a11 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -321,7 +321,7 @@ struct xpc_qsArgValArray memset(array, 0, N * sizeof(jsval)); } - JSAutoTempValueRooter tvr; + js::AutoArrayRooter tvr; jsval array[N]; }; diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index fb7e1192a64f..75964e97386c 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -1517,8 +1517,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) JSStackFrame *fp; nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp); - jsval retval = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter atvr(cx, 1, &retval); + js::AutoValueRooter retval(cx, obj); if(principal && fp) { @@ -1535,7 +1534,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags, - &retval); + retval.addr()); if(NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); @@ -1543,7 +1542,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } } - return JSVAL_TO_OBJECT(retval); + return JSVAL_TO_OBJECT(retval.value()); } JSObjectOps * diff --git a/js/src/xpconnect/tests/TestXPC.cpp b/js/src/xpconnect/tests/TestXPC.cpp index b9e6e723b8ca..5c69f4c7e03e 100644 --- a/js/src/xpconnect/tests/TestXPC.cpp +++ b/js/src/xpconnect/tests/TestXPC.cpp @@ -562,7 +562,7 @@ TestArgFormatter(JSContext* jscontext, JSObject* glob, nsIXPConnect* xpc) // Prepare an array of arguments for JS_ConvertArguments jsval argv[5]; - JSAutoTempValueRooter tvr(jscontext, 5, argv); + js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv); if (!PushArguments(jscontext, 5, argv, "s %ip %iv %is s", diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index 22062d4765d2..c595fca8f708 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -673,35 +673,35 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args, } } - JSTempValueRooter tvr; - JS_PUSH_TEMP_ROOT(cx, 0, jsargs, &tvr); - - // Convert args - for (PRUint32 i = 0; i < argCount; ++i) { - jsargs[i] = NPVariantToJSVal(npp, cx, args + i); - ++tvr.count; - } - jsval v; JSBool ok; - if (ctorCall) { - JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); - JSObject *newObj = - ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), - nsnull, global, argCount, jsargs); + { + js::AutoArrayRooter tvr(cx, 0, jsargs); - if (newObj) { - v = OBJECT_TO_JSVAL(newObj); - ok = JS_TRUE; - } else { - ok = JS_FALSE; + // Convert args + for (PRUint32 i = 0; i < argCount; ++i) { + jsargs[i] = NPVariantToJSVal(npp, cx, args + i); + tvr.changeLength(i + 1); } - } else { - ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); - } - JS_POP_TEMP_ROOT(cx, &tvr); + if (ctorCall) { + JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); + JSObject *newObj = + ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), + nsnull, global, argCount, jsargs); + + if (newObj) { + v = OBJECT_TO_JSVAL(newObj); + ok = JS_TRUE; + } else { + ok = JS_FALSE; + } + } else { + ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); + } + + } if (jsargs != jsargs_buf) PR_Free(jsargs); @@ -837,7 +837,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, AutoJSExceptionReporter reporter(cx); jsval v = NPVariantToJSVal(npp, cx, value); - JSAutoTempValueRooter tvr(cx, v); + js::AutoValueRooter tvr(cx, v); if (JSVAL_IS_STRING(id)) { JSString *str = JSVAL_TO_STRING(id); diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index 92843fff99f2..ac912561d0df 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -1693,7 +1693,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) // Root obj and the rval (below). jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL }; - JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); + js::AutoArrayRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); jsval *rval = &vec[1]; if (result) { diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index 98dceafa4f28..f35807655d15 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -247,7 +247,7 @@ XPITriggerEvent::Run() // Build arguments into rooted jsval array jsval args[2] = { JSVAL_NULL, JSVAL_NULL }; - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(args), args); + js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args); // args[0] is the URL JSString *str = JS_NewUCStringCopyZ(cx, URL.get()); From 52d8139de2954985c84bc31ea75e7fa459d56ff2 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Thu, 11 Feb 2010 17:04:42 -0800 Subject: [PATCH 002/213] Bug 515496 - Eliminate extra security check when computing this. r=jorendorff. --- js/src/jsapi.cpp | 6 ++--- js/src/jsdbgapi.cpp | 2 +- js/src/jsinterp.cpp | 59 ++++++--------------------------------------- js/src/jsinterp.h | 6 ++--- js/src/jstracer.cpp | 4 +-- 5 files changed, 17 insertions(+), 60 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 777b9d59b1ea..f906ccf99b87 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1693,7 +1693,7 @@ JS_GetGlobalForObject(JSContext *cx, JSObject *obj) JS_PUBLIC_API(jsval) JS_ComputeThis(JSContext *cx, jsval *vp) { - if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) + if (!js_ComputeThis(cx, vp + 2)) return JSVAL_NULL; return vp[1]; } @@ -4285,7 +4285,7 @@ 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. */ - if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) + if (!js_ComputeThis(cx, vp + 2)) return JS_FALSE; /* * Protect against argc underflowing. By calling js_ComputeThis, we made @@ -4349,7 +4349,7 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, * Follow Function.prototype.apply and .call by using the global object as * the 'this' param if no args. */ - if (!js_ComputeThis(cx, JS_TRUE, argv)) + if (!js_ComputeThis(cx, argv)) return JS_FALSE; js_GetTopStackFrame(cx)->thisv = argv[-1]; JS_ASSERT(cx->fp->argv == argv); diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 4d8b57b18883..50b6e82512d7 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1243,7 +1243,7 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp) } if (fp->argv) - fp->thisv = OBJECT_TO_JSVAL(js_ComputeThis(cx, JS_TRUE, fp->argv)); + fp->thisv = OBJECT_TO_JSVAL(js_ComputeThis(cx, fp->argv)); if (afp) { cx->fp = afp; diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 32fe8f00e750..fc525ca66b19 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -399,7 +399,7 @@ CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv) * The alert should display "true". */ JS_STATIC_INTERPRET JSObject * -js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv) +js_ComputeGlobalThis(JSContext *cx, jsval *argv) { JSObject *thisp; @@ -407,57 +407,14 @@ js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv) !JSVAL_TO_OBJECT(argv[-2])->getParent()) { thisp = cx->globalObject; } else { - jsid id; - jsval v; - uintN attrs; - JSBool ok; - JSObject *parent; - - /* - * Walk up the parent chain, first checking that the running script - * has access to the callee's parent object. Note that if lazy, the - * running script whose principals we want to check is the script - * associated with fp->down, not with fp. - * - * FIXME: 417851 -- this access check should not be required, as it - * imposes a performance penalty on all js_ComputeGlobalThis calls, - * and it represents a maintenance hazard. - * - * When the above FIXME is made fixed, the whole GC reachable frame - * mechanism can be removed as well. - */ - JSStackFrame *fp = js_GetTopStackFrame(cx); - JSGCReachableFrame reachable; - if (lazy) { - JS_ASSERT(fp->argv == argv); - cx->fp = fp->down; - fp->down = NULL; - cx->pushGCReachableFrame(reachable, fp); - } - thisp = JSVAL_TO_OBJECT(argv[-2]); - id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); - - ok = thisp->checkAccess(cx, id, JSACC_PARENT, &v, &attrs); - if (lazy) { - fp->down = cx->fp; - cx->fp = fp; - cx->popGCReachableFrame(); - } - if (!ok) - return NULL; - - if (v != JSVAL_NULL) { - thisp = JSVAL_IS_VOID(v) ? thisp->getParent() : JSVAL_TO_OBJECT(v); - while ((parent = thisp->getParent()) != NULL) - thisp = parent; - } + thisp = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(argv[-2])); } return CallThisObjectHook(cx, thisp, argv); } static JSObject * -ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) +ComputeThis(JSContext *cx, jsval *argv) { JSObject *thisp; @@ -471,18 +428,18 @@ ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) thisp = JSVAL_TO_OBJECT(argv[-1]); if (OBJ_GET_CLASS(cx, thisp) == &js_CallClass || OBJ_GET_CLASS(cx, thisp) == &js_BlockClass) - return js_ComputeGlobalThis(cx, lazy, argv); + return js_ComputeGlobalThis(cx, argv); return CallThisObjectHook(cx, thisp, argv); } JSObject * -js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) +js_ComputeThis(JSContext *cx, jsval *argv) { JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning if (JSVAL_IS_NULL(argv[-1])) - return js_ComputeGlobalThis(cx, lazy, argv); - return ComputeThis(cx, lazy, argv); + return js_ComputeGlobalThis(cx, argv); + return ComputeThis(cx, argv); } #if JS_HAS_NO_SUCH_METHOD @@ -723,7 +680,7 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags) * the appropriate this-computing bytecode, e.g., JSOP_THIS. */ if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) { - if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) { + if (!js_ComputeThis(cx, vp + 2)) { ok = JS_FALSE; goto out2; } diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 12016d72bb73..b4548a8414e2 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -265,7 +265,7 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); * must not be a JSVAL_VOID. */ extern JSObject * -js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv); +js_ComputeThis(JSContext *cx, jsval *argv); extern const uint16 js_PrimitiveTestFlags[]; @@ -280,7 +280,7 @@ js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp) { if (fp->flags & JSFRAME_COMPUTED_THIS) return JSVAL_TO_OBJECT(fp->thisv); /* JSVAL_COMPUTED_THIS invariant */ - JSObject* obj = js_ComputeThis(cx, JS_TRUE, fp->argv); + JSObject* obj = js_ComputeThis(cx, fp->argv); if (!obj) return NULL; fp->thisv = OBJECT_TO_JSVAL(obj); @@ -421,7 +421,7 @@ js_FreeRawStack(JSContext *cx, void *mark); * The alert should display "true". */ extern JSObject * -js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv); +js_ComputeGlobalThis(JSContext *cx, jsval *argv); extern JS_REQUIRES_STACK JSBool js_EnterWith(JSContext *cx, jsint stackIndex); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 27b4e87089bf..84fbcf922cdf 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -9437,7 +9437,7 @@ TraceRecorder::getThis(LIns*& this_ins) JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp); if (!thisObj) - RETURN_ERROR("js_ComputeThisForName failed"); + RETURN_ERROR("js_ComputeThisForFrame failed"); /* In global code, bake in the global object as 'this' object. */ if (!cx->fp->callee()) { @@ -10798,7 +10798,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode) */ if (!(fun->flags & JSFUN_FAST_NATIVE)) { if (JSVAL_IS_NULL(vp[1])) { - JSObject* thisObj = js_ComputeThis(cx, JS_FALSE, vp + 2); + JSObject* thisObj = js_ComputeThis(cx, vp + 2); if (!thisObj) RETURN_ERROR("error in js_ComputeGlobalThis"); this_ins = INS_CONSTOBJ(thisObj); From adf0fee09b7780c15cb92247b3910b0b6112ece7 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 1 Mar 2010 14:46:15 -0800 Subject: [PATCH 003/213] Bug 538690 - js::AutoValueVector for auto-managed rooting and storage of an indefinite number of jsvals. r=igor --- js/src/jsarray.cpp | 8 +- js/src/jsarray.h | 3 +- js/src/jscntxt.h | 49 ++++++++++- js/src/jscntxtinlines.h | 6 ++ js/src/jsstr.cpp | 180 +++++++++++++++++++--------------------- 5 files changed, 146 insertions(+), 100 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 5e834b5d8aeb..8e5adb637928 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1723,8 +1723,8 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva } static JSBool -InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector, - JSBool holey = JS_FALSE) +InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const jsval *vector, + bool holey = false) { JS_ASSERT(obj->isArray()); @@ -3329,7 +3329,7 @@ JSBool js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { jsuint length; - jsval *vector; + const jsval *vector; /* If called without new, replace obj with a new Array object. */ if (!JS_IsConstructing(cx)) { @@ -3431,7 +3431,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj) } JSObject * -js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) +js_NewArrayObject(JSContext *cx, jsuint length, const jsval *vector, bool holey) { JSObject *obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL); if (!obj) diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 7305b74760a9..685cfe67fc06 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -106,8 +106,7 @@ extern JSObject * JS_FASTCALL js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len); extern JSObject * -js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, - JSBool holey = JS_FALSE); +js_NewArrayObject(JSContext *cx, jsuint length, const jsval *vector, bool holey = false); /* Create an array object that starts out already made slow/sparse. */ extern JSObject * diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index d5005755c510..d40d04313492 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1667,7 +1667,8 @@ class AutoGCRooter { NAMESPACES = -9, /* js::AutoNamespaceArray */ XML = -10, /* js::AutoXMLRooter */ OBJECT = -11, /* js::AutoObjectRooter */ - ID = -12 /* js::AutoIdRooter */ + ID = -12, /* js::AutoIdRooter */ + VECTOR = -13 /* js::AutoValueVector */ }; }; @@ -2402,6 +2403,52 @@ ContextAllocPolicy::reportAllocOverflow() const js_ReportAllocationOverflow(cx); } +class AutoValueVector : private AutoGCRooter +{ + public: + explicit AutoValueVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, VECTOR), vector(cx) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + size_t length() const { return vector.length(); } + + bool push(jsval v) { return vector.append(v); } + bool push(JSString *str) { return push(STRING_TO_JSVAL(str)); } + bool push(JSObject *obj) { return push(OBJECT_TO_JSVAL(obj)); } + bool push(jsdouble *dp) { return push(DOUBLE_TO_JSVAL(dp)); } + + void pop() { vector.popBack(); } + + bool resize(size_t newLength) { + size_t oldLength = vector.length(); + if (!vector.resize(newLength)) + return false; + JS_STATIC_ASSERT(JSVAL_NULL == 0); + if (newLength > oldLength) + PodZero(vector.begin(), newLength - oldLength); + return true; + } + + bool reserve(size_t newLength) { + return vector.reserve(newLength); + } + + jsval & operator[](size_t i) { return vector[i]; } + jsval operator[](size_t i) const { return vector[i]; } + + const jsval * buffer() const { return vector.begin(); } + jsval * buffer() { return vector.begin(); } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + Vector vector; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + } #ifdef _MSC_VER diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index ca28d7682f2f..3141959102cb 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -136,6 +136,12 @@ AutoGCRooter::trace(JSTracer *trc) JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val"); js_CallValueTracerIfGCThing(trc, static_cast(this)->idval); return; + + case VECTOR: { + js::Vector &vector = static_cast(this)->vector; + js::TraceValues(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector"); + return; + } } JS_ASSERT(tag >= 0); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index bb6284ea7f5f..4cbf1fdd4f6b 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2147,103 +2147,97 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, static JSBool str_split(JSContext *cx, uintN argc, jsval *vp) { - JSString *str, *sub; - JSObject *arrayobj; - jsval v; - JSBool ok, limited; - JSRegExp *re; - JSSubString *sep, tmp; - jsdouble d; - jsint i, j; - uint32 len, limit; - + JSString *str; NORMALIZE_THIS(cx, vp, str); - arrayobj = js_NewArrayObject(cx, 0, NULL); - if (!arrayobj) - return JS_FALSE; - *vp = OBJECT_TO_JSVAL(arrayobj); - if (argc == 0) { - v = STRING_TO_JSVAL(str); - ok = arrayobj->setProperty(cx, INT_TO_JSID(0), &v); - } else { - if (VALUE_IS_REGEXP(cx, vp[2])) { - re = (JSRegExp *) JSVAL_TO_OBJECT(vp[2])->getPrivate(); - sep = &tmp; - - /* Set a magic value so we can detect a successful re match. */ - sep->chars = NULL; - sep->length = 0; - } else { - JSString *str2 = js_ValueToString(cx, vp[2]); - if (!str2) - return JS_FALSE; - vp[2] = STRING_TO_JSVAL(str2); - - /* - * Point sep at a local copy of str2's header because find_split - * will modify sep->length. - */ - str2->getCharsAndLength(tmp.chars, tmp.length); - sep = &tmp; - re = NULL; - } - - /* Use the second argument as the split limit, if given. */ - limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]); - limit = 0; /* Avoid warning. */ - if (limited) { - d = js_ValueToNumber(cx, &vp[3]); - if (JSVAL_IS_NULL(vp[3])) - return JS_FALSE; - - /* Clamp limit between 0 and 1 + string length. */ - limit = js_DoubleToECMAUint32(d); - if (limit > str->length()) - limit = 1 + str->length(); - } - - len = i = 0; - while ((j = find_split(cx, str, re, &i, sep)) >= 0) { - if (limited && len >= limit) - break; - sub = js_NewDependentString(cx, str, i, (size_t)(j - i)); - if (!sub) - return JS_FALSE; - v = STRING_TO_JSVAL(sub); - if (!JS_SetElement(cx, arrayobj, len, &v)) - return JS_FALSE; - len++; - - /* - * Imitate perl's feature of including parenthesized substrings - * that matched part of the delimiter in the new array, after the - * split substring that was delimited. - */ - if (re && sep->chars) { - uintN num; - JSSubString *parsub; - - for (num = 0; num < cx->regExpStatics.parenCount; num++) { - if (limited && len >= limit) - break; - parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num); - sub = js_NewStringCopyN(cx, parsub->chars, parsub->length); - if (!sub) - return JS_FALSE; - v = STRING_TO_JSVAL(sub); - if (!JS_SetElement(cx, arrayobj, len, &v)) - return JS_FALSE; - len++; - } - sep->chars = NULL; - } - i = j + sep->length; - } - ok = (j != -2); + jsval v = STRING_TO_JSVAL(str); + JSObject *aobj = js_NewArrayObject(cx, 1, &v); + if (!aobj) + return false; + *vp = OBJECT_TO_JSVAL(aobj); + return true; } - return ok; + + JSRegExp *re; + JSSubString *sep, tmp; + if (VALUE_IS_REGEXP(cx, vp[2])) { + re = (JSRegExp *) JSVAL_TO_OBJECT(vp[2])->getPrivate(); + sep = &tmp; + + /* Set a magic value so we can detect a successful re match. */ + sep->chars = NULL; + sep->length = 0; + } else { + JSString *str2 = js_ValueToString(cx, vp[2]); + if (!str2) + return false; + vp[2] = STRING_TO_JSVAL(str2); + + /* + * Point sep at a local copy of str2's header because find_split + * will modify sep->length. + */ + str2->getCharsAndLength(tmp.chars, tmp.length); + sep = &tmp; + re = NULL; + } + + /* Use the second argument as the split limit, if given. */ + uint32 limit = 0; /* Avoid warning. */ + bool limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]); + if (limited) { + jsdouble d = js_ValueToNumber(cx, &vp[3]); + if (JSVAL_IS_NULL(vp[3])) + return false; + + /* Clamp limit between 0 and 1 + string length. */ + limit = js_DoubleToECMAUint32(d); + if (limit > str->length()) + limit = 1 + str->length(); + } + + AutoValueVector splits(cx); + + jsint i, j; + uint32 len = i = 0; + while ((j = find_split(cx, str, re, &i, sep)) >= 0) { + if (limited && len >= limit) + break; + + JSString *sub = js_NewDependentString(cx, str, i, size_t(j - i)); + if (!sub || !splits.push(sub)) + return false; + len++; + + /* + * Imitate perl's feature of including parenthesized substrings that + * matched part of the delimiter in the new array, after the split + * substring that was delimited. + */ + if (re && sep->chars) { + for (uintN num = 0; num < cx->regExpStatics.parenCount; num++) { + if (limited && len >= limit) + break; + JSSubString *parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num); + sub = js_NewStringCopyN(cx, parsub->chars, parsub->length); + if (!sub || !splits.push(sub)) + return false; + len++; + } + sep->chars = NULL; + } + i = j + sep->length; + } + + if (j == -2) + return false; + + JSObject *aobj = js_NewArrayObject(cx, splits.length(), splits.buffer()); + if (!aobj) + return false; + *vp = OBJECT_TO_JSVAL(aobj); + return true; } #if JS_HAS_PERL_SUBSTR From 430bcd70ee9cab0eb0e68ec3b8471c976d915ab9 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 9 Mar 2010 15:07:38 -0800 Subject: [PATCH 004/213] Bustage fix, r=redness --- js/src/jsarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index d288561df8e0..19f7d7020370 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2233,7 +2233,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * the elements. */ #if JS_BITS_PER_WORD == 32 - if (size_t(newlen) > SIZE_MAX / (4 * sizeof(jsval))) { + if (size_t(newlen) > size_t(-1) / (4 * sizeof(jsval))) { js_ReportAllocationOverflow(cx); return false; } From 425dc3f000a4778a99b0b685db74dceb12421f18 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 9 Mar 2010 15:23:53 -0800 Subject: [PATCH 005/213] Fix up some class names in comments, r=sparky --- js/src/jscntxt.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 02833fcee675..00af9aab1990 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1653,17 +1653,17 @@ class AutoGCRooter { enum { JSVAL = -1, /* js::AutoValueRooter */ - SPROP = -2, /* JSAutoScopePropertyTreeRooter */ - WEAKROOTS = -3, /* AutoSaveWeakRoots */ + SPROP = -2, /* js::AutoScopePropertyRooter */ + WEAKROOTS = -3, /* js::AutoSaveWeakRoots */ COMPILER = -4, /* JSCompiler */ - SCRIPT = -5, /* JSAutoScriptRooter */ - ENUMERATOR = -6, /* JSAutoEnumStateRooter */ - IDARRAY = -7, /* JSAutoIdArray */ - DESCRIPTORS = -8, /* AutoDescriptorArray */ - NAMESPACES = -9, /* AutoNamespaceArray */ - XML = -10, /* JSAutoXML */ - OBJECT = -11, /* JSAutoObjectRooter */ - ID = -12 /* JSAutoTempIdRooter */ + SCRIPT = -5, /* js::AutoScriptRooter */ + ENUMERATOR = -6, /* js::AutoEnumStateRooter */ + IDARRAY = -7, /* js::AutoIdArray */ + DESCRIPTORS = -8, /* js::AutoDescriptorArray */ + NAMESPACES = -9, /* js::AutoNamespaces */ + XML = -10, /* js::AutoXMLRooter */ + OBJECT = -11, /* js::AutoObjectRooter */ + ID = -12 /* js::AutoIdRooter */ }; }; From 49f22f1f82216ba890074728dc9cb9b911b47286 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 9 Mar 2010 15:38:41 -0800 Subject: [PATCH 006/213] More bustage fix, sigh --- js/src/jsarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 19f7d7020370..522386256790 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2123,7 +2123,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * malloc'd vector. */ #if JS_BITS_PER_WORD == 32 - if (size_t(len) > SIZE_MAX / (2 * sizeof(jsval))) { + if (size_t(len) > size_t(-1) / (2 * sizeof(jsval))) { js_ReportAllocationOverflow(cx); return false; } From 062d268d450969b222f58386341100544f21644c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 9 Mar 2010 17:44:16 -0800 Subject: [PATCH 007/213] Further bustage fixing --- js/src/jsregexp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index e02ce42cf838..3eec2bbd88b2 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5235,7 +5235,8 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, AutoValueRooter *tvr) { *statics = cx->regExpStatics; - tvr->setString(statics->input); + if (statics->input) + tvr->setString(statics->input); /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). From b22620a062f18f7db127bac84c7162b7f9fb3501 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 9 Mar 2010 18:52:56 -0800 Subject: [PATCH 008/213] Clean up useless variables/params in the tracer. (bug 551100, r=lw) --- js/src/jstracer.cpp | 66 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index e39d20c38948..2bebd42880d3 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1525,9 +1525,10 @@ AssertTreeIsUnique(TraceMonitor* tm, TreeFragment* f) #endif static void -AttemptCompilation(JSContext *cx, TraceMonitor* tm, JSObject* globalObj, jsbytecode* pc, - uint32 argc) +AttemptCompilation(JSContext *cx, JSObject* globalObj, jsbytecode* pc, uint32 argc) { + TraceMonitor *tm = &JS_TRACE_MONITOR(cx); + /* If we already permanently blacklisted the location, undo that. */ JS_ASSERT(*pc == JSOP_NOP || *pc == JSOP_TRACE || *pc == JSOP_CALL); if (*pc == JSOP_NOP) @@ -4611,8 +4612,9 @@ TraceRecorder::closeLoop(SlotMap& slotMap, VMSideExit* exit) JS_ASSERT_IF(exit->exitType == RECURSIVE_UNLINKED_EXIT, exit->recursive_pc != fragment->root->ip); + JS_ASSERT(fragment->root == tree); + TreeFragment* peer = NULL; - TreeFragment* root = fragment->root; TypeConsensus consensus = TypeConsensus_Bad; @@ -4620,7 +4622,7 @@ TraceRecorder::closeLoop(SlotMap& slotMap, VMSideExit* exit) consensus = selfTypeStability(slotMap); if (consensus != TypeConsensus_Okay) { const void* ip = exit->exitType == RECURSIVE_UNLINKED_EXIT ? - exit->recursive_pc : fragment->root->ip; + exit->recursive_pc : tree->ip; TypeConsensus peerConsensus = peerTypeStability(slotMap, ip, &peer); /* If there was a semblance of a stable peer (even if not linkable), keep the result. */ if (peerConsensus != TypeConsensus_Bad) @@ -4693,8 +4695,11 @@ TraceRecorder::closeLoop(SlotMap& slotMap, VMSideExit* exit) debug_only_printf(LC_TMTreeVis, "TREEVIS CLOSELOOP EXIT=%p PEER=%p\n", (void*)exit, (void*)peer); - peer = LookupLoop(traceMonitor, root->ip, root->globalObj, root->globalShape, root->argc); - JS_ASSERT(peer); + JS_ASSERT(LookupLoop(traceMonitor, tree->ip, tree->globalObj, tree->globalShape, tree->argc) == + tree->first); + JS_ASSERT(tree->first); + + peer = tree->first; joinEdgesToEntry(peer); debug_only_stmt(DumpPeerStability(traceMonitor, peer->ip, peer->globalObj, @@ -4702,7 +4707,7 @@ TraceRecorder::closeLoop(SlotMap& slotMap, VMSideExit* exit) debug_only_print0(LC_TMTracer, "updating specializations on dependent and linked trees\n"); - if (fragment->root->code()) + if (tree->code()) SpecializeTreesToMissingGlobals(cx, globalObj, fragment->root); /* @@ -4710,7 +4715,7 @@ TraceRecorder::closeLoop(SlotMap& slotMap, VMSideExit* exit) * should try to compile the outer tree again. */ if (outer) - AttemptCompilation(cx, traceMonitor, globalObj, outer, outerArgc); + AttemptCompilation(cx, globalObj, outer, outerArgc); #ifdef JS_JIT_SPEW debug_only_printf(LC_TMMinimal, "Recording completed at %s:%u@%u via closeLoop (FragID=%06u)\n", @@ -4843,9 +4848,11 @@ TraceRecorder::endLoop() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::endLoop(VMSideExit* exit) { + JS_ASSERT(fragment->root == tree); + if (callDepth != 0) { debug_only_print0(LC_TMTracer, "Blacklisted: stack depth mismatch, possible recursion.\n"); - Blacklist((jsbytecode*) fragment->root->ip); + Blacklist((jsbytecode*)tree->ip); trashSelf = true; return ARECORD_STOP; } @@ -4860,11 +4867,13 @@ TraceRecorder::endLoop(VMSideExit* exit) debug_only_printf(LC_TMTreeVis, "TREEVIS ENDLOOP EXIT=%p\n", (void*)exit); - TreeFragment* root = fragment->root; - joinEdgesToEntry(LookupLoop(traceMonitor, root->ip, root->globalObj, - root->globalShape, root->argc)); - debug_only_stmt(DumpPeerStability(traceMonitor, root->ip, root->globalObj, - root->globalShape, root->argc);) + JS_ASSERT(LookupLoop(traceMonitor, tree->ip, tree->globalObj, tree->globalShape, tree->argc) == + tree->first); + + joinEdgesToEntry(tree->first); + + debug_only_stmt(DumpPeerStability(traceMonitor, tree->ip, tree->globalObj, + tree->globalShape, tree->argc);) /* * Note: this must always be done, in case we added new globals on trace @@ -4872,7 +4881,7 @@ TraceRecorder::endLoop(VMSideExit* exit) */ debug_only_print0(LC_TMTracer, "updating specializations on dependent and linked trees\n"); - if (fragment->root->code()) + if (tree->code()) SpecializeTreesToMissingGlobals(cx, globalObj, fragment->root); /* @@ -4880,7 +4889,7 @@ TraceRecorder::endLoop(VMSideExit* exit) * yet, we should try to compile the outer tree again. */ if (outer) - AttemptCompilation(cx, traceMonitor, globalObj, outer, outerArgc); + AttemptCompilation(cx, globalObj, outer, outerArgc); #ifdef JS_JIT_SPEW debug_only_printf(LC_TMMinimal, "Recording completed at %s:%u@%u via endLoop (FragID=%06u)\n", @@ -5573,10 +5582,11 @@ SynthesizeSlowNativeFrame(InterpState& state, JSContext *cx, VMSideExit *exit) } static JS_REQUIRES_STACK bool -RecordTree(JSContext* cx, TraceMonitor* tm, TreeFragment* peer, jsbytecode* outer, - uint32 outerArgc, JSObject* globalObj, uint32 globalShape, - SlotList* globalSlots, uint32 argc, RecordReason reason) +RecordTree(JSContext* cx, TreeFragment* peer, jsbytecode* outer, + uint32 outerArgc, SlotList* globalSlots, RecordReason reason) { + TraceMonitor* tm = &JS_TRACE_MONITOR(cx); + /* Try to find an unused peer fragment, or allocate a new one. */ TreeFragment* f = peer; while (f->code() && f->peer) @@ -5589,7 +5599,7 @@ RecordTree(JSContext* cx, TraceMonitor* tm, TreeFragment* peer, jsbytecode* oute const void* localRootIP = f->root->ip; /* Make sure the global type map didn't change on us. */ - if (!CheckGlobalObjectShape(cx, tm, globalObj)) { + if (!CheckGlobalObjectShape(cx, tm, f->globalObj)) { Backoff(cx, (jsbytecode*) localRootIP); return false; } @@ -5748,9 +5758,7 @@ AttemptToStabilizeTree(JSContext* cx, JSObject* globalObj, VMSideExit* exit, jsb if (*(jsbytecode*)from->ip == JSOP_NOP) return false; - return RecordTree(cx, tm, from->first, outer, outerArgc, globalObj, - globalShape, globalSlots, cx->fp->argc, - Record_Branch); + return RecordTree(cx, from->first, outer, outerArgc, globalSlots, Record_Branch); } static JS_REQUIRES_STACK VMFragment* @@ -5931,11 +5939,10 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall TreeFragment* outerFragment = root; jsbytecode* outer = (jsbytecode*) outerFragment->ip; uint32 outerArgc = outerFragment->argc; - uint32 argc = cx->fp->argc; + JS_ASSERT(cx->fp->argc == first->argc); AbortRecording(cx, "No compatible inner tree"); - return RecordTree(cx, tm, first, outer, outerArgc, globalObj, globalShape, - globalSlots, argc, Record_Branch); + return RecordTree(cx, first, outer, outerArgc, globalSlots, Record_Branch); } return r->attemptTreeCall(f, inlineCallCount) == ARECORD_CONTINUE; @@ -6909,8 +6916,7 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, RecordReason reason) * it will walk the peer list and find us a free slot or allocate a new * tree if needed. */ - bool rv = RecordTree(cx, tm, f->first, NULL, 0, globalObj, globalShape, - globalSlots, argc, reason); + bool rv = RecordTree(cx, f->first, NULL, 0, globalSlots, reason); #ifdef MOZ_TRACEVIS if (!rv) tvso.r = R_FAIL_RECORD_TREE; @@ -9818,8 +9824,8 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) SlotList* globalSlots = tree->globalSlots; TraceMonitor* tm = traceMonitor; AbortRecording(cx, "trying to compile inner recursive tree"); - if (RecordTree(_cx, tm, first, NULL, 0, first->globalObj, first->globalShape, - globalSlots, _cx->fp->argc, Record_EnterFrame)) { + JS_ASSERT(_cx->fp->argc == first->argc); + if (RecordTree(_cx, first, NULL, 0, globalSlots, Record_EnterFrame)) { JS_ASSERT(tm->recorder); } break; From 6a1644fbf0b6f10ee15e7d4433425484e860b0b9 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 10 Mar 2010 12:12:43 -0500 Subject: [PATCH 009/213] Bug 551118 followup. Need to conver spaces to 0, not NaN. r=jorendorff --- js/src/jsnum.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 3075e0b66218..5ca0b9b86790 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -448,7 +448,9 @@ StringToNumberType(JSContext *cx, JSString *str) if (str->length() == 1) { jschar c = str->chars()[0]; if ('0' <= c && c <= '9') - return NumberTraits::toSelfType(int32(c - '0')); + return NumberTraits::toSelfType(T(c - '0')); + if (JS_ISSPACE(c)) + return NumberTraits::toSelfType(T(0)); return NumberTraits::NaN(); } From 91914b8cd3e64fdd8eb24a638ba592cd5891f750 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 10 Mar 2010 18:28:44 -0500 Subject: [PATCH 010/213] Bug 551533. Use StringMatch in find_split instead of rolling our own search. r=lw --- js/src/jsstr.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 28f763c84969..1cd58ab86f42 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2020,7 +2020,7 @@ static jsint find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, JSSubString *sep) { - jsint i, j, k; + jsint i; size_t length; jschar *chars; @@ -2106,17 +2106,8 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, * occurrence of all of sep's chars. If we find them, return the index of * the first separator char. Otherwise, return length. */ - j = 0; - while ((size_t)(k = i + j) < length) { - if (chars[k] == sep->chars[j]) { - if ((size_t)++j == sep->length) - return i; - } else { - i++; - j = 0; - } - } - return k; + jsint match = StringMatch(chars + i, length - i, sep->chars, sep->length); + return match == -1 ? length : match + i; } static JSBool From c78f4378e43c7a47a2c766b357c53a326c3ae26d Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 10 Mar 2010 15:34:12 -0800 Subject: [PATCH 011/213] Bug 551276 - a more type-safe way to zero memory (r=Waldo) --HG-- extra : rebase_source : fc5564c34cde6490a1d3b48a16a451f7e50c052a --- js/src/jsarray.cpp | 4 ++-- js/src/jscntxt.cpp | 6 +++--- js/src/jscntxt.h | 2 +- js/src/jsdbgapi.cpp | 4 ++-- js/src/jsexn.cpp | 8 ++++---- js/src/jsfun.cpp | 4 ++-- js/src/jsgc.cpp | 8 ++++---- js/src/jsinterp.cpp | 2 +- js/src/jslock.cpp | 4 ++-- js/src/jsparse.h | 2 +- js/src/jsrecursion.cpp | 4 ++-- js/src/jsscan.cpp | 4 +++- js/src/jsscript.cpp | 2 +- js/src/jstl.h | 32 ++++++++++++++++++++++++++++++++ js/src/jstracer.cpp | 17 +++++++---------- js/src/jsutil.cpp | 5 ++++- 16 files changed, 71 insertions(+), 37 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 522386256790..7d0fa07616dc 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2202,7 +2202,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * initialization using memset. */ jsval *mergesort_tmp = vec + newlen; - memset(mergesort_tmp, 0, newlen * sizeof(jsval)); + PodZero(mergesort_tmp, newlen); tvr.changeLength(newlen * 2); /* Here len == 2 * (newlen + undefs + number_of_holes). */ @@ -2265,7 +2265,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) return false; } mergesort_tmp = vec + 2 * newlen; - memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval)); + PodZero(mergesort_tmp, newlen * 2); tvr.changeArray(vec, newlen * 4); elemsize = 2 * sizeof(jsval); } diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index ba235a5f608c..5f11e3ffaba1 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1364,7 +1364,7 @@ js_ReportOutOfMemory(JSContext *cx) const char *msg = efs ? efs->format : "Out of memory"; /* Fill out the report, but don't do anything that requires allocation. */ - memset(&report, 0, sizeof (struct JSErrorReport)); + PodZero(&report); report.flags = JSREPORT_ERROR; report.errorNumber = JSMSG_OUT_OF_MEMORY; PopulateReportBlame(cx, &report); @@ -1455,7 +1455,7 @@ js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap) return JS_FALSE; messagelen = strlen(message); - memset(&report, 0, sizeof (struct JSErrorReport)); + PodZero(&report); report.flags = flags; report.errorNumber = JSMSG_USER_DEFINED_ERROR; report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen); @@ -1647,7 +1647,7 @@ js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback, return JS_TRUE; warning = JSREPORT_IS_WARNING(flags); - memset(&report, 0, sizeof (struct JSErrorReport)); + PodZero(&report); report.flags = flags; report.errorNumber = errorNumber; PopulateReportBlame(cx, &report); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 00af9aab1990..15c3da0a2fc0 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -689,7 +689,7 @@ struct JSSetSlotRequest { /* Caching Class.prototype lookups for the standard classes. */ struct JSClassProtoCache { - void purge() { memset(entries, 0, sizeof(entries)); } + void purge() { js::PodArrayZero(entries); } #ifdef JS_PROTO_CACHE_METERING struct Stats { diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 05ba1230a0e6..34f0c46aa54b 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -697,9 +697,9 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) argv[0] = OBJECT_TO_JSVAL(closure); argv[1] = JSVAL_NULL; - memset(argv + 2, 0, (nslots - 2) * sizeof(jsval)); + PodZero(argv + 2, nslots - 2); - memset(&frame, 0, sizeof(frame)); + PodZero(&frame); frame.script = script; frame.regs = NULL; frame.fun = fun; diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index fea99f3133f6..478dac5505df 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -988,7 +988,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto)) return NULL; - memset(roots, 0, sizeof(roots)); + PodArrayZero(roots); AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); #ifdef __GNUC__ @@ -1146,7 +1146,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, cx->generatingError = JS_TRUE; /* Protect the newly-created strings below from nesting GCs. */ - memset(tv, 0, sizeof tv); + PodArrayZero(tv); AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv); /* @@ -1211,7 +1211,7 @@ js_ReportUncaughtException(JSContext *cx) if (!JS_GetPendingException(cx, &exn)) return false; - memset(roots, 0, sizeof roots); + PodArrayZero(roots); AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); /* @@ -1269,7 +1269,7 @@ js_ReportUncaughtException(JSContext *cx) return false; reportp = &report; - memset(&report, 0, sizeof report); + PodZero(&report); report.filename = filename; report.lineno = (uintN) lineno; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index ccd61484a105..de4fe92a0182 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1678,7 +1678,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) ok = false; goto release_mark; } - memset(bitmap, 0, bitmapLength * sizeof *bitmap); + PodZero(bitmap, bitmapLength); for (i = 0; i != n; ++i) { if (i < fun->nargs ? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL @@ -3035,7 +3035,7 @@ js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool) #if JS_HAS_DESTRUCTURING /* Some parameter names can be NULL due to destructuring patterns. */ - memset(names, 0, fun->nargs * sizeof *names); + PodZero(names, fun->nargs); #endif map = fun->u.i.names.map; args.fun = fun; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index f604570d8d4e..acdaa800f8be 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -359,7 +359,7 @@ struct JSGCArena { } void clearMarkBitmap() { - memset(markBitmap, 0, sizeof(markBitmap)); + PodArrayZero(markBitmap); } jsbitmap *getMarkBitmapEnd() { @@ -947,7 +947,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes) */ rt->setGCLastBytes(8192); - METER(memset(&rt->gcStats, 0, sizeof rt->gcStats)); + METER(PodZero(&rt->gcStats)); return true; } @@ -1402,7 +1402,7 @@ JSGCFreeLists::moveTo(JSGCFreeLists *another) { *another = *this; doubles = NULL; - memset(finalizables, 0, sizeof(finalizables)); + PodArrayZero(finalizables); JS_ASSERT(isEmpty()); } @@ -3088,7 +3088,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) #ifdef JS_TRACER if (gckind == GC_LAST_CONTEXT) { /* Clear builtin functions, which are recreated on demand. */ - memset(rt->builtinFunctions, 0, sizeof rt->builtinFunctions); + PodArrayZero(rt->builtinFunctions); } #endif diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 72cc90bf21d6..ad62f22afc58 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -504,7 +504,7 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) return; } - memset(cache->table, 0, sizeof cache->table); + PodArrayZero(cache->table); cache->empty = JS_TRUE; #ifdef JS_PROPERTY_CACHE_METERING diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index ed232d6f32fe..83e623d4e84b 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -317,7 +317,7 @@ js_InitLock(JSThinLock *tl) tl->owner = 0; tl->fat = (JSFatLock*)JS_NEW_LOCK(); #else - memset(tl, 0, sizeof(JSThinLock)); + PodZero(tl); #endif } @@ -1352,7 +1352,7 @@ js_InitTitle(JSContext *cx, JSTitle *title) { #ifdef JS_THREADSAFE title->ownercx = cx; - memset(&title->lock, 0, sizeof title->lock); + PodZero(&title->lock); /* * Set u.link = NULL, not u.count = 0, in case the target architecture's diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 04b15ff675dd..11fb854bcdbf 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -851,7 +851,7 @@ struct JSCompiler : private js::AutoGCRooter { aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL) { - memset(tempFreeList, 0, sizeof tempFreeList); + js::PodArrayZero(tempFreeList); setPrincipals(prin); JS_ASSERT_IF(cfp, cfp->script); } diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index 9b01ddce9568..0cd0af4f9452 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -175,7 +175,7 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame) VMSideExit* exit = (VMSideExit*) traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(TraceType) * exitTypeMapLen); - memset(exit, 0, sizeof(VMSideExit)); + PodZero(exit); exit->from = fragment; exit->calldepth = 0; JS_ASSERT(unsigned(exit->calldepth) == callDepth); @@ -450,7 +450,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) jsbytecode* recursive_pc = return_pc + JSOP_CALL_LENGTH; VMSideExit* exit = (VMSideExit*) traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(TraceType) * safeSlots); - memset(exit, 0, sizeof(VMSideExit)); + PodZero(exit); exit->pc = (jsbytecode*)recursive_pc; exit->from = fragment; exit->exitType = RECURSIVE_SLURP_FAIL_EXIT; diff --git a/js/src/jsscan.cpp b/js/src/jsscan.cpp index 403682b1559d..840843ea8111 100644 --- a/js/src/jsscan.cpp +++ b/js/src/jsscan.cpp @@ -77,6 +77,8 @@ #include "jsxml.h" #endif +using namespace js; + #define JS_KEYWORD(keyword, type, op, version) \ const char js_##keyword##_str[] = #keyword; #include "jskeyword.tbl" @@ -511,7 +513,7 @@ ReportCompileErrorNumberVA(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, warning = false; } - memset(&report, 0, sizeof report); + PodZero(&report); report.flags = flags; report.errorNumber = errorNumber; message = NULL; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 4e38b4434c51..f14552ff7960 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -829,7 +829,7 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, script = (JSScript *) cx->malloc(size); if (!script) return NULL; - memset(script, 0, sizeof(JSScript)); + PodZero(script); script->length = length; script->version = cx->version; diff --git a/js/src/jstl.h b/js/src/jstl.h index b0bcc3a3bfff..ddfe9675c9e3 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -43,6 +43,7 @@ #include "jsbit.h" #include +#include namespace js { @@ -296,6 +297,37 @@ class LazilyConstructed } }; +template +JS_ALWAYS_INLINE static void +PodZero(T *t) +{ + memset(t, 0, sizeof(T)); +} + +template +JS_ALWAYS_INLINE static void +PodZero(T *t, size_t nelem) +{ + memset(t, 0, nelem * sizeof(T)); +} + +/* + * Arrays implicitly convert to pointers to their first element, which is + * dangerous when combined with the above PodZero definitions. Adding an + * overload for arrays is ambiguous, so we need another identifier. The + * ambiguous overload is left to catch mistaken uses of PodZero; if you get a + * compile error involving PodZero and array types, use PodArrayZero instead. + */ +template static void PodZero(T (&)[N]); /* undefined */ +template static void PodZero(T (&)[N], size_t); /* undefined */ + +template +JS_ALWAYS_INLINE static void +PodArrayZero(T (&t)[N]) +{ + memset(t, 0, N * sizeof(T)); +} + } /* namespace js */ #endif /* jstl_h_ */ diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 2bebd42880d3..f06aa8f6f1ea 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -610,8 +610,8 @@ FragProfiling_showResults(TraceMonitor* tm) uint64_t totCount = 0, cumulCount; uint32_t totSE = 0; size_t totCodeB = 0, totExitB = 0; - memset(topFragID, 0, sizeof(topFragID)); - memset(topPI, 0, sizeof(topPI)); + PodArrayZero(topFragID); + PodArrayZero(topPI); FragStatsMap::Iter iter(*tm->profTab); while (iter.next()) { uint32_t fragID = iter.key(); @@ -2699,7 +2699,7 @@ TraceMonitor::flush() assembler = new (alloc) Assembler(*codeAlloc, alloc, alloc, core, &LogController, avmplus::AvmCore::config); verbose_only( branches = NULL; ) - memset(&vmfragments[0], 0, FRAGMENT_TABLE_SIZE * sizeof(TreeFragment*)); + PodArrayZero(vmfragments); reFragments = new (alloc) REHashMap(alloc); needFlush = JS_FALSE; @@ -7382,7 +7382,7 @@ InitJIT(TraceMonitor *tm) } tm->lastFragID = 0; #else - memset(&LogController, 0, sizeof(LogController)); + PodZero(&LogController); #endif if (!did_we_check_processor_features) { @@ -7431,7 +7431,7 @@ InitJIT(TraceMonitor *tm) verbose_only( tm->branches = NULL; ) #if !defined XP_WIN - debug_only(memset(&jitstats, 0, sizeof(jitstats))); + PodZero(&jitstats); #endif #ifdef JS_JIT_SPEW @@ -7526,7 +7526,7 @@ FinishJIT(TraceMonitor *tm) } #endif - memset(&tm->vmfragments[0], 0, FRAGMENT_TABLE_SIZE * sizeof(TreeFragment*)); + PodArrayZero(tm->vmfragments); if (tm->frameCache) { delete tm->frameCache; @@ -9822,12 +9822,9 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) RETURN_STOP_A("inner recursive tree is blacklisted"); JSContext* _cx = cx; SlotList* globalSlots = tree->globalSlots; - TraceMonitor* tm = traceMonitor; AbortRecording(cx, "trying to compile inner recursive tree"); JS_ASSERT(_cx->fp->argc == first->argc); - if (RecordTree(_cx, first, NULL, 0, globalSlots, Record_EnterFrame)) { - JS_ASSERT(tm->recorder); - } + RecordTree(_cx, first, NULL, 0, globalSlots, Record_EnterFrame); break; } } diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 679aa5fbca78..ad21141c40e8 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -46,6 +46,7 @@ #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" +#include "jstl.h" #ifdef WIN32 # include @@ -53,6 +54,8 @@ # include #endif +using namespace js; + /* * Checks the assumption that JS_FUNC_TO_DATA_PTR and JS_DATA_TO_FUNC_PTR * macros uses to implement casts between function and data pointers. @@ -140,7 +143,7 @@ JS_BasicStatsAccum(JSBasicStats *bs, uint32 val) if (newscale != oldscale) { uint32 newhist[11], newbin; - memset(newhist, 0, sizeof newhist); + PodArrayZero(newhist); for (bin = 0; bin <= 10; bin++) { newbin = ValToBin(newscale, BinToVal(oldscale, bin)); newhist[newbin] += bs->hist[bin]; From 4c90f806f88d0601a153944322b1ae821e6a8119 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 10 Mar 2010 15:48:53 -0800 Subject: [PATCH 012/213] Fix bustage on opt/NSPR builds --- js/src/jslock.cpp | 2 ++ js/src/jstracer.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index 83e623d4e84b..becfcc9d1106 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -56,6 +56,8 @@ #include "jsscope.h" #include "jsstr.h" +using namespace js; + #define ReadWord(W) (W) #if !defined(__GNUC__) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index f06aa8f6f1ea..486eb2f84857 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -7431,7 +7431,7 @@ InitJIT(TraceMonitor *tm) verbose_only( tm->branches = NULL; ) #if !defined XP_WIN - PodZero(&jitstats); + debug_only(PodZero(&jitstats)); #endif #ifdef JS_JIT_SPEW From 45318fdaaa4b1aef31c087db4e764d63c61a8917 Mon Sep 17 00:00:00 2001 From: Mike Moenig Date: Wed, 10 Mar 2010 21:02:18 -0800 Subject: [PATCH 013/213] Allow custom allocator use in SpiderMonkey (bug 549532, r=dvander). --- js/src/jsarena.h | 2 +- js/src/jscntxt.h | 9 ++++ js/src/jsgc.cpp | 4 -- js/src/jshash.cpp | 4 +- js/src/jslock.cpp | 2 +- js/src/jsrecursion.cpp | 4 +- js/src/jstl.h | 6 +-- js/src/jstracer.cpp | 106 ++++++++++++++++++++--------------------- js/src/jstracer.h | 31 ++++++++---- js/src/jsutil.h | 8 ++++ 10 files changed, 101 insertions(+), 75 deletions(-) diff --git a/js/src/jsarena.h b/js/src/jsarena.h index 47207f9fece7..ad2abd19ac6d 100644 --- a/js/src/jsarena.h +++ b/js/src/jsarena.h @@ -200,7 +200,7 @@ struct JSArenaPool { if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ *(pnext) = (a)->next; \ JS_CLEAR_ARENA(a); \ - free(a); \ + js_free(a); \ (a) = NULL; \ JS_END_MACRO diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 15c3da0a2fc0..931bd24cbc49 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -99,6 +99,7 @@ js_PurgeGSNCache(JSGSNCache *cache); #define JS_PURGE_GSN_CACHE(cx) js_PurgeGSNCache(&JS_GSN_CACHE(cx)) #define JS_METER_GSN_CACHE(cx,cnt) GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt) +#ifdef JS_TRACER /* Forward declarations of nanojit types. */ namespace nanojit { @@ -110,9 +111,11 @@ template class HashMap; template class Seq; } /* namespace nanojit */ +#endif namespace js { +#ifdef JS_TRACER /* Tracer constants. */ static const size_t MONITOR_N_GLOBAL_STATES = 4; static const size_t FRAGMENT_TABLE_SIZE = 512; @@ -217,6 +220,7 @@ struct TraceNativeStorage double *global() { return stack_global_buf + MAX_NATIVE_STACK_SLOTS; } FrameInfo **callstack() { return callstack_buf; } }; +#endif /* Holds data to track a single globa. */ struct GlobalState { @@ -326,12 +330,15 @@ class CallStack } }; +#ifdef JS_TRACER /* Holds the number of recording attemps for an address. */ typedef HashMap, SystemAllocPolicy> RecordAttemptMap; +class Oracle; + /* * Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not * JS_THREADSAFE) has an associated trace monitor that keeps track of loop @@ -393,6 +400,7 @@ struct TraceMonitor { nanojit::Assembler* assembler; FrameInfoCache* frameCache; + Oracle* oracle; TraceRecorder* recorder; GlobalState globalStates[MONITOR_N_GLOBAL_STATES]; @@ -451,6 +459,7 @@ struct TraceMonitor { }; } /* namespace js */ +#endif /* * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index acdaa800f8be..df9e27987e18 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3057,10 +3057,6 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) } #endif -#ifdef JS_TRACER - PurgeJITOracle(); -#endif - /* * Reset the property cache's type id generator so we can compress ids. * Same for the protoHazardShape proxy-shape standing in for all object diff --git a/js/src/jshash.cpp b/js/src/jshash.cpp index e347744e7319..15a8a460ab5c 100644 --- a/js/src/jshash.cpp +++ b/js/src/jshash.cpp @@ -67,7 +67,7 @@ static void * DefaultAllocTable(void *pool, size_t size) { - return malloc(size); + return js_malloc(size); } static void @@ -79,7 +79,7 @@ DefaultFreeTable(void *pool, void *item, size_t size) static JSHashEntry * DefaultAllocEntry(void *pool, const void *key) { - return (JSHashEntry*) malloc(sizeof(JSHashEntry)); + return (JSHashEntry*) js_malloc(sizeof(JSHashEntry)); } static void diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index becfcc9d1106..eaea40955bd7 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -839,7 +839,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v) static JSFatLock * NewFatlock() { - JSFatLock *fl = (JSFatLock *)malloc(sizeof(JSFatLock)); /* for now */ + JSFatLock *fl = (JSFatLock *)js_malloc(sizeof(JSFatLock)); /* for now */ if (!fl) return NULL; fl->susp = 0; fl->next = NULL; diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index 0cd0af4f9452..22ba2bc9cc27 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -121,8 +121,8 @@ class UpRecursiveSlotMap : public RecursiveSlotMap }; #if defined DEBUG -static JS_REQUIRES_STACK void -AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi) +JS_REQUIRES_STACK void +TraceRecorder::AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi) { JS_ASSERT(anchor->recursive_down); JS_ASSERT(anchor->recursive_down->callerHeight == fi->callerHeight); diff --git a/js/src/jstl.h b/js/src/jstl.h index ddfe9675c9e3..d6ae26fd86a5 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -242,9 +242,9 @@ PointerRangeSize(T *begin, T *end) class SystemAllocPolicy { public: - void *malloc(size_t bytes) { return ::malloc(bytes); } - void *realloc(void *p, size_t bytes) { return ::realloc(p, bytes); } - void free(void *p) { ::free(p); } + void *malloc(size_t bytes) { return js_malloc(bytes); } + void *realloc(void *p, size_t bytes) { return js_realloc(p, bytes); } + void free(void *p) { js_free(p); } void reportAllocOverflow() const {} }; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 486eb2f84857..cfb0d91193a6 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -107,7 +107,7 @@ nanojit::Allocator::allocChunk(size_t nbytes) { VMAllocator *vma = (VMAllocator*)this; JS_ASSERT(!vma->outOfMemory()); - void *p = calloc(1, nbytes); + void *p = js_calloc(nbytes); if (!p) { JS_ASSERT(nbytes < sizeof(vma->mReserve)); vma->mOutOfMemory = true; @@ -121,7 +121,7 @@ void nanojit::Allocator::freeChunk(void *p) { VMAllocator *vma = (VMAllocator*)this; if (p != &vma->mReserve[0]) - free(p); + js_free(p); } void @@ -394,6 +394,12 @@ static void DumpPeerStability(TraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape, uint32 argc); #endif +void +SetBuiltinError(JSContext *cx) +{ + cx->interpState->builtinStatus |= BUILTIN_ERROR; +} + /* * We really need a better way to configure the JIT. Shaver, where is * my fancy JIT object? @@ -909,12 +915,6 @@ TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3, LI } #endif -/* - * The entire VM shares one oracle. Collisions and concurrent updates are - * tolerated and worst case cause performance regressions. - */ -static Oracle oracle; - Tracker::Tracker() { pagelist = NULL; @@ -954,7 +954,7 @@ struct Tracker::TrackerPage* Tracker::addTrackerPage(const void* v) { jsuword base = getTrackerPageBase(v); - struct TrackerPage* p = (struct TrackerPage*) calloc(1, sizeof(*p)); + struct TrackerPage* p = (struct TrackerPage*) js_calloc(sizeof(*p)); p->base = base; p->next = pagelist; pagelist = p; @@ -967,7 +967,7 @@ Tracker::clear() while (pagelist) { TrackerPage* p = pagelist; pagelist = pagelist->next; - free(p); + js_free(p); } } @@ -1214,44 +1214,44 @@ Oracle::clearDemotability() _pcDontDemote.reset(); } -JS_REQUIRES_STACK static JS_INLINE void -MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot) +JS_REQUIRES_STACK void +TraceRecorder::MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot) { if (slot < f->nStackTypes) { - oracle.markStackSlotUndemotable(cx, slot); + oracle->markStackSlotUndemotable(cx, slot); return; } uint16* gslots = f->globalSlots->data(); - oracle.markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); + oracle->markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -JS_REQUIRES_STACK static JS_INLINE void -MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* pc) +JS_REQUIRES_STACK void +TraceRecorder::MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* pc) { if (slot < f->nStackTypes) { - oracle.markStackSlotUndemotable(cx, slot, pc); + oracle->markStackSlotUndemotable(cx, slot, pc); return; } uint16* gslots = f->globalSlots->data(); - oracle.markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); + oracle->markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -static JS_REQUIRES_STACK inline bool -IsSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* ip) +static JS_REQUIRES_STACK bool +IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot, const void* ip) { if (slot < f->nStackTypes) - return oracle.isStackSlotUndemotable(cx, slot, ip); + return oracle->isStackSlotUndemotable(cx, slot, ip); uint16* gslots = f->globalSlots->data(); - return oracle.isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); + return oracle->isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -static JS_REQUIRES_STACK inline bool -IsSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot) +static JS_REQUIRES_STACK bool +IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot) { - return IsSlotUndemotable(cx, f, slot, cx->fp->regs->pc); + return IsSlotUndemotable(oracle, cx, f, slot, cx->fp->regs->pc); } class FrameInfoCache @@ -1996,7 +1996,7 @@ public: visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { TraceType type = getCoercedType(*vp); if (type == TT_INT32 && - oracle.isGlobalSlotUndemotable(mCx, slot)) + JS_TRACE_MONITOR(mCx).oracle->isGlobalSlotUndemotable(mCx, slot)) type = TT_DOUBLE; JS_ASSERT(type != TT_JSVAL); debug_only_printf(LC_TMTracer, @@ -2010,7 +2010,7 @@ public: for (int i = 0; i < count; ++i) { TraceType type = getCoercedType(vp[i]); if (type == TT_INT32 && - oracle.isStackSlotUndemotable(mCx, length())) + JS_TRACE_MONITOR(mCx).oracle->isStackSlotUndemotable(mCx, length())) type = TT_DOUBLE; JS_ASSERT(type != TT_JSVAL); debug_only_printf(LC_TMTracer, @@ -2166,6 +2166,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag RecordReason recordReason) : cx(cx), traceMonitor(&JS_TRACE_MONITOR(cx)), + oracle(JS_TRACE_MONITOR(cx).oracle), fragment(fragment), tree(fragment->root), recordReason(recordReason), @@ -2688,6 +2689,7 @@ TraceMonitor::flush() codeAlloc->reset(); tempAlloc->reset(); reTempAlloc->reset(); + oracle->clear(); Allocator& alloc = *dataAlloc; @@ -3531,7 +3533,7 @@ TraceRecorder::importGlobalSlot(unsigned slot) int index = tree->globalSlots->offsetOf(uint16(slot)); if (index == -1) { type = getCoercedType(*vp); - if (type == TT_INT32 && oracle.isGlobalSlotUndemotable(cx, slot)) + if (type == TT_INT32 && oracle->isGlobalSlotUndemotable(cx, slot)) type = TT_DOUBLE; index = (int)tree->globalSlots->length(); tree->globalSlots->add(uint16(slot)); @@ -3762,7 +3764,7 @@ public: * Aggressively undo speculation so the inner tree will compile * if this fails. */ - oracle.markGlobalSlotUndemotable(mCx, slot); + mRecorder.oracle->markGlobalSlotUndemotable(mCx, slot); } JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32)); ++mTypeMap; @@ -3806,7 +3808,7 @@ public: * Aggressively undo speculation so the inner tree will compile * if this fails. */ - oracle.markStackSlotUndemotable(mCx, mSlotnum); + mRecorder.oracle->markStackSlotUndemotable(mCx, mSlotnum); } JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32)); ++vp; @@ -4427,7 +4429,7 @@ class SlotMap : public SlotVisitorBase { for (unsigned i = 0; i < length(); i++) { if (get(i).lastCheck == TypeCheck_Undemote) - MarkSlotUndemotable(mRecorder.cx, mRecorder.tree, i); + mRecorder.MarkSlotUndemotable(mRecorder.cx, mRecorder.tree, i); } } @@ -4752,7 +4754,7 @@ TypeMapLinkability(JSContext* cx, const TypeMap& typeMap, TreeFragment* peer) if (typeMap[i] == peerMap[i]) continue; if (typeMap[i] == TT_INT32 && peerMap[i] == TT_DOUBLE && - IsSlotUndemotable(cx, peer, i, peer->ip)) { + IsSlotUndemotable(JS_TRACE_MONITOR(cx).oracle, cx, peer, i, peer->ip)) { consensus = TypeConsensus_Undemotes; } else { return TypeConsensus_Bad; @@ -4761,8 +4763,8 @@ TypeMapLinkability(JSContext* cx, const TypeMap& typeMap, TreeFragment* peer) return consensus; } -static JS_REQUIRES_STACK unsigned -FindUndemotesInTypemaps(JSContext* cx, const TypeMap& typeMap, LinkableFragment* f, +JS_REQUIRES_STACK unsigned +TraceRecorder::FindUndemotesInTypemaps(JSContext* cx, const TypeMap& typeMap, LinkableFragment* f, Queue& undemotes) { undemotes.setLength(0); @@ -5647,6 +5649,7 @@ FindLoopEdgeTarget(JSContext* cx, VMSideExit* exit, TreeFragment** peerp) TreeFragment* from = exit->root(); JS_ASSERT(from->code()); + Oracle* oracle = JS_TRACE_MONITOR(cx).oracle; TypeMap typeMap(NULL); FullMapFromExit(typeMap, exit); @@ -5658,14 +5661,14 @@ FindLoopEdgeTarget(JSContext* cx, VMSideExit* exit, TreeFragment** peerp) if (typeMap[i] == TT_DOUBLE) { if (exit->exitType == RECURSIVE_UNLINKED_EXIT) { if (i < exit->numStackSlots) - oracle.markStackSlotUndemotable(cx, i, exit->recursive_pc); + oracle->markStackSlotUndemotable(cx, i, exit->recursive_pc); else - oracle.markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); + oracle->markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); } if (i < from->nStackTypes) - oracle.markStackSlotUndemotable(cx, i, from->ip); + oracle->markStackSlotUndemotable(cx, i, from->ip); else if (i >= exit->numStackSlots) - oracle.markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); + oracle->markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); } } @@ -6033,7 +6036,7 @@ TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount) } case OVERFLOW_EXIT: - oracle.markInstructionUndemotable(cx->fp->regs->pc); + oracle->markInstructionUndemotable(cx->fp->regs->pc); /* FALL THROUGH */ case RECURSIVE_SLURP_FAIL_EXIT: case RECURSIVE_SLURP_MISMATCH_EXIT: @@ -6135,10 +6138,10 @@ public: if (!IsEntryTypeCompatible(vp, mTypeMap)) { mOk = false; } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == TT_INT32) { - oracle.markGlobalSlotUndemotable(mCx, slot); + mRecorder.oracle->markGlobalSlotUndemotable(mCx, slot); mOk = false; } else if (JSVAL_IS_INT(*vp) && *mTypeMap == TT_DOUBLE) { - oracle.markGlobalSlotUndemotable(mCx, slot); + mRecorder.oracle->markGlobalSlotUndemotable(mCx, slot); } mTypeMap++; } @@ -6150,10 +6153,10 @@ public: if (!IsEntryTypeCompatible(vp, mTypeMap)) { mOk = false; } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == TT_INT32) { - oracle.markStackSlotUndemotable(mCx, mStackSlotNum); + mRecorder.oracle->markStackSlotUndemotable(mCx, mStackSlotNum); mOk = false; } else if (JSVAL_IS_INT(*vp) && *mTypeMap == TT_DOUBLE) { - oracle.markStackSlotUndemotable(mCx, mStackSlotNum); + mRecorder.oracle->markStackSlotUndemotable(mCx, mStackSlotNum); } vp++; mTypeMap++; @@ -6983,7 +6986,7 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, RecordReason reason) return rv; case OVERFLOW_EXIT: - oracle.markInstructionUndemotable(cx->fp->regs->pc); + tm->oracle->markInstructionUndemotable(cx->fp->regs->pc); /* FALL THROUGH */ case RECURSIVE_SLURP_FAIL_EXIT: case RECURSIVE_SLURP_MISMATCH_EXIT: @@ -7414,6 +7417,8 @@ InitJIT(TraceMonitor *tm) /* Set the default size for the code cache to 16MB. */ tm->maxCodeCacheBytes = 16 M; + tm->oracle = new Oracle(); + tm->recordAttempts = new RecordAttemptMap; if (!tm->recordAttempts->init(PC_HASH_COUNT)) abort(); @@ -7496,6 +7501,7 @@ FinishJIT(TraceMonitor *tm) #endif delete tm->recordAttempts; + delete tm->oracle; #ifdef DEBUG // Recover profiling data from expiring Fragments, and display @@ -7567,12 +7573,6 @@ FinishJIT(TraceMonitor *tm) tm->cachedTempTypeMap = NULL; } -void -PurgeJITOracle() -{ - oracle.clear(); -} - JS_REQUIRES_STACK void PurgeScriptFragments(JSContext* cx, JSScript* script) { @@ -8030,7 +8030,7 @@ TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1) * integers and the oracle must not give us a negative hint for the * instruction. */ - if (oracle.isInstructionUndemotable(cx->fp->regs->pc) || !isPromoteInt(s0) || !isPromoteInt(s1)) { + if (oracle->isInstructionUndemotable(cx->fp->regs->pc) || !isPromoteInt(s0) || !isPromoteInt(s1)) { out: if (v == LIR_fmod) { LIns* args[] = { s1, s0 }; @@ -10243,7 +10243,7 @@ TraceRecorder::record_JSOP_NEG() * a double. Only follow this path if we're not an integer that's 0 and * we're not a double that's zero. */ - if (!oracle.isInstructionUndemotable(cx->fp->regs->pc) && + if (!oracle->isInstructionUndemotable(cx->fp->regs->pc) && isPromoteInt(a) && (!JSVAL_IS_INT(v) || JSVAL_TO_INT(v) != 0) && (!JSVAL_IS_DOUBLE(v) || !JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) && @@ -15283,7 +15283,7 @@ StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval #endif /* MOZ_TRACEVIS */ JS_REQUIRES_STACK void -CaptureStackTypes(JSContext* cx, unsigned callDepth, TraceType* typeMap) +TraceRecorder::CaptureStackTypes(JSContext* cx, unsigned callDepth, TraceType* typeMap) { CaptureTypesVisitor capVisitor(cx, typeMap); VisitStackSlots(capVisitor, cx, callDepth); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 638cdbc6acf4..18f62ad2350b 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -78,7 +78,7 @@ public: memcpy(tmp, _data, _len * sizeof(T)); _data = tmp; } else { - _data = (T*)realloc(_data, _max * sizeof(T)); + _data = (T*)js_realloc(_data, _max * sizeof(T)); } #if defined(DEBUG) memset(&_data[_len], 0xcd, _max - _len); @@ -95,7 +95,7 @@ public: ~Queue() { if (!alloc) - free(_data); + js_free(_data); } bool contains(T a) { @@ -215,6 +215,8 @@ public: void clear(); }; +struct TreeFragment; + class VMFragment : public nanojit::Fragment { public: VMFragment(const void* _ip verbose_only(, uint32_t profFragID)) @@ -770,11 +772,8 @@ struct ArgsPrivateNative { } }; -static JS_INLINE void -SetBuiltinError(JSContext *cx) -{ - cx->interpState->builtinStatus |= BUILTIN_ERROR; -} +extern void +SetBuiltinError(JSContext *cx); #ifdef DEBUG_RECORDING_STATUS_NOT_BOOL /* #define DEBUG_RECORDING_STATUS_NOT_BOOL to detect misuses of RecordingStatus */ @@ -919,6 +918,9 @@ class TraceRecorder { /*************************************************************** Recording session constants */ + /* Cached oracle keeps track of hit counts for program counter locations */ + Oracle* oracle; + /* The context in which recording started. */ JSContext* const cx; @@ -1064,6 +1066,17 @@ class TraceRecorder */ JS_REQUIRES_STACK nanojit::GuardRecord* createGuardRecord(VMSideExit* exit); + JS_REQUIRES_STACK JS_INLINE void MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot); + + JS_REQUIRES_STACK JS_INLINE void MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* pc); + + JS_REQUIRES_STACK unsigned FindUndemotesInTypemaps(JSContext* cx, const TypeMap& typeMap, LinkableFragment* f, + Queue& undemotes); + + JS_REQUIRES_STACK void AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi); + + JS_REQUIRES_STACK void CaptureStackTypes(JSContext* cx, unsigned callDepth, TraceType* typeMap); + bool isGlobal(jsval* p) const; ptrdiff_t nativeGlobalSlot(jsval *p) const; ptrdiff_t nativeGlobalOffset(jsval* p) const; @@ -1385,8 +1398,8 @@ class TraceRecorder # include "jsopcode.tbl" #undef OPDEF - inline void* operator new(size_t size) { return calloc(1, size); } - inline void operator delete(void *p) { free(p); } + inline void* operator new(size_t size) { return js_calloc(size); } + inline void operator delete(void *p) { js_free(p); } JS_REQUIRES_STACK TraceRecorder(JSContext* cx, VMSideExit*, VMFragment*, diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 82e2f6bccd58..6a3aa33f732b 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -44,6 +44,7 @@ #ifndef jsutil_h___ #define jsutil_h___ +#include "jstypes.h" #include JS_BEGIN_EXTERN_C @@ -179,6 +180,12 @@ extern JS_FRIEND_API(void) JS_DumpBacktrace(JSCallsite *trace); #endif +#if defined JS_USE_CUSTOM_ALLOCATOR + +#include "jscustomallocator.h" + +#else + static JS_INLINE void* js_malloc(size_t bytes) { if (bytes < sizeof(void*)) /* for asyncFree */ bytes = sizeof(void*); @@ -200,6 +207,7 @@ static JS_INLINE void* js_realloc(void* p, size_t bytes) { static JS_INLINE void js_free(void* p) { free(p); } +#endif/* JS_USE_CUSTOM_ALLOCATOR */ JS_END_EXTERN_C From e9d974f4349a36763d40993d80495059d9b94f0a Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Thu, 11 Mar 2010 11:29:21 -0800 Subject: [PATCH 014/213] lightweight JSParseNode subclasses (bug 550350) --- js/src/jsparse.cpp | 320 ++++++++++++++++++++++----------------------- js/src/jsparse.h | 80 +++++++++++- 2 files changed, 233 insertions(+), 167 deletions(-) diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 4f279295dad4..88c9b26380f1 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -495,6 +495,10 @@ RecycleFuncNameKids(JSParseNode *pn, JSTreeContext *tc) } } +/* + * Allocate a JSParseNode from tc's node freelist or, failing that, from cx's + * temporary arena. + */ static JSParseNode * NewOrRecycledNode(JSTreeContext *tc) { @@ -569,24 +573,10 @@ NewOrRecycledNode(JSTreeContext *tc) return pn; } -static inline void -InitParseNode(JSParseNode *pn, JSTokenType type, JSOp op, JSParseNodeArity arity) -{ - pn->pn_type = type; - pn->pn_op = op; - pn->pn_arity = arity; - pn->pn_parens = false; - JS_ASSERT(!pn->pn_used); - JS_ASSERT(!pn->pn_defn); - pn->pn_next = pn->pn_link = NULL; -} +/* used only by static create methods of subclasses */ -/* - * Allocate a JSParseNode from tc's node freelist or, failing that, from cx's - * temporary arena. - */ -static JSParseNode * -NewParseNode(JSParseNodeArity arity, JSTreeContext *tc) +JSParseNode * +JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc) { JSParseNode *pn; JSToken *tp; @@ -595,38 +585,14 @@ NewParseNode(JSParseNodeArity arity, JSTreeContext *tc) if (!pn) return NULL; tp = &CURRENT_TOKEN(&tc->compiler->tokenStream); - InitParseNode(pn, tp->type, JSOP_NOP, arity); + pn->init(tp->type, JSOP_NOP, arity); pn->pn_pos = tp->pos; return pn; } -static inline void -InitNameNodeCommon(JSParseNode *pn, JSTreeContext *tc) -{ - pn->pn_expr = NULL; - pn->pn_cookie = FREE_UPVAR_COOKIE; - pn->pn_dflags = tc->atTopLevel() ? PND_TOPLEVEL : 0; - if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK) - pn->pn_dflags |= PND_BLOCKCHILD; - pn->pn_blockid = tc->blockid(); -} - -static JSParseNode * -NewNameNode(JSContext *cx, JSAtom *atom, JSTreeContext *tc) -{ - JSParseNode *pn; - - pn = NewParseNode(PN_NAME, tc); - if (pn) { - pn->pn_atom = atom; - InitNameNodeCommon(pn, tc); - } - return pn; -} - -static JSParseNode * -NewBinary(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, - JSTreeContext *tc) +JSParseNode * +JSParseNode::newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, + JSTreeContext *tc) { JSParseNode *pn, *pn1, *pn2; @@ -687,14 +653,42 @@ NewBinary(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, pn = NewOrRecycledNode(tc); if (!pn) return NULL; - InitParseNode(pn, tt, op, PN_BINARY); + pn->init(tt, op, PN_BINARY); pn->pn_pos.begin = left->pn_pos.begin; pn->pn_pos.end = right->pn_pos.end; pn->pn_left = left; pn->pn_right = right; - return pn; + return (BinaryNode *)pn; } +namespace js { + +inline void +NameNode::initCommon(JSTreeContext *tc) +{ + pn_expr = NULL; + pn_cookie = FREE_UPVAR_COOKIE; + pn_dflags = tc->atTopLevel() ? PND_TOPLEVEL : 0; + if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK) + pn_dflags |= PND_BLOCKCHILD; + pn_blockid = tc->blockid(); +} + +NameNode * +NameNode::create(JSAtom *atom, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = JSParseNode::create(PN_NAME, tc); + if (pn) { + pn->pn_atom = atom; + ((NameNode *)pn)->initCommon(tc); + } + return (NameNode *)pn; +} + +} /* namespace js */ + #if JS_HAS_GETTER_SETTER static JSTokenType CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) @@ -1260,8 +1254,7 @@ CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs) * pn is NULL. */ bool -CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, - JSParseNode *pn) +CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, JSParseNode *pn) { if (!tc->needStrictChecks()) return true; @@ -1282,7 +1275,7 @@ CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, * formals are legit given fun's strictness level, return true. Otherwise, * report an error and return false. Use pn for error position reporting, * unless we can find something more accurate in tc's decls. - * + * * In some cases the code to parse the argument list will already have noticed * the duplication; we could try to use that knowledge instead of re-checking * here. But since the strictness of the function's body determines what @@ -1359,7 +1352,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (CURRENT_TOKEN(ts).type == TOK_LC) { pn = Statements(cx, ts, tc); } else { - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (pn) { pn->pn_kid = AssignExpr(cx, ts, tc); if (!pn->pn_kid) { @@ -1405,8 +1398,7 @@ MakePlaceholder(JSParseNode *pn, JSTreeContext *tc) if (!ale) return NULL; - JSDefinition *dn = (JSDefinition *) - NewNameNode(tc->compiler->context, pn->pn_atom, tc); + JSDefinition *dn = (JSDefinition *)NameNode::create(pn->pn_atom, tc); if (!dn) return NULL; @@ -1588,7 +1580,7 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc) * but having TOK_NAME type and JSOP_NOP op. Insert it in a TOK_ARGSBODY * list node returned via pn->pn_body. */ - argpn = NewNameNode(tc->compiler->context, atom, tc); + argpn = NameNode::create(atom, tc); if (!argpn) return false; JS_ASSERT(PN_TYPE(argpn) == TOK_NAME && PN_OP(argpn) == JSOP_NOP); @@ -1600,7 +1592,7 @@ DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc) argsbody = pn->pn_body; if (!argsbody) { - argsbody = NewParseNode(PN_LIST, tc); + argsbody = ListNode::create(tc); if (!argsbody) return false; argsbody->pn_type = TOK_ARGSBODY; @@ -1645,7 +1637,7 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr /* FIXME: make Function format the source for a function definition. */ jsc.tokenStream.tokens[0].type = TOK_NAME; - JSParseNode *fn = NewParseNode(PN_FUNC, &funcg); + JSParseNode *fn = FunctionNode::create(&funcg); if (fn) { fn->pn_body = NULL; fn->pn_cookie = FREE_UPVAR_COOKIE; @@ -2028,7 +2020,7 @@ JSCompiler::markFunArgs(JSFunctionBox *funbox, uintN tcflags) * funarg if it is immediately applied. However, if its * name is used in an escaping function nested within * it, then it must become flagged as a funarg again. - * See bug 545980. + * See bug 545980. */ afunbox = funbox; uintN calleeLevel = UPVAR_FRAME_SKIP(lexdep->pn_cookie); @@ -2626,7 +2618,7 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSTreeContext *tc, if (funtc->lexdeps.count - foundCallee != 0) { JSParseNode *body = fn->pn_body; - fn->pn_body = NewParseNode(PN_NAMESET, tc); + fn->pn_body = NameSetNode::create(tc); if (!fn->pn_body) return false; @@ -2663,7 +2655,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, #if JS_HAS_GETTER_SETTER op = CURRENT_TOKEN(ts).t_op; #endif - pn = NewParseNode(PN_FUNC, tc); + pn = FunctionNode::create(tc); if (!pn) return NULL; pn->pn_body = NULL; @@ -2860,7 +2852,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * anonymous positional parameter into the destructuring * left-hand-side expression and accumulate it in list. */ - rhs = NewNameNode(cx, cx->runtime->atomState.emptyAtom, &funtc); + rhs = NameNode::create(cx->runtime->atomState.emptyAtom, &funtc); if (!rhs) return NULL; rhs->pn_type = TOK_NAME; @@ -2868,11 +2860,11 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, rhs->pn_cookie = MAKE_UPVAR_COOKIE(funtc.staticLevel, slot); rhs->pn_dflags |= PND_BOUND; - item = NewBinary(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc); + item = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc); if (!item) return NULL; if (!list) { - list = NewParseNode(PN_LIST, &funtc); + list = ListNode::create(&funtc); if (!list) return NULL; list->pn_type = TOK_COMMA; @@ -2889,7 +2881,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (!DefineArg(pn, atom, fun->nargs, &funtc)) return NULL; #ifdef JS_HAS_DESTRUCTURING - /* + /* * ECMA-262 requires us to support duplicate parameter names, but if the * parameter list includes destructuring, we consider the code to have * opted in to higher standards, and forbid duplicates. We may see a @@ -2975,7 +2967,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (body->pn_arity != PN_LIST) { JSParseNode *block; - block = NewParseNode(PN_LIST, tc); + block = ListNode::create(tc); if (!block) return NULL; block->pn_type = TOK_SEQ; @@ -2985,7 +2977,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, body = block; } - item = NewParseNode(PN_UNARY, tc); + item = UnaryNode::create(tc); if (!item) return NULL; @@ -3034,7 +3026,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * Edition 3 would have it). Backward compatibility must trump all, * unless JSOPTION_ANONFUNFIX is set. */ - result = NewParseNode(PN_UNARY, tc); + result = UnaryNode::create(tc); if (!result) return NULL; result->pn_type = TOK_SEMI; @@ -3135,7 +3127,7 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JS_CHECK_RECURSION(cx, return NULL); - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_LC; @@ -3444,7 +3436,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) JSParseNode *pnu = pn; if (pn->pn_defn) { - pnu = NewNameNode(cx, atom, tc); + pnu = NameNode::create(atom, tc); if (!pnu) return JS_FALSE; } @@ -3481,7 +3473,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) pn = ALE_DEFN(ale); tc->lexdeps.rawRemove(tc->compiler, ale, hep); } else { - JSParseNode *pn2 = NewNameNode(cx, atom, tc); + JSParseNode *pn2 = NameNode::create(atom, tc); if (!pn2) return JS_FALSE; @@ -4315,7 +4307,7 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return NULL; } - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; @@ -4381,7 +4373,7 @@ PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSObject *obj; JSObjectBox *blockbox; - pn = NewParseNode(PN_NAME, tc); + pn = LexicalScopeNode::create(tc); if (!pn) return NULL; @@ -4416,7 +4408,7 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LET); /* Create the let binary node. */ - pnlet = NewParseNode(PN_BINARY, tc); + pnlet = BinaryNode::create(tc); if (!pnlet) return NULL; @@ -4443,7 +4435,7 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop * the return value of the expression. */ - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_SEMI; @@ -4522,7 +4514,7 @@ NewBindingNode(JSAtom *atom, JSTreeContext *tc, bool let = false) } /* Make a new node for this declarator name (or destructuring pattern). */ - pn = NewNameNode(tc->compiler->context, atom, tc); + pn = NameNode::create(atom, tc); if (!pn) return NULL; return pn; @@ -4638,7 +4630,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case TOK_IF: /* An IF node has three kids: condition, then, and optional else. */ - pn = NewParseNode(PN_TERNARY, tc); + pn = TernaryNode::create(tc); if (!pn) return NULL; pn1 = Condition(cx, ts, tc); @@ -4672,7 +4664,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JSParseNode *pn5, *saveBlock; JSBool seenDefault = JS_FALSE; - pn = NewParseNode(PN_BINARY, tc); + pn = BinaryNode::create(tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH); @@ -4692,7 +4684,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1); /* pn2 is a list of case nodes. The default case has pn_left == NULL */ - pn2 = NewParseNode(PN_LIST, tc); + pn2 = ListNode::create(tc); if (!pn2) return NULL; pn2->makeEmpty(); @@ -4713,7 +4705,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* FALL THROUGH */ case TOK_CASE: - pn3 = NewParseNode(PN_BINARY, tc); + pn3 = BinaryNode::create(tc); if (!pn3) return NULL; if (tt == TOK_CASE) { @@ -4739,7 +4731,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); - pn4 = NewParseNode(PN_LIST, tc); + pn4 = ListNode::create(tc); if (!pn4) return NULL; pn4->pn_type = TOK_LC; @@ -4784,7 +4776,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } case TOK_WHILE: - pn = NewParseNode(PN_BINARY, tc); + pn = BinaryNode::create(tc); if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); @@ -4801,7 +4793,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn; case TOK_DO: - pn = NewParseNode(PN_BINARY, tc); + pn = BinaryNode::create(tc); if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); @@ -4836,7 +4828,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #endif /* A FOR node is binary, left is loop control and right is the body. */ - pn = NewParseNode(PN_BINARY, tc); + pn = BinaryNode::create(tc); if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); @@ -4972,7 +4964,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) || pn2->pn_type == TOK_ASSIGN #endif ) { - pnseq = NewParseNode(PN_LIST, tc); + pnseq = ListNode::create(tc); if (!pnseq) return NULL; pnseq->pn_type = TOK_SEQ; @@ -4984,7 +4976,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * Hoist just the 'i' from 'for (let x = i in o)' to * before the loop, glued together via pnseq. */ - pn3 = NewParseNode(PN_UNARY, tc); + pn3 = UnaryNode::create(tc); if (!pn3) return NULL; pn3->pn_type = TOK_SEMI; @@ -5030,7 +5022,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #endif { JS_ASSERT(pn2->pn_type == TOK_NAME); - pn1 = NewNameNode(cx, pn2->pn_atom, tc); + pn1 = NameNode::create(pn2->pn_atom, tc); if (!pn1) return NULL; pn1->pn_type = TOK_NAME; @@ -5104,7 +5096,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) tc->topStmt = save; #endif - pn2 = NewBinary(TOK_IN, JSOP_NOP, pn1, pn2, tc); + pn2 = JSParseNode::newBinaryOrAppend(TOK_IN, JSOP_NOP, pn1, pn2, tc); if (!pn2) return NULL; pn->pn_left = pn2; @@ -5140,7 +5132,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } /* Build the FORHEAD node to use as the left kid of pn. */ - pn4 = NewParseNode(PN_TERNARY, tc); + pn4 = TernaryNode::create(tc); if (!pn4) return NULL; pn4->pn_type = TOK_FORHEAD; @@ -5203,7 +5195,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * * finally nodes are TOK_LC Statement lists. */ - pn = NewParseNode(PN_TERNARY, tc); + pn = TernaryNode::create(tc); if (!pn) return NULL; pn->pn_op = JSOP_NOP; @@ -5220,7 +5212,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) catchList = NULL; tt = js_GetToken(cx, ts); if (tt == TOK_CATCH) { - catchList = NewParseNode(PN_LIST, tc); + catchList = ListNode::create(tc); if (!catchList) return NULL; catchList->pn_type = TOK_RESERVED; @@ -5254,7 +5246,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * where lhs is a name or a destructuring left-hand side. * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) */ - pn2 = NewParseNode(PN_TERNARY, tc); + pn2 = TernaryNode::create(tc); if (!pn2) return NULL; pnblock->pn_expr = pn2; @@ -5349,7 +5341,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } case TOK_THROW: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; @@ -5385,7 +5377,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return NULL; case TOK_BREAK: - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; if (!MatchLabel(cx, ts, pn)) @@ -5418,7 +5410,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) break; case TOK_CONTINUE: - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; if (!MatchLabel(cx, ts, pn)) @@ -5476,7 +5468,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return NULL; } - pn = NewParseNode(PN_BINARY, tc); + pn = BinaryNode::create(tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH); @@ -5606,7 +5598,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #endif /* Create a new lexical scope node for these statements. */ - pn1 = NewParseNode(PN_NAME, tc); + pn1 = LexicalScopeNode::create(tc); if (!pn1) return NULL; @@ -5662,7 +5654,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case TOK_EOL: case TOK_SEMI: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_SEMI; @@ -5670,7 +5662,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #if JS_HAS_DEBUGGER_KEYWORD case TOK_DEBUGGER: - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_DEBUGGER; @@ -5680,7 +5672,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #if JS_HAS_XML_SUPPORT case TOK_DEFAULT: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; if (!js_MatchToken(cx, ts, TOK_NAME) || @@ -5757,7 +5749,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn2; } - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_SEMI; @@ -5846,7 +5838,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) } data.op = let ? JSOP_NOP : CURRENT_TOKEN(ts).t_op; - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; pn->pn_op = data.op; @@ -5904,7 +5896,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) if (!init || !UndominateInitializers(pn2, init, tc)) return NULL; - pn2 = NewBinary(TOK_ASSIGN, JSOP_NOP, pn2, init, tc); + pn2 = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, pn2, init, tc); if (!pn2) return NULL; pn->append(pn2); @@ -5999,7 +5991,7 @@ Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = AssignExpr(cx, ts, tc); if (pn && js_MatchToken(cx, ts, TOK_COMMA)) { - pn2 = NewParseNode(PN_LIST, tc); + pn2 = ListNode::create(tc); if (!pn2) return NULL; pn2->pn_pos.begin = pn->pn_pos.begin; @@ -6085,7 +6077,7 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) rhs = AssignExpr(cx, ts, tc); if (!rhs || !CheckDestructuring(cx, NULL, pn, rhs, tc)) return NULL; - return NewBinary(TOK_ASSIGN, op, pn, rhs, tc); + return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc); #endif case TOK_LP: if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) @@ -6122,7 +6114,7 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } } - return NewBinary(TOK_ASSIGN, op, pn, rhs, tc); + return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc); } static JSParseNode * @@ -6134,7 +6126,7 @@ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = OrExpr(cx, ts, tc); if (pn && js_MatchToken(cx, ts, TOK_HOOK)) { pn1 = pn; - pn = NewParseNode(PN_TERNARY, tc); + pn = TernaryNode::create(tc); if (!pn) return NULL; /* @@ -6169,7 +6161,7 @@ OrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = AndExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_OR)) - pn = NewBinary(TOK_OR, JSOP_OR, pn, AndExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, AndExpr(cx, ts, tc), tc); return pn; } @@ -6180,7 +6172,7 @@ AndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = BitOrExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_AND)) - pn = NewBinary(TOK_AND, JSOP_AND, pn, BitOrExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, BitOrExpr(cx, ts, tc), tc); return pn; } @@ -6191,8 +6183,7 @@ BitOrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = BitXorExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_BITOR)) { - pn = NewBinary(TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc), - tc); + pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc), tc); } return pn; } @@ -6204,8 +6195,8 @@ BitXorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = BitAndExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_BITXOR)) { - pn = NewBinary(TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc), - tc); + pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc), + tc); } return pn; } @@ -6217,7 +6208,7 @@ BitAndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = EqExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_BITAND)) - pn = NewBinary(TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc); return pn; } @@ -6230,7 +6221,7 @@ EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = RelExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_EQOP)) { op = CURRENT_TOKEN(ts).t_op; - pn = NewBinary(TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc); } return pn; } @@ -6260,7 +6251,7 @@ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) js_MatchToken(cx, ts, TOK_INSTANCEOF))) { tt = CURRENT_TOKEN(ts).type; op = CURRENT_TOKEN(ts).t_op; - pn = NewBinary(tt, op, pn, ShiftExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(tt, op, pn, ShiftExpr(cx, ts, tc), tc); } /* Restore previous state of inForInit flag. */ tc->flags |= inForInitFlag; @@ -6277,7 +6268,7 @@ ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = AddExpr(cx, ts, tc); while (pn && js_MatchToken(cx, ts, TOK_SHOP)) { op = CURRENT_TOKEN(ts).t_op; - pn = NewBinary(TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc); } return pn; } @@ -6295,7 +6286,7 @@ AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) js_MatchToken(cx, ts, TOK_MINUS))) { tt = CURRENT_TOKEN(ts).type; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; - pn = NewBinary(tt, op, pn, MulExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(tt, op, pn, MulExpr(cx, ts, tc), tc); } return pn; } @@ -6313,7 +6304,7 @@ MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) js_MatchToken(cx, ts, TOK_DIVOP))) { tt = CURRENT_TOKEN(ts).type; op = CURRENT_TOKEN(ts).t_op; - pn = NewBinary(tt, op, pn, UnaryExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(tt, op, pn, UnaryExpr(cx, ts, tc), tc); } return pn; } @@ -6406,7 +6397,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case TOK_UNARYOP: case TOK_PLUS: case TOK_MINUS: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */ @@ -6420,7 +6411,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case TOK_INC: case TOK_DEC: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn2 = MemberExpr(cx, ts, tc, JS_TRUE); @@ -6432,7 +6423,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) break; case TOK_DELETE: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn2 = UnaryExpr(cx, ts, tc); @@ -6480,7 +6471,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) ts->flags &= ~TSF_OPERAND; if (tt == TOK_INC || tt == TOK_DEC) { (void) js_GetToken(cx, ts); - pn2 = NewParseNode(PN_UNARY, tc); + pn2 = UnaryNode::create(tc); if (!pn2) return NULL; if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE)) @@ -6674,8 +6665,7 @@ CompExprTransplanter::transplant(JSParseNode *pn) if (dn->pn_pos >= root->pn_pos) { tc->parent->lexdeps.remove(tc->compiler, atom); } else { - JSDefinition *dn2 = (JSDefinition *) - NewNameNode(tc->compiler->context, dn->pn_atom, tc); + JSDefinition *dn2 = (JSDefinition *)NameNode::create(dn->pn_atom, tc); if (!dn2) return false; @@ -6793,7 +6783,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, * index to count each block-local let-variable on the left-hand side * of the IN. */ - pn2 = NewParseNode(PN_BINARY, tc); + pn2 = BinaryNode::create(tc); if (!pn2) return NULL; @@ -6882,7 +6872,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, default:; } - pn2->pn_left = NewBinary(TOK_IN, JSOP_NOP, pn3, pn4, tc); + pn2->pn_left = JSParseNode::newBinaryOrAppend(TOK_IN, JSOP_NOP, pn3, pn4, tc); if (!pn2->pn_left) return NULL; *pnp = pn2; @@ -6890,7 +6880,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, } while (js_MatchToken(cx, ts, TOK_FOR)); if (js_MatchToken(cx, ts, TOK_IF)) { - pn2 = NewParseNode(PN_TERNARY, tc); + pn2 = TernaryNode::create(tc); if (!pn2) return NULL; pn2->pn_kid1 = Condition(cx, ts, tc); @@ -6900,7 +6890,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, pnp = &pn2->pn_kid2; } - pn2 = NewParseNode(PN_UNARY, tc); + pn2 = UnaryNode::create(tc); if (!pn2) return NULL; pn2->pn_type = type; @@ -6942,7 +6932,7 @@ GeneratorExpr(JSParseNode *pn, JSParseNode *kid, JSTreeContext *tc) pn->pn_hidden = true; /* Make a new node for the desugared generator function. */ - JSParseNode *genfn = NewParseNode(PN_FUNC, tc); + JSParseNode *genfn = FunctionNode::create(tc); if (!genfn) return NULL; genfn->pn_type = TOK_FUNCTION; @@ -6998,7 +6988,7 @@ GeneratorExpr(JSParseNode *pn, JSParseNode *kid, JSTreeContext *tc) * Our result is a call expression that invokes the anonymous generator * function object. */ - JSParseNode *result = NewParseNode(PN_LIST, tc); + JSParseNode *result = ListNode::create(tc); if (!result) return NULL; result->pn_type = TOK_LP; @@ -7039,7 +7029,7 @@ ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, #endif #if JS_HAS_GENERATOR_EXPRS if (js_MatchToken(cx, ts, TOK_FOR)) { - JSParseNode *pn = NewParseNode(PN_UNARY, tc); + JSParseNode *pn = UnaryNode::create(tc); if (!pn) return JS_FALSE; argNode = GeneratorExpr(pn, argNode, tc); @@ -7095,7 +7085,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, tt = js_GetToken(cx, ts); ts->flags &= ~TSF_OPERAND; if (tt == TOK_NEW) { - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; pn2 = MemberExpr(cx, ts, tc, JS_FALSE); @@ -7137,7 +7127,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, while ((tt = js_GetToken(cx, ts)) > TOK_EOF) { if (tt == TOK_DOT) { - pn2 = NewNameNode(cx, NULL, tc); + pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; #if JS_HAS_XML_SUPPORT @@ -7185,7 +7175,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; #if JS_HAS_XML_SUPPORT } else if (tt == TOK_DBLDOT) { - pn2 = NewParseNode(PN_BINARY, tc); + pn2 = BinaryNode::create(tc); if (!pn2) return NULL; ts->flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; @@ -7211,7 +7201,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; #endif } else if (tt == TOK_LB) { - pn2 = NewParseNode(PN_BINARY, tc); + pn2 = BinaryNode::create(tc); if (!pn2) return NULL; pn3 = Expr(cx, ts, tc); @@ -7250,7 +7240,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->pn_right = pn3; } while (0); } else if (allowCallSyntax && tt == TOK_LP) { - pn2 = NewParseNode(PN_LIST, tc); + pn2 = ListNode::create(tc); if (!pn2) return NULL; pn2->pn_op = JSOP_CALL; @@ -7382,7 +7372,7 @@ PropertySelector(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) { JSParseNode *pn; - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; if (pn->pn_type == TOK_STAR) { @@ -7407,7 +7397,7 @@ QualifiedSuffix(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, JSTokenType tt; JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_DBLCOLON); - pn2 = NewNameNode(cx, NULL, tc); + pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; @@ -7471,7 +7461,7 @@ AttributeIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JSTokenType tt; JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_AT); - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_op = JSOP_TOATTRNAME; @@ -7503,7 +7493,7 @@ XMLExpr(JSContext *cx, JSTokenStream *ts, JSBool inTag, JSTreeContext *tc) uintN oldflag; JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LC); - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; @@ -7538,7 +7528,7 @@ XMLAtomNode(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JSParseNode *pn; JSToken *tp; - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; tp = &CURRENT_TOKEN(ts); @@ -7585,7 +7575,7 @@ XMLNameExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = pn2; } else { if (!list) { - list = NewParseNode(PN_LIST, tc); + list = ListNode::create(tc); if (!list) return NULL; list->pn_type = TOK_XMLNAME; @@ -7652,7 +7642,7 @@ XMLTagContent(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (!pn2) return NULL; if (!list) { - list = NewParseNode(PN_LIST, tc); + list = ListNode::create(tc); if (!list) return NULL; list->pn_type = tagtype; @@ -7779,7 +7769,7 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JS_CHECK_RECURSION(cx, return NULL); JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLSTAGO); - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; @@ -7828,7 +7818,7 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (!XML_FOLDABLE(pn2)) pn->pn_xflags |= PNX_CANTFOLD; pn2 = pn; - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; } @@ -7876,7 +7866,7 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* Make a TOK_XMLETAGO list with pn2 as its single child. */ JS_ASSERT(pn2->pn_type == TOK_XMLNAME || pn2->pn_type == TOK_LC); - list = NewParseNode(PN_LIST, tc); + list = ListNode::create(tc); if (!list) return NULL; list->pn_type = TOK_XMLETAGO; @@ -8021,7 +8011,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, ts->flags |= TSF_KEYWORD_IS_NAME; if (js_MatchToken(cx, ts, TOK_DBLCOLON)) { ts->flags &= ~TSF_KEYWORD_IS_NAME; - pn2 = NewParseNode(PN_NULLARY, tc); + pn2 = NullaryNode::create(tc); if (!pn2) return NULL; pn2->pn_type = TOK_FUNCTION; @@ -8042,7 +8032,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool matched; jsuint index; - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_RB; @@ -8075,7 +8065,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (tt == TOK_COMMA) { /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ js_MatchToken(cx, ts, TOK_COMMA); - pn2 = NewParseNode(PN_NULLARY, tc); + pn2 = NullaryNode::create(tc); pn->pn_xflags |= PNX_HOLEY; } else { pn2 = AssignExpr(cx, ts, tc); @@ -8182,7 +8172,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, */ JSAutoAtomList seen(tc->compiler); - pn = NewParseNode(PN_LIST, tc); + pn = ListNode::create(tc); if (!pn) return NULL; pn->pn_type = TOK_RC; @@ -8197,7 +8187,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, ts->flags &= ~TSF_KEYWORD_IS_NAME; switch (tt) { case TOK_NUMBER: - pn3 = NewParseNode(PN_NULLARY, tc); + pn3 = NullaryNode::create(tc); if (!pn3) return NULL; pn3->pn_dval = CURRENT_TOKEN(ts).t_dval; @@ -8225,7 +8215,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, goto property_name; } atom = CURRENT_TOKEN(ts).t_atom; - pn3 = NewNameNode(cx, atom, tc); + pn3 = NameNode::create(atom, tc); if (!pn3) return NULL; @@ -8233,14 +8223,14 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, CURRENT_TOKEN(ts).t_op = JSOP_NOP; CURRENT_TOKEN(ts).type = TOK_FUNCTION; pn2 = FunctionExpr(cx, ts, tc); - pn2 = NewBinary(TOK_COLON, op, pn3, pn2, tc); + pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pn2, tc); goto skip; } property_name: #endif case TOK_STRING: atom = CURRENT_TOKEN(ts).t_atom; - pn3 = NewParseNode(PN_NULLARY, tc); + pn3 = NullaryNode::create(tc); if (!pn3) return NULL; pn3->pn_atom = atom; @@ -8285,12 +8275,12 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pnval = pn3; if (pnval->pn_type == TOK_NAME) { pnval->pn_arity = PN_NAME; - InitNameNodeCommon(pnval, tc); + ((NameNode *)pnval)->initCommon(tc); } #endif } - pn2 = NewBinary(TOK_COLON, op, pn3, pnval, tc); + pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pnval, tc); #if JS_HAS_GETTER_SETTER skip: #endif @@ -8302,7 +8292,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * In strict mode code, check for duplicate property names. Treat * getters and setters as distinct attributes of each property. A * plain old value conflicts with a getter or a setter. - */ + */ if (tc->needStrictChecks()) { unsigned attributesMask; if (op == JSOP_INITPROP) { @@ -8333,7 +8323,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return NULL; ALE_SET_INDEX(ale, attributesMask); } - } + } tt = js_GetToken(cx, ts); if (tt == TOK_RC) @@ -8361,7 +8351,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, #if JS_HAS_SHARP_VARS case TOK_DEFSHARP: - pn = NewParseNode(PN_UNARY, tc); + pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_num = (jsint) CURRENT_TOKEN(ts).t_dval; @@ -8387,7 +8377,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, case TOK_USESHARP: /* Check for forward/dangling references at runtime, to allow eval. */ - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; if (!tc->ensureSharpSlots()) @@ -8439,7 +8429,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, case TOK_XMLCOMMENT: case TOK_XMLPI: #endif - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; pn->pn_atom = CURRENT_TOKEN(ts).t_atom; @@ -8452,7 +8442,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, break; case TOK_NAME: - pn = NewNameNode(cx, CURRENT_TOKEN(ts).t_atom, tc); + pn = NameNode::create(CURRENT_TOKEN(ts).t_atom, tc); if (!pn) return NULL; JS_ASSERT(CURRENT_TOKEN(ts).t_op == JSOP_NAME); @@ -8589,7 +8579,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, { JSObject *obj; - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; @@ -8613,7 +8603,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } case TOK_NUMBER: - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; pn->pn_op = JSOP_DOUBLE; @@ -8621,7 +8611,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, break; case TOK_PRIMARY: - pn = NewParseNode(PN_NULLARY, tc); + pn = NullaryNode::create(tc); if (!pn) return NULL; pn->pn_op = CURRENT_TOKEN(ts).t_op; @@ -8670,7 +8660,7 @@ ParenExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return NULL; } if (!pn1) { - pn1 = NewParseNode(PN_UNARY, tc); + pn1 = UnaryNode::create(tc); if (!pn1) return NULL; } diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 11fb854bcdbf..793641d480de 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -386,6 +386,23 @@ struct JSParseNode { #define pn_dval pn_u.dval #define pn_atom2 pn_u.apair.atom2 +protected: + void inline init(JSTokenType type, JSOp op, JSParseNodeArity arity) { + pn_type = type; + pn_op = op; + pn_arity = arity; + pn_parens = false; + JS_ASSERT(!pn_used); + JS_ASSERT(!pn_defn); + pn_next = pn_link = NULL; + } + + static JSParseNode *create(JSParseNodeArity arity, JSTreeContext *tc); + +public: + static JSParseNode *newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, + JSParseNode *right, JSTreeContext *tc); + /* * The pn_expr and lexdef members are arms of an unsafe union. Unless you * know exactly what you're doing, use only the following methods to access @@ -481,7 +498,7 @@ struct JSParseNode { (PN_TYPE(this) == TOK_PRIMARY && PN_OP(this) != JSOP_THIS); } - /* + /* * True if this statement node could be a member of a Directive * Prologue. Note that the prologue may contain strings that * cannot themselves be directives; that's a stricter test. @@ -505,7 +522,8 @@ struct JSParseNode { JS_ASSERT(isDirectivePrologueMember()); JSParseNode *kid = pn_kid; JSString *str = ATOM_TO_STRING(kid->pn_atom); - /* + + /* * Directives must contain no EscapeSequences or LineContinuations. * If the string's length in the source code is its length as a value, * accounting for the quotes, then it qualifies. @@ -550,6 +568,64 @@ struct JSParseNode { } }; +namespace js { + +struct NullaryNode : public JSParseNode { + static inline NullaryNode *create(JSTreeContext *tc) { + return (NullaryNode *)JSParseNode::create(PN_NULLARY, tc); + } +}; + +struct UnaryNode : public JSParseNode { + static inline UnaryNode *create(JSTreeContext *tc) { + return (UnaryNode *)JSParseNode::create(PN_UNARY, tc); + } +}; + +struct BinaryNode : public JSParseNode { + static inline BinaryNode *create(JSTreeContext *tc) { + return (BinaryNode *)JSParseNode::create(PN_BINARY, tc); + } +}; + +struct TernaryNode : public JSParseNode { + static inline TernaryNode *create(JSTreeContext *tc) { + return (TernaryNode *)JSParseNode::create(PN_TERNARY, tc); + } +}; + +struct ListNode : public JSParseNode { + static inline ListNode *create(JSTreeContext *tc) { + return (ListNode *)JSParseNode::create(PN_LIST, tc); + } +}; + +struct FunctionNode : public JSParseNode { + static inline FunctionNode *create(JSTreeContext *tc) { + return (FunctionNode *)JSParseNode::create(PN_FUNC, tc); + } +}; + +struct NameNode : public JSParseNode { + static NameNode *create(JSAtom *atom, JSTreeContext *tc); + + void inline initCommon(JSTreeContext *tc); +}; + +struct NameSetNode : public JSParseNode { + static inline NameSetNode *create(JSTreeContext *tc) { + return (NameSetNode *)JSParseNode::create(PN_NAMESET, tc); + } +}; + +struct LexicalScopeNode : public JSParseNode { + static inline LexicalScopeNode *create(JSTreeContext *tc) { + return (LexicalScopeNode *)JSParseNode::create(PN_NAME, tc); + } +}; + +} /* namespace js */ + /* * JSDefinition is a degenerate subtype of the PN_FUNC and PN_NAME variants of * JSParseNode, allocated only for function, var, const, and let declarations From 78327d68b8d9e5f2b1745c2dc5780fe3b7da442e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Mar 2010 11:40:44 -0800 Subject: [PATCH 015/213] Fixed warnings from the tracer oracle (no bug, rs=brendan). --- js/src/jstracer.cpp | 6 ------ js/src/jstracer.h | 6 +++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index cfb0d91193a6..7209c8436d85 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1248,12 +1248,6 @@ IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned s return oracle->isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -static JS_REQUIRES_STACK bool -IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot) -{ - return IsSlotUndemotable(oracle, cx, f, slot, cx->fp->regs->pc); -} - class FrameInfoCache { struct HashPolicy diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 18f62ad2350b..dc0e041a66d6 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -918,15 +918,15 @@ class TraceRecorder { /*************************************************************** Recording session constants */ - /* Cached oracle keeps track of hit counts for program counter locations */ - Oracle* oracle; - /* The context in which recording started. */ JSContext* const cx; /* Cached value of JS_TRACE_MONITOR(cx). */ TraceMonitor* const traceMonitor; + /* Cached oracle keeps track of hit counts for program counter locations */ + Oracle* oracle; + /* The Fragment being recorded by this recording session. */ VMFragment* const fragment; From 26c81162af08bd24f4538599828ab7d2b7c57887 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Mar 2010 12:15:21 -0800 Subject: [PATCH 016/213] Backed out changeset 887a3e05324c. --- js/src/jstracer.cpp | 6 ++++++ js/src/jstracer.h | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 7209c8436d85..cfb0d91193a6 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1248,6 +1248,12 @@ IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned s return oracle->isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } +static JS_REQUIRES_STACK bool +IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot) +{ + return IsSlotUndemotable(oracle, cx, f, slot, cx->fp->regs->pc); +} + class FrameInfoCache { struct HashPolicy diff --git a/js/src/jstracer.h b/js/src/jstracer.h index dc0e041a66d6..18f62ad2350b 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -918,15 +918,15 @@ class TraceRecorder { /*************************************************************** Recording session constants */ + /* Cached oracle keeps track of hit counts for program counter locations */ + Oracle* oracle; + /* The context in which recording started. */ JSContext* const cx; /* Cached value of JS_TRACE_MONITOR(cx). */ TraceMonitor* const traceMonitor; - /* Cached oracle keeps track of hit counts for program counter locations */ - Oracle* oracle; - /* The Fragment being recorded by this recording session. */ VMFragment* const fragment; From 87abf060978dcf6cec4da7fdebc93ddab087f46e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Mar 2010 12:19:36 -0800 Subject: [PATCH 017/213] Backed out changeset 04023ea0fb08. --- js/src/jsarena.h | 2 +- js/src/jscntxt.h | 9 ---- js/src/jsgc.cpp | 4 ++ js/src/jshash.cpp | 4 +- js/src/jslock.cpp | 2 +- js/src/jsrecursion.cpp | 4 +- js/src/jstl.h | 6 +-- js/src/jstracer.cpp | 106 ++++++++++++++++++++--------------------- js/src/jstracer.h | 31 ++++-------- js/src/jsutil.h | 8 ---- 10 files changed, 75 insertions(+), 101 deletions(-) diff --git a/js/src/jsarena.h b/js/src/jsarena.h index ad2abd19ac6d..47207f9fece7 100644 --- a/js/src/jsarena.h +++ b/js/src/jsarena.h @@ -200,7 +200,7 @@ struct JSArenaPool { if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ *(pnext) = (a)->next; \ JS_CLEAR_ARENA(a); \ - js_free(a); \ + free(a); \ (a) = NULL; \ JS_END_MACRO diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 931bd24cbc49..15c3da0a2fc0 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -99,7 +99,6 @@ js_PurgeGSNCache(JSGSNCache *cache); #define JS_PURGE_GSN_CACHE(cx) js_PurgeGSNCache(&JS_GSN_CACHE(cx)) #define JS_METER_GSN_CACHE(cx,cnt) GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt) -#ifdef JS_TRACER /* Forward declarations of nanojit types. */ namespace nanojit { @@ -111,11 +110,9 @@ template class HashMap; template class Seq; } /* namespace nanojit */ -#endif namespace js { -#ifdef JS_TRACER /* Tracer constants. */ static const size_t MONITOR_N_GLOBAL_STATES = 4; static const size_t FRAGMENT_TABLE_SIZE = 512; @@ -220,7 +217,6 @@ struct TraceNativeStorage double *global() { return stack_global_buf + MAX_NATIVE_STACK_SLOTS; } FrameInfo **callstack() { return callstack_buf; } }; -#endif /* Holds data to track a single globa. */ struct GlobalState { @@ -330,15 +326,12 @@ class CallStack } }; -#ifdef JS_TRACER /* Holds the number of recording attemps for an address. */ typedef HashMap, SystemAllocPolicy> RecordAttemptMap; -class Oracle; - /* * Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not * JS_THREADSAFE) has an associated trace monitor that keeps track of loop @@ -400,7 +393,6 @@ struct TraceMonitor { nanojit::Assembler* assembler; FrameInfoCache* frameCache; - Oracle* oracle; TraceRecorder* recorder; GlobalState globalStates[MONITOR_N_GLOBAL_STATES]; @@ -459,7 +451,6 @@ struct TraceMonitor { }; } /* namespace js */ -#endif /* * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index df9e27987e18..acdaa800f8be 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3057,6 +3057,10 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) } #endif +#ifdef JS_TRACER + PurgeJITOracle(); +#endif + /* * Reset the property cache's type id generator so we can compress ids. * Same for the protoHazardShape proxy-shape standing in for all object diff --git a/js/src/jshash.cpp b/js/src/jshash.cpp index 15a8a460ab5c..e347744e7319 100644 --- a/js/src/jshash.cpp +++ b/js/src/jshash.cpp @@ -67,7 +67,7 @@ static void * DefaultAllocTable(void *pool, size_t size) { - return js_malloc(size); + return malloc(size); } static void @@ -79,7 +79,7 @@ DefaultFreeTable(void *pool, void *item, size_t size) static JSHashEntry * DefaultAllocEntry(void *pool, const void *key) { - return (JSHashEntry*) js_malloc(sizeof(JSHashEntry)); + return (JSHashEntry*) malloc(sizeof(JSHashEntry)); } static void diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index eaea40955bd7..becfcc9d1106 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -839,7 +839,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v) static JSFatLock * NewFatlock() { - JSFatLock *fl = (JSFatLock *)js_malloc(sizeof(JSFatLock)); /* for now */ + JSFatLock *fl = (JSFatLock *)malloc(sizeof(JSFatLock)); /* for now */ if (!fl) return NULL; fl->susp = 0; fl->next = NULL; diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index 22ba2bc9cc27..0cd0af4f9452 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -121,8 +121,8 @@ class UpRecursiveSlotMap : public RecursiveSlotMap }; #if defined DEBUG -JS_REQUIRES_STACK void -TraceRecorder::AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi) +static JS_REQUIRES_STACK void +AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi) { JS_ASSERT(anchor->recursive_down); JS_ASSERT(anchor->recursive_down->callerHeight == fi->callerHeight); diff --git a/js/src/jstl.h b/js/src/jstl.h index d6ae26fd86a5..ddfe9675c9e3 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -242,9 +242,9 @@ PointerRangeSize(T *begin, T *end) class SystemAllocPolicy { public: - void *malloc(size_t bytes) { return js_malloc(bytes); } - void *realloc(void *p, size_t bytes) { return js_realloc(p, bytes); } - void free(void *p) { js_free(p); } + void *malloc(size_t bytes) { return ::malloc(bytes); } + void *realloc(void *p, size_t bytes) { return ::realloc(p, bytes); } + void free(void *p) { ::free(p); } void reportAllocOverflow() const {} }; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index cfb0d91193a6..486eb2f84857 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -107,7 +107,7 @@ nanojit::Allocator::allocChunk(size_t nbytes) { VMAllocator *vma = (VMAllocator*)this; JS_ASSERT(!vma->outOfMemory()); - void *p = js_calloc(nbytes); + void *p = calloc(1, nbytes); if (!p) { JS_ASSERT(nbytes < sizeof(vma->mReserve)); vma->mOutOfMemory = true; @@ -121,7 +121,7 @@ void nanojit::Allocator::freeChunk(void *p) { VMAllocator *vma = (VMAllocator*)this; if (p != &vma->mReserve[0]) - js_free(p); + free(p); } void @@ -394,12 +394,6 @@ static void DumpPeerStability(TraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape, uint32 argc); #endif -void -SetBuiltinError(JSContext *cx) -{ - cx->interpState->builtinStatus |= BUILTIN_ERROR; -} - /* * We really need a better way to configure the JIT. Shaver, where is * my fancy JIT object? @@ -915,6 +909,12 @@ TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3, LI } #endif +/* + * The entire VM shares one oracle. Collisions and concurrent updates are + * tolerated and worst case cause performance regressions. + */ +static Oracle oracle; + Tracker::Tracker() { pagelist = NULL; @@ -954,7 +954,7 @@ struct Tracker::TrackerPage* Tracker::addTrackerPage(const void* v) { jsuword base = getTrackerPageBase(v); - struct TrackerPage* p = (struct TrackerPage*) js_calloc(sizeof(*p)); + struct TrackerPage* p = (struct TrackerPage*) calloc(1, sizeof(*p)); p->base = base; p->next = pagelist; pagelist = p; @@ -967,7 +967,7 @@ Tracker::clear() while (pagelist) { TrackerPage* p = pagelist; pagelist = pagelist->next; - js_free(p); + free(p); } } @@ -1214,44 +1214,44 @@ Oracle::clearDemotability() _pcDontDemote.reset(); } -JS_REQUIRES_STACK void -TraceRecorder::MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot) +JS_REQUIRES_STACK static JS_INLINE void +MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot) { if (slot < f->nStackTypes) { - oracle->markStackSlotUndemotable(cx, slot); + oracle.markStackSlotUndemotable(cx, slot); return; } uint16* gslots = f->globalSlots->data(); - oracle->markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); + oracle.markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -JS_REQUIRES_STACK void -TraceRecorder::MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* pc) +JS_REQUIRES_STACK static JS_INLINE void +MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* pc) { if (slot < f->nStackTypes) { - oracle->markStackSlotUndemotable(cx, slot, pc); + oracle.markStackSlotUndemotable(cx, slot, pc); return; } uint16* gslots = f->globalSlots->data(); - oracle->markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); + oracle.markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -static JS_REQUIRES_STACK bool -IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot, const void* ip) +static JS_REQUIRES_STACK inline bool +IsSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* ip) { if (slot < f->nStackTypes) - return oracle->isStackSlotUndemotable(cx, slot, ip); + return oracle.isStackSlotUndemotable(cx, slot, ip); uint16* gslots = f->globalSlots->data(); - return oracle->isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); + return oracle.isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); } -static JS_REQUIRES_STACK bool -IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot) +static JS_REQUIRES_STACK inline bool +IsSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot) { - return IsSlotUndemotable(oracle, cx, f, slot, cx->fp->regs->pc); + return IsSlotUndemotable(cx, f, slot, cx->fp->regs->pc); } class FrameInfoCache @@ -1996,7 +1996,7 @@ public: visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { TraceType type = getCoercedType(*vp); if (type == TT_INT32 && - JS_TRACE_MONITOR(mCx).oracle->isGlobalSlotUndemotable(mCx, slot)) + oracle.isGlobalSlotUndemotable(mCx, slot)) type = TT_DOUBLE; JS_ASSERT(type != TT_JSVAL); debug_only_printf(LC_TMTracer, @@ -2010,7 +2010,7 @@ public: for (int i = 0; i < count; ++i) { TraceType type = getCoercedType(vp[i]); if (type == TT_INT32 && - JS_TRACE_MONITOR(mCx).oracle->isStackSlotUndemotable(mCx, length())) + oracle.isStackSlotUndemotable(mCx, length())) type = TT_DOUBLE; JS_ASSERT(type != TT_JSVAL); debug_only_printf(LC_TMTracer, @@ -2166,7 +2166,6 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag RecordReason recordReason) : cx(cx), traceMonitor(&JS_TRACE_MONITOR(cx)), - oracle(JS_TRACE_MONITOR(cx).oracle), fragment(fragment), tree(fragment->root), recordReason(recordReason), @@ -2689,7 +2688,6 @@ TraceMonitor::flush() codeAlloc->reset(); tempAlloc->reset(); reTempAlloc->reset(); - oracle->clear(); Allocator& alloc = *dataAlloc; @@ -3533,7 +3531,7 @@ TraceRecorder::importGlobalSlot(unsigned slot) int index = tree->globalSlots->offsetOf(uint16(slot)); if (index == -1) { type = getCoercedType(*vp); - if (type == TT_INT32 && oracle->isGlobalSlotUndemotable(cx, slot)) + if (type == TT_INT32 && oracle.isGlobalSlotUndemotable(cx, slot)) type = TT_DOUBLE; index = (int)tree->globalSlots->length(); tree->globalSlots->add(uint16(slot)); @@ -3764,7 +3762,7 @@ public: * Aggressively undo speculation so the inner tree will compile * if this fails. */ - mRecorder.oracle->markGlobalSlotUndemotable(mCx, slot); + oracle.markGlobalSlotUndemotable(mCx, slot); } JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32)); ++mTypeMap; @@ -3808,7 +3806,7 @@ public: * Aggressively undo speculation so the inner tree will compile * if this fails. */ - mRecorder.oracle->markStackSlotUndemotable(mCx, mSlotnum); + oracle.markStackSlotUndemotable(mCx, mSlotnum); } JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32)); ++vp; @@ -4429,7 +4427,7 @@ class SlotMap : public SlotVisitorBase { for (unsigned i = 0; i < length(); i++) { if (get(i).lastCheck == TypeCheck_Undemote) - mRecorder.MarkSlotUndemotable(mRecorder.cx, mRecorder.tree, i); + MarkSlotUndemotable(mRecorder.cx, mRecorder.tree, i); } } @@ -4754,7 +4752,7 @@ TypeMapLinkability(JSContext* cx, const TypeMap& typeMap, TreeFragment* peer) if (typeMap[i] == peerMap[i]) continue; if (typeMap[i] == TT_INT32 && peerMap[i] == TT_DOUBLE && - IsSlotUndemotable(JS_TRACE_MONITOR(cx).oracle, cx, peer, i, peer->ip)) { + IsSlotUndemotable(cx, peer, i, peer->ip)) { consensus = TypeConsensus_Undemotes; } else { return TypeConsensus_Bad; @@ -4763,8 +4761,8 @@ TypeMapLinkability(JSContext* cx, const TypeMap& typeMap, TreeFragment* peer) return consensus; } -JS_REQUIRES_STACK unsigned -TraceRecorder::FindUndemotesInTypemaps(JSContext* cx, const TypeMap& typeMap, LinkableFragment* f, +static JS_REQUIRES_STACK unsigned +FindUndemotesInTypemaps(JSContext* cx, const TypeMap& typeMap, LinkableFragment* f, Queue& undemotes) { undemotes.setLength(0); @@ -5649,7 +5647,6 @@ FindLoopEdgeTarget(JSContext* cx, VMSideExit* exit, TreeFragment** peerp) TreeFragment* from = exit->root(); JS_ASSERT(from->code()); - Oracle* oracle = JS_TRACE_MONITOR(cx).oracle; TypeMap typeMap(NULL); FullMapFromExit(typeMap, exit); @@ -5661,14 +5658,14 @@ FindLoopEdgeTarget(JSContext* cx, VMSideExit* exit, TreeFragment** peerp) if (typeMap[i] == TT_DOUBLE) { if (exit->exitType == RECURSIVE_UNLINKED_EXIT) { if (i < exit->numStackSlots) - oracle->markStackSlotUndemotable(cx, i, exit->recursive_pc); + oracle.markStackSlotUndemotable(cx, i, exit->recursive_pc); else - oracle->markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); + oracle.markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); } if (i < from->nStackTypes) - oracle->markStackSlotUndemotable(cx, i, from->ip); + oracle.markStackSlotUndemotable(cx, i, from->ip); else if (i >= exit->numStackSlots) - oracle->markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); + oracle.markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); } } @@ -6036,7 +6033,7 @@ TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount) } case OVERFLOW_EXIT: - oracle->markInstructionUndemotable(cx->fp->regs->pc); + oracle.markInstructionUndemotable(cx->fp->regs->pc); /* FALL THROUGH */ case RECURSIVE_SLURP_FAIL_EXIT: case RECURSIVE_SLURP_MISMATCH_EXIT: @@ -6138,10 +6135,10 @@ public: if (!IsEntryTypeCompatible(vp, mTypeMap)) { mOk = false; } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == TT_INT32) { - mRecorder.oracle->markGlobalSlotUndemotable(mCx, slot); + oracle.markGlobalSlotUndemotable(mCx, slot); mOk = false; } else if (JSVAL_IS_INT(*vp) && *mTypeMap == TT_DOUBLE) { - mRecorder.oracle->markGlobalSlotUndemotable(mCx, slot); + oracle.markGlobalSlotUndemotable(mCx, slot); } mTypeMap++; } @@ -6153,10 +6150,10 @@ public: if (!IsEntryTypeCompatible(vp, mTypeMap)) { mOk = false; } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == TT_INT32) { - mRecorder.oracle->markStackSlotUndemotable(mCx, mStackSlotNum); + oracle.markStackSlotUndemotable(mCx, mStackSlotNum); mOk = false; } else if (JSVAL_IS_INT(*vp) && *mTypeMap == TT_DOUBLE) { - mRecorder.oracle->markStackSlotUndemotable(mCx, mStackSlotNum); + oracle.markStackSlotUndemotable(mCx, mStackSlotNum); } vp++; mTypeMap++; @@ -6986,7 +6983,7 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, RecordReason reason) return rv; case OVERFLOW_EXIT: - tm->oracle->markInstructionUndemotable(cx->fp->regs->pc); + oracle.markInstructionUndemotable(cx->fp->regs->pc); /* FALL THROUGH */ case RECURSIVE_SLURP_FAIL_EXIT: case RECURSIVE_SLURP_MISMATCH_EXIT: @@ -7417,8 +7414,6 @@ InitJIT(TraceMonitor *tm) /* Set the default size for the code cache to 16MB. */ tm->maxCodeCacheBytes = 16 M; - tm->oracle = new Oracle(); - tm->recordAttempts = new RecordAttemptMap; if (!tm->recordAttempts->init(PC_HASH_COUNT)) abort(); @@ -7501,7 +7496,6 @@ FinishJIT(TraceMonitor *tm) #endif delete tm->recordAttempts; - delete tm->oracle; #ifdef DEBUG // Recover profiling data from expiring Fragments, and display @@ -7573,6 +7567,12 @@ FinishJIT(TraceMonitor *tm) tm->cachedTempTypeMap = NULL; } +void +PurgeJITOracle() +{ + oracle.clear(); +} + JS_REQUIRES_STACK void PurgeScriptFragments(JSContext* cx, JSScript* script) { @@ -8030,7 +8030,7 @@ TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1) * integers and the oracle must not give us a negative hint for the * instruction. */ - if (oracle->isInstructionUndemotable(cx->fp->regs->pc) || !isPromoteInt(s0) || !isPromoteInt(s1)) { + if (oracle.isInstructionUndemotable(cx->fp->regs->pc) || !isPromoteInt(s0) || !isPromoteInt(s1)) { out: if (v == LIR_fmod) { LIns* args[] = { s1, s0 }; @@ -10243,7 +10243,7 @@ TraceRecorder::record_JSOP_NEG() * a double. Only follow this path if we're not an integer that's 0 and * we're not a double that's zero. */ - if (!oracle->isInstructionUndemotable(cx->fp->regs->pc) && + if (!oracle.isInstructionUndemotable(cx->fp->regs->pc) && isPromoteInt(a) && (!JSVAL_IS_INT(v) || JSVAL_TO_INT(v) != 0) && (!JSVAL_IS_DOUBLE(v) || !JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) && @@ -15283,7 +15283,7 @@ StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval #endif /* MOZ_TRACEVIS */ JS_REQUIRES_STACK void -TraceRecorder::CaptureStackTypes(JSContext* cx, unsigned callDepth, TraceType* typeMap) +CaptureStackTypes(JSContext* cx, unsigned callDepth, TraceType* typeMap) { CaptureTypesVisitor capVisitor(cx, typeMap); VisitStackSlots(capVisitor, cx, callDepth); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 18f62ad2350b..638cdbc6acf4 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -78,7 +78,7 @@ public: memcpy(tmp, _data, _len * sizeof(T)); _data = tmp; } else { - _data = (T*)js_realloc(_data, _max * sizeof(T)); + _data = (T*)realloc(_data, _max * sizeof(T)); } #if defined(DEBUG) memset(&_data[_len], 0xcd, _max - _len); @@ -95,7 +95,7 @@ public: ~Queue() { if (!alloc) - js_free(_data); + free(_data); } bool contains(T a) { @@ -215,8 +215,6 @@ public: void clear(); }; -struct TreeFragment; - class VMFragment : public nanojit::Fragment { public: VMFragment(const void* _ip verbose_only(, uint32_t profFragID)) @@ -772,8 +770,11 @@ struct ArgsPrivateNative { } }; -extern void -SetBuiltinError(JSContext *cx); +static JS_INLINE void +SetBuiltinError(JSContext *cx) +{ + cx->interpState->builtinStatus |= BUILTIN_ERROR; +} #ifdef DEBUG_RECORDING_STATUS_NOT_BOOL /* #define DEBUG_RECORDING_STATUS_NOT_BOOL to detect misuses of RecordingStatus */ @@ -918,9 +919,6 @@ class TraceRecorder { /*************************************************************** Recording session constants */ - /* Cached oracle keeps track of hit counts for program counter locations */ - Oracle* oracle; - /* The context in which recording started. */ JSContext* const cx; @@ -1066,17 +1064,6 @@ class TraceRecorder */ JS_REQUIRES_STACK nanojit::GuardRecord* createGuardRecord(VMSideExit* exit); - JS_REQUIRES_STACK JS_INLINE void MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot); - - JS_REQUIRES_STACK JS_INLINE void MarkSlotUndemotable(JSContext* cx, LinkableFragment* f, unsigned slot, const void* pc); - - JS_REQUIRES_STACK unsigned FindUndemotesInTypemaps(JSContext* cx, const TypeMap& typeMap, LinkableFragment* f, - Queue& undemotes); - - JS_REQUIRES_STACK void AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi); - - JS_REQUIRES_STACK void CaptureStackTypes(JSContext* cx, unsigned callDepth, TraceType* typeMap); - bool isGlobal(jsval* p) const; ptrdiff_t nativeGlobalSlot(jsval *p) const; ptrdiff_t nativeGlobalOffset(jsval* p) const; @@ -1398,8 +1385,8 @@ class TraceRecorder # include "jsopcode.tbl" #undef OPDEF - inline void* operator new(size_t size) { return js_calloc(size); } - inline void operator delete(void *p) { js_free(p); } + inline void* operator new(size_t size) { return calloc(1, size); } + inline void operator delete(void *p) { free(p); } JS_REQUIRES_STACK TraceRecorder(JSContext* cx, VMSideExit*, VMFragment*, diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 6a3aa33f732b..82e2f6bccd58 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -44,7 +44,6 @@ #ifndef jsutil_h___ #define jsutil_h___ -#include "jstypes.h" #include JS_BEGIN_EXTERN_C @@ -180,12 +179,6 @@ extern JS_FRIEND_API(void) JS_DumpBacktrace(JSCallsite *trace); #endif -#if defined JS_USE_CUSTOM_ALLOCATOR - -#include "jscustomallocator.h" - -#else - static JS_INLINE void* js_malloc(size_t bytes) { if (bytes < sizeof(void*)) /* for asyncFree */ bytes = sizeof(void*); @@ -207,7 +200,6 @@ static JS_INLINE void* js_realloc(void* p, size_t bytes) { static JS_INLINE void js_free(void* p) { free(p); } -#endif/* JS_USE_CUSTOM_ALLOCATOR */ JS_END_EXTERN_C From 8fd48ed1dbea062d936e737250f38b9b48a7ed58 Mon Sep 17 00:00:00 2001 From: Dave Herman Date: Thu, 11 Mar 2010 17:28:01 -0500 Subject: [PATCH 018/213] Make the parsing methods members of JSCompiler for bug 518055. r=jimb --- js/src/jsparse.cpp | 1474 +++++++++++++++++++++----------------------- js/src/jsparse.h | 65 ++ 2 files changed, 760 insertions(+), 779 deletions(-) diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 88c9b26380f1..1398f6979a36 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -100,68 +100,16 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom)); #undef pn_offsetof -/* - * JS parsers, from lowest to highest precedence. - * - * Each parser takes a context, a token stream, and a tree context struct. - * Each returns a parse node tree or null on error. - */ - -typedef JSParseNode * -JSParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc); - -typedef JSParseNode * -JSVariablesParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - bool inLetHead); - -typedef JSParseNode * -JSMemberParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowCallSyntax); - -typedef JSParseNode * -JSPrimaryParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSTokenType tt, JSBool afterDot); - -typedef JSParseNode * -JSParenParser(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParseNode *pn1, JSBool *genexp); - -static JSParser FunctionStmt; -static JSParser FunctionExpr; -static JSParser Statements; -static JSParser Statement; -static JSVariablesParser Variables; -static JSParser Expr; -static JSParser AssignExpr; -static JSParser CondExpr; -static JSParser OrExpr; -static JSParser AndExpr; -static JSParser BitOrExpr; -static JSParser BitXorExpr; -static JSParser BitAndExpr; -static JSParser EqExpr; -static JSParser RelExpr; -static JSParser ShiftExpr; -static JSParser AddExpr; -static JSParser MulExpr; -static JSParser UnaryExpr; -static JSMemberParser MemberExpr; -static JSPrimaryParser PrimaryExpr; -static JSParenParser ParenExpr; - -static bool -RecognizeDirectivePrologue(JSContext *cx, JSTreeContext *tc, JSParseNode *pn); - /* * Insist that the next token be of type tt, or report errno and return null. * NB: this macro uses cx and ts from its lexical environment. */ -#define MUST_MATCH_TOKEN(tt, errno) \ - JS_BEGIN_MACRO \ - if (js_GetToken(cx, ts) != tt) { \ - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, errno); \ - return NULL; \ - } \ +#define MUST_MATCH_TOKEN(tt, errno) \ + JS_BEGIN_MACRO \ + if (js_GetToken(context, &tokenStream) != tt) { \ + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ + return NULL; \ + } \ JS_END_MACRO #ifdef METER_PARSENODES @@ -776,10 +724,10 @@ JSCompiler::parse(JSObject *chain) if (!GenerateBlockId(&tc, tc.bodyid)) return NULL; - JSParseNode *pn = Statements(context, TS(this), &tc); + JSParseNode *pn = statements(&tc); if (pn) { - if (!js_MatchToken(context, TS(this), TOK_EOF)) { - js_ReportCompileErrorNumber(context, TS(this), NULL, JSREPORT_ERROR, + if (!js_MatchToken(context, &tokenStream, TOK_EOF)) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; } else { @@ -906,8 +854,8 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal } /* - * Inline Statements to emit as we go to save AST space. We must generate - * our script-body blockid since we aren't calling Statements. + * Inline this->statements to emit as we go to save AST space. We must + * generate our script-body blockid since we aren't calling Statements. */ uint32 bodyid; if (!GenerateBlockId(&cg, bodyid)) @@ -937,13 +885,13 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal goto out; } - pn = Statement(cx, &jsc.tokenStream, &cg); + pn = jsc.statement(&cg); if (!pn) goto out; JS_ASSERT(!cg.blockNode); if (inDirectivePrologue) - inDirectivePrologue = RecognizeDirectivePrologue(cx, &cg, pn); + inDirectivePrologue = jsc.recognizeDirectivePrologue(&cg, pn); if (!js_FoldConstants(cx, pn, &cg)) goto out; @@ -1328,8 +1276,8 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, return true; } -static JSParseNode * -FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::functionBody(JSTreeContext *tc) { JSStmtInfo stmtInfo; uintN oldflags, firstLine; @@ -1344,22 +1292,22 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* * Save the body's first line, and store it in pn->pn_pos.begin.lineno - * later, because we may have not peeked in ts yet, so Statements won't - * acquire a valid pn->pn_pos.begin from the current token. + * later, because we may have not peeked in tokenStream yet, so statements + * won't acquire a valid pn->pn_pos.begin from the current token. */ - firstLine = ts->lineno; + firstLine = tokenStream.lineno; #if JS_HAS_EXPR_CLOSURES - if (CURRENT_TOKEN(ts).type == TOK_LC) { - pn = Statements(cx, ts, tc); + if (CURRENT_TOKEN(&tokenStream).type == TOK_LC) { + pn = statements(tc); } else { pn = UnaryNode::create(tc); if (pn) { - pn->pn_kid = AssignExpr(cx, ts, tc); + pn->pn_kid = assignExpr(tc); if (!pn->pn_kid) { pn = NULL; } else { if (tc->flags & TCF_FUN_IS_GENERATOR) { - ReportBadReturn(cx, tc, JSREPORT_ERROR, + ReportBadReturn(context, tc, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN); pn = NULL; @@ -1372,7 +1320,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } } #else - pn = Statements(cx, ts, tc); + pn = statements(tc); #endif if (pn) { @@ -1381,8 +1329,8 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_pos.begin.lineno = firstLine; /* Check for falling off the end of a function that returns a value. */ - if (JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR) && - !CheckFinalReturn(cx, tc, pn)) { + if (JS_HAS_STRICT_OPTION(context) && (tc->flags & TCF_RETURN_EXPR) && + !CheckFinalReturn(context, tc, pn)) { pn = NULL; } } @@ -1666,7 +1614,7 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr * generate code for this function, including a stop opcode at the end. */ CURRENT_TOKEN(&jsc.tokenStream).type = TOK_LC; - JSParseNode *pn = fn ? FunctionBody(cx, &jsc.tokenStream, &funcg) : NULL; + JSParseNode *pn = fn ? jsc.functionBody(&funcg) : NULL; if (pn) { if (!CheckStrictFormals(cx, &funcg, fun, pn)) { pn = NULL; @@ -1706,8 +1654,6 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr * function is called indirectly from the variable declaration parser by way * of CheckDestructuring and its friends. */ -typedef struct BindData BindData; - typedef JSBool (*Binder)(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc); @@ -1748,13 +1694,6 @@ BindLocalVariable(JSContext *cx, JSFunction *fun, JSAtom *atom, } #if JS_HAS_DESTRUCTURING -/* - * Forward declaration to maintain top-down presentation. - */ -static JSParseNode * -DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc, - JSTokenType tt); - static JSBool BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) @@ -2636,9 +2575,8 @@ LeaveFunction(JSParseNode *fn, JSTreeContext *funtc, JSTreeContext *tc, return true; } -static JSParseNode * -FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - uintN lambda) +JSParseNode * +JSCompiler::functionDef(JSTreeContext *tc, uintN lambda) { JSOp op; JSParseNode *pn, *body, *result; @@ -2653,7 +2591,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* Make a TOK_FUNCTION node. */ #if JS_HAS_GETTER_SETTER - op = CURRENT_TOKEN(ts).t_op; + op = CURRENT_TOKEN(&tokenStream).t_op; #endif pn = FunctionNode::create(tc); if (!pn) @@ -2663,7 +2601,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* * If a lambda, give up on JSOP_{GET,CALL}UPVAR usage unless this function - * is immediately applied (we clear PND_FUNARG if so -- see MemberExpr). + * is immediately applied (we clear PND_FUNARG if so -- see memberExpr). * * Also treat function sub-statements (non-lambda, non-top-level functions) * as escaping funargs, since we can't statically analyze their definitions @@ -2673,19 +2611,19 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->pn_dflags = (lambda || !topLevel) ? PND_FUNARG : 0; /* Scan the optional function name into funAtom. */ - ts->flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_KEYWORD_IS_NAME; + tokenStream.flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_NAME) { - funAtom = CURRENT_TOKEN(ts).t_atom; + funAtom = CURRENT_TOKEN(&tokenStream).t_atom; } else { - if (lambda == 0 && (cx->options & JSOPTION_ANONFUNFIX)) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + if (lambda == 0 && (context->options & JSOPTION_ANONFUNFIX)) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); return NULL; } funAtom = NULL; - js_UngetToken(ts); + js_UngetToken(&tokenStream); } /* @@ -2701,10 +2639,10 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JS_ASSERT(!dn->pn_used); JS_ASSERT(dn->pn_defn); - if (JS_HAS_STRICT_OPTION(cx) || dn_kind == JSDefinition::CONST) { - const char *name = js_AtomToPrintableString(cx, funAtom); + if (JS_HAS_STRICT_OPTION(context) || dn_kind == JSDefinition::CONST) { + const char *name = js_AtomToPrintableString(context, funAtom); if (!name || - !js_ReportCompileErrorNumber(cx, ts, NULL, + !js_ReportCompileErrorNumber(context, &tokenStream, NULL, (dn_kind != JSDefinition::CONST) ? JSREPORT_WARNING | JSREPORT_STRICT : JSREPORT_ERROR, @@ -2726,7 +2664,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } else if (topLevel) { /* * If this function was used before it was defined, claim the - * pre-created definition node for this function that PrimaryExpr + * pre-created definition node for this function that primaryExpr * put in tc->lexdeps on first forward reference, and recycle pn. */ JSHashEntry **hep; @@ -2773,12 +2711,12 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * we add a variable even if a parameter with the given name * already exists. */ - localKind = js_LookupLocal(cx, tc->fun, funAtom, &index); + localKind = js_LookupLocal(context, tc->fun, funAtom, &index); switch (localKind) { case JSLOCAL_NONE: case JSLOCAL_ARG: index = tc->fun->u.i.nvars; - if (!js_AddLocal(cx, tc->fun, funAtom, JSLOCAL_VAR)) + if (!js_AddLocal(context, tc->fun, funAtom, JSLOCAL_VAR)) return NULL; /* FALL THROUGH */ @@ -2793,7 +2731,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } } - /* Initialize early for possible flags mutation via DestructuringExpr. */ + /* Initialize early for possible flags mutation via destructuringExpr. */ JSTreeContext funtc(tc->compiler); JSFunctionBox *funbox = EnterFunction(pn, tc, &funtc, funAtom, lambda); @@ -2809,9 +2747,9 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); - if (!js_MatchToken(cx, ts, TOK_RP)) { + if (!js_MatchToken(context, &tokenStream, TOK_RP)) { do { - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -2835,7 +2773,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, data.pn = NULL; data.op = JSOP_DEFVAR; data.binder = BindDestructuringArg; - lhs = DestructuringExpr(cx, &data, &funtc, tt); + lhs = destructuringExpr(&data, &funtc, tt); if (!lhs) return NULL; @@ -2844,7 +2782,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * parameter that is to be destructured. */ slot = fun->nargs; - if (!js_AddLocal(cx, fun, NULL, JSLOCAL_ARG)) + if (!js_AddLocal(context, fun, NULL, JSLOCAL_ARG)) return NULL; /* @@ -2852,7 +2790,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * anonymous positional parameter into the destructuring * left-hand-side expression and accumulate it in list. */ - rhs = NameNode::create(cx->runtime->atomState.emptyAtom, &funtc); + rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc); if (!rhs) return NULL; rhs->pn_type = TOK_NAME; @@ -2877,7 +2815,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, case TOK_NAME: { - JSAtom *atom = CURRENT_TOKEN(ts).t_atom; + JSAtom *atom = CURRENT_TOKEN(&tokenStream).t_atom; if (!DefineArg(pn, atom, fun->nargs, &funtc)) return NULL; #ifdef JS_HAS_DESTRUCTURING @@ -2891,19 +2829,19 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * mode code), but we do those tests in one place below, after having * parsed the body. */ - if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) { + if (js_LookupLocal(context, fun, atom, NULL) != JSLOCAL_NONE) { duplicatedArg = atom; if (destructuringArg) goto report_dup_and_destructuring; } #endif - if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG)) + if (!js_AddLocal(context, fun, atom, JSLOCAL_ARG)) return NULL; break; } default: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL); /* FALL THROUGH */ case TOK_ERROR: @@ -2912,48 +2850,47 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, #if JS_HAS_DESTRUCTURING report_dup_and_destructuring: JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg)); - js_ReportCompileErrorNumber(cx, TS(tc->compiler), dn, - JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG); return NULL; #endif } - } while (js_MatchToken(cx, ts, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); } #if JS_HAS_EXPR_CLOSURES - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt != TOK_LC) { - js_UngetToken(ts); + js_UngetToken(&tokenStream); fun->flags |= JSFUN_EXPR_CLOSURE; } #else MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY); #endif - body = FunctionBody(cx, ts, &funtc); + body = functionBody(&funtc); if (!body) return NULL; - if (!CheckStrictBinding(cx, &funtc, funAtom, pn)) + if (!CheckStrictBinding(context, &funtc, funAtom, pn)) return NULL; - if (!CheckStrictFormals(cx, &funtc, fun, pn)) + if (!CheckStrictFormals(context, &funtc, fun, pn)) return NULL; #if JS_HAS_EXPR_CLOSURES if (tt == TOK_LC) MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY); - else if (lambda == 0 && !MatchOrInsertSemicolon(cx, ts)) + else if (lambda == 0 && !MatchOrInsertSemicolon(context, &tokenStream)) return NULL; #else MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY); #endif - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; #if JS_HAS_DESTRUCTURING /* @@ -3063,21 +3000,21 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* If the surrounding function is not strict code, reset the lexer. */ if (!(tc->flags & TCF_STRICT_MODE_CODE)) - ts->flags &= ~TSF_STRICT_MODE_CODE; + tokenStream.flags &= ~TSF_STRICT_MODE_CODE; return result; } -static JSParseNode * -FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::functionStmt(JSTreeContext *tc) { - return FunctionDef(cx, ts, tc, 0); + return functionDef(tc, 0); } -static JSParseNode * -FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::functionExpr(JSTreeContext *tc) { - return FunctionDef(cx, ts, tc, JSFUN_LAMBDA); + return functionDef(tc, JSFUN_LAMBDA); } /* @@ -3098,16 +3035,16 @@ FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * That is, a statement can be a Directive Prologue member, even * if it can't possibly be a directive, now or in the future. */ -static bool -RecognizeDirectivePrologue(JSContext *cx, JSTreeContext *tc, JSParseNode *pn) +bool +JSCompiler::recognizeDirectivePrologue(JSTreeContext *tc, JSParseNode *pn) { if (!pn->isDirectivePrologueMember()) return false; if (pn->isDirective()) { JSAtom *directive = pn->pn_kid->pn_atom; - if (directive == cx->runtime->atomState.useStrictAtom) { + if (directive == context->runtime->atomState.useStrictAtom) { tc->flags |= TCF_STRICT_MODE_CODE; - tc->compiler->tokenStream.flags |= TSF_STRICT_MODE_CODE; + tokenStream.flags |= TSF_STRICT_MODE_CODE; } } return true; @@ -3118,14 +3055,14 @@ RecognizeDirectivePrologue(JSContext *cx, JSTreeContext *tc, JSParseNode *pn) * statements' trees. If called from block-parsing code, the caller must * match { before and } after. */ -static JSParseNode * -Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::statements(JSTreeContext *tc) { JSParseNode *pn, *pn2, *saveBlock; JSTokenType tt; bool inDirectivePrologue = tc->atTopLevel(); - JS_CHECK_RECURSION(cx, return NULL); + JS_CHECK_RECURSION(context, return NULL); pn = ListNode::create(tc); if (!pn) @@ -3137,26 +3074,26 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) tc->blockNode = pn; for (;;) { - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_PeekToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF || tt == TOK_RC) { if (tt == TOK_ERROR) { - if (ts->flags & TSF_EOF) - ts->flags |= TSF_UNEXPECTED_EOF; + if (tokenStream.flags & TSF_EOF) + tokenStream.flags |= TSF_UNEXPECTED_EOF; return NULL; } break; } - pn2 = Statement(cx, ts, tc); + pn2 = statement(tc); if (!pn2) { - if (ts->flags & TSF_EOF) - ts->flags |= TSF_UNEXPECTED_EOF; + if (tokenStream.flags & TSF_EOF) + tokenStream.flags |= TSF_UNEXPECTED_EOF; return NULL; } if (inDirectivePrologue) - inDirectivePrologue = RecognizeDirectivePrologue(cx, tc, pn2); + inDirectivePrologue = recognizeDirectivePrologue(tc, pn2); if (pn2->pn_type == TOK_FUNCTION) { /* @@ -3185,17 +3122,17 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = tc->blockNode; tc->blockNode = saveBlock; - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; return pn; } -static JSParseNode * -Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::condition(JSTreeContext *tc) { JSParseNode *pn; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND); - pn = ParenExpr(cx, ts, tc, NULL, NULL); + pn = parenExpr(tc, NULL, NULL); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND); @@ -3204,7 +3141,7 @@ Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP && !pn->pn_parens && - !js_ReportCompileErrorNumber(cx, ts, NULL, + !js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN, "")) { @@ -3880,12 +3817,12 @@ FindPropertyValue(JSParseNode *pn, JSParseNode *pnid, FindPropValData *data) * simple names; the destructuring defines them as new variables. * * In both cases, other code parses the pattern as an arbitrary - * PrimaryExpr, and then, here in CheckDestructuring, verify that the + * primaryExpr, and then, here in CheckDestructuring, verify that the * tree is a valid destructuring expression. * * In assignment-like contexts, we parse the pattern with the * TCF_DECL_DESTRUCTURING flag clear, so the lvalue expressions in the - * pattern are parsed normally. PrimaryExpr links variable references + * pattern are parsed normally. primaryExpr links variable references * into the appropriate use chains; creates placeholder definitions; * and so on. CheckDestructuring is called with |data| NULL (since we * won't be binding any new names), and we specialize lvalues as @@ -3895,7 +3832,7 @@ FindPropertyValue(JSParseNode *pn, JSParseNode *pnid, FindPropValData *data) * processing would just be an obstruction, because we're going to * define the names that appear in the property value positions as new * variables anyway. In this case, we parse the pattern with - * TCF_DECL_DESTRUCTURING set, which directs PrimaryExpr to leave + * TCF_DECL_DESTRUCTURING set, which directs primaryExpr to leave * whatever name nodes it creates unconnected. Then, here in * CheckDestructuring, we require the pattern's property value * positions to be simple names, and define them as appropriate to the @@ -4117,20 +4054,17 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) return JS_TRUE; } -static JSParseNode * -DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc, - JSTokenType tt) +JSParseNode * +JSCompiler::destructuringExpr(BindData *data, JSTreeContext *tc, JSTokenType tt) { - JSTokenStream *ts; JSParseNode *pn; - ts = TS(tc->compiler); tc->flags |= TCF_DECL_DESTRUCTURING; - pn = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); + pn = primaryExpr(tc, tt, JS_FALSE); tc->flags &= ~TCF_DECL_DESTRUCTURING; if (!pn) return NULL; - if (!CheckDestructuring(cx, data, pn, NULL, tc)) + if (!CheckDestructuring(context, data, pn, NULL, tc)) return NULL; return pn; } @@ -4293,16 +4227,15 @@ ContainsStmt(JSParseNode *pn, JSTokenType tt) return NULL; } -static JSParseNode * -ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParser operandParser) +JSParseNode * +JSCompiler::returnOrYield(JSTreeContext *tc, bool useAssignExpr) { JSTokenType tt, tt2; JSParseNode *pn, *pn2; - tt = CURRENT_TOKEN(ts).type; + tt = CURRENT_TOKEN(&tokenStream).type; if (tt == TOK_RETURN && !(tc->flags & TCF_IN_FUNCTION)) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return NULL; } @@ -4317,9 +4250,9 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, #endif /* This is ugly, but we don't want to require a semicolon. */ - ts->flags |= TSF_OPERAND; - tt2 = js_PeekTokenSameLine(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt2 = js_PeekTokenSameLine(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt2 == TOK_ERROR) return NULL; @@ -4330,7 +4263,7 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, tt2 != TOK_COLON && tt2 != TOK_COMMA)) #endif ) { - pn2 = operandParser(cx, ts, tc); + pn2 = useAssignExpr ? assignExpr(tc) : expr(tc); if (!pn2) return NULL; #if JS_HAS_GENERATORS @@ -4348,15 +4281,15 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if ((~tc->flags & (TCF_RETURN_EXPR | TCF_FUN_IS_GENERATOR)) == 0) { /* As in Python (see PEP-255), disallow return v; in generators. */ - ReportBadReturn(cx, tc, JSREPORT_ERROR, + ReportBadReturn(context, tc, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN); return NULL; } - if (JS_HAS_STRICT_OPTION(cx) && + if (JS_HAS_STRICT_OPTION(context) && (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0 && - !ReportBadReturn(cx, tc, JSREPORT_WARNING | JSREPORT_STRICT, + !ReportBadReturn(context, tc, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE)) { return NULL; @@ -4399,13 +4332,13 @@ PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, #if JS_HAS_BLOCK_SCOPE -static JSParseNode * -LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) +JSParseNode * +JSCompiler::letBlock(JSTreeContext *tc, JSBool statement) { JSParseNode *pn, *pnblock, *pnlet; JSStmtInfo stmtInfo; - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LET); + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_LET); /* Create the let binary node. */ pnlet = BinaryNode::create(tc); @@ -4415,21 +4348,21 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET); /* This is a let block or expression of the form: let (a, b, c) .... */ - pnblock = PushLexicalScope(cx, ts, tc, &stmtInfo); + pnblock = PushLexicalScope(context, &tokenStream, tc, &stmtInfo); if (!pnblock) return NULL; pn = pnblock; pn->pn_expr = pnlet; - pnlet->pn_left = Variables(cx, ts, tc, true); + pnlet->pn_left = variables(tc, true); if (!pnlet->pn_left) return NULL; pnlet->pn_left->pn_xflags = PNX_POPVAR; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET); - ts->flags |= TSF_OPERAND; - if (statement && !js_MatchToken(cx, ts, TOK_LC)) { + tokenStream.flags |= TSF_OPERAND; + if (statement && !js_MatchToken(context, &tokenStream, TOK_LC)) { /* * If this is really an expression in let statement guise, then we * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop @@ -4444,10 +4377,10 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) statement = JS_FALSE; } - ts->flags &= ~TSF_OPERAND; + tokenStream.flags &= ~TSF_OPERAND; if (statement) { - pnlet->pn_right = Statements(cx, ts, tc); + pnlet->pn_right = statements(tc); if (!pnlet->pn_right) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET); @@ -4457,7 +4390,7 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement) * result down after popping the block, and clear statement. */ pnblock->pn_op = JSOP_LEAVEBLOCKEXPR; - pnlet->pn_right = AssignExpr(cx, ts, tc); + pnlet->pn_right = assignExpr(tc); if (!pnlet->pn_right) return NULL; } @@ -4595,23 +4528,23 @@ RebindLets(JSParseNode *pn, JSTreeContext *tc) } #endif /* JS_HAS_BLOCK_SCOPE */ -static JSParseNode * -Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::statement(JSTreeContext *tc) { JSTokenType tt; JSParseNode *pn, *pn1, *pn2, *pn3, *pn4; JSStmtInfo stmtInfo, *stmt, *stmt2; JSAtom *label; - JS_CHECK_RECURSION(cx, return NULL); + JS_CHECK_RECURSION(context, return NULL); - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { - tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION); + tt = CheckGetterOrSetter(context, &tokenStream, TOK_FUNCTION); if (tt == TOK_ERROR) return NULL; } @@ -4620,36 +4553,36 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) switch (tt) { case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT - ts->flags |= TSF_KEYWORD_IS_NAME; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_KEYWORD_IS_NAME; + tokenStream.flags |= TSF_KEYWORD_IS_NAME; + tt = js_PeekToken(context, &tokenStream); + tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_DBLCOLON) goto expression; #endif - return FunctionStmt(cx, ts, tc); + return functionStmt(tc); case TOK_IF: /* An IF node has three kids: condition, then, and optional else. */ pn = TernaryNode::create(tc); if (!pn) return NULL; - pn1 = Condition(cx, ts, tc); + pn1 = condition(tc); if (!pn1) return NULL; js_PushStatement(tc, &stmtInfo, STMT_IF, -1); - pn2 = Statement(cx, ts, tc); + pn2 = statement(tc); if (!pn2) return NULL; - ts->flags |= TSF_OPERAND; - if (js_MatchToken(cx, ts, TOK_ELSE)) { - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + if (js_MatchToken(context, &tokenStream, TOK_ELSE)) { + tokenStream.flags &= ~TSF_OPERAND; stmtInfo.type = STMT_ELSE; - pn3 = Statement(cx, ts, tc); + pn3 = statement(tc); if (!pn3) return NULL; pn->pn_pos.end = pn3->pn_pos.end; } else { - ts->flags &= ~TSF_OPERAND; + tokenStream.flags &= ~TSF_OPERAND; pn3 = NULL; pn->pn_pos.end = pn2->pn_pos.end; } @@ -4670,7 +4603,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH); /* pn1 points to the switch's discriminant. */ - pn1 = ParenExpr(cx, ts, tc, NULL, NULL); + pn1 = parenExpr(tc, NULL, NULL); if (!pn1) return NULL; @@ -4693,11 +4626,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) saveBlock = tc->blockNode; tc->blockNode = pn2; - while ((tt = js_GetToken(cx, ts)) != TOK_RC) { + while ((tt = js_GetToken(context, &tokenStream)) != TOK_RC) { switch (tt) { case TOK_DEFAULT: if (seenDefault) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_DEFAULTS); return NULL; } @@ -4709,13 +4642,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (!pn3) return NULL; if (tt == TOK_CASE) { - pn3->pn_left = Expr(cx, ts, tc); + pn3->pn_left = expr(tc); if (!pn3->pn_left) return NULL; } pn2->append(pn3); if (pn2->pn_count == JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_CASES); return NULL; } @@ -4725,7 +4658,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return NULL; default: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_SWITCH); return NULL; } @@ -4736,20 +4669,20 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return NULL; pn4->pn_type = TOK_LC; pn4->makeEmpty(); - ts->flags |= TSF_OPERAND; - while ((tt = js_PeekToken(cx, ts)) != TOK_RC && + tokenStream.flags |= TSF_OPERAND; + while ((tt = js_PeekToken(context, &tokenStream)) != TOK_RC && tt != TOK_CASE && tt != TOK_DEFAULT) { - ts->flags &= ~TSF_OPERAND; + tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; - pn5 = Statement(cx, ts, tc); + pn5 = statement(tc); if (!pn5) return NULL; pn4->pn_pos.end = pn5->pn_pos.end; pn4->append(pn5); - ts->flags |= TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; } - ts->flags &= ~TSF_OPERAND; + tokenStream.flags &= ~TSF_OPERAND; /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */ if (pn4->pn_head) @@ -4769,7 +4702,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) tc->blockNode = saveBlock; PopStatement(tc); - pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; pn->pn_left = pn1; pn->pn_right = pn2; return pn; @@ -4780,11 +4713,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); - pn2 = Condition(cx, ts, tc); + pn2 = condition(tc); if (!pn2) return NULL; pn->pn_left = pn2; - pn2 = Statement(cx, ts, tc); + pn2 = statement(tc); if (!pn2) return NULL; PopStatement(tc); @@ -4797,24 +4730,24 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); - pn2 = Statement(cx, ts, tc); + pn2 = statement(tc); if (!pn2) return NULL; pn->pn_left = pn2; MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO); - pn2 = Condition(cx, ts, tc); + pn2 = condition(tc); if (!pn2) return NULL; PopStatement(tc); pn->pn_pos.end = pn2->pn_pos.end; pn->pn_right = pn2; - if (JSVERSION_NUMBER(cx) != JSVERSION_ECMA_3) { + if (JSVERSION_NUMBER(context) != JSVERSION_ECMA_3) { /* * All legacy and extended versions must do automatic semicolon * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ - (void) js_MatchToken(cx, ts, TOK_SEMI); + (void) js_MatchToken(context, &tokenStream, TOK_SEMI); return pn; } break; @@ -4835,17 +4768,17 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_op = JSOP_ITER; pn->pn_iflags = 0; - if (js_MatchToken(cx, ts, TOK_NAME)) { - if (CURRENT_TOKEN(ts).t_atom == cx->runtime->atomState.eachAtom) + if (js_MatchToken(context, &tokenStream, TOK_NAME)) { + if (CURRENT_TOKEN(&tokenStream).t_atom == context->runtime->atomState.eachAtom) pn->pn_iflags = JSITER_FOREACH; else - js_UngetToken(ts); + js_UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_PeekToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_BLOCK_SCOPE bool let = false; @@ -4873,25 +4806,25 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) */ tc->flags |= TCF_IN_FOR_INIT; if (tt == TOK_VAR) { - (void) js_GetToken(cx, ts); - pn1 = Variables(cx, ts, tc, false); + (void) js_GetToken(context, &tokenStream); + pn1 = variables(tc, false); #if JS_HAS_BLOCK_SCOPE } else if (tt == TOK_LET) { let = true; - (void) js_GetToken(cx, ts); - if (js_PeekToken(cx, ts) == TOK_LP) { - pn1 = LetBlock(cx, ts, tc, JS_FALSE); + (void) js_GetToken(context, &tokenStream); + if (js_PeekToken(context, &tokenStream) == TOK_LP) { + pn1 = letBlock(tc, JS_FALSE); tt = TOK_LEXICALSCOPE; } else { - pnlet = PushLexicalScope(cx, ts, tc, &blockInfo); + pnlet = PushLexicalScope(context, &tokenStream, tc, &blockInfo); if (!pnlet) return NULL; blockInfo.flags |= SIF_FOR_BLOCK; - pn1 = Variables(cx, ts, tc, false); + pn1 = variables(tc, false); } #endif } else { - pn1 = Expr(cx, ts, tc); + pn1 = expr(tc); } tc->flags &= ~TCF_IN_FOR_INIT; if (!pn1) @@ -4904,7 +4837,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * as we've excluded 'in' from being parsed in RelExpr by setting * the TCF_IN_FOR_INIT flag in our JSTreeContext. */ - if (pn1 && js_MatchToken(cx, ts, TOK_IN)) { + if (pn1 && js_MatchToken(context, &tokenStream, TOK_IN)) { pn->pn_iflags |= JSITER_ENUMERATE; stmtInfo.type = STMT_FOR_IN_LOOP; @@ -4913,7 +4846,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (TOKEN_TYPE_IS_DECL(tt) ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST #if JS_HAS_DESTRUCTURING - || (JSVERSION_NUMBER(cx) == JSVERSION_1_7 && + || (JSVERSION_NUMBER(context) == JSVERSION_1_7 && pn->pn_op == JSOP_ITER && !(pn->pn_iflags & JSITER_FOREACH) && (pn1->pn_head->pn_type == TOK_RC || @@ -4927,7 +4860,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) : (pn1->pn_type != TOK_NAME && pn1->pn_type != TOK_DOT && #if JS_HAS_DESTRUCTURING - ((JSVERSION_NUMBER(cx) == JSVERSION_1_7 && + ((JSVERSION_NUMBER(context) == JSVERSION_1_7 && pn->pn_op == JSOP_ITER && !(pn->pn_iflags & JSITER_FOREACH)) ? (pn1->pn_type != TOK_RB || pn1->pn_count != 2) @@ -4939,7 +4872,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn1->pn_op != JSOP_XMLNAME) && #endif pn1->pn_type != TOK_LB)) { - js_ReportCompileErrorNumber(cx, ts, pn1, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -5039,7 +4972,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (!pn2) { pn2 = pn1; if (pn2->pn_type == TOK_LP && - !MakeSetCall(cx, pn2, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) { + !MakeSetCall(context, pn2, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) { return NULL; } #if JS_HAS_XML_SUPPORT @@ -5051,7 +4984,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) switch (pn2->pn_type) { case TOK_NAME: /* Beware 'for (arguments in ...)' with or without a 'var'. */ - NoteLValue(cx, pn2, tc, dflag); + NoteLValue(context, pn2, tc, dflag); break; #if JS_HAS_DESTRUCTURING @@ -5062,10 +4995,10 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case TOK_RB: case TOK_RC: /* Check for valid lvalues in var-less destructuring for-in. */ - if (pn1 == pn2 && !CheckDestructuring(cx, NULL, pn2, NULL, tc)) + if (pn1 == pn2 && !CheckDestructuring(context, NULL, pn2, NULL, tc)) return NULL; - if (JSVERSION_NUMBER(cx) == JSVERSION_1_7) { + if (JSVERSION_NUMBER(context) == JSVERSION_1_7) { /* * Destructuring for-in requires [key, value] enumeration * in JS1.7. @@ -5090,7 +5023,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (let) tc->topStmt = save->down; #endif - pn2 = Expr(cx, ts, tc); + pn2 = expr(tc); #if JS_HAS_BLOCK_SCOPE if (let) tc->topStmt = save; @@ -5107,26 +5040,26 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* Parse the loop condition or null into pn2. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_PeekToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_SEMI) { pn2 = NULL; } else { - pn2 = Expr(cx, ts, tc); + pn2 = expr(tc); if (!pn2) return NULL; } /* Parse the update expression or null into pn3. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); - ts->flags |= TSF_OPERAND; - tt = js_PeekToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_PeekToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RP) { pn3 = NULL; } else { - pn3 = Expr(cx, ts, tc); + pn3 = expr(tc); if (!pn3) return NULL; } @@ -5146,7 +5079,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL); /* Parse the loop body into pn->pn_right. */ - pn2 = Statement(cx, ts, tc); + pn2 = statement(tc); if (!pn2) return NULL; pn->pn_right = pn2; @@ -5170,7 +5103,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn; bad_for_each: - js_ReportCompileErrorNumber(cx, ts, pn, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP); return NULL; } @@ -5180,9 +5113,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* * try nodes are ternary. - * kid1 is the try Statement + * kid1 is the try statement * kid2 is the catch node list or null - * kid3 is the finally Statement + * kid3 is the finally statement * * catch nodes are ternary. * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC) @@ -5193,7 +5126,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * TOK_NAME for a single identifier * TOK_RB or TOK_RC for a destructuring left-hand side * - * finally nodes are TOK_LC Statement lists. + * finally nodes are TOK_LC statement lists. */ pn = TernaryNode::create(tc); if (!pn) @@ -5203,14 +5136,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc)) return NULL; - pn->pn_kid1 = Statements(cx, ts, tc); + pn->pn_kid1 = statements(tc); if (!pn->pn_kid1) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY); PopStatement(tc); catchList = NULL; - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_CATCH) { catchList = ListNode::create(tc); if (!catchList) @@ -5225,7 +5158,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* Check for another catch after unconditional catch. */ if (lastCatch && !lastCatch->pn_kid2) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_CATCH_AFTER_GENERAL); return NULL; } @@ -5234,7 +5167,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * Create a lexical scope node around the whole catch clause, * including the head. */ - pnblock = PushLexicalScope(cx, ts, tc, &stmtInfo); + pnblock = PushLexicalScope(context, &tokenStream, tc, &stmtInfo); if (!pnblock) return NULL; stmtInfo.type = STMT_CATCH; @@ -5262,29 +5195,29 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) data.binder = BindLet; data.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: case TOK_LC: - pn3 = DestructuringExpr(cx, &data, tc, tt); + pn3 = destructuringExpr(&data, tc, tt); if (!pn3) return NULL; break; #endif case TOK_NAME: - label = CURRENT_TOKEN(ts).t_atom; + label = CURRENT_TOKEN(&tokenStream).t_atom; pn3 = NewBindingNode(label, tc, true); if (!pn3) return NULL; data.pn = pn3; - if (!data.binder(cx, &data, label, tc)) + if (!data.binder(context, &data, label, tc)) return NULL; break; default: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_CATCH_IDENTIFIER); return NULL; } @@ -5296,8 +5229,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * to avoid conflicting with the JS2/ECMAv4 type annotation * catchguard syntax. */ - if (js_MatchToken(cx, ts, TOK_IF)) { - pn2->pn_kid2 = Expr(cx, ts, tc); + if (js_MatchToken(context, &tokenStream, TOK_IF)) { + pn2->pn_kid2 = expr(tc); if (!pn2->pn_kid2) return NULL; } @@ -5305,7 +5238,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); - pn2->pn_kid3 = Statements(cx, ts, tc); + pn2->pn_kid3 = statements(tc); if (!pn2->pn_kid3) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH); @@ -5313,9 +5246,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) catchList->append(pnblock); lastCatch = pn2; - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; } while (tt == TOK_CATCH); } pn->pn_kid2 = catchList; @@ -5324,16 +5257,16 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY); if (!PushBlocklikeStatement(&stmtInfo, STMT_FINALLY, tc)) return NULL; - pn->pn_kid3 = Statements(cx, ts, tc); + pn->pn_kid3 = statements(tc); if (!pn->pn_kid3) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); PopStatement(tc); } else { - js_UngetToken(ts); + js_UngetToken(&tokenStream); } if (!catchList && !pn->pn_kid3) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_CATCH_OR_FINALLY); return NULL; } @@ -5346,18 +5279,18 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return NULL; /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ - ts->flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_PeekTokenSameLine(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); return NULL; } - pn2 = Expr(cx, ts, tc); + pn2 = expr(tc); if (!pn2) return NULL; pn->pn_pos.end = pn2->pn_pos.end; @@ -5367,12 +5300,12 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ case TOK_CATCH: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_CATCH_WITHOUT_TRY); return NULL; case TOK_FINALLY: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_FINALLY_WITHOUT_TRY); return NULL; @@ -5380,14 +5313,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = NullaryNode::create(tc); if (!pn) return NULL; - if (!MatchLabel(cx, ts, pn)) + if (!MatchLabel(context, &tokenStream, pn)) return NULL; stmt = tc->topStmt; label = pn->pn_atom; if (label) { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } @@ -5397,7 +5330,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } else { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_TOUGH_BREAK); return NULL; } @@ -5406,29 +5339,28 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } } if (label) - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; break; case TOK_CONTINUE: pn = NullaryNode::create(tc); if (!pn) return NULL; - if (!MatchLabel(cx, ts, pn)) + if (!MatchLabel(context, &tokenStream, pn)) return NULL; stmt = tc->topStmt; label = pn->pn_atom; if (label) { for (stmt2 = NULL; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL) { if (stmt->label == label) { if (!stmt2 || !STMT_IS_LOOP(stmt2)) { - js_ReportCompileErrorNumber(cx, ts, NULL, - JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE); return NULL; } @@ -5441,7 +5373,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } else { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE); return NULL; } @@ -5450,7 +5382,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } } if (label) - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; break; case TOK_WITH: @@ -5463,7 +5395,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. */ if (tc->flags & TCF_STRICT_MODE_CODE) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_STRICT_CODE_WITH); return NULL; } @@ -5472,14 +5404,14 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH); - pn2 = ParenExpr(cx, ts, tc, NULL, NULL); + pn2 = parenExpr(tc, NULL, NULL); if (!pn2) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH); pn->pn_left = pn2; js_PushStatement(tc, &stmtInfo, STMT_WITH, -1); - pn2 = Statement(cx, ts, tc); + pn2 = statement(tc); if (!pn2) return NULL; PopStatement(tc); @@ -5490,7 +5422,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn; case TOK_VAR: - pn = Variables(cx, ts, tc, false); + pn = variables(tc, false); if (!pn) return NULL; @@ -5505,8 +5437,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JSObjectBox *blockbox; /* Check for a let statement or let expression. */ - if (js_PeekToken(cx, ts) == TOK_LP) { - pn = LetBlock(cx, ts, tc, JS_TRUE); + if (js_PeekToken(context, &tokenStream) == TOK_LP) { + pn = letBlock(tc, JS_TRUE); if (!pn || pn->pn_op == JSOP_LEAVEBLOCK) return pn; @@ -5530,7 +5462,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) stmt = tc->topStmt; if (stmt && (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_LET_DECL_NOT_IN_BLOCK); return NULL; } @@ -5544,10 +5476,10 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * ES4 specifies that let at top level and at body-block scope * does not shadow var, so convert back to var. */ - CURRENT_TOKEN(ts).type = TOK_VAR; - CURRENT_TOKEN(ts).t_op = JSOP_DEFVAR; + CURRENT_TOKEN(&tokenStream).type = TOK_VAR; + CURRENT_TOKEN(&tokenStream).t_op = JSOP_DEFVAR; - pn = Variables(cx, ts, tc, false); + pn = variables(tc, false); if (!pn) return NULL; pn->pn_xflags |= PNX_POPVAR; @@ -5611,7 +5543,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) tc->blockNode = pn1; } - pn = Variables(cx, ts, tc, false); + pn = variables(tc, false); if (!pn) return NULL; pn->pn_xflags = PNX_POPVAR; @@ -5620,7 +5552,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #endif /* JS_HAS_BLOCK_SCOPE */ case TOK_RETURN: - pn = ReturnOrYield(cx, ts, tc, Expr); + pn = returnOrYield(tc, false); if (!pn) return NULL; break; @@ -5633,7 +5565,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) tc->flags = oldflags & ~TCF_HAS_FUNCTION_STMT; if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, tc)) return NULL; - pn = Statements(cx, ts, tc); + pn = statements(tc); if (!pn) return NULL; @@ -5675,20 +5607,20 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = UnaryNode::create(tc); if (!pn) return NULL; - if (!js_MatchToken(cx, ts, TOK_NAME) || - CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.xmlAtom || - !js_MatchToken(cx, ts, TOK_NAME) || - CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.namespaceAtom || - !js_MatchToken(cx, ts, TOK_ASSIGN) || - CURRENT_TOKEN(ts).t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + if (!js_MatchToken(context, &tokenStream, TOK_NAME) || + CURRENT_TOKEN(&tokenStream).t_atom != context->runtime->atomState.xmlAtom || + !js_MatchToken(context, &tokenStream, TOK_NAME) || + CURRENT_TOKEN(&tokenStream).t_atom != context->runtime->atomState.namespaceAtom || + !js_MatchToken(context, &tokenStream, TOK_ASSIGN) || + CURRENT_TOKEN(&tokenStream).t_op != JSOP_NOP) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_DEFAULT_XML_NAMESPACE); return NULL; } /* Is this an E4X dagger I see before me? */ tc->flags |= TCF_FUN_HEAVYWEIGHT; - pn2 = Expr(cx, ts, tc); + pn2 = expr(tc); if (!pn2) return NULL; pn->pn_op = JSOP_DEFXMLNS; @@ -5704,33 +5636,33 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #if JS_HAS_XML_SUPPORT expression: #endif - js_UngetToken(ts); - pn2 = Expr(cx, ts, tc); + js_UngetToken(&tokenStream); + pn2 = expr(tc); if (!pn2) return NULL; - if (js_PeekToken(cx, ts) == TOK_COLON) { + if (js_PeekToken(context, &tokenStream) == TOK_COLON) { if (pn2->pn_type != TOK_NAME) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL); return NULL; } label = pn2->pn_atom; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_LABEL && stmt->label == label) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL); return NULL; } } ForgetUse(pn2); - (void) js_GetToken(cx, ts); + (void) js_GetToken(context, &tokenStream); /* Push a label struct and parse the statement. */ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); stmtInfo.label = label; - pn = Statement(cx, ts, tc); + pn = statement(tc); if (!pn) return NULL; @@ -5790,7 +5722,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } /* Check termination of this primitive statement. */ - return MatchOrInsertSemicolon(cx, ts) ? pn : NULL; + return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; } static void @@ -5802,8 +5734,8 @@ NoteArgumentsUse(JSTreeContext *tc) tc->funbox->node->pn_dflags |= PND_FUNARG; } -static JSParseNode * -Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) +JSParseNode * +JSCompiler::variables(JSTreeContext *tc, bool inLetHead) { JSTokenType tt; bool let; @@ -5818,7 +5750,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) * - TOK_LP: We are parsing the head of a let block. * - Otherwise, we're parsing var declarations. */ - tt = CURRENT_TOKEN(ts).type; + tt = CURRENT_TOKEN(&tokenStream).type; let = (tt == TOK_LET || tt == TOK_LP); JS_ASSERT(let || tt == TOK_VAR); @@ -5827,7 +5759,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) JSStmtInfo *save = tc->topStmt, *saveScope = tc->topScopeStmt; #endif - /* Make sure that Statement set up the tree context correctly. */ + /* Make sure that statement set up the tree context correctly. */ scopeStmt = tc->topScopeStmt; if (let) { while (scopeStmt && !(scopeStmt->flags & SIF_SCOPE)) { @@ -5837,7 +5769,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) JS_ASSERT(scopeStmt); } - data.op = let ? JSOP_NOP : CURRENT_TOKEN(ts).t_op; + data.op = let ? JSOP_NOP : CURRENT_TOKEN(&tokenStream).t_op; pn = ListNode::create(tc); if (!pn) return NULL; @@ -5858,25 +5790,25 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) } do { - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); #if JS_HAS_DESTRUCTURING if (tt == TOK_LB || tt == TOK_LC) { tc->flags |= TCF_DECL_DESTRUCTURING; - pn2 = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); + pn2 = primaryExpr(tc, tt, JS_FALSE); tc->flags &= ~TCF_DECL_DESTRUCTURING; if (!pn2) return NULL; - if (!CheckDestructuring(cx, &data, pn2, NULL, tc)) + if (!CheckDestructuring(context, &data, pn2, NULL, tc)) return NULL; if ((tc->flags & TCF_IN_FOR_INIT) && - js_PeekToken(cx, ts) == TOK_IN) { + js_PeekToken(context, &tokenStream) == TOK_IN) { pn->append(pn2); continue; } MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); - if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) + if (CURRENT_TOKEN(&tokenStream).t_op != JSOP_NOP) goto bad_var_init; #if JS_HAS_BLOCK_SCOPE @@ -5885,7 +5817,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) tc->topScopeStmt = saveScope->downScope; } #endif - JSParseNode *init = AssignExpr(cx, ts, tc); + JSParseNode *init = assignExpr(tc); #if JS_HAS_BLOCK_SCOPE if (popScope) { tc->topStmt = save; @@ -5906,25 +5838,25 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) if (tt != TOK_NAME) { if (tt != TOK_ERROR) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_NO_VARIABLE_NAME); } return NULL; } - atom = CURRENT_TOKEN(ts).t_atom; + atom = CURRENT_TOKEN(&tokenStream).t_atom; pn2 = NewBindingNode(atom, tc, let); if (!pn2) return NULL; if (data.op == JSOP_DEFCONST) pn2->pn_dflags |= PND_CONST; data.pn = pn2; - if (!data.binder(cx, &data, atom, tc)) + if (!data.binder(context, &data, atom, tc)) return NULL; pn->append(pn2); - if (js_MatchToken(cx, ts, TOK_ASSIGN)) { - if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) + if (js_MatchToken(context, &tokenStream, TOK_ASSIGN)) { + if (CURRENT_TOKEN(&tokenStream).t_op != JSOP_NOP) goto bad_var_init; #if JS_HAS_BLOCK_SCOPE @@ -5933,7 +5865,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) tc->topScopeStmt = saveScope->downScope; } #endif - JSParseNode *init = AssignExpr(cx, ts, tc); + JSParseNode *init = assignExpr(tc); #if JS_HAS_BLOCK_SCOPE if (popScope) { tc->topStmt = save; @@ -5961,36 +5893,36 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, bool inLetHead) ? JSOP_SETCONST : JSOP_SETNAME; - NoteLValue(cx, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED); + NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED); /* The declarator's position must include the initializer. */ pn2->pn_pos.end = init->pn_pos.end; if ((tc->flags & TCF_IN_FUNCTION) && - atom == cx->runtime->atomState.argumentsAtom) { + atom == context->runtime->atomState.argumentsAtom) { NoteArgumentsUse(tc); if (!let) tc->flags |= TCF_FUN_HEAVYWEIGHT; } } - } while (js_MatchToken(cx, ts, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; return pn; bad_var_init: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_VAR_INIT); return NULL; } -static JSParseNode * -Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::expr(JSTreeContext *tc) { JSParseNode *pn, *pn2; - pn = AssignExpr(cx, ts, tc); - if (pn && js_MatchToken(cx, ts, TOK_COMMA)) { + pn = assignExpr(tc); + if (pn && js_MatchToken(context, &tokenStream, TOK_COMMA)) { pn2 = ListNode::create(tc); if (!pn2) return NULL; @@ -6001,64 +5933,64 @@ Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) #if JS_HAS_GENERATORS pn2 = pn->last(); if (pn2->pn_type == TOK_YIELD && !pn2->pn_parens) { - js_ReportCompileErrorNumber(cx, ts, pn2, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); return NULL; } #endif - pn2 = AssignExpr(cx, ts, tc); + pn2 = assignExpr(tc); if (!pn2) return NULL; pn->append(pn2); - } while (js_MatchToken(cx, ts, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; } return pn; } -static JSParseNode * -AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::assignExpr(JSTreeContext *tc) { JSParseNode *pn, *rhs; JSTokenType tt; JSOp op; - JS_CHECK_RECURSION(cx, return NULL); + JS_CHECK_RECURSION(context, return NULL); #if JS_HAS_GENERATORS - ts->flags |= TSF_OPERAND; - if (js_MatchToken(cx, ts, TOK_YIELD)) { - ts->flags &= ~TSF_OPERAND; - return ReturnOrYield(cx, ts, tc, AssignExpr); + tokenStream.flags |= TSF_OPERAND; + if (js_MatchToken(context, &tokenStream, TOK_YIELD)) { + tokenStream.flags &= ~TSF_OPERAND; + return returnOrYield(tc, true); } - ts->flags &= ~TSF_OPERAND; + tokenStream.flags &= ~TSF_OPERAND; #endif - pn = CondExpr(cx, ts, tc); + pn = condExpr(tc); if (!pn) return NULL; - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { - tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN); + tt = CheckGetterOrSetter(context, &tokenStream, TOK_ASSIGN); if (tt == TOK_ERROR) return NULL; } #endif if (tt != TOK_ASSIGN) { - js_UngetToken(ts); + js_UngetToken(&tokenStream); return pn; } - op = CURRENT_TOKEN(ts).t_op; + op = CURRENT_TOKEN(&tokenStream).t_op; switch (pn->pn_type) { case TOK_NAME: - if (!CheckStrictAssignment(cx, tc, pn)) + if (!CheckStrictAssignment(context, tc, pn)) return NULL; pn->pn_op = JSOP_SETNAME; - NoteLValue(cx, pn, tc); + NoteLValue(context, pn, tc); break; case TOK_DOT: pn->pn_op = JSOP_SETPROP; @@ -6070,17 +6002,17 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case TOK_RB: case TOK_RC: if (op != JSOP_NOP) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_DESTRUCT_ASS); return NULL; } - rhs = AssignExpr(cx, ts, tc); - if (!rhs || !CheckDestructuring(cx, NULL, pn, rhs, tc)) + rhs = assignExpr(tc); + if (!rhs || !CheckDestructuring(context, NULL, pn, rhs, tc)) return NULL; return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc); #endif case TOK_LP: - if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) + if (!MakeSetCall(context, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS)) return NULL; break; #if JS_HAS_XML_SUPPORT @@ -6092,12 +6024,12 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* FALL THROUGH */ #endif default: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); return NULL; } - rhs = AssignExpr(cx, ts, tc); + rhs = assignExpr(tc); if (rhs && PN_TYPE(pn) == TOK_NAME && pn->pn_used) { JSDefinition *dn = pn->pn_lexdef; @@ -6117,14 +6049,14 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc); } -static JSParseNode * -CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::condExpr(JSTreeContext *tc) { JSParseNode *pn, *pn1, *pn2, *pn3; uintN oldflags; - pn = OrExpr(cx, ts, tc); - if (pn && js_MatchToken(cx, ts, TOK_HOOK)) { + pn = orExpr(tc); + if (pn && js_MatchToken(context, &tokenStream, TOK_HOOK)) { pn1 = pn; pn = TernaryNode::create(tc); if (!pn) @@ -6136,13 +6068,13 @@ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) */ oldflags = tc->flags; tc->flags &= ~TCF_IN_FOR_INIT; - pn2 = AssignExpr(cx, ts, tc); + pn2 = assignExpr(tc); tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); if (!pn2) return NULL; MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND); - pn3 = AssignExpr(cx, ts, tc); + pn3 = assignExpr(tc); if (!pn3) return NULL; pn->pn_pos.begin = pn1->pn_pos.begin; @@ -6154,80 +6086,79 @@ CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn; } -static JSParseNode * -OrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::orExpr(JSTreeContext *tc) { JSParseNode *pn; - pn = AndExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_OR)) - pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, AndExpr(cx, ts, tc), tc); + pn = andExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_OR)) + pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr(tc), tc); return pn; } -static JSParseNode * -AndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::andExpr(JSTreeContext *tc) { JSParseNode *pn; - pn = BitOrExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_AND)) - pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, BitOrExpr(cx, ts, tc), tc); + pn = bitOrExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_AND)) + pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr(tc), tc); return pn; } -static JSParseNode * -BitOrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::bitOrExpr(JSTreeContext *tc) { JSParseNode *pn; - pn = BitXorExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_BITOR)) { - pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc), tc); + pn = bitXorExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_BITOR)) { + pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr(tc), tc); } return pn; } -static JSParseNode * -BitXorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::bitXorExpr(JSTreeContext *tc) { JSParseNode *pn; - pn = BitAndExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_BITXOR)) { - pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc), - tc); + pn = bitAndExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_BITXOR)) { + pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr(tc), tc); } return pn; } -static JSParseNode * -BitAndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::bitAndExpr(JSTreeContext *tc) { JSParseNode *pn; - pn = EqExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_BITAND)) - pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc); + pn = eqExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_BITAND)) + pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr(tc), tc); return pn; } -static JSParseNode * -EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::eqExpr(JSTreeContext *tc) { JSParseNode *pn; JSOp op; - pn = RelExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_EQOP)) { - op = CURRENT_TOKEN(ts).t_op; - pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc); + pn = relExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_EQOP)) { + op = CURRENT_TOKEN(&tokenStream).t_op; + pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr(tc), tc); } return pn; } -static JSParseNode * -RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::relExpr(JSTreeContext *tc) { JSParseNode *pn; JSTokenType tt; @@ -6235,23 +6166,23 @@ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT; /* - * Uses of the in operator in ShiftExprs are always unambiguous, + * Uses of the in operator in shiftExprs are always unambiguous, * so unset the flag that prohibits recognizing it. */ tc->flags &= ~TCF_IN_FOR_INIT; - pn = ShiftExpr(cx, ts, tc); + pn = shiftExpr(tc); while (pn && - (js_MatchToken(cx, ts, TOK_RELOP) || + (js_MatchToken(context, &tokenStream, TOK_RELOP) || /* * Recognize the 'in' token as an operator only if we're not * currently in the init expr of a for loop. */ - (inForInitFlag == 0 && js_MatchToken(cx, ts, TOK_IN)) || - js_MatchToken(cx, ts, TOK_INSTANCEOF))) { - tt = CURRENT_TOKEN(ts).type; - op = CURRENT_TOKEN(ts).t_op; - pn = JSParseNode::newBinaryOrAppend(tt, op, pn, ShiftExpr(cx, ts, tc), tc); + (inForInitFlag == 0 && js_MatchToken(context, &tokenStream, TOK_IN)) || + js_MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { + tt = CURRENT_TOKEN(&tokenStream).type; + op = CURRENT_TOKEN(&tokenStream).t_op; + pn = JSParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr(tc), tc); } /* Restore previous state of inForInit flag. */ tc->flags |= inForInitFlag; @@ -6259,52 +6190,52 @@ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn; } -static JSParseNode * -ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::shiftExpr(JSTreeContext *tc) { JSParseNode *pn; JSOp op; - pn = AddExpr(cx, ts, tc); - while (pn && js_MatchToken(cx, ts, TOK_SHOP)) { - op = CURRENT_TOKEN(ts).t_op; - pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc); + pn = addExpr(tc); + while (pn && js_MatchToken(context, &tokenStream, TOK_SHOP)) { + op = CURRENT_TOKEN(&tokenStream).t_op; + pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr(tc), tc); } return pn; } -static JSParseNode * -AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::addExpr(JSTreeContext *tc) { JSParseNode *pn; JSTokenType tt; JSOp op; - pn = MulExpr(cx, ts, tc); + pn = mulExpr(tc); while (pn && - (js_MatchToken(cx, ts, TOK_PLUS) || - js_MatchToken(cx, ts, TOK_MINUS))) { - tt = CURRENT_TOKEN(ts).type; + (js_MatchToken(context, &tokenStream, TOK_PLUS) || + js_MatchToken(context, &tokenStream, TOK_MINUS))) { + tt = CURRENT_TOKEN(&tokenStream).type; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; - pn = JSParseNode::newBinaryOrAppend(tt, op, pn, MulExpr(cx, ts, tc), tc); + pn = JSParseNode::newBinaryOrAppend(tt, op, pn, mulExpr(tc), tc); } return pn; } -static JSParseNode * -MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::mulExpr(JSTreeContext *tc) { JSParseNode *pn; JSTokenType tt; JSOp op; - pn = UnaryExpr(cx, ts, tc); + pn = unaryExpr(tc); while (pn && - (js_MatchToken(cx, ts, TOK_STAR) || - js_MatchToken(cx, ts, TOK_DIVOP))) { - tt = CURRENT_TOKEN(ts).type; - op = CURRENT_TOKEN(ts).t_op; - pn = JSParseNode::newBinaryOrAppend(tt, op, pn, UnaryExpr(cx, ts, tc), tc); + (js_MatchToken(context, &tokenStream, TOK_STAR) || + js_MatchToken(context, &tokenStream, TOK_DIVOP))) { + tt = CURRENT_TOKEN(&tokenStream).type; + op = CURRENT_TOKEN(&tokenStream).t_op; + pn = JSParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(tc), tc); } return pn; } @@ -6381,17 +6312,17 @@ SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return JS_TRUE; } -static JSParseNode * -UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::unaryExpr(JSTreeContext *tc) { JSTokenType tt; JSParseNode *pn, *pn2; - JS_CHECK_RECURSION(cx, return NULL); + JS_CHECK_RECURSION(context, return NULL); - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; switch (tt) { case TOK_UNARYOP: @@ -6401,8 +6332,8 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (!pn) return NULL; pn->pn_type = TOK_UNARYOP; /* PLUS and MINUS are binary */ - pn->pn_op = CURRENT_TOKEN(ts).t_op; - pn2 = UnaryExpr(cx, ts, tc); + pn->pn_op = CURRENT_TOKEN(&tokenStream).t_op; + pn2 = unaryExpr(tc); if (!pn2) return NULL; pn->pn_pos.end = pn2->pn_pos.end; @@ -6414,10 +6345,10 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = UnaryNode::create(tc); if (!pn) return NULL; - pn2 = MemberExpr(cx, ts, tc, JS_TRUE); + pn2 = memberExpr(tc, JS_TRUE); if (!pn2) return NULL; - if (!SetIncOpKid(cx, ts, tc, pn, pn2, tt, JS_TRUE)) + if (!SetIncOpKid(context, &tokenStream, tc, pn, pn2, tt, JS_TRUE)) return NULL; pn->pn_pos.end = pn2->pn_pos.end; break; @@ -6426,7 +6357,7 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = UnaryNode::create(tc); if (!pn) return NULL; - pn2 = UnaryExpr(cx, ts, tc); + pn2 = unaryExpr(tc); if (!pn2) return NULL; pn->pn_pos.end = pn2->pn_pos.end; @@ -6436,17 +6367,17 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * returns true. Here we fold constants before checking for a call * expression, in order to rule out delete of a generator expression. */ - if (!js_FoldConstants(cx, pn2, tc)) + if (!js_FoldConstants(context, pn2, tc)) return NULL; switch (pn2->pn_type) { case TOK_LP: if (pn2->pn_op != JSOP_SETCALL && - !MakeSetCall(cx, pn2, tc, JSMSG_BAD_DELETE_OPERAND)) { + !MakeSetCall(context, pn2, tc, JSMSG_BAD_DELETE_OPERAND)) { return NULL; } break; case TOK_NAME: - if (!js_ReportStrictModeError(cx, ts, tc, pn, JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!js_ReportStrictModeError(context, &tokenStream, tc, pn, JSMSG_DEPRECATED_DELETE_OPERAND)) return NULL; pn2->pn_op = JSOP_DELNAME; break; @@ -6459,22 +6390,22 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return NULL; default: - js_UngetToken(ts); - pn = MemberExpr(cx, ts, tc, JS_TRUE); + js_UngetToken(&tokenStream); + pn = memberExpr(tc, JS_TRUE); if (!pn) return NULL; /* Don't look across a newline boundary for a postfix incop. */ - if (ON_CURRENT_LINE(ts, pn->pn_pos)) { - ts->flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(cx, ts); - ts->flags &= ~TSF_OPERAND; + if (ON_CURRENT_LINE(&tokenStream, pn->pn_pos)) { + tokenStream.flags |= TSF_OPERAND; + tt = js_PeekTokenSameLine(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_INC || tt == TOK_DEC) { - (void) js_GetToken(cx, ts); + (void) js_GetToken(context, &tokenStream); pn2 = UnaryNode::create(tc); if (!pn2) return NULL; - if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE)) + if (!SetIncOpKid(context, &tokenStream, tc, pn2, pn, tt, JS_FALSE)) return NULL; pn2->pn_pos.begin = pn->pn_pos.begin; pn = pn2; @@ -6713,13 +6644,10 @@ CompExprTransplanter::transplant(JSParseNode *pn) * comprehension or generator expression, with a unary node as the body of the * (possibly nested) for-loop, initialized by |type, op, kid|. */ -static JSParseNode * -ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, - JSTokenType type = TOK_SEMI, JSOp op = JSOP_NOP) +JSParseNode * +JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, + JSTokenType type, JSOp op) { - JSContext *cx = tc->compiler->context; - JSTokenStream *ts = TS(tc->compiler); - uintN adjust; JSParseNode *pn, *pn2, *pn3, **pnp; JSStmtInfo stmtInfo; @@ -6727,7 +6655,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, JSTokenType tt; JSAtom *atom; - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_FOR); + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_FOR); if (type == TOK_SEMI) { /* @@ -6735,7 +6663,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, * yields the next value from a for-in loop (possibly nested, and with * optional if guard). Make pn be the TOK_LC body node. */ - pn = PushLexicalScope(cx, ts, tc, &stmtInfo); + pn = PushLexicalScope(context, &tokenStream, tc, &stmtInfo); if (!pn) return NULL; adjust = pn->pn_blockid - blockid; @@ -6744,7 +6672,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, /* * Make a parse-node and literal object representing the block scope of - * this array comprehension. Our caller in PrimaryExpr, the TOK_LB case + * this array comprehension. Our caller in primaryExpr, the TOK_LB case * aka the array initialiser case, has passed the blockid to claim for * the comprehension's block scope. We allocate that id or one above it * here, by calling js_PushLexicalScope. @@ -6755,7 +6683,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, * block scope. */ adjust = tc->blockid(); - pn = PushLexicalScope(cx, ts, tc, &stmtInfo); + pn = PushLexicalScope(context, &tokenStream, tc, &stmtInfo); if (!pn) return NULL; @@ -6789,22 +6717,22 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, pn2->pn_op = JSOP_ITER; pn2->pn_iflags = JSITER_ENUMERATE; - if (js_MatchToken(cx, ts, TOK_NAME)) { - if (CURRENT_TOKEN(ts).t_atom == cx->runtime->atomState.eachAtom) + if (js_MatchToken(context, &tokenStream, TOK_NAME)) { + if (CURRENT_TOKEN(&tokenStream).t_atom == context->runtime->atomState.eachAtom) pn2->pn_iflags |= JSITER_FOREACH; else - js_UngetToken(ts); + js_UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); atom = NULL; - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: case TOK_LC: tc->flags |= TCF_DECL_DESTRUCTURING; - pn3 = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); + pn3 = primaryExpr(tc, tt, JS_FALSE); tc->flags &= ~TCF_DECL_DESTRUCTURING; if (!pn3) return NULL; @@ -6812,7 +6740,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, #endif case TOK_NAME: - atom = CURRENT_TOKEN(ts).t_atom; + atom = CURRENT_TOKEN(&tokenStream).t_atom; /* * Create a name node with pn_op JSOP_NAME. We can't set pn_op to @@ -6827,7 +6755,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, break; default: - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_NO_VARIABLE_NAME); case TOK_ERROR: @@ -6835,7 +6763,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, } MUST_MATCH_TOKEN(TOK_IN, JSMSG_IN_AFTER_FOR_NAME); - JSParseNode *pn4 = Expr(cx, ts, tc); + JSParseNode *pn4 = expr(tc); if (!pn4) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL); @@ -6844,13 +6772,13 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, #if JS_HAS_DESTRUCTURING case TOK_LB: case TOK_LC: - if (!CheckDestructuring(cx, &data, pn3, NULL, tc)) + if (!CheckDestructuring(context, &data, pn3, NULL, tc)) return NULL; - if (JSVERSION_NUMBER(cx) == JSVERSION_1_7) { + if (JSVERSION_NUMBER(context) == JSVERSION_1_7) { /* Destructuring requires [key, value] enumeration in JS1.7. */ if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -6865,7 +6793,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, case TOK_NAME: data.pn = pn3; - if (!data.binder(cx, &data, atom, tc)) + if (!data.binder(context, &data, atom, tc)) return NULL; break; @@ -6877,13 +6805,13 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, return NULL; *pnp = pn2; pnp = &pn2->pn_right; - } while (js_MatchToken(cx, ts, TOK_FOR)); + } while (js_MatchToken(context, &tokenStream, TOK_FOR)); - if (js_MatchToken(cx, ts, TOK_IF)) { + if (js_MatchToken(context, &tokenStream, TOK_IF)) { pn2 = TernaryNode::create(tc); if (!pn2) return NULL; - pn2->pn_kid1 = Condition(cx, ts, tc); + pn2->pn_kid1 = condition(tc); if (!pn2->pn_kid1) return NULL; *pnp = pn2; @@ -6910,7 +6838,7 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, * generator function that is immediately called to evaluate to the generator * iterator that is the value of this generator expression. * - * Callers pass a blank unary node via pn, which GeneratorExpr fills in as the + * Callers pass a blank unary node via pn, which generatorExpr fills in as the * yield expression, which ComprehensionTail in turn wraps in a TOK_SEMI-type * expression-statement node that constitutes the body of the |for| loop(s) in * the generator function. @@ -6919,8 +6847,8 @@ ComprehensionTail(JSParseNode *kid, uintN blockid, JSTreeContext *tc, * the first |in| in the chain of |for| heads. Instead, a generator expression * is merely sugar for a generator function expression and its application. */ -static JSParseNode * -GeneratorExpr(JSParseNode *pn, JSParseNode *kid, JSTreeContext *tc) +JSParseNode * +JSCompiler::generatorExpr(JSParseNode *pn, JSParseNode *kid, JSTreeContext *tc) { /* Initialize pn, connecting it to kid. */ JS_ASSERT(pn->pn_arity == PN_UNARY); @@ -6972,13 +6900,13 @@ GeneratorExpr(JSParseNode *pn, JSParseNode *kid, JSTreeContext *tc) genfn->pn_funbox = funbox; genfn->pn_blockid = gentc.bodyid; - JSParseNode *body = ComprehensionTail(pn, tc->blockid(), &gentc); + JSParseNode *body = comprehensionTail(pn, tc->blockid(), &gentc); if (!body) return NULL; JS_ASSERT(!genfn->pn_body); genfn->pn_body = body; genfn->pn_pos.begin = body->pn_pos.begin = kid->pn_pos.begin; - genfn->pn_pos.end = body->pn_pos.end = CURRENT_TOKEN(TS(tc->compiler)).pos.end; + genfn->pn_pos.end = body->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; if (!LeaveFunction(genfn, &gentc, tc)) return NULL; @@ -7003,41 +6931,40 @@ static const char js_generator_str[] = "generator"; #endif /* JS_HAS_GENERATOR_EXPRS */ #endif /* JS_HAS_GENERATORS */ -static JSBool -ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParseNode *listNode) +JSBool +JSCompiler::argumentList(JSTreeContext *tc, JSParseNode *listNode) { JSBool matched; - ts->flags |= TSF_OPERAND; - matched = js_MatchToken(cx, ts, TOK_RP); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + matched = js_MatchToken(context, &tokenStream, TOK_RP); + tokenStream.flags &= ~TSF_OPERAND; if (!matched) { do { - JSParseNode *argNode = AssignExpr(cx, ts, tc); + JSParseNode *argNode = assignExpr(tc); if (!argNode) return JS_FALSE; #if JS_HAS_GENERATORS if (argNode->pn_type == TOK_YIELD && !argNode->pn_parens && - js_PeekToken(cx, ts) == TOK_COMMA) { - js_ReportCompileErrorNumber(cx, ts, argNode, JSREPORT_ERROR, + js_PeekToken(context, &tokenStream) == TOK_COMMA) { + js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); return JS_FALSE; } #endif #if JS_HAS_GENERATOR_EXPRS - if (js_MatchToken(cx, ts, TOK_FOR)) { + if (js_MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pn = UnaryNode::create(tc); if (!pn) return JS_FALSE; - argNode = GeneratorExpr(pn, argNode, tc); + argNode = generatorExpr(pn, argNode, tc); if (!argNode) return JS_FALSE; if (listNode->pn_count > 1 || - js_PeekToken(cx, ts) == TOK_COMMA) { - js_ReportCompileErrorNumber(cx, ts, argNode, JSREPORT_ERROR, + js_PeekToken(context, &tokenStream) == TOK_COMMA) { + js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); return JS_FALSE; @@ -7045,10 +6972,10 @@ ArgumentList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } #endif listNode->append(argNode); - } while (js_MatchToken(cx, ts, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); - if (js_GetToken(cx, ts) != TOK_RP) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + if (js_GetToken(context, &tokenStream) != TOK_RP) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_ARGS); return JS_FALSE; } @@ -7071,24 +6998,23 @@ CheckForImmediatelyAppliedLambda(JSParseNode *pn) return pn; } -static JSParseNode * -MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowCallSyntax) +JSParseNode * +JSCompiler::memberExpr(JSTreeContext *tc, JSBool allowCallSyntax) { JSParseNode *pn, *pn2, *pn3; JSTokenType tt; - JS_CHECK_RECURSION(cx, return NULL); + JS_CHECK_RECURSION(context, return NULL); /* Check for new expression first. */ - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_NEW) { pn = ListNode::create(tc); if (!pn) return NULL; - pn2 = MemberExpr(cx, ts, tc, JS_FALSE); + pn2 = memberExpr(tc, JS_FALSE); if (!pn2) return NULL; pn2 = CheckForImmediatelyAppliedLambda(pn2); @@ -7096,16 +7022,16 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->initList(pn2); pn->pn_pos.begin = pn2->pn_pos.begin; - if (js_MatchToken(cx, ts, TOK_LP) && !ArgumentList(cx, ts, tc, pn)) + if (js_MatchToken(context, &tokenStream, TOK_LP) && !argumentList(tc, pn)) return NULL; if (pn->pn_count > ARGC_LIMIT) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JS_ReportErrorNumber(context, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_CON_ARGS); return NULL; } pn->pn_pos.end = pn->last()->pn_pos.end; } else { - pn = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); + pn = primaryExpr(tc, tt, JS_FALSE); if (!pn) return NULL; @@ -7125,16 +7051,16 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } } - while ((tt = js_GetToken(cx, ts)) > TOK_EOF) { + while ((tt = js_GetToken(context, &tokenStream)) > TOK_EOF) { if (tt == TOK_DOT) { pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; #if JS_HAS_XML_SUPPORT - ts->flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = js_GetToken(cx, ts); - ts->flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); - pn3 = PrimaryExpr(cx, ts, tc, tt, JS_TRUE); + tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); + pn3 = primaryExpr(tc, tt, JS_TRUE); if (!pn3) return NULL; @@ -7155,7 +7081,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->pn_type = TOK_LB; pn2->pn_op = JSOP_GETELEM; } else { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT); return NULL; } @@ -7164,24 +7090,24 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->pn_right = pn3; } #else - ts->flags |= TSF_KEYWORD_IS_NAME; + tokenStream.flags |= TSF_KEYWORD_IS_NAME; MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT); - ts->flags &= ~TSF_KEYWORD_IS_NAME; + tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; pn2->pn_op = JSOP_GETPROP; pn2->pn_expr = pn; - pn2->pn_atom = CURRENT_TOKEN(ts).t_atom; + pn2->pn_atom = CURRENT_TOKEN(&tokenStream).t_atom; #endif pn2->pn_pos.begin = pn->pn_pos.begin; - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn2->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; #if JS_HAS_XML_SUPPORT } else if (tt == TOK_DBLDOT) { pn2 = BinaryNode::create(tc); if (!pn2) return NULL; - ts->flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = js_GetToken(cx, ts); - ts->flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); - pn3 = PrimaryExpr(cx, ts, tc, tt, JS_TRUE); + tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); + pn3 = primaryExpr(tc, tt, JS_TRUE); if (!pn3) return NULL; tt = PN_TYPE(pn3); @@ -7190,7 +7116,7 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn3->pn_arity = PN_NULLARY; pn3->pn_op = JSOP_QNAMEPART; } else if (!TOKEN_TYPE_IS_XML(tt)) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT); return NULL; } @@ -7198,19 +7124,19 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->pn_left = pn; pn2->pn_right = pn3; pn2->pn_pos.begin = pn->pn_pos.begin; - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn2->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; #endif } else if (tt == TOK_LB) { pn2 = BinaryNode::create(tc); if (!pn2) return NULL; - pn3 = Expr(cx, ts, tc); + pn3 = expr(tc); if (!pn3) return NULL; MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); pn2->pn_pos.begin = pn->pn_pos.begin; - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn2->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; /* * Optimize o['p'] to o.p by rewriting pn2, but avoid rewriting @@ -7247,14 +7173,14 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn = CheckForImmediatelyAppliedLambda(pn); if (pn->pn_op == JSOP_NAME) { - if (pn->pn_atom == cx->runtime->atomState.evalAtom) { + if (pn->pn_atom == context->runtime->atomState.evalAtom) { /* Select JSOP_EVAL and flag tc as heavyweight. */ pn2->pn_op = JSOP_EVAL; tc->flags |= TCF_FUN_HEAVYWEIGHT; } } else if (pn->pn_op == JSOP_GETPROP) { - if (pn->pn_atom == cx->runtime->atomState.applyAtom || - pn->pn_atom == cx->runtime->atomState.callAtom) { + if (pn->pn_atom == context->runtime->atomState.applyAtom || + pn->pn_atom == context->runtime->atomState.callAtom) { /* Select JSOP_APPLY given foo.apply(...). */ pn2->pn_op = JSOP_APPLY; } @@ -7263,16 +7189,16 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn2->initList(pn); pn2->pn_pos.begin = pn->pn_pos.begin; - if (!ArgumentList(cx, ts, tc, pn2)) + if (!argumentList(tc, pn2)) return NULL; if (pn2->pn_count > ARGC_LIMIT) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JS_ReportErrorNumber(context, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_ARGS); return NULL; } - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn2->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; } else { - js_UngetToken(ts); + js_UngetToken(&tokenStream); return pn; } @@ -7283,8 +7209,8 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return pn; } -static JSParseNode * -BracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::bracketedExpr(JSTreeContext *tc) { uintN oldflags; JSParseNode *pn; @@ -7296,19 +7222,19 @@ BracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) */ oldflags = tc->flags; tc->flags &= ~TCF_IN_FOR_INIT; - pn = Expr(cx, ts, tc); + pn = expr(tc); tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); return pn; } #if JS_HAS_XML_SUPPORT -static JSParseNode * -EndBracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::endBracketedExpr(JSTreeContext *tc) { JSParseNode *pn; - pn = BracketedExpr(cx, ts, tc); + pn = bracketedExpr(tc); if (!pn) return NULL; @@ -7367,8 +7293,8 @@ EndBracketedExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * We hoist the :: match into callers of QualifiedSuffix, in order to tweak * PropertySelector vs. Identifier pn_arity, pn_op, and other members. */ -static JSParseNode * -PropertySelector(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::propertySelector(JSTreeContext *tc) { JSParseNode *pn; @@ -7378,25 +7304,24 @@ PropertySelector(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (pn->pn_type == TOK_STAR) { pn->pn_type = TOK_ANYNAME; pn->pn_op = JSOP_ANYNAME; - pn->pn_atom = cx->runtime->atomState.starAtom; + pn->pn_atom = context->runtime->atomState.starAtom; } else { JS_ASSERT(pn->pn_type == TOK_NAME); pn->pn_op = JSOP_QNAMEPART; pn->pn_arity = PN_NAME; - pn->pn_atom = CURRENT_TOKEN(ts).t_atom; + pn->pn_atom = CURRENT_TOKEN(&tokenStream).t_atom; pn->pn_cookie = FREE_UPVAR_COOKIE; } return pn; } -static JSParseNode * -QualifiedSuffix(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, - JSTreeContext *tc) +JSParseNode * +JSCompiler::qualifiedSuffix(JSParseNode *pn, JSTreeContext *tc) { JSParseNode *pn2, *pn3; JSTokenType tt; - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_DBLCOLON); + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_DBLCOLON); pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; @@ -7405,27 +7330,27 @@ QualifiedSuffix(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, if (pn->pn_op == JSOP_QNAMEPART) pn->pn_op = JSOP_NAME; - ts->flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_KEYWORD_IS_NAME; + tokenStream.flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { - /* Inline and specialize PropertySelector for JSOP_QNAMECONST. */ + /* Inline and specialize propertySelector for JSOP_QNAMECONST. */ pn2->pn_op = JSOP_QNAMECONST; pn2->pn_pos.begin = pn->pn_pos.begin; pn2->pn_atom = (tt == TOK_STAR) - ? cx->runtime->atomState.starAtom - : CURRENT_TOKEN(ts).t_atom; + ? context->runtime->atomState.starAtom + : CURRENT_TOKEN(&tokenStream).t_atom; pn2->pn_expr = pn; pn2->pn_cookie = FREE_UPVAR_COOKIE; return pn2; } if (tt != TOK_LB) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); return NULL; } - pn3 = EndBracketedExpr(cx, ts, tc); + pn3 = endBracketedExpr(tc); if (!pn3) return NULL; @@ -7438,42 +7363,42 @@ QualifiedSuffix(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, return pn2; } -static JSParseNode * -QualifiedIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::qualifiedIdentifier(JSTreeContext *tc) { JSParseNode *pn; - pn = PropertySelector(cx, ts, tc); + pn = propertySelector(tc); if (!pn) return NULL; - if (js_MatchToken(cx, ts, TOK_DBLCOLON)) { + if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; - pn = QualifiedSuffix(cx, ts, pn, tc); + pn = qualifiedSuffix(pn, tc); } return pn; } -static JSParseNode * -AttributeIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::attributeIdentifier(JSTreeContext *tc) { JSParseNode *pn, *pn2; JSTokenType tt; - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_AT); + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_AT); pn = UnaryNode::create(tc); if (!pn) return NULL; pn->pn_op = JSOP_TOATTRNAME; - ts->flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_KEYWORD_IS_NAME; + tokenStream.flags |= TSF_KEYWORD_IS_NAME; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { - pn2 = QualifiedIdentifier(cx, ts, tc); + pn2 = qualifiedIdentifier(tc); } else if (tt == TOK_LB) { - pn2 = EndBracketedExpr(cx, ts, tc); + pn2 = endBracketedExpr(tc); } else { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); return NULL; } @@ -7486,13 +7411,13 @@ AttributeIdentifier(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) /* * Make a TOK_LC unary node whose pn_kid is an expression. */ -static JSParseNode * -XMLExpr(JSContext *cx, JSTokenStream *ts, JSBool inTag, JSTreeContext *tc) +JSParseNode * +JSCompiler::xmlExpr(JSBool inTag, JSTreeContext *tc) { JSParseNode *pn, *pn2; uintN oldflag; - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_LC); + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_LC); pn = UnaryNode::create(tc); if (!pn) return NULL; @@ -7503,14 +7428,14 @@ XMLExpr(JSContext *cx, JSTokenStream *ts, JSBool inTag, JSTreeContext *tc) * within text contained in an element, but outside of any start, end, or * point tag. */ - oldflag = ts->flags & TSF_XMLTAGMODE; - ts->flags &= ~TSF_XMLTAGMODE; - pn2 = Expr(cx, ts, tc); + oldflag = tokenStream.flags & TSF_XMLTAGMODE; + tokenStream.flags &= ~TSF_XMLTAGMODE; + pn2 = expr(tc); if (!pn2) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR); - ts->flags |= oldflag; + tokenStream.flags |= oldflag; pn->pn_kid = pn2; pn->pn_op = inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR; return pn; @@ -7522,8 +7447,8 @@ XMLExpr(JSContext *cx, JSTokenStream *ts, JSBool inTag, JSTreeContext *tc) * parse tree to XML, we preserve a TOK_XMLSPACE node only if it's the sole * child of a container tag. */ -static JSParseNode * -XMLAtomNode(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::xmlAtomNode(JSTreeContext *tc) { JSParseNode *pn; JSToken *tp; @@ -7531,7 +7456,7 @@ XMLAtomNode(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn = NullaryNode::create(tc); if (!pn) return NULL; - tp = &CURRENT_TOKEN(ts); + tp = &CURRENT_TOKEN(&tokenStream); pn->pn_op = tp->t_op; pn->pn_atom = tp->t_atom; if (tp->type == TOK_XMLPI) @@ -7551,22 +7476,22 @@ XMLAtomNode(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * If PN_LIST or PN_NULLARY, pn_type will be TOK_XMLNAME; if PN_UNARY, pn_type * will be TOK_LC. */ -static JSParseNode * -XMLNameExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) +JSParseNode * +JSCompiler::xmlNameExpr(JSTreeContext *tc) { JSParseNode *pn, *pn2, *list; JSTokenType tt; pn = list = NULL; do { - tt = CURRENT_TOKEN(ts).type; + tt = CURRENT_TOKEN(&tokenStream).type; if (tt == TOK_LC) { - pn2 = XMLExpr(cx, ts, JS_TRUE, tc); + pn2 = xmlExpr(JS_TRUE, tc); if (!pn2) return NULL; } else { JS_ASSERT(tt == TOK_XMLNAME); - pn2 = XMLAtomNode(cx, ts, tc); + pn2 = xmlAtomNode(tc); if (!pn2) return NULL; } @@ -7587,9 +7512,9 @@ XMLNameExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_pos.end = pn2->pn_pos.end; pn->append(pn2); } - } while ((tt = js_GetToken(cx, ts)) == TOK_XMLNAME || tt == TOK_LC); + } while ((tt = js_GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); - js_UngetToken(ts); + js_UngetToken(&tokenStream); return pn; } @@ -7618,27 +7543,26 @@ XMLNameExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * PN_LIST, pn_type will be tagtype. If PN_UNARY, pn_type will be TOK_LC and * we parsed exactly one expression. */ -static JSParseNode * -XMLTagContent(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSTokenType tagtype, JSAtom **namep) +JSParseNode * +JSCompiler::xmlTagContent(JSTreeContext *tc, JSTokenType tagtype, JSAtom **namep) { JSParseNode *pn, *pn2, *list; JSTokenType tt; - pn = XMLNameExpr(cx, ts, tc); + pn = xmlNameExpr(tc); if (!pn) return NULL; *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; list = NULL; - while (js_MatchToken(cx, ts, TOK_XMLSPACE)) { - tt = js_GetToken(cx, ts); + while (js_MatchToken(context, &tokenStream, TOK_XMLSPACE)) { + tt = js_GetToken(context, &tokenStream); if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_UngetToken(ts); + js_UngetToken(&tokenStream); break; } - pn2 = XMLNameExpr(cx, ts, tc); + pn2 = xmlNameExpr(tc); if (!pn2) return NULL; if (!list) { @@ -7654,18 +7578,18 @@ XMLTagContent(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (!XML_FOLDABLE(pn2)) pn->pn_xflags |= PNX_CANTFOLD; - js_MatchToken(cx, ts, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); - js_MatchToken(cx, ts, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_XMLATTR) { - pn2 = XMLAtomNode(cx, ts, tc); + pn2 = xmlAtomNode(tc); } else if (tt == TOK_LC) { - pn2 = XMLExpr(cx, ts, JS_TRUE, tc); + pn2 = xmlExpr(JS_TRUE, tc); pn->pn_xflags |= PNX_CANTFOLD; } else { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_ATTR_VALUE); return NULL; } @@ -7678,63 +7602,58 @@ XMLTagContent(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return pn; } -#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ - JS_BEGIN_MACRO \ - if ((tt) <= TOK_EOF) { \ - if ((tt) == TOK_EOF) { \ - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, \ - JSMSG_END_OF_XML_SOURCE); \ - } \ - return result; \ - } \ +#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ + JS_BEGIN_MACRO \ + if ((tt) <= TOK_EOF) { \ + if ((tt) == TOK_EOF) { \ + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ + JSMSG_END_OF_XML_SOURCE); \ + } \ + return result; \ + } \ JS_END_MACRO -static JSParseNode * -XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowList); - /* * Consume XML element tag content, including the TOK_XMLETAGO (flags &= ~TSF_XMLTAGMODE; + tokenStream.flags &= ~TSF_XMLTAGMODE; for (;;) { - ts->flags |= TSF_XMLTEXTMODE; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_XMLTEXTMODE; + tokenStream.flags |= TSF_XMLTEXTMODE; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_XMLTEXTMODE; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); JS_ASSERT(tt == TOK_XMLSPACE || tt == TOK_XMLTEXT); - textAtom = CURRENT_TOKEN(ts).t_atom; + textAtom = CURRENT_TOKEN(&tokenStream).t_atom; if (textAtom) { /* Non-zero-length XML text scanned. */ - pn2 = XMLAtomNode(cx, ts, tc); + pn2 = xmlAtomNode(tc); if (!pn2) return JS_FALSE; pn->pn_pos.end = pn2->pn_pos.end; pn->append(pn2); } - ts->flags |= TSF_OPERAND; - tt = js_GetToken(cx, ts); - ts->flags &= ~TSF_OPERAND; + tokenStream.flags |= TSF_OPERAND; + tt = js_GetToken(context, &tokenStream); + tokenStream.flags &= ~TSF_OPERAND; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); if (tt == TOK_XMLETAGO) break; if (tt == TOK_LC) { - pn2 = XMLExpr(cx, ts, JS_FALSE, tc); + pn2 = xmlExpr(JS_FALSE, tc); pn->pn_xflags |= PNX_CANTFOLD; } else if (tt == TOK_XMLSTAGO) { - pn2 = XMLElementOrList(cx, ts, tc, JS_FALSE); + pn2 = xmlElementOrList(tc, JS_FALSE); if (pn2) { pn2->pn_xflags &= ~PNX_XMLROOT; pn->pn_xflags |= pn2->pn_xflags; @@ -7742,7 +7661,7 @@ XMLElementContent(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, } else { JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT || tt == TOK_XMLPI); - pn2 = XMLAtomNode(cx, ts, tc); + pn2 = xmlAtomNode(tc); } if (!pn2) return JS_FALSE; @@ -7750,31 +7669,30 @@ XMLElementContent(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, pn->append(pn2); } - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLETAGO); - ts->flags |= TSF_XMLTAGMODE; + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_XMLETAGO); + tokenStream.flags |= TSF_XMLTAGMODE; return JS_TRUE; } /* * Return a PN_LIST node containing an XML or XMLList Initialiser. */ -static JSParseNode * -XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowList) +JSParseNode * +JSCompiler::xmlElementOrList(JSTreeContext *tc, JSBool allowList) { JSParseNode *pn, *pn2, *list; JSTokenType tt; JSAtom *startAtom, *endAtom; - JS_CHECK_RECURSION(cx, return NULL); + JS_CHECK_RECURSION(context, return NULL); - JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_XMLSTAGO); + JS_ASSERT(CURRENT_TOKEN(&tokenStream).type == TOK_XMLSTAGO); pn = ListNode::create(tc); if (!pn) return NULL; - ts->flags |= TSF_XMLTAGMODE; - tt = js_GetToken(cx, ts); + tokenStream.flags |= TSF_XMLTAGMODE; + tt = js_GetToken(context, &tokenStream); if (tt == TOK_ERROR) return NULL; @@ -7782,12 +7700,12 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* * XMLElement. Append the tag and its contents, if any, to pn. */ - pn2 = XMLTagContent(cx, ts, tc, TOK_XMLSTAGO, &startAtom); + pn2 = xmlTagContent(tc, TOK_XMLSTAGO, &startAtom); if (!pn2) return NULL; - js_MatchToken(cx, ts, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_XMLPTAGC) { /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ if (pn2->pn_type == TOK_XMLSTAGO) { @@ -7806,11 +7724,11 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } else { /* We had better have a tag-close (>) at this point. */ if (tt != TOK_XMLTAGC) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } - pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + pn2->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */ if (pn2->pn_type != TOK_XMLSTAGO) { @@ -7832,24 +7750,24 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->pn_xflags |= PNX_XMLROOT; /* Get element contents and delimiting end-tag-open sequence. */ - if (!XMLElementContent(cx, ts, pn, tc)) + if (!xmlElementContent(pn, tc)) return NULL; - tt = js_GetToken(cx, ts); + tt = js_GetToken(context, &tokenStream); XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } /* Parse end tag; check mismatch at compile-time if we can. */ - pn2 = XMLTagContent(cx, ts, tc, TOK_XMLETAGO, &endAtom); + pn2 = xmlTagContent(tc, TOK_XMLETAGO, &endAtom); if (!pn2) return NULL; if (pn2->pn_type == TOK_XMLETAGO) { /* Oops, end tag has attributes! */ - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } @@ -7857,7 +7775,7 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSString *str = ATOM_TO_STRING(startAtom); /* End vs. start tag name mismatch: point to the tag name. */ - js_ReportCompileErrorNumber(cx, ts, pn2, + js_ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_UC | JSREPORT_ERROR, JSMSG_XML_TAG_NAME_MISMATCH, str->chars()); @@ -7877,7 +7795,7 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->pn_xflags |= PNX_CANTFOLD; } - js_MatchToken(cx, ts, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); } @@ -7889,24 +7807,23 @@ XMLElementOrList(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->pn_op = JSOP_TOXMLLIST; pn->makeEmpty(); pn->pn_xflags |= PNX_XMLROOT; - if (!XMLElementContent(cx, ts, pn, tc)) + if (!xmlElementContent(pn, tc)) return NULL; MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX); } else { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_NAME_SYNTAX); return NULL; } - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; - ts->flags &= ~TSF_XMLTAGMODE; + pn->pn_pos.end = CURRENT_TOKEN(&tokenStream).pos.end; + tokenStream.flags &= ~TSF_XMLTAGMODE; return pn; } -static JSParseNode * -XMLElementOrListRoot(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSBool allowList) +JSParseNode * +JSCompiler::xmlElementOrListRoot(JSTreeContext *tc, JSBool allowList) { uint32 oldopts; JSParseNode *pn; @@ -7917,9 +7834,9 @@ XMLElementOrListRoot(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * to end of line (used in script tags to hide content from old browsers * that don't recognize + * + * It does not cope with malformed comment hiding hacks where --> is hidden + * by C-style comments, or on a dirty line. Such cases are already broken. + */ + TSF_IN_HTML_COMMENT = 0x2000, + + /* Ignore keywords and return TOK_NAME instead to the parser. */ + TSF_KEYWORD_IS_NAME = 0x4000, + + /* Tokenize as appropriate for strict mode code. */ + TSF_STRICT_MODE_CODE = 0x8000 +}; + +class JSTokenStream +{ + public: /* * To construct a JSTokenStream, first call the constructor, which is * infallible, then call |init|, which can fail. To destroy a JSTokenStream, @@ -295,59 +317,140 @@ struct JSTokenStream { * Create a new token stream, either from an input buffer or from a file. * Return false on file-open or memory-allocation failure. */ - bool init(JSContext *, const jschar *base, size_t length, - FILE *fp, const char *filename, uintN lineno); - - void close(JSContext *); + bool init(const jschar *base, size_t length, FILE *fp, const char *filename, uintN lineno); + void close(); ~JSTokenStream() {} + + /* Accessors. */ + JSContext *getContext() const { return cx; } + bool onCurrentLine(const JSTokenPos &pos) const { return lineno == pos.end.lineno; } + const JSToken ¤tToken() const { return tokens[cursor]; } + const JSToken &getTokenAt(size_t index) const { + JS_ASSERT(index < NTOKENS); + return tokens[index]; + } + const JSCharBuffer &getTokenbuf() const { return tokenbuf; } + const char *getFilename() const { return filename; } + uintN getLineno() const { return lineno; } + + /* Mutators. */ + JSToken *mutableCurrentToken() { return &tokens[cursor]; } + bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); + + JSTokenType getToken() { + /* Check for a pushed-back token resulting from mismatching lookahead. */ + while (lookahead != 0) { + JS_ASSERT(!(flags & TSF_XMLTEXTMODE)); + lookahead--; + cursor = (cursor + 1) & NTOKENS_MASK; + JSTokenType tt = currentToken().type; + if (tt != TOK_EOL || (flags & TSF_NEWLINES)) + return tt; + } + + /* If there was a fatal error, keep returning TOK_ERROR. */ + if (flags & TSF_ERROR) + return TOK_ERROR; + + return getTokenInternal(); + } + + JSToken *getMutableTokenAt(size_t index) { + JS_ASSERT(index < NTOKENS); + return &tokens[index]; + } + + void ungetToken() { + JS_ASSERT(lookahead < NTOKENS_MASK); + lookahead++; + cursor = (cursor - 1) & NTOKENS_MASK; + } + + JSTokenType peekToken() { + if (lookahead != 0) { + return tokens[(cursor + lookahead) & NTOKENS_MASK].type; + } + JSTokenType tt = getToken(); + ungetToken(); + return tt; + } + + JSTokenType peekTokenSameLine() { + if (!onCurrentLine(currentToken().pos)) + return TOK_EOL; + flags |= TSF_NEWLINES; + JSTokenType tt = peekToken(); + flags &= ~TSF_NEWLINES; + return tt; + } + + JSBool matchToken(JSTokenType tt) { + if (getToken() == tt) + return JS_TRUE; + ungetToken(); + return JS_FALSE; + } + + private: + typedef struct JSTokenBuf { + jschar *base; /* base of line or stream buffer */ + jschar *limit; /* limit for quick bounds check */ + jschar *ptr; /* next char to get, or slot to use */ + } JSTokenBuf; + + JSTokenType getTokenInternal(); /* doesn't check for pushback or error flag. */ + int32 getChar(); + void ungetChar(int32 c); + JSToken *newToken(ptrdiff_t adjust); + int32 getUnicodeEscape(); + JSBool peekChars(intN n, jschar *cp); + JSBool getXMLEntity(); + + JSBool matchChar(int32 expect) { + int32 c = getChar(); + if (c == expect) + return JS_TRUE; + ungetChar(c); + return JS_FALSE; + } + + int32 peekChar() { + int32 c = getChar(); + ungetChar(c); + return c; + } + + void skipChars(intN n) { + while (--n >= 0) + getChar(); + } + + JSContext * const cx; + JSToken tokens[NTOKENS];/* circular token buffer */ + uintN cursor; /* index of last parsed token */ + uintN lookahead; /* count of lookahead tokens */ + + uintN lineno; /* current line number */ + uintN ungetpos; /* next free char slot in ungetbuf */ + jschar ungetbuf[6]; /* at most 6, for \uXXXX lookahead */ + public: + uintN flags; /* flags -- see above */ + private: + uint32 linelen; /* physical linebuf segment length */ + uint32 linepos; /* linebuf offset in physical line */ + JSTokenBuf linebuf; /* line buffer for diagnostics */ + + JSTokenBuf userbuf; /* user input buffer if !file */ + const char *filename; /* input filename or null */ + FILE *file; /* stdio stream if reading from file */ + JSSourceHandler listener; /* callback for source; eg debugger */ + void *listenerData; /* listener 'this' data */ + void *listenerTSData;/* listener data for this TokenStream */ + jschar *saveEOL; /* save next end of line in userbuf, to + optimize for very long lines */ + JSCharBuffer tokenbuf; /* current token string buffer */ }; -#define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor]) -#define ON_CURRENT_LINE(ts,pos) ((ts)->lineno == (pos).end.lineno) - -/* JSTokenStream flags */ -#define TSF_ERROR 0x01 /* fatal error while compiling */ -#define TSF_EOF 0x02 /* hit end of file */ -#define TSF_NEWLINES 0x04 /* tokenize newlines */ -#define TSF_OPERAND 0x08 /* looking for operand, not operator */ -#define TSF_NLFLAG 0x20 /* last linebuf ended with \n */ -#define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */ -#define TSF_DIRTYLINE 0x80 /* non-whitespace since start of line */ -#define TSF_OWNFILENAME 0x100 /* ts->filename is malloc'd */ -#define TSF_XMLTAGMODE 0x200 /* scanning within an XML tag in E4X */ -#define TSF_XMLTEXTMODE 0x400 /* scanning XMLText terminal from E4X */ -#define TSF_XMLONLYMODE 0x800 /* don't scan {expr} within text/tag */ - -/* Flag indicating unexpected end of input, i.e. TOK_EOF not at top-level. */ -#define TSF_UNEXPECTED_EOF 0x1000 - -/* - * To handle the hard case of contiguous HTML comments, we want to clear the - * TSF_DIRTYINPUT flag at the end of each such comment. But we'd rather not - * scan for --> within every //-style comment unless we have to. So we set - * TSF_IN_HTML_COMMENT when a either on a clean line, or - * only if (ts->flags & TSF_IN_HTML_COMMENT), in a //-style comment. - * - * This still works as before given a malformed comment hiding hack such as: - * - * - * - * It does not cope with malformed comment hiding hacks where --> is hidden - * by C-style comments, or on a dirty line. Such cases are already broken. - */ -#define TSF_IN_HTML_COMMENT 0x2000 - -/* Ignore keywords and return TOK_NAME instead to the parser. */ -#define TSF_KEYWORD_IS_NAME 0x4000 - -/* Tokenize as appropriate for strict mode code. */ -#define TSF_STRICT_MODE_CODE 0x8000 - /* Unicode separators that are treated as line terminators, in addition to \n, \r */ #define LINE_SEPARATOR 0x2028 #define PARA_SEPARATOR 0x2029 @@ -417,29 +520,48 @@ js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, /* * Look ahead one token and return its type. */ -extern JSTokenType -js_PeekToken(JSContext *cx, JSTokenStream *ts); +static inline JSTokenType +js_PeekToken(JSContext *cx, JSTokenStream *ts) +{ + JS_ASSERT(cx == ts->getContext()); + return ts->peekToken(); +} -extern JSTokenType -js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts); +static inline JSTokenType +js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) +{ + JS_ASSERT(cx == ts->getContext()); + return ts->peekTokenSameLine(); +} /* * Get the next token from ts. */ -extern JSTokenType -js_GetToken(JSContext *cx, JSTokenStream *ts); +static inline JSTokenType +js_GetToken(JSContext *cx, JSTokenStream *ts) +{ + JS_ASSERT(cx == ts->getContext()); + return ts->getToken(); +} /* * Push back the last scanned token onto ts. */ -extern void -js_UngetToken(JSTokenStream *ts); +static inline void +js_UngetToken(JSTokenStream *ts) +{ + ts->ungetToken(); +} /* * Get the next token from ts if its type is tt. */ -extern JSBool -js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt); +static inline JSBool +js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt) +{ + JS_ASSERT(cx == ts->getContext()); + return ts->matchToken(tt); +} JS_END_EXTERN_C diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index f14552ff7960..5b54cf3e7925 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1004,7 +1004,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) script->nfixed = (uint16) nfixed; js_InitAtomMap(cx, &script->atomMap, &cg->atomList); - filename = cg->compiler->tokenStream.filename; + filename = cg->compiler->tokenStream.getFilename(); if (filename) { script->filename = js_SaveScriptFilename(cx, filename); if (!script->filename) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index a65b31ebbca3..e1b802098e0d 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1921,7 +1921,7 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* burn the leading lines */ line2 = JS_PCToLineNumber(cx, script, pc); for (line1 = 0; line1 < line2 - 1; line1++) - fgets(linebuf, LINE_BUF_LEN, file); + (void) fgets(linebuf, LINE_BUF_LEN, file); /* Intentionally unused result. */ bupline = 0; while (pc < end) { From 03995acf0aeebbb11430b1acdd1d1911449864d2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 15 Mar 2010 16:23:30 +1100 Subject: [PATCH 046/213] Don't use DebugBreak() in NanoAssertFail(), it causes Tinderbox problems on Windows. No bug, r=me. --HG-- extra : convert_revision : 01a6ad4362eedd1e25ec41d050a3e6bfaeaf5707 --- js/src/nanojit/avmplus.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/js/src/nanojit/avmplus.cpp b/js/src/nanojit/avmplus.cpp index 085e740e7495..e46b5d202921 100644 --- a/js/src/nanojit/avmplus.cpp +++ b/js/src/nanojit/avmplus.cpp @@ -62,15 +62,7 @@ avmplus::AvmLog(char const *msg, ...) { #ifdef _DEBUG void NanoAssertFail() { - #if defined(WIN32) - DebugBreak(); - exit(3); - #elif defined(XP_OS2) || (defined(__GNUC__) && defined(__i386)) - asm("int $3"); - abort(); - #else - abort(); - #endif + abort(); } #endif From eb44d106f40c5d4e4b80b38d388c73db504958b4 Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Mon, 15 Mar 2010 20:57:35 -0400 Subject: [PATCH 047/213] Fix bustage in _nvprof macro (no bug, r=nnethercote+) --HG-- extra : convert_revision : 62212ce5b6bbefad34c0924cae9ce1701182f082 --- js/src/vprof/vprof.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/vprof/vprof.h b/js/src/vprof/vprof.h index a71eea8245f5..0ae030ab194a 100644 --- a/js/src/vprof/vprof.h +++ b/js/src/vprof/vprof.h @@ -145,7 +145,7 @@ extern void* _tprof_before_id; (id != 0) ? \ _profileEntryValue (id, (int64_t) (v)) \ : \ - profileValue (&id, (char*) (e), -1, (int64_t) (v), ##__VA_ARGS__, NULL) \ + profileValue (&id, (char*) (e), -1, (int64_t) (v), NULL) \ ; \ } From 10966d080e8920bd6acd1a577df72fdf8d8393d5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Mar 2010 12:05:43 +1100 Subject: [PATCH 048/213] Bug 498193 - nanojit: inline all LirWriter functions. r=gal. --HG-- extra : convert_revision : 63d6441f969c16fe5c963c5c0c500bef4ce051bc --- js/src/nanojit/LIR.cpp | 68 +----------------------------------------- js/src/nanojit/LIR.h | 53 ++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 76 deletions(-) diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 9588ab9f38e6..00e7b73cfc8f 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -452,11 +452,6 @@ namespace nanojit (offsetof(LInsSti, ins) - offsetof(LInsSti, oprnd_2)) ); } - LIns* LirWriter::ins2i(LOpcode v, LIns* oprnd1, int32_t imm) - { - return ins2(v, oprnd1, insImm(imm)); - } - bool insIsS16(LInsp i) { if (i->isconst()) { @@ -920,34 +915,6 @@ namespace nanojit return out->insLoad(op, base, off, accSet); } - LIns* LirWriter::ins_eq0(LIns* oprnd1) - { - return ins2i(LIR_eq, oprnd1, 0); - } - - LIns* LirWriter::ins_peq0(LIns* oprnd1) - { - return ins2(LIR_peq, oprnd1, insImmWord(0)); - } - - LIns* LirWriter::ins_i2p(LIns* intIns) - { -#ifdef NANOJIT_64BIT - return ins1(LIR_i2q, intIns); -#else - return intIns; -#endif - } - - LIns* LirWriter::ins_u2p(LIns* uintIns) - { -#ifdef NANOJIT_64BIT - return ins1(LIR_u2q, uintIns); -#else - return uintIns; -#endif - } - LIns* LirWriter::insStorei(LIns* value, LIns* base, int32_t d, AccSet accSet) { // Determine which kind of store should be used for 'value' based on @@ -965,42 +932,9 @@ namespace nanojit return insStore(op, value, base, d, accSet); } -#if NJ_SOFTFLOAT_SUPPORTED - LIns* LirWriter::qjoin(LInsp lo, LInsp hi) - { - return ins2(LIR_qjoin, lo, hi); - } -#endif - - LIns* LirWriter::insImmWord(intptr_t value) - { -#ifdef NANOJIT_64BIT - return insImmq(value); -#else - return insImm(value); -#endif - } - - LIns* LirWriter::insImmPtr(const void *ptr) - { -#ifdef NANOJIT_64BIT - return insImmq((uint64_t)ptr); -#else - return insImm((int32_t)ptr); -#endif - } - LIns* LirWriter::ins_choose(LIns* cond, LIns* iftrue, LIns* iffalse, bool use_cmov) { - // if not a conditional, make it implicitly an ==0 test (then flop results) - if (!cond->isCmp()) - { - cond = ins_eq0(cond); - LInsp tmp = iftrue; - iftrue = iffalse; - iffalse = tmp; - } - + NanoAssert(cond->isCmp()); if (use_cmov) { LOpcode op = LIR_cmov; if (iftrue->isI32() && iffalse->isI32()) { diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 465c8b8aef08..a41352cea049 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -1441,24 +1441,59 @@ namespace nanojit LIns* ins_choose(LIns* cond, LIns* iftrue, LIns* iffalse, bool use_cmov); // Inserts an integer comparison to 0 - LIns* ins_eq0(LIns* oprnd1); + LIns* ins_eq0(LIns* oprnd1) { + return ins2i(LIR_eq, oprnd1, 0); + } // Inserts a pointer comparison to 0 - LIns* ins_peq0(LIns* oprnd1); + LIns* ins_peq0(LIns* oprnd1) { + return ins2(LIR_peq, oprnd1, insImmWord(0)); + } // Inserts a binary operation where the second operand is an // integer immediate. - LIns* ins2i(LOpcode op, LIns *oprnd1, int32_t); + LIns* ins2i(LOpcode v, LIns* oprnd1, int32_t imm) { + return ins2(v, oprnd1, insImm(imm)); + } #if NJ_SOFTFLOAT_SUPPORTED - LIns* qjoin(LInsp lo, LInsp hi); + LIns* qjoin(LInsp lo, LInsp hi) { + return ins2(LIR_qjoin, lo, hi); + } #endif - LIns* insImmPtr(const void *ptr); - LIns* insImmWord(intptr_t ptr); + LIns* insImmPtr(const void *ptr) { +#ifdef NANOJIT_64BIT + return insImmq((uint64_t)ptr); +#else + return insImm((int32_t)ptr); +#endif + } - // Sign or zero extend integers to native integers. On 32-bit this is a no-op. - LIns* ins_i2p(LIns* intIns); - LIns* ins_u2p(LIns* uintIns); + LIns* insImmWord(intptr_t value) { +#ifdef NANOJIT_64BIT + return insImmq(value); +#else + return insImm(value); +#endif + } + + // Sign-extend integers to native integers. On 32-bit this is a no-op. + LIns* ins_i2p(LIns* intIns) { +#ifdef NANOJIT_64BIT + return ins1(LIR_i2q, intIns); +#else + return intIns; +#endif + } + + // Zero-extend integers to native integers. On 32-bit this is a no-op. + LIns* ins_u2p(LIns* uintIns) { + #ifdef NANOJIT_64BIT + return ins1(LIR_u2q, uintIns); + #else + return uintIns; + #endif + } // Chooses LIR_sti or LIR_stqi based on size of value. LIns* insStorei(LIns* value, LIns* base, int32_t d, AccSet accSet); From e9a5ed9c7dbef0f781e0ea2a6f56663a31dbdc86 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Mar 2010 12:12:38 +1100 Subject: [PATCH 049/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 2c7cec0a0134..39f0eaaa4f0f 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -9a999bda712986c15b4590e57029b580621ffcf9 +0f045a5086e77b5117efe257b98c1d1b604b9487 From 07a82dbbd3c3c3b0ed292e1a78a02dcdbf29647c Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 15 Mar 2010 19:24:08 -0700 Subject: [PATCH 050/213] Bug 552248 - fix crash when JS_EvaluateInStackFrame is called for frame in saved callstack (r=Waldo) --- js/src/jscntxt.cpp | 33 ++++++++++++ js/src/jscntxt.h | 6 +++ js/src/jsemit.cpp | 4 +- js/src/jsfun.cpp | 2 +- js/src/jsinterp.cpp | 29 +---------- js/src/jsinterp.h | 7 --- js/src/jsparse.h | 9 ++-- js/src/shell/js.cpp | 51 +++++++++++++++++++ .../trace-test/tests/basic/testBug552248.js | 35 +++++++++++++ 9 files changed, 134 insertions(+), 42 deletions(-) create mode 100644 js/src/trace-test/tests/basic/testBug552248.js diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index db853ac1a4e2..487e2d6647c4 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1925,6 +1925,39 @@ js_CurrentPCIsInImacro(JSContext *cx) #endif } +CallStack * +JSContext::containingCallStack(JSStackFrame *target) +{ + /* The context may have nothing running. */ + CallStack *cs = currentCallStack; + if (!cs) + return NULL; + + /* The active callstack's top frame is cx->fp. */ + if (fp) { + JS_ASSERT(activeCallStack() == cs); + JSStackFrame *f = fp; + JSStackFrame *stop = cs->getInitialFrame()->down; + for (; f != stop; f = f->down) { + if (f == target) + return cs; + } + cs = cs->getPrevious(); + } + + /* A suspended callstack's top frame is its suspended frame. */ + for (; cs; cs = cs->getPrevious()) { + JSStackFrame *f = cs->getSuspendedFrame(); + JSStackFrame *stop = cs->getInitialFrame()->down; + for (; f != stop; f = f->down) { + if (f == target) + return cs; + } + } + + return NULL; +} + void JSContext::checkMallocGCPressure(void *p) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 15c3da0a2fc0..7af004b13872 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1363,6 +1363,12 @@ struct JSContext currentCallStack->restore(); } + /* + * Perform a linear search of all frames in all callstacks in the given context + * for the given frame, returning the callstack, if found, and null otherwise. + */ + js::CallStack *containingCallStack(JSStackFrame *target); + #ifdef JS_THREADSAFE JSThread *thread; jsrefcount requestDepth; diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 297393453a94..3ea68e54c70b 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -2101,7 +2101,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JSObject *scopeobj = (cg->flags & TCF_IN_FUNCTION) ? FUN_OBJECT(cg->fun)->getParent() : cg->scopeChain; - if (scopeobj != caller->varobj(cx)) + if (scopeobj != cg->compiler->callerVarObj) return JS_TRUE; /* @@ -2196,7 +2196,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JSCodeGenerator *evalcg = (JSCodeGenerator *) tc; JS_ASSERT(evalcg->flags & TCF_COMPILE_N_GO); - JS_ASSERT(caller->fun && caller->varobj(cx) == evalcg->scopeChain); + JS_ASSERT(caller->fun && cg->compiler->callerVarObj == evalcg->scopeChain); /* * Don't generate upvars on the left side of a for loop. See diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index afc31f3ad048..c5ba28896059 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -231,7 +231,7 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp) */ JS_ASSERT(fp->fun); JS_ASSERT_IF(fp->fun->flags & JSFUN_HEAVYWEIGHT, - fp->varobj(js_ContainingCallStack(cx, fp))); + fp->varobj(cx->containingCallStack(fp))); /* Skip eval and debugger frames. */ while (fp->flags & JSFRAME_SPECIAL) diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 9fcb528274fe..c700953a75d0 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1466,33 +1466,6 @@ js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, return js_InternalCall(cx, obj, fval, argc, argv, rval); } -CallStack * -js_ContainingCallStack(JSContext *cx, JSStackFrame *target) -{ - JS_ASSERT(cx->fp); - - /* The active callstack's top frame is cx->fp. */ - CallStack *cs = cx->activeCallStack(); - JSStackFrame *f = cx->fp; - JSStackFrame *stop = cs->getInitialFrame()->down; - for (; f != stop; f = f->down) { - if (f == target) - return cs; - } - - /* A suspended callstack's top frame is its suspended frame. */ - for (cs = cs->getPrevious(); cs; cs = cs->getPrevious()) { - f = cs->getSuspendedFrame(); - stop = cs->getInitialFrame()->down; - for (; f != stop; f = f->down) { - if (f == target) - return cs; - } - } - - return NULL; -} - JSBool js_Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *down, uintN flags, jsval *result) @@ -1547,7 +1520,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script, if (down == cx->fp) { callStack.setInitialVarObj(down->varobj(cx)); } else { - CallStack *cs = js_ContainingCallStack(cx, down); + CallStack *cs = cx->containingCallStack(down); callStack.setInitialVarObj(down->varobj(cs)); } } else { diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index b6ae9aeee5a7..a1e8f80cbc5a 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -170,13 +170,6 @@ struct JSStackFrame { }; #ifdef __cplusplus -/* - * Perform a linear search of all frames in all callstacks in the given context - * for the given frame, returning the callstack, if found, and NULL otherwise. - */ -extern js::CallStack * -js_ContainingCallStack(JSContext *cx, JSStackFrame *target); - static JS_INLINE uintN FramePCOffset(JSStackFrame* fp) { diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 0d93ec07ac85..396ba74d134d 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -919,7 +919,8 @@ struct JSCompiler : private js::AutoGCRooter { JSTokenStream tokenStream; void *tempPoolMark; /* initial JSContext.tempPool mark */ JSPrincipals *principals; /* principals associated with source */ - JSStackFrame *callerFrame; /* scripted caller frame for eval and dbgapi */ + JSStackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */ + JSObject *const callerVarObj; /* callerFrame's varObj */ JSParseNode *nodeList; /* list of recyclable parse-node structs */ uint32 functionCount; /* number of functions in current unit */ JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ @@ -927,9 +928,9 @@ struct JSCompiler : private js::AutoGCRooter { JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) : js::AutoGCRooter(cx, COMPILER), context(cx), - aleFreeList(NULL), tokenStream(cx), principals(NULL), - callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL), - tc(NULL) + aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), + callerVarObj(cfp ? cfp->varobj(cx->containingCallStack(cfp)) : NULL), + nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL) { js::PodArrayZero(tempFreeList); setPrincipals(prin); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index e1b802098e0d..f01970009135 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3028,6 +3028,54 @@ out: return ok; } +static JSBool +EvalInFrame(JSContext *cx, uintN argc, jsval *vp) +{ + jsval *argv = JS_ARGV(cx, vp); + if (argc < 2 || + !JSVAL_IS_INT(argv[0]) || + !JSVAL_IS_STRING(argv[1])) { + JS_ReportError(cx, "Invalid arguments to evalInFrame"); + return JS_FALSE; + } + + uint32 upCount = JSVAL_TO_INT(argv[0]); + JSString *str = JSVAL_TO_STRING(argv[1]); + + bool saveCurrent = JSVAL_IS_BOOLEAN(argv[2]) + ? (bool)JSVAL_TO_SPECIAL(argv[2]) + : false; + + JS_ASSERT(cx->fp); + + JSStackFrame *fp = cx->fp; + for (uint32 i = 0; i < upCount; ++i) { + if (!fp->down) + break; + fp = fp->down; + } + + if (!fp->script) { + JS_ReportError(cx, "cannot eval in non-script frame"); + return JS_FALSE; + } + + JSStackFrame *oldfp; + if (saveCurrent) + oldfp = JS_SaveFrameChain(cx); + + JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(), + fp->script->filename, + JS_PCToLineNumber(cx, fp->script, + fp->regs->pc), + vp); + + if (saveCurrent) + JS_RestoreFrameChain(cx, oldfp); + + return ok; +} + static JSBool ShapeOf(JSContext *cx, uintN argc, jsval *vp) { @@ -3784,6 +3832,7 @@ static JSFunctionSpec shell_functions[] = { JS_FN("getslx", GetSLX, 1,0), JS_FN("toint32", ToInt32, 1,0), JS_FS("evalcx", EvalInContext, 1,0,0), + JS_FN("evalInFrame", EvalInFrame, 2,0), JS_FN("shapeOf", ShapeOf, 1,0), #ifdef MOZ_SHARK JS_FS("startShark", js_StartShark, 0,0,0), @@ -3885,6 +3934,8 @@ static const char *const shell_help_messages[] = { " if (s == '' && !o) return new o with eager standard classes\n" " if (s == 'lazy' && !o) return new o with lazy standard classes\n" " if (s == 'split' && !o) return new split-object o with lazy standard classes", +"evalInFrame(n,str,save) Evaluate 'str' in the nth up frame.\n" +" If 'save' (default false), save the frame chain", "shapeOf(obj) Get the shape of obj (an implementation detail)", #ifdef MOZ_SHARK "startShark() Start a Shark session.\n" diff --git a/js/src/trace-test/tests/basic/testBug552248.js b/js/src/trace-test/tests/basic/testBug552248.js new file mode 100644 index 000000000000..936b33a5a159 --- /dev/null +++ b/js/src/trace-test/tests/basic/testBug552248.js @@ -0,0 +1,35 @@ +var a = new Array(); + +function i(save) { + var x = 9; + evalInFrame(0, "a.push(x)", save); + evalInFrame(1, "a.push(z)", save); + evalInFrame(2, "a.push(z)", save); + evalInFrame(3, "a.push(y)", save); + evalInFrame(4, "a.push(x)", save); +} + +function h() { + var z = 5; + evalInFrame(0, "a.push(z)"); + evalInFrame(1, "a.push(y)"); + evalInFrame(2, "a.push(x)"); + evalInFrame(0, "i(false)"); + evalInFrame(0, "a.push(z)", true); + evalInFrame(1, "a.push(y)", true); + evalInFrame(2, "a.push(x)", true); + evalInFrame(0, "i(true)", true); +} + +function g() { + var y = 4; + h(); +} + +function f() { + var x = 3; + g(); +} + +f(); +assertEq(a+'', [5, 4, 3, 9, 5, 5, 4, 3, 5, 4, 3, 9, 5, 5, 4, 3]+''); From 4bdd04d8b8c737b140c3b4fd37dff2750065138b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Mar 2010 14:58:52 +1100 Subject: [PATCH 051/213] Bug 552582 - TM: remove unused case from FuncFilter. r=gal. --- js/src/jstracer.cpp | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 59a3cefaed82..fe498d681f9b 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1662,12 +1662,6 @@ isPromote(LIns* i) return isPromoteInt(i) || isPromoteUint(i); } -static bool -IsConst(LIns* i, int32_t c) -{ - return i->isconst() && i->imm32() == c; -} - /* * Determine whether this operand is guaranteed to not overflow the specified * integer operation. @@ -1727,31 +1721,6 @@ public: v = LOpcode(v + (LIR_ult - LIR_lt)); // cmp -> ucmp return out->ins2(v, demote(out, s0), demote(out, s1)); } - } else if (v == LIR_or && - s0->isop(LIR_lsh) && IsConst(s0->oprnd2(), 16) && - s1->isop(LIR_and) && IsConst(s1->oprnd2(), 0xffff)) { - LIns* msw = s0->oprnd1(); - LIns* lsw = s1->oprnd1(); - LIns* x; - LIns* y; - if (lsw->isop(LIR_add) && - lsw->oprnd1()->isop(LIR_and) && - lsw->oprnd2()->isop(LIR_and) && - IsConst(lsw->oprnd1()->oprnd2(), 0xffff) && - IsConst(lsw->oprnd2()->oprnd2(), 0xffff) && - msw->isop(LIR_add) && - msw->oprnd1()->isop(LIR_add) && - msw->oprnd2()->isop(LIR_rsh) && - msw->oprnd1()->oprnd1()->isop(LIR_rsh) && - msw->oprnd1()->oprnd2()->isop(LIR_rsh) && - IsConst(msw->oprnd2()->oprnd2(), 16) && - IsConst(msw->oprnd1()->oprnd1()->oprnd2(), 16) && - IsConst(msw->oprnd1()->oprnd2()->oprnd2(), 16) && - (x = lsw->oprnd1()->oprnd1()) == msw->oprnd1()->oprnd1()->oprnd1() && - (y = lsw->oprnd2()->oprnd1()) == msw->oprnd1()->oprnd2()->oprnd1() && - lsw == msw->oprnd2()->oprnd1()) { - return out->ins2(LIR_add, x, y); - } } return out->ins2(v, s0, s1); } From 8d7d02e3948f70d2c015fdd2931864ec5f90956c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Mar 2010 15:06:04 +1100 Subject: [PATCH 052/213] Fix GCC warning. Follow-up to bug 552248. r=me. --- js/src/shell/js.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f01970009135..e0ae2f75f392 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3060,7 +3060,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - JSStackFrame *oldfp; + JSStackFrame *oldfp = NULL; if (saveCurrent) oldfp = JS_SaveFrameChain(cx); From f25453183dbafe7332f1b63a52aeb380c94cc079 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 16 Mar 2010 09:45:07 -0700 Subject: [PATCH 053/213] Add argv bounds check in js shell's EvalInFrame (no bug, r=me) --- js/src/shell/js.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index e0ae2f75f392..8d35cffed053 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3042,7 +3042,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp) uint32 upCount = JSVAL_TO_INT(argv[0]); JSString *str = JSVAL_TO_STRING(argv[1]); - bool saveCurrent = JSVAL_IS_BOOLEAN(argv[2]) + bool saveCurrent = (argc >= 3 && JSVAL_IS_BOOLEAN(argv[2])) ? (bool)JSVAL_TO_SPECIAL(argv[2]) : false; From 1fc5949cbdfe71503b7adc366327f86a7c5d24a3 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 16 Mar 2010 09:55:45 -0700 Subject: [PATCH 054/213] Bug 551539 - use memcmp for inner loop of StringMatch, sometimes (r=bzbarsky) --- js/src/jsstr.cpp | 115 ++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 41 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 362bebe69855..0cfa3a3999da 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1095,6 +1095,71 @@ js_BoyerMooreHorspool(const jschar *text, jsuint textlen, return -1; } +namespace { + +struct MemCmp { + typedef jsuint Extent; + static JS_ALWAYS_INLINE Extent computeExtent(const jschar *, jsuint patlen) { + return (patlen - 1) * sizeof(jschar); + } + static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { + return memcmp(p, t, extent) == 0; + } +}; + +struct ManualCmp { + typedef const jschar *Extent; + static JS_ALWAYS_INLINE Extent computeExtent(const jschar *pat, jsuint patlen) { + return pat + patlen; + } + static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { + for (; p != extent; ++p, ++t) { + if (*p != *t) + return false; + } + return true; + } +}; + +} + +template +static jsint +Duff(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) +{ + JS_ASSERT(patlen > 1 && textlen > 0); + const jschar *textend = text + textlen - (patlen - 1); + const jschar p0 = *pat; + const jschar *const patNext = pat + 1; + const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen); + uint8 fixup; + + const jschar *t = text; + switch ((textend - t) & 7) { + do { + case 0: if (*t++ == p0) { fixup = 8; goto match; } + case 7: if (*t++ == p0) { fixup = 7; goto match; } + case 6: if (*t++ == p0) { fixup = 6; goto match; } + case 5: if (*t++ == p0) { fixup = 5; goto match; } + case 4: if (*t++ == p0) { fixup = 4; goto match; } + case 3: if (*t++ == p0) { fixup = 3; goto match; } + case 2: if (*t++ == p0) { fixup = 2; goto match; } + case 1: if (*t++ == p0) { fixup = 1; goto match; } + continue; + do { + if (*t++ == p0) { + match: + if (!InnerMatch::match(patNext, t, extent)) + goto failed_match; + return t - text - 1; + } + failed_match:; + } while (--fixup > 0); + } while(t != textend); + } + return -1; +} + static JS_ALWAYS_INLINE jsint StringMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) @@ -1138,50 +1203,18 @@ StringMatch(const jschar *text, jsuint textlen, return index; } - const jschar *textend = text + textlen - (patlen - 1); - const jschar *patend = pat + patlen; - const jschar p0 = *pat; - const jschar *patNext = pat + 1; - uint8 fixup; - -#if __APPLE__ && __GNUC__ && __i386__ /* - * It is critical that |t| is kept in a register. The version of gcc we use - * to build on 32-bit Mac does not realize this. See bug 526173. + * For big patterns with large potential overlap we want the SIMD-optimized + * speed of memcmp. For small patterns, a simple loop is faster. + * + * FIXME: Linux memcmp performance is sad and the manual loop is faster. */ - register const jschar *t asm("esi") = text; -#else - const jschar *t = text; + return +#if !defined(__linux__) + patlen > 128 ? Duff(text, textlen, pat, patlen) + : #endif - - /* Credit: Duff */ - switch ((textend - text) & 7) { - do { - case 0: if (*t++ == p0) { fixup = 8; goto match; } - case 7: if (*t++ == p0) { fixup = 7; goto match; } - case 6: if (*t++ == p0) { fixup = 6; goto match; } - case 5: if (*t++ == p0) { fixup = 5; goto match; } - case 4: if (*t++ == p0) { fixup = 4; goto match; } - case 3: if (*t++ == p0) { fixup = 3; goto match; } - case 2: if (*t++ == p0) { fixup = 2; goto match; } - case 1: if (*t++ == p0) { fixup = 1; goto match; } - continue; - do { - if (*t++ == p0) { - match: - for (const jschar *p1 = patNext, *t1 = t; - p1 != patend; - ++p1, ++t1) { - if (*p1 != *t1) - goto failed_match; - } - return t - text - 1; - } - failed_match:; - } while (--fixup > 0); - } while(t != textend); - } - return -1; + Duff(text, textlen, pat, patlen); } static JSBool From c7d430a638fa8e772c25251a5c3458285eef403b Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Tue, 16 Mar 2010 21:28:33 +0300 Subject: [PATCH 055/213] bug 519476 - replacing JSSTRING_DEFLATED with scanning of the deflated cache. r=jwalden,dmandelin --- js/src/jsapi.cpp | 14 ++- js/src/jsatom.cpp | 3 +- js/src/jscntxt.cpp | 3 - js/src/jscntxt.h | 8 +- js/src/jsgc.cpp | 13 +- js/src/jsprvtd.h | 2 + js/src/jsstr.cpp | 298 ++++++++++++++++++++++----------------------- js/src/jsstr.h | 112 ++++++++--------- js/src/jsxml.cpp | 2 +- 9 files changed, 223 insertions(+), 232 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3437b9a8c4d4..1af8ffc1d3a7 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -565,10 +565,14 @@ JSRuntime::init(uint32 maxbytes) { if (!js_InitDtoa() || !js_InitGC(this, maxbytes) || - !js_InitAtomState(this) || - !js_InitDeflatedStringCache(this)) { + !js_InitAtomState(this)) { return false; } + + deflatedStringCache = new js::DeflatedStringCache(); + if (!deflatedStringCache || !deflatedStringCache->init()) + return false; + #ifdef JS_THREADSAFE gcLock = JS_NEW_LOCK(); if (!gcLock) @@ -629,7 +633,7 @@ JSRuntime::~JSRuntime() * Finish the deflated string cache after the last GC and after * calling js_FinishAtomState, which finalizes strings. */ - js_FinishDeflatedStringCache(this); + delete deflatedStringCache; js_FinishGC(this); #ifdef JS_THREADSAFE if (gcLock) @@ -5062,7 +5066,7 @@ JS_NewString(JSContext *cx, char *bytes, size_t nbytes) } /* Hand off bytes to the deflated string cache, if possible. */ - if (!js_SetStringBytes(cx, str, bytes, nbytes)) + if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes)) cx->free(bytes); return str; } @@ -5191,7 +5195,7 @@ JS_GetStringChars(JSString *str) if (s) { memcpy(s, str->dependentChars(), n * sizeof *s); s[n] = 0; - str->reinitFlat(s, n); + str->initFlat(s, n); } else { s = str->dependentChars(); } diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 08668187b9fa..3ed21b64e336 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -499,6 +499,7 @@ js_InitCommonAtoms(JSContext *cx) JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START); memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START); + cx->runtime->emptyString = ATOM_TO_STRING(state->emptyAtom); return JS_TRUE; } @@ -514,8 +515,8 @@ js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr, void js_FinishCommonAtoms(JSContext *cx) { + cx->runtime->emptyString = NULL; JSAtomState *state = &cx->runtime->atomState; - JS_DHashTableEnumerate(&state->stringAtoms, js_atom_unpinner, NULL); #ifdef DEBUG memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN, diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 487e2d6647c4..a5b620e305be 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -545,8 +545,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize) ok = js_InitRuntimeScriptState(rt); if (ok) ok = js_InitRuntimeNumberState(cx); - if (ok) - ok = js_InitRuntimeStringState(cx); if (ok) ok = JSScope::initRuntimeState(cx); @@ -778,7 +776,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) JSScope::finishRuntimeState(cx); js_FinishRuntimeNumberState(cx); - js_FinishRuntimeStringState(cx); /* Unpin all common atoms before final GC. */ js_FinishCommonAtoms(cx); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 7af004b13872..fc35d2bde5a6 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -820,13 +820,7 @@ struct JSRuntime { jsval negativeInfinityValue; jsval positiveInfinityValue; -#ifdef JS_THREADSAFE - JSLock *deflatedStringCacheLock; -#endif - JSHashTable *deflatedStringCache; -#ifdef DEBUG - uint32 deflatedStringCacheBytes; -#endif + js::DeflatedStringCache *deflatedStringCache; JSString *emptyString; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index acdaa800f8be..8b689045a646 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2622,8 +2622,6 @@ FinalizeString(JSContext *cx, JSString *str, unsigned thingKind) */ cx->free(str->flatChars()); } - if (str->isDeflated()) - js_PurgeDeflatedStringCache(cx->runtime, str); } inline void @@ -2643,8 +2641,6 @@ FinalizeExternalString(JSContext *cx, JSString *str, unsigned thingKind) JSStringFinalizeOp finalizer = str_finalizers[type]; if (finalizer) finalizer(cx, str); - if (str->isDeflated()) - js_PurgeDeflatedStringCache(cx->runtime, str); } /* @@ -2686,8 +2682,6 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str) } } } - if (str->isDeflated()) - js_PurgeDeflatedStringCache(rt, str); } template(cx, FINALIZE_XML, &emptyArenas); #endif + + /* + * We sweep the deflated cache before we finalize the strings so the + * cache can safely use js_IsAboutToBeFinalized.. + */ + rt->deflatedStringCache->sweep(cx); + FinalizeArenaList (cx, FINALIZE_STRING, &emptyArenas); for (unsigned i = FINALIZE_EXTERNAL_STRING0; diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 664a80206a94..7773972938f4 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -172,6 +172,8 @@ template class HashSet; +class DeflatedStringCache; + } /* namespace js */ /* Common instantiations. */ diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 0cfa3a3999da..0e37d4cfff1e 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -104,7 +104,7 @@ MinimizeDependentStrings(JSString *str, int level, JSString **basep) } while (base->isDependent()); } length = str->dependentLength(); - str->reinitDependent(base, start, length); + str->initDependent(base, start, length); } *basep = base; return start; @@ -187,7 +187,7 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right) /* Morph left into a dependent string if we realloc'd its buffer. */ if (ldep) { - ldep->reinitDependent(str, 0, ln); + ldep->initDependent(str, 0, ln); #ifdef DEBUG { JSRuntime *rt = cx->runtime; @@ -219,7 +219,7 @@ js_UndependString(JSContext *cx, JSString *str) js_strncpy(s, str->dependentChars(), n); s[n] = 0; - str->reinitFlat(s, n); + str->initFlat(s, n); #ifdef DEBUG { @@ -3048,66 +3048,6 @@ static JSFunctionSpec string_static_methods[] = { JS_FS_END }; -static JSHashNumber -js_hash_string_pointer(const void *key) -{ - return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS; -} - -JSBool -js_InitRuntimeStringState(JSContext *cx) -{ - JSRuntime *rt; - - rt = cx->runtime; - rt->emptyString = ATOM_TO_STRING(rt->atomState.emptyAtom); - return JS_TRUE; -} - -JSBool -js_InitDeflatedStringCache(JSRuntime *rt) -{ - JSHashTable *cache; - - /* Initialize string cache */ - JS_ASSERT(!rt->deflatedStringCache); - cache = JS_NewHashTable(8, js_hash_string_pointer, - JS_CompareValues, JS_CompareValues, - NULL, NULL); - if (!cache) - return JS_FALSE; - rt->deflatedStringCache = cache; - -#ifdef JS_THREADSAFE - JS_ASSERT(!rt->deflatedStringCacheLock); - rt->deflatedStringCacheLock = JS_NEW_LOCK(); - if (!rt->deflatedStringCacheLock) - return JS_FALSE; -#endif - return JS_TRUE; -} - -void -js_FinishRuntimeStringState(JSContext *cx) -{ - cx->runtime->emptyString = NULL; -} - -void -js_FinishDeflatedStringCache(JSRuntime *rt) -{ - if (rt->deflatedStringCache) { - JS_HashTableDestroy(rt->deflatedStringCache); - rt->deflatedStringCache = NULL; - } -#ifdef JS_THREADSAFE - if (rt->deflatedStringCacheLock) { - JS_DESTROY_LOCK(rt->deflatedStringCacheLock); - rt->deflatedStringCacheLock = NULL; - } -#endif -} - JSObject * js_InitStringClass(JSContext *cx, JSObject *obj) { @@ -3297,26 +3237,6 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s) return str; } -void -js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str) -{ - JSHashNumber hash; - JSHashEntry *he, **hep; - - hash = js_hash_string_pointer(str); - JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock); - hep = JS_HashTableRawLookup(rt->deflatedStringCache, hash, str); - he = *hep; - if (he) { -#ifdef DEBUG - rt->deflatedStringCacheBytes -= str->length(); -#endif - js_free(he->value); - JS_HashTableRawRemove(rt->deflatedStringCache, hep, he); - } - JS_RELEASE_LOCK(rt->deflatedStringCacheLock); -} - JS_FRIEND_API(const char *) js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun) { @@ -3827,42 +3747,161 @@ bufferTooSmall: return JS_FALSE; } -JSBool -js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length) +namespace js { + +DeflatedStringCache::DeflatedStringCache() { - JSRuntime *rt; - JSHashTable *cache; - JSBool ok; - JSHashNumber hash; - JSHashEntry **hep; - - rt = cx->runtime; - JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock); - - cache = rt->deflatedStringCache; - hash = js_hash_string_pointer(str); - hep = JS_HashTableRawLookup(cache, hash, str); - JS_ASSERT(*hep == NULL); - ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL; - if (ok) { - str->setDeflated(); -#ifdef DEBUG - rt->deflatedStringCacheBytes += length; +#ifdef JS_THREADSAFE + lock = NULL; #endif +} + +bool +DeflatedStringCache::init() +{ +#ifdef JS_THREADSAFE + JS_ASSERT(!lock); + lock = JS_NEW_LOCK(); + if (!lock) + return false; +#endif + + /* + * Make room for 2K deflated strings that a typical browser session + * creates. + */ + return map.init(2048); +} + +DeflatedStringCache::~DeflatedStringCache() +{ +#ifdef JS_THREADSAFE + if (lock) + JS_DESTROY_LOCK(lock); +#endif +} + +void +DeflatedStringCache::sweep(JSContext *cx) +{ + /* + * We must take a lock even during the GC as JS_GetStringBytes() can be + * called outside the request. + */ + JS_ACQUIRE_LOCK(lock); + + for (Map::Enum e(map); !e.empty(); e.popFront()) { + JSString *str = e.front().key; + if (js_IsAboutToBeFinalized(str)) { + char *bytes = e.front().value; + e.removeFront(); + + /* + * We cannot use cx->free here as bytes may come from the + * embedding that calls JS_NewString(cx, bytes, length). Those + * bytes may not be allocated via js_malloc and may not have + * space for the background free list. + */ + js_free(bytes); + } } - JS_RELEASE_LOCK(rt->deflatedStringCacheLock); + JS_RELEASE_LOCK(lock); +} + +void +DeflatedStringCache::remove(JSString *str) +{ + JS_ACQUIRE_LOCK(lock); + + Map::Ptr p = map.lookup(str); + if (p) { + js_free(p->value); + map.remove(p); + } + + JS_RELEASE_LOCK(lock); +} + +bool +DeflatedStringCache::setBytes(JSContext *cx, JSString *str, char *bytes) +{ + JS_ACQUIRE_LOCK(lock); + + Map::AddPtr p = map.lookupForAdd(str); + JS_ASSERT(!p); + bool ok = map.add(p, str, bytes); + + JS_RELEASE_LOCK(lock); + + if (!ok) + js_ReportOutOfMemory(cx); return ok; } +char * +DeflatedStringCache::getBytes(JSContext *cx, JSString *str) +{ + JS_ACQUIRE_LOCK(lock); + + char *bytes; + do { + Map::AddPtr p = map.lookupForAdd(str); + if (p) { + bytes = p->value; + break; + } +#ifdef JS_THREADSAFE + unsigned generation = map.generation(); + JS_RELEASE_LOCK(lock); +#endif + bytes = js_DeflateString(cx, str->chars(), str->length()); + if (!bytes) + return NULL; +#ifdef JS_THREADSAFE + JS_ACQUIRE_LOCK(lock); + if (generation != map.generation()) { + p = map.lookupForAdd(str); + if (p) { + /* Some other thread has asked for str bytes .*/ + if (cx) + cx->free(bytes); + else + js_free(bytes); + bytes = p->value; + break; + } + } +#endif + if (!map.add(p, str, bytes)) { + JS_RELEASE_LOCK(lock); + if (cx) { + cx->free(bytes); + js_ReportOutOfMemory(cx); + } else { + js_free(bytes); + } + return NULL; + } + } while (false); + + JS_ASSERT(bytes); + + /* Try to catch failure to JS_ShutDown between runtime epochs. */ + JS_ASSERT_IF(!js_CStringsAreUTF8 && *bytes != (char) str->chars()[0], + *bytes == '\0' && str->empty()); + + JS_RELEASE_LOCK(lock); + return bytes; +} + +} /* namespace js */ + const char * js_GetStringBytes(JSContext *cx, JSString *str) { JSRuntime *rt; - JSHashTable *cache; char *bytes; - JSHashNumber hash; - JSHashEntry *he, **hep; if (JSString::isUnitString(str)) { #ifdef IS_LITTLE_ENDIAN @@ -3892,50 +3931,7 @@ js_GetStringBytes(JSContext *cx, JSString *str) rt = js_GetGCStringRuntime(str); } -#ifdef JS_THREADSAFE - if (!rt->deflatedStringCacheLock) { - /* - * Called from last GC (see js_DestroyContext), after runtime string - * state has been finalized. We have no choice but to leak here. - */ - return js_DeflateString(NULL, str->chars(), str->length()); - } -#endif - - JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock); - - cache = rt->deflatedStringCache; - hash = js_hash_string_pointer(str); - hep = JS_HashTableRawLookup(cache, hash, str); - he = *hep; - if (he) { - bytes = (char *) he->value; - - /* Try to catch failure to JS_ShutDown between runtime epochs. */ - if (!js_CStringsAreUTF8) { - JS_ASSERT_IF(*bytes != (char) str->chars()[0], - *bytes == '\0' && str->empty()); - } - } else { - bytes = js_DeflateString(cx, str->chars(), str->length()); - if (bytes) { - if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) { -#ifdef DEBUG - rt->deflatedStringCacheBytes += str->length(); -#endif - str->setDeflated(); - } else { - if (cx) - cx->free(bytes); - else - js_free(bytes); - bytes = NULL; - } - } - } - - JS_RELEASE_LOCK(rt->deflatedStringCacheLock); - return bytes; + return rt->deflatedStringCache->getBytes(cx, str); } /* diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 4ce0f577ea2f..a11c513801d3 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -51,6 +51,7 @@ #include #include "jspubtd.h" #include "jsprvtd.h" +#include "jshashtable.h" #include "jslock.h" JS_BEGIN_EXTERN_C @@ -87,10 +88,6 @@ JS_STATIC_ASSERT(JS_BITS_PER_WORD >= 32); * A flat string with the ATOMIZED flag means that the string is hashed as * an atom. This flag is used to avoid re-hashing the already-atomized string. * - * Any string with the DEFLATED flag means that the string has an entry in the - * deflated string cache. The GC uses this flag to optimize string finalization - * and avoid an expensive cache lookup for strings that were never deflated. - * * When the DEPENDENT flag is set, the string depends on characters of another * string strongly referenced by the mBase field. The base member may point to * another dependent string if chars() has not been called yet. @@ -124,7 +121,6 @@ struct JSString { static const size_t DEPENDENT = JSSTRING_BIT(1); static const size_t MUTABLE = JSSTRING_BIT(2); static const size_t ATOMIZED = JSSTRING_BIT(3); - static const size_t DEFLATED = JSSTRING_BIT(4); inline bool hasFlag(size_t flag) const { return (mFlags & flag) != 0; @@ -145,14 +141,6 @@ struct JSString { return !isDependent(); } - inline bool isDeflated() const { - return hasFlag(DEFLATED); - } - - inline void setDeflated() { - JS_ATOMIC_SET_MASK(&mFlags, DEFLATED); - } - inline bool isMutable() const { return !isDependent() && hasFlag(MUTABLE); } @@ -201,18 +189,6 @@ struct JSString { return length(); } - /* - * Special flat string initializer that preserves the DEFLATED flag. - * Use this method when reinitializing an existing string which may be - * hashed to its deflated bytes. Newborn strings must use initFlat. - */ - void reinitFlat(jschar *chars, size_t length) { - mLength = length; - mOffset = 0; - mFlags = mFlags & DEFLATED; - mChars = chars; - } - /* * Methods to manipulate atomized and mutable flags of flat strings. It is * safe to use these without extra locking due to the following properties: @@ -264,15 +240,6 @@ struct JSString { mBase = bstr; } - /* See JSString::reinitFlat. */ - inline void reinitDependent(JSString *bstr, size_t off, size_t len) { - JS_ASSERT(len <= MAX_LENGTH); - mLength = len; - mOffset = off; - mFlags = DEPENDENT | (mFlags & DEFLATED); - mBase = bstr; - } - inline JSString *dependentBase() const { JS_ASSERT(isDependent()); return mBase; @@ -503,19 +470,6 @@ JS_ISSPACE(jschar c) #define JS7_UNHEX(c) (uintN)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a') #define JS7_ISLET(c) ((c) < 128 && isalpha(c)) -/* Initialize per-runtime string state for the first context in the runtime. */ -extern JSBool -js_InitRuntimeStringState(JSContext *cx); - -extern JSBool -js_InitDeflatedStringCache(JSRuntime *rt); - -extern void -js_FinishRuntimeStringState(JSContext *cx); - -extern void -js_FinishDeflatedStringCache(JSRuntime *rt); - /* Initialize the String class, returning its prototype object. */ extern JSClass js_StringClass; @@ -686,13 +640,6 @@ extern JSBool js_DeflateStringToBuffer(JSContext *cx, const jschar *chars, size_t charsLength, char *bytes, size_t *length); -/* - * Associate bytes with str in the deflated string cache, returning true on - * successful association, false on out of memory. - */ -extern JSBool -js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length); - /* * Find or create a deflated string cache entry for str that contains its * characters chopped from Unicode code points into bytes. @@ -700,10 +647,6 @@ js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length); extern const char * js_GetStringBytes(JSContext *cx, JSString *str); -/* Remove a deflated string cache entry associated with str if any. */ -extern void -js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str); - /* Export a few natives and a helper to other files in SpiderMonkey. */ extern JSBool js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, @@ -750,4 +693,57 @@ js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); JS_END_EXTERN_C +namespace js { + +class DeflatedStringCache { + public: + DeflatedStringCache(); + bool init(); + ~DeflatedStringCache(); + + void sweep(JSContext *cx); + void remove(JSString *str); + bool setBytes(JSContext *cx, JSString *str, char *bytes); + + private: + struct StringPtrHasher + { + typedef JSString *Lookup; + + static uint32 hash(JSString *str) { + /* + * We hash only GC-allocated Strings. They are aligned on + * sizeof(JSString) boundary so we can improve hashing by stripping + * initial zeros. + */ + const jsuword ALIGN_LOG = tl::FloorLog2::result; + JS_STATIC_ASSERT(sizeof(JSString) == (size_t(1) << ALIGN_LOG)); + + jsuword ptr = reinterpret_cast(str); + jsuword key = ptr >> ALIGN_LOG; + JS_ASSERT((key << ALIGN_LOG) == ptr); + return uint32(key); + } + + static bool match(JSString *s1, JSString *s2) { + return s1 == s2; + } + }; + + typedef HashMap Map; + + /* cx is NULL when the caller is JS_GetStringBytes(JSString *). */ + char *getBytes(JSContext *cx, JSString *str); + + friend const char * + ::js_GetStringBytes(JSContext *cx, JSString *str); + + Map map; +#ifdef JS_THREADSAFE + JSLock *lock; +#endif +}; + +} /* namespace js */ + #endif /* jsstr_h___ */ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 2908d205794d..684b5c4b3597 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -7495,7 +7495,7 @@ js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2) * Reallocating str (because we know it has no other references) * requires purging any deflated string cached for it. */ - js_PurgeDeflatedStringCache(cx->runtime, str); + cx->runtime->deflatedStringCache->remove(str); } str2->getCharsAndLength(chars2, len2); From 1cc2983a51467fbed8d14240fe038fea46bd012a Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 16 Mar 2010 14:47:19 -0700 Subject: [PATCH 056/213] Backed out changeset bc5039752e41 --- js/src/jsstr.cpp | 115 +++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 74 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 0cfa3a3999da..362bebe69855 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1095,71 +1095,6 @@ js_BoyerMooreHorspool(const jschar *text, jsuint textlen, return -1; } -namespace { - -struct MemCmp { - typedef jsuint Extent; - static JS_ALWAYS_INLINE Extent computeExtent(const jschar *, jsuint patlen) { - return (patlen - 1) * sizeof(jschar); - } - static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { - return memcmp(p, t, extent) == 0; - } -}; - -struct ManualCmp { - typedef const jschar *Extent; - static JS_ALWAYS_INLINE Extent computeExtent(const jschar *pat, jsuint patlen) { - return pat + patlen; - } - static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { - for (; p != extent; ++p, ++t) { - if (*p != *t) - return false; - } - return true; - } -}; - -} - -template -static jsint -Duff(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) -{ - JS_ASSERT(patlen > 1 && textlen > 0); - const jschar *textend = text + textlen - (patlen - 1); - const jschar p0 = *pat; - const jschar *const patNext = pat + 1; - const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen); - uint8 fixup; - - const jschar *t = text; - switch ((textend - t) & 7) { - do { - case 0: if (*t++ == p0) { fixup = 8; goto match; } - case 7: if (*t++ == p0) { fixup = 7; goto match; } - case 6: if (*t++ == p0) { fixup = 6; goto match; } - case 5: if (*t++ == p0) { fixup = 5; goto match; } - case 4: if (*t++ == p0) { fixup = 4; goto match; } - case 3: if (*t++ == p0) { fixup = 3; goto match; } - case 2: if (*t++ == p0) { fixup = 2; goto match; } - case 1: if (*t++ == p0) { fixup = 1; goto match; } - continue; - do { - if (*t++ == p0) { - match: - if (!InnerMatch::match(patNext, t, extent)) - goto failed_match; - return t - text - 1; - } - failed_match:; - } while (--fixup > 0); - } while(t != textend); - } - return -1; -} - static JS_ALWAYS_INLINE jsint StringMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) @@ -1203,18 +1138,50 @@ StringMatch(const jschar *text, jsuint textlen, return index; } + const jschar *textend = text + textlen - (patlen - 1); + const jschar *patend = pat + patlen; + const jschar p0 = *pat; + const jschar *patNext = pat + 1; + uint8 fixup; + +#if __APPLE__ && __GNUC__ && __i386__ /* - * For big patterns with large potential overlap we want the SIMD-optimized - * speed of memcmp. For small patterns, a simple loop is faster. - * - * FIXME: Linux memcmp performance is sad and the manual loop is faster. + * It is critical that |t| is kept in a register. The version of gcc we use + * to build on 32-bit Mac does not realize this. See bug 526173. */ - return -#if !defined(__linux__) - patlen > 128 ? Duff(text, textlen, pat, patlen) - : + register const jschar *t asm("esi") = text; +#else + const jschar *t = text; #endif - Duff(text, textlen, pat, patlen); + + /* Credit: Duff */ + switch ((textend - text) & 7) { + do { + case 0: if (*t++ == p0) { fixup = 8; goto match; } + case 7: if (*t++ == p0) { fixup = 7; goto match; } + case 6: if (*t++ == p0) { fixup = 6; goto match; } + case 5: if (*t++ == p0) { fixup = 5; goto match; } + case 4: if (*t++ == p0) { fixup = 4; goto match; } + case 3: if (*t++ == p0) { fixup = 3; goto match; } + case 2: if (*t++ == p0) { fixup = 2; goto match; } + case 1: if (*t++ == p0) { fixup = 1; goto match; } + continue; + do { + if (*t++ == p0) { + match: + for (const jschar *p1 = patNext, *t1 = t; + p1 != patend; + ++p1, ++t1) { + if (*p1 != *t1) + goto failed_match; + } + return t - text - 1; + } + failed_match:; + } while (--fixup > 0); + } while(t != textend); + } + return -1; } static JSBool From a64e9de660b4f8f355c12db24bcd261dfca87aef Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Mon, 15 Mar 2010 21:52:41 -0400 Subject: [PATCH 057/213] Redo X64 asm_fneg to only allocate XMM regs, fix indirect calls, and revert asm_restore to old logic (bug 535706 r=nnethercote+) The code for indirect calls needed shuffling; we must freeResourcesOf() before assigning the call address to a register. The old code was just getting lucky, and the regstate fixes tickled the latent bug. asm_restore() can be stricter once we eliminate all cases where an F64 instruction can be assigned to a GPR. The only known remaining case is asm_quad which is used for both LIR_float and LIR_quad, which should be fixed by bug 534310. --HG-- extra : convert_revision : e46657bf61cade04961da7e8abbb004385aaad7b --- js/src/nanojit/NativeX64.cpp | 75 +++++++++++++++++++++--------------- js/src/nanojit/NativeX64.h | 1 + 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index 5d5c9b9e1d3a..e23993f77b01 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -451,7 +451,8 @@ namespace nanojit // XORPD because it's one byte shorter. This is ok because it's only used for // zeroing an XMM register; hence the single argument. // Also note that (unlike most SSE2 instructions) XORPS does not have a prefix, thus emitrr() should be used. - void Assembler::XORPS( R r) { emitrr(X64_xorps, r,r); asm_output("xorps %s, %s", RQ(r),RQ(r)); } + void Assembler::XORPS( R r) { emitrr(X64_xorps, r,r); asm_output("xorps %s, %s", RQ(r),RQ(r)); } + void Assembler::XORPS( R l, R r) { emitrr(X64_xorps, l,r); asm_output("xorps %s, %s", RQ(l),RQ(r)); } void Assembler::DIVSD( R l, R r) { emitprr(X64_divsd, l,r); asm_output("divsd %s, %s", RQ(l),RQ(r)); } void Assembler::MULSD( R l, R r) { emitprr(X64_mulsd, l,r); asm_output("mulsd %s, %s", RQ(l),RQ(r)); } void Assembler::ADDSD( R l, R r) { emitprr(X64_addsd, l,r); asm_output("addsd %s, %s", RQ(l),RQ(r)); } @@ -804,7 +805,7 @@ namespace nanojit // binary op with integer registers void Assembler::asm_arith(LIns *ins) { - Register rr, ra, rb; + Register rr, ra, rb = UnspecifiedReg; // init to shut GCC up switch (ins->opcode()) { case LIR_lsh: case LIR_qilsh: @@ -895,8 +896,7 @@ namespace nanojit ArgSize sizes[MAXARGS]; int argc = call->get_sizes(sizes); - bool indirect = call->isIndirect(); - if (!indirect) { + if (!call->isIndirect()) { verbose_only(if (_logc->lcbits & LC_Assembly) outputf(" %p:", _nIns); ) @@ -908,16 +908,21 @@ namespace nanojit CALLRAX(); asm_quad(RAX, (uint64_t)target, /*canClobberCCs*/true); } + // Call this now so that the arg setup can involve 'rr'. + freeResourcesOf(ins); } else { // Indirect call: we assign the address arg to RAX since it's not // used for regular arguments, and is otherwise scratch since it's // clobberred by the call. - asm_regarg(ARGSIZE_P, ins->arg(--argc), RAX); CALLRAX(); - } - // Call this now so that the arg setup can involve 'rr'. - freeResourcesOf(ins); + // Call this now so that the arg setup can involve 'rr'. + freeResourcesOf(ins); + + // Assign the call address to RAX. Must happen after freeResourcesOf() + // since RAX is usually the return value and will be allocated until that point. + asm_regarg(ARGSIZE_P, ins->arg(--argc), RAX); + } #ifdef _WIN64 int stk_used = 32; // always reserve 32byte shadow area @@ -1380,15 +1385,13 @@ namespace nanojit } else { int d = findMemFor(ins); - if (ins->isF64()) { - NanoAssert(IsFpReg(r)); + if (IsFpReg(r)) { + NanoAssert(ins->isF64()); MOVSDRM(r, d, FP); - } else if (ins->isI64()) { - NanoAssert(IsGpReg(r)); + } else if (ins->isN64()) { MOVQRM(r, d, FP); } else { NanoAssert(ins->isI32()); - NanoAssert(IsGpReg(r)); MOVLRM(r, d, FP); } } @@ -1689,6 +1692,8 @@ namespace nanojit // Register clean-up for 2-address style unary ops of the form R = (op) R. // Pairs with beginOp1Regs() and beginOp2Regs(). void Assembler::endOpRegs(LIns* ins, Register rr, Register ra) { + (void) rr; // quell warnings when NanoAssert is compiled out. + LIns* a = ins->oprnd1(); // We're finished with 'ins'. @@ -1706,29 +1711,35 @@ namespace nanojit void Assembler::asm_fneg(LIns *ins) { Register rr, ra; - if (isS32((uintptr_t)negateMask) || isTargetWithinS32((NIns*)negateMask)) { - beginOp1Regs(ins, FpRegs, rr, ra); - if (isS32((uintptr_t)negateMask)) { - // builtin code is in bottom or top 2GB addr space, use absolute addressing - XORPSA(rr, (int32_t)(uintptr_t)negateMask); - } else { - // jit code is within +/-2GB of builtin code, use rip-relative - XORPSM(rr, (NIns*)negateMask); - } - if (ra != rr) - asm_nongp_copy(rr,ra); - endOpRegs(ins, rr, ra); - + beginOp1Regs(ins, FpRegs, rr, ra); + if (isS32((uintptr_t)negateMask)) { + // builtin code is in bottom or top 2GB addr space, use absolute addressing + XORPSA(rr, (int32_t)(uintptr_t)negateMask); + } else if (isTargetWithinS32((NIns*)negateMask)) { + // jit code is within +/-2GB of builtin code, use rip-relative + XORPSM(rr, (NIns*)negateMask); } else { // This is just hideous - can't use RIP-relative load, can't use // absolute-address load, and cant move imm64 const to XMM. - // so do it all in a GPR. hrmph. - rr = prepareResultReg(ins, GpRegs); - ra = findRegFor(ins->oprnd1(), GpRegs & ~rmask(rr)); - XORQRR(rr, ra); // xor rr, ra - asm_quad(rr, negateMask[0], /*canClobberCCs*/true); // mov rr, 0x8000000000000000 - freeResourcesOf(ins); + // Solution: move negateMask into a temp GP register, then copy to + // a temp XMM register. + // Nb: we don't want any F64 values to end up in a GpReg, nor any + // I64 values to end up in an FpReg. + // + // # 'gt' and 'ga' are temporary GpRegs. + // # ins->oprnd1() is in 'rr' (FpRegs) + // mov gt, 0x8000000000000000 + // mov rt, gt + // xorps rr, rt + Register rt = registerAllocTmp(FpRegs & ~(rmask(ra)|rmask(rr))); + Register gt = registerAllocTmp(GpRegs); + XORPS(rr, rt); + MOVQXR(rt, gt); + asm_quad(gt, negateMask[0], /*canClobberCCs*/true); } + if (ra != rr) + asm_nongp_copy(rr,ra); + endOpRegs(ins, rr, ra); } void Assembler::asm_spill(Register rr, int d, bool /*pop*/, bool quad) { diff --git a/js/src/nanojit/NativeX64.h b/js/src/nanojit/NativeX64.h index 67fe76cb8826..a092fcb196d2 100644 --- a/js/src/nanojit/NativeX64.h +++ b/js/src/nanojit/NativeX64.h @@ -478,6 +478,7 @@ namespace nanojit void MOVSXDR(Register l, Register r);\ void MOVZX8(Register l, Register r);\ void XORPS(Register r);\ + void XORPS(Register l, Register r);\ void DIVSD(Register l, Register r);\ void MULSD(Register l, Register r);\ void ADDSD(Register l, Register r);\ From 22f5136231876b70e9cc9e3f64d3d84cf82325bf Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Mar 2010 09:04:22 +1100 Subject: [PATCH 058/213] Fix mochitest failures caused by the patch for bug 498193. r=me. --HG-- extra : convert_revision : c99da00233629d7184224a0a3a8129e248bb86fe --- js/src/nanojit/LIR.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 00e7b73cfc8f..5b9e1bf287bf 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -934,7 +934,17 @@ namespace nanojit LIns* LirWriter::ins_choose(LIns* cond, LIns* iftrue, LIns* iffalse, bool use_cmov) { - NanoAssert(cond->isCmp()); + // 'cond' must be a conditional, unless it has been optimized to 0 or + // 1. In that case make it an ==0 test and flip the branches. It'll + // get constant-folded by ExprFilter subsequently. + if (!cond->isCmp()) { + NanoAssert(cond->isconst()); + cond = ins_eq0(cond); + LInsp tmp = iftrue; + iftrue = iffalse; + iffalse = tmp; + } + if (use_cmov) { LOpcode op = LIR_cmov; if (iftrue->isI32() && iffalse->isI32()) { From 3bf15ae808daca5fff6558e8bb3b3430740009bd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Mar 2010 09:08:13 +1100 Subject: [PATCH 059/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 39f0eaaa4f0f..846b499bb7ea 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -0f045a5086e77b5117efe257b98c1d1b604b9487 +c99da00233629d7184224a0a3a8129e248bb86fe From fa6b435f200f5d211361fe4f3055a3d1f31851fc Mon Sep 17 00:00:00 2001 From: Bob Clary Date: Tue, 16 Mar 2010 18:07:26 -0700 Subject: [PATCH 060/213] bug 552218 - mark ecma/Date/15.9.5.14.js, ecma/Date/15.9.5.34-1.js, ecma_3/Date/15.9.5.5.js as random on Linux due to DST issues. --- js/src/tests/ecma/Date/jstests.list | 4 ++-- js/src/tests/ecma_3/Date/jstests.list | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/tests/ecma/Date/jstests.list b/js/src/tests/ecma/Date/jstests.list index 173b761d16ce..373fac74fd0a 100644 --- a/js/src/tests/ecma/Date/jstests.list +++ b/js/src/tests/ecma/Date/jstests.list @@ -64,7 +64,7 @@ script 15.9.5.13-5.js script 15.9.5.13-6.js script 15.9.5.13-7.js script 15.9.5.13-8.js -script 15.9.5.14.js +random-if(xulRuntime.OS=="Linux") script 15.9.5.14.js script 15.9.5.15.js skip-if(!xulRuntime.shell&&xulRuntime.OS=="Linux"&&xulRuntime.XPCOMABI.match(/x86_64/)) script 15.9.5.16.js # bug xxx crash script 15.9.5.17.js @@ -127,7 +127,7 @@ script 15.9.5.30-1.js script 15.9.5.31-1.js script 15.9.5.32-1.js script 15.9.5.33-1.js -script 15.9.5.34-1.js +random-if(xulRuntime.OS=="Linux") script 15.9.5.34-1.js script 15.9.5.35-1.js script 15.9.5.36-1.js script 15.9.5.36-2.js diff --git a/js/src/tests/ecma_3/Date/jstests.list b/js/src/tests/ecma_3/Date/jstests.list index 27b135987e6a..072f7f64e351 100644 --- a/js/src/tests/ecma_3/Date/jstests.list +++ b/js/src/tests/ecma_3/Date/jstests.list @@ -5,7 +5,7 @@ script 15.9.4.3.js script 15.9.5.3.js script 15.9.5.4.js script 15.9.5.5-02.js -script 15.9.5.5.js +random-if(xulRuntime.OS=="Linux") script 15.9.5.5.js script 15.9.5.6.js script 15.9.5.7.js script regress-452786.js From 770366a10348691cbab6d64bc1e876560c5f2b47 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 16 Mar 2010 21:43:48 -0700 Subject: [PATCH 061/213] (Fixed assert) Bug 551539 - use memcmp for inner loop of StringMatch, sometimes (r=bzbarsky) --- js/src/jsstr.cpp | 117 ++++++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 42 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 4ab24df75950..04bc452a6438 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1095,6 +1095,71 @@ js_BoyerMooreHorspool(const jschar *text, jsuint textlen, return -1; } +namespace { + +struct MemCmp { + typedef jsuint Extent; + static JS_ALWAYS_INLINE Extent computeExtent(const jschar *, jsuint patlen) { + return (patlen - 1) * sizeof(jschar); + } + static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { + return memcmp(p, t, extent) == 0; + } +}; + +struct ManualCmp { + typedef const jschar *Extent; + static JS_ALWAYS_INLINE Extent computeExtent(const jschar *pat, jsuint patlen) { + return pat + patlen; + } + static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { + for (; p != extent; ++p, ++t) { + if (*p != *t) + return false; + } + return true; + } +}; + +} + +template +static jsint +Duff(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) +{ + JS_ASSERT(patlen > 0 && textlen > 0); + const jschar *textend = text + textlen - (patlen - 1); + const jschar p0 = *pat; + const jschar *const patNext = pat + 1; + const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen); + uint8 fixup; + + const jschar *t = text; + switch ((textend - t) & 7) { + do { + case 0: if (*t++ == p0) { fixup = 8; goto match; } + case 7: if (*t++ == p0) { fixup = 7; goto match; } + case 6: if (*t++ == p0) { fixup = 6; goto match; } + case 5: if (*t++ == p0) { fixup = 5; goto match; } + case 4: if (*t++ == p0) { fixup = 4; goto match; } + case 3: if (*t++ == p0) { fixup = 3; goto match; } + case 2: if (*t++ == p0) { fixup = 2; goto match; } + case 1: if (*t++ == p0) { fixup = 1; goto match; } + continue; + do { + if (*t++ == p0) { + match: + if (!InnerMatch::match(patNext, t, extent)) + goto failed_match; + return t - text - 1; + } + failed_match:; + } while (--fixup > 0); + } while(t != textend); + } + return -1; +} + static JS_ALWAYS_INLINE jsint StringMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) @@ -1104,7 +1169,7 @@ StringMatch(const jschar *text, jsuint textlen, if (textlen < patlen) return -1; -#if __i386__ +#if defined(__i386__) || defined(_M_IX86) /* * Given enough registers, the unrolled loop below is faster than the * following loop. 32-bit x86 does not have enough registers. @@ -1138,50 +1203,18 @@ StringMatch(const jschar *text, jsuint textlen, return index; } - const jschar *textend = text + textlen - (patlen - 1); - const jschar *patend = pat + patlen; - const jschar p0 = *pat; - const jschar *patNext = pat + 1; - uint8 fixup; - -#if __APPLE__ && __GNUC__ && __i386__ /* - * It is critical that |t| is kept in a register. The version of gcc we use - * to build on 32-bit Mac does not realize this. See bug 526173. + * For big patterns with large potential overlap we want the SIMD-optimized + * speed of memcmp. For small patterns, a simple loop is faster. + * + * FIXME: Linux memcmp performance is sad and the manual loop is faster. */ - register const jschar *t asm("esi") = text; -#else - const jschar *t = text; + return +#if !defined(__linux__) + patlen > 128 ? Duff(text, textlen, pat, patlen) + : #endif - - /* Credit: Duff */ - switch ((textend - text) & 7) { - do { - case 0: if (*t++ == p0) { fixup = 8; goto match; } - case 7: if (*t++ == p0) { fixup = 7; goto match; } - case 6: if (*t++ == p0) { fixup = 6; goto match; } - case 5: if (*t++ == p0) { fixup = 5; goto match; } - case 4: if (*t++ == p0) { fixup = 4; goto match; } - case 3: if (*t++ == p0) { fixup = 3; goto match; } - case 2: if (*t++ == p0) { fixup = 2; goto match; } - case 1: if (*t++ == p0) { fixup = 1; goto match; } - continue; - do { - if (*t++ == p0) { - match: - for (const jschar *p1 = patNext, *t1 = t; - p1 != patend; - ++p1, ++t1) { - if (*p1 != *t1) - goto failed_match; - } - return t - text - 1; - } - failed_match:; - } while (--fixup > 0); - } while(t != textend); - } - return -1; + Duff(text, textlen, pat, patlen); } static JSBool From 35f4d9147310dd97d5d37601cb14e15b6a6d3e10 Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Wed, 17 Mar 2010 10:29:37 +0300 Subject: [PATCH 062/213] bug 551680 - replacing JS_(Suspend|Resume)Request with JSAutoSuspendRequest. r=mrbkap --- dom/src/threads/nsDOMThreadService.cpp | 92 +++++-------- js/ctypes/Function.cpp | 9 +- js/src/jsapi.cpp | 20 +++ js/src/jsapi.h | 26 +++- js/src/shell/js.cpp | 72 ++++++---- js/src/xpconnect/src/XPCDispObject.cpp | 2 +- js/src/xpconnect/src/nsXPConnect.cpp | 2 +- js/src/xpconnect/src/xpccomponents.cpp | 11 +- js/src/xpconnect/src/xpclog.cpp | 2 +- js/src/xpconnect/src/xpcprivate.h | 130 ------------------ js/src/xpconnect/src/xpcthreadcontext.cpp | 35 ++--- js/src/xpconnect/src/xpcwrappednative.cpp | 27 +++- js/src/xpconnect/src/xpcwrappednativeinfo.cpp | 18 +-- 13 files changed, 178 insertions(+), 268 deletions(-) diff --git a/dom/src/threads/nsDOMThreadService.cpp b/dom/src/threads/nsDOMThreadService.cpp index 3a55d56af84b..54aff2dac954 100644 --- a/dom/src/threads/nsDOMThreadService.cpp +++ b/dom/src/threads/nsDOMThreadService.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -514,71 +514,49 @@ DOMWorkerOperationCallback(JSContext* aCx) nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(aCx); NS_ASSERTION(worker, "This must never be null!"); - PRBool wasSuspended = PR_FALSE; - PRBool extraThreadAllowed = PR_FALSE; - jsrefcount suspendDepth = 0; + PRBool canceled = worker->IsCanceled(); + if (!canceled && worker->IsSuspended()) { + JSAutoSuspendRequest suspended(aCx); - for (;;) { - // Kill execution if we're canceled. - if (worker->IsCanceled()) { - LOG(("Forcefully killing JS for worker [0x%p]", - static_cast(worker))); + // Since we're going to block this thread we should open up a new thread + // in the thread pool for other workers. Must check the return value to + // make sure we don't decrement when we failed. + PRBool extraThreadAllowed = + NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1)); - if (wasSuspended) { - if (extraThreadAllowed) { - gDOMThreadService->ChangeThreadPoolMaxThreads(-1); - } - JS_ResumeRequest(aCx, suspendDepth); + // Flush JIT caches now before suspending to avoid holding memory that we + // are not going to use. + JS_FlushCaches(aCx); + + for (;;) { + nsAutoMonitor mon(worker->Pool()->Monitor()); + + // There's a small chance that the worker was canceled after our check + // above in which case we shouldn't wait here. We're guaranteed not to + // race here because the pool reenters its monitor after canceling each + // worker in order to notify its condition variable. + canceled = worker->IsCanceled(); + if (!canceled && worker->IsSuspended()) { + mon.Wait(); } - - // Kill execution of the currently running JS. - JS_ClearPendingException(aCx); - return JS_FALSE; - } - - // Break out if we're not suspended. - if (!worker->IsSuspended()) { - if (wasSuspended) { - if (extraThreadAllowed) { - gDOMThreadService->ChangeThreadPoolMaxThreads(-1); - } - JS_ResumeRequest(aCx, suspendDepth); + else { + break; } - return JS_TRUE; } - if (!wasSuspended) { - // Make sure to suspend our request while we block like this, otherwise we - // prevent GC for everyone. - suspendDepth = JS_SuspendRequest(aCx); - - // Since we're going to block this thread we should open up a new thread - // in the thread pool for other workers. Must check the return value to - // make sure we don't decrement when we failed. - extraThreadAllowed = - NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1)); - - // Flush JIT caches now before suspending to avoid holding memory that we - // are not going to use. - JS_FlushCaches(aCx); - - // Only do all this setup once. - wasSuspended = PR_TRUE; - } - - nsAutoMonitor mon(worker->Pool()->Monitor()); - - // There's a small chance that the worker was canceled after our check - // above in which case we shouldn't wait here. We're guaranteed not to race - // here because the pool reenters its monitor after canceling each worker - // in order to notify its condition variable. - if (worker->IsSuspended() && !worker->IsCanceled()) { - mon.Wait(); + if (extraThreadAllowed) { + gDOMThreadService->ChangeThreadPoolMaxThreads(-1); } } - NS_NOTREACHED("Should never get here!"); - return JS_FALSE; + if (canceled) { + LOG(("Forcefully killing JS for worker [0x%p]", + static_cast(worker))); + // Kill execution of the currently running JS. + JS_ClearPendingException(aCx); + return JS_FALSE; + } + return JS_TRUE; } void diff --git a/js/ctypes/Function.cpp b/js/ctypes/Function.cpp index 8cb7f00f2330..f9cdde7a2fff 100644 --- a/js/ctypes/Function.cpp +++ b/js/ctypes/Function.cpp @@ -236,11 +236,10 @@ Function::Execute(JSContext* cx, PRUint32 argc, jsval* vp) // suspend the request before we call into the function, since the call // may block or otherwise take a long time to return. - jsrefcount rc = JS_SuspendRequest(cx); - - ffi_call(&mCIF, FFI_FN(mFunc), resultValue.mData, reinterpret_cast(values.Elements())); - - JS_ResumeRequest(cx, rc); + { + JSAutoSuspendRequest suspended(cx); + ffi_call(&mCIF, FFI_FN(mFunc), resultValue.mData, reinterpret_cast(values.Elements())); + } // prepare a JS object from the result jsval rval; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 1af8ffc1d3a7..f0d592c7254b 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -878,6 +878,26 @@ JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth) #endif } +JS_PUBLIC_API(void) +JS_TransferRequest(JSContext *cx, JSContext *another) +{ + JS_ASSERT(cx != another); + JS_ASSERT(cx->runtime == another->runtime); +#ifdef JS_THREADSAFE + JS_ASSERT(cx->thread); + JS_ASSERT(another->thread); + JS_ASSERT(cx->thread == another->thread); + JS_ASSERT(cx->requestDepth != 0); + JS_ASSERT(another->requestDepth == 0); + + /* Serialize access to JSContext::requestDepth from other threads. */ + JS_LOCK_GC(cx->runtime); + another->requestDepth = cx->requestDepth; + cx->requestDepth = 0; + JS_UNLOCK_GC(cx->runtime); +#endif +} + JS_PUBLIC_API(void) JS_Lock(JSRuntime *rt) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 553d8df2089e..9ccbde542e55 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=78: * * ***** BEGIN LICENSE BLOCK ***** @@ -561,6 +561,9 @@ JS_SuspendRequest(JSContext *cx); extern JS_PUBLIC_API(void) JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth); +extern JS_PUBLIC_API(void) +JS_TransferRequest(JSContext *cx, JSContext *another); + #ifdef __cplusplus JS_END_EXTERN_C @@ -626,6 +629,27 @@ class JSAutoSuspendRequest { #endif }; +class JSAutoTransferRequest +{ + public: + JSAutoTransferRequest(JSContext* cx1, JSContext* cx2) + : cx1(cx1), cx2(cx2) { + if(cx1 != cx2) + JS_TransferRequest(cx1, cx2); + } + ~JSAutoTransferRequest() { + if(cx1 != cx2) + JS_TransferRequest(cx2, cx1); + } + private: + JSContext* const cx1; + JSContext* const cx2; + + /* Not copyable. */ + JSAutoTransferRequest(JSAutoTransferRequest &); + void operator =(JSAutoTransferRequest&); +}; + JS_BEGIN_EXTERN_C #endif diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8d35cffed053..3f94007f9965 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -469,12 +469,15 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY) size_t len = 0; /* initialize to avoid warnings */ do { ScheduleWatchdog(cx->runtime, -1); - jsrefcount rc = JS_SuspendRequest(cx); gCanceled = false; errno = 0; - char *line = GetLine(file, startline == lineno ? "js> " : ""); + + char *line; + { + JSAutoSuspendRequest suspended(cx); + line = GetLine(file, startline == lineno ? "js> " : ""); + } if (!line) { - JS_ResumeRequest(cx, rc); if (errno) { JS_ReportError(cx, strerror(errno)); free(buffer); @@ -498,7 +501,6 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY) if (!newBuf) { free(buffer); free(line); - JS_ResumeRequest(cx, rc); JS_ReportOutOfMemory(cx); return; } @@ -512,7 +514,6 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY) free(line); } lineno++; - JS_ResumeRequest(cx, rc); if (!ScheduleWatchdog(cx->runtime, gTimeoutInterval)) { hitEOF = JS_TRUE; break; @@ -1920,8 +1921,15 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* burn the leading lines */ line2 = JS_PCToLineNumber(cx, script, pc); - for (line1 = 0; line1 < line2 - 1; line1++) - (void) fgets(linebuf, LINE_BUF_LEN, file); /* Intentionally unused result. */ + for (line1 = 0; line1 < line2 - 1; line1++) { + char *tmp = fgets(linebuf, LINE_BUF_LEN, file); + if (!tmp) { + JS_ReportError(cx, "failed to read %s fully", + script->filename); + ok = JS_FALSE; + goto bail; + } + } bupline = 0; while (pc < end) { @@ -2947,7 +2955,6 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, const jschar *src; size_t srclen; JSBool lazy, split, ok; - jsval v; JSStackFrame *fp; sobj = NULL; @@ -2963,7 +2970,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } JS_SetOptions(scx, JS_GetOptions(cx)); - JS_BeginRequest(scx); + JS_TransferRequest(cx, scx); src = JS_GetStringChars(str); srclen = JS_GetStringLength(str); split = lazy = JS_FALSE; @@ -2987,12 +2994,12 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, ok = JS_FALSE; goto out; } - v = BOOLEAN_TO_JSVAL(lazy); - ok = JS_SetProperty(cx, sobj, "lazy", &v); + AutoValueRooter root(scx, BOOLEAN_TO_JSVAL(lazy)); + ok = JS_SetProperty(scx, sobj, "lazy", root.addr()); if (!ok) goto out; if (split) - sobj = split_outerObject(cx, sobj); + sobj = split_outerObject(scx, sobj); } if (srclen == 0) { @@ -3002,7 +3009,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, fp = JS_GetScriptedCaller(cx, NULL); JS_SetGlobalObject(scx, sobj); JS_ToggleOptions(scx, JSOPTION_DONT_REPORT_UNCAUGHT); - OBJ_TO_INNER_OBJECT(cx, sobj); + OBJ_TO_INNER_OBJECT(scx, sobj); if (!sobj) { ok = JS_FALSE; goto out; @@ -3012,16 +3019,18 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_PCToLineNumber(cx, fp->script, fp->regs->pc), rval); - if (!ok) { - if (JS_GetPendingException(scx, &v)) - JS_SetPendingException(cx, v); - else - JS_ReportOutOfMemory(cx); - } } out: - JS_EndRequest(scx); + jsval exceptionValue = JSVAL_NULL; + JSBool exception = !ok && JS_GetPendingException(scx, &exceptionValue); + + JS_TransferRequest(scx, cx); + if (exception) + JS_SetPendingException(cx, exceptionValue); + else if (!ok) + JS_ClearPendingException(cx); + WITH_LOCKED_CONTEXT_LIST( JS_DestroyContextNoGC(scx) ); @@ -3135,7 +3144,7 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp) if (t_ticks == 0) { JS_YieldRequest(cx); } else { - jsrefcount rc = JS_SuspendRequest(cx); + JSAutoSuspendRequest suspended(cx); PR_Lock(gWatchdogLock); PRIntervalTime to_wakeup = PR_IntervalNow() + t_ticks; for (;;) { @@ -3148,7 +3157,6 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp) t_ticks = to_wakeup - now; } PR_Unlock(gWatchdogLock); - JS_ResumeRequest(cx, rc); } return !gCanceled; } @@ -3236,9 +3244,9 @@ Scatter(JSContext *cx, uintN argc, jsval *vp) jsuint n; /* number of threads */ JSObject *inArr; JSObject *arr; + JSObject *global; ScatterData sd; JSBool ok; - jsrefcount rc; sd.lock = NULL; sd.cvar = NULL; @@ -3305,6 +3313,7 @@ Scatter(JSContext *cx, uintN argc, jsval *vp) } } + global = JS_GetGlobalObject(cx); for (i = 1; i < n; i++) { JSContext *newcx; WITH_LOCKED_CONTEXT_LIST( @@ -3312,9 +3321,11 @@ Scatter(JSContext *cx, uintN argc, jsval *vp) ); if (!newcx) goto fail; - JS_BeginRequest(newcx); - JS_SetGlobalObject(newcx, JS_GetGlobalObject(cx)); - JS_EndRequest(newcx); + + { + JSAutoTransferRequest transfer(cx, newcx); + JS_SetGlobalObject(newcx, global); + } JS_ClearContextThread(newcx); sd.threads[i].cx = newcx; } @@ -3347,11 +3358,12 @@ Scatter(JSContext *cx, uintN argc, jsval *vp) DoScatteredWork(cx, &sd.threads[0]); - rc = JS_SuspendRequest(cx); - for (i = 1; i < n; i++) { - PR_JoinThread(sd.threads[i].thr); + { + JSAutoSuspendRequest suspended(cx); + for (i = 1; i < n; i++) { + PR_JoinThread(sd.threads[i].thr); + } } - JS_ResumeRequest(cx, rc); success: arr = JS_NewArrayObject(cx, n, sd.results); diff --git a/js/src/xpconnect/src/XPCDispObject.cpp b/js/src/xpconnect/src/XPCDispObject.cpp index fdc9a164f646..ab80aab8e136 100644 --- a/js/src/xpconnect/src/XPCDispObject.cpp +++ b/js/src/xpconnect/src/XPCDispObject.cpp @@ -195,7 +195,7 @@ JSBool XPCDispObject::Dispatch(XPCCallContext& ccx, IDispatch * disp, // Scope the lock { // avoid deadlock in case the native method blocks somehow - AutoJSSuspendRequest req(ccx); // scoped suspend of request + JSAutoSuspendRequest req(ccx); // scoped suspend of request // call IDispatch's invoke invokeResult= disp->Invoke( dispID, // IDispatch ID diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 516ab25159e6..abac34d492d7 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -2179,7 +2179,7 @@ nsXPConnect::UpdateXOWs(JSContext* aJSContext, if(!list) return NS_OK; // No wrappers to update. - AutoJSRequestWithNoCallContext req(aJSContext); + JSAutoRequest req(aJSContext); Link* cur = list; if(cur->obj && !PerformOp(aJSContext, aWay, cur->obj)) diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 8b1e2ff1774b..2405f50b527a 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -3221,7 +3221,7 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop) if (!tempcx) return NS_ERROR_OUT_OF_MEMORY; - AutoJSRequestWithNoCallContext req(tempcx); + JSAutoRequest req(tempcx); JSObject *sandbox = JS_NewObject(tempcx, &SandboxClass, nsnull, nsnull); if (!sandbox) return NS_ERROR_XPC_UNEXPECTED; @@ -3592,7 +3592,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, nsresult rv = NS_OK; { - AutoJSRequestWithNoCallContext req(sandcx->GetJSContext()); + JSAutoRequest req(sandcx->GetJSContext()); JSString *str = nsnull; if (!JS_EvaluateUCScriptForPrincipals(sandcx->GetJSContext(), sandbox, jsPrincipals, @@ -3608,9 +3608,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, // Stash the exception in |cx| so we can execute code on // sandcx without a pending exception. { - AutoJSSuspendRequestWithNoCallContext sus(sandcx->GetJSContext()); - AutoJSRequestWithNoCallContext cxreq(cx); - + JSAutoTransferRequest transfer(sandcx->GetJSContext(), cx); JS_SetPendingException(cx, exn); } @@ -3620,8 +3618,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, // exception into a string. str = JS_ValueToString(sandcx->GetJSContext(), exn); - AutoJSSuspendRequestWithNoCallContext sus(sandcx->GetJSContext()); - AutoJSRequestWithNoCallContext cxreq(cx); + JSAutoTransferRequest transfer(sandcx->GetJSContext(), cx); if (str) { // We converted the exception to a string. Use that // as the value exception. diff --git a/js/src/xpconnect/src/xpclog.cpp b/js/src/xpconnect/src/xpclog.cpp index 2e48c2da076b..01060cc0cd0b 100644 --- a/js/src/xpconnect/src/xpclog.cpp +++ b/js/src/xpconnect/src/xpclog.cpp @@ -157,7 +157,7 @@ LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, const char *reason) className ? " for " : "", className ? className : "", reason, obj); if(className) PR_Free(className); - AutoJSRequestWithNoCallContext autoRequest(cx); + JSAutoRequest autoRequest(cx); xpc_DumpJSStack(cx, JS_FALSE, JS_FALSE, JS_FALSE); } #endif diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 92ef8882f2d5..7097c6b6a1dd 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -3771,136 +3771,6 @@ private: nsCString mCategory; }; -/***************************************************************************/ -// XXX allowing for future notifications to XPCCallContext - -class AutoJSRequest -{ -public: - AutoJSRequest(XPCCallContext& aCCX) - : mCCX(aCCX), mCX(aCCX.GetJSContext()) {BeginRequest();} - ~AutoJSRequest() {EndRequest();} - - void EndRequest() { - if(mCX) { - JS_EndRequest(mCX); - mCX = nsnull; - } - } -private: - void BeginRequest() { - if(JS_GetContextThread(mCX)) - JS_BeginRequest(mCX); - else - mCX = nsnull; - } -private: - XPCCallContext& mCCX; - JSContext* mCX; -}; - -class AutoJSSuspendRequest -{ -public: - AutoJSSuspendRequest(XPCCallContext& aCCX) - : mCX(aCCX.GetJSContext()) {SuspendRequest();} - ~AutoJSSuspendRequest() {ResumeRequest();} - - void ResumeRequest() { - if(mCX) { - JS_ResumeRequest(mCX, mDepth); - mCX = nsnull; - } - } -private: - void SuspendRequest() { - if(JS_GetContextThread(mCX)) - mDepth = JS_SuspendRequest(mCX); - else - mCX = nsnull; - } -private: - JSContext* mCX; - jsrefcount mDepth; -}; - -class AutoJSSuspendRequestWithNoCallContext -{ -public: - AutoJSSuspendRequestWithNoCallContext(JSContext *aCX) - : mCX(aCX) {SuspendRequest();} - ~AutoJSSuspendRequestWithNoCallContext() {ResumeRequest();} - - void ResumeRequest() { - if(mCX) { - JS_ResumeRequest(mCX, mDepth); - mCX = nsnull; - } - } -private: - void SuspendRequest() { - if(JS_GetContextThread(mCX)) - mDepth = JS_SuspendRequest(mCX); - else - mCX = nsnull; - } -private: - JSContext* mCX; - jsrefcount mDepth; -}; - -class AutoJSSuspendNonMainThreadRequest -{ -public: - AutoJSSuspendNonMainThreadRequest(JSContext *aCX) - : mCX(aCX) {SuspendRequest();} - ~AutoJSSuspendNonMainThreadRequest() {ResumeRequest();} - - void ResumeRequest() { - if (mCX) { - JS_ResumeRequest(mCX, mDepth); - mCX = nsnull; - } - } - -private: - void SuspendRequest() { - if (mCX && !XPCPerThreadData::IsMainThread(mCX)) - mDepth = JS_SuspendRequest(mCX); - else - mCX = nsnull; - } - - JSContext *mCX; - jsrefcount mDepth; -}; - - -/*****************************************/ - -class AutoJSRequestWithNoCallContext -{ -public: - AutoJSRequestWithNoCallContext(JSContext* aCX) : mCX(aCX) {BeginRequest();} - ~AutoJSRequestWithNoCallContext() {EndRequest();} - - void EndRequest() { - if(mCX) { - JS_EndRequest(mCX); - mCX = nsnull; - } - } -private: - void BeginRequest() { - if(JS_GetContextThread(mCX)) - JS_BeginRequest(mCX); - else - mCX = nsnull; - } -private: - JSContext* mCX; -}; - /***************************************************************************/ class AutoJSErrorAndExceptionEater { diff --git a/js/src/xpconnect/src/xpcthreadcontext.cpp b/js/src/xpconnect/src/xpcthreadcontext.cpp index ffab33266847..15da96129727 100644 --- a/js/src/xpconnect/src/xpcthreadcontext.cpp +++ b/js/src/xpconnect/src/xpcthreadcontext.cpp @@ -248,12 +248,12 @@ XPCJSContextStack::GetSafeJSContext(JSContext * *aSafeJSContext) if(xpc && (xpcrt = xpc->GetRuntime()) && (rt = xpcrt->GetJSRuntime())) { + JSObject *glob; mSafeJSContext = JS_NewContext(rt, 8192); if(mSafeJSContext) { // scoped JS Request - AutoJSRequestWithNoCallContext req(mSafeJSContext); - JSObject *glob; + JSAutoRequest req(mSafeJSContext); glob = JS_NewObject(mSafeJSContext, &global_class, NULL, NULL); #ifndef XPCONNECT_STANDALONE @@ -276,23 +276,26 @@ XPCJSContextStack::GetSafeJSContext(JSContext * *aSafeJSContext) // nsCOMPtr or dealt with, or we'll release in the finalize // hook. #endif - if(!glob || NS_FAILED(xpc->InitClasses(mSafeJSContext, glob))) + if(glob && NS_FAILED(xpc->InitClasses(mSafeJSContext, glob))) { - // Explicitly end the request since we are about to kill - // the JSContext that 'req' will try to use when it - // goes out of scope. - req.EndRequest(); - JS_DestroyContext(mSafeJSContext); - mSafeJSContext = nsnull; + glob = nsnull; } - // Save it off so we can destroy it later, even if - // mSafeJSContext has been set to another context - // via SetSafeJSContext. If we don't get here, - // then mSafeJSContext must have been set via - // SetSafeJSContext, and we're not responsible for - // destroying the passed-in context. - mOwnSafeJSContext = mSafeJSContext; + } + if(!glob && mSafeJSContext) + { + // Destroy the context outside the scope of JSAutoRequest that + // uses the context in its destructor. + JS_DestroyContext(mSafeJSContext); + mSafeJSContext = nsnull; + } + // Save it off so we can destroy it later, even if + // mSafeJSContext has been set to another context + // via SetSafeJSContext. If we don't get here, + // then mSafeJSContext must have been set via + // SetSafeJSContext, and we're not responsible for + // destroying the passed-in context. + mOwnSafeJSContext = mSafeJSContext; } } diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index a8714a949a4c..12bd98d84692 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -2310,8 +2310,15 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx, nsISupports* qiresult = nsnull; { - AutoJSSuspendNonMainThreadRequest req(ccx.GetJSContext()); - invokeResult = callee->QueryInterface(*iid, (void**) &qiresult); + if(XPCPerThreadData::IsMainThread(ccx)) + { + invokeResult = callee->QueryInterface(*iid, (void**) &qiresult); + } + else + { + JSAutoSuspendRequest suspended(ccx); + invokeResult = callee->QueryInterface(*iid, (void**) &qiresult); + } } xpcc->SetLastResult(invokeResult); @@ -2721,10 +2728,18 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx, // do the invoke { - AutoJSSuspendNonMainThreadRequest req(ccx.GetJSContext()); - invokeResult = NS_InvokeByIndex(callee, vtblIndex, - paramCount + wantsOptArgc, - dispatchParams); + uint8 allParamCount = paramCount + wantsOptArgc; + if(XPCPerThreadData::IsMainThread(ccx)) + { + invokeResult = NS_InvokeByIndex(callee, vtblIndex, + allParamCount, dispatchParams); + } + else + { + JSAutoSuspendRequest suspended(ccx); + invokeResult = NS_InvokeByIndex(callee, vtblIndex, + allParamCount, dispatchParams); + } } xpcc->SetLastResult(invokeResult); diff --git a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp index 8e6e3df0b668..519927b1de9c 100644 --- a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp +++ b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp @@ -203,19 +203,11 @@ XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface) const char *memberName = iface->GetMemberName(ccx, this); - jsrefcount suspendDepth = 0; - if(cx != ccx) { - // Switching contexts, suspend the old and enter the new request. - suspendDepth = JS_SuspendRequest(ccx); - JS_BeginRequest(cx); - } - - JSFunction *fun = JS_NewFunction(cx, callback, argc, flags, nsnull, - memberName); - - if(suspendDepth) { - JS_EndRequest(cx); - JS_ResumeRequest(ccx, suspendDepth); + JSFunction *fun; + // Switching contexts, suspend the old and enter the new request. + { + JSAutoTransferRequest transfer(ccx, cx); + fun = JS_NewFunction(cx, callback, argc, flags, nsnull, memberName); } if(!fun) From f3ac73f624ddfbefdf2b52c5cb0c00b70c0be93a Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Wed, 17 Mar 2010 12:41:11 -0700 Subject: [PATCH 063/213] Restore lost rt->protoHazardShape check (503860, r=jorendorff). --- js/src/jsops.cpp | 4 +++- js/src/tests/js1_5/Regress/regress-452189.js | 24 +++++++++++++++++++ js/src/tests/js1_5/Regress/regress-503860.js | 25 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 js/src/tests/js1_5/Regress/regress-452189.js create mode 100644 js/src/tests/js1_5/Regress/regress-503860.js diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 70bfdc6a9ce3..0c392373bf1b 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1761,7 +1761,9 @@ BEGIN_CASE(JSOP_SETMETHOD) checkForAdd = !sprop->parent; } - if (checkForAdd && sprop->hasDefaultSetter() && + if (checkForAdd && + PCVCAP_SHAPE(entry->vcap) == rt->protoHazardShape && + sprop->hasDefaultSetter() && (slot = sprop->slot) == scope->freeslot) { /* * Fast path: adding a plain old property that was once diff --git a/js/src/tests/js1_5/Regress/regress-452189.js b/js/src/tests/js1_5/Regress/regress-452189.js new file mode 100644 index 000000000000..1305b6e6baf6 --- /dev/null +++ b/js/src/tests/js1_5/Regress/regress-452189.js @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Geoff Garen + */ + +var gTestfile = 'regress-452189.js'; +//----------------------------------------------------------------------------- +var BUGNUMBER = 452189; +var summary = "Don't shadow a readonly or setter proto-property"; +var expect = "PASS"; +var actual = "FAIL"; + +function c() { + this.x = 3; +} + + +new c; +Object.prototype.__defineSetter__('x', function(){ actual = expect; }) +new c; + +reportCompare(expect, actual, summary); diff --git a/js/src/tests/js1_5/Regress/regress-503860.js b/js/src/tests/js1_5/Regress/regress-503860.js new file mode 100644 index 000000000000..2ae44e8e6279 --- /dev/null +++ b/js/src/tests/js1_5/Regress/regress-503860.js @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Jason Orendorff + */ + +var gTestfile = 'regress-503860.js'; +//----------------------------------------------------------------------------- +var BUGNUMBER = 503860; +var summary = "Don't shadow a readonly or setter proto-property"; +var expect = "PASS"; +var actual = "FAIL"; +var a = {y: 1}; + +function B(){} +B.prototype.__defineSetter__('x', function setx(val) { actual = expect; }); +var b = new B; +b.y = 1; + +var arr = [a, b]; // same shape prior to bug 497789 fix +for each (var obj in arr) + obj.x = 2; // should call b's setter but doesn't + +reportCompare(expect, actual, summary); From 6bc0b2f1151fb59dc326db304af3f754fd98ad5d Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Wed, 17 Mar 2010 12:52:46 -0700 Subject: [PATCH 064/213] Add tests for 503860 to jstests.list. --- js/src/tests/js1_5/Regress/jstests.list | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/tests/js1_5/Regress/jstests.list b/js/src/tests/js1_5/Regress/jstests.list index 23cf2f32b44f..d0f2a22420b0 100644 --- a/js/src/tests/js1_5/Regress/jstests.list +++ b/js/src/tests/js1_5/Regress/jstests.list @@ -260,6 +260,7 @@ script regress-451884.js script regress-451946.js script regress-452008.js script regress-452170.js +script regress-452189.js script regress-452333.js script regress-452336.js script regress-452346.js @@ -346,6 +347,7 @@ script regress-482421.js script regress-482783.js script regress-483103.js script regress-501124.js +script regress-503860.js script regress-504078.js script regress-506567.js script regress-511859.js From 9ad2181a1acca6cd46f8384ccdde9eaa20550aac Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 16 Mar 2010 10:41:28 -0500 Subject: [PATCH 065/213] Bug 530583 - Delete silly JS_INT32_TO_PTR etc. macros. r=jwalden. --HG-- extra : rebase_source : ccd52d3c33a3fd984fb5588ef12cbf9a6a80c423 --- js/src/jsapi.cpp | 2 +- js/src/jsatom.h | 4 ++-- js/src/jscntxt.cpp | 2 +- js/src/jsobj.cpp | 13 ++++++------- js/src/jsobj.h | 10 +++++----- js/src/jstypes.h | 13 ------------- 6 files changed, 15 insertions(+), 29 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f0d592c7254b..bb241d0a997b 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2876,7 +2876,7 @@ DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, JSAtom *atom; if (attrs & JSPROP_INDEX) { - id = INT_TO_JSID(JS_PTR_TO_INT32(name)); + id = INT_TO_JSID(intptr_t(name)); atom = NULL; attrs &= ~JSPROP_INDEX; } else { diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 45fc24e4dbd8..4cb934caa176 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -87,7 +87,7 @@ struct JSAtomListElement { }; #define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key) -#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value)) +#define ALE_INDEX(ale) (jsatomid(uintptr_t((ale)->entry.value))) #define ALE_VALUE(ale) ((jsval) (ale)->entry.value) #define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next) @@ -99,7 +99,7 @@ struct JSAtomListElement { #define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value) #define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom)) -#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index)) +#define ALE_SET_INDEX(ale,index)((ale)->entry.value = (void *)(index)) #define ALE_SET_DEFN(ale, dn) ((ale)->entry.value = (void *)(dn)) #define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v)) #define ALE_SET_NEXT(ale,nxt) ((ale)->entry.next = (JSHashEntry *)(nxt)) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index a5b620e305be..69582a4d60fe 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -953,7 +953,7 @@ resolving_HashKey(JSDHashTable *table, const void *ptr) { const JSResolvingKey *key = (const JSResolvingKey *)ptr; - return ((JSDHashNumber)JS_PTR_TO_UINT32(key->obj) >> JSVAL_TAGBITS) ^ key->id; + return (JSDHashNumber(uintptr_t(key->obj)) >> JSVAL_TAGBITS) ^ key->id; } JS_PUBLIC_API(JSBool) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 7aa99b141bb2..542b1a9b769b 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -322,7 +322,7 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj, static JSHashNumber js_hash_object(const void *key) { - return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS; + return JSHashNumber(uintptr_t(key) >> JSVAL_TAGBITS); } static JSHashEntry * @@ -354,8 +354,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) he = *hep; if (!he) { sharpid = 0; - he = JS_HashTableRawAdd(table, hep, hash, obj, - JS_UINT32_TO_PTR(sharpid)); + he = JS_HashTableRawAdd(table, hep, hash, obj, (void *) sharpid); if (!he) { JS_ReportOutOfMemory(cx); return NULL; @@ -412,10 +411,10 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) if (!ok) return NULL; } else { - sharpid = JS_PTR_TO_UINT32(he->value); + sharpid = uintptr_t(he->value); if (sharpid == 0) { sharpid = ++map->sharpgen << SHARP_ID_SHIFT; - he->value = JS_UINT32_TO_PTR(sharpid); + he->value = (void *) sharpid; } ida = NULL; } @@ -475,7 +474,7 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, --map->depth; if (!he) goto bad; - JS_ASSERT((JS_PTR_TO_UINT32(he->value) & SHARP_BIT) == 0); + JS_ASSERT((uintptr_t(he->value) & SHARP_BIT) == 0); if (!idap) { JS_DestroyIdArray(cx, ida); ida = NULL; @@ -503,7 +502,7 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, } } - sharpid = JS_PTR_TO_UINT32(he->value); + sharpid = uintptr_t(he->value); if (sharpid != 0) { len = JS_snprintf(buf, sizeof buf, "#%u%c", sharpid >> SHARP_ID_SHIFT, diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 2af03e34b27e..69403e528248 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -658,11 +658,11 @@ struct JSSharpObjectMap { #define SHARP_BIT ((jsatomid) 1) #define BUSY_BIT ((jsatomid) 2) #define SHARP_ID_SHIFT 2 -#define IS_SHARP(he) (JS_PTR_TO_UINT32((he)->value) & SHARP_BIT) -#define MAKE_SHARP(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)|SHARP_BIT)) -#define IS_BUSY(he) (JS_PTR_TO_UINT32((he)->value) & BUSY_BIT) -#define MAKE_BUSY(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)|BUSY_BIT)) -#define CLEAR_BUSY(he) ((he)->value = JS_UINT32_TO_PTR(JS_PTR_TO_UINT32((he)->value)&~BUSY_BIT)) +#define IS_SHARP(he) (uintptr_t((he)->value) & SHARP_BIT) +#define MAKE_SHARP(he) ((he)->value = (void *) (uintptr_t((he)->value)|SHARP_BIT)) +#define IS_BUSY(he) (uintptr_t((he)->value) & BUSY_BIT) +#define MAKE_BUSY(he) ((he)->value = (void *) (uintptr_t((he)->value)|BUSY_BIT)) +#define CLEAR_BUSY(he) ((he)->value = (void *) (uintptr_t((he)->value)&~BUSY_BIT)) extern JSHashEntry * js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, diff --git a/js/src/jstypes.h b/js/src/jstypes.h index f6b49f49d65b..f664ac8fac51 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -267,19 +267,6 @@ #define JS_BIT(n) ((JSUint32)1 << (n)) #define JS_BITMASK(n) (JS_BIT(n) - 1) -/*********************************************************************** -** MACROS: JS_PTR_TO_INT32 -** JS_PTR_TO_UINT32 -** JS_INT32_TO_PTR -** JS_UINT32_TO_PTR -** DESCRIPTION: -** Integer to pointer and pointer to integer conversion macros. -***********************************************************************/ -#define JS_PTR_TO_INT32(x) ((jsint)((char *)(x) - (char *)0)) -#define JS_PTR_TO_UINT32(x) ((jsuint)((char *)(x) - (char *)0)) -#define JS_INT32_TO_PTR(x) ((void *)((char *)0 + (jsint)(x))) -#define JS_UINT32_TO_PTR(x) ((void *)((char *)0 + (jsuint)(x))) - /*********************************************************************** ** MACROS: JS_HOWMANY ** JS_ROUNDUP From 176743c01d241e95858f19f0646d9c0a69e787c2 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 17 Mar 2010 10:22:13 -0500 Subject: [PATCH 066/213] Bug 480850 - Add JSAPI function JS_New. r=mrbkap. --HG-- extra : rebase_source : bb808cedea84d20dfa6e2b3ab6d11b5491aa9058 --- js/src/jsapi-tests/Makefile.in | 1 + js/src/jsapi-tests/testNewObject.cpp | 101 +++++++++++++++++++++++++++ js/src/jsapi.cpp | 25 +++++++ js/src/jsapi.h | 3 + 4 files changed, 130 insertions(+) create mode 100644 js/src/jsapi-tests/testNewObject.cpp diff --git a/js/src/jsapi-tests/Makefile.in b/js/src/jsapi-tests/Makefile.in index e338907d08c3..f41b13fb805b 100644 --- a/js/src/jsapi-tests/Makefile.in +++ b/js/src/jsapi-tests/Makefile.in @@ -55,6 +55,7 @@ CPPSRCS = \ testIntString.cpp \ testIsAboutToBeFinalized.cpp \ testLookup.cpp \ + testNewObject.cpp \ testPropCache.cpp \ testTrap.cpp \ testSameValue.cpp \ diff --git a/js/src/jsapi-tests/testNewObject.cpp b/js/src/jsapi-tests/testNewObject.cpp new file mode 100644 index 000000000000..5b637453d32d --- /dev/null +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + */ + +#include "tests.h" + +const int N = 1000; +static jsval argv[N]; + +static JSBool +constructHook(JSContext *cx, JSObject *thisobj, uintN argc, jsval *argv, jsval *rval) +{ + // Check that arguments were passed properly from JS_New. + JSObject *callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); + if (!thisobj) { + JS_ReportError(cx, "test failed, null 'this'"); + return false; + } + if (strcmp(JS_GET_CLASS(cx, thisobj)->name, "Object") != 0) { + JS_ReportError(cx, "test failed, wrong class for 'this'"); + return false; + } + if (argc != 3) { + JS_ReportError(cx, "test failed, argc == %d", argc); + return false; + } + if (!JSVAL_IS_INT(argv[2]) || JSVAL_TO_INT(argv[2]) != 2) { + JS_ReportError(cx, "test failed, wrong value in argv[2]"); + return false; + } + if (!JS_IsConstructing(cx)) { + JS_ReportError(cx, "test failed, not constructing"); + return false; + } + + // Perform a side-effect to indicate that this hook was actually called. + if (!JS_SetElement(cx, callee, 0, &argv[0])) + return false; + + *rval = OBJECT_TO_JSVAL(callee); // return the callee, perversely + argv[0] = argv[1] = argv[2] = JSVAL_VOID; // trash the argv, perversely + return true; +} + +BEGIN_TEST(testNewObject_1) +{ + jsval v; + EVAL("Array", &v); + JSObject *Array = JSVAL_TO_OBJECT(v); + + // With no arguments. + JSObject *obj = JS_New(cx, Array, 0, NULL); + CHECK(obj); + jsvalRoot rt(cx, OBJECT_TO_JSVAL(obj)); + CHECK(JS_IsArrayObject(cx, obj)); + jsuint len; + CHECK(JS_GetArrayLength(cx, obj, &len)); + CHECK(len == 0); + + // With one argument. + argv[0] = INT_TO_JSVAL(4); + obj = JS_New(cx, Array, 1, argv); + CHECK(obj); + rt = OBJECT_TO_JSVAL(obj); + CHECK(JS_IsArrayObject(cx, obj)); + CHECK(JS_GetArrayLength(cx, obj, &len)); + CHECK(len == 4); + + // With N arguments. + JS_ASSERT(INT_FITS_IN_JSVAL(N)); + for (int i = 0; i < N; i++) + argv[i] = INT_TO_JSVAL(i); + obj = JS_New(cx, Array, N, argv); + CHECK(obj); + rt = OBJECT_TO_JSVAL(obj); + CHECK(JS_IsArrayObject(cx, obj)); + CHECK(JS_GetArrayLength(cx, obj, &len)); + CHECK(len == N); + CHECK(JS_GetElement(cx, obj, N - 1, &v)); + CHECK_SAME(v, INT_TO_JSVAL(N - 1)); + + // With JSClass.construct. + static JSClass cls = { + "testNewObject_1", + 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + NULL, NULL, NULL, constructHook, NULL, NULL, NULL, NULL + }; + JSObject *ctor = JS_NewObject(cx, &cls, NULL, NULL); + CHECK(ctor); + jsvalRoot rt2(cx, OBJECT_TO_JSVAL(ctor)); + obj = JS_New(cx, ctor, 3, argv); + CHECK(obj); + CHECK(obj == ctor); // constructHook returns ctor, perversely + CHECK(JS_GetElement(cx, ctor, 0, &v)); + CHECK_SAME(v, JSVAL_ZERO); + CHECK_SAME(argv[0], JSVAL_ZERO); // original argv should not have been trashed + CHECK_SAME(argv[1], JSVAL_ONE); +} +END_TEST(testNewObject_1) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index bb241d0a997b..a7fac4160220 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4981,6 +4981,31 @@ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, return ok; } +JS_PUBLIC_API(JSObject *) +JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv) +{ + CHECK_REQUEST(cx); + + // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW + // is not a simple variation of JSOP_CALL. We have to determine what class + // of object to create, create it, and clamp the return value to an object, + // among other details. js_InvokeConstructor does the hard work. + void *mark; + jsval *vp = js_AllocStack(cx, 2 + argc, &mark); + if (!vp) + return NULL; + vp[0] = OBJECT_TO_JSVAL(ctor); + vp[1] = JSVAL_NULL; + memcpy(vp + 2, argv, argc * sizeof(jsval)); + + JSBool ok = js_InvokeConstructor(cx, argc, JS_TRUE, vp); + JSObject *obj = ok ? JSVAL_TO_OBJECT(vp[0]) : NULL; + + js_FreeStack(cx, mark); + LAST_FRAME_CHECKS(cx, ok); + return obj; +} + JS_PUBLIC_API(JSOperationCallback) JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 9ccbde542e55..9dce64cbed8b 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1705,6 +1705,9 @@ extern JS_PUBLIC_API(JSObject *) JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent, uintN argc, jsval *argv); +extern JS_PUBLIC_API(JSObject *) +JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv); + extern JS_PUBLIC_API(JSObject *) JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp, JSObject *proto, uintN attrs); From 27e4be007fdc37e6c3e6a66ca07fd8b934d6f170 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Thu, 4 Mar 2010 16:49:31 -0800 Subject: [PATCH 067/213] b=550351; don't abort recording when accessing out of range typed array element (return undefined instead); r=gal --- js/src/jstracer.cpp | 177 ++++++++++-------- js/src/jstypedarray.cpp | 121 ++++++++---- js/src/tests/js1_8_5/extensions/typedarray.js | 23 ++- .../trace-test/tests/basic/testTypedArrays.js | 104 ++++++++++ 4 files changed, 307 insertions(+), 118 deletions(-) create mode 100644 js/src/trace-test/tests/basic/testTypedArrays.js diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index fe498d681f9b..31e3ef74e947 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8605,10 +8605,10 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, op = LIR_feq; } } else if (JSVAL_IS_NULL(l) && JSVAL_IS_SPECIAL(r)) { - l_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID)); + l_ins = INS_VOID(); cond = (r == JSVAL_VOID); } else if (JSVAL_IS_SPECIAL(l) && JSVAL_IS_NULL(r)) { - r_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID)); + r_ins = INS_VOID(); cond = (l == JSVAL_VOID); } else if (isNumber(l) && JSVAL_IS_STRING(r)) { args[0] = r_ins, args[1] = cx_ins; @@ -11967,10 +11967,10 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) LIns* priv_ins = stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE); - // The index was on the stack and is therefore a LIR float. Force it to - // be an integer. - idx_ins = makeNumberInt32(idx_ins); - + // The index was on the stack and is therefore a LIR float; force it to + // be an integer. + idx_ins = makeNumberInt32(idx_ins); + // Ensure idx >= 0 && idx < length (by using uint32) lir->insGuard(LIR_xf, lir->ins2(LIR_ult, @@ -11985,80 +11985,84 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) LIns* pidx_ins = lir->ins_u2p(idx_ins); LIns* addr_ins = 0; - if (isNumber(v)) { - if (isPromoteInt(v_ins) && - tarray->type != js::TypedArray::TYPE_FLOAT32 && - tarray->type != js::TypedArray::TYPE_FLOAT64) { - LIns *v_ins_int = demote(lir, v_ins); - - if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) { - /* Wrap v_ins_int in some magic to clamp it */ - v_ins_int = lir->ins_choose(lir->ins2i(LIR_lt, v_ins_int, 0), - lir->insImm(0), - lir->ins_choose(lir->ins2i(LIR_gt, v_ins_int, 0xff), - lir->insImm(0xff), - v_ins_int, - avmplus::AvmCore::use_cmov()), - avmplus::AvmCore::use_cmov()); - } - - switch (tarray->type) { - case js::TypedArray::TYPE_INT8: - case js::TypedArray::TYPE_UINT8: - case js::TypedArray::TYPE_UINT8_CLAMPED: - addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - lir->insStore(LIR_stb, v_ins_int, addr_ins, 0); - break; - case js::TypedArray::TYPE_INT16: - case js::TypedArray::TYPE_UINT16: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); - lir->insStore(LIR_sts, v_ins_int, addr_ins, 0); - break; - case js::TypedArray::TYPE_INT32: - case js::TypedArray::TYPE_UINT32: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_sti, v_ins_int, addr_ins, 0); - break; - case js::TypedArray::TYPE_FLOAT32: - case js::TypedArray::TYPE_FLOAT64: - default: - JS_NOT_REACHED("Unknown typed array in tracer"); - } + // If it's not a number, convert objects to NaN, + // null to 0, and call StringToNumber or BooleanOrUndefinedToNumber + // for those. + if (!isNumber(v)) { + if (JSVAL_IS_NULL(v)) { + v_ins = INS_CONST(0); + } else if (JSVAL_IS_PRIMITIVE(v)) { + JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + LIns* args[] = { v_ins, cx_ins }; + v_ins = lir->insCall(JSVAL_IS_STRING(v) + ? &js_StringToNumber_ci + : &js_BooleanOrUndefinedToNumber_ci, + args); } else { - switch (tarray->type) { - case js::TypedArray::TYPE_INT8: - case js::TypedArray::TYPE_UINT8: - addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - lir->insStore(LIR_stb, lir->ins1(LIR_f2i, v_ins), addr_ins, 0); - break; - case js::TypedArray::TYPE_INT16: - case js::TypedArray::TYPE_UINT16: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); - lir->insStore(LIR_sts, lir->ins1(LIR_f2i, v_ins), addr_ins, 0); - break; - case js::TypedArray::TYPE_INT32: - case js::TypedArray::TYPE_UINT32: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_sti, lir->ins1(LIR_f2i, v_ins), addr_ins, 0); - break; - case js::TypedArray::TYPE_FLOAT32: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_st32f, v_ins, addr_ins, 0); - break; - case js::TypedArray::TYPE_FLOAT64: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 3)); - lir->insStore(LIR_stfi, v_ins, addr_ins, 0); - break; - case js::TypedArray::TYPE_UINT8_CLAMPED: - addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - lir->insStore(LIR_stb, lir->insCall(&js_TypedArray_uint8_clamp_double_ci, &v_ins), addr_ins, 0); - break; - default: - JS_NOT_REACHED("Unknown typed array type in tracer"); - } + v_ins = lir->insImmf(js_NaN); } - } else { - RETURN_STOP_A("can't trace setting typed array element to non-number value"); + } + + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_INT32: + v_ins = f2i(v_ins); + break; + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT16: + case js::TypedArray::TYPE_UINT32: + v_ins = f2u(v_ins); + break; + case js::TypedArray::TYPE_UINT8_CLAMPED: + if (isPromoteInt(v_ins)) { + v_ins = demote(lir, v_ins); + v_ins = lir->ins_choose(lir->ins2i(LIR_lt, v_ins, 0), + lir->insImm(0), + lir->ins_choose(lir->ins2i(LIR_gt, v_ins, 0xff), + lir->insImm(0xff), + v_ins, + avmplus::AvmCore::use_cmov()), + avmplus::AvmCore::use_cmov()); + } else { + v_ins = lir->insCall(&js_TypedArray_uint8_clamp_double_ci, &v_ins); + } + break; + case js::TypedArray::TYPE_FLOAT32: + case js::TypedArray::TYPE_FLOAT64: + // Do nothing, this is already a float + break; + default: + JS_NOT_REACHED("Unknown typed array type in tracer"); + } + + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + case js::TypedArray::TYPE_UINT8: + addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); + lir->insStore(LIR_stb, v_ins, addr_ins, 0); + break; + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_UINT16: + addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); + lir->insStore(LIR_sts, v_ins, addr_ins, 0); + break; + case js::TypedArray::TYPE_INT32: + case js::TypedArray::TYPE_UINT32: + addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); + lir->insStore(LIR_sti, v_ins, addr_ins, 0); + break; + case js::TypedArray::TYPE_FLOAT32: + addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); + lir->insStore(LIR_st32f, v_ins, addr_ins, 0); + break; + case js::TypedArray::TYPE_FLOAT64: + addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 3)); + lir->insStore(LIR_stfi, v_ins, addr_ins, 0); + break; + default: + JS_NOT_REACHED("Unknown typed array type in tracer"); } } else if (JSVAL_TO_INT(idx) < 0 || !obj->isDenseArray()) { CHECK_STATUS_A(initOrSetPropertyByIndex(obj_ins, idx_ins, &v, @@ -12948,7 +12952,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT)); // Return undefined and indicate that we didn't actually read this (addr_ins). - v_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID)); + v_ins = INS_VOID(); addr_ins = NULL; return RECORD_CONTINUE; } @@ -13020,9 +13024,16 @@ TraceRecorder::typedArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ /* priv_ins will load the TypedArray* */ LIns* priv_ins = stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE); - /* for out-of-range, just let the interpreter handle it */ - if ((jsuint) idx >= tarray->length) - return ARECORD_STOP; + /* for out-of-range, do the same thing that the interpreter does, which is return undefined */ + if ((jsuint) idx >= tarray->length) { + guard(false, + lir->ins2(LIR_ult, + idx_ins, + lir->insLoad(LIR_ld, priv_ins, js::TypedArray::lengthOffset(), ACC_READONLY)), + BRANCH_EXIT); + v_ins = INS_VOID(); + return ARECORD_CONTINUE; + } /* * Ensure idx < length @@ -13037,7 +13048,7 @@ TraceRecorder::typedArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ lir->ins2(LIR_ult, idx_ins, lir->insLoad(LIR_ld, priv_ins, js::TypedArray::lengthOffset(), ACC_READONLY)), - OVERFLOW_EXIT); + BRANCH_EXIT); /* We are now ready to load. Do a different type of load * depending on what type of thing we're loading. */ diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index ac8a2c9424dc..7aec65f1461d 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -368,12 +368,12 @@ struct uint8_clamped { } inline uint8_clamped& operator= (uint16 x) { - val = (x > 255) ? 255 : 0; + val = (x > 255) ? 255 : uint8(x); return *this; } inline uint8_clamped& operator= (uint32 x) { - val = (x > 255) ? 255 : 0; + val = (x > 255) ? 255 : uint8(x); return *this; } @@ -424,6 +424,15 @@ template<> inline const int TypeIDOfType() { return TypedArray::TYPE_FLOA template<> inline const int TypeIDOfType() { return TypedArray::TYPE_FLOAT64; } template<> inline const int TypeIDOfType() { return TypedArray::TYPE_UINT8_CLAMPED; } +template static inline const bool TypeIsUnsigned() { return false; } +template<> inline const bool TypeIsUnsigned() { return true; } +template<> inline const bool TypeIsUnsigned() { return true; } +template<> inline const bool TypeIsUnsigned() { return true; } + +template static inline const bool TypeIsFloatingPoint() { return false; } +template<> inline const bool TypeIsFloatingPoint() { return true; } +template<> inline const bool TypeIsFloatingPoint() { return true; } + template class TypedArrayTemplate; typedef TypedArrayTemplate Int8Array; @@ -442,6 +451,9 @@ class TypedArrayTemplate { public: typedef TypedArrayTemplate ThisTypeArray; + static const int ArrayTypeID() { return TypeIDOfType(); } + static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned(); } + static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint(); } static JSObjectOps fastObjectOps; static JSObjectMap fastObjectMap; @@ -450,12 +462,12 @@ class TypedArrayTemplate static inline JSClass *slowClass() { - return &TypedArray::slowClasses[TypeIDOfType()]; + return &TypedArray::slowClasses[ArrayTypeID()]; } static inline JSClass *fastClass() { - return &TypedArray::fastClasses[TypeIDOfType()]; + return &TypedArray::fastClasses[ArrayTypeID()]; } static JSObjectOps *getObjectOps(JSContext *cx, JSClass *clasp) @@ -536,12 +548,51 @@ class TypedArrayTemplate if (JSVAL_IS_INT(*vp)) { tarray->setIndex(index, NativeType(JSVAL_TO_INT(*vp))); - } else if (JSVAL_IS_DOUBLE(*vp)) { - tarray->setIndex(index, NativeType(*JSVAL_TO_DOUBLE(*vp))); + return true; + } + + jsdouble d; + + if (JSVAL_IS_DOUBLE(*vp)) { + d = *JSVAL_TO_DOUBLE(*vp); + } else if (JSVAL_IS_NULL(*vp)) { + d = 0.0f; + } else if (JSVAL_IS_PRIMITIVE(*vp)) { + JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp)); + if (JSVAL_IS_STRING(*vp)) { + // note that ValueToNumber will always + // succeed with a string arg + d = js_ValueToNumber(cx, vp); + JS_ASSERT(*vp != JSVAL_NULL); + } else if (*vp == JSVAL_VOID) { + d = js_NaN; + } else { + d = (double) JSVAL_TO_BOOLEAN(*vp); + } } else { - jsdouble d; - if (JS_ValueToNumber(cx, *vp, &d)) - tarray->setIndex(index, NativeType(d)); + // non-primitive assignments become NaN or 0 (for float/int arrays) + d = js_NaN; + } + + // If the array is an integer array, we only handle up to + // 32-bit ints from this point on. if we want to handle + // 64-bit ints, we'll need some changes. + + // Assign based on characteristics of the destination type + if (ArrayTypeIsFloatingPoint()) { + tarray->setIndex(index, NativeType(d)); + } else if (ArrayTypeIsUnsigned()) { + JS_ASSERT(sizeof(NativeType) <= 4); + uint32 n = js_DoubleToECMAUint32(d); + tarray->setIndex(index, NativeType(n)); + } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) { + // The uint8_clamped type has a special rounding converter + // for doubles. + tarray->setIndex(index, NativeType(d)); + } else { + JS_ASSERT(sizeof(NativeType) <= 4); + int32 n = js_DoubleToECMAInt32(d); + tarray->setIndex(index, NativeType(n)); } return true; @@ -815,14 +866,14 @@ class TypedArrayTemplate bool init(JSContext *cx, uint32 len) { - type = TypeIDOfType(); + type = ArrayTypeID(); return createBufferWithSizeAndCount(cx, sizeof(NativeType), len); } bool init(JSContext *cx, JSObject *other, int32 byteOffsetInt = -1, int32 lengthInt = -1) { - type = TypeIDOfType(); + type = ArrayTypeID(); //printf ("Constructing with type %d other %p offset %d length %d\n", type, other, byteOffset, length); @@ -924,28 +975,40 @@ class TypedArrayTemplate } protected: + static NativeType + nativeFromValue(JSContext *cx, jsval v) + { + if (JSVAL_IS_INT(v)) + return NativeType(JSVAL_TO_INT(v)); + + if (JSVAL_IS_DOUBLE(v)) + return NativeType(*JSVAL_TO_DOUBLE(v)); + + if (JSVAL_IS_PRIMITIVE(v) && v != JSVAL_HOLE) { + jsdouble dval = js_ValueToNumber(cx, &v); + JS_ASSERT(v != JSVAL_NULL); + return NativeType(dval); + } + + if (ArrayTypeIsFloatingPoint()) + return NativeType(js_NaN); + + return NativeType(int32(0)); + } + bool copyFrom(JSContext *cx, JSObject *ar, jsuint len) { NativeType *dest = static_cast(data); - if (ar->isDenseArray()) { + if (ar->isDenseArray() && js_DenseArrayCapacity(ar) >= len) { JS_ASSERT(ar->fslots[JSSLOT_ARRAY_LENGTH] == (jsval)len); jsval *src = ar->dslots; for (uintN i = 0; i < len; ++i) { jsval v = *src++; - if (JSVAL_IS_INT(v)) { - *dest++ = NativeType(JSVAL_TO_INT(v)); - } else if (JSVAL_IS_DOUBLE(v)) { - *dest++ = NativeType(*JSVAL_TO_DOUBLE(v)); - } else { - jsdouble dval; - if (!JS_ValueToNumber(cx, v, &dval)) - return false; - *dest++ = NativeType(dval); - } + *dest++ = nativeFromValue(cx, v); } } else { // slow path @@ -954,17 +1017,7 @@ class TypedArrayTemplate for (uintN i = 0; i < len; ++i) { if (!JS_GetElement(cx, ar, i, &v)) return false; - - if (JSVAL_IS_INT(v)) { - *dest++ = NativeType(JSVAL_TO_INT(v)); - } else if (JSVAL_IS_DOUBLE(v)) { - *dest++ = NativeType(*JSVAL_TO_DOUBLE(v)); - } else { - jsdouble dval; - if (!JS_ValueToNumber(cx, v, &dval)) - return false; - *dest++ = NativeType(dval); - } + *dest++ = nativeFromValue(cx, v); } } @@ -1341,7 +1394,7 @@ js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) return JSVAL_TO_OBJECT(rval.value()); } -static inline bool +static inline JSBool TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, jsval *argv, jsval *rv) { switch (atype) { diff --git a/js/src/tests/js1_8_5/extensions/typedarray.js b/js/src/tests/js1_8_5/extensions/typedarray.js index 81b8a27e31f1..84c52107fdab 100644 --- a/js/src/tests/js1_8_5/extensions/typedarray.js +++ b/js/src/tests/js1_8_5/extensions/typedarray.js @@ -182,7 +182,6 @@ function test() //checkThrows(function() a[-10] = 0); check(function() (a[0] = "10") && (a[0] == 10)); - // check Uint8ClampedArray, which is an extension to this extension a = new Uint8ClampedArray(4); a[0] = 128; @@ -195,6 +194,28 @@ function test() check(function() a[2] == 0); check(function() a[3] == 0); + // check handling of holes and non-numeric values + var x = Array(5); + x[0] = "hello"; + x[1] = { }; + //x[2] is a hole + x[3] = undefined; + x[4] = true; + + a = new Uint8Array(x); + check(function() a[0] == 0); + check(function() a[1] == 0); + check(function() a[2] == 0); + check(function() a[3] == 0); + check(function() a[4] == 1); + + a = new Float32Array(x); + check(function() !(a[0] == a[0])); + check(function() !(a[1] == a[1])); + check(function() !(a[2] == a[2])); + check(function() !(a[3] == a[3])); + check(function() a[4] == 1); + print ("done"); reportCompare(0, TestFailCount, "typed array tests"); diff --git a/js/src/trace-test/tests/basic/testTypedArrays.js b/js/src/trace-test/tests/basic/testTypedArrays.js new file mode 100644 index 000000000000..485d1132c930 --- /dev/null +++ b/js/src/trace-test/tests/basic/testTypedArrays.js @@ -0,0 +1,104 @@ +function testBasicTypedArrays() +{ + var ar, aridx, idx; + + var a = new Uint8Array(16); + var b = new Uint16Array(16); + var c = new Uint32Array(16); + var d = new Int8Array(16); + var e = new Int16Array(16); + var f = new Int32Array(16); + + var g = new Float32Array(16); + var h = new Float64Array(16); + + var iarrays = [ a, b, c, d, e, f ]; + for (aridx = 0; aridx < iarrays.length; ++aridx) { + ar = iarrays[aridx]; + + for (idx = 0; idx < ar.length-4; ++idx) { + ar[idx] = 22; + ar[idx+1] = 12.7; + ar[idx+2] = "99"; + ar[idx+3] = { k: "thing" }; + ar[idx+4] = Infinity; + } + + assertEq(ar[ar.length-5], 22); + assertEq(ar[ar.length-4], 12); + assertEq(ar[ar.length-3], 99); + assertEq(ar[ar.length-2], 0); + assertEq(ar[ar.length-1], 0); + } + + var farrays = [ g, h ]; + for (aridx = 0; aridx < farrays.length; ++aridx) { + ar = farrays[aridx]; + + for (idx = 0; idx < ar.length-4; ++idx) { + ar[idx] = 22; + ar[idx+1] = 12.25; + ar[idx+2] = "99"; + ar[idx+3] = { k: "thing" }; + ar[idx+4] = Infinity; + } + + assertEq(ar[ar.length-5], 22); + assertEq(ar[ar.length-4], 12.25); + assertEq(ar[ar.length-3], 99); + assertEq(!(ar[ar.length-2] == ar[ar.length-2]), true); + assertEq(ar[ar.length-1], Infinity); + } +} + +function testSpecialTypedArrays() +{ + var ar, aridx, idx; + + ar = new Uint8ClampedArray(16); + for (idx = 0; idx < ar.length-4; ++idx) { + ar[idx] = -200; + ar[idx+1] = 127.5; + ar[idx+2] = 987; + ar[idx+3] = Infinity; + ar[idx+4] = "hello world"; + } + + assertEq(ar[ar.length-5], 0); + assertEq(ar[ar.length-4], 128); + assertEq(ar[ar.length-3], 255); + assertEq(ar[ar.length-2], 255); + assertEq(ar[ar.length-1], 0); +} + +function testTypedArrayOther() +{ + var ar = new Int32Array(16); + for (var i = 0; i < ar.length; ++i) { + ar[i] = i; + } + + for (var i = 0; i < ar.length; ++i) { + // deliberate out of bounds access + ar[i-2] = ar[i+2]; + } + + var t = 0; + for (var i = 0; i < ar.length; ++i) { + t += ar[i]; + } + + assertEq(t, 143); +} + +testBasicTypedArrays(); +testSpecialTypedArrays(); +testTypedArrayOther(); + +checkStats({ + // Note! These are all inner tree growing aborts, because we change + // the array type in the inner loop of the tests. This isn't ideal, + // and if we ever fix these to not report as aborts, this should go + // back to 0. + recorderAborted: 5 +}); From 06318b44ee8863aa99522a5ddfa1afc32fde9cb9 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Wed, 17 Mar 2010 15:35:06 -0700 Subject: [PATCH 068/213] Fix warnings. rs=jorendorff --- js/src/jsapi-tests/testNewObject.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/src/jsapi-tests/testNewObject.cpp b/js/src/jsapi-tests/testNewObject.cpp index 5b637453d32d..b845126e18a5 100644 --- a/js/src/jsapi-tests/testNewObject.cpp +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -4,7 +4,7 @@ #include "tests.h" -const int N = 1000; +const size_t N = 1000; static jsval argv[N]; static JSBool @@ -68,7 +68,7 @@ BEGIN_TEST(testNewObject_1) // With N arguments. JS_ASSERT(INT_FITS_IN_JSVAL(N)); - for (int i = 0; i < N; i++) + for (size_t i = 0; i < N; i++) argv[i] = INT_TO_JSVAL(i); obj = JS_New(cx, Array, N, argv); CHECK(obj); @@ -97,5 +97,6 @@ BEGIN_TEST(testNewObject_1) CHECK_SAME(v, JSVAL_ZERO); CHECK_SAME(argv[0], JSVAL_ZERO); // original argv should not have been trashed CHECK_SAME(argv[1], JSVAL_ONE); + return true; } END_TEST(testNewObject_1) From ee991917919c538cc0c4e770fa98081335dee3fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 09:53:06 +1100 Subject: [PATCH 069/213] Bug 552614 - nanojit: fix AR::Iter::next(). r=rreitmai. --HG-- extra : convert_revision : 4dd75fe044cc599088bb52ebce8a880528bc05b4 --- js/src/nanojit/Assembler.cpp | 68 ++++++++++++++++++------------------ js/src/nanojit/Assembler.h | 1 + 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index aeca74b66939..cd9dbb2d01b5 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -118,49 +118,49 @@ namespace nanojit NanoAssert(_entries[i] == BAD_ENTRY); } - void AR::validate() - { + void AR::validate() + { static uint32_t validateCounter = 0; - if (++validateCounter >= 100) - { - validateFull(); - validateCounter = 0; - } - else - { - validateQuick(); - } - } + if (++validateCounter >= 100) + { + validateFull(); + validateCounter = 0; + } + else + { + validateQuick(); + } + } #endif - inline void AR::clear() - { - _highWaterMark = 0; + inline void AR::clear() + { + _highWaterMark = 0; NanoAssert(_entries[0] == NULL); #ifdef _DEBUG for (uint32_t i = 1; i < NJ_MAX_STACK_ENTRY; ++i) _entries[i] = BAD_ENTRY; #endif - } + } - bool AR::Iter::next(LIns*& ins, uint32_t& nStackSlots, int32_t& arIndex) - { - while (++_i <= _ar._highWaterMark) - { - if ((ins = _ar._entries[_i]) != NULL) - { - nStackSlots = nStackSlotsFor(ins); - _i += nStackSlots - 1; - arIndex = _i; - return true; - } - } - ins = NULL; - nStackSlots = 0; - arIndex = 0; - return false; - } + bool AR::Iter::next(LIns*& ins, uint32_t& nStackSlots, int32_t& arIndex) + { + while (_i <= _ar._highWaterMark) { + ins = _ar._entries[_i]; + if (ins) { + arIndex = _i; + nStackSlots = nStackSlotsFor(ins); + _i += nStackSlots; + return true; + } + _i++; + } + ins = NULL; + nStackSlots = 0; + arIndex = 0; + return false; + } void Assembler::arReset() { @@ -2054,7 +2054,7 @@ namespace nanojit void AR::checkForResourceLeaks() const { for (uint32_t i = 1; i <= _highWaterMark; i++) { - NanoAssertMsgf(_entries[i] == NULL, "frame entry %d wasn't freed\n",-4*i); + NanoAssertMsgf(_entries[i] == NULL, "frame entry %d wasn't freed\n",4*i); } } #endif diff --git a/js/src/nanojit/Assembler.h b/js/src/nanojit/Assembler.h index 9f0f0a310483..2f4072dc1ca9 100644 --- a/js/src/nanojit/Assembler.h +++ b/js/src/nanojit/Assembler.h @@ -136,6 +136,7 @@ namespace nanojit { private: const AR& _ar; + // '_i' points to the start of the entries for an LIns, or to the first NULL entry. uint32_t _i; public: inline Iter(const AR& ar) : _ar(ar), _i(1) { } From 318eeb3df0cef05a2670bc4c6c55993016091d4e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 10:21:02 +1100 Subject: [PATCH 070/213] Bug 534310 - nanojit: split asm_quad() into asm_immq() and asm_immf(). r=edwsmith. --HG-- extra : convert_revision : 04a7a273ac34034a84391f0e9b965220f19200be --- js/src/nanojit/Assembler.cpp | 15 ++++-- js/src/nanojit/Assembler.h | 7 ++- js/src/nanojit/NativeARM.cpp | 18 +++---- js/src/nanojit/NativeARM.h | 2 +- js/src/nanojit/NativeMIPS.cpp | 8 +-- js/src/nanojit/NativePPC.cpp | 43 +++++++++++++++- js/src/nanojit/NativeSparc.cpp | 4 +- js/src/nanojit/NativeX64.cpp | 90 ++++++++++++++++++++-------------- js/src/nanojit/NativeX64.h | 5 +- js/src/nanojit/Nativei386.cpp | 28 +++++------ js/src/nanojit/Nativei386.h | 4 +- 11 files changed, 145 insertions(+), 79 deletions(-) diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index cd9dbb2d01b5..ac1e1f12e32e 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -1328,14 +1328,21 @@ namespace nanojit case LIR_int: { countlir_imm(); - asm_int(ins); + asm_immi(ins); break; } - case LIR_float: - CASE64(LIR_quad:) +#ifdef NANOJIT_64BIT + case LIR_quad: { countlir_imm(); - asm_quad(ins); + asm_immq(ins); + break; + } +#endif + case LIR_float: + { + countlir_imm(); + asm_immf(ins); break; } case LIR_param: diff --git a/js/src/nanojit/Assembler.h b/js/src/nanojit/Assembler.h index 2f4072dc1ca9..17a07fdf5603 100644 --- a/js/src/nanojit/Assembler.h +++ b/js/src/nanojit/Assembler.h @@ -427,7 +427,10 @@ namespace nanojit void asm_spill(Register rr, int d, bool pop, bool quad); void asm_load64(LInsp i); void asm_ret(LInsp p); - void asm_quad(LInsp i); +#ifdef NANOJIT_64BIT + void asm_immq(LInsp i); +#endif + void asm_immf(LInsp i); void asm_fcond(LInsp i); void asm_cond(LInsp i); void asm_arith(LInsp i); @@ -435,7 +438,7 @@ namespace nanojit void asm_load32(LInsp i); void asm_cmov(LInsp i); void asm_param(LInsp i); - void asm_int(LInsp i); + void asm_immi(LInsp i); #if NJ_SOFTFLOAT_SUPPORTED void asm_qlo(LInsp i); void asm_qhi(LInsp i); diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index 2cd25386920f..cba8181ca7e6 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -1434,7 +1434,7 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) // has the right value if (value->isconstq()) { underrunProtect(4*4); - asm_quad_nochk(rv, value->imm64_0(), value->imm64_1()); + asm_immf_nochk(rv, value->imm64_0(), value->imm64_1()); } } else { int da = findMemFor(value); @@ -1485,7 +1485,7 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) // has the right value if (value->isconstq()) { underrunProtect(4*4); - asm_quad_nochk(rv, value->imm64_0(), value->imm64_1()); + asm_immf_nochk(rv, value->imm64_0(), value->imm64_1()); } } else { NanoAssertMsg(0, "st32f not supported with non-VFP, fix me"); @@ -1499,10 +1499,10 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) //asm_output(">>> store64"); } -// stick a quad into register rr, where p points to the two +// Stick a float into register rr, where p points to the two // 32-bit parts of the quad, optinally also storing at FP+d void -Assembler::asm_quad_nochk(Register rr, int32_t imm64_0, int32_t imm64_1) +Assembler::asm_immf_nochk(Register rr, int32_t imm64_0, int32_t imm64_1) { // We're not going to use a slot, because it might be too far // away. Instead, we're going to stick a branch in the stream to @@ -1524,9 +1524,9 @@ Assembler::asm_quad_nochk(Register rr, int32_t imm64_0, int32_t imm64_1) } void -Assembler::asm_quad(LInsp ins) +Assembler::asm_immf(LInsp ins) { - //asm_output(">>> asm_quad"); + //asm_output(">>> asm_immf"); int d = deprecated_disp(ins); Register rr = ins->deprecated_getReg(); @@ -1537,7 +1537,7 @@ Assembler::asm_quad(LInsp ins) asm_spill(rr, d, false, true); underrunProtect(4*4); - asm_quad_nochk(rr, ins->imm64_0(), ins->imm64_1()); + asm_immf_nochk(rr, ins->imm64_0(), ins->imm64_1()); } else { NanoAssert(d); // asm_mmq might spill a reg, so don't call it; @@ -1550,7 +1550,7 @@ Assembler::asm_quad(LInsp ins) asm_ld_imm(IP, ins->imm64_0()); } - //asm_output("<<< asm_quad"); + //asm_output("<<< asm_immf"); } void @@ -2676,7 +2676,7 @@ Assembler::asm_param(LInsp ins) } void -Assembler::asm_int(LInsp ins) +Assembler::asm_immi(LInsp ins) { Register rr = deprecated_prepResultReg(ins, GpRegs); asm_ld_imm(rr, ins->imm32()); diff --git a/js/src/nanojit/NativeARM.h b/js/src/nanojit/NativeARM.h index 230fc16b2ed8..b490b1688a18 100644 --- a/js/src/nanojit/NativeARM.h +++ b/js/src/nanojit/NativeARM.h @@ -219,7 +219,7 @@ verbose_only( extern const char* shiftNames[]; ) void underrunProtect(int bytes); \ void nativePageReset(); \ void nativePageSetup(); \ - void asm_quad_nochk(Register, int32_t, int32_t); \ + void asm_immf_nochk(Register, int32_t, int32_t); \ void asm_regarg(ArgSize, LInsp, Register); \ void asm_stkarg(LInsp p, int stkd); \ void asm_cmpi(Register, int32_t imm); \ diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp index f0e3251b1bd0..0bb11c07d877 100644 --- a/js/src/nanojit/NativeMIPS.cpp +++ b/js/src/nanojit/NativeMIPS.cpp @@ -635,7 +635,7 @@ namespace nanojit TAG("asm_fneg(ins=%p{%s})", ins, lirNames[ins->opcode()]); } - void Assembler::asm_quad(LIns *ins) + void Assembler::asm_immf(LIns *ins) { int d = deprecated_disp(ins); Register rr = ins->deprecated_getReg(); @@ -650,7 +650,7 @@ namespace nanojit NanoAssert(d); asm_store_imm64(ins, d, FP); } - TAG("asm_quad(ins=%p{%s})", ins, lirNames[ins->opcode()]); + TAG("asm_immf(ins=%p{%s})", ins, lirNames[ins->opcode()]); } void @@ -764,11 +764,11 @@ namespace nanojit TAG("asm_neg_not(ins=%p{%s})", ins, lirNames[ins->opcode()]); } - void Assembler::asm_int(LIns *ins) + void Assembler::asm_immi(LIns *ins) { Register rr = deprecated_prepResultReg(ins, GpRegs); asm_li(rr, ins->imm32()); - TAG("asm_int(ins=%p{%s})", ins, lirNames[ins->opcode()]); + TAG("asm_immi(ins=%p{%s})", ins, lirNames[ins->opcode()]); } void Assembler::asm_cmov(LIns *ins) diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index c695a0f16fe3..6f6ea9322e6e 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -641,7 +641,7 @@ namespace nanojit } } - void Assembler::asm_int(LIns *ins) { + void Assembler::asm_immi(LIns *ins) { Register rr = deprecated_prepResultReg(ins, GpRegs); asm_li(rr, ins->imm32()); } @@ -1028,7 +1028,46 @@ namespace nanojit } #endif - void Assembler::asm_quad(LIns *ins) { +#ifdef NANOJIT_64BIT + void Assembler::asm_immq(LIns *ins) { + Register r = ins->deprecated_getReg(); + if (deprecated_isKnownReg(r) && (rmask(r) & FpRegs)) { + // FPR already assigned, fine, use it + deprecated_freeRsrcOf(ins, false); + } else { + // use a GPR register; its okay to copy doubles with GPR's + // but *not* okay to copy non-doubles with FPR's + r = deprecated_prepResultReg(ins, GpRegs); + } + + if (rmask(r) & FpRegs) { + union { + double d; + struct { + int32_t hi, lo; + } w; + }; + d = ins->imm64f(); + LFD(r, 8, SP); + STW(R0, 12, SP); + asm_li(R0, w.lo); + STW(R0, 8, SP); + asm_li(R0, w.hi); + } + else { + int64_t q = ins->imm64(); + if (isS32(q)) { + asm_li(r, int32_t(q)); + return; + } + RLDIMI(r,R0,32,0); // or 32,32? + asm_li(R0, int32_t(q>>32)); // hi bits into R0 + asm_li(r, int32_t(q)); // lo bits into dest reg + } + } +#endif + + void Assembler::asm_immf(LIns *ins) { #ifdef NANOJIT_64BIT Register r = ins->deprecated_getReg(); if (deprecated_isKnownReg(r) && (rmask(r) & FpRegs)) { diff --git a/js/src/nanojit/NativeSparc.cpp b/js/src/nanojit/NativeSparc.cpp index a32906300317..c2a7b395a0f3 100644 --- a/js/src/nanojit/NativeSparc.cpp +++ b/js/src/nanojit/NativeSparc.cpp @@ -795,7 +795,7 @@ namespace nanojit deprecated_prepResultReg(ins, rmask(argRegs[a])); } - void Assembler::asm_int(LInsp ins) + void Assembler::asm_immi(LInsp ins) { underrunProtect(8); Register rr = deprecated_prepResultReg(ins, GpRegs); @@ -806,7 +806,7 @@ namespace nanojit SET32(val, rr); } - void Assembler::asm_quad(LInsp ins) + void Assembler::asm_immf(LInsp ins) { underrunProtect(64); Register rr = ins->deprecated_getReg(); diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index e23993f77b01..874dc76af837 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -906,7 +906,7 @@ namespace nanojit } else { // can't reach target from here, load imm64 and do an indirect jump CALLRAX(); - asm_quad(RAX, (uint64_t)target, /*canClobberCCs*/true); + asm_immq(RAX, (uint64_t)target, /*canClobberCCs*/true); } // Call this now so that the arg setup can involve 'rr'. freeResourcesOf(ins); @@ -967,7 +967,7 @@ namespace nanojit if (sz == ARGSIZE_I) { NanoAssert(p->isI32()); if (p->isconst()) { - asm_quad(r, int64_t(p->imm32()), /*canClobberCCs*/true); + asm_immq(r, int64_t(p->imm32()), /*canClobberCCs*/true); return; } // sign extend int32 to int64 @@ -975,7 +975,7 @@ namespace nanojit } else if (sz == ARGSIZE_U) { NanoAssert(p->isI32()); if (p->isconst()) { - asm_quad(r, uint64_t(uint32_t(p->imm32())), /*canClobberCCs*/true); + asm_immq(r, uint64_t(uint32_t(p->imm32())), /*canClobberCCs*/true); return; } // zero extend with 32bit mov, auto-zeros upper 32bits @@ -1377,18 +1377,23 @@ namespace nanojit } else if (ins->isconst()) { ins->clearReg(); - asm_int(r, ins->imm32(), /*canClobberCCs*/false); + asm_immi(r, ins->imm32(), /*canClobberCCs*/false); } - else if (ins->isconstq() && IsGpReg(r)) { + else if (ins->isop(LIR_quad)) { ins->clearReg(); - asm_quad(r, ins->imm64(), /*canClobberCCs*/false); + asm_immq(r, ins->imm64(), /*canClobberCCs*/false); + } + else if (ins->isconstf()) { + ins->clearReg(); + asm_immf(r, ins->imm64(), /*canClobberCCs*/false); } else { int d = findMemFor(ins); - if (IsFpReg(r)) { - NanoAssert(ins->isF64()); + if (ins->isF64()) { + NanoAssert(IsFpReg(r)); MOVSDRM(r, d, FP); - } else if (ins->isN64()) { + } else if (ins->isI64()) { + NanoAssert(IsGpReg(r)); MOVQRM(r, d, FP); } else { NanoAssert(ins->isI32()); @@ -1586,41 +1591,37 @@ namespace nanojit } } - void Assembler::asm_int(LIns *ins) { + void Assembler::asm_immi(LIns *ins) { Register rr = prepareResultReg(ins, GpRegs); - - asm_int(rr, ins->imm32(), /*canClobberCCs*/true); - + asm_immi(rr, ins->imm32(), /*canClobberCCs*/true); freeResourcesOf(ins); } - void Assembler::asm_int(Register r, int32_t v, bool canClobberCCs) { + void Assembler::asm_immq(LIns *ins) { + Register rr = prepareResultReg(ins, GpRegs); + asm_immq(rr, ins->imm64(), /*canClobberCCs*/true); + freeResourcesOf(ins); + } + + void Assembler::asm_immf(LIns *ins) { + Register r = prepareResultReg(ins, FpRegs); + asm_immf(r, ins->imm64(), /*canClobberCCs*/true); + freeResourcesOf(ins); + } + + void Assembler::asm_immi(Register r, int32_t v, bool canClobberCCs) { + NanoAssert(IsGpReg(r)); if (v == 0 && canClobberCCs) { - if (IsGpReg(r)) { - XORRR(r, r); - } else { - XORPS(r); - } + XORRR(r, r); } else { - NanoAssert(!IsFpReg(r)); MOVI(r, v); } } - void Assembler::asm_quad(LIns *ins) { - uint64_t v = ins->imm64(); - RegisterMask allow = v == 0 ? GpRegs|FpRegs : GpRegs; - Register rr = prepareResultReg(ins, allow); - - asm_quad(rr, v, /*canClobberCCs*/true); - - freeResourcesOf(ins); - } - - void Assembler::asm_quad(Register r, uint64_t v, bool canClobberCCs) { - NanoAssert(v == 0 || IsGpReg(r)); + void Assembler::asm_immq(Register r, uint64_t v, bool canClobberCCs) { + NanoAssert(IsGpReg(r)); if (isU32(v)) { - asm_int(r, int32_t(v), canClobberCCs); + asm_immi(r, int32_t(v), canClobberCCs); } else if (isS32(v)) { // safe for sign-extension 32->64 MOVQI32(r, int32_t(v)); @@ -1633,6 +1634,21 @@ namespace nanojit } } + void Assembler::asm_immf(Register r, uint64_t v, bool canClobberCCs) { + NanoAssert(IsFpReg(r)); + if (v == 0 && canClobberCCs) { + XORPS(r); + } else { + // There's no general way to load an immediate into an XMM reg. + // For non-zero floats the best thing is to put the equivalent + // 64-bit integer into a scratch GpReg and then move it into the + // appropriate FpReg. + Register rt = registerAllocTmp(GpRegs); + MOVQXR(r, rt); + asm_immq(rt, v, canClobberCCs); + } + } + void Assembler::asm_param(LIns *ins) { uint32_t a = ins->paramArg(); uint32_t kind = ins->paramKind(); @@ -1735,7 +1751,7 @@ namespace nanojit Register gt = registerAllocTmp(GpRegs); XORPS(rr, rt); MOVQXR(rt, gt); - asm_quad(gt, negateMask[0], /*canClobberCCs*/true); + asm_immq(gt, negateMask[0], /*canClobberCCs*/true); } if (ra != rr) asm_nongp_copy(rr,ra); @@ -1885,7 +1901,7 @@ namespace nanojit MR(RSP, RBP); // return value is GuardRecord* - asm_quad(RAX, uintptr_t(lr), /*canClobberCCs*/true); + asm_immq(RAX, uintptr_t(lr), /*canClobberCCs*/true); } void Assembler::nInit(AvmCore*) { @@ -1962,7 +1978,7 @@ namespace nanojit // at this point. emitr(X64_popr, RAX); // popq %rax emit(X64_inclmRAX); // incl (%rax) - asm_quad(RAX, (uint64_t)pCtr, /*canClobberCCs*/true); // movabsq $pCtr, %rax + asm_immq(RAX, (uint64_t)pCtr, /*canClobberCCs*/true); // movabsq $pCtr, %rax emitr(X64_pushr, RAX); // pushq %rax } ) @@ -1982,7 +1998,7 @@ namespace nanojit // jmp [indexreg*8 + tablereg] JMPXB(indexreg, tablereg); // tablereg <- #table - asm_quad(tablereg, (uint64_t)table, /*canClobberCCs*/true); + asm_immq(tablereg, (uint64_t)table, /*canClobberCCs*/true); } } diff --git a/js/src/nanojit/NativeX64.h b/js/src/nanojit/NativeX64.h index a092fcb196d2..f22ea62792b3 100644 --- a/js/src/nanojit/NativeX64.h +++ b/js/src/nanojit/NativeX64.h @@ -392,8 +392,9 @@ namespace nanojit void emitxm_rel(uint64_t op, Register r, NIns* addr64);\ bool isTargetWithinS8(NIns* target);\ bool isTargetWithinS32(NIns* target);\ - void asm_int(Register r, int32_t v, bool canClobberCCs);\ - void asm_quad(Register r, uint64_t v, bool canClobberCCs);\ + void asm_immi(Register r, int32_t v, bool canClobberCCs);\ + void asm_immq(Register r, uint64_t v, bool canClobberCCs);\ + void asm_immf(Register r, uint64_t v, bool canClobberCCs);\ void asm_regarg(ArgSize, LIns*, Register);\ void asm_stkarg(ArgSize, LIns*, int);\ void asm_shift(LIns*);\ diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index dd4e5c5c1758..b2132c5b6491 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -148,7 +148,7 @@ namespace nanojit MR(SP,FP); // return value is GuardRecord* - asm_int(EAX, int(lr), /*canClobberCCs*/true); + asm_immi(EAX, int(lr), /*canClobberCCs*/true); } NIns *Assembler::genEpilogue() @@ -369,11 +369,11 @@ namespace nanojit LEA(r, arDisp(ins), FP); } else if (ins->isconst()) { - asm_int(r, ins->imm32(), /*canClobberCCs*/false); + asm_immi(r, ins->imm32(), /*canClobberCCs*/false); ins->clearReg(); - } else if (ins->isconstq()) { - asm_quad(r, ins->imm64(), ins->imm64f(), /*canClobberCCs*/false); + } else if (ins->isconstf()) { + asm_immf(r, ins->imm64(), ins->imm64f(), /*canClobberCCs*/false); ins->clearReg(); } else if (ins->isop(LIR_param) && ins->paramKind() == 0 && @@ -1251,16 +1251,16 @@ namespace nanojit freeResourcesOf(ins); } - void Assembler::asm_int(LInsp ins) + void Assembler::asm_immi(LInsp ins) { Register rr = prepareResultReg(ins, GpRegs); - asm_int(rr, ins->imm32(), /*canClobberCCs*/true); + asm_immi(rr, ins->imm32(), /*canClobberCCs*/true); freeResourcesOf(ins); } - void Assembler::asm_int(Register r, int32_t val, bool canClobberCCs) + void Assembler::asm_immi(Register r, int32_t val, bool canClobberCCs) { if (val == 0 && canClobberCCs) XOR(r, r); @@ -1268,15 +1268,15 @@ namespace nanojit LDi(r, val); } - void Assembler::asm_quad(Register r, uint64_t q, double d, bool canClobberCCs) + void Assembler::asm_immf(Register r, uint64_t q, double d, bool canClobberCCs) { - // Quads require non-standard handling. There is no load-64-bit-immediate + // Floats require non-standard handling. There is no load-64-bit-immediate // instruction on i386, so in the general case, we must load it from memory. // This is unlike most other LIR operations which can be computed directly // in a register. We can special-case 0.0 and various other small ints // (1.0 on x87, any int32_t value on SSE2), but for all other values, we // allocate an 8-byte chunk via dataAlloc and load from there. Note that - // this implies that quads never require spill area, since they will always + // this implies that floats never require spill area, since they will always // be rematerialized from const data (or inline instructions in the special cases). if (rmask(r) & XmmRegs) { @@ -1288,7 +1288,7 @@ namespace nanojit Register tr = registerAllocTmp(GpRegs); SSE_CVTSI2SD(r, tr); SSE_XORPDr(r, r); // zero r to ensure no dependency stalls - asm_int(tr, (int)d, canClobberCCs); + asm_immi(tr, (int)d, canClobberCCs); } else { const uint64_t* p = findQuadConstant(q); LDSDm(r, (const double*)p); @@ -1307,13 +1307,13 @@ namespace nanojit } } - void Assembler::asm_quad(LInsp ins) + void Assembler::asm_immf(LInsp ins) { NanoAssert(ins->isconstf()); if (ins->isInReg()) { Register rr = ins->getReg(); NanoAssert(rmask(rr) & FpRegs); - asm_quad(rr, ins->imm64(), ins->imm64f(), /*canClobberCCs*/true); + asm_immf(rr, ins->imm64(), ins->imm64f(), /*canClobberCCs*/true); } else { // Do nothing, will be rematerialized when necessary. } @@ -1393,7 +1393,7 @@ namespace nanojit if (r != UnspecifiedReg) { if (ins->isconst()) { // Rematerialize the constant. - asm_int(r, ins->imm32(), /*canClobberCCs*/true); + asm_immi(r, ins->imm32(), /*canClobberCCs*/true); } else if (ins->isInReg()) { if (r != ins->getReg()) MR(r, ins->getReg()); diff --git a/js/src/nanojit/Nativei386.h b/js/src/nanojit/Nativei386.h index c87277aeb277..580c959e43bf 100644 --- a/js/src/nanojit/Nativei386.h +++ b/js/src/nanojit/Nativei386.h @@ -181,7 +181,7 @@ namespace nanojit void nativePageReset();\ void nativePageSetup();\ void underrunProtect(int);\ - void asm_int(Register r, int32_t val, bool canClobberCCs);\ + void asm_immi(Register r, int32_t val, bool canClobberCCs);\ void asm_stkarg(LInsp p, int32_t& stkd);\ void asm_farg(LInsp, int32_t& stkd);\ void asm_arg(ArgSize sz, LInsp p, Register r, int32_t& stkd);\ @@ -191,7 +191,7 @@ namespace nanojit void asm_cmp(LIns *cond); \ void asm_div_mod(LIns *cond); \ void asm_load(int d, Register r); \ - void asm_quad(Register r, uint64_t q, double d, bool canClobberCCs); + void asm_immf(Register r, uint64_t q, double d, bool canClobberCCs); #define IMM8(i) \ _nIns -= 1; \ From 07f83b1d8b1acefb9708cdd300bd5e56eda4ac20 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 10:42:30 +1100 Subject: [PATCH 071/213] Bug 531687 - Duplicate node names in TMFLAGS=aftersf printout. r=edwsmith. --HG-- extra : convert_revision : c844bd17e4a5e66b7913bb534e298088bee3e528 --- js/src/lirasm/lirasm.cpp | 44 ++--- js/src/nanojit/Assembler.cpp | 54 +++--- js/src/nanojit/Assembler.h | 2 +- js/src/nanojit/LIR.cpp | 346 +++++++++++++++++++---------------- js/src/nanojit/LIR.h | 107 +++++++---- js/src/nanojit/VMPI.h | 1 + 6 files changed, 314 insertions(+), 240 deletions(-) diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index 95a724bf25da..3422027b883e 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -97,34 +97,32 @@ nanojit::StackFilter::getTop(LIns*) #if defined NJ_VERBOSE void -nanojit::LirNameMap::formatGuard(LIns *i, char *out) +nanojit::LInsPrinter::formatGuard(InsBuf *buf, LIns *ins) { - LasmSideExit *x; - - x = (LasmSideExit *)i->record()->exit; - sprintf(out, + RefBuf b1, b2; + LasmSideExit *x = (LasmSideExit *)ins->record()->exit; + snprintf(buf->buf, buf->len, "%s: %s %s -> line=%ld (GuardID=%03d)", - formatRef(i), - lirNames[i->opcode()], - i->oprnd1() ? formatRef(i->oprnd1()) : "", + formatRef(&b1, ins), + lirNames[ins->opcode()], + ins->oprnd1() ? formatRef(&b2, ins->oprnd1()) : "", (long)x->line, - i->record()->profGuardID); + ins->record()->profGuardID); } void -nanojit::LirNameMap::formatGuardXov(LIns *i, char *out) +nanojit::LInsPrinter::formatGuardXov(InsBuf *buf, LIns *ins) { - LasmSideExit *x; - - x = (LasmSideExit *)i->record()->exit; - sprintf(out, + RefBuf b1, b2, b3; + LasmSideExit *x = (LasmSideExit *)ins->record()->exit; + snprintf(buf->buf, buf->len, "%s = %s %s, %s -> line=%ld (GuardID=%03d)", - formatRef(i), - lirNames[i->opcode()], - formatRef(i->oprnd1()), - formatRef(i->oprnd2()), + formatRef(&b1, ins), + lirNames[ins->opcode()], + formatRef(&b2, ins->oprnd1()), + formatRef(&b3, ins->oprnd2()), (long)x->line, - i->record()->profGuardID); + ins->record()->profGuardID); } #endif @@ -269,7 +267,6 @@ public: bool lookupFunction(const string &name, CallInfo *&ci); LirBuffer *mLirbuf; - verbose_only( LabelMap *mLabelMap; ) LogControl mLogc; avmplus::AvmCore mCore; Allocator mAlloc; @@ -524,7 +521,7 @@ FragmentAssembler::FragmentAssembler(Lirasm &parent, const string &fragmentName, #ifdef DEBUG if (mParent.mVerbose) { mLir = mVerboseWriter = new VerboseWriter(mParent.mAlloc, mLir, - mParent.mLirbuf->names, + mParent.mLirbuf->printer, &mParent.mLogc); } #endif @@ -805,7 +802,7 @@ FragmentAssembler::endFragment() mLir->insGuard(LIR_x, NULL, createGuardRecord(createSideExit())); mParent.mAssm.compile(mFragment, mParent.mAlloc, optimize - verbose_only(, mParent.mLabelMap)); + verbose_only(, mParent.mLirbuf->printer)); if (mParent.mAssm.error() != nanojit::None) { cerr << "error during assembly: "; @@ -1968,8 +1965,7 @@ Lirasm::Lirasm(bool verbose) : #ifdef DEBUG if (mVerbose) { mLogc.lcbits = LC_ReadLIR | LC_Assembly | LC_RegAlloc | LC_Activation; - mLabelMap = new (mAlloc) LabelMap(mAlloc, &mLogc); - mLirbuf->names = new (mAlloc) LirNameMap(mAlloc, mLabelMap); + mLirbuf->printer = new (mAlloc) LInsPrinter(mAlloc); } #endif diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index ac1e1f12e32e..90ad49278da6 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -647,9 +647,10 @@ namespace nanojit { int d = ins->isInAr() ? arDisp(ins) : 0; Register r = ins->getReg(); - verbose_only( if (d && (_logc->lcbits & LC_Assembly)) { + verbose_only( RefBuf b; + if (d && (_logc->lcbits & LC_Assembly)) { setOutputForEOL(" <= spill %s", - _thisfrag->lirbuf->names->formatRef(ins)); } ) + _thisfrag->lirbuf->printer->formatRef(&b, ins)); } ) asm_spill(r, d, pop, ins->isN64()); } @@ -710,9 +711,10 @@ namespace nanojit NanoAssert(!_allocator.isFree(r)); NanoAssert(vic == _allocator.getActive(r)); - verbose_only( if (_logc->lcbits & LC_Assembly) { + verbose_only( RefBuf b; + if (_logc->lcbits & LC_Assembly) { setOutputForEOL(" <= restore %s", - _thisfrag->lirbuf->names->formatRef(vic)); } ) + _thisfrag->lirbuf->printer->formatRef(&b, vic)); } ) asm_restore(vic, r); _allocator.retire(r); @@ -825,7 +827,7 @@ namespace nanojit return jmpTarget; } - void Assembler::compile(Fragment* frag, Allocator& alloc, bool optimize verbose_only(, LabelMap* labels)) + void Assembler::compile(Fragment* frag, Allocator& alloc, bool optimize verbose_only(, LInsPrinter* printer)) { verbose_only( bool anyVerb = (_logc->lcbits & 0xFFFF & ~LC_FragProfile) > 0; @@ -872,9 +874,9 @@ namespace nanojit }) // now the the main trunk + verbose_only( RefBuf b; ) verbose_only( if (anyVerb) { - _logc->printf("=== -- Compile trunk %s: begin\n", - labels->format(frag)); + _logc->printf("=== -- Compile trunk %s: begin\n", printer->formatAddr(&b, frag)); }) // Used for debug printing, if needed @@ -898,7 +900,7 @@ namespace nanojit // INITIAL PRINTING verbose_only( if (_logc->lcbits & LC_ReadLIR) { - pp_init = new (alloc) ReverseLister(lir, alloc, frag->lirbuf->names, _logc, + pp_init = new (alloc) ReverseLister(lir, alloc, frag->lirbuf->printer, _logc, "Initial LIR"); lir = pp_init; }) @@ -910,7 +912,7 @@ namespace nanojit } verbose_only( if (_logc->lcbits & LC_AfterSF) { - pp_after_sf = new (alloc) ReverseLister(lir, alloc, frag->lirbuf->names, _logc, + pp_after_sf = new (alloc) ReverseLister(lir, alloc, frag->lirbuf->printer, _logc, "After StackFilter"); lir = pp_after_sf; }) @@ -925,13 +927,12 @@ namespace nanojit ) verbose_only( if (anyVerb) { - _logc->printf("=== -- Compile trunk %s: end\n", - labels->format(frag)); + _logc->printf("=== -- Compile trunk %s: end\n", printer->formatAddr(&b, frag)); }) verbose_only( if (asmVerb) - outputf("## compiling trunk %s", labels->format(frag)); + outputf("## compiling trunk %s", printer->formatAddr(&b, frag)); ) endAssembly(frag); @@ -1604,7 +1605,8 @@ namespace nanojit LabelState *lstate = _labels.get(to); if (lstate) { unionRegisterState(lstate->regs); - asm_output(" %u: [&%s]", i, _thisfrag->lirbuf->names->formatRef(to)); + verbose_only( RefBuf b; ) + asm_output(" %u: [&%s]", i, _thisfrag->lirbuf->printer->formatRef(&b, to)); } else { has_back_edges = true; } @@ -1627,7 +1629,8 @@ namespace nanojit LabelState *lstate = _labels.get(to); if (!lstate) { _labels.add(to, 0, _allocator); - asm_output(" %u: [&%s]", i, _thisfrag->lirbuf->names->formatRef(to)); + verbose_only( RefBuf b; ) + asm_output(" %u: [&%s]", i, _thisfrag->lirbuf->printer->formatRef(&b, to)); } } asm_output("backward edges"); @@ -1662,8 +1665,10 @@ namespace nanojit intersectRegisterState(label->regs); label->addr = _nIns; } - verbose_only( if (_logc->lcbits & LC_Assembly) { - asm_output("[%s]", _thisfrag->lirbuf->names->formatRef(ins)); + verbose_only( + RefBuf b; + if (_logc->lcbits & LC_Assembly) { + asm_output("[%s]", _thisfrag->lirbuf->printer->formatRef(&b, ins)); }) break; } @@ -1798,8 +1803,9 @@ namespace nanojit // field in another machine instruction). // if (_logc->lcbits & LC_Assembly) { - LirNameMap* names = _thisfrag->lirbuf->names; - outputf(" %s", names->formatIns(ins)); + InsBuf b; + LInsPrinter* printer = _thisfrag->lirbuf->printer; + outputf(" %s", printer->formatIns(&b, ins)); if (ins->isGuard() && ins->oprnd1() && ins->oprnd1()->isCmp()) { // Special case: code is generated for guard conditions at // the same time that code is generated for the guard @@ -1809,19 +1815,19 @@ namespace nanojit // the condition *is* used again we'll end up printing it // twice, but that's ok. outputf(" %s # codegen'd with the %s", - names->formatIns(ins->oprnd1()), lirNames[op]); + printer->formatIns(&b, ins->oprnd1()), lirNames[op]); } else if (ins->isCmov()) { // Likewise for cmov conditions. outputf(" %s # codegen'd with the %s", - names->formatIns(ins->oprnd1()), lirNames[op]); + printer->formatIns(&b, ins->oprnd1()), lirNames[op]); } #if defined NANOJIT_IA32 || defined NANOJIT_X64 else if (ins->isop(LIR_mod)) { // There's a similar case when a div feeds into a mod. outputf(" %s # codegen'd with the mod", - names->formatIns(ins->oprnd1())); + printer->formatIns(&b, ins->oprnd1())); } #endif } @@ -1940,7 +1946,8 @@ namespace nanojit if (ins) { NanoAssertMsg(!_allocator.isFree(r), "Coding error; register is both free and active! " ); - const char* n = _thisfrag->lirbuf->names->formatRef(ins); + RefBuf b; + const char* n = _thisfrag->lirbuf->printer->formatRef(&b, ins); if (ins->isop(LIR_param) && ins->paramKind()==1 && r == Assembler::savedRegs[ins->paramArg()]) @@ -1969,7 +1976,8 @@ namespace nanojit int32_t arIndex = 0; for (AR::Iter iter(_activation); iter.next(ins, nStackSlots, arIndex); ) { - const char* n = _thisfrag->lirbuf->names->formatRef(ins); + RefBuf b; + const char* n = _thisfrag->lirbuf->printer->formatRef(&b, ins); if (nStackSlots > 1) { VMPI_sprintf(s," %d-%d(%s)", 4*arIndex, 4*(arIndex+nStackSlots-1), n); } diff --git a/js/src/nanojit/Assembler.h b/js/src/nanojit/Assembler.h index 17a07fdf5603..5a67184a11c3 100644 --- a/js/src/nanojit/Assembler.h +++ b/js/src/nanojit/Assembler.h @@ -297,7 +297,7 @@ namespace nanojit Assembler(CodeAlloc& codeAlloc, Allocator& dataAlloc, Allocator& alloc, AvmCore* core, LogControl* logc, const Config& config); void compile(Fragment *frag, Allocator& alloc, bool optimize - verbose_only(, LabelMap*)); + verbose_only(, LInsPrinter*)); void endAssembly(Fragment* frag); void assemble(Fragment* frag, LirFilter* reader); diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 5b9e1bf287bf..217f22ff0a6d 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -97,7 +97,8 @@ namespace nanojit LInsp ReverseLister::read() { LInsp i = in->read(); - const char* str = _names->formatIns(i); + InsBuf b; + const char* str = _printer->formatIns(&b, i); char* cpy = new (_alloc) char[strlen(str)+1]; VMPI_strcpy(cpy, str); _strs.insert(cpy); @@ -114,7 +115,7 @@ namespace nanojit // LCompressedBuffer LirBuffer::LirBuffer(Allocator& alloc) : #ifdef NJ_VERBOSE - names(NULL), + printer(NULL), #endif abi(ABI_FASTCALL), state(NULL), param1(NULL), sp(NULL), rp(NULL), _allocator(alloc) @@ -1652,10 +1653,12 @@ namespace nanojit logc->printf("\n"); // print live exprs, going forwards - LirNameMap *names = frag->lirbuf->names; + LInsPrinter *printer = frag->lirbuf->printer; bool newblock = true; for (Seq* p = live.retired.get(); p != NULL; p = p->tail) { RetiredEntry* e = p->head; + InsBuf ib; + RefBuf rb; char livebuf[4000], *s=livebuf; *s = 0; if (!newblock && e->i->isop(LIR_label)) { @@ -1663,7 +1666,7 @@ namespace nanojit } newblock = false; for (Seq* p = e->live; p != NULL; p = p->tail) { - VMPI_strcpy(s, names->formatRef(p->head)); + VMPI_strcpy(s, printer->formatRef(&rb, p->head)); s += VMPI_strlen(s); *s++ = ' '; *s = 0; NanoAssert(s < livebuf+sizeof(livebuf)); @@ -1671,11 +1674,11 @@ namespace nanojit /* If the LIR insn is pretty short, print it and its live-after set on the same line. If not, put live-after set on a new line, suitably indented. */ - const char* insn_text = names->formatIns(e->i); + const char* insn_text = printer->formatIns(&ib, e->i); if (VMPI_strlen(insn_text) >= 30-2) { - logc->printf(" %-30s\n %-30s %s\n", names->formatIns(e->i), "", livebuf); + logc->printf(" %-30s\n %-30s %s\n", insn_text, "", livebuf); } else { - logc->printf(" %-30s %s\n", names->formatIns(e->i), livebuf); + logc->printf(" %-30s %s\n", insn_text, livebuf); } if (e->i->isGuard() || e->i->isBranch() || e->i->isRet()) { @@ -1685,16 +1688,71 @@ namespace nanojit } } - void LirNameMap::addName(LInsp i, const char* name) { - if (!names.containsKey(i)) { - char *copy = new (alloc) char[VMPI_strlen(name)+1]; - VMPI_strcpy(copy, name); + + void LirNameMap::addNameWithSuffix(LInsp ins, const char *name, int suffix, + bool ignoreOneSuffix) { + // The lookup may succeed, ie. we may already have a name for this + // instruction. This can happen because of CSE. Eg. if we have this: + // + // ins = addName("foo", insImm(0)) + // + // that assigns the name "foo1" to 'ins'. If we later do this: + // + // ins2 = addName("foo", insImm(0)) + // + // then CSE will cause 'ins' and 'ins2' to be equal. So 'ins2' + // already has a name ("foo1") and there's no need to generate a new + // name "foo2". + // + if (!names.containsKey(ins)) { + const int N = 100; + char name2[N]; + if (suffix == 1 && ignoreOneSuffix) { + VMPI_snprintf(name2, N, "%s", name); // don't add '1' suffix + } else if (VMPI_isdigit(name[VMPI_strlen(name)-1])) { + VMPI_snprintf(name2, N, "%s_%d", name, suffix); // use '_' to avoid confusion + } else { + VMPI_snprintf(name2, N, "%s%d", name, suffix); // normal case + } + + char *copy = new (alloc) char[VMPI_strlen(name2)+1]; + VMPI_strcpy(copy, name2); Entry *e = new (alloc) Entry(copy); - names.put(i, e); + names.put(ins, e); } } - char* LirNameMap::formatAccSet(LInsp ins, bool isLoad, char* buf) { + void LirNameMap::addName(LInsp ins, const char* name) { + addNameWithSuffix(ins, name, namecounts.add(name), /*ignoreOneSuffix*/true); + } + + const char* LirNameMap::createName(LInsp ins) { + if (ins->isCall()) { +#if NJ_SOFTFLOAT_SUPPORTED + if (ins->isop(LIR_callh)) { + ins = ins->oprnd1(); // we've presumably seen the other half already + } else +#endif + { + addNameWithSuffix(ins, ins->callInfo()->_name, funccounts.add(ins->callInfo()), + /*ignoreOneSuffix*/false); + } + } else { + addNameWithSuffix(ins, lirNames[ins->opcode()], lircounts.add(ins->opcode()), + /*ignoreOneSuffix*/false); + + } + return names.get(ins)->name; + } + + const char* LirNameMap::lookupName(LInsp ins) + { + Entry* e = names.get(ins); + return e ? e->name : NULL; + } + + + char* LInsPrinter::formatAccSet(RefBuf* buf, LInsp ins, bool isLoad) { AccSet accSet = ins->accSet(); int i = 0; if ((isLoad && accSet == ACC_LOAD_ANY) || @@ -1702,120 +1760,116 @@ namespace nanojit { // boring, don't bother with a suffix } else { - buf[i++] = '.'; - if (accSet & ACC_READONLY) { buf[i++] = 'r'; accSet &= ~ACC_READONLY; } - if (accSet & ACC_STACK) { buf[i++] = 's'; accSet &= ~ACC_STACK; } - if (accSet & ACC_OTHER) { buf[i++] = 'o'; accSet &= ~ACC_OTHER; } + buf->buf[i++] = '.'; + if (accSet & ACC_READONLY) { buf->buf[i++] = 'r'; accSet &= ~ACC_READONLY; } + if (accSet & ACC_STACK) { buf->buf[i++] = 's'; accSet &= ~ACC_STACK; } + if (accSet & ACC_OTHER) { buf->buf[i++] = 'o'; accSet &= ~ACC_OTHER; } // This assertion will fail if we add a new accSet value but // forget to handle it here. NanoAssert(accSet == 0); } - buf[i] = 0; - return buf; + buf->buf[i] = 0; + return buf->buf; } - void LirNameMap::copyName(LInsp i, const char *s, int suffix) { - char s2[200]; - if (VMPI_isdigit(s[VMPI_strlen(s)-1])) { - // if s ends with a digit, add '_' to clarify the suffix - VMPI_sprintf(s2,"%s_%d", s, suffix); - } else { - VMPI_sprintf(s2,"%s%d", s, suffix); - } - addName(i, s2); - } - - void LirNameMap::formatImm(int32_t c, char *buf) { + void LInsPrinter::formatImm(RefBuf* buf, int32_t c) { if (-10000 < c || c < 10000) { - VMPI_sprintf(buf,"%d", c); + VMPI_snprintf(buf->buf, buf->len, "%d", c); } else { #if !defined NANOJIT_64BIT - VMPI_sprintf(buf, "%s", labels->format((void*)c)); + formatAddr(buf, (void*)c); #else - VMPI_sprintf(buf, "0x%x", (unsigned int)c); + VMPI_snprintf(buf->buf, buf->len, "0x%x", (unsigned int)c); #endif } } - void LirNameMap::formatImmq(uint64_t c, char *buf) { + void LInsPrinter::formatImmq(RefBuf* buf, uint64_t c) { if (-10000 < (int64_t)c || c < 10000) { - VMPI_sprintf(buf, "%dLL", (int)c); + VMPI_snprintf(buf->buf, buf->len, "%dLL", (int)c); } else { #if defined NANOJIT_64BIT - VMPI_sprintf(buf, "%s", labels->format((void*)c)); + formatAddr(buf, (void*)c); #else - VMPI_sprintf(buf, "0x%llxLL", c); + VMPI_snprintf(buf->buf, buf->len, "0x%llxLL", c); #endif } } - const char* LirNameMap::formatRef(LIns *ref) + char* LInsPrinter::formatAddr(RefBuf* buf, void* p) { - char buffer[200], *buf=buffer; - buf[0]=0; - if (names.containsKey(ref)) { - const char* name = names.get(ref)->name; - VMPI_strcat(buf, name); + char* name; + int32_t offset; + addrNameMap->lookupAddr(p, name, offset); + + if (name) { + if (offset != 0) { + VMPI_snprintf(buf->buf, buf->len, "%p %s+%d", p, name, offset); + } else { + VMPI_snprintf(buf->buf, buf->len, "%p %s", p, name); + } + } else { + VMPI_snprintf(buf->buf, buf->len, "%p", p); + } + + return buf->buf; + } + + char* LInsPrinter::formatRef(RefBuf* buf, LIns *ref) + { + // - If 'ref' already has a name, use it. + // - Otherwise, if it's a constant, use the constant. + // - Otherwise, give it a name and use it. + const char* name = lirNameMap->lookupName(ref); + if (name) { + VMPI_snprintf(buf->buf, buf->len, "%s", name); } else if (ref->isconstf()) { - VMPI_sprintf(buf, "%g", ref->imm64f()); + VMPI_snprintf(buf->buf, buf->len, "%g", ref->imm64f()); } else if (ref->isconstq()) { - formatImmq(ref->imm64(), buf); + formatImmq(buf, ref->imm64()); } else if (ref->isconst()) { - formatImm(ref->imm32(), buf); + formatImm(buf, ref->imm32()); } else { - if (ref->isCall()) { -#if NJ_SOFTFLOAT_SUPPORTED - if (ref->isop(LIR_callh)) { - // we've presumably seen the other half already - ref = ref->oprnd1(); - } else -#endif - { - copyName(ref, ref->callInfo()->_name, funccounts.add(ref->callInfo())); - } - } else { - NanoAssert(size_t(ref->opcode()) < sizeof(lirNames) / sizeof(lirNames[0])); - copyName(ref, lirNames[ref->opcode()], lircounts.add(ref->opcode())); - } - const char* name = names.get(ref)->name; - VMPI_strcat(buf, name); + name = lirNameMap->createName(ref); + VMPI_snprintf(buf->buf, buf->len, "%s", name); } - return labels->dup(buffer); + return buf->buf; } - const char* LirNameMap::formatIns(LIns* i) + char* LInsPrinter::formatIns(InsBuf* buf, LIns* i) { - char sbuf[4096]; - char *s = sbuf; + char *s = buf->buf; + size_t n = buf->len; + RefBuf b1, b2, b3, b4; LOpcode op = i->opcode(); switch (op) { case LIR_int: - VMPI_sprintf(s, "%s = %s %d", formatRef(i), lirNames[op], i->imm32()); + VMPI_snprintf(s, n, "%s = %s %d", formatRef(&b1, i), lirNames[op], i->imm32()); break; case LIR_alloc: - VMPI_sprintf(s, "%s = %s %d", formatRef(i), lirNames[op], i->size()); + VMPI_snprintf(s, n, "%s = %s %d", formatRef(&b1, i), lirNames[op], i->size()); break; #ifdef NANOJIT_64BIT case LIR_quad: - VMPI_sprintf(s, "%s = %s %X:%X", formatRef(i), lirNames[op], + VMPI_snprintf(s, n, "%s = %s %X:%X", formatRef(&b1, i), lirNames[op], i->imm64_1(), i->imm64_0()); break; #endif case LIR_float: - VMPI_sprintf(s, "%s = %s %g", formatRef(i), lirNames[op], i->imm64f()); + VMPI_snprintf(s, n, "%s = %s %g", formatRef(&b1, i), lirNames[op], i->imm64f()); break; case LIR_start: case LIR_regfence: - VMPI_sprintf(s, "%s", lirNames[op]); + VMPI_snprintf(s, n, "%s", lirNames[op]); break; case LIR_icall: @@ -1823,64 +1877,68 @@ namespace nanojit CASE64(LIR_qcall:) { const CallInfo* call = i->callInfo(); int32_t argc = i->argc(); + ssize_t m = n; if (call->isIndirect()) - VMPI_sprintf(s, "%s = %s [%s] ( ", formatRef(i), lirNames[op], formatRef(i->arg(--argc))); + m -= VMPI_snprintf(s, m, "%s = %s [%s] ( ", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->arg(--argc))); else - VMPI_sprintf(s, "%s = %s #%s ( ", formatRef(i), lirNames[op], call->_name); + m -= VMPI_snprintf(s, m, "%s = %s #%s ( ", formatRef(&b1, i), lirNames[op], + call->_name); + if (m < 0) break; for (int32_t j = argc - 1; j >= 0; j--) { s += VMPI_strlen(s); - VMPI_sprintf(s, "%s ",formatRef(i->arg(j))); + m -= VMPI_snprintf(s, m, "%s ",formatRef(&b2, i->arg(j))); + if (m < 0) break; } s += VMPI_strlen(s); - VMPI_sprintf(s, ")"); + m -= VMPI_snprintf(s, m, ")"); break; } - case LIR_jtbl: - VMPI_sprintf(s, "%s %s [ ", lirNames[op], formatRef(i->oprnd1())); - for (uint32_t j = 0, n = i->getTableSize(); j < n; j++) { - if (VMPI_strlen(sbuf) + 50 > sizeof(sbuf)) { - s += VMPI_strlen(s); - VMPI_sprintf(s, "... "); - break; - } + case LIR_jtbl: { + ssize_t m = n; + m -= VMPI_snprintf(s, m, "%s %s [ ", lirNames[op], formatRef(&b1, i->oprnd1())); + if (m < 0) break; + for (uint32_t j = 0, sz = i->getTableSize(); j < sz; j++) { LIns* target = i->getTarget(j); s += VMPI_strlen(s); - VMPI_sprintf(s, "%s ", target ? formatRef(target) : "unpatched"); + m -= VMPI_snprintf(s, m, "%s ", target ? formatRef(&b2, target) : "unpatched"); + if (m < 0) break; } s += VMPI_strlen(s); - VMPI_sprintf(s, "]"); + m -= VMPI_snprintf(s, m, "]"); break; + } case LIR_param: { uint32_t arg = i->paramArg(); if (!i->paramKind()) { if (arg < sizeof(Assembler::argRegs)/sizeof(Assembler::argRegs[0])) { - VMPI_sprintf(s, "%s = %s %d %s", formatRef(i), lirNames[op], + VMPI_snprintf(s, n, "%s = %s %d %s", formatRef(&b1, i), lirNames[op], arg, gpn(Assembler::argRegs[arg])); } else { - VMPI_sprintf(s, "%s = %s %d", formatRef(i), lirNames[op], arg); + VMPI_snprintf(s, n, "%s = %s %d", formatRef(&b1, i), lirNames[op], arg); } } else { - VMPI_sprintf(s, "%s = %s %d %s", formatRef(i), lirNames[op], + VMPI_snprintf(s, n, "%s = %s %d %s", formatRef(&b1, i), lirNames[op], arg, gpn(Assembler::savedRegs[arg])); } break; } case LIR_label: - VMPI_sprintf(s, "%s:", formatRef(i)); + VMPI_snprintf(s, n, "%s:", formatRef(&b1, i)); break; case LIR_jt: case LIR_jf: - VMPI_sprintf(s, "%s %s -> %s", lirNames[op], formatRef(i->oprnd1()), - i->oprnd2() ? formatRef(i->oprnd2()) : "unpatched"); + VMPI_snprintf(s, n, "%s %s -> %s", lirNames[op], formatRef(&b1, i->oprnd1()), + i->oprnd2() ? formatRef(&b2, i->oprnd2()) : "unpatched"); break; case LIR_j: - VMPI_sprintf(s, "%s -> %s", lirNames[op], - i->oprnd2() ? formatRef(i->oprnd2()) : "unpatched"); + VMPI_snprintf(s, n, "%s -> %s", lirNames[op], + i->oprnd2() ? formatRef(&b1, i->oprnd2()) : "unpatched"); break; case LIR_live: @@ -1889,7 +1947,7 @@ namespace nanojit case LIR_ret: CASE64(LIR_qret:) case LIR_fret: - VMPI_sprintf(s, "%s %s", lirNames[op], formatRef(i->oprnd1())); + VMPI_snprintf(s, n, "%s %s", lirNames[op], formatRef(&b1, i->oprnd1())); break; CASESF(LIR_callh:) @@ -1905,7 +1963,8 @@ namespace nanojit CASE64(LIR_u2q:) CASE64(LIR_q2i:) case LIR_f2i: - VMPI_sprintf(s, "%s = %s %s", formatRef(i), lirNames[op], formatRef(i->oprnd1())); + VMPI_snprintf(s, n, "%s = %s %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1())); break; case LIR_x: @@ -1913,13 +1972,13 @@ namespace nanojit case LIR_xf: case LIR_xbarrier: case LIR_xtbl: - formatGuard(i, s); + formatGuard(buf, i); break; case LIR_addxov: case LIR_subxov: case LIR_mulxov: - formatGuardXov(i, s); + formatGuardXov(buf, i); break; case LIR_add: CASE64(LIR_qiadd:) @@ -1951,25 +2010,20 @@ namespace nanojit case LIR_fle: case LIR_fgt: case LIR_fge: - VMPI_sprintf(s, "%s = %s %s, %s", formatRef(i), lirNames[op], - formatRef(i->oprnd1()), - formatRef(i->oprnd2())); - break; - #if NJ_SOFTFLOAT_SUPPORTED case LIR_qjoin: - VMPI_sprintf(s, "%s (%s), %s", lirNames[op], - formatRef(i->oprnd1()), - formatRef(i->oprnd2())); - break; #endif + VMPI_snprintf(s, n, "%s = %s %s, %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1()), + formatRef(&b3, i->oprnd2())); + break; CASE64(LIR_qcmov:) case LIR_cmov: - VMPI_sprintf(s, "%s = %s %s ? %s : %s", formatRef(i), lirNames[op], - formatRef(i->oprnd1()), - formatRef(i->oprnd2()), - formatRef(i->oprnd3())); + VMPI_snprintf(s, n, "%s = %s %s ? %s : %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1()), + formatRef(&b3, i->oprnd2()), + formatRef(&b4, i->oprnd3())); break; case LIR_ld: @@ -1979,36 +2033,31 @@ namespace nanojit case LIR_ldzs: case LIR_ldsb: case LIR_ldss: - case LIR_ld32f: { - char b[32]; - VMPI_sprintf(s, "%s = %s%s %s[%d]", formatRef(i), lirNames[op], - formatAccSet(i, /*isLoad*/true, b), - formatRef(i->oprnd1()), + case LIR_ld32f: + VMPI_snprintf(s, n, "%s = %s%s %s[%d]", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, i, /*isLoad*/true), + formatRef(&b3, i->oprnd1()), i->disp()); break; - } case LIR_sti: CASE64(LIR_stqi:) case LIR_stfi: case LIR_stb: case LIR_sts: - case LIR_st32f: { - char b[32]; - VMPI_sprintf(s, "%s%s %s[%d] = %s", lirNames[op], - formatAccSet(i, /*isLoad*/false, b), - formatRef(i->oprnd2()), + case LIR_st32f: + VMPI_snprintf(s, n, "%s%s %s[%d] = %s", lirNames[op], + formatAccSet(&b1, i, /*isLoad*/false), + formatRef(&b2, i->oprnd2()), i->disp(), - formatRef(i->oprnd1())); + formatRef(&b3, i->oprnd1())); break; - } default: NanoAssertMsgf(0, "Can't handle opcode %s\n", lirNames[op]); break; } - NanoAssert(VMPI_strlen(sbuf) < sizeof(sbuf)-1); - return labels->dup(sbuf); + return buf->buf; } #endif @@ -2387,11 +2436,11 @@ namespace nanojit #endif /* FEATURE_NANOJIT */ #if defined(NJ_VERBOSE) - LabelMap::LabelMap(Allocator& a, LogControl *logc) - : allocator(a), names(a), logc(logc), end(buf) + AddrNameMap::AddrNameMap(Allocator& a) + : allocator(a), names(a) {} - void LabelMap::add(const void *p, size_t size, size_t align, const char *name) + void AddrNameMap::addAddrRange(const void *p, size_t size, size_t align, const char *name) { if (!this || names.containsKey(p)) return; @@ -2401,45 +2450,28 @@ namespace nanojit names.put(p, e); } - const char *LabelMap::format(const void *p) + void AddrNameMap::lookupAddr(void *p, char*& name, int32_t& offset) { - char b[200]; - const void *start = names.findNear(p); - if (start != NULL) { + if (start) { Entry *e = names.get(start); const void *end = (const char*)start + e->size; - const char *name = e->name; if (p == start) { - VMPI_sprintf(b, "%p %s", p, name); - return dup(b); + name = e->name; + offset = 0; } else if (p > start && p < end) { - int32_t d = int32_t(intptr_t(p)-intptr_t(start)) >> e->align; - VMPI_sprintf(b, "%p %s+%d", p, name, d); - return dup(b); + name = e->name; + offset = int32_t(intptr_t(p)-intptr_t(start)) >> e->align; } else { - VMPI_sprintf(b, "%p", p); - return dup(b); + name = NULL; + offset = 0; } + } else { + name = NULL; + offset = 0; } - VMPI_sprintf(b, "%p", p); - return dup(b); - } - - const char *LabelMap::dup(const char *b) - { - size_t need = VMPI_strlen(b)+1; - NanoAssert(need <= sizeof(buf)); - char *s = end; - end += need; - if (end > buf+sizeof(buf)) { - s = buf; - end = s+need; - } - VMPI_strcpy(s, b); - return s; } // --------------------------------------------------------------- diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index a41352cea049..6be7f26f7f44 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -1514,33 +1514,29 @@ namespace nanojit #ifdef NJ_VERBOSE extern const char* lirNames[]; - /** - * map address ranges to meaningful names. - */ - class LabelMap + // Maps address ranges to meaningful names. + class AddrNameMap { Allocator& allocator; class Entry { public: Entry(int) : name(0), size(0), align(0) {} - Entry(char *n, size_t s, size_t a) : name(n),size(s),align(a) {} + Entry(char *n, size_t s, size_t a) : name(n), size(s), align(a) {} char* name; size_t size:29, align:3; }; - TreeMap names; - LogControl *logc; - char buf[5000], *end; - void formatAddr(const void *p, char *buf); + TreeMap names; // maps code regions to names public: - LabelMap(Allocator& allocator, LogControl* logc); - void add(const void *p, size_t size, size_t align, const char *name); - const char *dup(const char *); - const char *format(const void *p); + AddrNameMap(Allocator& allocator); + void addAddrRange(const void *p, size_t size, size_t align, const char *name); + void lookupAddr(void *p, char*& name, int32_t& offset); }; + // Maps LIR instructions to meaningful names. class LirNameMap { + private: Allocator& alloc; template @@ -1556,8 +1552,12 @@ namespace nanojit return c; } }; + CountMap lircounts; CountMap funccounts; + CountMap namecounts; + + void addNameWithSuffix(LInsp i, const char *s, int suffix, bool ignoreOneSuffix); class Entry { @@ -1566,41 +1566,77 @@ namespace nanojit Entry(char* n) : name(n) {} char* name; }; + HashMap names; - void formatImm(int32_t c, char *buf); - void formatImmq(uint64_t c, char *buf); public: - LabelMap *labels; - LirNameMap(Allocator& alloc, LabelMap *lm) + LirNameMap(Allocator& alloc) : alloc(alloc), lircounts(alloc), funccounts(alloc), - names(alloc), - labels(lm) + namecounts(alloc), + names(alloc) {} - void addName(LInsp i, const char *s); - void copyName(LInsp i, const char *s, int suffix); - char* formatAccSet(LInsp ins, bool isLoad, char* buf); - const char *formatRef(LIns *ref); - const char *formatIns(LInsp i); - void formatGuard(LInsp i, char *buf); - void formatGuardXov(LInsp i, char *buf); + void addName(LInsp ins, const char *s); // gives 'ins' a special name + const char* createName(LInsp ins); // gives 'ins' a generic name + const char* lookupName(LInsp ins); + }; + + // We use big buffers for cases where we need to fit a whole instruction, + // and smaller buffers for all the others. These should easily be long + // enough, but for safety the formatXyz() functions check and won't exceed + // those limits. + class InsBuf { + public: + static const size_t len = 1000; + char buf[len]; + }; + class RefBuf { + public: + static const size_t len = 200; + char buf[len]; + }; + + class LInsPrinter + { + private: + Allocator& alloc; + + void formatImm(RefBuf* buf, int32_t c); + void formatImmq(RefBuf* buf, uint64_t c); + void formatGuard(InsBuf* buf, LInsp ins); + void formatGuardXov(InsBuf* buf, LInsp ins); + char* formatAccSet(RefBuf* buf, LInsp ins, bool isLoad); + + public: + LInsPrinter(Allocator& alloc) + : alloc(alloc) + { + addrNameMap = new (alloc) AddrNameMap(alloc); + lirNameMap = new (alloc) LirNameMap(alloc); + } + + char *formatAddr(RefBuf* buf, void* p); + char *formatRef(RefBuf* buf, LInsp ref); + char *formatIns(InsBuf* buf, LInsp ins); + + AddrNameMap* addrNameMap; + LirNameMap* lirNameMap; }; class VerboseWriter : public LirWriter { InsList code; - LirNameMap* names; + LInsPrinter* printer; LogControl* logc; const char* const prefix; bool const always_flush; public: - VerboseWriter(Allocator& alloc, LirWriter *out, - LirNameMap* names, LogControl* logc, const char* prefix = "", bool always_flush = false) - : LirWriter(out), code(alloc), names(names), logc(logc), prefix(prefix), always_flush(always_flush) + VerboseWriter(Allocator& alloc, LirWriter *out, LInsPrinter* printer, LogControl* logc, + const char* prefix = "", bool always_flush = false) + : LirWriter(out), code(alloc), printer(printer), logc(logc), prefix(prefix), always_flush(always_flush) {} LInsp add(LInsp i) { @@ -1621,9 +1657,10 @@ namespace nanojit void flush() { if (!code.isEmpty()) { + InsBuf b; int32_t count = 0; for (Seq* p = code.get(); p != NULL; p = p->tail) { - logc->printf("%s %s\n",prefix,names->formatIns(p->head)); + logc->printf("%s %s\n", prefix, printer->formatIns(&b, p->head)); count++; } code.clear(); @@ -1822,7 +1859,7 @@ namespace nanojit uintptr_t makeRoom(size_t szB); // make room for an instruction debug_only (void validate() const;) - verbose_only(LirNameMap* names;) + verbose_only(LInsPrinter* printer;) int32_t insCount(); size_t byteCount(); @@ -2072,16 +2109,16 @@ namespace nanojit class ReverseLister : public LirFilter { Allocator& _alloc; - LirNameMap* _names; + LInsPrinter* _printer; const char* _title; StringList _strs; LogControl* _logc; public: ReverseLister(LirFilter* in, Allocator& alloc, - LirNameMap* names, LogControl* logc, const char* title) + LInsPrinter* printer, LogControl* logc, const char* title) : LirFilter(in) , _alloc(alloc) - , _names(names) + , _printer(printer) , _title(title) , _strs(alloc) , _logc(logc) diff --git a/js/src/nanojit/VMPI.h b/js/src/nanojit/VMPI.h index 63838579180a..b24f688e436f 100644 --- a/js/src/nanojit/VMPI.h +++ b/js/src/nanojit/VMPI.h @@ -85,6 +85,7 @@ typedef unsigned __int64 uint64_t; #define VMPI_strncat strncat #define VMPI_strcpy strcpy #define VMPI_sprintf sprintf +#define VMPI_snprintf snprintf #define VMPI_vfprintf vfprintf #define VMPI_memset memset #define VMPI_isdigit isdigit From 2e1576ff718ce44e3be502b5de902f57059ffa17 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 10:45:57 +1100 Subject: [PATCH 072/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 846b499bb7ea..462117f8c6e8 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -c99da00233629d7184224a0a3a8129e248bb86fe +c844bd17e4a5e66b7913bb534e298088bee3e528 From d0a63c268d95de70f630ad7942a5f9c3cd72ea30 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 10:53:26 +1100 Subject: [PATCH 073/213] Bug 531687 - Duplicate node names in TMFLAGS=aftersf printout (TM-specific part). r=jseward. --- js/src/jsregexp.cpp | 10 ++++------ js/src/jstracer.cpp | 48 +++++++++++++++++++++------------------------ 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 4f9255fab134..20754462d056 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -3098,7 +3098,7 @@ class RegExpNativeCompiler { addName(LirBuffer* lirbuf, LIns* ins, const char* name) { #ifdef NJ_VERBOSE - debug_only_stmt(lirbuf->names->addName(ins, name);) + debug_only_stmt(lirbuf->printer->lirNameMap->addName(ins, name);) #endif return ins; } @@ -3145,8 +3145,7 @@ class RegExpNativeCompiler { { fragment->lirbuf = lirbuf; #ifdef DEBUG - LabelMap* labels = new (tempAlloc) LabelMap(tempAlloc, &LogController); - lirbuf->names = new (tempAlloc) LirNameMap(tempAlloc, labels); + lirbuf->printer = new (tempAlloc) LInsPrinter(tempAlloc); #endif } @@ -3188,7 +3187,7 @@ class RegExpNativeCompiler { #ifdef NJ_VERBOSE debug_only_stmt( if (LogController.lcbits & LC_TMRegexp) { - lir = verbose_filter = new VerboseWriter(tempAlloc, lir, lirbuf->names, + lir = verbose_filter = new VerboseWriter(tempAlloc, lir, lirbuf->printer, &LogController); } ) @@ -3248,8 +3247,7 @@ class RegExpNativeCompiler { */ JS_ASSERT(!lirbuf->sp && !lirbuf->rp); - assm->compile(fragment, tempAlloc, /*optimize*/true - verbose_only(, lirbuf->names->labels)); + assm->compile(fragment, tempAlloc, /*optimize*/true verbose_only(, lirbuf->printer)); if (assm->error() != nanojit::None) goto fail; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 31e3ef74e947..65146eeb095f 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -140,40 +140,38 @@ StackFilter::getTop(LIns* guard) #if defined NJ_VERBOSE void -LirNameMap::formatGuard(LIns *i, char *out) +LInsPrinter::formatGuard(InsBuf *buf, LIns *ins) { - VMSideExit *x; - - x = (VMSideExit *)i->record()->exit; - sprintf(out, + RefBuf b1, b2; + VMSideExit *x = (VMSideExit *)ins->record()->exit; + VMPI_snprintf(buf->buf, buf->len, "%s: %s %s -> pc=%p imacpc=%p sp%+ld rp%+ld (GuardID=%03d)", - formatRef(i), - lirNames[i->opcode()], - i->oprnd1() ? formatRef(i->oprnd1()) : "", + formatRef(&b1, ins), + lirNames[ins->opcode()], + ins->oprnd1() ? formatRef(&b2, ins->oprnd1()) : "", (void *)x->pc, (void *)x->imacpc, (long int)x->sp_adj, (long int)x->rp_adj, - i->record()->profGuardID); + ins->record()->profGuardID); } void -LirNameMap::formatGuardXov(LIns *i, char *out) +LInsPrinter::formatGuardXov(InsBuf *buf, LIns *ins) { - VMSideExit *x; - - x = (VMSideExit *)i->record()->exit; - sprintf(out, + RefBuf b1, b2, b3; + VMSideExit *x = (VMSideExit *)ins->record()->exit; + VMPI_snprintf(buf->buf, buf->len, "%s = %s %s, %s -> pc=%p imacpc=%p sp%+ld rp%+ld (GuardID=%03d)", - formatRef(i), - lirNames[i->opcode()], - formatRef(i->oprnd1()), - formatRef(i->oprnd2()), + formatRef(&b1, ins), + lirNames[ins->opcode()], + formatRef(&b2, ins->oprnd1()), + formatRef(&b3, ins->oprnd2()), (void *)x->pc, (void *)x->imacpc, (long int)x->sp_adj, (long int)x->rp_adj, - i->record()->profGuardID); + ins->record()->profGuardID); } #endif @@ -2175,8 +2173,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag fragment->lirbuf = lirbuf; #ifdef DEBUG - LabelMap* labels = new (tempAlloc()) LabelMap(tempAlloc(), &LogController); - lirbuf->names = new (tempAlloc()) LirNameMap(tempAlloc(), labels); + lirbuf->printer = new (tempAlloc()) LInsPrinter(tempAlloc()); #endif /* @@ -2222,7 +2219,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag #endif debug_only_stmt( if (LogController.lcbits & LC_TMRecorder) { - lir = new (tempAlloc()) VerboseWriter(tempAlloc(), lir, lirbuf->names, + lir = new (tempAlloc()) VerboseWriter(tempAlloc(), lir, lirbuf->printer, &LogController); } ) @@ -2417,7 +2414,7 @@ TraceRecorder::addName(LIns* ins, const char* name) * in adding names otherwise. */ if (LogController.lcbits > 0) - lirbuf->names->addName(ins, name); + lirbuf->printer->lirNameMap->addName(ins, name); #endif return ins; } @@ -4214,14 +4211,13 @@ TraceRecorder::compile() char* label = (char*)js_malloc((filename ? strlen(filename) : 7) + 16); sprintf(label, "%s:%u", filename ? filename : "", js_FramePCToLineNumber(cx, cx->fp)); - lirbuf->names->labels->add(fragment, sizeof(Fragment), 0, label); + lirbuf->printer->addrNameMap->addAddrRange(fragment, sizeof(Fragment), 0, label); js_free(label); #endif Assembler *assm = traceMonitor->assembler; JS_ASSERT(assm->error() == nanojit::None); - assm->compile(fragment, tempAlloc(), /*optimize*/true - verbose_only(, lirbuf->names->labels)); + assm->compile(fragment, tempAlloc(), /*optimize*/true verbose_only(, lirbuf->printer)); if (assm->error() != nanojit::None) { assm->setError(nanojit::None); From 77d5bd7f58ba48c8b991ea55579da1bd3d52c040 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 18 Mar 2010 13:05:22 +1300 Subject: [PATCH 074/213] Bug 526793 - Add gczeal() function to xpcshell. r=mrbkap --- js/src/xpconnect/shell/xpcshell.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index 6e06a3564950..282b18a472f5 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -553,6 +553,19 @@ GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_TRUE; } +#ifdef JS_GC_ZEAL +static JSBool +GCZeal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uint32 zeal; + if (!JS_ValueToECMAUint32(cx, argv[0], &zeal)) + return JS_FALSE; + + JS_SetGCZeal(cx, (PRUint8)zeal); + return JS_TRUE; +} +#endif + #ifdef DEBUG static JSBool @@ -756,6 +769,9 @@ static JSFunctionSpec glob_functions[] = { {"dumpXPC", DumpXPC, 1,0,0}, {"dump", Dump, 1,0,0}, {"gc", GC, 0,0,0}, +#ifdef JS_GC_ZEAL + {"gczeal", GCZeal, 1,0,0}, +#endif {"clear", Clear, 1,0,0}, {"options", Options, 0,0,0}, #ifdef DEBUG From 8e863e08fe464b973d00c3c55b2e017b4ef9b35b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 11:28:32 +1100 Subject: [PATCH 075/213] Windows bustage fix for bug 531687. --HG-- extra : convert_revision : 9fb3875862d0d0f8f1c6ffb84566c0bd73a66a46 --- js/src/nanojit/VMPI.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/src/nanojit/VMPI.h b/js/src/nanojit/VMPI.h index b24f688e436f..4938dfcf3e7c 100644 --- a/js/src/nanojit/VMPI.h +++ b/js/src/nanojit/VMPI.h @@ -85,7 +85,11 @@ typedef unsigned __int64 uint64_t; #define VMPI_strncat strncat #define VMPI_strcpy strcpy #define VMPI_sprintf sprintf -#define VMPI_snprintf snprintf +#ifdef _MSC_VER +# define VMPI_snprintf sprintf_s +#else +# define VMPI_snprintf snprintf +#endif #define VMPI_vfprintf vfprintf #define VMPI_memset memset #define VMPI_isdigit isdigit From 44aabe14ff49a5fab12da591b3de94e239ad11eb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 11:36:21 +1100 Subject: [PATCH 076/213] Another Windows bustage fix for bug 531687. --HG-- extra : convert_revision : 6cb0cf13894a89a41916baa0b45e12b86267c6dc --- js/src/nanojit/LIR.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 217f22ff0a6d..a646c68fc9e8 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -1877,7 +1877,7 @@ namespace nanojit CASE64(LIR_qcall:) { const CallInfo* call = i->callInfo(); int32_t argc = i->argc(); - ssize_t m = n; + int32_t m = int32_t(n); // Windows doesn't have 'ssize_t' if (call->isIndirect()) m -= VMPI_snprintf(s, m, "%s = %s [%s] ( ", formatRef(&b1, i), lirNames[op], formatRef(&b2, i->arg(--argc))); @@ -1896,7 +1896,7 @@ namespace nanojit } case LIR_jtbl: { - ssize_t m = n; + int32_t m = int32_t(n); // Windows doesn't have 'ssize_t' m -= VMPI_snprintf(s, m, "%s %s [ ", lirNames[op], formatRef(&b1, i->oprnd1())); if (m < 0) break; for (uint32_t j = 0, sz = i->getTableSize(); j < sz; j++) { From c3d53c70c9a81ad8a274e8e8548e73a119239e64 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 11:40:37 +1100 Subject: [PATCH 077/213] Yet another Windows bustage fix for bug 531687. --HG-- extra : convert_revision : ba9b07136948b3e1d87c1bc6b1b518f2182bf762 --- js/src/lirasm/lirasm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index 3422027b883e..84b2d19456f1 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -101,7 +101,7 @@ nanojit::LInsPrinter::formatGuard(InsBuf *buf, LIns *ins) { RefBuf b1, b2; LasmSideExit *x = (LasmSideExit *)ins->record()->exit; - snprintf(buf->buf, buf->len, + VMPI_snprintf(buf->buf, buf->len, "%s: %s %s -> line=%ld (GuardID=%03d)", formatRef(&b1, ins), lirNames[ins->opcode()], @@ -115,7 +115,7 @@ nanojit::LInsPrinter::formatGuardXov(InsBuf *buf, LIns *ins) { RefBuf b1, b2, b3; LasmSideExit *x = (LasmSideExit *)ins->record()->exit; - snprintf(buf->buf, buf->len, + VMPI_snprintf(buf->buf, buf->len, "%s = %s %s, %s -> line=%ld (GuardID=%03d)", formatRef(&b1, ins), lirNames[ins->opcode()], From 9a11c3a885d46b76b84b5ea99284e6bbf1219090 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Mar 2010 11:49:33 +1100 Subject: [PATCH 078/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 462117f8c6e8..84fd89cb6d61 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -c844bd17e4a5e66b7913bb534e298088bee3e528 +ba9b07136948b3e1d87c1bc6b1b518f2182bf762 From 29e02cea4224ad6c88da29bb2cc9d97c74a89d3c Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Thu, 18 Mar 2010 08:27:26 -0700 Subject: [PATCH 079/213] Re-seed Math.random() for each window/frame/context (475585, r=waldo,dolske). --- js/src/jscntxt.cpp | 3 ++- js/src/jscntxt.h | 6 +++--- js/src/jsmath.cpp | 32 ++++++++++++++++++++------------ js/src/jsmath.h | 2 +- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 69582a4d60fe..8775486c1cc8 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -111,7 +111,6 @@ JSThreadData::init() #ifdef JS_TRACER InitJIT(&traceMonitor); #endif - js_InitRandom(this); } void @@ -522,6 +521,8 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize) JS_APPEND_LINK(&cx->link, &rt->contextList); JS_UNLOCK_GC(rt); + js_InitRandom(cx); + /* * If cx is the first context on this runtime, initialize well-known atoms, * keywords, numbers, and strings. If one of these steps should fail, the diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index fc35d2bde5a6..216c5699c45a 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -540,9 +540,6 @@ struct JSThreadData { /* Property cache for faster call/get/set invocation. */ JSPropertyCache propertyCache; - /* Random number generator state, used by jsmath.cpp. */ - int64 rngSeed; - /* Optional stack of heap-allocated scoped local GC roots. */ JSLocalRootStack *localRootStack; @@ -1394,6 +1391,9 @@ struct JSContext /* Stored here to avoid passing it around as a parameter. */ uintN resolveFlags; + /* Random number generator state, used by jsmath.cpp. */ + int64 rngSeed; + #ifdef JS_TRACER /* * State for the current tree execution. bailExit is valid if the tree has diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 5ac7b49930a9..bd48ed59da2f 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -434,38 +434,46 @@ static const jsdouble RNG_DSCALE = jsdouble(1LL << 53); * Math.random() support, lifted from java.util.Random.java. */ static inline void -random_setSeed(JSThreadData *data, int64 seed) +random_setSeed(JSContext *cx, int64 seed) { - data->rngSeed = (seed ^ RNG_MULTIPLIER) & RNG_MASK; + cx->rngSeed = (seed ^ RNG_MULTIPLIER) & RNG_MASK; } void -js_InitRandom(JSThreadData *data) +js_InitRandom(JSContext *cx) { - /* Finally, set the seed from current time. */ - random_setSeed(data, PRMJ_Now() / 1000); + /* + * Set the seed from current time. Since we have a RNG per context and we often bring + * up several contexts at the same time, we xor in some additional values, namely + * the context and its successor. We don't just use the context because it might be + * possible to reverse engineer the context pointer if one guesses the time right. + */ + random_setSeed(cx, + (PRMJ_Now() / 1000) ^ + int64(cx) ^ + int64(cx->link.next)); } static inline uint64 -random_next(JSThreadData *data, int bits) +random_next(JSContext *cx, int bits) { - uint64 nextseed = data->rngSeed * RNG_MULTIPLIER; + uint64 nextseed = cx->rngSeed * RNG_MULTIPLIER; nextseed += RNG_ADDEND; nextseed &= RNG_MASK; - data->rngSeed = nextseed; + cx->rngSeed = nextseed; return nextseed >> (48 - bits); } static inline jsdouble -random_nextDouble(JSThreadData *data) +random_nextDouble(JSContext *cx) { - return jsdouble((random_next(data, 26) << 27) + random_next(data, 27)) / RNG_DSCALE; + return jsdouble((random_next(cx, 26) << 27) + random_next(cx, 27)) / RNG_DSCALE; } static JSBool math_random(JSContext *cx, uintN argc, jsval *vp) { - jsdouble z = random_nextDouble(JS_THREAD_DATA(cx)); + jsdouble z = random_nextDouble(cx); return js_NewNumberInRootedValue(cx, z, vp); } @@ -670,7 +678,7 @@ math_pow_tn(jsdouble d, jsdouble p) static jsdouble FASTCALL math_random_tn(JSContext *cx) { - return random_nextDouble(JS_THREAD_DATA(cx)); + return random_nextDouble(cx); } static jsdouble FASTCALL diff --git a/js/src/jsmath.h b/js/src/jsmath.h index 98a2bf1d5377..0eab6dfb0657 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -51,7 +51,7 @@ extern JSObject * js_InitMathClass(JSContext *cx, JSObject *obj); extern void -js_InitRandom(JSThreadData *data); +js_InitRandom(JSContext *cx); extern JSBool js_math_ceil(JSContext *cx, uintN argc, jsval *vp); From ca9b29506a07f47cbbcb00208a6aaf15764513bd Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 18 Mar 2010 12:12:06 -0700 Subject: [PATCH 080/213] Bug 552586 - split JSVAL_SPECIAL into TT_SPECIAL and TT_VOID (r=dvander) --- js/src/jsbuiltins.cpp | 16 +-- js/src/jsbuiltins.h | 6 +- js/src/jsrecursion.cpp | 28 +++-- js/src/jstracer.cpp | 258 ++++++++++++++++++++++++----------------- js/src/jstracer.h | 13 ++- 5 files changed, 184 insertions(+), 137 deletions(-) diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index f27c001bcad1..49d77ce89482 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -317,23 +317,13 @@ js_TypeOfBoolean(JSContext* cx, int32 unboxed) } JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, ACC_NONE) -jsdouble FASTCALL -js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed) -{ - if (unboxed == JSVAL_TO_SPECIAL(JSVAL_VOID)) - return js_NaN; - JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE); - return unboxed; -} -JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, ACC_NONE) - JSString* FASTCALL -js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed) +js_BooleanIntToString(JSContext *cx, int32 unboxed) { - JS_ASSERT(uint32(unboxed) <= 2); + JS_ASSERT(uint32(unboxed) <= 1); return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); } -JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, ACC_NONE) +JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACC_NONE) JSObject* FASTCALL js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h index 80efbfe984b6..fd115a420305 100644 --- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -503,9 +503,6 @@ struct ClosureVarInfo; jsdouble FASTCALL js_StringToNumber(JSContext* cx, JSString* str); -jsdouble FASTCALL -js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed); - /* Extern version of SetBuiltinError. */ extern JS_FRIEND_API(void) js_SetTraceableNativeFailed(JSContext *cx); @@ -557,8 +554,7 @@ JS_DECLARE_CALLINFO(js_HasNamedProperty) JS_DECLARE_CALLINFO(js_HasNamedPropertyInt32) JS_DECLARE_CALLINFO(js_TypeOfObject) JS_DECLARE_CALLINFO(js_TypeOfBoolean) -JS_DECLARE_CALLINFO(js_BooleanOrUndefinedToNumber) -JS_DECLARE_CALLINFO(js_BooleanOrUndefinedToString) +JS_DECLARE_CALLINFO(js_BooleanIntToString) JS_DECLARE_CALLINFO(js_NewNullClosure) JS_DECLARE_CALLINFO(js_PopInterpFrame) JS_DECLARE_CALLINFO(js_ConcatN) diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index e737ec38d77e..1a243df48e2e 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -167,7 +167,7 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame) if (*cx->fp->regs->pc == JSOP_RETURN) exitTypeMap[downPostSlots] = determineSlotType(&stackval(-1)); else - exitTypeMap[downPostSlots] = TT_PSEUDOBOOLEAN; + exitTypeMap[downPostSlots] = TT_VOID; /* Add global types. */ determineGlobalTypes(&exitTypeMap[downPostSlots + 1]); @@ -314,7 +314,7 @@ TraceRecorder::upRecursion() NULL; JS_ASSERT(rval_ins); } else { - rval_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + rval_ins = INS_VOID(); } TraceType returnType = exit->stackTypeMap()[downPostSlots]; @@ -331,7 +331,7 @@ TraceRecorder::upRecursion() if (*cx->fp->regs->pc == JSOP_RETURN) slotMap.addSlot(&stackval(-1)); else - slotMap.addSlot(TT_PSEUDOBOOLEAN); + slotMap.addSlot(TT_VOID); VisitGlobalSlots(slotMap, cx, *tree->globalSlots); if (recursive_pc == (jsbytecode*)fragment->root->ip) { debug_only_print0(LC_TMTracer, "Compiling up-recursive loop...\n"); @@ -473,7 +473,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (*cx->fp->regs->pc == JSOP_RETURN) typeMap[downPostSlots] = determineSlotType(&stackval(-1)); else - typeMap[downPostSlots] = TT_PSEUDOBOOLEAN; + typeMap[downPostSlots] = TT_VOID; } else { typeMap[downPostSlots] = anchor->stackTypeMap()[anchor->numStackSlots - 1]; } @@ -510,7 +510,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) } else { switch (returnType) { - case TT_PSEUDOBOOLEAN: + case TT_SPECIAL: + case TT_VOID: case TT_INT32: rval_ins = lir->insLoad(LIR_ld, lirbuf->sp, offset); break; @@ -591,7 +592,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (*cx->fp->regs->pc == JSOP_RETURN) slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]); else - slotMap.addSlot(TT_PSEUDOBOOLEAN); + slotMap.addSlot(TT_VOID); VisitGlobalSlots(slotMap, cx, *tree->globalSlots); debug_only_print0(LC_TMTracer, "Compiling up-recursive slurp...\n"); exit = copy(exit); @@ -721,7 +722,7 @@ TraceRecorder::slurpDoubleSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) } JS_REQUIRES_STACK LIns* -TraceRecorder::slurpBoolSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +TraceRecorder::slurpSpecialSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) { guard(true, lir->ins2(LIR_peq, @@ -733,6 +734,13 @@ TraceRecorder::slurpBoolSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) return bool_ins; } +JS_REQUIRES_STACK LIns* +TraceRecorder::slurpVoidSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +{ + guard(true, lir->ins2(LIR_peq, val_ins, INS_CONSTWORD(JSVAL_VOID)), exit); + return INS_VOID(); +} + JS_REQUIRES_STACK LIns* TraceRecorder::slurpStringSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) { @@ -801,8 +809,10 @@ TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) { switch (exit->slurpType) { - case TT_PSEUDOBOOLEAN: - return slurpBoolSlot(val_ins, vp, exit); + case TT_SPECIAL: + return slurpSpecialSlot(val_ins, vp, exit); + case TT_VOID: + return slurpVoidSlot(val_ins, vp, exit); case TT_INT32: return slurpInt32Slot(val_ins, vp, exit); case TT_DOUBLE: diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 65146eeb095f..ae2ac0c9a25b 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -194,14 +194,6 @@ using namespace nanojit; #define RETURN_IF_XML_A(val) RETURN_VALUE_IF_XML(val, ARECORD_STOP) #define RETURN_IF_XML(val) RETURN_VALUE_IF_XML(val, RECORD_STOP) -/* - * Never use JSVAL_IS_BOOLEAN because it restricts the value (true, false) and - * the type. What you want to use is JSVAL_IS_SPECIAL(x) and then handle the - * undefined case properly (bug 457363). - */ -#undef JSVAL_IS_BOOLEAN -#define JSVAL_IS_BOOLEAN(x) JS_STATIC_ASSERT(0) - JS_STATIC_ASSERT(sizeof(TraceType) == 1); JS_STATIC_ASSERT(offsetof(TraceNativeStorage, stack_global_buf) % 16 == 0); @@ -1049,11 +1041,14 @@ GetPromotedType(jsval v) return TT_FUNCTION; return TT_OBJECT; } + /* N.B. void is JSVAL_SPECIAL. */ + if (JSVAL_IS_VOID(v)) + return TT_VOID; uint8_t tag = JSVAL_TAG(v); JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL); JS_STATIC_ASSERT(static_cast(TT_DOUBLE) == JSVAL_DOUBLE); JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL); + JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); return TraceType(tag); } @@ -1070,11 +1065,14 @@ getCoercedType(jsval v) return TT_FUNCTION; return TT_OBJECT; } + /* N.B. void is JSVAL_SPECIAL. */ + if (JSVAL_IS_VOID(v)) + return TT_VOID; uint8_t tag = JSVAL_TAG(v); JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL); JS_STATIC_ASSERT(static_cast(TT_DOUBLE) == JSVAL_DOUBLE); JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL); + JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); return TraceType(tag); } @@ -2597,11 +2595,16 @@ ValueToNative(JSContext* cx, jsval v, TraceType type, double* slot) debug_only_print0(LC_TMTracer, "null "); return; - case TT_PSEUDOBOOLEAN: - /* Watch out for pseudo-booleans. */ + case TT_SPECIAL: JS_ASSERT(tag == JSVAL_SPECIAL); *(JSBool*)slot = JSVAL_TO_SPECIAL(v); - debug_only_printf(LC_TMTracer, "pseudoboolean<%d> ", *(JSBool*)slot); + debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); + return; + + case TT_VOID: + JS_ASSERT(JSVAL_IS_VOID(v)); + *(JSBool*)slot = JSVAL_TO_SPECIAL(JSVAL_VOID); + debug_only_print0(LC_TMTracer, "undefined "); return; case TT_FUNCTION: { @@ -2773,10 +2776,14 @@ NativeToValue(JSContext* cx, jsval& v, TraceType type, double* slot) debug_only_printf(LC_TMTracer, "null<%p> ", (void*)(*(JSObject**)slot)); break; - case TT_PSEUDOBOOLEAN: - /* Watch out for pseudo-booleans. */ + case TT_SPECIAL: v = SPECIAL_TO_JSVAL(*(JSBool*)slot); - debug_only_printf(LC_TMTracer, "boolean<%d> ", *(JSBool*)slot); + debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); + break; + + case TT_VOID: + v = JSVAL_VOID; + debug_only_print0(LC_TMTracer, "undefined "); break; case TT_FUNCTION: { @@ -3322,8 +3329,10 @@ TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, JS_ASSERT_IF(t != TT_JSVAL, isNumber(*p) == (t == TT_DOUBLE)); if (t == TT_DOUBLE) { ins = lir->insLoad(LIR_ldf, base, offset); - } else if (t == TT_PSEUDOBOOLEAN) { + } else if (t == TT_SPECIAL) { ins = lir->insLoad(LIR_ld, base, offset); + } else if (t == TT_VOID) { + ins = INS_VOID(); } else { ins = lir->insLoad(LIR_ldp, base, offset); } @@ -3822,10 +3831,13 @@ TraceRecorder::determineSlotType(jsval* vp) m = TT_FUNCTION; else m = TT_OBJECT; + } else if (JSVAL_IS_VOID(*vp)) { + /* N.B. void is JSVAL_SPECIAL. */ + m = TT_VOID; } else { - JS_ASSERT(JSVAL_TAG(*vp) == JSVAL_STRING || JSVAL_IS_SPECIAL(*vp)); + JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp)); JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL); + JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); m = TraceType(JSVAL_TAG(*vp)); } JS_ASSERT(m != TT_INT32 || isInt32(*vp)); @@ -6059,11 +6071,17 @@ IsEntryTypeCompatible(jsval* vp, TraceType* m) return true; debug_only_printf(LC_TMTracer, "null != tag%u ", tag); return false; - case TT_PSEUDOBOOLEAN: - if (tag == JSVAL_SPECIAL) + case TT_SPECIAL: + /* N.B. void is JSVAL_SPECIAL. */ + if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) return true; debug_only_printf(LC_TMTracer, "bool != tag%u ", tag); return false; + case TT_VOID: + if (JSVAL_IS_VOID(*vp)) + return true; + debug_only_printf(LC_TMTracer, "undefined != tag%u ", tag); + return false; default: JS_ASSERT(*m == TT_FUNCTION); if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) && @@ -8132,6 +8150,12 @@ TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1) return lir->ins1(LIR_i2f, result); } +LIns* +TraceRecorder::i2f(LIns* i) +{ + return lir->ins1(LIR_i2f, i); +} + LIns* TraceRecorder::f2i(LIns* f) { @@ -8210,8 +8234,12 @@ TraceRecorder::stringify(jsval& v) const CallInfo* ci; if (JSVAL_IS_NUMBER(v)) { ci = &js_NumberToString_ci; + } else if (JSVAL_IS_VOID(v)) { + /* N.B. void is JSVAL_SPECIAL. */ + return INS_ATOM(cx->runtime->atomState.booleanAtoms[2]); } else if (JSVAL_IS_SPECIAL(v)) { - ci = &js_BooleanOrUndefinedToString_ci; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + ci = &js_BooleanIntToString_ci; } else { /* * Callers must deal with non-primitive (non-null object) values by @@ -8581,14 +8609,16 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, */ if (GetPromotedType(l) == GetPromotedType(r)) { - if (JSVAL_TAG(l) == JSVAL_OBJECT || JSVAL_IS_SPECIAL(l)) { - if (JSVAL_TAG(l) == JSVAL_OBJECT && l) { - JSClass *clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(l)); - if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality) - RETURN_STOP_A("Can't trace extended class equality operator"); - } - if (JSVAL_TAG(l) == JSVAL_OBJECT) - op = LIR_peq; + if (JSVAL_IS_VOID(l) || JSVAL_IS_NULL(l)) { + cond = true; + } else if (JSVAL_IS_OBJECT(l)) { + JSClass *clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(l)); + if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality) + RETURN_STOP_A("Can't trace extended class equality operator"); + op = LIR_peq; + cond = (l == r); + } else if (JSVAL_IS_SPECIAL(l)) { + JS_ASSERT(JSVAL_IS_BOOLEAN(l) && JSVAL_IS_BOOLEAN(r)); cond = (l == r); } else if (JSVAL_IS_STRING(l)) { args[0] = r_ins, args[1] = l_ins; @@ -8600,12 +8630,12 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, cond = (asNumber(l) == asNumber(r)); op = LIR_feq; } - } else if (JSVAL_IS_NULL(l) && JSVAL_IS_SPECIAL(r)) { + } else if (JSVAL_IS_NULL(l) && JSVAL_IS_VOID(r)) { l_ins = INS_VOID(); - cond = (r == JSVAL_VOID); - } else if (JSVAL_IS_SPECIAL(l) && JSVAL_IS_NULL(r)) { + cond = true; + } else if (JSVAL_IS_VOID(l) && JSVAL_IS_NULL(r)) { r_ins = INS_VOID(); - cond = (l == JSVAL_VOID); + cond = true; } else if (isNumber(l) && JSVAL_IS_STRING(r)) { args[0] = r_ins, args[1] = cx_ins; r_ins = lir->insCall(&js_StringToNumber_ci, args); @@ -8617,43 +8647,25 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, cond = (js_StringToNumber(cx, JSVAL_TO_STRING(l)) == asNumber(r)); op = LIR_feq; } else { - if (JSVAL_IS_SPECIAL(l)) { - bool isVoid = !!JSVAL_IS_VOID(l); - guard(isVoid, - lir->ins2(LIR_eq, l_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))), - BRANCH_EXIT); - if (!isVoid) { - args[0] = l_ins, args[1] = cx_ins; - l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - l = (l == JSVAL_VOID) - ? cx->runtime->NaNValue - : INT_TO_JSVAL(l == JSVAL_TRUE); - return equalityHelper(l, r, l_ins, r_ins, negate, - tryBranchAfterCond, rval); - } - } else if (JSVAL_IS_SPECIAL(r)) { - bool isVoid = !!JSVAL_IS_VOID(r); - guard(isVoid, - lir->ins2(LIR_eq, r_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))), - BRANCH_EXIT); - if (!isVoid) { - args[0] = r_ins, args[1] = cx_ins; - r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - r = (r == JSVAL_VOID) - ? cx->runtime->NaNValue - : INT_TO_JSVAL(r == JSVAL_TRUE); - return equalityHelper(l, r, l_ins, r_ins, negate, - tryBranchAfterCond, rval); - } - } else { - if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) { - RETURN_IF_XML_A(r); - return InjectStatus(call_imacro(equality_imacros.any_obj)); - } - if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) { - RETURN_IF_XML_A(l); - return InjectStatus(call_imacro(equality_imacros.obj_any)); - } + if (JSVAL_IS_BOOLEAN(l)) { + l_ins = i2f(l_ins); + l = INT_TO_JSVAL(l == JSVAL_TRUE); + return equalityHelper(l, r, l_ins, r_ins, negate, + tryBranchAfterCond, rval); + } + if (JSVAL_IS_BOOLEAN(r)) { + r_ins = i2f(r_ins); + r = INT_TO_JSVAL(r == JSVAL_TRUE); + return equalityHelper(l, r, l_ins, r_ins, negate, + tryBranchAfterCond, rval); + } + if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) { + RETURN_IF_XML_A(r); + return InjectStatus(call_imacro(equality_imacros.any_obj)); + } + if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) { + RETURN_IF_XML_A(l); + return InjectStatus(call_imacro(equality_imacros.obj_any)); } l_ins = lir->insImm(0); @@ -8740,7 +8752,10 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) LIns* args[] = { l_ins, cx_ins }; switch (JSVAL_TAG(l)) { case JSVAL_SPECIAL: - l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + if (JSVAL_IS_VOID(l)) + l_ins = lir->insImmf(js_NaN); + else + l_ins = i2f(l_ins); break; case JSVAL_STRING: l_ins = lir->insCall(&js_StringToNumber_ci, args); @@ -8763,7 +8778,10 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) LIns* args[] = { r_ins, cx_ins }; switch (JSVAL_TAG(r)) { case JSVAL_SPECIAL: - r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); + if (JSVAL_IS_VOID(r)) + r_ins = lir->insImmf(js_NaN); + else + r_ins = i2f(r_ins); break; case JSVAL_STRING: r_ins = lir->insCall(&js_StringToNumber_ci, args); @@ -8894,16 +8912,25 @@ TraceRecorder::binary(LOpcode op) rnum = js_StringToNumber(cx, JSVAL_TO_STRING(r)); rightIsNumber = true; } + /* N.B. void is JSVAL_SPECIAL. */ if (JSVAL_IS_SPECIAL(l)) { - LIns* args[] = { a, cx_ins }; - a = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_SPECIAL(l)); + if (JSVAL_IS_VOID(l)) { + a = lir->insImmf(js_NaN); + lnum = js_NaN; + } else { + a = i2f(a); + lnum = JSVAL_TO_SPECIAL(l); + } leftIsNumber = true; } if (JSVAL_IS_SPECIAL(r)) { - LIns* args[] = { b, cx_ins }; - b = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args); - rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_SPECIAL(r)); + if (JSVAL_IS_VOID(r)) { + b = lir->insImmf(js_NaN); + rnum = js_NaN; + } else { + b = i2f(b); + rnum = JSVAL_TO_SPECIAL(r); + } rightIsNumber = true; } if (leftIsNumber && rightIsNumber) { @@ -9365,11 +9392,17 @@ TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit) } switch (JSVAL_TAG(v)) { case JSVAL_SPECIAL: + if (JSVAL_IS_VOID(v)) { + guard(true, lir->ins2(LIR_peq, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); + return INS_VOID(); + } guard(true, lir->ins2(LIR_peq, lir->ins2(LIR_piand, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)), INS_CONSTWORD(JSVAL_SPECIAL)), exit); + assert(!v_ins->isconstp()); + guard(false, lir->ins2(LIR_peq, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); return p2i(lir->ins2i(LIR_pursh, v_ins, JSVAL_TAGBITS)); case JSVAL_OBJECT: @@ -9834,7 +9867,7 @@ TraceRecorder::record_LeaveFrame() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_PUSH() { - stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))); + stack(0, INS_VOID()); return ARECORD_CONTINUE; } @@ -10230,14 +10263,20 @@ TraceRecorder::record_JSOP_NEG() return ARECORD_CONTINUE; } - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + if (JSVAL_IS_VOID(v)) { + set(&v, lir->insImmf(js_NaN)); + return ARECORD_CONTINUE; + } - LIns* args[] = { get(&v), cx_ins }; - set(&v, lir->ins1(LIR_fneg, - lir->insCall(JSVAL_IS_STRING(v) - ? &js_StringToNumber_ci - : &js_BooleanOrUndefinedToNumber_ci, - args))); + if (JSVAL_IS_STRING(v)) { + LIns* args[] = { get(&v), cx_ins }; + set(&v, lir->ins1(LIR_fneg, + lir->insCall(&js_StringToNumber_ci, args))); + return ARECORD_CONTINUE; + } + + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + set(&v, i2f(get(&v))); return ARECORD_CONTINUE; } @@ -10258,14 +10297,19 @@ TraceRecorder::record_JSOP_POS() set(&v, lir->insImmf(0)); return ARECORD_CONTINUE; } + if (JSVAL_IS_VOID(v)) { + set(&v, lir->insImmf(js_NaN)); + return ARECORD_CONTINUE; + } - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + if (JSVAL_IS_STRING(v)) { + LIns* args[] = { get(&v), cx_ins }; + set(&v, lir->insCall(&js_StringToNumber_ci, args)); + return ARECORD_CONTINUE; + } - LIns* args[] = { get(&v), cx_ins }; - set(&v, lir->insCall(JSVAL_IS_STRING(v) - ? &js_StringToNumber_ci - : &js_BooleanOrUndefinedToNumber_ci, - args)); + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + set(&v, i2f(get(&v))); return ARECORD_CONTINUE; } @@ -10995,7 +11039,7 @@ TraceRecorder::record_JSOP_TYPEOF() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_VOID() { - stack(-1, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))); + stack(-1, INS_VOID()); return ARECORD_CONTINUE; } @@ -11987,13 +12031,14 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) if (!isNumber(v)) { if (JSVAL_IS_NULL(v)) { v_ins = INS_CONST(0); - } else if (JSVAL_IS_PRIMITIVE(v)) { - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v)); + } else if (JSVAL_IS_VOID(v)) { + v_ins = lir->insImmf(js_NaN); + } else if (JSVAL_IS_STRING(v)) { LIns* args[] = { v_ins, cx_ins }; - v_ins = lir->insCall(JSVAL_IS_STRING(v) - ? &js_StringToNumber_ci - : &js_BooleanOrUndefinedToNumber_ci, - args); + v_ins = lir->insCall(&js_StringToNumber_ci, args); + } else if (JSVAL_IS_SPECIAL(v)) { + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + v_ins = i2f(v_ins); } else { v_ins = lir->insImmf(js_NaN); } @@ -12224,7 +12269,8 @@ LIns* TraceRecorder::stackLoad(LIns* base, uint8 type) loadOp = LIR_ldp; break; case TT_INT32: - case TT_PSEUDOBOOLEAN: + case TT_SPECIAL: + case TT_VOID: loadOp = LIR_ld; break; case TT_JSVAL: @@ -12384,7 +12430,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, * and does not call any TR::record_*CallComplete hook. */ if (fun->u.i.script->isEmpty()) { - LIns* rval_ins = constructing ? stack(-1 - argc) : INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + LIns* rval_ins = constructing ? stack(-1 - argc) : INS_VOID(); stack(-2 - argc, rval_ins); return RECORD_CONTINUE; } @@ -12787,7 +12833,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, } } while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit)); - set(outp, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))); + set(outp, INS_VOID()); return ARECORD_CONTINUE; } @@ -12985,7 +13031,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ lir->ins2i(LIR_pilsh, pidx_ins, (sizeof(jsval) == 4) ? 2 : 3)); v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0), exit); - if (JSVAL_IS_SPECIAL(*vp)) { + if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) { /* * If we read a hole from the array, convert it to undefined and guard * that there are no indexed properties along the prototype chain. @@ -14625,7 +14671,7 @@ TraceRecorder::record_JSOP_STOP() JS_ASSERT(fp->thisv == fp->argv[-1]); rval_ins = get(&fp->argv[-1]); } else { - rval_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + rval_ins = INS_VOID(); } clearCurrentFrameSlotsFromTracker(nativeFrameTracker); return ARECORD_CONTINUE; @@ -14664,7 +14710,7 @@ TraceRecorder::record_JSOP_ENTERBLOCK() JSObject* obj; obj = cx->fp->script->getObject(getFullIndex(0)); - LIns* void_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); + LIns* void_ins = INS_VOID(); for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++) stack(i, void_ins); return ARECORD_CONTINUE; diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 78ec9f58937a..924bdc209b4c 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -348,9 +348,10 @@ enum TraceType_ TT_JSVAL = 3, /* arbitrary jsval */ TT_STRING = 4, /* pointer to JSString */ TT_NULL = 5, /* null */ - TT_PSEUDOBOOLEAN = 6, /* true, false, or undefined (0, 1, or 2) */ - TT_FUNCTION = 7, /* pointer to JSObject whose class is js_FunctionClass */ - TT_IGNORE = 8 + TT_SPECIAL = 6, /* true, false, hole, or areturn (0, 1, 6, or 8) */ + TT_VOID = 7, /* undefined (2) */ + TT_FUNCTION = 8, /* pointer to JSObject whose class is js_FunctionClass */ + TT_IGNORE = 9 } #if defined(__GNUC__) && defined(USE_TRACE_TYPE_ENUM) __attribute__((packed)) @@ -1096,7 +1097,9 @@ class TraceRecorder VMSideExit* exit); JS_REQUIRES_STACK nanojit::LIns* slurpNullSlot(nanojit::LIns* val_ins, jsval* vp, VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpBoolSlot(nanojit::LIns* val_ins, jsval* vp, + JS_REQUIRES_STACK nanojit::LIns* slurpSpecialSlot(nanojit::LIns* val_ins, jsval* vp, + VMSideExit* exit); + JS_REQUIRES_STACK nanojit::LIns* slurpVoidSlot(nanojit::LIns* val_ins, jsval* vp, VMSideExit* exit); JS_REQUIRES_STACK nanojit::LIns* slurpSlot(nanojit::LIns* val_ins, jsval* vp, VMSideExit* exit); @@ -1155,6 +1158,8 @@ class TraceRecorder JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1, nanojit::LIns* s0, nanojit::LIns* s1); + + nanojit::LIns* i2f(nanojit::LIns* i); nanojit::LIns* f2i(nanojit::LIns* f); nanojit::LIns* f2u(nanojit::LIns* f); JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f); From 70297b5302c4233dce05f75eedc05ae95ea0c3ba Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 18 Mar 2010 13:46:56 -0700 Subject: [PATCH 081/213] Fixed 64-bit LIR type assertion (no bug, rs=dvander). --- js/src/jstracer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index ae2ac0c9a25b..e0612982f60d 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8611,6 +8611,8 @@ TraceRecorder::equalityHelper(jsval l, jsval r, LIns* l_ins, LIns* r_ins, if (GetPromotedType(l) == GetPromotedType(r)) { if (JSVAL_IS_VOID(l) || JSVAL_IS_NULL(l)) { cond = true; + if (JSVAL_IS_NULL(l)) + op = LIR_peq; } else if (JSVAL_IS_OBJECT(l)) { JSClass *clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(l)); if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality) From a3d656dd0689a9484051585298c725be9f412d35 Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Thu, 18 Mar 2010 14:43:35 -0700 Subject: [PATCH 082/213] Skip test for 503860 until bug 497789 is patched. --- js/src/tests/js1_5/Regress/jstests.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/tests/js1_5/Regress/jstests.list b/js/src/tests/js1_5/Regress/jstests.list index d0f2a22420b0..1c8c0458a158 100644 --- a/js/src/tests/js1_5/Regress/jstests.list +++ b/js/src/tests/js1_5/Regress/jstests.list @@ -347,7 +347,7 @@ script regress-482421.js script regress-482783.js script regress-483103.js script regress-501124.js -script regress-503860.js +skip script regress-503860.js # waiting for bug 497789 to be fixed script regress-504078.js script regress-506567.js script regress-511859.js From 85b60d98b9f4deb2ea8e404b4d0e5a60c9b886ee Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Thu, 18 Mar 2010 18:00:58 -0700 Subject: [PATCH 083/213] Report proper typeof for XPCNativeWrapper(obj) and XPCNativeWrapper(fun) (553407, r=mrbkap). --- dom/base/nsDOMClassInfo.cpp | 2 +- dom/base/nsDOMClassInfo.h | 22 +++++----- dom/base/nsJSEnvironment.cpp | 6 ++- js/src/xpconnect/idl/nsIXPConnect.idl | 5 ++- js/src/xpconnect/src/XPCNativeWrapper.cpp | 42 +++++++++++++++++--- js/src/xpconnect/src/XPCNativeWrapper.h | 16 +++++--- js/src/xpconnect/src/nsXPConnect.cpp | 10 +++-- js/src/xpconnect/tests/mochitest/Makefile.in | 1 + 8 files changed, 74 insertions(+), 30 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 40e8d7fff8e7..5b7a49a286ca 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1474,7 +1474,7 @@ jsval nsDOMClassInfo::sJava_id = JSVAL_VOID; jsval nsDOMClassInfo::sPackages_id = JSVAL_VOID; static const JSClass *sObjectClass = nsnull; -const JSClass *nsDOMClassInfo::sXPCNativeWrapperClass = nsnull; +JSPropertyOp nsDOMClassInfo::sXPCNativeWrapperGetPropertyOp = nsnull; /** * Set our JSClass pointer for the Object class diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index c2c7b439487e..845b4169e3b6 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -174,17 +174,17 @@ public: /** * Get our JSClass pointer for the XPCNativeWrapper class */ - static const JSClass* GetXPCNativeWrapperClass() { - return sXPCNativeWrapperClass; + static JSPropertyOp GetXPCNativeWrapperGetPropertyOp() { + return sXPCNativeWrapperGetPropertyOp; } /** * Set our JSClass pointer for the XPCNativeWrapper class */ - static void SetXPCNativeWrapperClass(JSClass* aClass) { - NS_ASSERTION(!sXPCNativeWrapperClass, - "Double set of sXPCNativeWrapperClass"); - sXPCNativeWrapperClass = aClass; + static void SetXPCNativeWrapperGetPropertyOp(JSPropertyOp getPropertyOp) { + NS_ASSERTION(!sXPCNativeWrapperGetPropertyOp, + "Double set of sXPCNativeWrapperGetPropertyOp"); + sXPCNativeWrapperGetPropertyOp = getPropertyOp; } static PRBool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj) @@ -194,13 +194,13 @@ public: nsIScriptContext *scx = GetScriptContextFromJSContext(cx); NS_PRECONDITION(!scx || !scx->IsContextInitialized() || - sXPCNativeWrapperClass, - "Must know what the XPCNativeWrapper class is!"); + sXPCNativeWrapperGetPropertyOp, + "Must know what the XPCNativeWrapper class GetProperty op is!"); } #endif - return sXPCNativeWrapperClass && - ::JS_GET_CLASS(cx, obj) == sXPCNativeWrapperClass; + return sXPCNativeWrapperGetPropertyOp && + ::JS_GET_CLASS(cx, obj)->getProperty == sXPCNativeWrapperGetPropertyOp; } static void PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper); @@ -365,7 +365,7 @@ protected: static jsval sJava_id; static jsval sPackages_id; - static const JSClass *sXPCNativeWrapperClass; + static JSPropertyOp sXPCNativeWrapperGetPropertyOp; }; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 2f0b245b0bda..8f521067bbc8 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2586,8 +2586,10 @@ nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject) // Now check whether we need to grab a pointer to the // XPCNativeWrapper class - if (!nsDOMClassInfo::GetXPCNativeWrapperClass()) { - nsDOMClassInfo::SetXPCNativeWrapperClass(xpc->GetNativeWrapperClass()); + if (!nsDOMClassInfo::GetXPCNativeWrapperGetPropertyOp()) { + JSPropertyOp getProperty; + xpc->GetNativeWrapperGetPropertyOp(&getProperty); + nsDOMClassInfo::SetXPCNativeWrapperGetPropertyOp(getProperty); } } else { // There's already a global object. We are preparing this outer window diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index 382adc8d0c6f..92320add099d 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -65,6 +65,7 @@ [ptr] native JSClassPtr(JSClass); [ptr] native JSObjectPtr(JSObject); [ptr] native JSValPtr(jsval); + native JSPropertyOp(JSPropertyOp); native JSEqualityOp(JSEqualityOp); native JSID(jsid); [ptr] native voidPtrPtr(void*); @@ -396,7 +397,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[uuid(96540596-c21e-4183-bb47-f6a5c1ad2dba)] +[uuid(0332b12a-8103-4601-aed3-b9933a0d9441)] interface nsIXPConnect : nsISupports { %{ C++ @@ -868,5 +869,5 @@ interface nsIXPConnect : nsISupports #endif %} - [notxpcom] JSClassPtr getNativeWrapperClass(); + [notxpcom] void getNativeWrapperGetPropertyOp(out JSPropertyOp getProperty); }; diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index c3fe67645fd7..60e3081ef628 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -112,7 +112,33 @@ namespace XPCNativeWrapper { namespace internal { // JS class for XPCNativeWrapper (and this doubles as the constructor // for XPCNativeWrapper for the moment too...) -JSExtendedClass NWClass = { +JSExtendedClass NW_NoCall_Class = { + // JSClass (JSExtendedClass.base) initialization + { "XPCNativeWrapper", + JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | + // Our one reserved slot holds a jsint of flag bits + JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED | JSCLASS_CONSTRUCT_PROTOTYPE, + XPC_NW_AddProperty, XPC_NW_DelProperty, + XPC_NW_GetProperty, XPC_NW_SetProperty, + XPC_NW_Enumerate, (JSResolveOp)XPC_NW_NewResolve, + XPC_NW_Convert, XPC_NW_Finalize, + nsnull, XPC_NW_CheckAccess, + nsnull, XPC_NW_Construct, + nsnull, XPC_NW_HasInstance, + JS_CLASS_TRACE(XPC_NW_Trace), nsnull + }, + + // JSExtendedClass initialization + XPC_NW_Equality, + nsnull, // outerObject + nsnull, // innerObject + XPC_NW_Iterator, + nsnull, // wrappedObject + JSCLASS_NO_RESERVED_MEMBERS +}; + +JSExtendedClass NW_Call_Class = { // JSClass (JSExtendedClass.base) initialization { "XPCNativeWrapper", JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | @@ -1112,7 +1138,7 @@ XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) } JSObject *wrapperIter = - JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(), nsnull, + JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(false), nsnull, obj->getParent()); if (!wrapperIter) { return nsnull; @@ -1208,7 +1234,7 @@ XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject) { JSObject *class_obj = - ::JS_InitClass(ccx, aGlobalObject, nsnull, &internal::NWClass.base, + ::JS_InitClass(ccx, aGlobalObject, nsnull, &internal::NW_Call_Class.base, XPCNativeWrapperCtor, 0, nsnull, nsnull, nsnull, static_functions); if (!class_obj) { @@ -1226,7 +1252,7 @@ XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx, JSBool found; return ::JS_SetPropertyAttributes(ccx, aGlobalObject, - internal::NWClass.base.name, + internal::NW_Call_Class.base.name, JSPROP_READONLY | JSPROP_PERMANENT, &found); } @@ -1295,7 +1321,9 @@ XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper, ::JS_LockGCThing(cx, nw_parent); } - obj = ::JS_NewObjectWithGivenProto(cx, GetJSClass(), nsnull, nw_parent); + bool call = NATIVE_HAS_FLAG(wrapper, WantCall) || + NATIVE_HAS_FLAG(wrapper, WantConstruct); + obj = ::JS_NewObjectWithGivenProto(cx, GetJSClass(call), nsnull, nw_parent); if (lock) { ::JS_UnlockGCThing(cx, nw_parent); @@ -1338,8 +1366,10 @@ XPCNativeWrapper::CreateExplicitWrapper(JSContext *cx, printf("Creating new JSObject\n"); #endif + bool call = NATIVE_HAS_FLAG(wrappedNative, WantCall) || + NATIVE_HAS_FLAG(wrappedNative, WantConstruct); JSObject *wrapperObj = - JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(), nsnull, + JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(call), nsnull, wrappedNative->GetScope()->GetGlobalJSObject()); if (!wrapperObj) { diff --git a/js/src/xpconnect/src/XPCNativeWrapper.h b/js/src/xpconnect/src/XPCNativeWrapper.h index 74f8b68f130e..2bccbca14fea 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.h +++ b/js/src/xpconnect/src/XPCNativeWrapper.h @@ -44,7 +44,10 @@ class nsIPrincipal; namespace XPCNativeWrapper { -namespace internal { extern JSExtendedClass NWClass; } +namespace internal { + extern JSExtendedClass NW_NoCall_Class; + extern JSExtendedClass NW_Call_Class; +} PRBool AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject); @@ -59,13 +62,14 @@ CreateExplicitWrapper(JSContext *cx, XPCWrappedNative *wrapper, JSBool deep, inline PRBool IsNativeWrapperClass(JSClass *clazz) { - return clazz == &internal::NWClass.base; + return clazz == &internal::NW_NoCall_Class.base || + clazz == &internal::NW_Call_Class.base; } inline PRBool IsNativeWrapper(JSObject *obj) { - return STOBJ_GET_CLASS(obj) == &internal::NWClass.base; + return IsNativeWrapperClass(obj->getClass()); } JSBool @@ -80,9 +84,11 @@ SafeGetWrappedNative(JSObject *obj) } inline JSClass * -GetJSClass() +GetJSClass(bool call) { - return &internal::NWClass.base; + return call + ? &internal::NW_Call_Class.base + : &internal::NW_NoCall_Class.base; } void diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index abac34d492d7..ab219592389d 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -2796,10 +2796,14 @@ nsXPConnect::GetPrincipal(JSObject* obj, PRBool allowShortCircuit) const return nsnull; } -NS_IMETHODIMP_(JSClass *) -nsXPConnect::GetNativeWrapperClass() +NS_IMETHODIMP_(void) +nsXPConnect::GetNativeWrapperGetPropertyOp(JSPropertyOp *getPropertyPtr) { - return XPCNativeWrapper::GetJSClass(); + NS_ASSERTION(XPCNativeWrapper::GetJSClass(true)->getProperty == + XPCNativeWrapper::GetJSClass(false)->getProperty, + "Call and NoCall XPCNativeWrapper Class must use the same " + "getProperty hook."); + *getPropertyPtr = XPCNativeWrapper::GetJSClass(true)->getProperty; } /* These are here to be callable from a debugger */ diff --git a/js/src/xpconnect/tests/mochitest/Makefile.in b/js/src/xpconnect/tests/mochitest/Makefile.in index a9572f2fd230..496e28d61f43 100644 --- a/js/src/xpconnect/tests/mochitest/Makefile.in +++ b/js/src/xpconnect/tests/mochitest/Makefile.in @@ -68,6 +68,7 @@ _TEST_FILES = bug500931_helper.html \ test_bug504877.html \ test_bug505915.html \ test_bug517163.html \ + test_bug553407.html \ test_cows.html \ test_frameWrapping.html \ $(NULL) From 56d053c2f5891bcbfa1448d1ff7f938de0f912b8 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Thu, 18 Mar 2010 18:02:35 -0700 Subject: [PATCH 084/213] add missing test file for bug 553407 --- .../tests/mochitest/test_bug553407.html | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 js/src/xpconnect/tests/mochitest/test_bug553407.html diff --git a/js/src/xpconnect/tests/mochitest/test_bug553407.html b/js/src/xpconnect/tests/mochitest/test_bug553407.html new file mode 100644 index 000000000000..93f90dab60cb --- /dev/null +++ b/js/src/xpconnect/tests/mochitest/test_bug553407.html @@ -0,0 +1,30 @@ + + + + + Test for Bug 553407 + + + + + +Mozilla Bug 553407 +

+ +
+
+
+ + From 7b07e705a22e05c3ef640714540b38b93d1a1498 Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Thu, 18 Mar 2010 22:15:51 -0700 Subject: [PATCH 085/213] Bug 553423 - JS scanner namespacing cleanup (r=lw) --- js/src/jsemit.cpp | 49 ++- js/src/jsexn.cpp | 2 +- js/src/jsfun.cpp | 19 +- js/src/json.cpp | 2 +- js/src/jsparse.cpp | 765 +++++++++++++++++++++----------------------- js/src/jsparse.h | 34 +- js/src/jsprvtd.h | 9 +- js/src/jsregexp.cpp | 13 +- js/src/jsregexp.h | 4 +- js/src/jsscan.cpp | 158 ++++----- js/src/jsscan.h | 214 +++++++------ js/src/jsscript.cpp | 3 +- js/src/jsxml.cpp | 43 ++- 13 files changed, 635 insertions(+), 680 deletions(-) diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 3ea68e54c70b..a9e17741da99 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -79,6 +79,8 @@ #define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote)) #define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote)) +using namespace js; + static JSBool NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, size_t start, size_t end); @@ -184,7 +186,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) JS_ASSERT(cg->stackDepth >= 0); if (cg->stackDepth < 0) { char numBuf[12]; - JSTokenStream *ts; + TokenStream *ts; JS_snprintf(numBuf, sizeof numBuf, "%d", target); ts = &cg->compiler->tokenStream; @@ -893,7 +895,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) if (growth) { #ifdef DEBUG_brendan - JSTokenStream *ts = &cg->compiler->tokenStream; + TokenStream *ts = &cg->compiler->tokenStream; printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n", ts->filename ? ts->filename : "stdin", cg->firstLine, @@ -1835,9 +1837,7 @@ AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) if (cg->flags & TCF_IN_FUNCTION) { slot += cg->fun->u.i.nvars; if ((uintN) slot >= SLOTNO_LIMIT) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, - JSREPORT_ERROR, - JSMSG_TOO_MANY_LOCALS); + ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); slot = -1; } } @@ -3934,8 +3934,7 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, depth = limit = (uintN) cg->stackDepth; for (pn = rhs->pn_head; pn; pn = pn->pn_next) { if (limit == JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, - JSMSG_ARRAY_INIT_TOO_BIG); + ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG); return JS_FALSE; } @@ -4333,7 +4332,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JSSrcNoteType noteType; jsbytecode *pc; JSOp op; - JSTokenType type; + TokenType type; uint32 argc; #if JS_HAS_SHARP_VARS jsint sharpnum; @@ -4695,7 +4694,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn3 = pn2->pn_left; type = PN_TYPE(pn3); cg->flags |= TCF_IN_FOR_INIT; - if (TOKEN_TYPE_IS_DECL(type) && !js_EmitTree(cx, cg, pn3)) + if (TokenTypeIsDecl(type) && !js_EmitTree(cx, cg, pn3)) return JS_FALSE; cg->flags &= ~TCF_IN_FOR_INIT; @@ -4804,8 +4803,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) op = PN_OP(pn3); } if (pn3->isConst()) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return JS_FALSE; } if (pn3->pn_cookie != FREE_UPVAR_COOKIE) { @@ -4917,7 +4916,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (op == JSOP_POP) { if (!js_EmitTree(cx, cg, pn3)) return JS_FALSE; - if (TOKEN_TYPE_IS_DECL(pn3->pn_type)) { + if (TokenTypeIsDecl(PN_TYPE(pn3))) { /* * Check whether a destructuring-initialized var decl * was optimized to a group assignment. If so, we do @@ -5486,9 +5485,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #if JS_HAS_GENERATORS case TOK_YIELD: if (!(cg->flags & TCF_IN_FUNCTION)) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, - JSMSG_BAD_RETURN_OR_YIELD, - js_yield_str); + ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, + js_yield_str); return JS_FALSE; } if (pn->pn_kid) { @@ -5626,10 +5625,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) cg->topStmt->type != STMT_LABEL || cg->topStmt->update < CG_OFFSET(cg))) { CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno; - if (!js_ReportCompileErrorNumber(cx, CG_TS(cg), pn2, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_USELESS_EXPR)) { + if (!ReportCompileErrorNumber(cx, CG_TS(cg), pn2, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_USELESS_EXPR)) { return JS_FALSE; } } else { @@ -5796,13 +5794,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * x getter = y where x is a local or let variable is not * supported. */ - js_ReportCompileErrorNumber(cx, - TS(cg->compiler), - pn2, JSREPORT_ERROR, - JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) - ? js_getter_str - : js_setter_str); + ReportCompileErrorNumber(cx, TS(cg->compiler), pn2, JSREPORT_ERROR, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) ? js_getter_str : js_setter_str); return JS_FALSE; } @@ -6633,8 +6627,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #endif #if JS_HAS_DESTRUCTURING_SHORTHAND if (pn->pn_xflags & PNX_DESTRUCT) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, - JSMSG_BAD_OBJECT_INIT); + ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 478dac5505df..cc2bec6b7e88 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -351,7 +351,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, * Construct a new copy of the error report struct. We can't use the * error report struct that was passed in, because it's allocated on * the stack, and also because it may point to transient data in the - * JSTokenStream. + * TokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index c5ba28896059..a07be6899ea3 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2183,12 +2183,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const char *filename; JSBool ok; JSString *str, *arg; - JSTokenStream ts(cx); + TokenStream ts(cx); JSPrincipals *principals; jschar *collected_args, *cp; void *mark; size_t arg_length, args_length, old_args_length; - JSTokenType tt; + TokenType tt; if (!JS_IsConstructing(cx)) { obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL); @@ -2336,7 +2336,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* The argument string may be empty or contain no tokens. */ - tt = js_GetToken(cx, &ts); + tt = GetToken(cx, &ts); if (tt != TOK_EOF) { for (;;) { /* @@ -2358,12 +2358,9 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const char *name; name = js_AtomToPrintableString(cx, atom); - ok = name && - js_ReportCompileErrorNumber(cx, &ts, NULL, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_DUPLICATE_FORMAL, - name); + ok = name && ReportCompileErrorNumber(cx, &ts, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, name); if (!ok) goto after_args; } @@ -2374,12 +2371,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ - tt = js_GetToken(cx, &ts); + tt = GetToken(cx, &ts); if (tt == TOK_EOF) break; if (tt != TOK_COMMA) goto after_args; - tt = js_GetToken(cx, &ts); + tt = GetToken(cx, &ts); } } diff --git a/js/src/json.cpp b/js/src/json.cpp index 44897ba6d41c..3c734ce8c926 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -923,7 +923,7 @@ static JSBool HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) { jsval keyword; - JSTokenType tt = js_CheckKeyword(buf, len); + TokenType tt = js_CheckKeyword(buf, len); if (tt != TOK_PRIMARY) { // bad keyword JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 0b185b11075b..8dfdac0d88c6 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -104,12 +104,12 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom)); * Insist that the next token be of type tt, or report errno and return null. * NB: this macro uses cx and ts from its lexical environment. */ -#define MUST_MATCH_TOKEN(tt, errno) \ - JS_BEGIN_MACRO \ - if (js_GetToken(context, &tokenStream) != tt) { \ - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ - return NULL; \ - } \ +#define MUST_MATCH_TOKEN(tt, errno) \ + JS_BEGIN_MACRO \ + if (GetToken(context, &tokenStream) != tt) { \ + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ + return NULL; \ + } \ JS_END_MACRO #ifdef METER_PARSENODES @@ -529,14 +529,14 @@ JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc) JSParseNode *pn = NewOrRecycledNode(tc); if (!pn) return NULL; - JSToken *tp = tc->compiler->tokenStream.mutableCurrentToken(); + Token *tp = tc->compiler->tokenStream.mutableCurrentToken(); pn->init(tp->type, JSOP_NOP, arity); pn->pn_pos = tp->pos; return pn; } JSParseNode * -JSParseNode::newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, +JSParseNode::newBinaryOrAppend(TokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, JSTreeContext *tc) { JSParseNode *pn, *pn1, *pn2; @@ -635,8 +635,8 @@ NameNode::create(JSAtom *atom, JSTreeContext *tc) } /* namespace js */ #if JS_HAS_GETTER_SETTER -static JSTokenType -CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) +static TokenType +CheckGetterOrSetter(JSContext *cx, TokenStream *ts, TokenType tt) { JSAtom *atom; JSRuntime *rt; @@ -652,25 +652,20 @@ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) op = JSOP_SETTER; else return TOK_NAME; - if (js_PeekTokenSameLine(cx, ts) != tt) + if (PeekTokenSameLine(cx, ts) != tt) return TOK_NAME; - (void) js_GetToken(cx, ts); + (void) GetToken(cx, ts); if (ts->currentToken().t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, - JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) - ? js_getter_str - : js_setter_str); + ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) ? js_getter_str : js_setter_str); return TOK_ERROR; } ts->mutableCurrentToken()->t_op = op; if (JS_HAS_STRICT_OPTION(cx)) { name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportCompileErrorNumber(cx, ts, NULL, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_DEPRECATED_USAGE, - name)) { + !ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, name)) { return TOK_ERROR; } } @@ -723,9 +718,9 @@ JSCompiler::parse(JSObject *chain) JSParseNode *pn = statements(); if (pn) { - if (!js_MatchToken(context, &tokenStream, TOK_EOF)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + if (!MatchToken(context, &tokenStream, TOK_EOF)) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); pn = NULL; } else { if (!js_FoldConstants(context, pn, &globaltc)) @@ -771,7 +766,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal { JSCompiler jsc(cx, principals, callerFrame); JSArenaPool codePool, notePool; - JSTokenType tt; + TokenType tt; JSParseNode *pn; uint32 scriptGlobals; JSScript *script; @@ -873,7 +868,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal inDirectivePrologue = true; for (;;) { jsc.tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(cx, &jsc.tokenStream); + tt = PeekToken(cx, &jsc.tokenStream); jsc.tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF) { if (tt == TOK_EOF) @@ -904,7 +899,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal #if JS_HAS_XML_SUPPORT if (PN_TYPE(pn) != TOK_SEMI || !pn->pn_kid || - !TREE_TYPE_IS_XML(PN_TYPE(pn->pn_kid))) { + !TreeTypeIsXML(PN_TYPE(pn->pn_kid))) { onlyXML = false; } #endif @@ -919,8 +914,8 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal * https://bugzilla.mozilla.org/show_bug.cgi?id=336551 */ if (pn && onlyXML && (tcflags & TCF_NO_SCRIPT_RVAL)) { - js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, - JSMSG_XML_WHOLE_PROGRAM); + ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, + JSMSG_XML_WHOLE_PROGRAM); goto out; } #endif @@ -1010,8 +1005,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal return script; too_many_slots: - js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, - JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); + ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); script = NULL; goto out; } @@ -1156,8 +1150,7 @@ ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum, errnum = anonerrnum; name = NULL; } - return js_ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, flags, - errnum, name); + return ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, flags, errnum, name); } static JSBool @@ -1183,8 +1176,8 @@ CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs) if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) { const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportStrictModeError(cx, TS(tc->compiler), tc, lhs, - JSMSG_DEPRECATED_ASSIGN, name)) { + !ReportStrictModeError(cx, TS(tc->compiler), tc, lhs, JSMSG_DEPRECATED_ASSIGN, + name)) { return false; } } @@ -1208,8 +1201,7 @@ CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, JSParseNode * if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) { const char *name = js_AtomToPrintableString(cx, atom); if (name) - js_ReportStrictModeError(cx, TS(tc->compiler), tc, pn, - JSMSG_BAD_BINDING, name); + ReportStrictModeError(cx, TS(tc->compiler), tc, pn, JSMSG_BAD_BINDING, name); return false; } return true; @@ -1249,8 +1241,7 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, pn = dn; const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportStrictModeError(cx, TS(tc->compiler), tc, pn, - JSMSG_DUPLICATE_FORMAL, name)) { + !ReportStrictModeError(cx, TS(tc->compiler), tc, pn, JSMSG_DUPLICATE_FORMAL, name)) { return false; } } @@ -1264,8 +1255,7 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, JS_ASSERT(dn->pn_atom == atom); const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportStrictModeError(cx, TS(tc->compiler), tc, dn, - JSMSG_BAD_BINDING, name)) { + !ReportStrictModeError(cx, TS(tc->compiler), tc, dn, JSMSG_BAD_BINDING, name)) { return false; } } @@ -1615,9 +1605,9 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr if (pn) { if (!CheckStrictFormals(cx, &funcg, fun, pn)) { pn = NULL; - } else if (!js_MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { - js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, - JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); + } else if (!MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { + ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); pn = NULL; } else if (!js_FoldConstants(cx, pn, &funcg)) { /* js_FoldConstants reported the error already. */ @@ -1707,8 +1697,8 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSLocalKind localKind = js_LookupLocal(cx, tc->fun, atom, NULL); if (localKind != JSLOCAL_NONE) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, - JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG); + ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, JSREPORT_ERROR, + JSMSG_DESTRUCT_DUP_ARG); return JS_FALSE; } JS_ASSERT(!tc->decls.lookup(atom)); @@ -1756,21 +1746,20 @@ JSCompiler::newFunction(JSTreeContext *tc, JSAtom *atom, uintN lambda) } static JSBool -MatchOrInsertSemicolon(JSContext *cx, JSTokenStream *ts) +MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) { - JSTokenType tt; + TokenType tt; ts->flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(cx, ts); + tt = PeekTokenSameLine(cx, ts); ts->flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return JS_FALSE; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, - JSMSG_SEMI_BEFORE_STMNT); + ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT); return JS_FALSE; } - (void) js_MatchToken(cx, ts, TOK_SEMI); + (void) MatchToken(cx, ts, TOK_SEMI); return JS_TRUE; } @@ -2158,7 +2147,7 @@ static void DeoptimizeUsesWithin(JSDefinition *dn, JSFunctionBox *funbox, uint32& tcflags) { uintN ndeoptimized = 0; - const JSTokenPos &pos = funbox->node->pn_body->pn_pos; + const TokenPos &pos = funbox->node->pn_body->pn_pos; for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { JS_ASSERT(pnu->pn_used); @@ -2578,7 +2567,7 @@ JSCompiler::functionDef(uintN lambda) { JSOp op; JSParseNode *pn, *body, *result; - JSTokenType tt; + TokenType tt; JSAtom *funAtom; JSAtomListElement *ale; #if JS_HAS_DESTRUCTURING @@ -2610,18 +2599,18 @@ JSCompiler::functionDef(uintN lambda) /* Scan the optional function name into funAtom. */ tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_NAME) { funAtom = tokenStream.currentToken().t_atom; } else { if (lambda == 0 && (context->options & JSOPTION_ANONFUNFIX)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } funAtom = NULL; - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } /* @@ -2640,13 +2629,13 @@ JSCompiler::functionDef(uintN lambda) if (JS_HAS_STRICT_OPTION(context) || dn_kind == JSDefinition::CONST) { const char *name = js_AtomToPrintableString(context, funAtom); if (!name || - !js_ReportCompileErrorNumber(context, &tokenStream, NULL, - (dn_kind != JSDefinition::CONST) - ? JSREPORT_WARNING | JSREPORT_STRICT - : JSREPORT_ERROR, - JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), - name)) { + !ReportCompileErrorNumber(context, &tokenStream, NULL, + (dn_kind != JSDefinition::CONST) + ? JSREPORT_WARNING | JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + JSDefinition::kindString(dn_kind), + name)) { return NULL; } } @@ -2747,9 +2736,9 @@ JSCompiler::functionDef(uintN lambda) /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); - if (!js_MatchToken(context, &tokenStream, TOK_RP)) { + if (!MatchToken(context, &tokenStream, TOK_RP)) { do { - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -2841,8 +2830,8 @@ JSCompiler::functionDef(uintN lambda) } default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_MISSING_FORMAL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_MISSING_FORMAL); /* FALL THROUGH */ case TOK_ERROR: return NULL; @@ -2850,22 +2839,22 @@ JSCompiler::functionDef(uintN lambda) #if JS_HAS_DESTRUCTURING report_dup_and_destructuring: JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg)); - js_ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, - JSMSG_DESTRUCT_DUP_ARG); + ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, + JSMSG_DESTRUCT_DUP_ARG); return NULL; #endif } - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); } #if JS_HAS_EXPR_CLOSURES tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt != TOK_LC) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); fun->flags |= JSFUN_EXPR_CLOSURE; } #else @@ -3059,7 +3048,7 @@ JSParseNode * JSCompiler::statements() { JSParseNode *pn, *pn2, *saveBlock; - JSTokenType tt; + TokenType tt; bool inDirectivePrologue = tc->atTopLevel(); JS_CHECK_RECURSION(context, return NULL); @@ -3075,7 +3064,7 @@ JSCompiler::statements() for (;;) { tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF || tt == TOK_RC) { if (tt == TOK_ERROR) { @@ -3141,26 +3130,24 @@ JSCompiler::condition() if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP && !pn->pn_parens && - !js_ReportCompileErrorNumber(context, &tokenStream, NULL, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_EQUAL_AS_ASSIGN, - "")) { + !ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_EQUAL_AS_ASSIGN, "")) { return NULL; } return pn; } static JSBool -MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn) +MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn) { JSAtom *label; - JSTokenType tt; + TokenType tt; - tt = js_PeekTokenSameLine(cx, ts); + tt = PeekTokenSameLine(cx, ts); if (tt == TOK_ERROR) return JS_FALSE; if (tt == TOK_NAME) { - (void) js_GetToken(cx, ts); + (void) GetToken(cx, ts); label = ts->currentToken().t_atom; } else { label = NULL; @@ -3192,20 +3179,20 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (ale && ALE_DEFN(ale)->pn_blockid == tc->blockid()) { const char *name = js_AtomToPrintableString(cx, atom); if (name) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_REDECLARED_VAR, - (ale && ALE_DEFN(ale)->isConst()) - ? js_const_str - : js_variable_str, - name); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_REDECLARED_VAR, + (ale && ALE_DEFN(ale)->isConst()) + ? js_const_str + : js_variable_str, + name); } return JS_FALSE; } n = OBJ_BLOCK_COUNT(cx, blockObj); if (n == JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, data->let.overflow); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, data->let.overflow); return JS_FALSE; } @@ -3315,14 +3302,14 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) return JS_FALSE; if (op == JSOP_DEFCONST) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, - name); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, + name); return JS_FALSE; } - if (!js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_VAR_HIDES_ARG, name)) { + if (!ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_VAR_HIDES_ARG, name)) { return JS_FALSE; } } else { @@ -3336,13 +3323,13 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) : error) { name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - !error - ? JSREPORT_WARNING | JSREPORT_STRICT - : JSREPORT_ERROR, - JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), - name)) { + !ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + !error + ? JSREPORT_WARNING | JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + JSDefinition::kindString(dn_kind), + name)) { return JS_FALSE; } } @@ -3518,7 +3505,7 @@ MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL || pn->pn_op == JSOP_APPLY); pn2 = pn->pn_head; if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, msg); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, msg); return JS_FALSE; } pn->pn_op = JSOP_SETCALL; @@ -3655,8 +3642,8 @@ BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) #endif default: - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); return JS_FALSE; } @@ -3853,15 +3840,15 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *lhs, *rhs, *pn, *pn2; if (left->pn_type == TOK_ARRAYCOMP) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), left, - JSREPORT_ERROR, JSMSG_ARRAY_COMP_LEFTSIDE); + ReportCompileErrorNumber(cx, TS(tc->compiler), left, JSREPORT_ERROR, + JSMSG_ARRAY_COMP_LEFTSIDE); return JS_FALSE; } #if JS_HAS_DESTRUCTURING_SHORTHAND if (right && right->pn_arity == PN_LIST && (right->pn_xflags & PNX_DESTRUCT)) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), right, - JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + ReportCompileErrorNumber(cx, TS(tc->compiler), right, JSREPORT_ERROR, + JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif @@ -3968,8 +3955,8 @@ CheckDestructuring(JSContext *cx, BindData *data, return ok; no_var_name: - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); ok = JS_FALSE; goto out; } @@ -4002,8 +3989,8 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) #if JS_HAS_DESTRUCTURING_SHORTHAND if (right->pn_arity == PN_LIST && (right->pn_xflags & PNX_DESTRUCT)) { - js_ReportCompileErrorNumber(tc->compiler->context, TS(tc->compiler), right, - JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + ReportCompileErrorNumber(tc->compiler->context, TS(tc->compiler), right, JSREPORT_ERROR, + JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif @@ -4055,7 +4042,7 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) } JSParseNode * -JSCompiler::destructuringExpr(BindData *data, JSTokenType tt) +JSCompiler::destructuringExpr(BindData *data, TokenType tt) { JSParseNode *pn; @@ -4179,7 +4166,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) extern const char js_with_statement_str[]; static JSParseNode * -ContainsStmt(JSParseNode *pn, JSTokenType tt) +ContainsStmt(JSParseNode *pn, TokenType tt) { JSParseNode *pn2, *pnt; @@ -4230,13 +4217,13 @@ ContainsStmt(JSParseNode *pn, JSTokenType tt) JSParseNode * JSCompiler::returnOrYield(bool useAssignExpr) { - JSTokenType tt, tt2; + TokenType tt, tt2; JSParseNode *pn, *pn2; tt = tokenStream.currentToken().type; if (tt == TOK_RETURN && !(tc->flags & TCF_IN_FUNCTION)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return NULL; } @@ -4251,7 +4238,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) /* This is ugly, but we don't want to require a semicolon. */ tokenStream.flags |= TSF_OPERAND; - tt2 = js_PeekTokenSameLine(context, &tokenStream); + tt2 = PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt2 == TOK_ERROR) return NULL; @@ -4299,7 +4286,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) } static JSParseNode * -PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, +PushLexicalScope(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSStmtInfo *stmt) { JSParseNode *pn; @@ -4362,7 +4349,7 @@ JSCompiler::letBlock(JSBool statement) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET); tokenStream.flags |= TSF_OPERAND; - if (statement && !js_MatchToken(context, &tokenStream, TOK_LC)) { + if (statement && !MatchToken(context, &tokenStream, TOK_LC)) { /* * If this is really an expression in let statement guise, then we * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop @@ -4531,7 +4518,7 @@ RebindLets(JSParseNode *pn, JSTreeContext *tc) JSParseNode * JSCompiler::statement() { - JSTokenType tt; + TokenType tt; JSParseNode *pn, *pn1, *pn2, *pn3, *pn4; JSStmtInfo stmtInfo, *stmt, *stmt2; JSAtom *label; @@ -4539,7 +4526,7 @@ JSCompiler::statement() JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_GETTER_SETTER @@ -4554,7 +4541,7 @@ JSCompiler::statement() case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_DBLCOLON) goto expression; @@ -4574,7 +4561,7 @@ JSCompiler::statement() if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND; - if (js_MatchToken(context, &tokenStream, TOK_ELSE)) { + if (MatchToken(context, &tokenStream, TOK_ELSE)) { tokenStream.flags &= ~TSF_OPERAND; stmtInfo.type = STMT_ELSE; pn3 = statement(); @@ -4626,12 +4613,12 @@ JSCompiler::statement() saveBlock = tc->blockNode; tc->blockNode = pn2; - while ((tt = js_GetToken(context, &tokenStream)) != TOK_RC) { + while ((tt = GetToken(context, &tokenStream)) != TOK_RC) { switch (tt) { case TOK_DEFAULT: if (seenDefault) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOO_MANY_DEFAULTS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_DEFAULTS); return NULL; } seenDefault = JS_TRUE; @@ -4648,8 +4635,8 @@ JSCompiler::statement() } pn2->append(pn3); if (pn2->pn_count == JS_BIT(16)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOO_MANY_CASES); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_CASES); return NULL; } break; @@ -4658,8 +4645,8 @@ JSCompiler::statement() return NULL; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_SWITCH); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_SWITCH); return NULL; } MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); @@ -4670,7 +4657,7 @@ JSCompiler::statement() pn4->pn_type = TOK_LC; pn4->makeEmpty(); tokenStream.flags |= TSF_OPERAND; - while ((tt = js_PeekToken(context, &tokenStream)) != TOK_RC && + while ((tt = PeekToken(context, &tokenStream)) != TOK_RC && tt != TOK_CASE && tt != TOK_DEFAULT) { tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) @@ -4747,7 +4734,7 @@ JSCompiler::statement() * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ - (void) js_MatchToken(context, &tokenStream, TOK_SEMI); + (void) MatchToken(context, &tokenStream, TOK_SEMI); return pn; } break; @@ -4768,16 +4755,16 @@ JSCompiler::statement() pn->pn_op = JSOP_ITER; pn->pn_iflags = 0; - if (js_MatchToken(context, &tokenStream, TOK_NAME)) { + if (MatchToken(context, &tokenStream, TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn->pn_iflags = JSITER_FOREACH; else - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_BLOCK_SCOPE @@ -4806,13 +4793,13 @@ JSCompiler::statement() */ tc->flags |= TCF_IN_FOR_INIT; if (tt == TOK_VAR) { - (void) js_GetToken(context, &tokenStream); + (void) GetToken(context, &tokenStream); pn1 = variables(false); #if JS_HAS_BLOCK_SCOPE } else if (tt == TOK_LET) { let = true; - (void) js_GetToken(context, &tokenStream); - if (js_PeekToken(context, &tokenStream) == TOK_LP) { + (void) GetToken(context, &tokenStream); + if (PeekToken(context, &tokenStream) == TOK_LP) { pn1 = letBlock(JS_FALSE); tt = TOK_LEXICALSCOPE; } else { @@ -4837,13 +4824,13 @@ JSCompiler::statement() * as we've excluded 'in' from being parsed in RelExpr by setting * the TCF_IN_FOR_INIT flag in our JSTreeContext. */ - if (pn1 && js_MatchToken(context, &tokenStream, TOK_IN)) { + if (pn1 && MatchToken(context, &tokenStream, TOK_IN)) { pn->pn_iflags |= JSITER_ENUMERATE; stmtInfo.type = STMT_FOR_IN_LOOP; /* Check that the left side of the 'in' is valid. */ - JS_ASSERT(!TOKEN_TYPE_IS_DECL(tt) || PN_TYPE(pn1) == tt); - if (TOKEN_TYPE_IS_DECL(tt) + JS_ASSERT(!TokenTypeIsDecl(tt) || PN_TYPE(pn1) == tt); + if (TokenTypeIsDecl(tt) ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST #if JS_HAS_DESTRUCTURING || (JSVERSION_NUMBER(context) == JSVERSION_1_7 && @@ -4872,8 +4859,8 @@ JSCompiler::statement() pn1->pn_op != JSOP_XMLNAME) && #endif pn1->pn_type != TOK_LB)) { - js_ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -4881,7 +4868,7 @@ JSCompiler::statement() pn2 = NULL; uintN dflag = PND_ASSIGNED; - if (TOKEN_TYPE_IS_DECL(tt)) { + if (TokenTypeIsDecl(tt)) { /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */ pn1->pn_xflags |= PNX_FORINVAR; @@ -5041,7 +5028,7 @@ JSCompiler::statement() /* Parse the loop condition or null into pn2. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_SEMI) { pn2 = NULL; @@ -5054,7 +5041,7 @@ JSCompiler::statement() /* Parse the update expression or null into pn3. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RP) { pn3 = NULL; @@ -5103,8 +5090,8 @@ JSCompiler::statement() return pn; bad_for_each: - js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_FOR_EACH_LOOP); + ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_FOR_EACH_LOOP); return NULL; } @@ -5143,7 +5130,7 @@ JSCompiler::statement() PopStatement(tc); catchList = NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_CATCH) { catchList = ListNode::create(tc); if (!catchList) @@ -5158,8 +5145,8 @@ JSCompiler::statement() /* Check for another catch after unconditional catch. */ if (lastCatch && !lastCatch->pn_kid2) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_AFTER_GENERAL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_AFTER_GENERAL); return NULL; } @@ -5195,7 +5182,7 @@ JSCompiler::statement() data.binder = BindLet; data.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -5217,8 +5204,8 @@ JSCompiler::statement() break; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_IDENTIFIER); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_IDENTIFIER); return NULL; } @@ -5229,7 +5216,7 @@ JSCompiler::statement() * to avoid conflicting with the JS2/ECMAv4 type annotation * catchguard syntax. */ - if (js_MatchToken(context, &tokenStream, TOK_IF)) { + if (MatchToken(context, &tokenStream, TOK_IF)) { pn2->pn_kid2 = expr(); if (!pn2->pn_kid2) return NULL; @@ -5247,7 +5234,7 @@ JSCompiler::statement() catchList->append(pnblock); lastCatch = pn2; tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; } while (tt == TOK_CATCH); } @@ -5263,11 +5250,11 @@ JSCompiler::statement() MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); PopStatement(tc); } else { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } if (!catchList && !pn->pn_kid3) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_OR_FINALLY); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_OR_FINALLY); return NULL; } return pn; @@ -5280,13 +5267,13 @@ JSCompiler::statement() /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ tokenStream.flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(context, &tokenStream); + tt = PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } @@ -5300,13 +5287,13 @@ JSCompiler::statement() /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ case TOK_CATCH: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_WITHOUT_TRY); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_WITHOUT_TRY); return NULL; case TOK_FINALLY: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_FINALLY_WITHOUT_TRY); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_FINALLY_WITHOUT_TRY); return NULL; case TOK_BREAK: @@ -5320,8 +5307,8 @@ JSCompiler::statement() if (label) { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_LABEL_NOT_FOUND); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL && stmt->label == label) @@ -5330,8 +5317,8 @@ JSCompiler::statement() } else { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOUGH_BREAK); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOUGH_BREAK); return NULL; } if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH) @@ -5353,15 +5340,15 @@ JSCompiler::statement() if (label) { for (stmt2 = NULL; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL) { if (stmt->label == label) { if (!stmt2 || !STMT_IS_LOOP(stmt2)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); return NULL; } break; @@ -5373,8 +5360,8 @@ JSCompiler::statement() } else { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); return NULL; } if (STMT_IS_LOOP(stmt)) @@ -5389,14 +5376,14 @@ JSCompiler::statement() /* * In most cases, we want the constructs forbidden in strict mode * code to be a subset of those that JSOPTION_STRICT warns about, and - * we should use js_ReportStrictModeError. However, 'with' is the sole + * we should use ReportStrictModeError. However, 'with' is the sole * instance of a construct that is forbidden in strict mode code, but * doesn't even merit a warning under JSOPTION_STRICT. See * https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. */ if (tc->flags & TCF_STRICT_MODE_CODE) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_STRICT_CODE_WITH); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_STRICT_CODE_WITH); return NULL; } @@ -5437,7 +5424,7 @@ JSCompiler::statement() JSObjectBox *blockbox; /* Check for a let statement or let expression. */ - if (js_PeekToken(context, &tokenStream) == TOK_LP) { + if (PeekToken(context, &tokenStream) == TOK_LP) { pn = letBlock(JS_TRUE); if (!pn || pn->pn_op == JSOP_LEAVEBLOCK) return pn; @@ -5462,8 +5449,8 @@ JSCompiler::statement() stmt = tc->topStmt; if (stmt && (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_LET_DECL_NOT_IN_BLOCK); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_LET_DECL_NOT_IN_BLOCK); return NULL; } @@ -5607,14 +5594,14 @@ JSCompiler::statement() pn = UnaryNode::create(tc); if (!pn) return NULL; - if (!js_MatchToken(context, &tokenStream, TOK_NAME) || + if (!MatchToken(context, &tokenStream, TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.xmlAtom || - !js_MatchToken(context, &tokenStream, TOK_NAME) || + !MatchToken(context, &tokenStream, TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.namespaceAtom || - !js_MatchToken(context, &tokenStream, TOK_ASSIGN) || + !MatchToken(context, &tokenStream, TOK_ASSIGN) || tokenStream.currentToken().t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_DEFAULT_XML_NAMESPACE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_DEFAULT_XML_NAMESPACE); return NULL; } @@ -5636,28 +5623,28 @@ JSCompiler::statement() #if JS_HAS_XML_SUPPORT expression: #endif - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); pn2 = expr(); if (!pn2) return NULL; - if (js_PeekToken(context, &tokenStream) == TOK_COLON) { + if (PeekToken(context, &tokenStream) == TOK_COLON) { if (pn2->pn_type != TOK_NAME) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_LABEL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_LABEL); return NULL; } label = pn2->pn_atom; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_LABEL && stmt->label == label) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_DUPLICATE_LABEL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_DUPLICATE_LABEL); return NULL; } } ForgetUse(pn2); - (void) js_GetToken(context, &tokenStream); + (void) GetToken(context, &tokenStream); /* Push a label struct and parse the statement. */ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); @@ -5737,7 +5724,7 @@ NoteArgumentsUse(JSTreeContext *tc) JSParseNode * JSCompiler::variables(bool inLetHead) { - JSTokenType tt; + TokenType tt; bool let; JSStmtInfo *scopeStmt; BindData data; @@ -5790,7 +5777,7 @@ JSCompiler::variables(bool inLetHead) } do { - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); #if JS_HAS_DESTRUCTURING if (tt == TOK_LB || tt == TOK_LC) { tc->flags |= TCF_DECL_DESTRUCTURING; @@ -5802,7 +5789,7 @@ JSCompiler::variables(bool inLetHead) if (!CheckDestructuring(context, &data, pn2, NULL, tc)) return NULL; if ((tc->flags & TCF_IN_FOR_INIT) && - js_PeekToken(context, &tokenStream) == TOK_IN) { + PeekToken(context, &tokenStream) == TOK_IN) { pn->append(pn2); continue; } @@ -5838,8 +5825,8 @@ JSCompiler::variables(bool inLetHead) if (tt != TOK_NAME) { if (tt != TOK_ERROR) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); } return NULL; } @@ -5855,7 +5842,7 @@ JSCompiler::variables(bool inLetHead) return NULL; pn->append(pn2); - if (js_MatchToken(context, &tokenStream, TOK_ASSIGN)) { + if (MatchToken(context, &tokenStream, TOK_ASSIGN)) { if (tokenStream.currentToken().t_op != JSOP_NOP) goto bad_var_init; @@ -5905,14 +5892,14 @@ JSCompiler::variables(bool inLetHead) tc->flags |= TCF_FUN_HEAVYWEIGHT; } } - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; return pn; bad_var_init: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_VAR_INIT); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_VAR_INIT); return NULL; } @@ -5922,7 +5909,7 @@ JSCompiler::expr() JSParseNode *pn, *pn2; pn = assignExpr(); - if (pn && js_MatchToken(context, &tokenStream, TOK_COMMA)) { + if (pn && MatchToken(context, &tokenStream, TOK_COMMA)) { pn2 = ListNode::create(tc); if (!pn2) return NULL; @@ -5933,9 +5920,9 @@ JSCompiler::expr() #if JS_HAS_GENERATORS pn2 = pn->last(); if (pn2->pn_type == TOK_YIELD && !pn2->pn_parens) { - js_ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return NULL; } #endif @@ -5943,7 +5930,7 @@ JSCompiler::expr() if (!pn2) return NULL; pn->append(pn2); - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; } return pn; @@ -5953,14 +5940,14 @@ JSParseNode * JSCompiler::assignExpr() { JSParseNode *pn, *rhs; - JSTokenType tt; + TokenType tt; JSOp op; JS_CHECK_RECURSION(context, return NULL); #if JS_HAS_GENERATORS tokenStream.flags |= TSF_OPERAND; - if (js_MatchToken(context, &tokenStream, TOK_YIELD)) { + if (MatchToken(context, &tokenStream, TOK_YIELD)) { tokenStream.flags &= ~TSF_OPERAND; return returnOrYield(true); } @@ -5971,7 +5958,7 @@ JSCompiler::assignExpr() if (!pn) return NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { tt = CheckGetterOrSetter(context, &tokenStream, TOK_ASSIGN); @@ -5980,7 +5967,7 @@ JSCompiler::assignExpr() } #endif if (tt != TOK_ASSIGN) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); return pn; } @@ -6002,8 +5989,8 @@ JSCompiler::assignExpr() case TOK_RB: case TOK_RC: if (op != JSOP_NOP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_DESTRUCT_ASS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_DESTRUCT_ASS); return NULL; } rhs = assignExpr(); @@ -6024,8 +6011,8 @@ JSCompiler::assignExpr() /* FALL THROUGH */ #endif default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_LEFTSIDE_OF_ASS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_LEFTSIDE_OF_ASS); return NULL; } @@ -6056,7 +6043,7 @@ JSCompiler::condExpr() uintN oldflags; pn = orExpr(); - if (pn && js_MatchToken(context, &tokenStream, TOK_HOOK)) { + if (pn && MatchToken(context, &tokenStream, TOK_HOOK)) { pn1 = pn; pn = TernaryNode::create(tc); if (!pn) @@ -6092,7 +6079,7 @@ JSCompiler::orExpr() JSParseNode *pn; pn = andExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_OR)) + while (pn && MatchToken(context, &tokenStream, TOK_OR)) pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr(), tc); return pn; } @@ -6103,7 +6090,7 @@ JSCompiler::andExpr() JSParseNode *pn; pn = bitOrExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_AND)) + while (pn && MatchToken(context, &tokenStream, TOK_AND)) pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr(), tc); return pn; } @@ -6114,7 +6101,7 @@ JSCompiler::bitOrExpr() JSParseNode *pn; pn = bitXorExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_BITOR)) { + while (pn && MatchToken(context, &tokenStream, TOK_BITOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr(), tc); } return pn; @@ -6126,7 +6113,7 @@ JSCompiler::bitXorExpr() JSParseNode *pn; pn = bitAndExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_BITXOR)) { + while (pn && MatchToken(context, &tokenStream, TOK_BITXOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr(), tc); } return pn; @@ -6138,7 +6125,7 @@ JSCompiler::bitAndExpr() JSParseNode *pn; pn = eqExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_BITAND)) + while (pn && MatchToken(context, &tokenStream, TOK_BITAND)) pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr(), tc); return pn; } @@ -6150,7 +6137,7 @@ JSCompiler::eqExpr() JSOp op; pn = relExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_EQOP)) { + while (pn && MatchToken(context, &tokenStream, TOK_EQOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr(), tc); } @@ -6161,7 +6148,7 @@ JSParseNode * JSCompiler::relExpr() { JSParseNode *pn; - JSTokenType tt; + TokenType tt; JSOp op; uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT; @@ -6173,13 +6160,13 @@ JSCompiler::relExpr() pn = shiftExpr(); while (pn && - (js_MatchToken(context, &tokenStream, TOK_RELOP) || + (MatchToken(context, &tokenStream, TOK_RELOP) || /* * Recognize the 'in' token as an operator only if we're not * currently in the init expr of a for loop. */ - (inForInitFlag == 0 && js_MatchToken(context, &tokenStream, TOK_IN)) || - js_MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { + (inForInitFlag == 0 && MatchToken(context, &tokenStream, TOK_IN)) || + MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr(), tc); @@ -6197,7 +6184,7 @@ JSCompiler::shiftExpr() JSOp op; pn = addExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_SHOP)) { + while (pn && MatchToken(context, &tokenStream, TOK_SHOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr(), tc); } @@ -6208,13 +6195,13 @@ JSParseNode * JSCompiler::addExpr() { JSParseNode *pn; - JSTokenType tt; + TokenType tt; JSOp op; pn = mulExpr(); while (pn && - (js_MatchToken(context, &tokenStream, TOK_PLUS) || - js_MatchToken(context, &tokenStream, TOK_MINUS))) { + (MatchToken(context, &tokenStream, TOK_PLUS) || + MatchToken(context, &tokenStream, TOK_MINUS))) { tt = tokenStream.currentToken().type; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, mulExpr(), tc); @@ -6226,13 +6213,13 @@ JSParseNode * JSCompiler::mulExpr() { JSParseNode *pn; - JSTokenType tt; + TokenType tt; JSOp op; pn = unaryExpr(); while (pn && - (js_MatchToken(context, &tokenStream, TOK_STAR) || - js_MatchToken(context, &tokenStream, TOK_DIVOP))) { + (MatchToken(context, &tokenStream, TOK_STAR) || + MatchToken(context, &tokenStream, TOK_DIVOP))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(), tc); @@ -6241,7 +6228,7 @@ JSCompiler::mulExpr() } static JSParseNode * -SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, +SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, JSParseNode *kid, const char *name) { if (kid->pn_type != TOK_NAME && @@ -6252,8 +6239,7 @@ SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) && #endif kid->pn_type != TOK_LB) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, - JSMSG_BAD_OPERAND, name); + ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name); return NULL; } if (!CheckStrictAssignment(cx, tc, kid)) @@ -6265,9 +6251,9 @@ SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, static const char incop_name_str[][10] = {"increment", "decrement"}; static JSBool -SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, +SetIncOpKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, JSParseNode *kid, - JSTokenType tt, JSBool preorder) + TokenType tt, JSBool preorder) { JSOp op; @@ -6315,13 +6301,13 @@ SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSParseNode * JSCompiler::unaryExpr() { - JSTokenType tt; + TokenType tt; JSParseNode *pn, *pn2; JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; switch (tt) { @@ -6377,7 +6363,8 @@ JSCompiler::unaryExpr() } break; case TOK_NAME: - if (!js_ReportStrictModeError(context, &tokenStream, tc, pn, JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!ReportStrictModeError(context, &tokenStream, tc, pn, + JSMSG_DEPRECATED_DELETE_OPERAND)) return NULL; pn2->pn_op = JSOP_DELNAME; break; @@ -6390,7 +6377,7 @@ JSCompiler::unaryExpr() return NULL; default: - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); pn = memberExpr(JS_TRUE); if (!pn) return NULL; @@ -6398,10 +6385,10 @@ JSCompiler::unaryExpr() /* Don't look across a newline boundary for a postfix incop. */ if (tokenStream.onCurrentLine(pn->pn_pos)) { tokenStream.flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(context, &tokenStream); + tt = PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_INC || tt == TOK_DEC) { - (void) js_GetToken(context, &tokenStream); + (void) GetToken(context, &tokenStream); pn2 = UnaryNode::create(tc); if (!pn2) return NULL; @@ -6646,13 +6633,13 @@ CompExprTransplanter::transplant(JSParseNode *pn) */ JSParseNode * JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, - JSTokenType type, JSOp op) + TokenType type, JSOp op) { uintN adjust; JSParseNode *pn, *pn2, *pn3, **pnp; JSStmtInfo stmtInfo; BindData data; - JSTokenType tt; + TokenType tt; JSAtom *atom; JS_ASSERT(tokenStream.currentToken().type == TOK_FOR); @@ -6717,16 +6704,16 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, pn2->pn_op = JSOP_ITER; pn2->pn_iflags = JSITER_ENUMERATE; - if (js_MatchToken(context, &tokenStream, TOK_NAME)) { + if (MatchToken(context, &tokenStream, TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn2->pn_iflags |= JSITER_FOREACH; else - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); atom = NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -6755,8 +6742,8 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, break; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); case TOK_ERROR: return NULL; @@ -6778,8 +6765,8 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, if (JSVERSION_NUMBER(context) == JSVERSION_1_7) { /* Destructuring requires [key, value] enumeration in JS1.7. */ if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -6805,9 +6792,9 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, return NULL; *pnp = pn2; pnp = &pn2->pn_right; - } while (js_MatchToken(context, &tokenStream, TOK_FOR)); + } while (MatchToken(context, &tokenStream, TOK_FOR)); - if (js_MatchToken(context, &tokenStream, TOK_IF)) { + if (MatchToken(context, &tokenStream, TOK_IF)) { pn2 = TernaryNode::create(tc); if (!pn2) return NULL; @@ -6939,7 +6926,7 @@ JSCompiler::argumentList(JSParseNode *listNode) JSBool matched; tokenStream.flags |= TSF_OPERAND; - matched = js_MatchToken(context, &tokenStream, TOK_RP); + matched = MatchToken(context, &tokenStream, TOK_RP); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { do { @@ -6949,15 +6936,15 @@ JSCompiler::argumentList(JSParseNode *listNode) #if JS_HAS_GENERATORS if (argNode->pn_type == TOK_YIELD && !argNode->pn_parens && - js_PeekToken(context, &tokenStream) == TOK_COMMA) { - js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + PeekToken(context, &tokenStream) == TOK_COMMA) { + ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return JS_FALSE; } #endif #if JS_HAS_GENERATOR_EXPRS - if (js_MatchToken(context, &tokenStream, TOK_FOR)) { + if (MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pn = UnaryNode::create(tc); if (!pn) return JS_FALSE; @@ -6965,20 +6952,20 @@ JSCompiler::argumentList(JSParseNode *listNode) if (!argNode) return JS_FALSE; if (listNode->pn_count > 1 || - js_PeekToken(context, &tokenStream) == TOK_COMMA) { - js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + PeekToken(context, &tokenStream) == TOK_COMMA) { + ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); return JS_FALSE; } } #endif listNode->append(argNode); - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); - if (js_GetToken(context, &tokenStream) != TOK_RP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_PAREN_AFTER_ARGS); + if (GetToken(context, &tokenStream) != TOK_RP) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_PAREN_AFTER_ARGS); return JS_FALSE; } } @@ -7004,13 +6991,13 @@ JSParseNode * JSCompiler::memberExpr(JSBool allowCallSyntax) { JSParseNode *pn, *pn2, *pn3; - JSTokenType tt; + TokenType tt; JS_CHECK_RECURSION(context, return NULL); /* Check for new expression first. */ tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_NEW) { pn = ListNode::create(tc); @@ -7024,7 +7011,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn->initList(pn2); pn->pn_pos.begin = pn2->pn_pos.begin; - if (js_MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) + if (MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) return NULL; if (pn->pn_count > ARGC_LIMIT) { JS_ReportErrorNumber(context, js_GetErrorMessage, NULL, @@ -7053,14 +7040,14 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } } - while ((tt = js_GetToken(context, &tokenStream)) > TOK_EOF) { + while ((tt = GetToken(context, &tokenStream)) > TOK_EOF) { if (tt == TOK_DOT) { pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7079,12 +7066,12 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) /* A filtering predicate is like a with statement. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; - } else if (TOKEN_TYPE_IS_XML(PN_TYPE(pn3))) { + } else if (TokenTypeIsXML(PN_TYPE(pn3))) { pn2->pn_type = TOK_LB; pn2->pn_op = JSOP_GETELEM; } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); return NULL; } pn2->pn_arity = PN_BINARY; @@ -7107,7 +7094,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7117,9 +7104,9 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn3->pn_type = TOK_STRING; pn3->pn_arity = PN_NULLARY; pn3->pn_op = JSOP_QNAMEPART; - } else if (!TOKEN_TYPE_IS_XML(tt)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); + } else if (!TokenTypeIsXML(tt)) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); return NULL; } pn2->pn_op = JSOP_DESCENDANTS; @@ -7200,7 +7187,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } pn2->pn_pos.end = tokenStream.currentToken().pos.end; } else { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); return pn; } @@ -7321,7 +7308,7 @@ JSParseNode * JSCompiler::qualifiedSuffix(JSParseNode *pn) { JSParseNode *pn2, *pn3; - JSTokenType tt; + TokenType tt; JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON); pn2 = NameNode::create(NULL, tc); @@ -7333,7 +7320,7 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) pn->pn_op = JSOP_NAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { /* Inline and specialize propertySelector for JSOP_QNAMECONST. */ @@ -7348,8 +7335,8 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) } if (tt != TOK_LB) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } pn3 = endBracketedExpr(); @@ -7373,7 +7360,7 @@ JSCompiler::qualifiedIdentifier() pn = propertySelector(); if (!pn) return NULL; - if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; pn = qualifiedSuffix(pn); @@ -7385,7 +7372,7 @@ JSParseNode * JSCompiler::attributeIdentifier() { JSParseNode *pn, *pn2; - JSTokenType tt; + TokenType tt; JS_ASSERT(tokenStream.currentToken().type == TOK_AT); pn = UnaryNode::create(tc); @@ -7393,15 +7380,15 @@ JSCompiler::attributeIdentifier() return NULL; pn->pn_op = JSOP_TOATTRNAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { pn2 = qualifiedIdentifier(); } else if (tt == TOK_LB) { pn2 = endBracketedExpr(); } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } if (!pn2) @@ -7455,7 +7442,7 @@ JSCompiler::xmlAtomNode() JSParseNode *pn = NullaryNode::create(tc); if (!pn) return NULL; - JSToken *tp = tokenStream.mutableCurrentToken(); + Token *tp = tokenStream.mutableCurrentToken(); pn->pn_op = tp->t_op; pn->pn_atom = tp->t_atom; if (tp->type == TOK_XMLPI) @@ -7479,7 +7466,7 @@ JSParseNode * JSCompiler::xmlNameExpr() { JSParseNode *pn, *pn2, *list; - JSTokenType tt; + TokenType tt; pn = list = NULL; do { @@ -7511,9 +7498,9 @@ JSCompiler::xmlNameExpr() pn->pn_pos.end = pn2->pn_pos.end; pn->append(pn2); } - } while ((tt = js_GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); + } while ((tt = GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); return pn; } @@ -7543,10 +7530,10 @@ JSCompiler::xmlNameExpr() * we parsed exactly one expression. */ JSParseNode * -JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) +JSCompiler::xmlTagContent(TokenType tagtype, JSAtom **namep) { JSParseNode *pn, *pn2, *list; - JSTokenType tt; + TokenType tt; pn = xmlNameExpr(); if (!pn) @@ -7554,10 +7541,10 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; list = NULL; - while (js_MatchToken(context, &tokenStream, TOK_XMLSPACE)) { - tt = js_GetToken(context, &tokenStream); + while (MatchToken(context, &tokenStream, TOK_XMLSPACE)) { + tt = GetToken(context, &tokenStream); if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); break; } @@ -7577,19 +7564,19 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) if (!XML_FOLDABLE(pn2)) pn->pn_xflags |= PNX_CANTFOLD; - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_XMLATTR) { pn2 = xmlAtomNode(); } else if (tt == TOK_LC) { pn2 = xmlExpr(JS_TRUE); pn->pn_xflags |= PNX_CANTFOLD; } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_ATTR_VALUE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_ATTR_VALUE); return NULL; } if (!pn2) @@ -7601,15 +7588,15 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) return pn; } -#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ - JS_BEGIN_MACRO \ - if ((tt) <= TOK_EOF) { \ - if ((tt) == TOK_EOF) { \ - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ - JSMSG_END_OF_XML_SOURCE); \ - } \ - return result; \ - } \ +#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ + JS_BEGIN_MACRO \ + if ((tt) <= TOK_EOF) { \ + if ((tt) == TOK_EOF) { \ + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ + JSMSG_END_OF_XML_SOURCE); \ + } \ + return result; \ + } \ JS_END_MACRO /* @@ -7619,14 +7606,14 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) JSBool JSCompiler::xmlElementContent(JSParseNode *pn) { - JSTokenType tt; + TokenType tt; JSParseNode *pn2; JSAtom *textAtom; tokenStream.flags &= ~TSF_XMLTAGMODE; for (;;) { tokenStream.flags |= TSF_XMLTEXTMODE; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_XMLTEXTMODE; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); @@ -7642,7 +7629,7 @@ JSCompiler::xmlElementContent(JSParseNode *pn) } tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); if (tt == TOK_XMLETAGO) @@ -7680,7 +7667,7 @@ JSParseNode * JSCompiler::xmlElementOrList(JSBool allowList) { JSParseNode *pn, *pn2, *list; - JSTokenType tt; + TokenType tt; JSAtom *startAtom, *endAtom; JS_CHECK_RECURSION(context, return NULL); @@ -7691,7 +7678,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; tokenStream.flags |= TSF_XMLTAGMODE; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_ERROR) return NULL; @@ -7702,9 +7689,9 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn2 = xmlTagContent(TOK_XMLSTAGO, &startAtom); if (!pn2) return NULL; - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_XMLPTAGC) { /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ if (pn2->pn_type == TOK_XMLSTAGO) { @@ -7723,8 +7710,8 @@ JSCompiler::xmlElementOrList(JSBool allowList) } else { /* We had better have a tag-close (>) at this point. */ if (tt != TOK_XMLTAGC) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } pn2->pn_pos.end = tokenStream.currentToken().pos.end; @@ -7752,11 +7739,11 @@ JSCompiler::xmlElementOrList(JSBool allowList) if (!xmlElementContent(pn)) return NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } @@ -7766,18 +7753,16 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; if (pn2->pn_type == TOK_XMLETAGO) { /* Oops, end tag has attributes! */ - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } if (endAtom && startAtom && endAtom != startAtom) { JSString *str = ATOM_TO_STRING(startAtom); /* End vs. start tag name mismatch: point to the tag name. */ - js_ReportCompileErrorNumber(context, &tokenStream, pn2, - JSREPORT_UC | JSREPORT_ERROR, - JSMSG_XML_TAG_NAME_MISMATCH, - str->chars()); + ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_UC | JSREPORT_ERROR, + JSMSG_XML_TAG_NAME_MISMATCH, str->chars()); return NULL; } @@ -7794,7 +7779,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn->pn_xflags |= PNX_CANTFOLD; } - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); } @@ -7811,8 +7796,8 @@ JSCompiler::xmlElementOrList(JSBool allowList) MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX); } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_NAME_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_NAME_SYNTAX); return NULL; } @@ -7852,13 +7837,13 @@ JSCompiler::parseXMLText(JSObject *chain, bool allowList) /* Set XML-only mode to turn off special treatment of {expr} in XML. */ tokenStream.flags |= TSF_OPERAND | TSF_XMLONLYMODE; - JSTokenType tt = js_GetToken(context, &tokenStream); + TokenType tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; JSParseNode *pn; if (tt != TOK_XMLSTAGO) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); pn = NULL; } else { pn = xmlElementOrListRoot(allowList); @@ -7905,7 +7890,7 @@ BlockIdInScope(uintN blockid, JSTreeContext *tc) #endif JSParseNode * -JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) +JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) { JSParseNode *pn, *pn2, *pn3; JSOp op; @@ -7924,7 +7909,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; pn2 = NullaryNode::create(tc); if (!pn2) @@ -7959,18 +7944,18 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) #endif tokenStream.flags |= TSF_OPERAND; - matched = js_MatchToken(context, &tokenStream, TOK_RB); + matched = MatchToken(context, &tokenStream, TOK_RB); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { for (index = 0; ; index++) { if (index == JS_ARGS_LENGTH_MAX) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_ARRAY_INIT_TOO_BIG); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_ARRAY_INIT_TOO_BIG); return NULL; } tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RB) { pn->pn_xflags |= PNX_ENDCOMMA; @@ -7979,7 +7964,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) if (tt == TOK_COMMA) { /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ - js_MatchToken(context, &tokenStream, TOK_COMMA); + MatchToken(context, &tokenStream, TOK_COMMA); pn2 = NullaryNode::create(tc); pn->pn_xflags |= PNX_HOLEY; } else { @@ -7991,7 +7976,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) if (tt != TOK_COMMA) { /* If we didn't already match TOK_COMMA in above case. */ - if (!js_MatchToken(context, &tokenStream, TOK_COMMA)) + if (!MatchToken(context, &tokenStream, TOK_COMMA)) break; } } @@ -8041,7 +8026,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) */ if (index == 0 && pn->pn_count != 0 && - js_MatchToken(context, &tokenStream, TOK_FOR)) { + MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pnexp, *pntop; /* Relabel pn as an array comprehension node. */ @@ -8098,7 +8083,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) for (;;) { JSAtom *atom; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; switch (tt) { case TOK_NUMBER: @@ -8123,10 +8108,10 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) goto property_name; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt != TOK_NAME) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); goto property_name; } atom = tokenStream.currentToken().t_atom; @@ -8153,12 +8138,12 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) case TOK_RC: goto end_obj_init; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_PROP_ID); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_PROP_ID); return NULL; } - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); op = JSOP_INITPROP; #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { @@ -8175,8 +8160,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) #if JS_HAS_DESTRUCTURING_SHORTHAND if (tt != TOK_COMMA && tt != TOK_RC) { #endif - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_COLON_AFTER_ID); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_COLON_AFTER_ID); return NULL; #if JS_HAS_DESTRUCTURING_SHORTHAND } @@ -8185,7 +8170,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) * Support, e.g., |var {x, y} = o| as destructuring shorthand * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8. */ - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); pn->pn_xflags |= PNX_DESTRUCT; pnval = pn3; if (pnval->pn_type == TOK_NAME) { @@ -8226,8 +8211,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) if (ALE_INDEX(ale) & attributesMask) { const char *name = js_AtomToPrintableString(context, atom); if (!name || - !js_ReportStrictModeError(context, &tokenStream, tc, NULL, - JSMSG_DUPLICATE_PROPERTY, name)) { + !ReportStrictModeError(context, &tokenStream, tc, NULL, + JSMSG_DUPLICATE_PROPERTY, name)) { return NULL; } } @@ -8240,12 +8225,12 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) } } - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_RC) goto end_obj_init; if (tt != TOK_COMMA) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CURLY_AFTER_LIST); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CURLY_AFTER_LIST); return NULL; } afterComma = JS_TRUE; @@ -8271,7 +8256,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) return NULL; pn->pn_num = (jsint) tokenStream.currentToken().t_dval; tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_USESHARP || tt == TOK_DEFSHARP || #if JS_HAS_XML_SUPPORT @@ -8279,8 +8264,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) tt == TOK_XMLSTAGO /* XXXbe could be sharp? */ || #endif tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_PRIMARY) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_SHARP_VAR_DEF); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_SHARP_VAR_DEF); return NULL; } pn->pn_kid = primaryExpr(tt, JS_FALSE); @@ -8384,7 +8369,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) } } else if ((!afterDot #if JS_HAS_XML_SUPPORT - || js_PeekToken(context, &tokenStream) == TOK_DBLCOLON + || PeekToken(context, &tokenStream) == TOK_DBLCOLON #endif ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) { JSStmtInfo *stmt = js_LexicalLookup(tc, pn->pn_atom, NULL); @@ -8446,7 +8431,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) */ JS_ASSERT(PN_TYPE(dn) == TOK_NAME); JS_ASSERT(dn->pn_op == JSOP_NOP); - if (js_PeekToken(context, &tokenStream) != TOK_LP) + if (PeekToken(context, &tokenStream) != TOK_LP) dn->pn_dflags |= PND_FUNARG; } } @@ -8455,7 +8440,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) LinkUseToDef(pn, dn, tc); /* Here we handle the backward function reference case. */ - if (js_PeekToken(context, &tokenStream) != TOK_LP) + if (PeekToken(context, &tokenStream) != TOK_LP) dn->pn_dflags |= PND_FUNARG; pn->pn_dflags |= (dn->pn_dflags & PND_FUNARG); @@ -8463,7 +8448,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) } #if JS_HAS_XML_SUPPORT - if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { if (afterDot) { JSString *str; @@ -8478,8 +8463,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) pn->pn_arity = PN_NULLARY; pn->pn_type = TOK_FUNCTION; } else if (tt != TOK_EOF) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_KEYWORD_NOT_NS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_KEYWORD_NOT_NS); return NULL; } } @@ -8537,8 +8522,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) return NULL; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } return pn; @@ -8547,7 +8532,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) JSParseNode * JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) { - JSTokenPtr begin; + TokenPtr begin; JSParseNode *pn; JS_ASSERT(tokenStream.currentToken().type == TOK_LP); @@ -8560,18 +8545,15 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; #if JS_HAS_GENERATOR_EXPRS - if (js_MatchToken(context, &tokenStream, TOK_FOR)) { + if (MatchToken(context, &tokenStream, TOK_FOR)) { if (pn->pn_type == TOK_YIELD && !pn->pn_parens) { - js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); return NULL; } if (pn->pn_type == TOK_COMMA && !pn->pn_parens) { - js_ReportCompileErrorNumber(context, &tokenStream, pn->last(), - JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + ReportCompileErrorNumber(context, &tokenStream, pn->last(), JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); return NULL; } if (!pn1) { @@ -8584,10 +8566,9 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; pn->pn_pos.begin = begin; if (genexp) { - if (js_GetToken(context, &tokenStream) != TOK_RP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + if (GetToken(context, &tokenStream) != TOK_RP) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); return NULL; } pn->pn_pos.end = tokenStream.currentToken().pos.end; @@ -8604,7 +8585,7 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) * XXX handles only strings and numbers for now */ static JSBool -FoldType(JSContext *cx, JSParseNode *pn, JSTokenType type) +FoldType(JSContext *cx, JSParseNode *pn, TokenType type) { if (PN_TYPE(pn) != type) { switch (type) { @@ -8727,7 +8708,7 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, static JSBool FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) { - JSTokenType tt; + TokenType tt; JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 396ba74d134d..07f4f34e0cbf 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -296,9 +296,9 @@ struct JSParseNode { pn_defn:1; /* this node is a JSDefinition */ #define PN_OP(pn) ((JSOp)(pn)->pn_op) -#define PN_TYPE(pn) ((JSTokenType)(pn)->pn_type) +#define PN_TYPE(pn) ((js::TokenType)(pn)->pn_type) - JSTokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ + js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ int32 pn_offset; /* first generated bytecode offset */ JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */ JSParseNode *pn_link; /* def/use link (alignment freebie); @@ -387,7 +387,7 @@ struct JSParseNode { #define pn_atom2 pn_u.apair.atom2 protected: - void inline init(JSTokenType type, JSOp op, JSParseNodeArity arity) { + void inline init(js::TokenType type, JSOp op, JSParseNodeArity arity) { pn_type = type; pn_op = op; pn_arity = arity; @@ -400,7 +400,7 @@ protected: static JSParseNode *create(JSParseNodeArity arity, JSTreeContext *tc); public: - static JSParseNode *newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, + static JSParseNode *newBinaryOrAppend(js::TokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, JSTreeContext *tc); /* @@ -493,9 +493,9 @@ public: /* True if pn is a parsenode representing a literal constant. */ bool isLiteral() const { - return PN_TYPE(this) == TOK_NUMBER || - PN_TYPE(this) == TOK_STRING || - (PN_TYPE(this) == TOK_PRIMARY && PN_OP(this) != JSOP_THIS); + return PN_TYPE(this) == js::TOK_NUMBER || + PN_TYPE(this) == js::TOK_STRING || + (PN_TYPE(this) == js::TOK_PRIMARY && PN_OP(this) != JSOP_THIS); } /* @@ -506,10 +506,10 @@ public: * we'll need additional flags that we can test here. */ bool isDirectivePrologueMember() const { - if (PN_TYPE(this) == TOK_SEMI) { + if (PN_TYPE(this) == js::TOK_SEMI) { JS_ASSERT(pn_arity == PN_UNARY); JSParseNode *kid = pn_kid; - return kid && PN_TYPE(kid) == TOK_STRING && !kid->pn_parens; + return kid && PN_TYPE(kid) == js::TOK_STRING && !kid->pn_parens; } return false; } @@ -756,7 +756,7 @@ struct JSDefinition : public JSParseNode JSDefinition *resolve() { JSParseNode *pn = this; while (!pn->pn_defn) { - if (pn->pn_type == TOK_ASSIGN) { + if (pn->pn_type == js::TOK_ASSIGN) { pn = pn->pn_left; continue; } @@ -781,9 +781,9 @@ struct JSDefinition : public JSParseNode static const char *kindString(Kind kind); Kind kind() { - if (PN_TYPE(this) == TOK_FUNCTION) + if (PN_TYPE(this) == js::TOK_FUNCTION) return FUNCTION; - JS_ASSERT(PN_TYPE(this) == TOK_NAME); + JS_ASSERT(PN_TYPE(this) == js::TOK_NAME); if (PN_OP(this) == JSOP_NOP) return UNKNOWN; if (PN_OP(this) == JSOP_GETARG) @@ -916,7 +916,7 @@ struct JSCompiler : private js::AutoGCRooter { JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; - JSTokenStream tokenStream; + js::TokenStream tokenStream; void *tempPoolMark; /* initial JSContext.tempPool mark */ JSPrincipals *principals; /* principals associated with source */ JSStackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */ @@ -1015,7 +1015,7 @@ private: JSParseNode *mulExpr(); JSParseNode *unaryExpr(); JSParseNode *memberExpr(JSBool allowCallSyntax); - JSParseNode *primaryExpr(JSTokenType tt, JSBool afterDot); + JSParseNode *primaryExpr(js::TokenType tt, JSBool afterDot); JSParseNode *parenExpr(JSParseNode *pn1, JSBool *genexp); /* @@ -1026,13 +1026,13 @@ private: JSParseNode *functionDef(uintN lambda); JSParseNode *condition(); JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid, - JSTokenType type = TOK_SEMI, JSOp op = JSOP_NOP); + js::TokenType type = js::TOK_SEMI, JSOp op = JSOP_NOP); JSParseNode *generatorExpr(JSParseNode *pn, JSParseNode *kid); JSBool argumentList(JSParseNode *listNode); JSParseNode *bracketedExpr(); JSParseNode *letBlock(JSBool statement); JSParseNode *returnOrYield(bool useAssignExpr); - JSParseNode *destructuringExpr(BindData *data, JSTokenType tt); + JSParseNode *destructuringExpr(BindData *data, js::TokenType tt); #if JS_HAS_XML_SUPPORT JSParseNode *endBracketedExpr(); @@ -1044,7 +1044,7 @@ private: JSParseNode *xmlExpr(JSBool inTag); JSParseNode *xmlAtomNode(); JSParseNode *xmlNameExpr(); - JSParseNode *xmlTagContent(JSTokenType tagtype, JSAtom **namep); + JSParseNode *xmlTagContent(js::TokenType tagtype, JSAtom **namep); JSBool xmlElementContent(JSParseNode *pn); JSParseNode *xmlElementOrList(JSBool allowList); JSParseNode *xmlElementOrListRoot(JSBool allowList); diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 7773972938f4..6171bd68964e 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -105,10 +105,6 @@ typedef struct JSEmptyScope JSEmptyScope; typedef struct JSTempValueRooter JSTempValueRooter; typedef struct JSThread JSThread; typedef struct JSThreadData JSThreadData; -typedef struct JSToken JSToken; -typedef struct JSTokenPos JSTokenPos; -typedef struct JSTokenPtr JSTokenPtr; -typedef struct JSTokenStream JSTokenStream; typedef struct JSTreeContext JSTreeContext; typedef struct JSTryNote JSTryNote; typedef struct JSWeakRoots JSWeakRoots; @@ -150,6 +146,11 @@ class TraceRecorder; struct TraceMonitor; class CallStack; +struct TokenStream; +struct Token; +struct TokenPos; +struct TokenPtr; + class ContextAllocPolicy; class SystemAllocPolicy; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 20754462d056..4afef943c6c0 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -178,7 +178,7 @@ struct RENode { typedef struct CompilerState { JSContext *context; - JSTokenStream *tokenStream; /* For reporting errors */ + TokenStream *tokenStream; /* For reporting errors */ const jschar *cpbegin; const jschar *cpend; const jschar *cp; @@ -441,9 +441,8 @@ ReportRegExpErrorHelper(CompilerState *state, uintN flags, uintN errorNumber, const jschar *arg) { if (state->tokenStream) { - return js_ReportCompileErrorNumber(state->context, state->tokenStream, - NULL, JSREPORT_UC | flags, - errorNumber, arg); + return ReportCompileErrorNumber(state->context, state->tokenStream, + NULL, JSREPORT_UC | flags, errorNumber, arg); } return JS_ReportErrorFlagsAndNumberUC(state->context, flags, js_GetErrorMessage, NULL, @@ -1958,7 +1957,7 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth, } static JSBool -CompileRegExpToAST(JSContext* cx, JSTokenStream* ts, +CompileRegExpToAST(JSContext* cx, TokenStream* ts, JSString* str, uintN flags, CompilerState& state) { uintN i; @@ -3337,7 +3336,7 @@ GetNativeRegExp(JSContext* cx, JSRegExp* re) #endif JSRegExp * -js_NewRegExp(JSContext *cx, JSTokenStream *ts, +js_NewRegExp(JSContext *cx, TokenStream *ts, JSString *str, uintN flags, JSBool flat) { JSRegExp *re; @@ -5832,7 +5831,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) } JSObject * -js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, +js_NewRegExpObject(JSContext *cx, TokenStream *ts, const jschar *chars, size_t length, uintN flags) { JSString *str; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index b439f0782516..73cfee817450 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -120,7 +120,7 @@ struct JSRegExp { }; extern JSRegExp * -js_NewRegExp(JSContext *cx, JSTokenStream *ts, +js_NewRegExp(JSContext *cx, js::TokenStream *ts, JSString *str, uintN flags, JSBool flat); extern JSRegExp * @@ -183,7 +183,7 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp); * Create, serialize/deserialize, or clone a RegExp object. */ extern JSObject * -js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, +js_NewRegExpObject(JSContext *cx, js::TokenStream *ts, const jschar *chars, size_t length, uintN flags); extern JSBool diff --git a/js/src/jsscan.cpp b/js/src/jsscan.cpp index a3e2b4ddcea4..c832d692442e 100644 --- a/js/src/jsscan.cpp +++ b/js/src/jsscan.cpp @@ -86,7 +86,7 @@ using namespace js; struct keyword { const char *chars; /* C string with keyword text */ - JSTokenType tokentype; /* JSTokenType */ + TokenType tokentype; JSOp op; /* JSOp */ JSVersion version; /* JSVersion */ }; @@ -137,7 +137,7 @@ FindKeyword(const jschar *s, size_t length) return NULL; } -JSTokenType +TokenType js_CheckKeyword(const jschar *str, size_t length) { const struct keyword *kw; @@ -175,7 +175,7 @@ js_IsIdentifier(JSString *str) #endif /* Initialize members that aren't initialized in |init|. */ -JSTokenStream::JSTokenStream(JSContext *cx) +TokenStream::TokenStream(JSContext *cx) : cx(cx), tokens(), cursor(), lookahead(), ungetpos(), ungetbuf(), flags(), linelen(), linepos(), file(), listenerTSData(), saveEOL(), tokenbuf(cx) {} @@ -185,16 +185,15 @@ JSTokenStream::JSTokenStream(JSContext *cx) #endif bool -JSTokenStream::init(const jschar *base, size_t length, - FILE *fp, const char *fn, uintN ln) +TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, uintN ln) { jschar *buf; JS_ASSERT_IF(fp, !base); JS_ASSERT_IF(!base, length == 0); size_t nb = fp - ? 2 * JS_LINE_LIMIT * sizeof(jschar) - : JS_LINE_LIMIT * sizeof(jschar); + ? 2 * LINE_LIMIT * sizeof(jschar) + : LINE_LIMIT * sizeof(jschar); JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb); if (!buf) { js_ReportOutOfScriptQuota(cx); @@ -208,8 +207,8 @@ JSTokenStream::init(const jschar *base, size_t length, linebuf.base = linebuf.limit = linebuf.ptr = buf; if (fp) { file = fp; - userbuf.base = buf + JS_LINE_LIMIT; - userbuf.ptr = userbuf.limit = userbuf.base + JS_LINE_LIMIT; + userbuf.base = buf + LINE_LIMIT; + userbuf.ptr = userbuf.limit = userbuf.base + LINE_LIMIT; } else { userbuf.base = (jschar *)base; userbuf.limit = (jschar *)base + length; @@ -221,7 +220,7 @@ JSTokenStream::init(const jschar *base, size_t length, } void -JSTokenStream::close() +TokenStream::close() { if (flags & TSF_OWNFILENAME) cx->free((void *) filename); @@ -265,12 +264,12 @@ js_fgets(char *buf, int size, FILE *file) } int32 -JSTokenStream::getChar() +TokenStream::getChar() { int32 c; ptrdiff_t i, j, len, olen; JSBool crflag; - char cbuf[JS_LINE_LIMIT]; + char cbuf[LINE_LIMIT]; jschar *ubuf, *nl; if (ungetpos != 0) { @@ -286,7 +285,7 @@ JSTokenStream::getChar() /* Fill userbuf so that \r and \r\n convert to \n. */ crflag = (flags & TSF_CRFLAG) != 0; - len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, file); + len = js_fgets(cbuf, LINE_LIMIT - crflag, file); if (len <= 0) { flags |= TSF_EOF; return EOF; @@ -338,12 +337,12 @@ JSTokenStream::getChar() /* * If there was a line terminator, copy thru it into linebuf. - * Else copy JS_LINE_LIMIT-1 bytes into linebuf. + * Else copy LINE_LIMIT-1 bytes into linebuf. */ if (nl < userbuf.limit) len = (nl - userbuf.ptr) + 1; - if (len >= JS_LINE_LIMIT) { - len = JS_LINE_LIMIT - 1; + if (len >= (ptrdiff_t) LINE_LIMIT) { + len = LINE_LIMIT - 1; saveEOL = nl; } else { saveEOL = NULL; @@ -419,7 +418,7 @@ JSTokenStream::getChar() } void -JSTokenStream::ungetChar(int32 c) +TokenStream::ungetChar(int32 c) { if (c == EOF) return; @@ -435,7 +434,7 @@ JSTokenStream::ungetChar(int32 c) * be used to peek into or past a newline. */ JSBool -JSTokenStream::peekChars(intN n, jschar *cp) +TokenStream::peekChars(intN n, jschar *cp) { intN i, j; int32 c; @@ -456,8 +455,8 @@ JSTokenStream::peekChars(intN n, jschar *cp) } bool -JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, - uintN errorNumber, va_list ap) +TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, + va_list ap) { JSErrorReport report; char *message; @@ -466,11 +465,11 @@ JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, char *linebytes; bool warning; JSBool ok; - JSTokenPos *tp; + TokenPos *tp; uintN index, i; JSErrorReporter onError; - JS_ASSERT(linebuf.limit < linebuf.base + JS_LINE_LIMIT); + JS_ASSERT(linebuf.limit < linebuf.base + LINE_LIMIT); if (JSREPORT_IS_STRICT(flags) && !JS_HAS_STRICT_OPTION(cx)) return JS_TRUE; @@ -625,8 +624,8 @@ JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, } bool -js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParseNode *pn, uintN errorNumber, ...) +js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, + uintN errorNumber, ...) { bool result; va_list ap; @@ -653,14 +652,14 @@ js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } bool -js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, - uintN flags, uintN errorNumber, ...) +js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, + uintN flags, uintN errorNumber, ...) { va_list ap; /* * We don't accept a JSTreeContext argument, so we can't implement - * JSREPORT_STRICT_MODE_ERROR here. Use js_ReportStrictModeError instead, + * JSREPORT_STRICT_MODE_ERROR here. Use ReportStrictModeError instead, * or do the checks in the caller and pass plain old JSREPORT_ERROR. */ JS_ASSERT(!(flags & JSREPORT_STRICT_MODE_ERROR)); @@ -676,7 +675,7 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, #if JS_HAS_XML_SUPPORT JSBool -JSTokenStream::getXMLEntity() +TokenStream::getXMLEntity() { ptrdiff_t offset, length, i; int c, d; @@ -693,8 +692,7 @@ JSTokenStream::getXMLEntity() return JS_FALSE; while ((c = getChar()) != ';') { if (c == EOF || c == '\n') { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_END_OF_XML_ENTITY); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_END_OF_XML_ENTITY); return JS_FALSE; } if (!tb.append(c)) @@ -786,8 +784,7 @@ JSTokenStream::getXMLEntity() JS_ASSERT((tb.end() - bp) >= 1); bytes = js_DeflateString(cx, bp + 1, (tb.end() - bp) - 1); if (bytes) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - msg, bytes); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, msg, bytes); cx->free(bytes); } return JS_FALSE; @@ -801,7 +798,7 @@ JSTokenStream::getXMLEntity() * Otherwise, non-destructively return the original '\'. */ int32 -JSTokenStream::getUnicodeEscape() +TokenStream::getUnicodeEscape() { jschar cp[5]; int32 c; @@ -820,11 +817,11 @@ JSTokenStream::getUnicodeEscape() return '\\'; } -JSToken * -JSTokenStream::newToken(ptrdiff_t adjust) +Token * +TokenStream::newToken(ptrdiff_t adjust) { - cursor = (cursor + 1) & NTOKENS_MASK; - JSToken *tp = mutableCurrentToken(); + cursor = (cursor + 1) & ntokensMask; + Token *tp = mutableCurrentToken(); tp->ptr = linebuf.ptr + adjust; tp->pos.begin.index = linepos + (tp->ptr - linebuf.base) - ungetpos; tp->pos.begin.lineno = tp->pos.end.lineno = lineno; @@ -846,12 +843,12 @@ atomize(JSContext *cx, JSCharBuffer &cb) return js_AtomizeChars(cx, cb.begin(), cb.length(), 0); } -JSTokenType -JSTokenStream::getTokenInternal() +TokenType +TokenStream::getTokenInternal() { - JSTokenType tt; + TokenType tt; int c, qc; - JSToken *tp; + Token *tp; JSAtom *atom; JSBool hadUnicodeEscape; const struct keyword *kw; @@ -927,9 +924,8 @@ JSTokenStream::getTokenInternal() (nextc = peekChar(), ((flags & TSF_XMLONLYMODE) || nextc != '{') && !JS_ISXMLNAME(nextc))) { - js_ReportCompileErrorNumber(cx, this, NULL, - JSREPORT_ERROR, - JSMSG_BAD_XML_QNAME); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_QNAME); goto error; } sawColon = JS_TRUE; @@ -965,8 +961,8 @@ JSTokenStream::getTokenInternal() qc = c; while ((c = getChar()) != qc) { if (c == EOF) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); goto error; } @@ -1014,8 +1010,7 @@ JSTokenStream::getTokenInternal() bad_xml_char: default: - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_CHARACTER); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_CHARACTER); goto error; } /* NOTREACHED */ @@ -1071,11 +1066,8 @@ JSTokenStream::getTokenInternal() !(flags & TSF_KEYWORD_IS_NAME) && (kw = FindKeyword(tokenbuf.begin(), tokenbuf.length()))) { if (kw->tokentype == TOK_RESERVED) { - if (!js_ReportCompileErrorNumber(cx, this, NULL, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_RESERVED_ID, - kw->chars)) { + if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_RESERVED_ID, kw->chars)) { goto error; } } else if (kw->version <= JSVERSION_NUMBER(cx)) { @@ -1123,7 +1115,7 @@ JSTokenStream::getTokenInternal() if (radix == 8) { /* Octal integer literals are not permitted in strict mode code. */ - if (!js_ReportStrictModeError(cx, this, NULL, NULL, JSMSG_DEPRECATED_OCTAL)) + if (!ReportStrictModeError(cx, this, NULL, NULL, JSMSG_DEPRECATED_OCTAL)) goto error; /* @@ -1132,9 +1124,8 @@ JSTokenStream::getTokenInternal() * might not always be so permissive, so we warn about it. */ if (c >= '8') { - if (!js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING, - JSMSG_BAD_OCTAL, - c == '8' ? "08" : "09")) { + if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING, + JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) { goto error; } radix = 10; @@ -1164,8 +1155,8 @@ JSTokenStream::getTokenInternal() c = getChar(); } if (!JS7_ISDEC(c)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_MISSING_EXPONENT); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_MISSING_EXPONENT); goto error; } do { @@ -1177,8 +1168,7 @@ JSTokenStream::getTokenInternal() } if (JS_ISIDSTART(c)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_IDSTART_AFTER_NUMBER); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_IDSTART_AFTER_NUMBER); goto error; } @@ -1189,15 +1179,13 @@ JSTokenStream::getTokenInternal() if (radix == 10) { if (!js_strtod(cx, tokenbuf.begin(), tokenbuf.end(), &endptr, &dval)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_OUT_OF_MEMORY); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); goto error; } } else { if (!js_strtointeger(cx, tokenbuf.begin(), tokenbuf.end(), &endptr, radix, &dval)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_OUT_OF_MEMORY); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); goto error; } } @@ -1212,8 +1200,8 @@ JSTokenStream::getTokenInternal() while ((c = getChar()) != qc) { if (c == '\n' || c == EOF) { ungetChar(c); - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); goto error; } if (c == '\\') { @@ -1232,8 +1220,8 @@ JSTokenStream::getTokenInternal() c = peekChar(); /* Strict mode code allows only \0, then a non-digit. */ if (val != 0 || JS7_ISDEC(c)) { - if (!js_ReportStrictModeError(cx, this, NULL, NULL, - JSMSG_DEPRECATED_OCTAL)) { + if (!ReportStrictModeError(cx, this, NULL, NULL, + JSMSG_DEPRECATED_OCTAL)) { goto error; } } @@ -1526,8 +1514,7 @@ JSTokenStream::getTokenInternal() goto out; bad_xml_markup: - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); goto error; } #endif /* JS_HAS_XML_SUPPORT */ @@ -1647,7 +1634,7 @@ JSTokenStream::getTokenInternal() continue; } ungetChar(c); - cursor = (cursor - 1) & NTOKENS_MASK; + cursor = (cursor - 1) & ntokensMask; goto retry; } @@ -1658,8 +1645,8 @@ JSTokenStream::getTokenInternal() /* Ignore all characters until comment close. */ } if (c == EOF) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_COMMENT); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_COMMENT); goto error; } if ((flags & TSF_NEWLINES) && linenoBefore != lineno) { @@ -1667,7 +1654,7 @@ JSTokenStream::getTokenInternal() tt = TOK_EOL; goto eol_out; } - cursor = (cursor - 1) & NTOKENS_MASK; + cursor = (cursor - 1) & ntokensMask; goto retry; } @@ -1680,8 +1667,8 @@ JSTokenStream::getTokenInternal() c = getChar(); if (c == '\n' || c == EOF) { ungetChar(c); - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_REGEXP); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_REGEXP); goto error; } if (c == '\\') { @@ -1718,8 +1705,8 @@ JSTokenStream::getTokenInternal() char buf[2] = { '\0' }; tp->pos.begin.index += length + 1; buf[0] = (char)c; - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_REGEXP_FLAG, buf); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_REGEXP_FLAG, + buf); (void) getChar(); goto error; } @@ -1787,8 +1774,7 @@ JSTokenStream::getTokenInternal() break; n = 10 * n + JS7_UNDEC(c); if (n >= UINT16_LIMIT) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_SHARPVAR_TOO_BIG); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_SHARPVAR_TOO_BIG); goto error; } } @@ -1797,11 +1783,8 @@ JSTokenStream::getTokenInternal() (c == '=' || c == '#')) { char buf[20]; JS_snprintf(buf, sizeof buf, "#%u%c", n, c); - if (!js_ReportCompileErrorNumber(cx, this, NULL, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_DEPRECATED_USAGE, - buf)) { + if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, buf)) { goto error; } } @@ -1820,8 +1803,7 @@ JSTokenStream::getTokenInternal() #endif default: - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_ILLEGAL_CHARACTER); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_ILLEGAL_CHARACTER); goto error; } diff --git a/js/src/jsscan.h b/js/src/jsscan.h index 815ec528f64f..7706bd70b217 100644 --- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -50,14 +50,14 @@ #include "jspubtd.h" #include "jsvector.h" -JS_BEGIN_EXTERN_C - #define JS_KEYWORD(keyword, type, op, version) \ extern const char js_##keyword##_str[]; #include "jskeyword.tbl" #undef JS_KEYWORD -typedef enum JSTokenType { +namespace js { + +enum TokenType { TOK_ERROR = -1, /* well-known as the only code < EOF */ TOK_EOF = 0, /* end of file */ TOK_EOL = 1, /* end of line */ @@ -144,87 +144,91 @@ typedef enum JSTokenType { tree full of uses of those names */ TOK_RESERVED, /* reserved keywords */ TOK_LIMIT /* domain size */ -} JSTokenType; +}; -#define IS_PRIMARY_TOKEN(tt) \ - ((uintN)((tt) - TOK_NAME) <= (uintN)(TOK_PRIMARY - TOK_NAME)) +static inline bool TokenTypeIsXML(TokenType tt) +{ + return tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME; +} -#define TOKEN_TYPE_IS_XML(tt) \ - ((tt) == TOK_AT || (tt) == TOK_DBLCOLON || (tt) == TOK_ANYNAME) +static inline bool TreeTypeIsXML(TokenType tt) +{ + return tt == TOK_XMLCOMMENT || tt == TOK_XMLCDATA || tt == TOK_XMLPI || tt == TOK_XMLELEM || + tt == TOK_XMLLIST; +} -#define TREE_TYPE_IS_XML(tt) \ - ((tt) == TOK_XMLCOMMENT || (tt) == TOK_XMLCDATA || (tt) == TOK_XMLPI || \ - (tt) == TOK_XMLELEM || (tt) == TOK_XMLLIST) +static inline bool TokenTypeIsDecl(TokenType tt) +{ +# if JS_HAS_BLOCK_SCOPE + return tt == TOK_VAR || tt == TOK_LET; +# else + return tt == TOK_VAR; +# endif +} -#if JS_HAS_BLOCK_SCOPE -# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR || (tt) == TOK_LET) -#else -# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR) -#endif - -struct JSTokenPtr { +struct TokenPtr { uint32 index; /* index of char in physical line */ uint32 lineno; /* physical line number */ - bool operator==(const JSTokenPtr& bptr) { + bool operator==(const TokenPtr& bptr) { return index == bptr.index && lineno == bptr.lineno; } - bool operator!=(const JSTokenPtr& bptr) { + bool operator!=(const TokenPtr& bptr) { return index != bptr.index || lineno != bptr.lineno; } - bool operator <(const JSTokenPtr& bptr) { + bool operator <(const TokenPtr& bptr) { return lineno < bptr.lineno || (lineno == bptr.lineno && index < bptr.index); } - bool operator <=(const JSTokenPtr& bptr) { + bool operator <=(const TokenPtr& bptr) { return lineno < bptr.lineno || (lineno == bptr.lineno && index <= bptr.index); } - bool operator >(const JSTokenPtr& bptr) { + bool operator >(const TokenPtr& bptr) { return !(*this <= bptr); } - bool operator >=(const JSTokenPtr& bptr) { + bool operator >=(const TokenPtr& bptr) { return !(*this < bptr); } }; -struct JSTokenPos { - JSTokenPtr begin; /* first character and line of token */ - JSTokenPtr end; /* index 1 past last char, last line */ +struct TokenPos { + TokenPtr begin; /* first character and line of token */ + TokenPtr end; /* index 1 past last char, last line */ - bool operator==(const JSTokenPos& bpos) { + bool operator==(const TokenPos& bpos) { return begin == bpos.begin && end == bpos.end; } - bool operator!=(const JSTokenPos& bpos) { + bool operator!=(const TokenPos& bpos) { return begin != bpos.begin || end != bpos.end; } - bool operator <(const JSTokenPos& bpos) { + bool operator <(const TokenPos& bpos) { return begin < bpos.begin; } - bool operator <=(const JSTokenPos& bpos) { + bool operator <=(const TokenPos& bpos) { return begin <= bpos.begin; } - bool operator >(const JSTokenPos& bpos) { + bool operator >(const TokenPos& bpos) { return !(*this <= bpos); } - bool operator >=(const JSTokenPos& bpos) { + bool operator >=(const TokenPos& bpos) { return !(*this < bpos); } }; -struct JSToken { - JSTokenType type; /* char value or above enumerator */ - JSTokenPos pos; /* token position in file */ +struct Token { + TokenType type; /* char value or above enumerator */ + TokenPos pos; /* token position in file */ jschar *ptr; /* beginning of token in line buffer */ union { struct { /* name or string literal */ @@ -241,19 +245,7 @@ struct JSToken { } u; }; -#define t_op u.s.op -#define t_reflags u.reflags -#define t_atom u.s.atom -#define t_atom2 u.p.atom2 -#define t_dval u.dval - -#define JS_LINE_LIMIT 256 /* logical line buffer size limit -- - physical line length is unlimited */ -#define NTOKENS 4 /* 1 current + 2 lookahead, rounded */ -#define NTOKENS_MASK (NTOKENS-1) /* to power of 2 to avoid divmod by 3 */ - - -enum JSTokenStreamFlags +enum TokenStreamFlags { TSF_ERROR = 0x01, /* fatal error while compiling */ TSF_EOF = 0x02, /* hit end of file */ @@ -298,12 +290,24 @@ enum JSTokenStreamFlags TSF_STRICT_MODE_CODE = 0x8000 }; -class JSTokenStream +#define t_op u.s.op +#define t_reflags u.reflags +#define t_atom u.s.atom +#define t_atom2 u.p.atom2 +#define t_dval u.dval + +const size_t LINE_LIMIT = 256; /* logical line buffer size limit + -- physical line length is unlimited */ + +class TokenStream { + static const size_t ntokens = 4; /* 1 current + 2 lookahead, rounded + to power of 2 to avoid divmod by 3 */ + static const uintN ntokensMask = ntokens - 1; public: /* - * To construct a JSTokenStream, first call the constructor, which is - * infallible, then call |init|, which can fail. To destroy a JSTokenStream, + * To construct a TokenStream, first call the constructor, which is + * infallible, then call |init|, which can fail. To destroy a TokenStream, * first call |close| then call the destructor. If |init| fails, do not call * |close|. * @@ -311,7 +315,7 @@ class JSTokenStream * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE * after calling |close|. */ - JSTokenStream(JSContext *); + TokenStream(JSContext *); /* * Create a new token stream, either from an input buffer or from a file. @@ -319,14 +323,14 @@ class JSTokenStream */ bool init(const jschar *base, size_t length, FILE *fp, const char *filename, uintN lineno); void close(); - ~JSTokenStream() {} + ~TokenStream() {} /* Accessors. */ JSContext *getContext() const { return cx; } - bool onCurrentLine(const JSTokenPos &pos) const { return lineno == pos.end.lineno; } - const JSToken ¤tToken() const { return tokens[cursor]; } - const JSToken &getTokenAt(size_t index) const { - JS_ASSERT(index < NTOKENS); + bool onCurrentLine(const TokenPos &pos) const { return lineno == pos.end.lineno; } + const Token ¤tToken() const { return tokens[cursor]; } + const Token &getTokenAt(size_t index) const { + JS_ASSERT(index < ntokens); return tokens[index]; } const JSCharBuffer &getTokenbuf() const { return tokenbuf; } @@ -334,16 +338,16 @@ class JSTokenStream uintN getLineno() const { return lineno; } /* Mutators. */ - JSToken *mutableCurrentToken() { return &tokens[cursor]; } + Token *mutableCurrentToken() { return &tokens[cursor]; } bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); - JSTokenType getToken() { + TokenType getToken() { /* Check for a pushed-back token resulting from mismatching lookahead. */ while (lookahead != 0) { JS_ASSERT(!(flags & TSF_XMLTEXTMODE)); lookahead--; - cursor = (cursor + 1) & NTOKENS_MASK; - JSTokenType tt = currentToken().type; + cursor = (cursor + 1) & ntokensMask; + TokenType tt = currentToken().type; if (tt != TOK_EOL || (flags & TSF_NEWLINES)) return tt; } @@ -355,36 +359,36 @@ class JSTokenStream return getTokenInternal(); } - JSToken *getMutableTokenAt(size_t index) { - JS_ASSERT(index < NTOKENS); + Token *getMutableTokenAt(size_t index) { + JS_ASSERT(index < ntokens); return &tokens[index]; } void ungetToken() { - JS_ASSERT(lookahead < NTOKENS_MASK); + JS_ASSERT(lookahead < ntokensMask); lookahead++; - cursor = (cursor - 1) & NTOKENS_MASK; + cursor = (cursor - 1) & ntokensMask; } - JSTokenType peekToken() { + TokenType peekToken() { if (lookahead != 0) { - return tokens[(cursor + lookahead) & NTOKENS_MASK].type; + return tokens[(cursor + lookahead) & ntokensMask].type; } - JSTokenType tt = getToken(); + TokenType tt = getToken(); ungetToken(); return tt; } - JSTokenType peekTokenSameLine() { + TokenType peekTokenSameLine() { if (!onCurrentLine(currentToken().pos)) return TOK_EOL; flags |= TSF_NEWLINES; - JSTokenType tt = peekToken(); + TokenType tt = peekToken(); flags &= ~TSF_NEWLINES; return tt; } - JSBool matchToken(JSTokenType tt) { + JSBool matchToken(TokenType tt) { if (getToken() == tt) return JS_TRUE; ungetToken(); @@ -392,16 +396,16 @@ class JSTokenStream } private: - typedef struct JSTokenBuf { + typedef struct TokenBuf { jschar *base; /* base of line or stream buffer */ jschar *limit; /* limit for quick bounds check */ jschar *ptr; /* next char to get, or slot to use */ - } JSTokenBuf; + } TokenBuf; - JSTokenType getTokenInternal(); /* doesn't check for pushback or error flag. */ + TokenType getTokenInternal(); /* doesn't check for pushback or error flag. */ int32 getChar(); void ungetChar(int32 c); - JSToken *newToken(ptrdiff_t adjust); + Token *newToken(ptrdiff_t adjust); int32 getUnicodeEscape(); JSBool peekChars(intN n, jschar *cp); JSBool getXMLEntity(); @@ -426,7 +430,7 @@ class JSTokenStream } JSContext * const cx; - JSToken tokens[NTOKENS];/* circular token buffer */ + Token tokens[ntokens];/* circular token buffer */ uintN cursor; /* index of last parsed token */ uintN lookahead; /* count of lookahead tokens */ @@ -438,9 +442,9 @@ class JSTokenStream private: uint32 linelen; /* physical linebuf segment length */ uint32 linepos; /* linebuf offset in physical line */ - JSTokenBuf linebuf; /* line buffer for diagnostics */ + TokenBuf linebuf; /* line buffer for diagnostics */ - JSTokenBuf userbuf; /* user input buffer if !file */ + TokenBuf userbuf; /* user input buffer if !file */ const char *filename; /* input filename or null */ FILE *file; /* stdio stream if reading from file */ JSSourceHandler listener; /* callback for source; eg debugger */ @@ -451,12 +455,14 @@ class JSTokenStream JSCharBuffer tokenbuf; /* current token string buffer */ }; +} /* namespace js */ + /* Unicode separators that are treated as line terminators, in addition to \n, \r */ #define LINE_SEPARATOR 0x2028 #define PARA_SEPARATOR 0x2029 extern void -js_CloseTokenStream(JSContext *cx, JSTokenStream *ts); +js_CloseTokenStream(JSContext *cx, js::TokenStream *ts); extern JS_FRIEND_API(int) js_fgets(char *buf, int size, FILE *file); @@ -465,7 +471,7 @@ js_fgets(char *buf, int size, FILE *file); * If the given char array forms JavaScript keyword, return corresponding * token. Otherwise return TOK_EOF. */ -extern JSTokenType +extern js::TokenType js_CheckKeyword(const jschar *chars, size_t length); /* @@ -481,54 +487,56 @@ typedef void (*JSMapKeywordFun)(const char *); extern JSBool js_IsIdentifier(JSString *str); +/* + * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error + * message have const jschar* type, not const char*. + */ +#define JSREPORT_UC 0x100 + +namespace js { + /* * Report a compile-time error by its number. Return true for a warning, false * for an error. When pn is not null, use it to report error's location. * Otherwise use ts, which must not be null. */ bool -js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, - uintN flags, uintN errorNumber, ...); +ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN flags, + uintN errorNumber, ...); /* * Report a condition that should elicit a warning with JSOPTION_STRICT, * or an error if ts or tc is handling strict mode code. This function - * defers to js_ReportCompileErrorNumber to do the real work. Either tc + * defers to ReportCompileErrorNumber to do the real work. Either tc * or ts may be NULL, if there is no tree context or token stream state * whose strictness should affect the report. * - * One could have js_ReportCompileErrorNumber recognize the + * One could have ReportCompileErrorNumber recognize the * JSREPORT_STRICT_MODE_ERROR flag instead of having a separate function * like this one. However, the strict mode code flag we need to test is * in the JSTreeContext structure for that code; we would have to change - * the ~120 js_ReportCompileErrorNumber calls to pass the additional + * the ~120 ReportCompileErrorNumber calls to pass the additional * argument, even though many of those sites would never use it. Using * ts's TSF_STRICT_MODE_CODE flag instead of tc's would be brittle: at some * points ts's flags don't correspond to those of the tc relevant to the * error. */ bool -js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParseNode *pn, uintN errorNumber, ...); - -/* - * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error - * message have const jschar* type, not const char*. - */ -#define JSREPORT_UC 0x100 +ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, + uintN errorNumber, ...); /* * Look ahead one token and return its type. */ -static inline JSTokenType -js_PeekToken(JSContext *cx, JSTokenStream *ts) +static inline TokenType +PeekToken(JSContext *cx, TokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->peekToken(); } -static inline JSTokenType -js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) +static inline TokenType +PeekTokenSameLine(JSContext *cx, TokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->peekTokenSameLine(); @@ -537,8 +545,8 @@ js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) /* * Get the next token from ts. */ -static inline JSTokenType -js_GetToken(JSContext *cx, JSTokenStream *ts) +static inline TokenType +GetToken(JSContext *cx, TokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->getToken(); @@ -548,7 +556,7 @@ js_GetToken(JSContext *cx, JSTokenStream *ts) * Push back the last scanned token onto ts. */ static inline void -js_UngetToken(JSTokenStream *ts) +UngetToken(TokenStream *ts) { ts->ungetToken(); } @@ -557,12 +565,12 @@ js_UngetToken(JSTokenStream *ts) * Get the next token from ts if its type is tt. */ static inline JSBool -js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt) +MatchToken(JSContext *cx, TokenStream *ts, TokenType tt) { JS_ASSERT(cx == ts->getContext()); return ts->matchToken(tt); } -JS_END_EXTERN_C +} /* namespace js */ #endif /* jsscan_h___ */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 5b54cf3e7925..8239ee78e9f1 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1012,8 +1012,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) } script->lineno = cg->firstLine; if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, - JSMSG_NEED_DIET, "script"); + ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET, "script"); goto bad; } script->nslots = script->nfixed + cg->maxStackDepth; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 684b5c4b3597..e5aff106faa5 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -1268,11 +1268,10 @@ ParseNodeToQName(JSCompiler *jsc, JSParseNode *pn, } if (!uri) { - js_ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn, - JSREPORT_ERROR, - JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(jsc->context, - STRING_TO_JSVAL(prefix))); + ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn, + JSREPORT_ERROR, JSMSG_BAD_XML_NAMESPACE, + js_ValueToPrintableString(jsc->context, + STRING_TO_JSVAL(prefix))); return NULL; } @@ -1350,8 +1349,8 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, int stackDummy; if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, - JSMSG_OVER_RECURSED); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, + JSMSG_OVER_RECURSED); return NULL; } @@ -1489,11 +1488,10 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, /* Enforce "Well-formedness constraint: Unique Att Spec". */ for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { if (pn3->pn_atom == pn2->pn_atom) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, - JSREPORT_ERROR, - JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, + JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); goto fail; } } @@ -1600,11 +1598,10 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, attrjqn = attrj->name; if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) && js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, - JSREPORT_ERROR, - JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, + JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); goto fail; } } @@ -1641,11 +1638,10 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, xml_class = JSXML_CLASS_COMMENT; } else if (pn->pn_type == TOK_XMLPI) { if (IS_XML(str)) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, - JSREPORT_ERROR, - JSMSG_RESERVED_ID, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(str))); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, + JSREPORT_ERROR, JSMSG_RESERVED_ID, + js_ValueToPrintableString(cx, + STRING_TO_JSVAL(str))); goto fail; } @@ -1690,8 +1686,7 @@ skip_child: #undef PN2X_SKIP_CHILD syntax: - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); fail: js_LeaveLocalRootScope(cx); return NULL; From 8619abe400d39463469e9cf1b4ecf20817f2851e Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 18 Mar 2010 22:26:47 -0700 Subject: [PATCH 086/213] Backed out changeset 6403442ffa1d (failure on windows, winnt.h defines TokenType!) --- js/src/jsemit.cpp | 49 +-- js/src/jsexn.cpp | 2 +- js/src/jsfun.cpp | 19 +- js/src/json.cpp | 2 +- js/src/jsparse.cpp | 765 +++++++++++++++++++++++--------------------- js/src/jsparse.h | 34 +- js/src/jsprvtd.h | 9 +- js/src/jsregexp.cpp | 13 +- js/src/jsregexp.h | 4 +- js/src/jsscan.cpp | 158 +++++---- js/src/jsscan.h | 214 ++++++------- js/src/jsscript.cpp | 3 +- js/src/jsxml.cpp | 43 +-- 13 files changed, 680 insertions(+), 635 deletions(-) diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index a9e17741da99..3ea68e54c70b 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -79,8 +79,6 @@ #define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote)) #define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote)) -using namespace js; - static JSBool NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, size_t start, size_t end); @@ -186,7 +184,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) JS_ASSERT(cg->stackDepth >= 0); if (cg->stackDepth < 0) { char numBuf[12]; - TokenStream *ts; + JSTokenStream *ts; JS_snprintf(numBuf, sizeof numBuf, "%d", target); ts = &cg->compiler->tokenStream; @@ -895,7 +893,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) if (growth) { #ifdef DEBUG_brendan - TokenStream *ts = &cg->compiler->tokenStream; + JSTokenStream *ts = &cg->compiler->tokenStream; printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n", ts->filename ? ts->filename : "stdin", cg->firstLine, @@ -1837,7 +1835,9 @@ AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) if (cg->flags & TCF_IN_FUNCTION) { slot += cg->fun->u.i.nvars; if ((uintN) slot >= SLOTNO_LIMIT) { - ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); + js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, + JSREPORT_ERROR, + JSMSG_TOO_MANY_LOCALS); slot = -1; } } @@ -3934,7 +3934,8 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, depth = limit = (uintN) cg->stackDepth; for (pn = rhs->pn_head; pn; pn = pn->pn_next) { if (limit == JS_BIT(16)) { - ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG); + js_ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, + JSMSG_ARRAY_INIT_TOO_BIG); return JS_FALSE; } @@ -4332,7 +4333,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JSSrcNoteType noteType; jsbytecode *pc; JSOp op; - TokenType type; + JSTokenType type; uint32 argc; #if JS_HAS_SHARP_VARS jsint sharpnum; @@ -4694,7 +4695,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn3 = pn2->pn_left; type = PN_TYPE(pn3); cg->flags |= TCF_IN_FOR_INIT; - if (TokenTypeIsDecl(type) && !js_EmitTree(cx, cg, pn3)) + if (TOKEN_TYPE_IS_DECL(type) && !js_EmitTree(cx, cg, pn3)) return JS_FALSE; cg->flags &= ~TCF_IN_FOR_INIT; @@ -4803,8 +4804,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) op = PN_OP(pn3); } if (pn3->isConst()) { - ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return JS_FALSE; } if (pn3->pn_cookie != FREE_UPVAR_COOKIE) { @@ -4916,7 +4917,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (op == JSOP_POP) { if (!js_EmitTree(cx, cg, pn3)) return JS_FALSE; - if (TokenTypeIsDecl(PN_TYPE(pn3))) { + if (TOKEN_TYPE_IS_DECL(pn3->pn_type)) { /* * Check whether a destructuring-initialized var decl * was optimized to a group assignment. If so, we do @@ -5485,9 +5486,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #if JS_HAS_GENERATORS case TOK_YIELD: if (!(cg->flags & TCF_IN_FUNCTION)) { - ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, - JSMSG_BAD_RETURN_OR_YIELD, - js_yield_str); + js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, + js_yield_str); return JS_FALSE; } if (pn->pn_kid) { @@ -5625,9 +5626,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) cg->topStmt->type != STMT_LABEL || cg->topStmt->update < CG_OFFSET(cg))) { CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno; - if (!ReportCompileErrorNumber(cx, CG_TS(cg), pn2, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_USELESS_EXPR)) { + if (!js_ReportCompileErrorNumber(cx, CG_TS(cg), pn2, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_USELESS_EXPR)) { return JS_FALSE; } } else { @@ -5794,9 +5796,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * x getter = y where x is a local or let variable is not * supported. */ - ReportCompileErrorNumber(cx, TS(cg->compiler), pn2, JSREPORT_ERROR, - JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) ? js_getter_str : js_setter_str); + js_ReportCompileErrorNumber(cx, + TS(cg->compiler), + pn2, JSREPORT_ERROR, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); return JS_FALSE; } @@ -6627,7 +6633,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #endif #if JS_HAS_DESTRUCTURING_SHORTHAND if (pn->pn_xflags & PNX_DESTRUCT) { - ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index cc2bec6b7e88..478dac5505df 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -351,7 +351,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, * Construct a new copy of the error report struct. We can't use the * error report struct that was passed in, because it's allocated on * the stack, and also because it may point to transient data in the - * TokenStream. + * JSTokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index a07be6899ea3..c5ba28896059 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2183,12 +2183,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const char *filename; JSBool ok; JSString *str, *arg; - TokenStream ts(cx); + JSTokenStream ts(cx); JSPrincipals *principals; jschar *collected_args, *cp; void *mark; size_t arg_length, args_length, old_args_length; - TokenType tt; + JSTokenType tt; if (!JS_IsConstructing(cx)) { obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL); @@ -2336,7 +2336,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* The argument string may be empty or contain no tokens. */ - tt = GetToken(cx, &ts); + tt = js_GetToken(cx, &ts); if (tt != TOK_EOF) { for (;;) { /* @@ -2358,9 +2358,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const char *name; name = js_AtomToPrintableString(cx, atom); - ok = name && ReportCompileErrorNumber(cx, &ts, NULL, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_DUPLICATE_FORMAL, name); + ok = name && + js_ReportCompileErrorNumber(cx, &ts, NULL, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, + name); if (!ok) goto after_args; } @@ -2371,12 +2374,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ - tt = GetToken(cx, &ts); + tt = js_GetToken(cx, &ts); if (tt == TOK_EOF) break; if (tt != TOK_COMMA) goto after_args; - tt = GetToken(cx, &ts); + tt = js_GetToken(cx, &ts); } } diff --git a/js/src/json.cpp b/js/src/json.cpp index 3c734ce8c926..44897ba6d41c 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -923,7 +923,7 @@ static JSBool HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) { jsval keyword; - TokenType tt = js_CheckKeyword(buf, len); + JSTokenType tt = js_CheckKeyword(buf, len); if (tt != TOK_PRIMARY) { // bad keyword JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 8dfdac0d88c6..0b185b11075b 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -104,12 +104,12 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom)); * Insist that the next token be of type tt, or report errno and return null. * NB: this macro uses cx and ts from its lexical environment. */ -#define MUST_MATCH_TOKEN(tt, errno) \ - JS_BEGIN_MACRO \ - if (GetToken(context, &tokenStream) != tt) { \ - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ - return NULL; \ - } \ +#define MUST_MATCH_TOKEN(tt, errno) \ + JS_BEGIN_MACRO \ + if (js_GetToken(context, &tokenStream) != tt) { \ + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ + return NULL; \ + } \ JS_END_MACRO #ifdef METER_PARSENODES @@ -529,14 +529,14 @@ JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc) JSParseNode *pn = NewOrRecycledNode(tc); if (!pn) return NULL; - Token *tp = tc->compiler->tokenStream.mutableCurrentToken(); + JSToken *tp = tc->compiler->tokenStream.mutableCurrentToken(); pn->init(tp->type, JSOP_NOP, arity); pn->pn_pos = tp->pos; return pn; } JSParseNode * -JSParseNode::newBinaryOrAppend(TokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, +JSParseNode::newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, JSTreeContext *tc) { JSParseNode *pn, *pn1, *pn2; @@ -635,8 +635,8 @@ NameNode::create(JSAtom *atom, JSTreeContext *tc) } /* namespace js */ #if JS_HAS_GETTER_SETTER -static TokenType -CheckGetterOrSetter(JSContext *cx, TokenStream *ts, TokenType tt) +static JSTokenType +CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) { JSAtom *atom; JSRuntime *rt; @@ -652,20 +652,25 @@ CheckGetterOrSetter(JSContext *cx, TokenStream *ts, TokenType tt) op = JSOP_SETTER; else return TOK_NAME; - if (PeekTokenSameLine(cx, ts) != tt) + if (js_PeekTokenSameLine(cx, ts) != tt) return TOK_NAME; - (void) GetToken(cx, ts); + (void) js_GetToken(cx, ts); if (ts->currentToken().t_op != JSOP_NOP) { - ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) ? js_getter_str : js_setter_str); + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); return TOK_ERROR; } ts->mutableCurrentToken()->t_op = op; if (JS_HAS_STRICT_OPTION(cx)) { name = js_AtomToPrintableString(cx, atom); if (!name || - !ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_DEPRECATED_USAGE, name)) { + !js_ReportCompileErrorNumber(cx, ts, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, + name)) { return TOK_ERROR; } } @@ -718,9 +723,9 @@ JSCompiler::parse(JSObject *chain) JSParseNode *pn = statements(); if (pn) { - if (!MatchToken(context, &tokenStream, TOK_EOF)) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + if (!js_MatchToken(context, &tokenStream, TOK_EOF)) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); pn = NULL; } else { if (!js_FoldConstants(context, pn, &globaltc)) @@ -766,7 +771,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal { JSCompiler jsc(cx, principals, callerFrame); JSArenaPool codePool, notePool; - TokenType tt; + JSTokenType tt; JSParseNode *pn; uint32 scriptGlobals; JSScript *script; @@ -868,7 +873,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal inDirectivePrologue = true; for (;;) { jsc.tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(cx, &jsc.tokenStream); + tt = js_PeekToken(cx, &jsc.tokenStream); jsc.tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF) { if (tt == TOK_EOF) @@ -899,7 +904,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal #if JS_HAS_XML_SUPPORT if (PN_TYPE(pn) != TOK_SEMI || !pn->pn_kid || - !TreeTypeIsXML(PN_TYPE(pn->pn_kid))) { + !TREE_TYPE_IS_XML(PN_TYPE(pn->pn_kid))) { onlyXML = false; } #endif @@ -914,8 +919,8 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal * https://bugzilla.mozilla.org/show_bug.cgi?id=336551 */ if (pn && onlyXML && (tcflags & TCF_NO_SCRIPT_RVAL)) { - ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, - JSMSG_XML_WHOLE_PROGRAM); + js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, + JSMSG_XML_WHOLE_PROGRAM); goto out; } #endif @@ -1005,7 +1010,8 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal return script; too_many_slots: - ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); + js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, + JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); script = NULL; goto out; } @@ -1150,7 +1156,8 @@ ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum, errnum = anonerrnum; name = NULL; } - return ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, flags, errnum, name); + return js_ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, flags, + errnum, name); } static JSBool @@ -1176,8 +1183,8 @@ CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs) if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) { const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !ReportStrictModeError(cx, TS(tc->compiler), tc, lhs, JSMSG_DEPRECATED_ASSIGN, - name)) { + !js_ReportStrictModeError(cx, TS(tc->compiler), tc, lhs, + JSMSG_DEPRECATED_ASSIGN, name)) { return false; } } @@ -1201,7 +1208,8 @@ CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, JSParseNode * if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) { const char *name = js_AtomToPrintableString(cx, atom); if (name) - ReportStrictModeError(cx, TS(tc->compiler), tc, pn, JSMSG_BAD_BINDING, name); + js_ReportStrictModeError(cx, TS(tc->compiler), tc, pn, + JSMSG_BAD_BINDING, name); return false; } return true; @@ -1241,7 +1249,8 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, pn = dn; const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !ReportStrictModeError(cx, TS(tc->compiler), tc, pn, JSMSG_DUPLICATE_FORMAL, name)) { + !js_ReportStrictModeError(cx, TS(tc->compiler), tc, pn, + JSMSG_DUPLICATE_FORMAL, name)) { return false; } } @@ -1255,7 +1264,8 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, JS_ASSERT(dn->pn_atom == atom); const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !ReportStrictModeError(cx, TS(tc->compiler), tc, dn, JSMSG_BAD_BINDING, name)) { + !js_ReportStrictModeError(cx, TS(tc->compiler), tc, dn, + JSMSG_BAD_BINDING, name)) { return false; } } @@ -1605,9 +1615,9 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr if (pn) { if (!CheckStrictFormals(cx, &funcg, fun, pn)) { pn = NULL; - } else if (!MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { - ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + } else if (!js_MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { + js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, + JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; } else if (!js_FoldConstants(cx, pn, &funcg)) { /* js_FoldConstants reported the error already. */ @@ -1697,8 +1707,8 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSLocalKind localKind = js_LookupLocal(cx, tc->fun, atom, NULL); if (localKind != JSLOCAL_NONE) { - ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, JSREPORT_ERROR, - JSMSG_DESTRUCT_DUP_ARG); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, + JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG); return JS_FALSE; } JS_ASSERT(!tc->decls.lookup(atom)); @@ -1746,20 +1756,21 @@ JSCompiler::newFunction(JSTreeContext *tc, JSAtom *atom, uintN lambda) } static JSBool -MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) +MatchOrInsertSemicolon(JSContext *cx, JSTokenStream *ts) { - TokenType tt; + JSTokenType tt; ts->flags |= TSF_OPERAND; - tt = PeekTokenSameLine(cx, ts); + tt = js_PeekTokenSameLine(cx, ts); ts->flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return JS_FALSE; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { - ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT); + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_SEMI_BEFORE_STMNT); return JS_FALSE; } - (void) MatchToken(cx, ts, TOK_SEMI); + (void) js_MatchToken(cx, ts, TOK_SEMI); return JS_TRUE; } @@ -2147,7 +2158,7 @@ static void DeoptimizeUsesWithin(JSDefinition *dn, JSFunctionBox *funbox, uint32& tcflags) { uintN ndeoptimized = 0; - const TokenPos &pos = funbox->node->pn_body->pn_pos; + const JSTokenPos &pos = funbox->node->pn_body->pn_pos; for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { JS_ASSERT(pnu->pn_used); @@ -2567,7 +2578,7 @@ JSCompiler::functionDef(uintN lambda) { JSOp op; JSParseNode *pn, *body, *result; - TokenType tt; + JSTokenType tt; JSAtom *funAtom; JSAtomListElement *ale; #if JS_HAS_DESTRUCTURING @@ -2599,18 +2610,18 @@ JSCompiler::functionDef(uintN lambda) /* Scan the optional function name into funAtom. */ tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_NAME) { funAtom = tokenStream.currentToken().t_atom; } else { if (lambda == 0 && (context->options & JSOPTION_ANONFUNFIX)) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } funAtom = NULL; - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); } /* @@ -2629,13 +2640,13 @@ JSCompiler::functionDef(uintN lambda) if (JS_HAS_STRICT_OPTION(context) || dn_kind == JSDefinition::CONST) { const char *name = js_AtomToPrintableString(context, funAtom); if (!name || - !ReportCompileErrorNumber(context, &tokenStream, NULL, - (dn_kind != JSDefinition::CONST) - ? JSREPORT_WARNING | JSREPORT_STRICT - : JSREPORT_ERROR, - JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), - name)) { + !js_ReportCompileErrorNumber(context, &tokenStream, NULL, + (dn_kind != JSDefinition::CONST) + ? JSREPORT_WARNING | JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + JSDefinition::kindString(dn_kind), + name)) { return NULL; } } @@ -2736,9 +2747,9 @@ JSCompiler::functionDef(uintN lambda) /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); - if (!MatchToken(context, &tokenStream, TOK_RP)) { + if (!js_MatchToken(context, &tokenStream, TOK_RP)) { do { - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -2830,8 +2841,8 @@ JSCompiler::functionDef(uintN lambda) } default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_MISSING_FORMAL); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_MISSING_FORMAL); /* FALL THROUGH */ case TOK_ERROR: return NULL; @@ -2839,22 +2850,22 @@ JSCompiler::functionDef(uintN lambda) #if JS_HAS_DESTRUCTURING report_dup_and_destructuring: JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg)); - ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, - JSMSG_DESTRUCT_DUP_ARG); + js_ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, + JSMSG_DESTRUCT_DUP_ARG); return NULL; #endif } - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); } #if JS_HAS_EXPR_CLOSURES tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt != TOK_LC) { - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); fun->flags |= JSFUN_EXPR_CLOSURE; } #else @@ -3048,7 +3059,7 @@ JSParseNode * JSCompiler::statements() { JSParseNode *pn, *pn2, *saveBlock; - TokenType tt; + JSTokenType tt; bool inDirectivePrologue = tc->atTopLevel(); JS_CHECK_RECURSION(context, return NULL); @@ -3064,7 +3075,7 @@ JSCompiler::statements() for (;;) { tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = js_PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF || tt == TOK_RC) { if (tt == TOK_ERROR) { @@ -3130,24 +3141,26 @@ JSCompiler::condition() if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP && !pn->pn_parens && - !ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_EQUAL_AS_ASSIGN, "")) { + !js_ReportCompileErrorNumber(context, &tokenStream, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_EQUAL_AS_ASSIGN, + "")) { return NULL; } return pn; } static JSBool -MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn) +MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn) { JSAtom *label; - TokenType tt; + JSTokenType tt; - tt = PeekTokenSameLine(cx, ts); + tt = js_PeekTokenSameLine(cx, ts); if (tt == TOK_ERROR) return JS_FALSE; if (tt == TOK_NAME) { - (void) GetToken(cx, ts); + (void) js_GetToken(cx, ts); label = ts->currentToken().t_atom; } else { label = NULL; @@ -3179,20 +3192,20 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (ale && ALE_DEFN(ale)->pn_blockid == tc->blockid()) { const char *name = js_AtomToPrintableString(cx, atom); if (name) { - ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_REDECLARED_VAR, - (ale && ALE_DEFN(ale)->isConst()) - ? js_const_str - : js_variable_str, - name); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_REDECLARED_VAR, + (ale && ALE_DEFN(ale)->isConst()) + ? js_const_str + : js_variable_str, + name); } return JS_FALSE; } n = OBJ_BLOCK_COUNT(cx, blockObj); if (n == JS_BIT(16)) { - ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, data->let.overflow); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, data->let.overflow); return JS_FALSE; } @@ -3302,14 +3315,14 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) return JS_FALSE; if (op == JSOP_DEFCONST) { - ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, - name); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, + name); return JS_FALSE; } - if (!ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_VAR_HIDES_ARG, name)) { + if (!js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_VAR_HIDES_ARG, name)) { return JS_FALSE; } } else { @@ -3323,13 +3336,13 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) : error) { name = js_AtomToPrintableString(cx, atom); if (!name || - !ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - !error - ? JSREPORT_WARNING | JSREPORT_STRICT - : JSREPORT_ERROR, - JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), - name)) { + !js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + !error + ? JSREPORT_WARNING | JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + JSDefinition::kindString(dn_kind), + name)) { return JS_FALSE; } } @@ -3505,7 +3518,7 @@ MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL || pn->pn_op == JSOP_APPLY); pn2 = pn->pn_head; if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) { - ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, msg); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, msg); return JS_FALSE; } pn->pn_op = JSOP_SETCALL; @@ -3642,8 +3655,8 @@ BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) #endif default: - ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); return JS_FALSE; } @@ -3840,15 +3853,15 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *lhs, *rhs, *pn, *pn2; if (left->pn_type == TOK_ARRAYCOMP) { - ReportCompileErrorNumber(cx, TS(tc->compiler), left, JSREPORT_ERROR, - JSMSG_ARRAY_COMP_LEFTSIDE); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), left, + JSREPORT_ERROR, JSMSG_ARRAY_COMP_LEFTSIDE); return JS_FALSE; } #if JS_HAS_DESTRUCTURING_SHORTHAND if (right && right->pn_arity == PN_LIST && (right->pn_xflags & PNX_DESTRUCT)) { - ReportCompileErrorNumber(cx, TS(tc->compiler), right, JSREPORT_ERROR, - JSMSG_BAD_OBJECT_INIT); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), right, + JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif @@ -3955,8 +3968,8 @@ CheckDestructuring(JSContext *cx, BindData *data, return ok; no_var_name: - ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); ok = JS_FALSE; goto out; } @@ -3989,8 +4002,8 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) #if JS_HAS_DESTRUCTURING_SHORTHAND if (right->pn_arity == PN_LIST && (right->pn_xflags & PNX_DESTRUCT)) { - ReportCompileErrorNumber(tc->compiler->context, TS(tc->compiler), right, JSREPORT_ERROR, - JSMSG_BAD_OBJECT_INIT); + js_ReportCompileErrorNumber(tc->compiler->context, TS(tc->compiler), right, + JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif @@ -4042,7 +4055,7 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) } JSParseNode * -JSCompiler::destructuringExpr(BindData *data, TokenType tt) +JSCompiler::destructuringExpr(BindData *data, JSTokenType tt) { JSParseNode *pn; @@ -4166,7 +4179,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) extern const char js_with_statement_str[]; static JSParseNode * -ContainsStmt(JSParseNode *pn, TokenType tt) +ContainsStmt(JSParseNode *pn, JSTokenType tt) { JSParseNode *pn2, *pnt; @@ -4217,13 +4230,13 @@ ContainsStmt(JSParseNode *pn, TokenType tt) JSParseNode * JSCompiler::returnOrYield(bool useAssignExpr) { - TokenType tt, tt2; + JSTokenType tt, tt2; JSParseNode *pn, *pn2; tt = tokenStream.currentToken().type; if (tt == TOK_RETURN && !(tc->flags & TCF_IN_FUNCTION)) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return NULL; } @@ -4238,7 +4251,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) /* This is ugly, but we don't want to require a semicolon. */ tokenStream.flags |= TSF_OPERAND; - tt2 = PeekTokenSameLine(context, &tokenStream); + tt2 = js_PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt2 == TOK_ERROR) return NULL; @@ -4286,7 +4299,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) } static JSParseNode * -PushLexicalScope(JSContext *cx, TokenStream *ts, JSTreeContext *tc, +PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSStmtInfo *stmt) { JSParseNode *pn; @@ -4349,7 +4362,7 @@ JSCompiler::letBlock(JSBool statement) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET); tokenStream.flags |= TSF_OPERAND; - if (statement && !MatchToken(context, &tokenStream, TOK_LC)) { + if (statement && !js_MatchToken(context, &tokenStream, TOK_LC)) { /* * If this is really an expression in let statement guise, then we * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop @@ -4518,7 +4531,7 @@ RebindLets(JSParseNode *pn, JSTreeContext *tc) JSParseNode * JSCompiler::statement() { - TokenType tt; + JSTokenType tt; JSParseNode *pn, *pn1, *pn2, *pn3, *pn4; JSStmtInfo stmtInfo, *stmt, *stmt2; JSAtom *label; @@ -4526,7 +4539,7 @@ JSCompiler::statement() JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_GETTER_SETTER @@ -4541,7 +4554,7 @@ JSCompiler::statement() case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = PeekToken(context, &tokenStream); + tt = js_PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_DBLCOLON) goto expression; @@ -4561,7 +4574,7 @@ JSCompiler::statement() if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND; - if (MatchToken(context, &tokenStream, TOK_ELSE)) { + if (js_MatchToken(context, &tokenStream, TOK_ELSE)) { tokenStream.flags &= ~TSF_OPERAND; stmtInfo.type = STMT_ELSE; pn3 = statement(); @@ -4613,12 +4626,12 @@ JSCompiler::statement() saveBlock = tc->blockNode; tc->blockNode = pn2; - while ((tt = GetToken(context, &tokenStream)) != TOK_RC) { + while ((tt = js_GetToken(context, &tokenStream)) != TOK_RC) { switch (tt) { case TOK_DEFAULT: if (seenDefault) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOO_MANY_DEFAULTS); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_DEFAULTS); return NULL; } seenDefault = JS_TRUE; @@ -4635,8 +4648,8 @@ JSCompiler::statement() } pn2->append(pn3); if (pn2->pn_count == JS_BIT(16)) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOO_MANY_CASES); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_CASES); return NULL; } break; @@ -4645,8 +4658,8 @@ JSCompiler::statement() return NULL; default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_SWITCH); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_SWITCH); return NULL; } MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); @@ -4657,7 +4670,7 @@ JSCompiler::statement() pn4->pn_type = TOK_LC; pn4->makeEmpty(); tokenStream.flags |= TSF_OPERAND; - while ((tt = PeekToken(context, &tokenStream)) != TOK_RC && + while ((tt = js_PeekToken(context, &tokenStream)) != TOK_RC && tt != TOK_CASE && tt != TOK_DEFAULT) { tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) @@ -4734,7 +4747,7 @@ JSCompiler::statement() * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ - (void) MatchToken(context, &tokenStream, TOK_SEMI); + (void) js_MatchToken(context, &tokenStream, TOK_SEMI); return pn; } break; @@ -4755,16 +4768,16 @@ JSCompiler::statement() pn->pn_op = JSOP_ITER; pn->pn_iflags = 0; - if (MatchToken(context, &tokenStream, TOK_NAME)) { + if (js_MatchToken(context, &tokenStream, TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn->pn_iflags = JSITER_FOREACH; else - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = js_PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_BLOCK_SCOPE @@ -4793,13 +4806,13 @@ JSCompiler::statement() */ tc->flags |= TCF_IN_FOR_INIT; if (tt == TOK_VAR) { - (void) GetToken(context, &tokenStream); + (void) js_GetToken(context, &tokenStream); pn1 = variables(false); #if JS_HAS_BLOCK_SCOPE } else if (tt == TOK_LET) { let = true; - (void) GetToken(context, &tokenStream); - if (PeekToken(context, &tokenStream) == TOK_LP) { + (void) js_GetToken(context, &tokenStream); + if (js_PeekToken(context, &tokenStream) == TOK_LP) { pn1 = letBlock(JS_FALSE); tt = TOK_LEXICALSCOPE; } else { @@ -4824,13 +4837,13 @@ JSCompiler::statement() * as we've excluded 'in' from being parsed in RelExpr by setting * the TCF_IN_FOR_INIT flag in our JSTreeContext. */ - if (pn1 && MatchToken(context, &tokenStream, TOK_IN)) { + if (pn1 && js_MatchToken(context, &tokenStream, TOK_IN)) { pn->pn_iflags |= JSITER_ENUMERATE; stmtInfo.type = STMT_FOR_IN_LOOP; /* Check that the left side of the 'in' is valid. */ - JS_ASSERT(!TokenTypeIsDecl(tt) || PN_TYPE(pn1) == tt); - if (TokenTypeIsDecl(tt) + JS_ASSERT(!TOKEN_TYPE_IS_DECL(tt) || PN_TYPE(pn1) == tt); + if (TOKEN_TYPE_IS_DECL(tt) ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST #if JS_HAS_DESTRUCTURING || (JSVERSION_NUMBER(context) == JSVERSION_1_7 && @@ -4859,8 +4872,8 @@ JSCompiler::statement() pn1->pn_op != JSOP_XMLNAME) && #endif pn1->pn_type != TOK_LB)) { - ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + js_ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -4868,7 +4881,7 @@ JSCompiler::statement() pn2 = NULL; uintN dflag = PND_ASSIGNED; - if (TokenTypeIsDecl(tt)) { + if (TOKEN_TYPE_IS_DECL(tt)) { /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */ pn1->pn_xflags |= PNX_FORINVAR; @@ -5028,7 +5041,7 @@ JSCompiler::statement() /* Parse the loop condition or null into pn2. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = js_PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_SEMI) { pn2 = NULL; @@ -5041,7 +5054,7 @@ JSCompiler::statement() /* Parse the update expression or null into pn3. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = js_PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RP) { pn3 = NULL; @@ -5090,8 +5103,8 @@ JSCompiler::statement() return pn; bad_for_each: - ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_FOR_EACH_LOOP); + js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_FOR_EACH_LOOP); return NULL; } @@ -5130,7 +5143,7 @@ JSCompiler::statement() PopStatement(tc); catchList = NULL; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_CATCH) { catchList = ListNode::create(tc); if (!catchList) @@ -5145,8 +5158,8 @@ JSCompiler::statement() /* Check for another catch after unconditional catch. */ if (lastCatch && !lastCatch->pn_kid2) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_AFTER_GENERAL); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_AFTER_GENERAL); return NULL; } @@ -5182,7 +5195,7 @@ JSCompiler::statement() data.binder = BindLet; data.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -5204,8 +5217,8 @@ JSCompiler::statement() break; default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_IDENTIFIER); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_IDENTIFIER); return NULL; } @@ -5216,7 +5229,7 @@ JSCompiler::statement() * to avoid conflicting with the JS2/ECMAv4 type annotation * catchguard syntax. */ - if (MatchToken(context, &tokenStream, TOK_IF)) { + if (js_MatchToken(context, &tokenStream, TOK_IF)) { pn2->pn_kid2 = expr(); if (!pn2->pn_kid2) return NULL; @@ -5234,7 +5247,7 @@ JSCompiler::statement() catchList->append(pnblock); lastCatch = pn2; tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; } while (tt == TOK_CATCH); } @@ -5250,11 +5263,11 @@ JSCompiler::statement() MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); PopStatement(tc); } else { - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); } if (!catchList && !pn->pn_kid3) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_OR_FINALLY); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_OR_FINALLY); return NULL; } return pn; @@ -5267,13 +5280,13 @@ JSCompiler::statement() /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ tokenStream.flags |= TSF_OPERAND; - tt = PeekTokenSameLine(context, &tokenStream); + tt = js_PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } @@ -5287,13 +5300,13 @@ JSCompiler::statement() /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ case TOK_CATCH: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_WITHOUT_TRY); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_WITHOUT_TRY); return NULL; case TOK_FINALLY: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_FINALLY_WITHOUT_TRY); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_FINALLY_WITHOUT_TRY); return NULL; case TOK_BREAK: @@ -5307,8 +5320,8 @@ JSCompiler::statement() if (label) { for (; ; stmt = stmt->down) { if (!stmt) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_LABEL_NOT_FOUND); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL && stmt->label == label) @@ -5317,8 +5330,8 @@ JSCompiler::statement() } else { for (; ; stmt = stmt->down) { if (!stmt) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOUGH_BREAK); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOUGH_BREAK); return NULL; } if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH) @@ -5340,15 +5353,15 @@ JSCompiler::statement() if (label) { for (stmt2 = NULL; ; stmt = stmt->down) { if (!stmt) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL) { if (stmt->label == label) { if (!stmt2 || !STMT_IS_LOOP(stmt2)) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); return NULL; } break; @@ -5360,8 +5373,8 @@ JSCompiler::statement() } else { for (; ; stmt = stmt->down) { if (!stmt) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); return NULL; } if (STMT_IS_LOOP(stmt)) @@ -5376,14 +5389,14 @@ JSCompiler::statement() /* * In most cases, we want the constructs forbidden in strict mode * code to be a subset of those that JSOPTION_STRICT warns about, and - * we should use ReportStrictModeError. However, 'with' is the sole + * we should use js_ReportStrictModeError. However, 'with' is the sole * instance of a construct that is forbidden in strict mode code, but * doesn't even merit a warning under JSOPTION_STRICT. See * https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. */ if (tc->flags & TCF_STRICT_MODE_CODE) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_STRICT_CODE_WITH); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_STRICT_CODE_WITH); return NULL; } @@ -5424,7 +5437,7 @@ JSCompiler::statement() JSObjectBox *blockbox; /* Check for a let statement or let expression. */ - if (PeekToken(context, &tokenStream) == TOK_LP) { + if (js_PeekToken(context, &tokenStream) == TOK_LP) { pn = letBlock(JS_TRUE); if (!pn || pn->pn_op == JSOP_LEAVEBLOCK) return pn; @@ -5449,8 +5462,8 @@ JSCompiler::statement() stmt = tc->topStmt; if (stmt && (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_LET_DECL_NOT_IN_BLOCK); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_LET_DECL_NOT_IN_BLOCK); return NULL; } @@ -5594,14 +5607,14 @@ JSCompiler::statement() pn = UnaryNode::create(tc); if (!pn) return NULL; - if (!MatchToken(context, &tokenStream, TOK_NAME) || + if (!js_MatchToken(context, &tokenStream, TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.xmlAtom || - !MatchToken(context, &tokenStream, TOK_NAME) || + !js_MatchToken(context, &tokenStream, TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.namespaceAtom || - !MatchToken(context, &tokenStream, TOK_ASSIGN) || + !js_MatchToken(context, &tokenStream, TOK_ASSIGN) || tokenStream.currentToken().t_op != JSOP_NOP) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_DEFAULT_XML_NAMESPACE); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_DEFAULT_XML_NAMESPACE); return NULL; } @@ -5623,28 +5636,28 @@ JSCompiler::statement() #if JS_HAS_XML_SUPPORT expression: #endif - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); pn2 = expr(); if (!pn2) return NULL; - if (PeekToken(context, &tokenStream) == TOK_COLON) { + if (js_PeekToken(context, &tokenStream) == TOK_COLON) { if (pn2->pn_type != TOK_NAME) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_LABEL); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_LABEL); return NULL; } label = pn2->pn_atom; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_LABEL && stmt->label == label) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_DUPLICATE_LABEL); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_DUPLICATE_LABEL); return NULL; } } ForgetUse(pn2); - (void) GetToken(context, &tokenStream); + (void) js_GetToken(context, &tokenStream); /* Push a label struct and parse the statement. */ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); @@ -5724,7 +5737,7 @@ NoteArgumentsUse(JSTreeContext *tc) JSParseNode * JSCompiler::variables(bool inLetHead) { - TokenType tt; + JSTokenType tt; bool let; JSStmtInfo *scopeStmt; BindData data; @@ -5777,7 +5790,7 @@ JSCompiler::variables(bool inLetHead) } do { - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); #if JS_HAS_DESTRUCTURING if (tt == TOK_LB || tt == TOK_LC) { tc->flags |= TCF_DECL_DESTRUCTURING; @@ -5789,7 +5802,7 @@ JSCompiler::variables(bool inLetHead) if (!CheckDestructuring(context, &data, pn2, NULL, tc)) return NULL; if ((tc->flags & TCF_IN_FOR_INIT) && - PeekToken(context, &tokenStream) == TOK_IN) { + js_PeekToken(context, &tokenStream) == TOK_IN) { pn->append(pn2); continue; } @@ -5825,8 +5838,8 @@ JSCompiler::variables(bool inLetHead) if (tt != TOK_NAME) { if (tt != TOK_ERROR) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); } return NULL; } @@ -5842,7 +5855,7 @@ JSCompiler::variables(bool inLetHead) return NULL; pn->append(pn2); - if (MatchToken(context, &tokenStream, TOK_ASSIGN)) { + if (js_MatchToken(context, &tokenStream, TOK_ASSIGN)) { if (tokenStream.currentToken().t_op != JSOP_NOP) goto bad_var_init; @@ -5892,14 +5905,14 @@ JSCompiler::variables(bool inLetHead) tc->flags |= TCF_FUN_HEAVYWEIGHT; } } - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; return pn; bad_var_init: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_VAR_INIT); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_VAR_INIT); return NULL; } @@ -5909,7 +5922,7 @@ JSCompiler::expr() JSParseNode *pn, *pn2; pn = assignExpr(); - if (pn && MatchToken(context, &tokenStream, TOK_COMMA)) { + if (pn && js_MatchToken(context, &tokenStream, TOK_COMMA)) { pn2 = ListNode::create(tc); if (!pn2) return NULL; @@ -5920,9 +5933,9 @@ JSCompiler::expr() #if JS_HAS_GENERATORS pn2 = pn->last(); if (pn2->pn_type == TOK_YIELD && !pn2->pn_parens) { - ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + js_ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return NULL; } #endif @@ -5930,7 +5943,7 @@ JSCompiler::expr() if (!pn2) return NULL; pn->append(pn2); - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; } return pn; @@ -5940,14 +5953,14 @@ JSParseNode * JSCompiler::assignExpr() { JSParseNode *pn, *rhs; - TokenType tt; + JSTokenType tt; JSOp op; JS_CHECK_RECURSION(context, return NULL); #if JS_HAS_GENERATORS tokenStream.flags |= TSF_OPERAND; - if (MatchToken(context, &tokenStream, TOK_YIELD)) { + if (js_MatchToken(context, &tokenStream, TOK_YIELD)) { tokenStream.flags &= ~TSF_OPERAND; return returnOrYield(true); } @@ -5958,7 +5971,7 @@ JSCompiler::assignExpr() if (!pn) return NULL; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { tt = CheckGetterOrSetter(context, &tokenStream, TOK_ASSIGN); @@ -5967,7 +5980,7 @@ JSCompiler::assignExpr() } #endif if (tt != TOK_ASSIGN) { - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); return pn; } @@ -5989,8 +6002,8 @@ JSCompiler::assignExpr() case TOK_RB: case TOK_RC: if (op != JSOP_NOP) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_DESTRUCT_ASS); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_DESTRUCT_ASS); return NULL; } rhs = assignExpr(); @@ -6011,8 +6024,8 @@ JSCompiler::assignExpr() /* FALL THROUGH */ #endif default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_LEFTSIDE_OF_ASS); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_LEFTSIDE_OF_ASS); return NULL; } @@ -6043,7 +6056,7 @@ JSCompiler::condExpr() uintN oldflags; pn = orExpr(); - if (pn && MatchToken(context, &tokenStream, TOK_HOOK)) { + if (pn && js_MatchToken(context, &tokenStream, TOK_HOOK)) { pn1 = pn; pn = TernaryNode::create(tc); if (!pn) @@ -6079,7 +6092,7 @@ JSCompiler::orExpr() JSParseNode *pn; pn = andExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_OR)) + while (pn && js_MatchToken(context, &tokenStream, TOK_OR)) pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr(), tc); return pn; } @@ -6090,7 +6103,7 @@ JSCompiler::andExpr() JSParseNode *pn; pn = bitOrExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_AND)) + while (pn && js_MatchToken(context, &tokenStream, TOK_AND)) pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr(), tc); return pn; } @@ -6101,7 +6114,7 @@ JSCompiler::bitOrExpr() JSParseNode *pn; pn = bitXorExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_BITOR)) { + while (pn && js_MatchToken(context, &tokenStream, TOK_BITOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr(), tc); } return pn; @@ -6113,7 +6126,7 @@ JSCompiler::bitXorExpr() JSParseNode *pn; pn = bitAndExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_BITXOR)) { + while (pn && js_MatchToken(context, &tokenStream, TOK_BITXOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr(), tc); } return pn; @@ -6125,7 +6138,7 @@ JSCompiler::bitAndExpr() JSParseNode *pn; pn = eqExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_BITAND)) + while (pn && js_MatchToken(context, &tokenStream, TOK_BITAND)) pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr(), tc); return pn; } @@ -6137,7 +6150,7 @@ JSCompiler::eqExpr() JSOp op; pn = relExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_EQOP)) { + while (pn && js_MatchToken(context, &tokenStream, TOK_EQOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr(), tc); } @@ -6148,7 +6161,7 @@ JSParseNode * JSCompiler::relExpr() { JSParseNode *pn; - TokenType tt; + JSTokenType tt; JSOp op; uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT; @@ -6160,13 +6173,13 @@ JSCompiler::relExpr() pn = shiftExpr(); while (pn && - (MatchToken(context, &tokenStream, TOK_RELOP) || + (js_MatchToken(context, &tokenStream, TOK_RELOP) || /* * Recognize the 'in' token as an operator only if we're not * currently in the init expr of a for loop. */ - (inForInitFlag == 0 && MatchToken(context, &tokenStream, TOK_IN)) || - MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { + (inForInitFlag == 0 && js_MatchToken(context, &tokenStream, TOK_IN)) || + js_MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr(), tc); @@ -6184,7 +6197,7 @@ JSCompiler::shiftExpr() JSOp op; pn = addExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_SHOP)) { + while (pn && js_MatchToken(context, &tokenStream, TOK_SHOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr(), tc); } @@ -6195,13 +6208,13 @@ JSParseNode * JSCompiler::addExpr() { JSParseNode *pn; - TokenType tt; + JSTokenType tt; JSOp op; pn = mulExpr(); while (pn && - (MatchToken(context, &tokenStream, TOK_PLUS) || - MatchToken(context, &tokenStream, TOK_MINUS))) { + (js_MatchToken(context, &tokenStream, TOK_PLUS) || + js_MatchToken(context, &tokenStream, TOK_MINUS))) { tt = tokenStream.currentToken().type; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, mulExpr(), tc); @@ -6213,13 +6226,13 @@ JSParseNode * JSCompiler::mulExpr() { JSParseNode *pn; - TokenType tt; + JSTokenType tt; JSOp op; pn = unaryExpr(); while (pn && - (MatchToken(context, &tokenStream, TOK_STAR) || - MatchToken(context, &tokenStream, TOK_DIVOP))) { + (js_MatchToken(context, &tokenStream, TOK_STAR) || + js_MatchToken(context, &tokenStream, TOK_DIVOP))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(), tc); @@ -6228,7 +6241,7 @@ JSCompiler::mulExpr() } static JSParseNode * -SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, +SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSParseNode *pn, JSParseNode *kid, const char *name) { if (kid->pn_type != TOK_NAME && @@ -6239,7 +6252,8 @@ SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) && #endif kid->pn_type != TOK_LB) { - ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name); + js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, + JSMSG_BAD_OPERAND, name); return NULL; } if (!CheckStrictAssignment(cx, tc, kid)) @@ -6251,9 +6265,9 @@ SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, static const char incop_name_str[][10] = {"increment", "decrement"}; static JSBool -SetIncOpKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, +SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSParseNode *pn, JSParseNode *kid, - TokenType tt, JSBool preorder) + JSTokenType tt, JSBool preorder) { JSOp op; @@ -6301,13 +6315,13 @@ SetIncOpKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode * JSCompiler::unaryExpr() { - TokenType tt; + JSTokenType tt; JSParseNode *pn, *pn2; JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; switch (tt) { @@ -6363,8 +6377,7 @@ JSCompiler::unaryExpr() } break; case TOK_NAME: - if (!ReportStrictModeError(context, &tokenStream, tc, pn, - JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!js_ReportStrictModeError(context, &tokenStream, tc, pn, JSMSG_DEPRECATED_DELETE_OPERAND)) return NULL; pn2->pn_op = JSOP_DELNAME; break; @@ -6377,7 +6390,7 @@ JSCompiler::unaryExpr() return NULL; default: - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); pn = memberExpr(JS_TRUE); if (!pn) return NULL; @@ -6385,10 +6398,10 @@ JSCompiler::unaryExpr() /* Don't look across a newline boundary for a postfix incop. */ if (tokenStream.onCurrentLine(pn->pn_pos)) { tokenStream.flags |= TSF_OPERAND; - tt = PeekTokenSameLine(context, &tokenStream); + tt = js_PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_INC || tt == TOK_DEC) { - (void) GetToken(context, &tokenStream); + (void) js_GetToken(context, &tokenStream); pn2 = UnaryNode::create(tc); if (!pn2) return NULL; @@ -6633,13 +6646,13 @@ CompExprTransplanter::transplant(JSParseNode *pn) */ JSParseNode * JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, - TokenType type, JSOp op) + JSTokenType type, JSOp op) { uintN adjust; JSParseNode *pn, *pn2, *pn3, **pnp; JSStmtInfo stmtInfo; BindData data; - TokenType tt; + JSTokenType tt; JSAtom *atom; JS_ASSERT(tokenStream.currentToken().type == TOK_FOR); @@ -6704,16 +6717,16 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, pn2->pn_op = JSOP_ITER; pn2->pn_iflags = JSITER_ENUMERATE; - if (MatchToken(context, &tokenStream, TOK_NAME)) { + if (js_MatchToken(context, &tokenStream, TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn2->pn_iflags |= JSITER_FOREACH; else - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); atom = NULL; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -6742,8 +6755,8 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, break; default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); case TOK_ERROR: return NULL; @@ -6765,8 +6778,8 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, if (JSVERSION_NUMBER(context) == JSVERSION_1_7) { /* Destructuring requires [key, value] enumeration in JS1.7. */ if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -6792,9 +6805,9 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, return NULL; *pnp = pn2; pnp = &pn2->pn_right; - } while (MatchToken(context, &tokenStream, TOK_FOR)); + } while (js_MatchToken(context, &tokenStream, TOK_FOR)); - if (MatchToken(context, &tokenStream, TOK_IF)) { + if (js_MatchToken(context, &tokenStream, TOK_IF)) { pn2 = TernaryNode::create(tc); if (!pn2) return NULL; @@ -6926,7 +6939,7 @@ JSCompiler::argumentList(JSParseNode *listNode) JSBool matched; tokenStream.flags |= TSF_OPERAND; - matched = MatchToken(context, &tokenStream, TOK_RP); + matched = js_MatchToken(context, &tokenStream, TOK_RP); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { do { @@ -6936,15 +6949,15 @@ JSCompiler::argumentList(JSParseNode *listNode) #if JS_HAS_GENERATORS if (argNode->pn_type == TOK_YIELD && !argNode->pn_parens && - PeekToken(context, &tokenStream) == TOK_COMMA) { - ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + js_PeekToken(context, &tokenStream) == TOK_COMMA) { + js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return JS_FALSE; } #endif #if JS_HAS_GENERATOR_EXPRS - if (MatchToken(context, &tokenStream, TOK_FOR)) { + if (js_MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pn = UnaryNode::create(tc); if (!pn) return JS_FALSE; @@ -6952,20 +6965,20 @@ JSCompiler::argumentList(JSParseNode *listNode) if (!argNode) return JS_FALSE; if (listNode->pn_count > 1 || - PeekToken(context, &tokenStream) == TOK_COMMA) { - ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + js_PeekToken(context, &tokenStream) == TOK_COMMA) { + js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); return JS_FALSE; } } #endif listNode->append(argNode); - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); - if (GetToken(context, &tokenStream) != TOK_RP) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_PAREN_AFTER_ARGS); + if (js_GetToken(context, &tokenStream) != TOK_RP) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_PAREN_AFTER_ARGS); return JS_FALSE; } } @@ -6991,13 +7004,13 @@ JSParseNode * JSCompiler::memberExpr(JSBool allowCallSyntax) { JSParseNode *pn, *pn2, *pn3; - TokenType tt; + JSTokenType tt; JS_CHECK_RECURSION(context, return NULL); /* Check for new expression first. */ tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_NEW) { pn = ListNode::create(tc); @@ -7011,7 +7024,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn->initList(pn2); pn->pn_pos.begin = pn2->pn_pos.begin; - if (MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) + if (js_MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) return NULL; if (pn->pn_count > ARGC_LIMIT) { JS_ReportErrorNumber(context, js_GetErrorMessage, NULL, @@ -7040,14 +7053,14 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } } - while ((tt = GetToken(context, &tokenStream)) > TOK_EOF) { + while ((tt = js_GetToken(context, &tokenStream)) > TOK_EOF) { if (tt == TOK_DOT) { pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7066,12 +7079,12 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) /* A filtering predicate is like a with statement. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; - } else if (TokenTypeIsXML(PN_TYPE(pn3))) { + } else if (TOKEN_TYPE_IS_XML(PN_TYPE(pn3))) { pn2->pn_type = TOK_LB; pn2->pn_op = JSOP_GETELEM; } else { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); return NULL; } pn2->pn_arity = PN_BINARY; @@ -7094,7 +7107,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7104,9 +7117,9 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn3->pn_type = TOK_STRING; pn3->pn_arity = PN_NULLARY; pn3->pn_op = JSOP_QNAMEPART; - } else if (!TokenTypeIsXML(tt)) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); + } else if (!TOKEN_TYPE_IS_XML(tt)) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); return NULL; } pn2->pn_op = JSOP_DESCENDANTS; @@ -7187,7 +7200,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } pn2->pn_pos.end = tokenStream.currentToken().pos.end; } else { - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); return pn; } @@ -7308,7 +7321,7 @@ JSParseNode * JSCompiler::qualifiedSuffix(JSParseNode *pn) { JSParseNode *pn2, *pn3; - TokenType tt; + JSTokenType tt; JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON); pn2 = NameNode::create(NULL, tc); @@ -7320,7 +7333,7 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) pn->pn_op = JSOP_NAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { /* Inline and specialize propertySelector for JSOP_QNAMECONST. */ @@ -7335,8 +7348,8 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) } if (tt != TOK_LB) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } pn3 = endBracketedExpr(); @@ -7360,7 +7373,7 @@ JSCompiler::qualifiedIdentifier() pn = propertySelector(); if (!pn) return NULL; - if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; pn = qualifiedSuffix(pn); @@ -7372,7 +7385,7 @@ JSParseNode * JSCompiler::attributeIdentifier() { JSParseNode *pn, *pn2; - TokenType tt; + JSTokenType tt; JS_ASSERT(tokenStream.currentToken().type == TOK_AT); pn = UnaryNode::create(tc); @@ -7380,15 +7393,15 @@ JSCompiler::attributeIdentifier() return NULL; pn->pn_op = JSOP_TOATTRNAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { pn2 = qualifiedIdentifier(); } else if (tt == TOK_LB) { pn2 = endBracketedExpr(); } else { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } if (!pn2) @@ -7442,7 +7455,7 @@ JSCompiler::xmlAtomNode() JSParseNode *pn = NullaryNode::create(tc); if (!pn) return NULL; - Token *tp = tokenStream.mutableCurrentToken(); + JSToken *tp = tokenStream.mutableCurrentToken(); pn->pn_op = tp->t_op; pn->pn_atom = tp->t_atom; if (tp->type == TOK_XMLPI) @@ -7466,7 +7479,7 @@ JSParseNode * JSCompiler::xmlNameExpr() { JSParseNode *pn, *pn2, *list; - TokenType tt; + JSTokenType tt; pn = list = NULL; do { @@ -7498,9 +7511,9 @@ JSCompiler::xmlNameExpr() pn->pn_pos.end = pn2->pn_pos.end; pn->append(pn2); } - } while ((tt = GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); + } while ((tt = js_GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); return pn; } @@ -7530,10 +7543,10 @@ JSCompiler::xmlNameExpr() * we parsed exactly one expression. */ JSParseNode * -JSCompiler::xmlTagContent(TokenType tagtype, JSAtom **namep) +JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) { JSParseNode *pn, *pn2, *list; - TokenType tt; + JSTokenType tt; pn = xmlNameExpr(); if (!pn) @@ -7541,10 +7554,10 @@ JSCompiler::xmlTagContent(TokenType tagtype, JSAtom **namep) *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; list = NULL; - while (MatchToken(context, &tokenStream, TOK_XMLSPACE)) { - tt = GetToken(context, &tokenStream); + while (js_MatchToken(context, &tokenStream, TOK_XMLSPACE)) { + tt = js_GetToken(context, &tokenStream); if (tt != TOK_XMLNAME && tt != TOK_LC) { - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); break; } @@ -7564,19 +7577,19 @@ JSCompiler::xmlTagContent(TokenType tagtype, JSAtom **namep) if (!XML_FOLDABLE(pn2)) pn->pn_xflags |= PNX_CANTFOLD; - MatchToken(context, &tokenStream, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); - MatchToken(context, &tokenStream, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_XMLATTR) { pn2 = xmlAtomNode(); } else if (tt == TOK_LC) { pn2 = xmlExpr(JS_TRUE); pn->pn_xflags |= PNX_CANTFOLD; } else { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_ATTR_VALUE); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_ATTR_VALUE); return NULL; } if (!pn2) @@ -7588,15 +7601,15 @@ JSCompiler::xmlTagContent(TokenType tagtype, JSAtom **namep) return pn; } -#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ - JS_BEGIN_MACRO \ - if ((tt) <= TOK_EOF) { \ - if ((tt) == TOK_EOF) { \ - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ - JSMSG_END_OF_XML_SOURCE); \ - } \ - return result; \ - } \ +#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ + JS_BEGIN_MACRO \ + if ((tt) <= TOK_EOF) { \ + if ((tt) == TOK_EOF) { \ + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ + JSMSG_END_OF_XML_SOURCE); \ + } \ + return result; \ + } \ JS_END_MACRO /* @@ -7606,14 +7619,14 @@ JSCompiler::xmlTagContent(TokenType tagtype, JSAtom **namep) JSBool JSCompiler::xmlElementContent(JSParseNode *pn) { - TokenType tt; + JSTokenType tt; JSParseNode *pn2; JSAtom *textAtom; tokenStream.flags &= ~TSF_XMLTAGMODE; for (;;) { tokenStream.flags |= TSF_XMLTEXTMODE; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_XMLTEXTMODE; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); @@ -7629,7 +7642,7 @@ JSCompiler::xmlElementContent(JSParseNode *pn) } tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); if (tt == TOK_XMLETAGO) @@ -7667,7 +7680,7 @@ JSParseNode * JSCompiler::xmlElementOrList(JSBool allowList) { JSParseNode *pn, *pn2, *list; - TokenType tt; + JSTokenType tt; JSAtom *startAtom, *endAtom; JS_CHECK_RECURSION(context, return NULL); @@ -7678,7 +7691,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; tokenStream.flags |= TSF_XMLTAGMODE; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_ERROR) return NULL; @@ -7689,9 +7702,9 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn2 = xmlTagContent(TOK_XMLSTAGO, &startAtom); if (!pn2) return NULL; - MatchToken(context, &tokenStream, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_XMLPTAGC) { /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ if (pn2->pn_type == TOK_XMLSTAGO) { @@ -7710,8 +7723,8 @@ JSCompiler::xmlElementOrList(JSBool allowList) } else { /* We had better have a tag-close (>) at this point. */ if (tt != TOK_XMLTAGC) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } pn2->pn_pos.end = tokenStream.currentToken().pos.end; @@ -7739,11 +7752,11 @@ JSCompiler::xmlElementOrList(JSBool allowList) if (!xmlElementContent(pn)) return NULL; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); if (tt != TOK_XMLNAME && tt != TOK_LC) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } @@ -7753,16 +7766,18 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; if (pn2->pn_type == TOK_XMLETAGO) { /* Oops, end tag has attributes! */ - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } if (endAtom && startAtom && endAtom != startAtom) { JSString *str = ATOM_TO_STRING(startAtom); /* End vs. start tag name mismatch: point to the tag name. */ - ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_UC | JSREPORT_ERROR, - JSMSG_XML_TAG_NAME_MISMATCH, str->chars()); + js_ReportCompileErrorNumber(context, &tokenStream, pn2, + JSREPORT_UC | JSREPORT_ERROR, + JSMSG_XML_TAG_NAME_MISMATCH, + str->chars()); return NULL; } @@ -7779,7 +7794,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn->pn_xflags |= PNX_CANTFOLD; } - MatchToken(context, &tokenStream, TOK_XMLSPACE); + js_MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); } @@ -7796,8 +7811,8 @@ JSCompiler::xmlElementOrList(JSBool allowList) MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX); } else { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_NAME_SYNTAX); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_NAME_SYNTAX); return NULL; } @@ -7837,13 +7852,13 @@ JSCompiler::parseXMLText(JSObject *chain, bool allowList) /* Set XML-only mode to turn off special treatment of {expr} in XML. */ tokenStream.flags |= TSF_OPERAND | TSF_XMLONLYMODE; - TokenType tt = GetToken(context, &tokenStream); + JSTokenType tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; JSParseNode *pn; if (tt != TOK_XMLSTAGO) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); pn = NULL; } else { pn = xmlElementOrListRoot(allowList); @@ -7890,7 +7905,7 @@ BlockIdInScope(uintN blockid, JSTreeContext *tc) #endif JSParseNode * -JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) +JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) { JSParseNode *pn, *pn2, *pn3; JSOp op; @@ -7909,7 +7924,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; pn2 = NullaryNode::create(tc); if (!pn2) @@ -7944,18 +7959,18 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) #endif tokenStream.flags |= TSF_OPERAND; - matched = MatchToken(context, &tokenStream, TOK_RB); + matched = js_MatchToken(context, &tokenStream, TOK_RB); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { for (index = 0; ; index++) { if (index == JS_ARGS_LENGTH_MAX) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_ARRAY_INIT_TOO_BIG); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_ARRAY_INIT_TOO_BIG); return NULL; } tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = js_PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RB) { pn->pn_xflags |= PNX_ENDCOMMA; @@ -7964,7 +7979,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) if (tt == TOK_COMMA) { /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ - MatchToken(context, &tokenStream, TOK_COMMA); + js_MatchToken(context, &tokenStream, TOK_COMMA); pn2 = NullaryNode::create(tc); pn->pn_xflags |= PNX_HOLEY; } else { @@ -7976,7 +7991,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) if (tt != TOK_COMMA) { /* If we didn't already match TOK_COMMA in above case. */ - if (!MatchToken(context, &tokenStream, TOK_COMMA)) + if (!js_MatchToken(context, &tokenStream, TOK_COMMA)) break; } } @@ -8026,7 +8041,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) */ if (index == 0 && pn->pn_count != 0 && - MatchToken(context, &tokenStream, TOK_FOR)) { + js_MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pnexp, *pntop; /* Relabel pn as an array comprehension node. */ @@ -8083,7 +8098,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) for (;;) { JSAtom *atom; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; switch (tt) { case TOK_NUMBER: @@ -8108,10 +8123,10 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) goto property_name; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt != TOK_NAME) { - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); goto property_name; } atom = tokenStream.currentToken().t_atom; @@ -8138,12 +8153,12 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) case TOK_RC: goto end_obj_init; default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_PROP_ID); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_PROP_ID); return NULL; } - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); op = JSOP_INITPROP; #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { @@ -8160,8 +8175,8 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) #if JS_HAS_DESTRUCTURING_SHORTHAND if (tt != TOK_COMMA && tt != TOK_RC) { #endif - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_COLON_AFTER_ID); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_COLON_AFTER_ID); return NULL; #if JS_HAS_DESTRUCTURING_SHORTHAND } @@ -8170,7 +8185,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) * Support, e.g., |var {x, y} = o| as destructuring shorthand * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8. */ - UngetToken(&tokenStream); + js_UngetToken(&tokenStream); pn->pn_xflags |= PNX_DESTRUCT; pnval = pn3; if (pnval->pn_type == TOK_NAME) { @@ -8211,8 +8226,8 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) if (ALE_INDEX(ale) & attributesMask) { const char *name = js_AtomToPrintableString(context, atom); if (!name || - !ReportStrictModeError(context, &tokenStream, tc, NULL, - JSMSG_DUPLICATE_PROPERTY, name)) { + !js_ReportStrictModeError(context, &tokenStream, tc, NULL, + JSMSG_DUPLICATE_PROPERTY, name)) { return NULL; } } @@ -8225,12 +8240,12 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) } } - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); if (tt == TOK_RC) goto end_obj_init; if (tt != TOK_COMMA) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CURLY_AFTER_LIST); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CURLY_AFTER_LIST); return NULL; } afterComma = JS_TRUE; @@ -8256,7 +8271,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) return NULL; pn->pn_num = (jsint) tokenStream.currentToken().t_dval; tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = js_GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_USESHARP || tt == TOK_DEFSHARP || #if JS_HAS_XML_SUPPORT @@ -8264,8 +8279,8 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) tt == TOK_XMLSTAGO /* XXXbe could be sharp? */ || #endif tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_PRIMARY) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_SHARP_VAR_DEF); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_SHARP_VAR_DEF); return NULL; } pn->pn_kid = primaryExpr(tt, JS_FALSE); @@ -8369,7 +8384,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) } } else if ((!afterDot #if JS_HAS_XML_SUPPORT - || PeekToken(context, &tokenStream) == TOK_DBLCOLON + || js_PeekToken(context, &tokenStream) == TOK_DBLCOLON #endif ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) { JSStmtInfo *stmt = js_LexicalLookup(tc, pn->pn_atom, NULL); @@ -8431,7 +8446,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) */ JS_ASSERT(PN_TYPE(dn) == TOK_NAME); JS_ASSERT(dn->pn_op == JSOP_NOP); - if (PeekToken(context, &tokenStream) != TOK_LP) + if (js_PeekToken(context, &tokenStream) != TOK_LP) dn->pn_dflags |= PND_FUNARG; } } @@ -8440,7 +8455,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) LinkUseToDef(pn, dn, tc); /* Here we handle the backward function reference case. */ - if (PeekToken(context, &tokenStream) != TOK_LP) + if (js_PeekToken(context, &tokenStream) != TOK_LP) dn->pn_dflags |= PND_FUNARG; pn->pn_dflags |= (dn->pn_dflags & PND_FUNARG); @@ -8448,7 +8463,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) } #if JS_HAS_XML_SUPPORT - if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { if (afterDot) { JSString *str; @@ -8463,8 +8478,8 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) pn->pn_arity = PN_NULLARY; pn->pn_type = TOK_FUNCTION; } else if (tt != TOK_EOF) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_KEYWORD_NOT_NS); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_KEYWORD_NOT_NS); return NULL; } } @@ -8522,8 +8537,8 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) return NULL; default: - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } return pn; @@ -8532,7 +8547,7 @@ JSCompiler::primaryExpr(TokenType tt, JSBool afterDot) JSParseNode * JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) { - TokenPtr begin; + JSTokenPtr begin; JSParseNode *pn; JS_ASSERT(tokenStream.currentToken().type == TOK_LP); @@ -8545,15 +8560,18 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; #if JS_HAS_GENERATOR_EXPRS - if (MatchToken(context, &tokenStream, TOK_FOR)) { + if (js_MatchToken(context, &tokenStream, TOK_FOR)) { if (pn->pn_type == TOK_YIELD && !pn->pn_parens) { - ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); + js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return NULL; } if (pn->pn_type == TOK_COMMA && !pn->pn_parens) { - ReportCompileErrorNumber(context, &tokenStream, pn->last(), JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); + js_ReportCompileErrorNumber(context, &tokenStream, pn->last(), + JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); return NULL; } if (!pn1) { @@ -8566,9 +8584,10 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; pn->pn_pos.begin = begin; if (genexp) { - if (GetToken(context, &tokenStream) != TOK_RP) { - ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); + if (js_GetToken(context, &tokenStream) != TOK_RP) { + js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); return NULL; } pn->pn_pos.end = tokenStream.currentToken().pos.end; @@ -8585,7 +8604,7 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) * XXX handles only strings and numbers for now */ static JSBool -FoldType(JSContext *cx, JSParseNode *pn, TokenType type) +FoldType(JSContext *cx, JSParseNode *pn, JSTokenType type) { if (PN_TYPE(pn) != type) { switch (type) { @@ -8708,7 +8727,7 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, static JSBool FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) { - TokenType tt; + JSTokenType tt; JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 07f4f34e0cbf..396ba74d134d 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -296,9 +296,9 @@ struct JSParseNode { pn_defn:1; /* this node is a JSDefinition */ #define PN_OP(pn) ((JSOp)(pn)->pn_op) -#define PN_TYPE(pn) ((js::TokenType)(pn)->pn_type) +#define PN_TYPE(pn) ((JSTokenType)(pn)->pn_type) - js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ + JSTokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ int32 pn_offset; /* first generated bytecode offset */ JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */ JSParseNode *pn_link; /* def/use link (alignment freebie); @@ -387,7 +387,7 @@ struct JSParseNode { #define pn_atom2 pn_u.apair.atom2 protected: - void inline init(js::TokenType type, JSOp op, JSParseNodeArity arity) { + void inline init(JSTokenType type, JSOp op, JSParseNodeArity arity) { pn_type = type; pn_op = op; pn_arity = arity; @@ -400,7 +400,7 @@ protected: static JSParseNode *create(JSParseNodeArity arity, JSTreeContext *tc); public: - static JSParseNode *newBinaryOrAppend(js::TokenType tt, JSOp op, JSParseNode *left, + static JSParseNode *newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, JSTreeContext *tc); /* @@ -493,9 +493,9 @@ public: /* True if pn is a parsenode representing a literal constant. */ bool isLiteral() const { - return PN_TYPE(this) == js::TOK_NUMBER || - PN_TYPE(this) == js::TOK_STRING || - (PN_TYPE(this) == js::TOK_PRIMARY && PN_OP(this) != JSOP_THIS); + return PN_TYPE(this) == TOK_NUMBER || + PN_TYPE(this) == TOK_STRING || + (PN_TYPE(this) == TOK_PRIMARY && PN_OP(this) != JSOP_THIS); } /* @@ -506,10 +506,10 @@ public: * we'll need additional flags that we can test here. */ bool isDirectivePrologueMember() const { - if (PN_TYPE(this) == js::TOK_SEMI) { + if (PN_TYPE(this) == TOK_SEMI) { JS_ASSERT(pn_arity == PN_UNARY); JSParseNode *kid = pn_kid; - return kid && PN_TYPE(kid) == js::TOK_STRING && !kid->pn_parens; + return kid && PN_TYPE(kid) == TOK_STRING && !kid->pn_parens; } return false; } @@ -756,7 +756,7 @@ struct JSDefinition : public JSParseNode JSDefinition *resolve() { JSParseNode *pn = this; while (!pn->pn_defn) { - if (pn->pn_type == js::TOK_ASSIGN) { + if (pn->pn_type == TOK_ASSIGN) { pn = pn->pn_left; continue; } @@ -781,9 +781,9 @@ struct JSDefinition : public JSParseNode static const char *kindString(Kind kind); Kind kind() { - if (PN_TYPE(this) == js::TOK_FUNCTION) + if (PN_TYPE(this) == TOK_FUNCTION) return FUNCTION; - JS_ASSERT(PN_TYPE(this) == js::TOK_NAME); + JS_ASSERT(PN_TYPE(this) == TOK_NAME); if (PN_OP(this) == JSOP_NOP) return UNKNOWN; if (PN_OP(this) == JSOP_GETARG) @@ -916,7 +916,7 @@ struct JSCompiler : private js::AutoGCRooter { JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; - js::TokenStream tokenStream; + JSTokenStream tokenStream; void *tempPoolMark; /* initial JSContext.tempPool mark */ JSPrincipals *principals; /* principals associated with source */ JSStackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */ @@ -1015,7 +1015,7 @@ private: JSParseNode *mulExpr(); JSParseNode *unaryExpr(); JSParseNode *memberExpr(JSBool allowCallSyntax); - JSParseNode *primaryExpr(js::TokenType tt, JSBool afterDot); + JSParseNode *primaryExpr(JSTokenType tt, JSBool afterDot); JSParseNode *parenExpr(JSParseNode *pn1, JSBool *genexp); /* @@ -1026,13 +1026,13 @@ private: JSParseNode *functionDef(uintN lambda); JSParseNode *condition(); JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid, - js::TokenType type = js::TOK_SEMI, JSOp op = JSOP_NOP); + JSTokenType type = TOK_SEMI, JSOp op = JSOP_NOP); JSParseNode *generatorExpr(JSParseNode *pn, JSParseNode *kid); JSBool argumentList(JSParseNode *listNode); JSParseNode *bracketedExpr(); JSParseNode *letBlock(JSBool statement); JSParseNode *returnOrYield(bool useAssignExpr); - JSParseNode *destructuringExpr(BindData *data, js::TokenType tt); + JSParseNode *destructuringExpr(BindData *data, JSTokenType tt); #if JS_HAS_XML_SUPPORT JSParseNode *endBracketedExpr(); @@ -1044,7 +1044,7 @@ private: JSParseNode *xmlExpr(JSBool inTag); JSParseNode *xmlAtomNode(); JSParseNode *xmlNameExpr(); - JSParseNode *xmlTagContent(js::TokenType tagtype, JSAtom **namep); + JSParseNode *xmlTagContent(JSTokenType tagtype, JSAtom **namep); JSBool xmlElementContent(JSParseNode *pn); JSParseNode *xmlElementOrList(JSBool allowList); JSParseNode *xmlElementOrListRoot(JSBool allowList); diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 6171bd68964e..7773972938f4 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -105,6 +105,10 @@ typedef struct JSEmptyScope JSEmptyScope; typedef struct JSTempValueRooter JSTempValueRooter; typedef struct JSThread JSThread; typedef struct JSThreadData JSThreadData; +typedef struct JSToken JSToken; +typedef struct JSTokenPos JSTokenPos; +typedef struct JSTokenPtr JSTokenPtr; +typedef struct JSTokenStream JSTokenStream; typedef struct JSTreeContext JSTreeContext; typedef struct JSTryNote JSTryNote; typedef struct JSWeakRoots JSWeakRoots; @@ -146,11 +150,6 @@ class TraceRecorder; struct TraceMonitor; class CallStack; -struct TokenStream; -struct Token; -struct TokenPos; -struct TokenPtr; - class ContextAllocPolicy; class SystemAllocPolicy; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 4afef943c6c0..20754462d056 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -178,7 +178,7 @@ struct RENode { typedef struct CompilerState { JSContext *context; - TokenStream *tokenStream; /* For reporting errors */ + JSTokenStream *tokenStream; /* For reporting errors */ const jschar *cpbegin; const jschar *cpend; const jschar *cp; @@ -441,8 +441,9 @@ ReportRegExpErrorHelper(CompilerState *state, uintN flags, uintN errorNumber, const jschar *arg) { if (state->tokenStream) { - return ReportCompileErrorNumber(state->context, state->tokenStream, - NULL, JSREPORT_UC | flags, errorNumber, arg); + return js_ReportCompileErrorNumber(state->context, state->tokenStream, + NULL, JSREPORT_UC | flags, + errorNumber, arg); } return JS_ReportErrorFlagsAndNumberUC(state->context, flags, js_GetErrorMessage, NULL, @@ -1957,7 +1958,7 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth, } static JSBool -CompileRegExpToAST(JSContext* cx, TokenStream* ts, +CompileRegExpToAST(JSContext* cx, JSTokenStream* ts, JSString* str, uintN flags, CompilerState& state) { uintN i; @@ -3336,7 +3337,7 @@ GetNativeRegExp(JSContext* cx, JSRegExp* re) #endif JSRegExp * -js_NewRegExp(JSContext *cx, TokenStream *ts, +js_NewRegExp(JSContext *cx, JSTokenStream *ts, JSString *str, uintN flags, JSBool flat) { JSRegExp *re; @@ -5831,7 +5832,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) } JSObject * -js_NewRegExpObject(JSContext *cx, TokenStream *ts, +js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, const jschar *chars, size_t length, uintN flags) { JSString *str; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 73cfee817450..b439f0782516 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -120,7 +120,7 @@ struct JSRegExp { }; extern JSRegExp * -js_NewRegExp(JSContext *cx, js::TokenStream *ts, +js_NewRegExp(JSContext *cx, JSTokenStream *ts, JSString *str, uintN flags, JSBool flat); extern JSRegExp * @@ -183,7 +183,7 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp); * Create, serialize/deserialize, or clone a RegExp object. */ extern JSObject * -js_NewRegExpObject(JSContext *cx, js::TokenStream *ts, +js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, const jschar *chars, size_t length, uintN flags); extern JSBool diff --git a/js/src/jsscan.cpp b/js/src/jsscan.cpp index c832d692442e..a3e2b4ddcea4 100644 --- a/js/src/jsscan.cpp +++ b/js/src/jsscan.cpp @@ -86,7 +86,7 @@ using namespace js; struct keyword { const char *chars; /* C string with keyword text */ - TokenType tokentype; + JSTokenType tokentype; /* JSTokenType */ JSOp op; /* JSOp */ JSVersion version; /* JSVersion */ }; @@ -137,7 +137,7 @@ FindKeyword(const jschar *s, size_t length) return NULL; } -TokenType +JSTokenType js_CheckKeyword(const jschar *str, size_t length) { const struct keyword *kw; @@ -175,7 +175,7 @@ js_IsIdentifier(JSString *str) #endif /* Initialize members that aren't initialized in |init|. */ -TokenStream::TokenStream(JSContext *cx) +JSTokenStream::JSTokenStream(JSContext *cx) : cx(cx), tokens(), cursor(), lookahead(), ungetpos(), ungetbuf(), flags(), linelen(), linepos(), file(), listenerTSData(), saveEOL(), tokenbuf(cx) {} @@ -185,15 +185,16 @@ TokenStream::TokenStream(JSContext *cx) #endif bool -TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, uintN ln) +JSTokenStream::init(const jschar *base, size_t length, + FILE *fp, const char *fn, uintN ln) { jschar *buf; JS_ASSERT_IF(fp, !base); JS_ASSERT_IF(!base, length == 0); size_t nb = fp - ? 2 * LINE_LIMIT * sizeof(jschar) - : LINE_LIMIT * sizeof(jschar); + ? 2 * JS_LINE_LIMIT * sizeof(jschar) + : JS_LINE_LIMIT * sizeof(jschar); JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb); if (!buf) { js_ReportOutOfScriptQuota(cx); @@ -207,8 +208,8 @@ TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, u linebuf.base = linebuf.limit = linebuf.ptr = buf; if (fp) { file = fp; - userbuf.base = buf + LINE_LIMIT; - userbuf.ptr = userbuf.limit = userbuf.base + LINE_LIMIT; + userbuf.base = buf + JS_LINE_LIMIT; + userbuf.ptr = userbuf.limit = userbuf.base + JS_LINE_LIMIT; } else { userbuf.base = (jschar *)base; userbuf.limit = (jschar *)base + length; @@ -220,7 +221,7 @@ TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, u } void -TokenStream::close() +JSTokenStream::close() { if (flags & TSF_OWNFILENAME) cx->free((void *) filename); @@ -264,12 +265,12 @@ js_fgets(char *buf, int size, FILE *file) } int32 -TokenStream::getChar() +JSTokenStream::getChar() { int32 c; ptrdiff_t i, j, len, olen; JSBool crflag; - char cbuf[LINE_LIMIT]; + char cbuf[JS_LINE_LIMIT]; jschar *ubuf, *nl; if (ungetpos != 0) { @@ -285,7 +286,7 @@ TokenStream::getChar() /* Fill userbuf so that \r and \r\n convert to \n. */ crflag = (flags & TSF_CRFLAG) != 0; - len = js_fgets(cbuf, LINE_LIMIT - crflag, file); + len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, file); if (len <= 0) { flags |= TSF_EOF; return EOF; @@ -337,12 +338,12 @@ TokenStream::getChar() /* * If there was a line terminator, copy thru it into linebuf. - * Else copy LINE_LIMIT-1 bytes into linebuf. + * Else copy JS_LINE_LIMIT-1 bytes into linebuf. */ if (nl < userbuf.limit) len = (nl - userbuf.ptr) + 1; - if (len >= (ptrdiff_t) LINE_LIMIT) { - len = LINE_LIMIT - 1; + if (len >= JS_LINE_LIMIT) { + len = JS_LINE_LIMIT - 1; saveEOL = nl; } else { saveEOL = NULL; @@ -418,7 +419,7 @@ TokenStream::getChar() } void -TokenStream::ungetChar(int32 c) +JSTokenStream::ungetChar(int32 c) { if (c == EOF) return; @@ -434,7 +435,7 @@ TokenStream::ungetChar(int32 c) * be used to peek into or past a newline. */ JSBool -TokenStream::peekChars(intN n, jschar *cp) +JSTokenStream::peekChars(intN n, jschar *cp) { intN i, j; int32 c; @@ -455,8 +456,8 @@ TokenStream::peekChars(intN n, jschar *cp) } bool -TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, - va_list ap) +JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, + uintN errorNumber, va_list ap) { JSErrorReport report; char *message; @@ -465,11 +466,11 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro char *linebytes; bool warning; JSBool ok; - TokenPos *tp; + JSTokenPos *tp; uintN index, i; JSErrorReporter onError; - JS_ASSERT(linebuf.limit < linebuf.base + LINE_LIMIT); + JS_ASSERT(linebuf.limit < linebuf.base + JS_LINE_LIMIT); if (JSREPORT_IS_STRICT(flags) && !JS_HAS_STRICT_OPTION(cx)) return JS_TRUE; @@ -624,8 +625,8 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro } bool -js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, - uintN errorNumber, ...) +js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParseNode *pn, uintN errorNumber, ...) { bool result; va_list ap; @@ -652,14 +653,14 @@ js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSP } bool -js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, - uintN flags, uintN errorNumber, ...) +js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, + uintN flags, uintN errorNumber, ...) { va_list ap; /* * We don't accept a JSTreeContext argument, so we can't implement - * JSREPORT_STRICT_MODE_ERROR here. Use ReportStrictModeError instead, + * JSREPORT_STRICT_MODE_ERROR here. Use js_ReportStrictModeError instead, * or do the checks in the caller and pass plain old JSREPORT_ERROR. */ JS_ASSERT(!(flags & JSREPORT_STRICT_MODE_ERROR)); @@ -675,7 +676,7 @@ js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, #if JS_HAS_XML_SUPPORT JSBool -TokenStream::getXMLEntity() +JSTokenStream::getXMLEntity() { ptrdiff_t offset, length, i; int c, d; @@ -692,7 +693,8 @@ TokenStream::getXMLEntity() return JS_FALSE; while ((c = getChar()) != ';') { if (c == EOF || c == '\n') { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_END_OF_XML_ENTITY); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_END_OF_XML_ENTITY); return JS_FALSE; } if (!tb.append(c)) @@ -784,7 +786,8 @@ TokenStream::getXMLEntity() JS_ASSERT((tb.end() - bp) >= 1); bytes = js_DeflateString(cx, bp + 1, (tb.end() - bp) - 1); if (bytes) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, msg, bytes); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + msg, bytes); cx->free(bytes); } return JS_FALSE; @@ -798,7 +801,7 @@ TokenStream::getXMLEntity() * Otherwise, non-destructively return the original '\'. */ int32 -TokenStream::getUnicodeEscape() +JSTokenStream::getUnicodeEscape() { jschar cp[5]; int32 c; @@ -817,11 +820,11 @@ TokenStream::getUnicodeEscape() return '\\'; } -Token * -TokenStream::newToken(ptrdiff_t adjust) +JSToken * +JSTokenStream::newToken(ptrdiff_t adjust) { - cursor = (cursor + 1) & ntokensMask; - Token *tp = mutableCurrentToken(); + cursor = (cursor + 1) & NTOKENS_MASK; + JSToken *tp = mutableCurrentToken(); tp->ptr = linebuf.ptr + adjust; tp->pos.begin.index = linepos + (tp->ptr - linebuf.base) - ungetpos; tp->pos.begin.lineno = tp->pos.end.lineno = lineno; @@ -843,12 +846,12 @@ atomize(JSContext *cx, JSCharBuffer &cb) return js_AtomizeChars(cx, cb.begin(), cb.length(), 0); } -TokenType -TokenStream::getTokenInternal() +JSTokenType +JSTokenStream::getTokenInternal() { - TokenType tt; + JSTokenType tt; int c, qc; - Token *tp; + JSToken *tp; JSAtom *atom; JSBool hadUnicodeEscape; const struct keyword *kw; @@ -924,8 +927,9 @@ TokenStream::getTokenInternal() (nextc = peekChar(), ((flags & TSF_XMLONLYMODE) || nextc != '{') && !JS_ISXMLNAME(nextc))) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_QNAME); + js_ReportCompileErrorNumber(cx, this, NULL, + JSREPORT_ERROR, + JSMSG_BAD_XML_QNAME); goto error; } sawColon = JS_TRUE; @@ -961,8 +965,8 @@ TokenStream::getTokenInternal() qc = c; while ((c = getChar()) != qc) { if (c == EOF) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); goto error; } @@ -1010,7 +1014,8 @@ TokenStream::getTokenInternal() bad_xml_char: default: - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_CHARACTER); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_CHARACTER); goto error; } /* NOTREACHED */ @@ -1066,8 +1071,11 @@ TokenStream::getTokenInternal() !(flags & TSF_KEYWORD_IS_NAME) && (kw = FindKeyword(tokenbuf.begin(), tokenbuf.length()))) { if (kw->tokentype == TOK_RESERVED) { - if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_RESERVED_ID, kw->chars)) { + if (!js_ReportCompileErrorNumber(cx, this, NULL, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_RESERVED_ID, + kw->chars)) { goto error; } } else if (kw->version <= JSVERSION_NUMBER(cx)) { @@ -1115,7 +1123,7 @@ TokenStream::getTokenInternal() if (radix == 8) { /* Octal integer literals are not permitted in strict mode code. */ - if (!ReportStrictModeError(cx, this, NULL, NULL, JSMSG_DEPRECATED_OCTAL)) + if (!js_ReportStrictModeError(cx, this, NULL, NULL, JSMSG_DEPRECATED_OCTAL)) goto error; /* @@ -1124,8 +1132,9 @@ TokenStream::getTokenInternal() * might not always be so permissive, so we warn about it. */ if (c >= '8') { - if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING, - JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) { + if (!js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING, + JSMSG_BAD_OCTAL, + c == '8' ? "08" : "09")) { goto error; } radix = 10; @@ -1155,8 +1164,8 @@ TokenStream::getTokenInternal() c = getChar(); } if (!JS7_ISDEC(c)) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_MISSING_EXPONENT); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_MISSING_EXPONENT); goto error; } do { @@ -1168,7 +1177,8 @@ TokenStream::getTokenInternal() } if (JS_ISIDSTART(c)) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_IDSTART_AFTER_NUMBER); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_IDSTART_AFTER_NUMBER); goto error; } @@ -1179,13 +1189,15 @@ TokenStream::getTokenInternal() if (radix == 10) { if (!js_strtod(cx, tokenbuf.begin(), tokenbuf.end(), &endptr, &dval)) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_OUT_OF_MEMORY); goto error; } } else { if (!js_strtointeger(cx, tokenbuf.begin(), tokenbuf.end(), &endptr, radix, &dval)) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_OUT_OF_MEMORY); goto error; } } @@ -1200,8 +1212,8 @@ TokenStream::getTokenInternal() while ((c = getChar()) != qc) { if (c == '\n' || c == EOF) { ungetChar(c); - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); goto error; } if (c == '\\') { @@ -1220,8 +1232,8 @@ TokenStream::getTokenInternal() c = peekChar(); /* Strict mode code allows only \0, then a non-digit. */ if (val != 0 || JS7_ISDEC(c)) { - if (!ReportStrictModeError(cx, this, NULL, NULL, - JSMSG_DEPRECATED_OCTAL)) { + if (!js_ReportStrictModeError(cx, this, NULL, NULL, + JSMSG_DEPRECATED_OCTAL)) { goto error; } } @@ -1514,7 +1526,8 @@ TokenStream::getTokenInternal() goto out; bad_xml_markup: - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); goto error; } #endif /* JS_HAS_XML_SUPPORT */ @@ -1634,7 +1647,7 @@ TokenStream::getTokenInternal() continue; } ungetChar(c); - cursor = (cursor - 1) & ntokensMask; + cursor = (cursor - 1) & NTOKENS_MASK; goto retry; } @@ -1645,8 +1658,8 @@ TokenStream::getTokenInternal() /* Ignore all characters until comment close. */ } if (c == EOF) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_COMMENT); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_COMMENT); goto error; } if ((flags & TSF_NEWLINES) && linenoBefore != lineno) { @@ -1654,7 +1667,7 @@ TokenStream::getTokenInternal() tt = TOK_EOL; goto eol_out; } - cursor = (cursor - 1) & ntokensMask; + cursor = (cursor - 1) & NTOKENS_MASK; goto retry; } @@ -1667,8 +1680,8 @@ TokenStream::getTokenInternal() c = getChar(); if (c == '\n' || c == EOF) { ungetChar(c); - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_REGEXP); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_REGEXP); goto error; } if (c == '\\') { @@ -1705,8 +1718,8 @@ TokenStream::getTokenInternal() char buf[2] = { '\0' }; tp->pos.begin.index += length + 1; buf[0] = (char)c; - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_REGEXP_FLAG, - buf); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_BAD_REGEXP_FLAG, buf); (void) getChar(); goto error; } @@ -1774,7 +1787,8 @@ TokenStream::getTokenInternal() break; n = 10 * n + JS7_UNDEC(c); if (n >= UINT16_LIMIT) { - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_SHARPVAR_TOO_BIG); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_SHARPVAR_TOO_BIG); goto error; } } @@ -1783,8 +1797,11 @@ TokenStream::getTokenInternal() (c == '=' || c == '#')) { char buf[20]; JS_snprintf(buf, sizeof buf, "#%u%c", n, c); - if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_DEPRECATED_USAGE, buf)) { + if (!js_ReportCompileErrorNumber(cx, this, NULL, + JSREPORT_WARNING | + JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, + buf)) { goto error; } } @@ -1803,7 +1820,8 @@ TokenStream::getTokenInternal() #endif default: - ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_ILLEGAL_CHARACTER); + js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_ILLEGAL_CHARACTER); goto error; } diff --git a/js/src/jsscan.h b/js/src/jsscan.h index 7706bd70b217..815ec528f64f 100644 --- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -50,14 +50,14 @@ #include "jspubtd.h" #include "jsvector.h" +JS_BEGIN_EXTERN_C + #define JS_KEYWORD(keyword, type, op, version) \ extern const char js_##keyword##_str[]; #include "jskeyword.tbl" #undef JS_KEYWORD -namespace js { - -enum TokenType { +typedef enum JSTokenType { TOK_ERROR = -1, /* well-known as the only code < EOF */ TOK_EOF = 0, /* end of file */ TOK_EOL = 1, /* end of line */ @@ -144,91 +144,87 @@ enum TokenType { tree full of uses of those names */ TOK_RESERVED, /* reserved keywords */ TOK_LIMIT /* domain size */ -}; +} JSTokenType; -static inline bool TokenTypeIsXML(TokenType tt) -{ - return tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME; -} +#define IS_PRIMARY_TOKEN(tt) \ + ((uintN)((tt) - TOK_NAME) <= (uintN)(TOK_PRIMARY - TOK_NAME)) -static inline bool TreeTypeIsXML(TokenType tt) -{ - return tt == TOK_XMLCOMMENT || tt == TOK_XMLCDATA || tt == TOK_XMLPI || tt == TOK_XMLELEM || - tt == TOK_XMLLIST; -} +#define TOKEN_TYPE_IS_XML(tt) \ + ((tt) == TOK_AT || (tt) == TOK_DBLCOLON || (tt) == TOK_ANYNAME) -static inline bool TokenTypeIsDecl(TokenType tt) -{ -# if JS_HAS_BLOCK_SCOPE - return tt == TOK_VAR || tt == TOK_LET; -# else - return tt == TOK_VAR; -# endif -} +#define TREE_TYPE_IS_XML(tt) \ + ((tt) == TOK_XMLCOMMENT || (tt) == TOK_XMLCDATA || (tt) == TOK_XMLPI || \ + (tt) == TOK_XMLELEM || (tt) == TOK_XMLLIST) -struct TokenPtr { +#if JS_HAS_BLOCK_SCOPE +# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR || (tt) == TOK_LET) +#else +# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR) +#endif + +struct JSTokenPtr { uint32 index; /* index of char in physical line */ uint32 lineno; /* physical line number */ - bool operator==(const TokenPtr& bptr) { + bool operator==(const JSTokenPtr& bptr) { return index == bptr.index && lineno == bptr.lineno; } - bool operator!=(const TokenPtr& bptr) { + bool operator!=(const JSTokenPtr& bptr) { return index != bptr.index || lineno != bptr.lineno; } - bool operator <(const TokenPtr& bptr) { + bool operator <(const JSTokenPtr& bptr) { return lineno < bptr.lineno || (lineno == bptr.lineno && index < bptr.index); } - bool operator <=(const TokenPtr& bptr) { + bool operator <=(const JSTokenPtr& bptr) { return lineno < bptr.lineno || (lineno == bptr.lineno && index <= bptr.index); } - bool operator >(const TokenPtr& bptr) { + bool operator >(const JSTokenPtr& bptr) { return !(*this <= bptr); } - bool operator >=(const TokenPtr& bptr) { + bool operator >=(const JSTokenPtr& bptr) { return !(*this < bptr); } }; -struct TokenPos { - TokenPtr begin; /* first character and line of token */ - TokenPtr end; /* index 1 past last char, last line */ +struct JSTokenPos { + JSTokenPtr begin; /* first character and line of token */ + JSTokenPtr end; /* index 1 past last char, last line */ - bool operator==(const TokenPos& bpos) { + bool operator==(const JSTokenPos& bpos) { return begin == bpos.begin && end == bpos.end; } - bool operator!=(const TokenPos& bpos) { + bool operator!=(const JSTokenPos& bpos) { return begin != bpos.begin || end != bpos.end; } - bool operator <(const TokenPos& bpos) { + bool operator <(const JSTokenPos& bpos) { return begin < bpos.begin; } - bool operator <=(const TokenPos& bpos) { + bool operator <=(const JSTokenPos& bpos) { return begin <= bpos.begin; } - bool operator >(const TokenPos& bpos) { + bool operator >(const JSTokenPos& bpos) { return !(*this <= bpos); } - bool operator >=(const TokenPos& bpos) { + bool operator >=(const JSTokenPos& bpos) { return !(*this < bpos); } }; -struct Token { - TokenType type; /* char value or above enumerator */ - TokenPos pos; /* token position in file */ +struct JSToken { + JSTokenType type; /* char value or above enumerator */ + JSTokenPos pos; /* token position in file */ jschar *ptr; /* beginning of token in line buffer */ union { struct { /* name or string literal */ @@ -245,7 +241,19 @@ struct Token { } u; }; -enum TokenStreamFlags +#define t_op u.s.op +#define t_reflags u.reflags +#define t_atom u.s.atom +#define t_atom2 u.p.atom2 +#define t_dval u.dval + +#define JS_LINE_LIMIT 256 /* logical line buffer size limit -- + physical line length is unlimited */ +#define NTOKENS 4 /* 1 current + 2 lookahead, rounded */ +#define NTOKENS_MASK (NTOKENS-1) /* to power of 2 to avoid divmod by 3 */ + + +enum JSTokenStreamFlags { TSF_ERROR = 0x01, /* fatal error while compiling */ TSF_EOF = 0x02, /* hit end of file */ @@ -290,24 +298,12 @@ enum TokenStreamFlags TSF_STRICT_MODE_CODE = 0x8000 }; -#define t_op u.s.op -#define t_reflags u.reflags -#define t_atom u.s.atom -#define t_atom2 u.p.atom2 -#define t_dval u.dval - -const size_t LINE_LIMIT = 256; /* logical line buffer size limit - -- physical line length is unlimited */ - -class TokenStream +class JSTokenStream { - static const size_t ntokens = 4; /* 1 current + 2 lookahead, rounded - to power of 2 to avoid divmod by 3 */ - static const uintN ntokensMask = ntokens - 1; public: /* - * To construct a TokenStream, first call the constructor, which is - * infallible, then call |init|, which can fail. To destroy a TokenStream, + * To construct a JSTokenStream, first call the constructor, which is + * infallible, then call |init|, which can fail. To destroy a JSTokenStream, * first call |close| then call the destructor. If |init| fails, do not call * |close|. * @@ -315,7 +311,7 @@ class TokenStream * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE * after calling |close|. */ - TokenStream(JSContext *); + JSTokenStream(JSContext *); /* * Create a new token stream, either from an input buffer or from a file. @@ -323,14 +319,14 @@ class TokenStream */ bool init(const jschar *base, size_t length, FILE *fp, const char *filename, uintN lineno); void close(); - ~TokenStream() {} + ~JSTokenStream() {} /* Accessors. */ JSContext *getContext() const { return cx; } - bool onCurrentLine(const TokenPos &pos) const { return lineno == pos.end.lineno; } - const Token ¤tToken() const { return tokens[cursor]; } - const Token &getTokenAt(size_t index) const { - JS_ASSERT(index < ntokens); + bool onCurrentLine(const JSTokenPos &pos) const { return lineno == pos.end.lineno; } + const JSToken ¤tToken() const { return tokens[cursor]; } + const JSToken &getTokenAt(size_t index) const { + JS_ASSERT(index < NTOKENS); return tokens[index]; } const JSCharBuffer &getTokenbuf() const { return tokenbuf; } @@ -338,16 +334,16 @@ class TokenStream uintN getLineno() const { return lineno; } /* Mutators. */ - Token *mutableCurrentToken() { return &tokens[cursor]; } + JSToken *mutableCurrentToken() { return &tokens[cursor]; } bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); - TokenType getToken() { + JSTokenType getToken() { /* Check for a pushed-back token resulting from mismatching lookahead. */ while (lookahead != 0) { JS_ASSERT(!(flags & TSF_XMLTEXTMODE)); lookahead--; - cursor = (cursor + 1) & ntokensMask; - TokenType tt = currentToken().type; + cursor = (cursor + 1) & NTOKENS_MASK; + JSTokenType tt = currentToken().type; if (tt != TOK_EOL || (flags & TSF_NEWLINES)) return tt; } @@ -359,36 +355,36 @@ class TokenStream return getTokenInternal(); } - Token *getMutableTokenAt(size_t index) { - JS_ASSERT(index < ntokens); + JSToken *getMutableTokenAt(size_t index) { + JS_ASSERT(index < NTOKENS); return &tokens[index]; } void ungetToken() { - JS_ASSERT(lookahead < ntokensMask); + JS_ASSERT(lookahead < NTOKENS_MASK); lookahead++; - cursor = (cursor - 1) & ntokensMask; + cursor = (cursor - 1) & NTOKENS_MASK; } - TokenType peekToken() { + JSTokenType peekToken() { if (lookahead != 0) { - return tokens[(cursor + lookahead) & ntokensMask].type; + return tokens[(cursor + lookahead) & NTOKENS_MASK].type; } - TokenType tt = getToken(); + JSTokenType tt = getToken(); ungetToken(); return tt; } - TokenType peekTokenSameLine() { + JSTokenType peekTokenSameLine() { if (!onCurrentLine(currentToken().pos)) return TOK_EOL; flags |= TSF_NEWLINES; - TokenType tt = peekToken(); + JSTokenType tt = peekToken(); flags &= ~TSF_NEWLINES; return tt; } - JSBool matchToken(TokenType tt) { + JSBool matchToken(JSTokenType tt) { if (getToken() == tt) return JS_TRUE; ungetToken(); @@ -396,16 +392,16 @@ class TokenStream } private: - typedef struct TokenBuf { + typedef struct JSTokenBuf { jschar *base; /* base of line or stream buffer */ jschar *limit; /* limit for quick bounds check */ jschar *ptr; /* next char to get, or slot to use */ - } TokenBuf; + } JSTokenBuf; - TokenType getTokenInternal(); /* doesn't check for pushback or error flag. */ + JSTokenType getTokenInternal(); /* doesn't check for pushback or error flag. */ int32 getChar(); void ungetChar(int32 c); - Token *newToken(ptrdiff_t adjust); + JSToken *newToken(ptrdiff_t adjust); int32 getUnicodeEscape(); JSBool peekChars(intN n, jschar *cp); JSBool getXMLEntity(); @@ -430,7 +426,7 @@ class TokenStream } JSContext * const cx; - Token tokens[ntokens];/* circular token buffer */ + JSToken tokens[NTOKENS];/* circular token buffer */ uintN cursor; /* index of last parsed token */ uintN lookahead; /* count of lookahead tokens */ @@ -442,9 +438,9 @@ class TokenStream private: uint32 linelen; /* physical linebuf segment length */ uint32 linepos; /* linebuf offset in physical line */ - TokenBuf linebuf; /* line buffer for diagnostics */ + JSTokenBuf linebuf; /* line buffer for diagnostics */ - TokenBuf userbuf; /* user input buffer if !file */ + JSTokenBuf userbuf; /* user input buffer if !file */ const char *filename; /* input filename or null */ FILE *file; /* stdio stream if reading from file */ JSSourceHandler listener; /* callback for source; eg debugger */ @@ -455,14 +451,12 @@ class TokenStream JSCharBuffer tokenbuf; /* current token string buffer */ }; -} /* namespace js */ - /* Unicode separators that are treated as line terminators, in addition to \n, \r */ #define LINE_SEPARATOR 0x2028 #define PARA_SEPARATOR 0x2029 extern void -js_CloseTokenStream(JSContext *cx, js::TokenStream *ts); +js_CloseTokenStream(JSContext *cx, JSTokenStream *ts); extern JS_FRIEND_API(int) js_fgets(char *buf, int size, FILE *file); @@ -471,7 +465,7 @@ js_fgets(char *buf, int size, FILE *file); * If the given char array forms JavaScript keyword, return corresponding * token. Otherwise return TOK_EOF. */ -extern js::TokenType +extern JSTokenType js_CheckKeyword(const jschar *chars, size_t length); /* @@ -487,56 +481,54 @@ typedef void (*JSMapKeywordFun)(const char *); extern JSBool js_IsIdentifier(JSString *str); -/* - * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error - * message have const jschar* type, not const char*. - */ -#define JSREPORT_UC 0x100 - -namespace js { - /* * Report a compile-time error by its number. Return true for a warning, false * for an error. When pn is not null, use it to report error's location. * Otherwise use ts, which must not be null. */ bool -ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN flags, - uintN errorNumber, ...); +js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, + uintN flags, uintN errorNumber, ...); /* * Report a condition that should elicit a warning with JSOPTION_STRICT, * or an error if ts or tc is handling strict mode code. This function - * defers to ReportCompileErrorNumber to do the real work. Either tc + * defers to js_ReportCompileErrorNumber to do the real work. Either tc * or ts may be NULL, if there is no tree context or token stream state * whose strictness should affect the report. * - * One could have ReportCompileErrorNumber recognize the + * One could have js_ReportCompileErrorNumber recognize the * JSREPORT_STRICT_MODE_ERROR flag instead of having a separate function * like this one. However, the strict mode code flag we need to test is * in the JSTreeContext structure for that code; we would have to change - * the ~120 ReportCompileErrorNumber calls to pass the additional + * the ~120 js_ReportCompileErrorNumber calls to pass the additional * argument, even though many of those sites would never use it. Using * ts's TSF_STRICT_MODE_CODE flag instead of tc's would be brittle: at some * points ts's flags don't correspond to those of the tc relevant to the * error. */ bool -ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, - uintN errorNumber, ...); +js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, + JSParseNode *pn, uintN errorNumber, ...); + +/* + * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error + * message have const jschar* type, not const char*. + */ +#define JSREPORT_UC 0x100 /* * Look ahead one token and return its type. */ -static inline TokenType -PeekToken(JSContext *cx, TokenStream *ts) +static inline JSTokenType +js_PeekToken(JSContext *cx, JSTokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->peekToken(); } -static inline TokenType -PeekTokenSameLine(JSContext *cx, TokenStream *ts) +static inline JSTokenType +js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->peekTokenSameLine(); @@ -545,8 +537,8 @@ PeekTokenSameLine(JSContext *cx, TokenStream *ts) /* * Get the next token from ts. */ -static inline TokenType -GetToken(JSContext *cx, TokenStream *ts) +static inline JSTokenType +js_GetToken(JSContext *cx, JSTokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->getToken(); @@ -556,7 +548,7 @@ GetToken(JSContext *cx, TokenStream *ts) * Push back the last scanned token onto ts. */ static inline void -UngetToken(TokenStream *ts) +js_UngetToken(JSTokenStream *ts) { ts->ungetToken(); } @@ -565,12 +557,12 @@ UngetToken(TokenStream *ts) * Get the next token from ts if its type is tt. */ static inline JSBool -MatchToken(JSContext *cx, TokenStream *ts, TokenType tt) +js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt) { JS_ASSERT(cx == ts->getContext()); return ts->matchToken(tt); } -} /* namespace js */ +JS_END_EXTERN_C #endif /* jsscan_h___ */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 8239ee78e9f1..5b54cf3e7925 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1012,7 +1012,8 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) } script->lineno = cg->firstLine; if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) { - ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET, "script"); + js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, + JSMSG_NEED_DIET, "script"); goto bad; } script->nslots = script->nfixed + cg->maxStackDepth; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index e5aff106faa5..684b5c4b3597 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -1268,10 +1268,11 @@ ParseNodeToQName(JSCompiler *jsc, JSParseNode *pn, } if (!uri) { - ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn, - JSREPORT_ERROR, JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(jsc->context, - STRING_TO_JSVAL(prefix))); + js_ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn, + JSREPORT_ERROR, + JSMSG_BAD_XML_NAMESPACE, + js_ValueToPrintableString(jsc->context, + STRING_TO_JSVAL(prefix))); return NULL; } @@ -1349,8 +1350,8 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, int stackDummy; if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, - JSMSG_OVER_RECURSED); + js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, + JSMSG_OVER_RECURSED); return NULL; } @@ -1488,10 +1489,11 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, /* Enforce "Well-formedness constraint: Unique Att Spec". */ for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { if (pn3->pn_atom == pn2->pn_atom) { - ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, - JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, + JSREPORT_ERROR, + JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); goto fail; } } @@ -1598,10 +1600,11 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, attrjqn = attrj->name; if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) && js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) { - ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, - JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, + JSREPORT_ERROR, + JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); goto fail; } } @@ -1638,10 +1641,11 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, xml_class = JSXML_CLASS_COMMENT; } else if (pn->pn_type == TOK_XMLPI) { if (IS_XML(str)) { - ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, - JSREPORT_ERROR, JSMSG_RESERVED_ID, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(str))); + js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, + JSREPORT_ERROR, + JSMSG_RESERVED_ID, + js_ValueToPrintableString(cx, + STRING_TO_JSVAL(str))); goto fail; } @@ -1686,7 +1690,8 @@ skip_child: #undef PN2X_SKIP_CHILD syntax: - ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); + js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); fail: js_LeaveLocalRootScope(cx); return NULL; From 07436ef88a30c40d15af0d415509730fb24b5d02 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Mar 2010 17:39:12 -0700 Subject: [PATCH 087/213] Attempt to (temporarily, for one build cycle only) preempt symbol-stripping on n810, so that the generated build will have symbols and thus can be debugged. r=evil-evil-awful-hack-this-is-the-worst-thing-I-have-ever-pushed-but-it-must-be-done --- testing/mochitest/ssltunnel/Makefile.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/testing/mochitest/ssltunnel/Makefile.in b/testing/mochitest/ssltunnel/Makefile.in index 71a3d9495678..e3f1f4d44ce2 100644 --- a/testing/mochitest/ssltunnel/Makefile.in +++ b/testing/mochitest/ssltunnel/Makefile.in @@ -65,4 +65,11 @@ ifeq ($(OS_ARCH),WINCE) EXTRA_LIBS += libcmt.lib endif +ifdef MOZ_PLATFORM_MAEMO +libs:: ssltunnel + if [ -e "$(DEPTH)/../mobile/config/autoconf.mk" ]; then \ + echo 'PKG_SKIP_STRIP=1' >> $(DEPTH)/../mobile/config/autoconf.mk; \ + fi +endif + include $(topsrcdir)/config/rules.mk From b132358b8eef28abf2e0cfaba1a39f508bc56709 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Mar 2010 17:42:31 -0700 Subject: [PATCH 088/213] Back out previous change now that it's triggered an n810 tinderbox build. r=sweet-clean-hackfree-code-again --- testing/mochitest/ssltunnel/Makefile.in | 7 ------- 1 file changed, 7 deletions(-) diff --git a/testing/mochitest/ssltunnel/Makefile.in b/testing/mochitest/ssltunnel/Makefile.in index e3f1f4d44ce2..71a3d9495678 100644 --- a/testing/mochitest/ssltunnel/Makefile.in +++ b/testing/mochitest/ssltunnel/Makefile.in @@ -65,11 +65,4 @@ ifeq ($(OS_ARCH),WINCE) EXTRA_LIBS += libcmt.lib endif -ifdef MOZ_PLATFORM_MAEMO -libs:: ssltunnel - if [ -e "$(DEPTH)/../mobile/config/autoconf.mk" ]; then \ - echo 'PKG_SKIP_STRIP=1' >> $(DEPTH)/../mobile/config/autoconf.mk; \ - fi -endif - include $(topsrcdir)/config/rules.mk From 734264345e7c38a4802e8c43ca39622d5817f795 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Mar 2010 17:39:12 -0700 Subject: [PATCH 089/213] (Again, Tinderbox cycles lied to me about when the build of which revision had started) attempt to (temporarily, for one build cycle only) preempt symbol-stripping on n810, so that the generated build will have symbols and thus can be debugged. r=evil-evil-awful-hack-this-is-the-worst-thing-I-have-ever-pushed-but-it-must-be-done --- testing/mochitest/ssltunnel/Makefile.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/testing/mochitest/ssltunnel/Makefile.in b/testing/mochitest/ssltunnel/Makefile.in index 71a3d9495678..e3f1f4d44ce2 100644 --- a/testing/mochitest/ssltunnel/Makefile.in +++ b/testing/mochitest/ssltunnel/Makefile.in @@ -65,4 +65,11 @@ ifeq ($(OS_ARCH),WINCE) EXTRA_LIBS += libcmt.lib endif +ifdef MOZ_PLATFORM_MAEMO +libs:: ssltunnel + if [ -e "$(DEPTH)/../mobile/config/autoconf.mk" ]; then \ + echo 'PKG_SKIP_STRIP=1' >> $(DEPTH)/../mobile/config/autoconf.mk; \ + fi +endif + include $(topsrcdir)/config/rules.mk From b8769ece3e65f8da36e2f68b179e5d02765763ee Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 19 Mar 2010 17:42:31 -0700 Subject: [PATCH 090/213] (Again) back out previous change now that it's triggered an n810 tinderbox build. r=sweet-clean-hackfree-code-again --- testing/mochitest/ssltunnel/Makefile.in | 7 ------- 1 file changed, 7 deletions(-) diff --git a/testing/mochitest/ssltunnel/Makefile.in b/testing/mochitest/ssltunnel/Makefile.in index e3f1f4d44ce2..71a3d9495678 100644 --- a/testing/mochitest/ssltunnel/Makefile.in +++ b/testing/mochitest/ssltunnel/Makefile.in @@ -65,11 +65,4 @@ ifeq ($(OS_ARCH),WINCE) EXTRA_LIBS += libcmt.lib endif -ifdef MOZ_PLATFORM_MAEMO -libs:: ssltunnel - if [ -e "$(DEPTH)/../mobile/config/autoconf.mk" ]; then \ - echo 'PKG_SKIP_STRIP=1' >> $(DEPTH)/../mobile/config/autoconf.mk; \ - fi -endif - include $(topsrcdir)/config/rules.mk From 014dbb62f84ba8888fd56b4c2ad363fabf3e8aee Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 15:08:03 -0700 Subject: [PATCH 091/213] Bug 552374 - nanojit: clean up asm_spill() and friends a little. r=edwsmith. --HG-- extra : convert_revision : 5806c6f3bf1257fc3142f5eb8718e01071bcbb35 --- js/src/nanojit/Assembler.cpp | 46 +++++++++++++++++------------- js/src/nanojit/Assembler.h | 46 +++++++++++++++--------------- js/src/nanojit/NativeARM.cpp | 52 +++++++++++++++++----------------- js/src/nanojit/NativeMIPS.cpp | 26 ++++++++--------- js/src/nanojit/NativePPC.cpp | 31 ++++++++++---------- js/src/nanojit/NativeSparc.cpp | 15 +++++----- js/src/nanojit/NativeX64.cpp | 21 +++++++------- js/src/nanojit/Nativei386.cpp | 25 ++++++---------- 8 files changed, 130 insertions(+), 132 deletions(-) diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index 90ad49278da6..7c06e19fe924 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -583,13 +583,13 @@ namespace nanojit Register Assembler::deprecated_prepResultReg(LIns *ins, RegisterMask allow) { #ifdef NANOJIT_IA32 - const bool pop = (allow & rmask(FST0)) && - (!ins->isInReg() || ins->getReg() != FST0); -#else - const bool pop = false; + // We used to have to worry about possibly popping the x87 stack here. + // But this function is no longer used on i386, and this assertion + // ensures that. + NanoAssert(0); #endif Register r = findRegFor(ins, allow); - deprecated_freeRsrcOf(ins, pop); + deprecated_freeRsrcOf(ins); return r; } @@ -627,38 +627,46 @@ namespace nanojit // which case the restore will have already been generated, so we now // generate the spill (unless the restore was actually a // rematerialize, in which case it's not necessary). - // - // As for 'pop': it's only relevant on i386 and if 'allow' includes - // FST0, in which case we have to pop if 'ins' isn't in FST0 in the - // post-regstate. This could be because 'ins' is unused, 'ins' is in - // a spill slot, or 'ins' is in an XMM register. #ifdef NANOJIT_IA32 + // If 'allow' includes FST0 we have to pop if 'ins' isn't in FST0 in + // the post-regstate. This could be because 'ins' is unused, 'ins' is + // in a spill slot, or 'ins' is in an XMM register. const bool pop = (allow & rmask(FST0)) && (!ins->isInReg() || ins->getReg() != FST0); #else const bool pop = false; #endif Register r = findRegFor(ins, allow); - asm_spilli(ins, pop); + asm_maybe_spill(ins, pop); +#ifdef NANOJIT_IA32 + if (!ins->isInAr() && pop && r == FST0) { + // This can only happen with a LIR_fcall to an impure function + // whose return value was ignored (ie. if ins->isInReg() was false + // prior to the findRegFor() call). + FSTP(FST0); // pop the fpu result since it isn't used + } +#endif return r; } - void Assembler::asm_spilli(LInsp ins, bool pop) + void Assembler::asm_maybe_spill(LInsp ins, bool pop) { int d = ins->isInAr() ? arDisp(ins) : 0; Register r = ins->getReg(); - verbose_only( RefBuf b; - if (d && (_logc->lcbits & LC_Assembly)) { - setOutputForEOL(" <= spill %s", - _thisfrag->lirbuf->printer->formatRef(&b, ins)); } ) - asm_spill(r, d, pop, ins->isN64()); + if (ins->isInAr()) { + verbose_only( RefBuf b; + if (_logc->lcbits & LC_Assembly) { + setOutputForEOL(" <= spill %s", + _thisfrag->lirbuf->printer->formatRef(&b, ins)); } ) + asm_spill(r, d, pop, ins->isN64()); + } } // XXX: This function is error-prone and should be phased out; see bug 513615. - void Assembler::deprecated_freeRsrcOf(LIns *ins, bool pop) + void Assembler::deprecated_freeRsrcOf(LIns *ins) { if (ins->isInReg()) { - asm_spilli(ins, pop); + asm_maybe_spill(ins, /*pop*/false); _allocator.retire(ins->getReg()); // free any register associated with entry ins->clearReg(); } diff --git a/js/src/nanojit/Assembler.h b/js/src/nanojit/Assembler.h index 5a67184a11c3..cf36b617a4d4 100644 --- a/js/src/nanojit/Assembler.h +++ b/js/src/nanojit/Assembler.h @@ -344,22 +344,22 @@ namespace nanojit void assignSaved(RegAlloc &saved, RegisterMask skip); LInsp findVictim(RegisterMask allow); - Register getBaseReg(LIns *i, int &d, RegisterMask allow); + Register getBaseReg(LIns *ins, int &d, RegisterMask allow); void getBaseReg2(RegisterMask allowValue, LIns* value, Register& rv, RegisterMask allowBase, LIns* base, Register& rb, int &d); #if NJ_USES_QUAD_CONSTANTS const uint64_t* findQuadConstant(uint64_t q); #endif - int findMemFor(LIns* i); - Register findRegFor(LIns* i, RegisterMask allow); + int findMemFor(LIns* ins); + Register findRegFor(LIns* ins, RegisterMask allow); void findRegFor2(RegisterMask allowa, LIns* ia, Register &ra, RegisterMask allowb, LIns *ib, Register &rb); - Register findSpecificRegFor(LIns* i, Register r); - Register findSpecificRegForUnallocated(LIns* i, Register r); - Register deprecated_prepResultReg(LIns *i, RegisterMask allow); - Register prepareResultReg(LIns *i, RegisterMask allow); - void deprecated_freeRsrcOf(LIns *i, bool pop); + Register findSpecificRegFor(LIns* ins, Register r); + Register findSpecificRegForUnallocated(LIns* ins, Register r); + Register deprecated_prepResultReg(LIns *ins, RegisterMask allow); + Register prepareResultReg(LIns *ins, RegisterMask allow); + void deprecated_freeRsrcOf(LIns *ins); void freeResourcesOf(LIns *ins); void evictIfActive(Register r); void evict(LIns* vic); @@ -423,25 +423,25 @@ namespace nanojit void asm_store32(LOpcode op, LIns *val, int d, LIns *base); void asm_store64(LOpcode op, LIns *val, int d, LIns *base); void asm_restore(LInsp, Register); - void asm_spilli(LInsp i, bool pop); + void asm_maybe_spill(LInsp ins, bool pop); void asm_spill(Register rr, int d, bool pop, bool quad); - void asm_load64(LInsp i); - void asm_ret(LInsp p); + void asm_load64(LInsp ins); + void asm_ret(LInsp ins); #ifdef NANOJIT_64BIT - void asm_immq(LInsp i); + void asm_immq(LInsp ins); #endif - void asm_immf(LInsp i); - void asm_fcond(LInsp i); - void asm_cond(LInsp i); - void asm_arith(LInsp i); - void asm_neg_not(LInsp i); - void asm_load32(LInsp i); - void asm_cmov(LInsp i); - void asm_param(LInsp i); - void asm_immi(LInsp i); + void asm_immf(LInsp ins); + void asm_fcond(LInsp ins); + void asm_cond(LInsp ins); + void asm_arith(LInsp ins); + void asm_neg_not(LInsp ins); + void asm_load32(LInsp ins); + void asm_cmov(LInsp ins); + void asm_param(LInsp ins); + void asm_immi(LInsp ins); #if NJ_SOFTFLOAT_SUPPORTED - void asm_qlo(LInsp i); - void asm_qhi(LInsp i); + void asm_qlo(LInsp ins); + void asm_qhi(LInsp ins); void asm_qjoin(LIns *ins); #endif void asm_fneg(LInsp ins); diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index cba8181ca7e6..2e26ce4f0bc7 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -875,7 +875,7 @@ Assembler::asm_call(LInsp ins) if (!deprecated_isKnownReg(rr)) { int d = deprecated_disp(ins); NanoAssert(d != 0); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); // The result doesn't have a register allocated, so store the // result (in R0,R1) directly to its stack slot. @@ -1192,7 +1192,7 @@ Assembler::asm_qjoin(LIns *ins) // okay if r gets recycled. r = findRegFor(lo, GpRegs); STR(r, FP, d); - deprecated_freeRsrcOf(ins, false); // if we had a reg in use, emit a ST to flush it to mem + deprecated_freeRsrcOf(ins); // if we had a reg in use, emit a ST to flush it to mem } void @@ -1279,28 +1279,27 @@ Assembler::asm_spill(Register rr, int d, bool pop, bool quad) { (void) pop; (void) quad; - if (d) { - if (_config.arm_vfp && IsFpReg(rr)) { - if (isS8(d >> 2)) { - FSTD(rr, FP, d); - } else { - FSTD(rr, IP, 0); - asm_add_imm(IP, FP, d); - } + NanoAssert(d); + if (_config.arm_vfp && IsFpReg(rr)) { + if (isS8(d >> 2)) { + FSTD(rr, FP, d); } else { - NIns merged; - STR(rr, FP, d); - // See if we can merge this store into an immediately following one, - // one, by creating or extending a STM instruction. - if (/* is it safe to poke _nIns[1] ? */ - does_next_instruction_exist(_nIns, codeStart, codeEnd, - exitStart, exitEnd) - && /* can we merge _nIns[0] into _nIns[1] ? */ - do_peep_2_1(&merged, _nIns[0], _nIns[1])) { - _nIns[1] = merged; - _nIns++; - verbose_only( asm_output("merge next into STMDB"); ) - } + FSTD(rr, IP, 0); + asm_add_imm(IP, FP, d); + } + } else { + NIns merged; + STR(rr, FP, d); + // See if we can merge this store into an immediately following one, + // one, by creating or extending a STM instruction. + if (/* is it safe to poke _nIns[1] ? */ + does_next_instruction_exist(_nIns, codeStart, codeEnd, + exitStart, exitEnd) + && /* can we merge _nIns[0] into _nIns[1] ? */ + do_peep_2_1(&merged, _nIns[0], _nIns[1])) { + _nIns[1] = merged; + _nIns++; + verbose_only( asm_output("merge next into STMDB"); ) } } } @@ -1320,7 +1319,7 @@ Assembler::asm_load64(LInsp ins) Register rb = findRegFor(base, GpRegs); NanoAssert(IsGpReg(rb)); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); //outputf("--- load64: Finished register allocation."); @@ -1531,10 +1530,11 @@ Assembler::asm_immf(LInsp ins) int d = deprecated_disp(ins); Register rr = ins->deprecated_getReg(); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); if (_config.arm_vfp && deprecated_isKnownReg(rr)) { - asm_spill(rr, d, false, true); + if (d) + asm_spill(rr, d, false, true); underrunProtect(4*4); asm_immf_nochk(rr, ins->imm64_0(), ins->imm64_1()); diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp index 0bb11c07d877..24332d568e20 100644 --- a/js/src/nanojit/NativeMIPS.cpp +++ b/js/src/nanojit/NativeMIPS.cpp @@ -590,7 +590,7 @@ namespace nanojit SW(r, d+mswoff(), FP); r = findRegFor(lo, GpRegs); // okay if r gets recycled. SW(r, d+lswoff(), FP); - deprecated_freeRsrcOf(ins, false); // if we had a reg in use, flush it to mem + deprecated_freeRsrcOf(ins); // if we had a reg in use, flush it to mem TAG("asm_qjoin(ins=%p{%s})", ins, lirNames[ins->opcode()]); } @@ -640,10 +640,11 @@ namespace nanojit int d = deprecated_disp(ins); Register rr = ins->deprecated_getReg(); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); if (cpu_has_fpu && deprecated_isKnownReg(rr)) { - asm_spill(rr, d, false, true); + if (d) + asm_spill(rr, d, false, true); asm_li_d(rr, ins->imm64_1(), ins->imm64_0()); } else { @@ -678,7 +679,7 @@ namespace nanojit Register rbase = findRegFor(base, GpRegs); NanoAssert(IsGpReg(rbase)); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); if (cpu_has_fpu && deprecated_isKnownReg(rd)) { NanoAssert(IsFpReg(rd)); @@ -1471,15 +1472,14 @@ namespace nanojit { USE(pop); USE(quad); - if (d) { - if (IsFpReg(rr)) { - NanoAssert(quad); - asm_ldst64(true, rr, d, FP); - } - else { - NanoAssert(!quad); - asm_ldst(OP_SW, rr, d, FP); - } + NanoAssert(d); + if (IsFpReg(rr)) { + NanoAssert(quad); + asm_ldst64(true, rr, d, FP); + } + else { + NanoAssert(!quad); + asm_ldst(OP_SW, rr, d, FP); } TAG("asm_spill(rr=%d, d=%d, pop=%d, quad=%d)", rr, d, pop, quad); } diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index 6f6ea9322e6e..13c4bcaa4614 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -224,7 +224,7 @@ namespace nanojit Register rr = ins->deprecated_getReg(); if (deprecated_isKnownReg(rr) && (rmask(rr) & FpRegs)) { // FPR already assigned, fine, use it - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); } else { // use a GPR register; its okay to copy doubles with GPR's // but *not* okay to copy non-doubles with FPR's @@ -811,20 +811,19 @@ namespace nanojit void Assembler::asm_spill(Register rr, int d, bool /* pop */, bool quad) { (void)quad; - if (d) { - if (IsFpReg(rr)) { - NanoAssert(quad); - STFD(rr, d, FP); - } - #ifdef NANOJIT_64BIT - else if (quad) { - STD(rr, d, FP); - } - #endif - else { - NanoAssert(!quad); - STW(rr, d, FP); - } + NanoAssert(d); + if (IsFpReg(rr)) { + NanoAssert(quad); + STFD(rr, d, FP); + } + #ifdef NANOJIT_64BIT + else if (quad) { + STD(rr, d, FP); + } + #endif + else { + NanoAssert(!quad); + STW(rr, d, FP); } } @@ -1072,7 +1071,7 @@ namespace nanojit Register r = ins->deprecated_getReg(); if (deprecated_isKnownReg(r) && (rmask(r) & FpRegs)) { // FPR already assigned, fine, use it - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); } else { // use a GPR register; its okay to copy doubles with GPR's // but *not* okay to copy non-doubles with FPR's diff --git a/js/src/nanojit/NativeSparc.cpp b/js/src/nanojit/NativeSparc.cpp index c2a7b395a0f3..5dd252bac619 100644 --- a/js/src/nanojit/NativeSparc.cpp +++ b/js/src/nanojit/NativeSparc.cpp @@ -317,12 +317,11 @@ namespace nanojit { underrunProtect(24); (void)quad; - if (d) { - if (rmask(rr) & FpRegs) { - STDF32(rr, d, FP); - } else { - STW32(rr, d, FP); - } + NanoAssert(d); + if (rmask(rr) & FpRegs) { + STDF32(rr, d, FP); + } else { + STW32(rr, d, FP); } } @@ -359,7 +358,7 @@ namespace nanojit if (dr) asm_mmq(FP, dr, rb, db); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); if (rr != deprecated_UnknownReg) { @@ -823,7 +822,7 @@ namespace nanojit // @todo, if we used xor, ldsd, fldz, etc above, we don't need mem here int d = deprecated_disp(ins); - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); if (d) { STW32(L2, d+4, FP); diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index 874dc76af837..1ef399a2cf02 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -1759,17 +1759,16 @@ namespace nanojit } void Assembler::asm_spill(Register rr, int d, bool /*pop*/, bool quad) { - if (d) { - if (!IsFpReg(rr)) { - if (quad) - MOVQMR(rr, d, FP); - else - MOVLMR(rr, d, FP); - } else { - // store 64bits from XMM to memory - NanoAssert(quad); - MOVSDMR(rr, d, FP); - } + NanoAssert(d); + if (!IsFpReg(rr)) { + if (quad) + MOVQMR(rr, d, FP); + else + MOVLMR(rr, d, FP); + } else { + // store 64bits from XMM to memory + NanoAssert(quad); + MOVSDMR(rr, d, FP); } } diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index b2132c5b6491..4e5ff51cd9f7 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -465,21 +465,14 @@ namespace nanojit void Assembler::asm_spill(Register rr, int d, bool pop, bool quad) { (void)quad; - if (d) - { - if (rmask(rr) & GpRegs) { - ST(FP, d, rr); - } else if (rmask(rr) & XmmRegs) { - SSE_STQ(d, FP, rr); - } else { - NanoAssert(rmask(rr) & x87Regs); - FSTQ((pop?1:0), d, FP); - } - } - else if (pop && (rmask(rr) & x87Regs)) - { - // pop the fpu result since it isn't used - FSTP(FST0); + NanoAssert(d); + if (rmask(rr) & GpRegs) { + ST(FP, d, rr); + } else if (rmask(rr) & XmmRegs) { + SSE_STQ(d, FP, rr); + } else { + NanoAssert(rmask(rr) & x87Regs); + FSTQ((pop?1:0), d, FP); } } @@ -501,7 +494,7 @@ namespace nanojit // if (ins->isInReg()) { Register rr = ins->getReg(); - asm_spilli(ins, false); // if also in memory in post-state, spill it now + asm_maybe_spill(ins, false); // if also in memory in post-state, spill it now switch (ins->opcode()) { case LIR_ldf: if (rmask(rr) & XmmRegs) { From 09fd66cd2f46e6f7846c1342f42f0b18452ce621 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 15:12:49 -0700 Subject: [PATCH 092/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 84fd89cb6d61..9d1c59c1e7a4 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -ba9b07136948b3e1d87c1bc6b1b518f2182bf762 +5806c6f3bf1257fc3142f5eb8718e01071bcbb35 From a52e773d774641dc289520d11965c0f712d20db7 Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Sun, 21 Mar 2010 16:07:48 -0700 Subject: [PATCH 093/213] Bug 553423 - JS scanner namespacing cleanup (r=lw) --- js/src/jsemit.cpp | 49 ++- js/src/jsexn.cpp | 2 +- js/src/jsfun.cpp | 19 +- js/src/json.cpp | 2 +- js/src/jsparse.cpp | 765 +++++++++++++++++++++----------------------- js/src/jsparse.h | 34 +- js/src/jsprvtd.h | 9 +- js/src/jsregexp.cpp | 13 +- js/src/jsregexp.h | 4 +- js/src/jsscan.cpp | 158 ++++----- js/src/jsscan.h | 208 ++++++------ js/src/jsscript.cpp | 3 +- js/src/jsxml.cpp | 43 ++- 13 files changed, 632 insertions(+), 677 deletions(-) diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 3ea68e54c70b..a389382aafe7 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -79,6 +79,8 @@ #define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote)) #define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote)) +using namespace js; + static JSBool NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, size_t start, size_t end); @@ -184,7 +186,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) JS_ASSERT(cg->stackDepth >= 0); if (cg->stackDepth < 0) { char numBuf[12]; - JSTokenStream *ts; + TokenStream *ts; JS_snprintf(numBuf, sizeof numBuf, "%d", target); ts = &cg->compiler->tokenStream; @@ -893,7 +895,7 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) if (growth) { #ifdef DEBUG_brendan - JSTokenStream *ts = &cg->compiler->tokenStream; + TokenStream *ts = &cg->compiler->tokenStream; printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n", ts->filename ? ts->filename : "stdin", cg->firstLine, @@ -1835,9 +1837,7 @@ AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) if (cg->flags & TCF_IN_FUNCTION) { slot += cg->fun->u.i.nvars; if ((uintN) slot >= SLOTNO_LIMIT) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, - JSREPORT_ERROR, - JSMSG_TOO_MANY_LOCALS); + ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); slot = -1; } } @@ -3934,8 +3934,7 @@ EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, depth = limit = (uintN) cg->stackDepth; for (pn = rhs->pn_head; pn; pn = pn->pn_next) { if (limit == JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, - JSMSG_ARRAY_INIT_TOO_BIG); + ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG); return JS_FALSE; } @@ -4333,7 +4332,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JSSrcNoteType noteType; jsbytecode *pc; JSOp op; - JSTokenType type; + TokenKind type; uint32 argc; #if JS_HAS_SHARP_VARS jsint sharpnum; @@ -4695,7 +4694,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn3 = pn2->pn_left; type = PN_TYPE(pn3); cg->flags |= TCF_IN_FOR_INIT; - if (TOKEN_TYPE_IS_DECL(type) && !js_EmitTree(cx, cg, pn3)) + if (TokenKindIsDecl(type) && !js_EmitTree(cx, cg, pn3)) return JS_FALSE; cg->flags &= ~TCF_IN_FOR_INIT; @@ -4804,8 +4803,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) op = PN_OP(pn3); } if (pn3->isConst()) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return JS_FALSE; } if (pn3->pn_cookie != FREE_UPVAR_COOKIE) { @@ -4917,7 +4916,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (op == JSOP_POP) { if (!js_EmitTree(cx, cg, pn3)) return JS_FALSE; - if (TOKEN_TYPE_IS_DECL(pn3->pn_type)) { + if (TokenKindIsDecl(PN_TYPE(pn3))) { /* * Check whether a destructuring-initialized var decl * was optimized to a group assignment. If so, we do @@ -5486,9 +5485,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #if JS_HAS_GENERATORS case TOK_YIELD: if (!(cg->flags & TCF_IN_FUNCTION)) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, - JSMSG_BAD_RETURN_OR_YIELD, - js_yield_str); + ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, + js_yield_str); return JS_FALSE; } if (pn->pn_kid) { @@ -5626,10 +5625,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) cg->topStmt->type != STMT_LABEL || cg->topStmt->update < CG_OFFSET(cg))) { CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno; - if (!js_ReportCompileErrorNumber(cx, CG_TS(cg), pn2, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_USELESS_EXPR)) { + if (!ReportCompileErrorNumber(cx, CG_TS(cg), pn2, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_USELESS_EXPR)) { return JS_FALSE; } } else { @@ -5796,13 +5794,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * x getter = y where x is a local or let variable is not * supported. */ - js_ReportCompileErrorNumber(cx, - TS(cg->compiler), - pn2, JSREPORT_ERROR, - JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) - ? js_getter_str - : js_setter_str); + ReportCompileErrorNumber(cx, TS(cg->compiler), pn2, JSREPORT_ERROR, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) ? js_getter_str : js_setter_str); return JS_FALSE; } @@ -6633,8 +6627,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #endif #if JS_HAS_DESTRUCTURING_SHORTHAND if (pn->pn_xflags & PNX_DESTRUCT) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, - JSMSG_BAD_OBJECT_INIT); + ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 478dac5505df..cc2bec6b7e88 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -351,7 +351,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, * Construct a new copy of the error report struct. We can't use the * error report struct that was passed in, because it's allocated on * the stack, and also because it may point to transient data in the - * JSTokenStream. + * TokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index c5ba28896059..9ac0205ff24d 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2183,12 +2183,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const char *filename; JSBool ok; JSString *str, *arg; - JSTokenStream ts(cx); + TokenStream ts(cx); JSPrincipals *principals; jschar *collected_args, *cp; void *mark; size_t arg_length, args_length, old_args_length; - JSTokenType tt; + TokenKind tt; if (!JS_IsConstructing(cx)) { obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL); @@ -2336,7 +2336,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* The argument string may be empty or contain no tokens. */ - tt = js_GetToken(cx, &ts); + tt = GetToken(cx, &ts); if (tt != TOK_EOF) { for (;;) { /* @@ -2358,12 +2358,9 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const char *name; name = js_AtomToPrintableString(cx, atom); - ok = name && - js_ReportCompileErrorNumber(cx, &ts, NULL, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_DUPLICATE_FORMAL, - name); + ok = name && ReportCompileErrorNumber(cx, &ts, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, name); if (!ok) goto after_args; } @@ -2374,12 +2371,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ - tt = js_GetToken(cx, &ts); + tt = GetToken(cx, &ts); if (tt == TOK_EOF) break; if (tt != TOK_COMMA) goto after_args; - tt = js_GetToken(cx, &ts); + tt = GetToken(cx, &ts); } } diff --git a/js/src/json.cpp b/js/src/json.cpp index 44897ba6d41c..2a18aded1c0d 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -923,7 +923,7 @@ static JSBool HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) { jsval keyword; - JSTokenType tt = js_CheckKeyword(buf, len); + TokenKind tt = js_CheckKeyword(buf, len); if (tt != TOK_PRIMARY) { // bad keyword JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 0b185b11075b..73047c3e530e 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -104,12 +104,12 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom)); * Insist that the next token be of type tt, or report errno and return null. * NB: this macro uses cx and ts from its lexical environment. */ -#define MUST_MATCH_TOKEN(tt, errno) \ - JS_BEGIN_MACRO \ - if (js_GetToken(context, &tokenStream) != tt) { \ - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ - return NULL; \ - } \ +#define MUST_MATCH_TOKEN(tt, errno) \ + JS_BEGIN_MACRO \ + if (GetToken(context, &tokenStream) != tt) { \ + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ + return NULL; \ + } \ JS_END_MACRO #ifdef METER_PARSENODES @@ -529,14 +529,14 @@ JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc) JSParseNode *pn = NewOrRecycledNode(tc); if (!pn) return NULL; - JSToken *tp = tc->compiler->tokenStream.mutableCurrentToken(); + Token *tp = tc->compiler->tokenStream.mutableCurrentToken(); pn->init(tp->type, JSOP_NOP, arity); pn->pn_pos = tp->pos; return pn; } JSParseNode * -JSParseNode::newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, JSParseNode *right, +JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParseNode *right, JSTreeContext *tc) { JSParseNode *pn, *pn1, *pn2; @@ -635,8 +635,8 @@ NameNode::create(JSAtom *atom, JSTreeContext *tc) } /* namespace js */ #if JS_HAS_GETTER_SETTER -static JSTokenType -CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) +static TokenKind +CheckGetterOrSetter(JSContext *cx, TokenStream *ts, TokenKind tt) { JSAtom *atom; JSRuntime *rt; @@ -652,25 +652,20 @@ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt) op = JSOP_SETTER; else return TOK_NAME; - if (js_PeekTokenSameLine(cx, ts) != tt) + if (PeekTokenSameLine(cx, ts) != tt) return TOK_NAME; - (void) js_GetToken(cx, ts); + (void) GetToken(cx, ts); if (ts->currentToken().t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, - JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) - ? js_getter_str - : js_setter_str); + ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) ? js_getter_str : js_setter_str); return TOK_ERROR; } ts->mutableCurrentToken()->t_op = op; if (JS_HAS_STRICT_OPTION(cx)) { name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportCompileErrorNumber(cx, ts, NULL, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_DEPRECATED_USAGE, - name)) { + !ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, name)) { return TOK_ERROR; } } @@ -723,9 +718,9 @@ JSCompiler::parse(JSObject *chain) JSParseNode *pn = statements(); if (pn) { - if (!js_MatchToken(context, &tokenStream, TOK_EOF)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + if (!MatchToken(context, &tokenStream, TOK_EOF)) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); pn = NULL; } else { if (!js_FoldConstants(context, pn, &globaltc)) @@ -771,7 +766,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal { JSCompiler jsc(cx, principals, callerFrame); JSArenaPool codePool, notePool; - JSTokenType tt; + TokenKind tt; JSParseNode *pn; uint32 scriptGlobals; JSScript *script; @@ -873,7 +868,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal inDirectivePrologue = true; for (;;) { jsc.tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(cx, &jsc.tokenStream); + tt = PeekToken(cx, &jsc.tokenStream); jsc.tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF) { if (tt == TOK_EOF) @@ -904,7 +899,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal #if JS_HAS_XML_SUPPORT if (PN_TYPE(pn) != TOK_SEMI || !pn->pn_kid || - !TREE_TYPE_IS_XML(PN_TYPE(pn->pn_kid))) { + !TreeTypeIsXML(PN_TYPE(pn->pn_kid))) { onlyXML = false; } #endif @@ -919,8 +914,8 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal * https://bugzilla.mozilla.org/show_bug.cgi?id=336551 */ if (pn && onlyXML && (tcflags & TCF_NO_SCRIPT_RVAL)) { - js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, - JSMSG_XML_WHOLE_PROGRAM); + ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, + JSMSG_XML_WHOLE_PROGRAM); goto out; } #endif @@ -1010,8 +1005,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal return script; too_many_slots: - js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, - JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); + ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); script = NULL; goto out; } @@ -1156,8 +1150,7 @@ ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum, errnum = anonerrnum; name = NULL; } - return js_ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, flags, - errnum, name); + return ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, flags, errnum, name); } static JSBool @@ -1183,8 +1176,8 @@ CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs) if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) { const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportStrictModeError(cx, TS(tc->compiler), tc, lhs, - JSMSG_DEPRECATED_ASSIGN, name)) { + !ReportStrictModeError(cx, TS(tc->compiler), tc, lhs, JSMSG_DEPRECATED_ASSIGN, + name)) { return false; } } @@ -1208,8 +1201,7 @@ CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, JSParseNode * if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) { const char *name = js_AtomToPrintableString(cx, atom); if (name) - js_ReportStrictModeError(cx, TS(tc->compiler), tc, pn, - JSMSG_BAD_BINDING, name); + ReportStrictModeError(cx, TS(tc->compiler), tc, pn, JSMSG_BAD_BINDING, name); return false; } return true; @@ -1249,8 +1241,7 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, pn = dn; const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportStrictModeError(cx, TS(tc->compiler), tc, pn, - JSMSG_DUPLICATE_FORMAL, name)) { + !ReportStrictModeError(cx, TS(tc->compiler), tc, pn, JSMSG_DUPLICATE_FORMAL, name)) { return false; } } @@ -1264,8 +1255,7 @@ CheckStrictFormals(JSContext *cx, JSTreeContext *tc, JSFunction *fun, JS_ASSERT(dn->pn_atom == atom); const char *name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportStrictModeError(cx, TS(tc->compiler), tc, dn, - JSMSG_BAD_BINDING, name)) { + !ReportStrictModeError(cx, TS(tc->compiler), tc, dn, JSMSG_BAD_BINDING, name)) { return false; } } @@ -1615,9 +1605,9 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr if (pn) { if (!CheckStrictFormals(cx, &funcg, fun, pn)) { pn = NULL; - } else if (!js_MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { - js_ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, - JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); + } else if (!MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { + ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); pn = NULL; } else if (!js_FoldConstants(cx, pn, &funcg)) { /* js_FoldConstants reported the error already. */ @@ -1707,8 +1697,8 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSLocalKind localKind = js_LookupLocal(cx, tc->fun, atom, NULL); if (localKind != JSLOCAL_NONE) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, - JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG); + ReportCompileErrorNumber(cx, TS(tc->compiler), NULL, JSREPORT_ERROR, + JSMSG_DESTRUCT_DUP_ARG); return JS_FALSE; } JS_ASSERT(!tc->decls.lookup(atom)); @@ -1756,21 +1746,20 @@ JSCompiler::newFunction(JSTreeContext *tc, JSAtom *atom, uintN lambda) } static JSBool -MatchOrInsertSemicolon(JSContext *cx, JSTokenStream *ts) +MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) { - JSTokenType tt; + TokenKind tt; ts->flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(cx, ts); + tt = PeekTokenSameLine(cx, ts); ts->flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return JS_FALSE; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, - JSMSG_SEMI_BEFORE_STMNT); + ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT); return JS_FALSE; } - (void) js_MatchToken(cx, ts, TOK_SEMI); + (void) MatchToken(cx, ts, TOK_SEMI); return JS_TRUE; } @@ -2158,7 +2147,7 @@ static void DeoptimizeUsesWithin(JSDefinition *dn, JSFunctionBox *funbox, uint32& tcflags) { uintN ndeoptimized = 0; - const JSTokenPos &pos = funbox->node->pn_body->pn_pos; + const TokenPos &pos = funbox->node->pn_body->pn_pos; for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { JS_ASSERT(pnu->pn_used); @@ -2578,7 +2567,7 @@ JSCompiler::functionDef(uintN lambda) { JSOp op; JSParseNode *pn, *body, *result; - JSTokenType tt; + TokenKind tt; JSAtom *funAtom; JSAtomListElement *ale; #if JS_HAS_DESTRUCTURING @@ -2610,18 +2599,18 @@ JSCompiler::functionDef(uintN lambda) /* Scan the optional function name into funAtom. */ tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_NAME) { funAtom = tokenStream.currentToken().t_atom; } else { if (lambda == 0 && (context->options & JSOPTION_ANONFUNFIX)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } funAtom = NULL; - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } /* @@ -2640,13 +2629,13 @@ JSCompiler::functionDef(uintN lambda) if (JS_HAS_STRICT_OPTION(context) || dn_kind == JSDefinition::CONST) { const char *name = js_AtomToPrintableString(context, funAtom); if (!name || - !js_ReportCompileErrorNumber(context, &tokenStream, NULL, - (dn_kind != JSDefinition::CONST) - ? JSREPORT_WARNING | JSREPORT_STRICT - : JSREPORT_ERROR, - JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), - name)) { + !ReportCompileErrorNumber(context, &tokenStream, NULL, + (dn_kind != JSDefinition::CONST) + ? JSREPORT_WARNING | JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + JSDefinition::kindString(dn_kind), + name)) { return NULL; } } @@ -2747,9 +2736,9 @@ JSCompiler::functionDef(uintN lambda) /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); - if (!js_MatchToken(context, &tokenStream, TOK_RP)) { + if (!MatchToken(context, &tokenStream, TOK_RP)) { do { - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -2841,8 +2830,8 @@ JSCompiler::functionDef(uintN lambda) } default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_MISSING_FORMAL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_MISSING_FORMAL); /* FALL THROUGH */ case TOK_ERROR: return NULL; @@ -2850,22 +2839,22 @@ JSCompiler::functionDef(uintN lambda) #if JS_HAS_DESTRUCTURING report_dup_and_destructuring: JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg)); - js_ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, - JSMSG_DESTRUCT_DUP_ARG); + ReportCompileErrorNumber(context, &tokenStream, dn, JSREPORT_ERROR, + JSMSG_DESTRUCT_DUP_ARG); return NULL; #endif } - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); } #if JS_HAS_EXPR_CLOSURES tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt != TOK_LC) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); fun->flags |= JSFUN_EXPR_CLOSURE; } #else @@ -3059,7 +3048,7 @@ JSParseNode * JSCompiler::statements() { JSParseNode *pn, *pn2, *saveBlock; - JSTokenType tt; + TokenKind tt; bool inDirectivePrologue = tc->atTopLevel(); JS_CHECK_RECURSION(context, return NULL); @@ -3075,7 +3064,7 @@ JSCompiler::statements() for (;;) { tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF || tt == TOK_RC) { if (tt == TOK_ERROR) { @@ -3141,26 +3130,24 @@ JSCompiler::condition() if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP && !pn->pn_parens && - !js_ReportCompileErrorNumber(context, &tokenStream, NULL, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_EQUAL_AS_ASSIGN, - "")) { + !ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_EQUAL_AS_ASSIGN, "")) { return NULL; } return pn; } static JSBool -MatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn) +MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn) { JSAtom *label; - JSTokenType tt; + TokenKind tt; - tt = js_PeekTokenSameLine(cx, ts); + tt = PeekTokenSameLine(cx, ts); if (tt == TOK_ERROR) return JS_FALSE; if (tt == TOK_NAME) { - (void) js_GetToken(cx, ts); + (void) GetToken(cx, ts); label = ts->currentToken().t_atom; } else { label = NULL; @@ -3192,20 +3179,20 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (ale && ALE_DEFN(ale)->pn_blockid == tc->blockid()) { const char *name = js_AtomToPrintableString(cx, atom); if (name) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_REDECLARED_VAR, - (ale && ALE_DEFN(ale)->isConst()) - ? js_const_str - : js_variable_str, - name); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_REDECLARED_VAR, + (ale && ALE_DEFN(ale)->isConst()) + ? js_const_str + : js_variable_str, + name); } return JS_FALSE; } n = OBJ_BLOCK_COUNT(cx, blockObj); if (n == JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, data->let.overflow); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, data->let.overflow); return JS_FALSE; } @@ -3315,14 +3302,14 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) return JS_FALSE; if (op == JSOP_DEFCONST) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, - name); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_REDECLARED_PARAM, + name); return JS_FALSE; } - if (!js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_WARNING | JSREPORT_STRICT, - JSMSG_VAR_HIDES_ARG, name)) { + if (!ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_VAR_HIDES_ARG, name)) { return JS_FALSE; } } else { @@ -3336,13 +3323,13 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) : error) { name = js_AtomToPrintableString(cx, atom); if (!name || - !js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - !error - ? JSREPORT_WARNING | JSREPORT_STRICT - : JSREPORT_ERROR, - JSMSG_REDECLARED_VAR, - JSDefinition::kindString(dn_kind), - name)) { + !ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + !error + ? JSREPORT_WARNING | JSREPORT_STRICT + : JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + JSDefinition::kindString(dn_kind), + name)) { return JS_FALSE; } } @@ -3518,7 +3505,7 @@ MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg) JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL || pn->pn_op == JSOP_APPLY); pn2 = pn->pn_head; if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, msg); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, msg); return JS_FALSE; } pn->pn_op = JSOP_SETCALL; @@ -3655,8 +3642,8 @@ BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) #endif default: - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, - JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, + JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS); return JS_FALSE; } @@ -3853,15 +3840,15 @@ CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *lhs, *rhs, *pn, *pn2; if (left->pn_type == TOK_ARRAYCOMP) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), left, - JSREPORT_ERROR, JSMSG_ARRAY_COMP_LEFTSIDE); + ReportCompileErrorNumber(cx, TS(tc->compiler), left, JSREPORT_ERROR, + JSMSG_ARRAY_COMP_LEFTSIDE); return JS_FALSE; } #if JS_HAS_DESTRUCTURING_SHORTHAND if (right && right->pn_arity == PN_LIST && (right->pn_xflags & PNX_DESTRUCT)) { - js_ReportCompileErrorNumber(cx, TS(tc->compiler), right, - JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + ReportCompileErrorNumber(cx, TS(tc->compiler), right, JSREPORT_ERROR, + JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif @@ -3968,8 +3955,8 @@ CheckDestructuring(JSContext *cx, BindData *data, return ok; no_var_name: - js_ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + ReportCompileErrorNumber(cx, TS(tc->compiler), pn, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); ok = JS_FALSE; goto out; } @@ -4002,8 +3989,8 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) #if JS_HAS_DESTRUCTURING_SHORTHAND if (right->pn_arity == PN_LIST && (right->pn_xflags & PNX_DESTRUCT)) { - js_ReportCompileErrorNumber(tc->compiler->context, TS(tc->compiler), right, - JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + ReportCompileErrorNumber(tc->compiler->context, TS(tc->compiler), right, JSREPORT_ERROR, + JSMSG_BAD_OBJECT_INIT); return JS_FALSE; } #endif @@ -4055,7 +4042,7 @@ UndominateInitializers(JSParseNode *left, JSParseNode *right, JSTreeContext *tc) } JSParseNode * -JSCompiler::destructuringExpr(BindData *data, JSTokenType tt) +JSCompiler::destructuringExpr(BindData *data, TokenKind tt) { JSParseNode *pn; @@ -4179,7 +4166,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) extern const char js_with_statement_str[]; static JSParseNode * -ContainsStmt(JSParseNode *pn, JSTokenType tt) +ContainsStmt(JSParseNode *pn, TokenKind tt) { JSParseNode *pn2, *pnt; @@ -4230,13 +4217,13 @@ ContainsStmt(JSParseNode *pn, JSTokenType tt) JSParseNode * JSCompiler::returnOrYield(bool useAssignExpr) { - JSTokenType tt, tt2; + TokenKind tt, tt2; JSParseNode *pn, *pn2; tt = tokenStream.currentToken().type; if (tt == TOK_RETURN && !(tc->flags & TCF_IN_FUNCTION)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_RETURN_OR_YIELD, js_return_str); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, js_return_str); return NULL; } @@ -4251,7 +4238,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) /* This is ugly, but we don't want to require a semicolon. */ tokenStream.flags |= TSF_OPERAND; - tt2 = js_PeekTokenSameLine(context, &tokenStream); + tt2 = PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt2 == TOK_ERROR) return NULL; @@ -4299,7 +4286,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) } static JSParseNode * -PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, +PushLexicalScope(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSStmtInfo *stmt) { JSParseNode *pn; @@ -4362,7 +4349,7 @@ JSCompiler::letBlock(JSBool statement) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET); tokenStream.flags |= TSF_OPERAND; - if (statement && !js_MatchToken(context, &tokenStream, TOK_LC)) { + if (statement && !MatchToken(context, &tokenStream, TOK_LC)) { /* * If this is really an expression in let statement guise, then we * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop @@ -4531,7 +4518,7 @@ RebindLets(JSParseNode *pn, JSTreeContext *tc) JSParseNode * JSCompiler::statement() { - JSTokenType tt; + TokenKind tt; JSParseNode *pn, *pn1, *pn2, *pn3, *pn4; JSStmtInfo stmtInfo, *stmt, *stmt2; JSAtom *label; @@ -4539,7 +4526,7 @@ JSCompiler::statement() JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_GETTER_SETTER @@ -4554,7 +4541,7 @@ JSCompiler::statement() case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_DBLCOLON) goto expression; @@ -4574,7 +4561,7 @@ JSCompiler::statement() if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND; - if (js_MatchToken(context, &tokenStream, TOK_ELSE)) { + if (MatchToken(context, &tokenStream, TOK_ELSE)) { tokenStream.flags &= ~TSF_OPERAND; stmtInfo.type = STMT_ELSE; pn3 = statement(); @@ -4626,12 +4613,12 @@ JSCompiler::statement() saveBlock = tc->blockNode; tc->blockNode = pn2; - while ((tt = js_GetToken(context, &tokenStream)) != TOK_RC) { + while ((tt = GetToken(context, &tokenStream)) != TOK_RC) { switch (tt) { case TOK_DEFAULT: if (seenDefault) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOO_MANY_DEFAULTS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_DEFAULTS); return NULL; } seenDefault = JS_TRUE; @@ -4648,8 +4635,8 @@ JSCompiler::statement() } pn2->append(pn3); if (pn2->pn_count == JS_BIT(16)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOO_MANY_CASES); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOO_MANY_CASES); return NULL; } break; @@ -4658,8 +4645,8 @@ JSCompiler::statement() return NULL; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_SWITCH); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_SWITCH); return NULL; } MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); @@ -4670,7 +4657,7 @@ JSCompiler::statement() pn4->pn_type = TOK_LC; pn4->makeEmpty(); tokenStream.flags |= TSF_OPERAND; - while ((tt = js_PeekToken(context, &tokenStream)) != TOK_RC && + while ((tt = PeekToken(context, &tokenStream)) != TOK_RC && tt != TOK_CASE && tt != TOK_DEFAULT) { tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) @@ -4747,7 +4734,7 @@ JSCompiler::statement() * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ - (void) js_MatchToken(context, &tokenStream, TOK_SEMI); + (void) MatchToken(context, &tokenStream, TOK_SEMI); return pn; } break; @@ -4768,16 +4755,16 @@ JSCompiler::statement() pn->pn_op = JSOP_ITER; pn->pn_iflags = 0; - if (js_MatchToken(context, &tokenStream, TOK_NAME)) { + if (MatchToken(context, &tokenStream, TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn->pn_iflags = JSITER_FOREACH; else - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_BLOCK_SCOPE @@ -4806,13 +4793,13 @@ JSCompiler::statement() */ tc->flags |= TCF_IN_FOR_INIT; if (tt == TOK_VAR) { - (void) js_GetToken(context, &tokenStream); + (void) GetToken(context, &tokenStream); pn1 = variables(false); #if JS_HAS_BLOCK_SCOPE } else if (tt == TOK_LET) { let = true; - (void) js_GetToken(context, &tokenStream); - if (js_PeekToken(context, &tokenStream) == TOK_LP) { + (void) GetToken(context, &tokenStream); + if (PeekToken(context, &tokenStream) == TOK_LP) { pn1 = letBlock(JS_FALSE); tt = TOK_LEXICALSCOPE; } else { @@ -4837,13 +4824,13 @@ JSCompiler::statement() * as we've excluded 'in' from being parsed in RelExpr by setting * the TCF_IN_FOR_INIT flag in our JSTreeContext. */ - if (pn1 && js_MatchToken(context, &tokenStream, TOK_IN)) { + if (pn1 && MatchToken(context, &tokenStream, TOK_IN)) { pn->pn_iflags |= JSITER_ENUMERATE; stmtInfo.type = STMT_FOR_IN_LOOP; /* Check that the left side of the 'in' is valid. */ - JS_ASSERT(!TOKEN_TYPE_IS_DECL(tt) || PN_TYPE(pn1) == tt); - if (TOKEN_TYPE_IS_DECL(tt) + JS_ASSERT(!TokenKindIsDecl(tt) || PN_TYPE(pn1) == tt); + if (TokenKindIsDecl(tt) ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST #if JS_HAS_DESTRUCTURING || (JSVERSION_NUMBER(context) == JSVERSION_1_7 && @@ -4872,8 +4859,8 @@ JSCompiler::statement() pn1->pn_op != JSOP_XMLNAME) && #endif pn1->pn_type != TOK_LB)) { - js_ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + ReportCompileErrorNumber(context, &tokenStream, pn1, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -4881,7 +4868,7 @@ JSCompiler::statement() pn2 = NULL; uintN dflag = PND_ASSIGNED; - if (TOKEN_TYPE_IS_DECL(tt)) { + if (TokenKindIsDecl(tt)) { /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */ pn1->pn_xflags |= PNX_FORINVAR; @@ -5041,7 +5028,7 @@ JSCompiler::statement() /* Parse the loop condition or null into pn2. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_SEMI) { pn2 = NULL; @@ -5054,7 +5041,7 @@ JSCompiler::statement() /* Parse the update expression or null into pn3. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RP) { pn3 = NULL; @@ -5103,8 +5090,8 @@ JSCompiler::statement() return pn; bad_for_each: - js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_FOR_EACH_LOOP); + ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_FOR_EACH_LOOP); return NULL; } @@ -5143,7 +5130,7 @@ JSCompiler::statement() PopStatement(tc); catchList = NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_CATCH) { catchList = ListNode::create(tc); if (!catchList) @@ -5158,8 +5145,8 @@ JSCompiler::statement() /* Check for another catch after unconditional catch. */ if (lastCatch && !lastCatch->pn_kid2) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_AFTER_GENERAL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_AFTER_GENERAL); return NULL; } @@ -5195,7 +5182,7 @@ JSCompiler::statement() data.binder = BindLet; data.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -5217,8 +5204,8 @@ JSCompiler::statement() break; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_IDENTIFIER); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_IDENTIFIER); return NULL; } @@ -5229,7 +5216,7 @@ JSCompiler::statement() * to avoid conflicting with the JS2/ECMAv4 type annotation * catchguard syntax. */ - if (js_MatchToken(context, &tokenStream, TOK_IF)) { + if (MatchToken(context, &tokenStream, TOK_IF)) { pn2->pn_kid2 = expr(); if (!pn2->pn_kid2) return NULL; @@ -5247,7 +5234,7 @@ JSCompiler::statement() catchList->append(pnblock); lastCatch = pn2; tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; } while (tt == TOK_CATCH); } @@ -5263,11 +5250,11 @@ JSCompiler::statement() MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); PopStatement(tc); } else { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } if (!catchList && !pn->pn_kid3) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_OR_FINALLY); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_OR_FINALLY); return NULL; } return pn; @@ -5280,13 +5267,13 @@ JSCompiler::statement() /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ tokenStream.flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(context, &tokenStream); + tt = PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } @@ -5300,13 +5287,13 @@ JSCompiler::statement() /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ case TOK_CATCH: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CATCH_WITHOUT_TRY); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CATCH_WITHOUT_TRY); return NULL; case TOK_FINALLY: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_FINALLY_WITHOUT_TRY); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_FINALLY_WITHOUT_TRY); return NULL; case TOK_BREAK: @@ -5320,8 +5307,8 @@ JSCompiler::statement() if (label) { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_LABEL_NOT_FOUND); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL && stmt->label == label) @@ -5330,8 +5317,8 @@ JSCompiler::statement() } else { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_TOUGH_BREAK); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_TOUGH_BREAK); return NULL; } if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH) @@ -5353,15 +5340,15 @@ JSCompiler::statement() if (label) { for (stmt2 = NULL; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL) { if (stmt->label == label) { if (!stmt2 || !STMT_IS_LOOP(stmt2)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); return NULL; } break; @@ -5373,8 +5360,8 @@ JSCompiler::statement() } else { for (; ; stmt = stmt->down) { if (!stmt) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_CONTINUE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_CONTINUE); return NULL; } if (STMT_IS_LOOP(stmt)) @@ -5389,14 +5376,14 @@ JSCompiler::statement() /* * In most cases, we want the constructs forbidden in strict mode * code to be a subset of those that JSOPTION_STRICT warns about, and - * we should use js_ReportStrictModeError. However, 'with' is the sole + * we should use ReportStrictModeError. However, 'with' is the sole * instance of a construct that is forbidden in strict mode code, but * doesn't even merit a warning under JSOPTION_STRICT. See * https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1. */ if (tc->flags & TCF_STRICT_MODE_CODE) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_STRICT_CODE_WITH); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_STRICT_CODE_WITH); return NULL; } @@ -5437,7 +5424,7 @@ JSCompiler::statement() JSObjectBox *blockbox; /* Check for a let statement or let expression. */ - if (js_PeekToken(context, &tokenStream) == TOK_LP) { + if (PeekToken(context, &tokenStream) == TOK_LP) { pn = letBlock(JS_TRUE); if (!pn || pn->pn_op == JSOP_LEAVEBLOCK) return pn; @@ -5462,8 +5449,8 @@ JSCompiler::statement() stmt = tc->topStmt; if (stmt && (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_LET_DECL_NOT_IN_BLOCK); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_LET_DECL_NOT_IN_BLOCK); return NULL; } @@ -5607,14 +5594,14 @@ JSCompiler::statement() pn = UnaryNode::create(tc); if (!pn) return NULL; - if (!js_MatchToken(context, &tokenStream, TOK_NAME) || + if (!MatchToken(context, &tokenStream, TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.xmlAtom || - !js_MatchToken(context, &tokenStream, TOK_NAME) || + !MatchToken(context, &tokenStream, TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.namespaceAtom || - !js_MatchToken(context, &tokenStream, TOK_ASSIGN) || + !MatchToken(context, &tokenStream, TOK_ASSIGN) || tokenStream.currentToken().t_op != JSOP_NOP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_DEFAULT_XML_NAMESPACE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_DEFAULT_XML_NAMESPACE); return NULL; } @@ -5636,28 +5623,28 @@ JSCompiler::statement() #if JS_HAS_XML_SUPPORT expression: #endif - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); pn2 = expr(); if (!pn2) return NULL; - if (js_PeekToken(context, &tokenStream) == TOK_COLON) { + if (PeekToken(context, &tokenStream) == TOK_COLON) { if (pn2->pn_type != TOK_NAME) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_LABEL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_LABEL); return NULL; } label = pn2->pn_atom; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_LABEL && stmt->label == label) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_DUPLICATE_LABEL); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_DUPLICATE_LABEL); return NULL; } } ForgetUse(pn2); - (void) js_GetToken(context, &tokenStream); + (void) GetToken(context, &tokenStream); /* Push a label struct and parse the statement. */ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); @@ -5737,7 +5724,7 @@ NoteArgumentsUse(JSTreeContext *tc) JSParseNode * JSCompiler::variables(bool inLetHead) { - JSTokenType tt; + TokenKind tt; bool let; JSStmtInfo *scopeStmt; BindData data; @@ -5790,7 +5777,7 @@ JSCompiler::variables(bool inLetHead) } do { - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); #if JS_HAS_DESTRUCTURING if (tt == TOK_LB || tt == TOK_LC) { tc->flags |= TCF_DECL_DESTRUCTURING; @@ -5802,7 +5789,7 @@ JSCompiler::variables(bool inLetHead) if (!CheckDestructuring(context, &data, pn2, NULL, tc)) return NULL; if ((tc->flags & TCF_IN_FOR_INIT) && - js_PeekToken(context, &tokenStream) == TOK_IN) { + PeekToken(context, &tokenStream) == TOK_IN) { pn->append(pn2); continue; } @@ -5838,8 +5825,8 @@ JSCompiler::variables(bool inLetHead) if (tt != TOK_NAME) { if (tt != TOK_ERROR) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); } return NULL; } @@ -5855,7 +5842,7 @@ JSCompiler::variables(bool inLetHead) return NULL; pn->append(pn2); - if (js_MatchToken(context, &tokenStream, TOK_ASSIGN)) { + if (MatchToken(context, &tokenStream, TOK_ASSIGN)) { if (tokenStream.currentToken().t_op != JSOP_NOP) goto bad_var_init; @@ -5905,14 +5892,14 @@ JSCompiler::variables(bool inLetHead) tc->flags |= TCF_FUN_HEAVYWEIGHT; } } - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; return pn; bad_var_init: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_VAR_INIT); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_VAR_INIT); return NULL; } @@ -5922,7 +5909,7 @@ JSCompiler::expr() JSParseNode *pn, *pn2; pn = assignExpr(); - if (pn && js_MatchToken(context, &tokenStream, TOK_COMMA)) { + if (pn && MatchToken(context, &tokenStream, TOK_COMMA)) { pn2 = ListNode::create(tc); if (!pn2) return NULL; @@ -5933,9 +5920,9 @@ JSCompiler::expr() #if JS_HAS_GENERATORS pn2 = pn->last(); if (pn2->pn_type == TOK_YIELD && !pn2->pn_parens) { - js_ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return NULL; } #endif @@ -5943,7 +5930,7 @@ JSCompiler::expr() if (!pn2) return NULL; pn->append(pn2); - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; } return pn; @@ -5953,14 +5940,14 @@ JSParseNode * JSCompiler::assignExpr() { JSParseNode *pn, *rhs; - JSTokenType tt; + TokenKind tt; JSOp op; JS_CHECK_RECURSION(context, return NULL); #if JS_HAS_GENERATORS tokenStream.flags |= TSF_OPERAND; - if (js_MatchToken(context, &tokenStream, TOK_YIELD)) { + if (MatchToken(context, &tokenStream, TOK_YIELD)) { tokenStream.flags &= ~TSF_OPERAND; return returnOrYield(true); } @@ -5971,7 +5958,7 @@ JSCompiler::assignExpr() if (!pn) return NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { tt = CheckGetterOrSetter(context, &tokenStream, TOK_ASSIGN); @@ -5980,7 +5967,7 @@ JSCompiler::assignExpr() } #endif if (tt != TOK_ASSIGN) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); return pn; } @@ -6002,8 +5989,8 @@ JSCompiler::assignExpr() case TOK_RB: case TOK_RC: if (op != JSOP_NOP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_DESTRUCT_ASS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_DESTRUCT_ASS); return NULL; } rhs = assignExpr(); @@ -6024,8 +6011,8 @@ JSCompiler::assignExpr() /* FALL THROUGH */ #endif default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_LEFTSIDE_OF_ASS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_LEFTSIDE_OF_ASS); return NULL; } @@ -6056,7 +6043,7 @@ JSCompiler::condExpr() uintN oldflags; pn = orExpr(); - if (pn && js_MatchToken(context, &tokenStream, TOK_HOOK)) { + if (pn && MatchToken(context, &tokenStream, TOK_HOOK)) { pn1 = pn; pn = TernaryNode::create(tc); if (!pn) @@ -6092,7 +6079,7 @@ JSCompiler::orExpr() JSParseNode *pn; pn = andExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_OR)) + while (pn && MatchToken(context, &tokenStream, TOK_OR)) pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr(), tc); return pn; } @@ -6103,7 +6090,7 @@ JSCompiler::andExpr() JSParseNode *pn; pn = bitOrExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_AND)) + while (pn && MatchToken(context, &tokenStream, TOK_AND)) pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr(), tc); return pn; } @@ -6114,7 +6101,7 @@ JSCompiler::bitOrExpr() JSParseNode *pn; pn = bitXorExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_BITOR)) { + while (pn && MatchToken(context, &tokenStream, TOK_BITOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr(), tc); } return pn; @@ -6126,7 +6113,7 @@ JSCompiler::bitXorExpr() JSParseNode *pn; pn = bitAndExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_BITXOR)) { + while (pn && MatchToken(context, &tokenStream, TOK_BITXOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr(), tc); } return pn; @@ -6138,7 +6125,7 @@ JSCompiler::bitAndExpr() JSParseNode *pn; pn = eqExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_BITAND)) + while (pn && MatchToken(context, &tokenStream, TOK_BITAND)) pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr(), tc); return pn; } @@ -6150,7 +6137,7 @@ JSCompiler::eqExpr() JSOp op; pn = relExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_EQOP)) { + while (pn && MatchToken(context, &tokenStream, TOK_EQOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr(), tc); } @@ -6161,7 +6148,7 @@ JSParseNode * JSCompiler::relExpr() { JSParseNode *pn; - JSTokenType tt; + TokenKind tt; JSOp op; uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT; @@ -6173,13 +6160,13 @@ JSCompiler::relExpr() pn = shiftExpr(); while (pn && - (js_MatchToken(context, &tokenStream, TOK_RELOP) || + (MatchToken(context, &tokenStream, TOK_RELOP) || /* * Recognize the 'in' token as an operator only if we're not * currently in the init expr of a for loop. */ - (inForInitFlag == 0 && js_MatchToken(context, &tokenStream, TOK_IN)) || - js_MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { + (inForInitFlag == 0 && MatchToken(context, &tokenStream, TOK_IN)) || + MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr(), tc); @@ -6197,7 +6184,7 @@ JSCompiler::shiftExpr() JSOp op; pn = addExpr(); - while (pn && js_MatchToken(context, &tokenStream, TOK_SHOP)) { + while (pn && MatchToken(context, &tokenStream, TOK_SHOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr(), tc); } @@ -6208,13 +6195,13 @@ JSParseNode * JSCompiler::addExpr() { JSParseNode *pn; - JSTokenType tt; + TokenKind tt; JSOp op; pn = mulExpr(); while (pn && - (js_MatchToken(context, &tokenStream, TOK_PLUS) || - js_MatchToken(context, &tokenStream, TOK_MINUS))) { + (MatchToken(context, &tokenStream, TOK_PLUS) || + MatchToken(context, &tokenStream, TOK_MINUS))) { tt = tokenStream.currentToken().type; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, mulExpr(), tc); @@ -6226,13 +6213,13 @@ JSParseNode * JSCompiler::mulExpr() { JSParseNode *pn; - JSTokenType tt; + TokenKind tt; JSOp op; pn = unaryExpr(); while (pn && - (js_MatchToken(context, &tokenStream, TOK_STAR) || - js_MatchToken(context, &tokenStream, TOK_DIVOP))) { + (MatchToken(context, &tokenStream, TOK_STAR) || + MatchToken(context, &tokenStream, TOK_DIVOP))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(), tc); @@ -6241,7 +6228,7 @@ JSCompiler::mulExpr() } static JSParseNode * -SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, +SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, JSParseNode *kid, const char *name) { if (kid->pn_type != TOK_NAME && @@ -6252,8 +6239,7 @@ SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) && #endif kid->pn_type != TOK_LB) { - js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, - JSMSG_BAD_OPERAND, name); + ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name); return NULL; } if (!CheckStrictAssignment(cx, tc, kid)) @@ -6265,9 +6251,9 @@ SetLvalKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, static const char incop_name_str[][10] = {"increment", "decrement"}; static JSBool -SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, +SetIncOpKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, JSParseNode *kid, - JSTokenType tt, JSBool preorder) + TokenKind tt, JSBool preorder) { JSOp op; @@ -6315,13 +6301,13 @@ SetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSParseNode * JSCompiler::unaryExpr() { - JSTokenType tt; + TokenKind tt; JSParseNode *pn, *pn2; JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; switch (tt) { @@ -6377,7 +6363,8 @@ JSCompiler::unaryExpr() } break; case TOK_NAME: - if (!js_ReportStrictModeError(context, &tokenStream, tc, pn, JSMSG_DEPRECATED_DELETE_OPERAND)) + if (!ReportStrictModeError(context, &tokenStream, tc, pn, + JSMSG_DEPRECATED_DELETE_OPERAND)) return NULL; pn2->pn_op = JSOP_DELNAME; break; @@ -6390,7 +6377,7 @@ JSCompiler::unaryExpr() return NULL; default: - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); pn = memberExpr(JS_TRUE); if (!pn) return NULL; @@ -6398,10 +6385,10 @@ JSCompiler::unaryExpr() /* Don't look across a newline boundary for a postfix incop. */ if (tokenStream.onCurrentLine(pn->pn_pos)) { tokenStream.flags |= TSF_OPERAND; - tt = js_PeekTokenSameLine(context, &tokenStream); + tt = PeekTokenSameLine(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_INC || tt == TOK_DEC) { - (void) js_GetToken(context, &tokenStream); + (void) GetToken(context, &tokenStream); pn2 = UnaryNode::create(tc); if (!pn2) return NULL; @@ -6646,13 +6633,13 @@ CompExprTransplanter::transplant(JSParseNode *pn) */ JSParseNode * JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, - JSTokenType type, JSOp op) + TokenKind type, JSOp op) { uintN adjust; JSParseNode *pn, *pn2, *pn3, **pnp; JSStmtInfo stmtInfo; BindData data; - JSTokenType tt; + TokenKind tt; JSAtom *atom; JS_ASSERT(tokenStream.currentToken().type == TOK_FOR); @@ -6717,16 +6704,16 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, pn2->pn_op = JSOP_ITER; pn2->pn_iflags = JSITER_ENUMERATE; - if (js_MatchToken(context, &tokenStream, TOK_NAME)) { + if (MatchToken(context, &tokenStream, TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn2->pn_iflags |= JSITER_FOREACH; else - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); atom = NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -6755,8 +6742,8 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, break; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NO_VARIABLE_NAME); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NO_VARIABLE_NAME); case TOK_ERROR: return NULL; @@ -6778,8 +6765,8 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, if (JSVERSION_NUMBER(context) == JSVERSION_1_7) { /* Destructuring requires [key, value] enumeration in JS1.7. */ if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_FOR_LEFTSIDE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); return NULL; } @@ -6805,9 +6792,9 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, return NULL; *pnp = pn2; pnp = &pn2->pn_right; - } while (js_MatchToken(context, &tokenStream, TOK_FOR)); + } while (MatchToken(context, &tokenStream, TOK_FOR)); - if (js_MatchToken(context, &tokenStream, TOK_IF)) { + if (MatchToken(context, &tokenStream, TOK_IF)) { pn2 = TernaryNode::create(tc); if (!pn2) return NULL; @@ -6939,7 +6926,7 @@ JSCompiler::argumentList(JSParseNode *listNode) JSBool matched; tokenStream.flags |= TSF_OPERAND; - matched = js_MatchToken(context, &tokenStream, TOK_RP); + matched = MatchToken(context, &tokenStream, TOK_RP); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { do { @@ -6949,15 +6936,15 @@ JSCompiler::argumentList(JSParseNode *listNode) #if JS_HAS_GENERATORS if (argNode->pn_type == TOK_YIELD && !argNode->pn_parens && - js_PeekToken(context, &tokenStream) == TOK_COMMA) { - js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + PeekToken(context, &tokenStream) == TOK_COMMA) { + ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_yield_str); return JS_FALSE; } #endif #if JS_HAS_GENERATOR_EXPRS - if (js_MatchToken(context, &tokenStream, TOK_FOR)) { + if (MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pn = UnaryNode::create(tc); if (!pn) return JS_FALSE; @@ -6965,20 +6952,20 @@ JSCompiler::argumentList(JSParseNode *listNode) if (!argNode) return JS_FALSE; if (listNode->pn_count > 1 || - js_PeekToken(context, &tokenStream) == TOK_COMMA) { - js_ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + PeekToken(context, &tokenStream) == TOK_COMMA) { + ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, + js_generator_str); return JS_FALSE; } } #endif listNode->append(argNode); - } while (js_MatchToken(context, &tokenStream, TOK_COMMA)); + } while (MatchToken(context, &tokenStream, TOK_COMMA)); - if (js_GetToken(context, &tokenStream) != TOK_RP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_PAREN_AFTER_ARGS); + if (GetToken(context, &tokenStream) != TOK_RP) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_PAREN_AFTER_ARGS); return JS_FALSE; } } @@ -7004,13 +6991,13 @@ JSParseNode * JSCompiler::memberExpr(JSBool allowCallSyntax) { JSParseNode *pn, *pn2, *pn3; - JSTokenType tt; + TokenKind tt; JS_CHECK_RECURSION(context, return NULL); /* Check for new expression first. */ tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_NEW) { pn = ListNode::create(tc); @@ -7024,7 +7011,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn->initList(pn2); pn->pn_pos.begin = pn2->pn_pos.begin; - if (js_MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) + if (MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) return NULL; if (pn->pn_count > ARGC_LIMIT) { JS_ReportErrorNumber(context, js_GetErrorMessage, NULL, @@ -7053,14 +7040,14 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } } - while ((tt = js_GetToken(context, &tokenStream)) > TOK_EOF) { + while ((tt = GetToken(context, &tokenStream)) > TOK_EOF) { if (tt == TOK_DOT) { pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7079,12 +7066,12 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) /* A filtering predicate is like a with statement. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; - } else if (TOKEN_TYPE_IS_XML(PN_TYPE(pn3))) { + } else if (TokenKindIsXML(PN_TYPE(pn3))) { pn2->pn_type = TOK_LB; pn2->pn_op = JSOP_GETELEM; } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); return NULL; } pn2->pn_arity = PN_BINARY; @@ -7107,7 +7094,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7117,9 +7104,9 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn3->pn_type = TOK_STRING; pn3->pn_arity = PN_NULLARY; pn3->pn_op = JSOP_QNAMEPART; - } else if (!TOKEN_TYPE_IS_XML(tt)) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_NAME_AFTER_DOT); + } else if (!TokenKindIsXML(tt)) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_NAME_AFTER_DOT); return NULL; } pn2->pn_op = JSOP_DESCENDANTS; @@ -7200,7 +7187,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } pn2->pn_pos.end = tokenStream.currentToken().pos.end; } else { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); return pn; } @@ -7321,7 +7308,7 @@ JSParseNode * JSCompiler::qualifiedSuffix(JSParseNode *pn) { JSParseNode *pn2, *pn3; - JSTokenType tt; + TokenKind tt; JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON); pn2 = NameNode::create(NULL, tc); @@ -7333,7 +7320,7 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) pn->pn_op = JSOP_NAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { /* Inline and specialize propertySelector for JSOP_QNAMECONST. */ @@ -7348,8 +7335,8 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) } if (tt != TOK_LB) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } pn3 = endBracketedExpr(); @@ -7373,7 +7360,7 @@ JSCompiler::qualifiedIdentifier() pn = propertySelector(); if (!pn) return NULL; - if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; pn = qualifiedSuffix(pn); @@ -7385,7 +7372,7 @@ JSParseNode * JSCompiler::attributeIdentifier() { JSParseNode *pn, *pn2; - JSTokenType tt; + TokenKind tt; JS_ASSERT(tokenStream.currentToken().type == TOK_AT); pn = UnaryNode::create(tc); @@ -7393,15 +7380,15 @@ JSCompiler::attributeIdentifier() return NULL; pn->pn_op = JSOP_TOATTRNAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { pn2 = qualifiedIdentifier(); } else if (tt == TOK_LB) { pn2 = endBracketedExpr(); } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } if (!pn2) @@ -7455,7 +7442,7 @@ JSCompiler::xmlAtomNode() JSParseNode *pn = NullaryNode::create(tc); if (!pn) return NULL; - JSToken *tp = tokenStream.mutableCurrentToken(); + Token *tp = tokenStream.mutableCurrentToken(); pn->pn_op = tp->t_op; pn->pn_atom = tp->t_atom; if (tp->type == TOK_XMLPI) @@ -7479,7 +7466,7 @@ JSParseNode * JSCompiler::xmlNameExpr() { JSParseNode *pn, *pn2, *list; - JSTokenType tt; + TokenKind tt; pn = list = NULL; do { @@ -7511,9 +7498,9 @@ JSCompiler::xmlNameExpr() pn->pn_pos.end = pn2->pn_pos.end; pn->append(pn2); } - } while ((tt = js_GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); + } while ((tt = GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); return pn; } @@ -7543,10 +7530,10 @@ JSCompiler::xmlNameExpr() * we parsed exactly one expression. */ JSParseNode * -JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) +JSCompiler::xmlTagContent(TokenKind tagtype, JSAtom **namep) { JSParseNode *pn, *pn2, *list; - JSTokenType tt; + TokenKind tt; pn = xmlNameExpr(); if (!pn) @@ -7554,10 +7541,10 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; list = NULL; - while (js_MatchToken(context, &tokenStream, TOK_XMLSPACE)) { - tt = js_GetToken(context, &tokenStream); + while (MatchToken(context, &tokenStream, TOK_XMLSPACE)) { + tt = GetToken(context, &tokenStream); if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); break; } @@ -7577,19 +7564,19 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) if (!XML_FOLDABLE(pn2)) pn->pn_xflags |= PNX_CANTFOLD; - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_XMLATTR) { pn2 = xmlAtomNode(); } else if (tt == TOK_LC) { pn2 = xmlExpr(JS_TRUE); pn->pn_xflags |= PNX_CANTFOLD; } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_ATTR_VALUE); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_ATTR_VALUE); return NULL; } if (!pn2) @@ -7601,15 +7588,15 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) return pn; } -#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ - JS_BEGIN_MACRO \ - if ((tt) <= TOK_EOF) { \ - if ((tt) == TOK_EOF) { \ - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ - JSMSG_END_OF_XML_SOURCE); \ - } \ - return result; \ - } \ +#define XML_CHECK_FOR_ERROR_AND_EOF(tt,result) \ + JS_BEGIN_MACRO \ + if ((tt) <= TOK_EOF) { \ + if ((tt) == TOK_EOF) { \ + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, \ + JSMSG_END_OF_XML_SOURCE); \ + } \ + return result; \ + } \ JS_END_MACRO /* @@ -7619,14 +7606,14 @@ JSCompiler::xmlTagContent(JSTokenType tagtype, JSAtom **namep) JSBool JSCompiler::xmlElementContent(JSParseNode *pn) { - JSTokenType tt; + TokenKind tt; JSParseNode *pn2; JSAtom *textAtom; tokenStream.flags &= ~TSF_XMLTAGMODE; for (;;) { tokenStream.flags |= TSF_XMLTEXTMODE; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_XMLTEXTMODE; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); @@ -7642,7 +7629,7 @@ JSCompiler::xmlElementContent(JSParseNode *pn) } tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); if (tt == TOK_XMLETAGO) @@ -7680,7 +7667,7 @@ JSParseNode * JSCompiler::xmlElementOrList(JSBool allowList) { JSParseNode *pn, *pn2, *list; - JSTokenType tt; + TokenKind tt; JSAtom *startAtom, *endAtom; JS_CHECK_RECURSION(context, return NULL); @@ -7691,7 +7678,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; tokenStream.flags |= TSF_XMLTAGMODE; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_ERROR) return NULL; @@ -7702,9 +7689,9 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn2 = xmlTagContent(TOK_XMLSTAGO, &startAtom); if (!pn2) return NULL; - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_XMLPTAGC) { /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ if (pn2->pn_type == TOK_XMLSTAGO) { @@ -7723,8 +7710,8 @@ JSCompiler::xmlElementOrList(JSBool allowList) } else { /* We had better have a tag-close (>) at this point. */ if (tt != TOK_XMLTAGC) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } pn2->pn_pos.end = tokenStream.currentToken().pos.end; @@ -7752,11 +7739,11 @@ JSCompiler::xmlElementOrList(JSBool allowList) if (!xmlElementContent(pn)) return NULL; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); if (tt != TOK_XMLNAME && tt != TOK_LC) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } @@ -7766,18 +7753,16 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; if (pn2->pn_type == TOK_XMLETAGO) { /* Oops, end tag has attributes! */ - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_TAG_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_TAG_SYNTAX); return NULL; } if (endAtom && startAtom && endAtom != startAtom) { JSString *str = ATOM_TO_STRING(startAtom); /* End vs. start tag name mismatch: point to the tag name. */ - js_ReportCompileErrorNumber(context, &tokenStream, pn2, - JSREPORT_UC | JSREPORT_ERROR, - JSMSG_XML_TAG_NAME_MISMATCH, - str->chars()); + ReportCompileErrorNumber(context, &tokenStream, pn2, JSREPORT_UC | JSREPORT_ERROR, + JSMSG_XML_TAG_NAME_MISMATCH, str->chars()); return NULL; } @@ -7794,7 +7779,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn->pn_xflags |= PNX_CANTFOLD; } - js_MatchToken(context, &tokenStream, TOK_XMLSPACE); + MatchToken(context, &tokenStream, TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); } @@ -7811,8 +7796,8 @@ JSCompiler::xmlElementOrList(JSBool allowList) MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX); } else { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_NAME_SYNTAX); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_NAME_SYNTAX); return NULL; } @@ -7852,13 +7837,13 @@ JSCompiler::parseXMLText(JSObject *chain, bool allowList) /* Set XML-only mode to turn off special treatment of {expr} in XML. */ tokenStream.flags |= TSF_OPERAND | TSF_XMLONLYMODE; - JSTokenType tt = js_GetToken(context, &tokenStream); + TokenKind tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; JSParseNode *pn; if (tt != TOK_XMLSTAGO) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_MARKUP); pn = NULL; } else { pn = xmlElementOrListRoot(allowList); @@ -7905,7 +7890,7 @@ BlockIdInScope(uintN blockid, JSTreeContext *tc) #endif JSParseNode * -JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) +JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) { JSParseNode *pn, *pn2, *pn3; JSOp op; @@ -7924,7 +7909,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; pn2 = NullaryNode::create(tc); if (!pn2) @@ -7959,18 +7944,18 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) #endif tokenStream.flags |= TSF_OPERAND; - matched = js_MatchToken(context, &tokenStream, TOK_RB); + matched = MatchToken(context, &tokenStream, TOK_RB); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { for (index = 0; ; index++) { if (index == JS_ARGS_LENGTH_MAX) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_ARRAY_INIT_TOO_BIG); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_ARRAY_INIT_TOO_BIG); return NULL; } tokenStream.flags |= TSF_OPERAND; - tt = js_PeekToken(context, &tokenStream); + tt = PeekToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RB) { pn->pn_xflags |= PNX_ENDCOMMA; @@ -7979,7 +7964,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) if (tt == TOK_COMMA) { /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ - js_MatchToken(context, &tokenStream, TOK_COMMA); + MatchToken(context, &tokenStream, TOK_COMMA); pn2 = NullaryNode::create(tc); pn->pn_xflags |= PNX_HOLEY; } else { @@ -7991,7 +7976,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) if (tt != TOK_COMMA) { /* If we didn't already match TOK_COMMA in above case. */ - if (!js_MatchToken(context, &tokenStream, TOK_COMMA)) + if (!MatchToken(context, &tokenStream, TOK_COMMA)) break; } } @@ -8041,7 +8026,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) */ if (index == 0 && pn->pn_count != 0 && - js_MatchToken(context, &tokenStream, TOK_FOR)) { + MatchToken(context, &tokenStream, TOK_FOR)) { JSParseNode *pnexp, *pntop; /* Relabel pn as an array comprehension node. */ @@ -8098,7 +8083,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) for (;;) { JSAtom *atom; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; switch (tt) { case TOK_NUMBER: @@ -8123,10 +8108,10 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) goto property_name; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt != TOK_NAME) { - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); goto property_name; } atom = tokenStream.currentToken().t_atom; @@ -8153,12 +8138,12 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) case TOK_RC: goto end_obj_init; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_PROP_ID); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_PROP_ID); return NULL; } - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); op = JSOP_INITPROP; #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { @@ -8175,8 +8160,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) #if JS_HAS_DESTRUCTURING_SHORTHAND if (tt != TOK_COMMA && tt != TOK_RC) { #endif - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_COLON_AFTER_ID); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_COLON_AFTER_ID); return NULL; #if JS_HAS_DESTRUCTURING_SHORTHAND } @@ -8185,7 +8170,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) * Support, e.g., |var {x, y} = o| as destructuring shorthand * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8. */ - js_UngetToken(&tokenStream); + UngetToken(&tokenStream); pn->pn_xflags |= PNX_DESTRUCT; pnval = pn3; if (pnval->pn_type == TOK_NAME) { @@ -8226,8 +8211,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) if (ALE_INDEX(ale) & attributesMask) { const char *name = js_AtomToPrintableString(context, atom); if (!name || - !js_ReportStrictModeError(context, &tokenStream, tc, NULL, - JSMSG_DUPLICATE_PROPERTY, name)) { + !ReportStrictModeError(context, &tokenStream, tc, NULL, + JSMSG_DUPLICATE_PROPERTY, name)) { return NULL; } } @@ -8240,12 +8225,12 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) } } - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); if (tt == TOK_RC) goto end_obj_init; if (tt != TOK_COMMA) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_CURLY_AFTER_LIST); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_CURLY_AFTER_LIST); return NULL; } afterComma = JS_TRUE; @@ -8271,7 +8256,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) return NULL; pn->pn_num = (jsint) tokenStream.currentToken().t_dval; tokenStream.flags |= TSF_OPERAND; - tt = js_GetToken(context, &tokenStream); + tt = GetToken(context, &tokenStream); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_USESHARP || tt == TOK_DEFSHARP || #if JS_HAS_XML_SUPPORT @@ -8279,8 +8264,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) tt == TOK_XMLSTAGO /* XXXbe could be sharp? */ || #endif tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_PRIMARY) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_SHARP_VAR_DEF); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_SHARP_VAR_DEF); return NULL; } pn->pn_kid = primaryExpr(tt, JS_FALSE); @@ -8384,7 +8369,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) } } else if ((!afterDot #if JS_HAS_XML_SUPPORT - || js_PeekToken(context, &tokenStream) == TOK_DBLCOLON + || PeekToken(context, &tokenStream) == TOK_DBLCOLON #endif ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) { JSStmtInfo *stmt = js_LexicalLookup(tc, pn->pn_atom, NULL); @@ -8446,7 +8431,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) */ JS_ASSERT(PN_TYPE(dn) == TOK_NAME); JS_ASSERT(dn->pn_op == JSOP_NOP); - if (js_PeekToken(context, &tokenStream) != TOK_LP) + if (PeekToken(context, &tokenStream) != TOK_LP) dn->pn_dflags |= PND_FUNARG; } } @@ -8455,7 +8440,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) LinkUseToDef(pn, dn, tc); /* Here we handle the backward function reference case. */ - if (js_PeekToken(context, &tokenStream) != TOK_LP) + if (PeekToken(context, &tokenStream) != TOK_LP) dn->pn_dflags |= PND_FUNARG; pn->pn_dflags |= (dn->pn_dflags & PND_FUNARG); @@ -8463,7 +8448,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) } #if JS_HAS_XML_SUPPORT - if (js_MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { if (afterDot) { JSString *str; @@ -8478,8 +8463,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) pn->pn_arity = PN_NULLARY; pn->pn_type = TOK_FUNCTION; } else if (tt != TOK_EOF) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_KEYWORD_NOT_NS); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_KEYWORD_NOT_NS); return NULL; } } @@ -8537,8 +8522,8 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) return NULL; default: - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_SYNTAX_ERROR); + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_SYNTAX_ERROR); return NULL; } return pn; @@ -8547,7 +8532,7 @@ JSCompiler::primaryExpr(JSTokenType tt, JSBool afterDot) JSParseNode * JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) { - JSTokenPtr begin; + TokenPtr begin; JSParseNode *pn; JS_ASSERT(tokenStream.currentToken().type == TOK_LP); @@ -8560,18 +8545,15 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; #if JS_HAS_GENERATOR_EXPRS - if (js_MatchToken(context, &tokenStream, TOK_FOR)) { + if (MatchToken(context, &tokenStream, TOK_FOR)) { if (pn->pn_type == TOK_YIELD && !pn->pn_parens) { - js_ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_yield_str); + ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); return NULL; } if (pn->pn_type == TOK_COMMA && !pn->pn_parens) { - js_ReportCompileErrorNumber(context, &tokenStream, pn->last(), - JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + ReportCompileErrorNumber(context, &tokenStream, pn->last(), JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); return NULL; } if (!pn1) { @@ -8584,10 +8566,9 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; pn->pn_pos.begin = begin; if (genexp) { - if (js_GetToken(context, &tokenStream) != TOK_RP) { - js_ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, - JSMSG_BAD_GENERATOR_SYNTAX, - js_generator_str); + if (GetToken(context, &tokenStream) != TOK_RP) { + ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, + JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); return NULL; } pn->pn_pos.end = tokenStream.currentToken().pos.end; @@ -8604,7 +8585,7 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) * XXX handles only strings and numbers for now */ static JSBool -FoldType(JSContext *cx, JSParseNode *pn, JSTokenType type) +FoldType(JSContext *cx, JSParseNode *pn, TokenKind type) { if (PN_TYPE(pn) != type) { switch (type) { @@ -8727,7 +8708,7 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2, static JSBool FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) { - JSTokenType tt; + TokenKind tt; JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 396ba74d134d..b7155cf70407 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -296,9 +296,9 @@ struct JSParseNode { pn_defn:1; /* this node is a JSDefinition */ #define PN_OP(pn) ((JSOp)(pn)->pn_op) -#define PN_TYPE(pn) ((JSTokenType)(pn)->pn_type) +#define PN_TYPE(pn) ((js::TokenKind)(pn)->pn_type) - JSTokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ + js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ int32 pn_offset; /* first generated bytecode offset */ JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */ JSParseNode *pn_link; /* def/use link (alignment freebie); @@ -387,7 +387,7 @@ struct JSParseNode { #define pn_atom2 pn_u.apair.atom2 protected: - void inline init(JSTokenType type, JSOp op, JSParseNodeArity arity) { + void inline init(js::TokenKind type, JSOp op, JSParseNodeArity arity) { pn_type = type; pn_op = op; pn_arity = arity; @@ -400,7 +400,7 @@ protected: static JSParseNode *create(JSParseNodeArity arity, JSTreeContext *tc); public: - static JSParseNode *newBinaryOrAppend(JSTokenType tt, JSOp op, JSParseNode *left, + static JSParseNode *newBinaryOrAppend(js::TokenKind tt, JSOp op, JSParseNode *left, JSParseNode *right, JSTreeContext *tc); /* @@ -493,9 +493,9 @@ public: /* True if pn is a parsenode representing a literal constant. */ bool isLiteral() const { - return PN_TYPE(this) == TOK_NUMBER || - PN_TYPE(this) == TOK_STRING || - (PN_TYPE(this) == TOK_PRIMARY && PN_OP(this) != JSOP_THIS); + return PN_TYPE(this) == js::TOK_NUMBER || + PN_TYPE(this) == js::TOK_STRING || + (PN_TYPE(this) == js::TOK_PRIMARY && PN_OP(this) != JSOP_THIS); } /* @@ -506,10 +506,10 @@ public: * we'll need additional flags that we can test here. */ bool isDirectivePrologueMember() const { - if (PN_TYPE(this) == TOK_SEMI) { + if (PN_TYPE(this) == js::TOK_SEMI) { JS_ASSERT(pn_arity == PN_UNARY); JSParseNode *kid = pn_kid; - return kid && PN_TYPE(kid) == TOK_STRING && !kid->pn_parens; + return kid && PN_TYPE(kid) == js::TOK_STRING && !kid->pn_parens; } return false; } @@ -756,7 +756,7 @@ struct JSDefinition : public JSParseNode JSDefinition *resolve() { JSParseNode *pn = this; while (!pn->pn_defn) { - if (pn->pn_type == TOK_ASSIGN) { + if (pn->pn_type == js::TOK_ASSIGN) { pn = pn->pn_left; continue; } @@ -781,9 +781,9 @@ struct JSDefinition : public JSParseNode static const char *kindString(Kind kind); Kind kind() { - if (PN_TYPE(this) == TOK_FUNCTION) + if (PN_TYPE(this) == js::TOK_FUNCTION) return FUNCTION; - JS_ASSERT(PN_TYPE(this) == TOK_NAME); + JS_ASSERT(PN_TYPE(this) == js::TOK_NAME); if (PN_OP(this) == JSOP_NOP) return UNKNOWN; if (PN_OP(this) == JSOP_GETARG) @@ -916,7 +916,7 @@ struct JSCompiler : private js::AutoGCRooter { JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; - JSTokenStream tokenStream; + js::TokenStream tokenStream; void *tempPoolMark; /* initial JSContext.tempPool mark */ JSPrincipals *principals; /* principals associated with source */ JSStackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */ @@ -1015,7 +1015,7 @@ private: JSParseNode *mulExpr(); JSParseNode *unaryExpr(); JSParseNode *memberExpr(JSBool allowCallSyntax); - JSParseNode *primaryExpr(JSTokenType tt, JSBool afterDot); + JSParseNode *primaryExpr(js::TokenKind tt, JSBool afterDot); JSParseNode *parenExpr(JSParseNode *pn1, JSBool *genexp); /* @@ -1026,13 +1026,13 @@ private: JSParseNode *functionDef(uintN lambda); JSParseNode *condition(); JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid, - JSTokenType type = TOK_SEMI, JSOp op = JSOP_NOP); + js::TokenKind type = js::TOK_SEMI, JSOp op = JSOP_NOP); JSParseNode *generatorExpr(JSParseNode *pn, JSParseNode *kid); JSBool argumentList(JSParseNode *listNode); JSParseNode *bracketedExpr(); JSParseNode *letBlock(JSBool statement); JSParseNode *returnOrYield(bool useAssignExpr); - JSParseNode *destructuringExpr(BindData *data, JSTokenType tt); + JSParseNode *destructuringExpr(BindData *data, js::TokenKind tt); #if JS_HAS_XML_SUPPORT JSParseNode *endBracketedExpr(); @@ -1044,7 +1044,7 @@ private: JSParseNode *xmlExpr(JSBool inTag); JSParseNode *xmlAtomNode(); JSParseNode *xmlNameExpr(); - JSParseNode *xmlTagContent(JSTokenType tagtype, JSAtom **namep); + JSParseNode *xmlTagContent(js::TokenKind tagtype, JSAtom **namep); JSBool xmlElementContent(JSParseNode *pn); JSParseNode *xmlElementOrList(JSBool allowList); JSParseNode *xmlElementOrListRoot(JSBool allowList); diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 7773972938f4..6171bd68964e 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -105,10 +105,6 @@ typedef struct JSEmptyScope JSEmptyScope; typedef struct JSTempValueRooter JSTempValueRooter; typedef struct JSThread JSThread; typedef struct JSThreadData JSThreadData; -typedef struct JSToken JSToken; -typedef struct JSTokenPos JSTokenPos; -typedef struct JSTokenPtr JSTokenPtr; -typedef struct JSTokenStream JSTokenStream; typedef struct JSTreeContext JSTreeContext; typedef struct JSTryNote JSTryNote; typedef struct JSWeakRoots JSWeakRoots; @@ -150,6 +146,11 @@ class TraceRecorder; struct TraceMonitor; class CallStack; +struct TokenStream; +struct Token; +struct TokenPos; +struct TokenPtr; + class ContextAllocPolicy; class SystemAllocPolicy; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 20754462d056..4afef943c6c0 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -178,7 +178,7 @@ struct RENode { typedef struct CompilerState { JSContext *context; - JSTokenStream *tokenStream; /* For reporting errors */ + TokenStream *tokenStream; /* For reporting errors */ const jschar *cpbegin; const jschar *cpend; const jschar *cp; @@ -441,9 +441,8 @@ ReportRegExpErrorHelper(CompilerState *state, uintN flags, uintN errorNumber, const jschar *arg) { if (state->tokenStream) { - return js_ReportCompileErrorNumber(state->context, state->tokenStream, - NULL, JSREPORT_UC | flags, - errorNumber, arg); + return ReportCompileErrorNumber(state->context, state->tokenStream, + NULL, JSREPORT_UC | flags, errorNumber, arg); } return JS_ReportErrorFlagsAndNumberUC(state->context, flags, js_GetErrorMessage, NULL, @@ -1958,7 +1957,7 @@ EmitREBytecode(CompilerState *state, JSRegExp *re, size_t treeDepth, } static JSBool -CompileRegExpToAST(JSContext* cx, JSTokenStream* ts, +CompileRegExpToAST(JSContext* cx, TokenStream* ts, JSString* str, uintN flags, CompilerState& state) { uintN i; @@ -3337,7 +3336,7 @@ GetNativeRegExp(JSContext* cx, JSRegExp* re) #endif JSRegExp * -js_NewRegExp(JSContext *cx, JSTokenStream *ts, +js_NewRegExp(JSContext *cx, TokenStream *ts, JSString *str, uintN flags, JSBool flat) { JSRegExp *re; @@ -5832,7 +5831,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) } JSObject * -js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, +js_NewRegExpObject(JSContext *cx, TokenStream *ts, const jschar *chars, size_t length, uintN flags) { JSString *str; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index b439f0782516..73cfee817450 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -120,7 +120,7 @@ struct JSRegExp { }; extern JSRegExp * -js_NewRegExp(JSContext *cx, JSTokenStream *ts, +js_NewRegExp(JSContext *cx, js::TokenStream *ts, JSString *str, uintN flags, JSBool flat); extern JSRegExp * @@ -183,7 +183,7 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp); * Create, serialize/deserialize, or clone a RegExp object. */ extern JSObject * -js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, +js_NewRegExpObject(JSContext *cx, js::TokenStream *ts, const jschar *chars, size_t length, uintN flags); extern JSBool diff --git a/js/src/jsscan.cpp b/js/src/jsscan.cpp index a3e2b4ddcea4..7c9d67ee5c63 100644 --- a/js/src/jsscan.cpp +++ b/js/src/jsscan.cpp @@ -86,7 +86,7 @@ using namespace js; struct keyword { const char *chars; /* C string with keyword text */ - JSTokenType tokentype; /* JSTokenType */ + TokenKind tokentype; JSOp op; /* JSOp */ JSVersion version; /* JSVersion */ }; @@ -137,7 +137,7 @@ FindKeyword(const jschar *s, size_t length) return NULL; } -JSTokenType +TokenKind js_CheckKeyword(const jschar *str, size_t length) { const struct keyword *kw; @@ -175,7 +175,7 @@ js_IsIdentifier(JSString *str) #endif /* Initialize members that aren't initialized in |init|. */ -JSTokenStream::JSTokenStream(JSContext *cx) +TokenStream::TokenStream(JSContext *cx) : cx(cx), tokens(), cursor(), lookahead(), ungetpos(), ungetbuf(), flags(), linelen(), linepos(), file(), listenerTSData(), saveEOL(), tokenbuf(cx) {} @@ -185,16 +185,15 @@ JSTokenStream::JSTokenStream(JSContext *cx) #endif bool -JSTokenStream::init(const jschar *base, size_t length, - FILE *fp, const char *fn, uintN ln) +TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, uintN ln) { jschar *buf; JS_ASSERT_IF(fp, !base); JS_ASSERT_IF(!base, length == 0); size_t nb = fp - ? 2 * JS_LINE_LIMIT * sizeof(jschar) - : JS_LINE_LIMIT * sizeof(jschar); + ? 2 * LINE_LIMIT * sizeof(jschar) + : LINE_LIMIT * sizeof(jschar); JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb); if (!buf) { js_ReportOutOfScriptQuota(cx); @@ -208,8 +207,8 @@ JSTokenStream::init(const jschar *base, size_t length, linebuf.base = linebuf.limit = linebuf.ptr = buf; if (fp) { file = fp; - userbuf.base = buf + JS_LINE_LIMIT; - userbuf.ptr = userbuf.limit = userbuf.base + JS_LINE_LIMIT; + userbuf.base = buf + LINE_LIMIT; + userbuf.ptr = userbuf.limit = userbuf.base + LINE_LIMIT; } else { userbuf.base = (jschar *)base; userbuf.limit = (jschar *)base + length; @@ -221,7 +220,7 @@ JSTokenStream::init(const jschar *base, size_t length, } void -JSTokenStream::close() +TokenStream::close() { if (flags & TSF_OWNFILENAME) cx->free((void *) filename); @@ -265,12 +264,12 @@ js_fgets(char *buf, int size, FILE *file) } int32 -JSTokenStream::getChar() +TokenStream::getChar() { int32 c; ptrdiff_t i, j, len, olen; JSBool crflag; - char cbuf[JS_LINE_LIMIT]; + char cbuf[LINE_LIMIT]; jschar *ubuf, *nl; if (ungetpos != 0) { @@ -286,7 +285,7 @@ JSTokenStream::getChar() /* Fill userbuf so that \r and \r\n convert to \n. */ crflag = (flags & TSF_CRFLAG) != 0; - len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, file); + len = js_fgets(cbuf, LINE_LIMIT - crflag, file); if (len <= 0) { flags |= TSF_EOF; return EOF; @@ -338,12 +337,12 @@ JSTokenStream::getChar() /* * If there was a line terminator, copy thru it into linebuf. - * Else copy JS_LINE_LIMIT-1 bytes into linebuf. + * Else copy LINE_LIMIT-1 bytes into linebuf. */ if (nl < userbuf.limit) len = (nl - userbuf.ptr) + 1; - if (len >= JS_LINE_LIMIT) { - len = JS_LINE_LIMIT - 1; + if (len >= (ptrdiff_t) LINE_LIMIT) { + len = LINE_LIMIT - 1; saveEOL = nl; } else { saveEOL = NULL; @@ -419,7 +418,7 @@ JSTokenStream::getChar() } void -JSTokenStream::ungetChar(int32 c) +TokenStream::ungetChar(int32 c) { if (c == EOF) return; @@ -435,7 +434,7 @@ JSTokenStream::ungetChar(int32 c) * be used to peek into or past a newline. */ JSBool -JSTokenStream::peekChars(intN n, jschar *cp) +TokenStream::peekChars(intN n, jschar *cp) { intN i, j; int32 c; @@ -456,8 +455,8 @@ JSTokenStream::peekChars(intN n, jschar *cp) } bool -JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, - uintN errorNumber, va_list ap) +TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, + va_list ap) { JSErrorReport report; char *message; @@ -466,11 +465,11 @@ JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, char *linebytes; bool warning; JSBool ok; - JSTokenPos *tp; + TokenPos *tp; uintN index, i; JSErrorReporter onError; - JS_ASSERT(linebuf.limit < linebuf.base + JS_LINE_LIMIT); + JS_ASSERT(linebuf.limit < linebuf.base + LINE_LIMIT); if (JSREPORT_IS_STRICT(flags) && !JS_HAS_STRICT_OPTION(cx)) return JS_TRUE; @@ -625,8 +624,8 @@ JSTokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, } bool -js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParseNode *pn, uintN errorNumber, ...) +js::ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, + uintN errorNumber, ...) { bool result; va_list ap; @@ -653,14 +652,14 @@ js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } bool -js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, - uintN flags, uintN errorNumber, ...) +js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, + uintN flags, uintN errorNumber, ...) { va_list ap; /* * We don't accept a JSTreeContext argument, so we can't implement - * JSREPORT_STRICT_MODE_ERROR here. Use js_ReportStrictModeError instead, + * JSREPORT_STRICT_MODE_ERROR here. Use ReportStrictModeError instead, * or do the checks in the caller and pass plain old JSREPORT_ERROR. */ JS_ASSERT(!(flags & JSREPORT_STRICT_MODE_ERROR)); @@ -676,7 +675,7 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, #if JS_HAS_XML_SUPPORT JSBool -JSTokenStream::getXMLEntity() +TokenStream::getXMLEntity() { ptrdiff_t offset, length, i; int c, d; @@ -693,8 +692,7 @@ JSTokenStream::getXMLEntity() return JS_FALSE; while ((c = getChar()) != ';') { if (c == EOF || c == '\n') { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_END_OF_XML_ENTITY); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_END_OF_XML_ENTITY); return JS_FALSE; } if (!tb.append(c)) @@ -786,8 +784,7 @@ JSTokenStream::getXMLEntity() JS_ASSERT((tb.end() - bp) >= 1); bytes = js_DeflateString(cx, bp + 1, (tb.end() - bp) - 1); if (bytes) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - msg, bytes); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, msg, bytes); cx->free(bytes); } return JS_FALSE; @@ -801,7 +798,7 @@ JSTokenStream::getXMLEntity() * Otherwise, non-destructively return the original '\'. */ int32 -JSTokenStream::getUnicodeEscape() +TokenStream::getUnicodeEscape() { jschar cp[5]; int32 c; @@ -820,11 +817,11 @@ JSTokenStream::getUnicodeEscape() return '\\'; } -JSToken * -JSTokenStream::newToken(ptrdiff_t adjust) +Token * +TokenStream::newToken(ptrdiff_t adjust) { - cursor = (cursor + 1) & NTOKENS_MASK; - JSToken *tp = mutableCurrentToken(); + cursor = (cursor + 1) & ntokensMask; + Token *tp = mutableCurrentToken(); tp->ptr = linebuf.ptr + adjust; tp->pos.begin.index = linepos + (tp->ptr - linebuf.base) - ungetpos; tp->pos.begin.lineno = tp->pos.end.lineno = lineno; @@ -846,12 +843,12 @@ atomize(JSContext *cx, JSCharBuffer &cb) return js_AtomizeChars(cx, cb.begin(), cb.length(), 0); } -JSTokenType -JSTokenStream::getTokenInternal() +TokenKind +TokenStream::getTokenInternal() { - JSTokenType tt; + TokenKind tt; int c, qc; - JSToken *tp; + Token *tp; JSAtom *atom; JSBool hadUnicodeEscape; const struct keyword *kw; @@ -927,9 +924,8 @@ JSTokenStream::getTokenInternal() (nextc = peekChar(), ((flags & TSF_XMLONLYMODE) || nextc != '{') && !JS_ISXMLNAME(nextc))) { - js_ReportCompileErrorNumber(cx, this, NULL, - JSREPORT_ERROR, - JSMSG_BAD_XML_QNAME); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_BAD_XML_QNAME); goto error; } sawColon = JS_TRUE; @@ -965,8 +961,8 @@ JSTokenStream::getTokenInternal() qc = c; while ((c = getChar()) != qc) { if (c == EOF) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); goto error; } @@ -1014,8 +1010,7 @@ JSTokenStream::getTokenInternal() bad_xml_char: default: - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_CHARACTER); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_CHARACTER); goto error; } /* NOTREACHED */ @@ -1071,11 +1066,8 @@ JSTokenStream::getTokenInternal() !(flags & TSF_KEYWORD_IS_NAME) && (kw = FindKeyword(tokenbuf.begin(), tokenbuf.length()))) { if (kw->tokentype == TOK_RESERVED) { - if (!js_ReportCompileErrorNumber(cx, this, NULL, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_RESERVED_ID, - kw->chars)) { + if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_RESERVED_ID, kw->chars)) { goto error; } } else if (kw->version <= JSVERSION_NUMBER(cx)) { @@ -1123,7 +1115,7 @@ JSTokenStream::getTokenInternal() if (radix == 8) { /* Octal integer literals are not permitted in strict mode code. */ - if (!js_ReportStrictModeError(cx, this, NULL, NULL, JSMSG_DEPRECATED_OCTAL)) + if (!ReportStrictModeError(cx, this, NULL, NULL, JSMSG_DEPRECATED_OCTAL)) goto error; /* @@ -1132,9 +1124,8 @@ JSTokenStream::getTokenInternal() * might not always be so permissive, so we warn about it. */ if (c >= '8') { - if (!js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING, - JSMSG_BAD_OCTAL, - c == '8' ? "08" : "09")) { + if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING, + JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) { goto error; } radix = 10; @@ -1164,8 +1155,8 @@ JSTokenStream::getTokenInternal() c = getChar(); } if (!JS7_ISDEC(c)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_MISSING_EXPONENT); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_MISSING_EXPONENT); goto error; } do { @@ -1177,8 +1168,7 @@ JSTokenStream::getTokenInternal() } if (JS_ISIDSTART(c)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_IDSTART_AFTER_NUMBER); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_IDSTART_AFTER_NUMBER); goto error; } @@ -1189,15 +1179,13 @@ JSTokenStream::getTokenInternal() if (radix == 10) { if (!js_strtod(cx, tokenbuf.begin(), tokenbuf.end(), &endptr, &dval)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_OUT_OF_MEMORY); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); goto error; } } else { if (!js_strtointeger(cx, tokenbuf.begin(), tokenbuf.end(), &endptr, radix, &dval)) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_OUT_OF_MEMORY); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); goto error; } } @@ -1212,8 +1200,8 @@ JSTokenStream::getTokenInternal() while ((c = getChar()) != qc) { if (c == '\n' || c == EOF) { ungetChar(c); - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_STRING); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_STRING); goto error; } if (c == '\\') { @@ -1232,8 +1220,8 @@ JSTokenStream::getTokenInternal() c = peekChar(); /* Strict mode code allows only \0, then a non-digit. */ if (val != 0 || JS7_ISDEC(c)) { - if (!js_ReportStrictModeError(cx, this, NULL, NULL, - JSMSG_DEPRECATED_OCTAL)) { + if (!ReportStrictModeError(cx, this, NULL, NULL, + JSMSG_DEPRECATED_OCTAL)) { goto error; } } @@ -1526,8 +1514,7 @@ JSTokenStream::getTokenInternal() goto out; bad_xml_markup: - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); goto error; } #endif /* JS_HAS_XML_SUPPORT */ @@ -1647,7 +1634,7 @@ JSTokenStream::getTokenInternal() continue; } ungetChar(c); - cursor = (cursor - 1) & NTOKENS_MASK; + cursor = (cursor - 1) & ntokensMask; goto retry; } @@ -1658,8 +1645,8 @@ JSTokenStream::getTokenInternal() /* Ignore all characters until comment close. */ } if (c == EOF) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_COMMENT); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_COMMENT); goto error; } if ((flags & TSF_NEWLINES) && linenoBefore != lineno) { @@ -1667,7 +1654,7 @@ JSTokenStream::getTokenInternal() tt = TOK_EOL; goto eol_out; } - cursor = (cursor - 1) & NTOKENS_MASK; + cursor = (cursor - 1) & ntokensMask; goto retry; } @@ -1680,8 +1667,8 @@ JSTokenStream::getTokenInternal() c = getChar(); if (c == '\n' || c == EOF) { ungetChar(c); - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_UNTERMINATED_REGEXP); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, + JSMSG_UNTERMINATED_REGEXP); goto error; } if (c == '\\') { @@ -1718,8 +1705,8 @@ JSTokenStream::getTokenInternal() char buf[2] = { '\0' }; tp->pos.begin.index += length + 1; buf[0] = (char)c; - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_BAD_REGEXP_FLAG, buf); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_REGEXP_FLAG, + buf); (void) getChar(); goto error; } @@ -1787,8 +1774,7 @@ JSTokenStream::getTokenInternal() break; n = 10 * n + JS7_UNDEC(c); if (n >= UINT16_LIMIT) { - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_SHARPVAR_TOO_BIG); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_SHARPVAR_TOO_BIG); goto error; } } @@ -1797,11 +1783,8 @@ JSTokenStream::getTokenInternal() (c == '=' || c == '#')) { char buf[20]; JS_snprintf(buf, sizeof buf, "#%u%c", n, c); - if (!js_ReportCompileErrorNumber(cx, this, NULL, - JSREPORT_WARNING | - JSREPORT_STRICT, - JSMSG_DEPRECATED_USAGE, - buf)) { + if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DEPRECATED_USAGE, buf)) { goto error; } } @@ -1820,8 +1803,7 @@ JSTokenStream::getTokenInternal() #endif default: - js_ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, - JSMSG_ILLEGAL_CHARACTER); + ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_ILLEGAL_CHARACTER); goto error; } diff --git a/js/src/jsscan.h b/js/src/jsscan.h index 815ec528f64f..84c6ad3d5d90 100644 --- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -50,14 +50,14 @@ #include "jspubtd.h" #include "jsvector.h" -JS_BEGIN_EXTERN_C - #define JS_KEYWORD(keyword, type, op, version) \ extern const char js_##keyword##_str[]; #include "jskeyword.tbl" #undef JS_KEYWORD -typedef enum JSTokenType { +namespace js { + +enum TokenKind { TOK_ERROR = -1, /* well-known as the only code < EOF */ TOK_EOF = 0, /* end of file */ TOK_EOL = 1, /* end of line */ @@ -144,87 +144,91 @@ typedef enum JSTokenType { tree full of uses of those names */ TOK_RESERVED, /* reserved keywords */ TOK_LIMIT /* domain size */ -} JSTokenType; +}; -#define IS_PRIMARY_TOKEN(tt) \ - ((uintN)((tt) - TOK_NAME) <= (uintN)(TOK_PRIMARY - TOK_NAME)) +static inline bool TokenKindIsXML(TokenKind tt) +{ + return tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME; +} -#define TOKEN_TYPE_IS_XML(tt) \ - ((tt) == TOK_AT || (tt) == TOK_DBLCOLON || (tt) == TOK_ANYNAME) - -#define TREE_TYPE_IS_XML(tt) \ - ((tt) == TOK_XMLCOMMENT || (tt) == TOK_XMLCDATA || (tt) == TOK_XMLPI || \ - (tt) == TOK_XMLELEM || (tt) == TOK_XMLLIST) +static inline bool TreeTypeIsXML(TokenKind tt) +{ + return tt == TOK_XMLCOMMENT || tt == TOK_XMLCDATA || tt == TOK_XMLPI || + tt == TOK_XMLELEM || tt == TOK_XMLLIST; +} +static inline bool TokenKindIsDecl(TokenKind tt) +{ #if JS_HAS_BLOCK_SCOPE -# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR || (tt) == TOK_LET) + return tt == TOK_VAR || tt == TOK_LET; #else -# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR) + return tt == TOK_VAR; #endif +} -struct JSTokenPtr { +struct TokenPtr { uint32 index; /* index of char in physical line */ uint32 lineno; /* physical line number */ - bool operator==(const JSTokenPtr& bptr) { + bool operator==(const TokenPtr& bptr) { return index == bptr.index && lineno == bptr.lineno; } - bool operator!=(const JSTokenPtr& bptr) { + bool operator!=(const TokenPtr& bptr) { return index != bptr.index || lineno != bptr.lineno; } - bool operator <(const JSTokenPtr& bptr) { + bool operator <(const TokenPtr& bptr) { return lineno < bptr.lineno || (lineno == bptr.lineno && index < bptr.index); } - bool operator <=(const JSTokenPtr& bptr) { + bool operator <=(const TokenPtr& bptr) { return lineno < bptr.lineno || (lineno == bptr.lineno && index <= bptr.index); } - bool operator >(const JSTokenPtr& bptr) { + bool operator >(const TokenPtr& bptr) { return !(*this <= bptr); } - bool operator >=(const JSTokenPtr& bptr) { + bool operator >=(const TokenPtr& bptr) { return !(*this < bptr); } }; -struct JSTokenPos { - JSTokenPtr begin; /* first character and line of token */ - JSTokenPtr end; /* index 1 past last char, last line */ +struct TokenPos { + TokenPtr begin; /* first character and line of token */ + TokenPtr end; /* index 1 past last char, last line */ - bool operator==(const JSTokenPos& bpos) { + bool operator==(const TokenPos& bpos) { return begin == bpos.begin && end == bpos.end; } - bool operator!=(const JSTokenPos& bpos) { + bool operator!=(const TokenPos& bpos) { return begin != bpos.begin || end != bpos.end; } - bool operator <(const JSTokenPos& bpos) { + bool operator <(const TokenPos& bpos) { return begin < bpos.begin; } - bool operator <=(const JSTokenPos& bpos) { + bool operator <=(const TokenPos& bpos) { return begin <= bpos.begin; } - bool operator >(const JSTokenPos& bpos) { + bool operator >(const TokenPos& bpos) { return !(*this <= bpos); } - bool operator >=(const JSTokenPos& bpos) { + bool operator >=(const TokenPos& bpos) { return !(*this < bpos); } }; -struct JSToken { - JSTokenType type; /* char value or above enumerator */ - JSTokenPos pos; /* token position in file */ +struct Token { + TokenKind type; /* char value or above enumerator */ + TokenPos pos; /* token position in file */ jschar *ptr; /* beginning of token in line buffer */ union { struct { /* name or string literal */ @@ -241,19 +245,7 @@ struct JSToken { } u; }; -#define t_op u.s.op -#define t_reflags u.reflags -#define t_atom u.s.atom -#define t_atom2 u.p.atom2 -#define t_dval u.dval - -#define JS_LINE_LIMIT 256 /* logical line buffer size limit -- - physical line length is unlimited */ -#define NTOKENS 4 /* 1 current + 2 lookahead, rounded */ -#define NTOKENS_MASK (NTOKENS-1) /* to power of 2 to avoid divmod by 3 */ - - -enum JSTokenStreamFlags +enum TokenStreamFlags { TSF_ERROR = 0x01, /* fatal error while compiling */ TSF_EOF = 0x02, /* hit end of file */ @@ -298,12 +290,24 @@ enum JSTokenStreamFlags TSF_STRICT_MODE_CODE = 0x8000 }; -class JSTokenStream +#define t_op u.s.op +#define t_reflags u.reflags +#define t_atom u.s.atom +#define t_atom2 u.p.atom2 +#define t_dval u.dval + +const size_t LINE_LIMIT = 256; /* logical line buffer size limit + -- physical line length is unlimited */ + +class TokenStream { + static const size_t ntokens = 4; /* 1 current + 2 lookahead, rounded + to power of 2 to avoid divmod by 3 */ + static const uintN ntokensMask = ntokens - 1; public: /* - * To construct a JSTokenStream, first call the constructor, which is - * infallible, then call |init|, which can fail. To destroy a JSTokenStream, + * To construct a TokenStream, first call the constructor, which is + * infallible, then call |init|, which can fail. To destroy a TokenStream, * first call |close| then call the destructor. If |init| fails, do not call * |close|. * @@ -311,7 +315,7 @@ class JSTokenStream * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE * after calling |close|. */ - JSTokenStream(JSContext *); + TokenStream(JSContext *); /* * Create a new token stream, either from an input buffer or from a file. @@ -319,14 +323,14 @@ class JSTokenStream */ bool init(const jschar *base, size_t length, FILE *fp, const char *filename, uintN lineno); void close(); - ~JSTokenStream() {} + ~TokenStream() {} /* Accessors. */ JSContext *getContext() const { return cx; } - bool onCurrentLine(const JSTokenPos &pos) const { return lineno == pos.end.lineno; } - const JSToken ¤tToken() const { return tokens[cursor]; } - const JSToken &getTokenAt(size_t index) const { - JS_ASSERT(index < NTOKENS); + bool onCurrentLine(const TokenPos &pos) const { return lineno == pos.end.lineno; } + const Token ¤tToken() const { return tokens[cursor]; } + const Token &getTokenAt(size_t index) const { + JS_ASSERT(index < ntokens); return tokens[index]; } const JSCharBuffer &getTokenbuf() const { return tokenbuf; } @@ -334,16 +338,16 @@ class JSTokenStream uintN getLineno() const { return lineno; } /* Mutators. */ - JSToken *mutableCurrentToken() { return &tokens[cursor]; } + Token *mutableCurrentToken() { return &tokens[cursor]; } bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); - JSTokenType getToken() { + TokenKind getToken() { /* Check for a pushed-back token resulting from mismatching lookahead. */ while (lookahead != 0) { JS_ASSERT(!(flags & TSF_XMLTEXTMODE)); lookahead--; - cursor = (cursor + 1) & NTOKENS_MASK; - JSTokenType tt = currentToken().type; + cursor = (cursor + 1) & ntokensMask; + TokenKind tt = currentToken().type; if (tt != TOK_EOL || (flags & TSF_NEWLINES)) return tt; } @@ -355,36 +359,36 @@ class JSTokenStream return getTokenInternal(); } - JSToken *getMutableTokenAt(size_t index) { - JS_ASSERT(index < NTOKENS); + Token *getMutableTokenAt(size_t index) { + JS_ASSERT(index < ntokens); return &tokens[index]; } void ungetToken() { - JS_ASSERT(lookahead < NTOKENS_MASK); + JS_ASSERT(lookahead < ntokensMask); lookahead++; - cursor = (cursor - 1) & NTOKENS_MASK; + cursor = (cursor - 1) & ntokensMask; } - JSTokenType peekToken() { + TokenKind peekToken() { if (lookahead != 0) { - return tokens[(cursor + lookahead) & NTOKENS_MASK].type; + return tokens[(cursor + lookahead) & ntokensMask].type; } - JSTokenType tt = getToken(); + TokenKind tt = getToken(); ungetToken(); return tt; } - JSTokenType peekTokenSameLine() { + TokenKind peekTokenSameLine() { if (!onCurrentLine(currentToken().pos)) return TOK_EOL; flags |= TSF_NEWLINES; - JSTokenType tt = peekToken(); + TokenKind tt = peekToken(); flags &= ~TSF_NEWLINES; return tt; } - JSBool matchToken(JSTokenType tt) { + JSBool matchToken(TokenKind tt) { if (getToken() == tt) return JS_TRUE; ungetToken(); @@ -392,16 +396,16 @@ class JSTokenStream } private: - typedef struct JSTokenBuf { + typedef struct TokenBuf { jschar *base; /* base of line or stream buffer */ jschar *limit; /* limit for quick bounds check */ jschar *ptr; /* next char to get, or slot to use */ - } JSTokenBuf; + } TokenBuf; - JSTokenType getTokenInternal(); /* doesn't check for pushback or error flag. */ + TokenKind getTokenInternal(); /* doesn't check for pushback or error flag. */ int32 getChar(); void ungetChar(int32 c); - JSToken *newToken(ptrdiff_t adjust); + Token *newToken(ptrdiff_t adjust); int32 getUnicodeEscape(); JSBool peekChars(intN n, jschar *cp); JSBool getXMLEntity(); @@ -426,7 +430,7 @@ class JSTokenStream } JSContext * const cx; - JSToken tokens[NTOKENS];/* circular token buffer */ + Token tokens[ntokens];/* circular token buffer */ uintN cursor; /* index of last parsed token */ uintN lookahead; /* count of lookahead tokens */ @@ -438,9 +442,9 @@ class JSTokenStream private: uint32 linelen; /* physical linebuf segment length */ uint32 linepos; /* linebuf offset in physical line */ - JSTokenBuf linebuf; /* line buffer for diagnostics */ + TokenBuf linebuf; /* line buffer for diagnostics */ - JSTokenBuf userbuf; /* user input buffer if !file */ + TokenBuf userbuf; /* user input buffer if !file */ const char *filename; /* input filename or null */ FILE *file; /* stdio stream if reading from file */ JSSourceHandler listener; /* callback for source; eg debugger */ @@ -451,12 +455,14 @@ class JSTokenStream JSCharBuffer tokenbuf; /* current token string buffer */ }; +} /* namespace js */ + /* Unicode separators that are treated as line terminators, in addition to \n, \r */ #define LINE_SEPARATOR 0x2028 #define PARA_SEPARATOR 0x2029 extern void -js_CloseTokenStream(JSContext *cx, JSTokenStream *ts); +js_CloseTokenStream(JSContext *cx, js::TokenStream *ts); extern JS_FRIEND_API(int) js_fgets(char *buf, int size, FILE *file); @@ -465,7 +471,7 @@ js_fgets(char *buf, int size, FILE *file); * If the given char array forms JavaScript keyword, return corresponding * token. Otherwise return TOK_EOF. */ -extern JSTokenType +extern js::TokenKind js_CheckKeyword(const jschar *chars, size_t length); /* @@ -481,54 +487,56 @@ typedef void (*JSMapKeywordFun)(const char *); extern JSBool js_IsIdentifier(JSString *str); +/* + * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error + * message have const jschar* type, not const char*. + */ +#define JSREPORT_UC 0x100 + +namespace js { + /* * Report a compile-time error by its number. Return true for a warning, false * for an error. When pn is not null, use it to report error's location. * Otherwise use ts, which must not be null. */ bool -js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, - uintN flags, uintN errorNumber, ...); +ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN flags, + uintN errorNumber, ...); /* * Report a condition that should elicit a warning with JSOPTION_STRICT, * or an error if ts or tc is handling strict mode code. This function - * defers to js_ReportCompileErrorNumber to do the real work. Either tc + * defers to ReportCompileErrorNumber to do the real work. Either tc * or ts may be NULL, if there is no tree context or token stream state * whose strictness should affect the report. * - * One could have js_ReportCompileErrorNumber recognize the + * One could have ReportCompileErrorNumber recognize the * JSREPORT_STRICT_MODE_ERROR flag instead of having a separate function * like this one. However, the strict mode code flag we need to test is * in the JSTreeContext structure for that code; we would have to change - * the ~120 js_ReportCompileErrorNumber calls to pass the additional + * the ~120 ReportCompileErrorNumber calls to pass the additional * argument, even though many of those sites would never use it. Using * ts's TSF_STRICT_MODE_CODE flag instead of tc's would be brittle: at some * points ts's flags don't correspond to those of the tc relevant to the * error. */ bool -js_ReportStrictModeError(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, - JSParseNode *pn, uintN errorNumber, ...); - -/* - * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error - * message have const jschar* type, not const char*. - */ -#define JSREPORT_UC 0x100 +ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, + uintN errorNumber, ...); /* * Look ahead one token and return its type. */ -static inline JSTokenType -js_PeekToken(JSContext *cx, JSTokenStream *ts) +static inline TokenKind +PeekToken(JSContext *cx, TokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->peekToken(); } -static inline JSTokenType -js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) +static inline TokenKind +PeekTokenSameLine(JSContext *cx, TokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->peekTokenSameLine(); @@ -537,8 +545,8 @@ js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts) /* * Get the next token from ts. */ -static inline JSTokenType -js_GetToken(JSContext *cx, JSTokenStream *ts) +static inline TokenKind +GetToken(JSContext *cx, TokenStream *ts) { JS_ASSERT(cx == ts->getContext()); return ts->getToken(); @@ -548,7 +556,7 @@ js_GetToken(JSContext *cx, JSTokenStream *ts) * Push back the last scanned token onto ts. */ static inline void -js_UngetToken(JSTokenStream *ts) +UngetToken(TokenStream *ts) { ts->ungetToken(); } @@ -557,12 +565,12 @@ js_UngetToken(JSTokenStream *ts) * Get the next token from ts if its type is tt. */ static inline JSBool -js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt) +MatchToken(JSContext *cx, TokenStream *ts, TokenKind tt) { JS_ASSERT(cx == ts->getContext()); return ts->matchToken(tt); } -JS_END_EXTERN_C +} /* namespace js */ #endif /* jsscan_h___ */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 5b54cf3e7925..8239ee78e9f1 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1012,8 +1012,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) } script->lineno = cg->firstLine; if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) { - js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, - JSMSG_NEED_DIET, "script"); + ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET, "script"); goto bad; } script->nslots = script->nfixed + cg->maxStackDepth; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 684b5c4b3597..e5aff106faa5 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -1268,11 +1268,10 @@ ParseNodeToQName(JSCompiler *jsc, JSParseNode *pn, } if (!uri) { - js_ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn, - JSREPORT_ERROR, - JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(jsc->context, - STRING_TO_JSVAL(prefix))); + ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn, + JSREPORT_ERROR, JSMSG_BAD_XML_NAMESPACE, + js_ValueToPrintableString(jsc->context, + STRING_TO_JSVAL(prefix))); return NULL; } @@ -1350,8 +1349,8 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, int stackDummy; if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, - JSMSG_OVER_RECURSED); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, + JSMSG_OVER_RECURSED); return NULL; } @@ -1489,11 +1488,10 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, /* Enforce "Well-formedness constraint: Unique Att Spec". */ for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { if (pn3->pn_atom == pn2->pn_atom) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, - JSREPORT_ERROR, - JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, + JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); goto fail; } } @@ -1600,11 +1598,10 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, attrjqn = attrj->name; if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) && js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, - JSREPORT_ERROR, - JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2, + JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, + js_ValueToPrintableString(cx, + ATOM_KEY(pn2->pn_atom))); goto fail; } } @@ -1641,11 +1638,10 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn, xml_class = JSXML_CLASS_COMMENT; } else if (pn->pn_type == TOK_XMLPI) { if (IS_XML(str)) { - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, - JSREPORT_ERROR, - JSMSG_RESERVED_ID, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(str))); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, + JSREPORT_ERROR, JSMSG_RESERVED_ID, + js_ValueToPrintableString(cx, + STRING_TO_JSVAL(str))); goto fail; } @@ -1690,8 +1686,7 @@ skip_child: #undef PN2X_SKIP_CHILD syntax: - js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, - JSMSG_BAD_XML_MARKUP); + ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); fail: js_LeaveLocalRootScope(cx); return NULL; From 497b913b9c43b6b2a15551e312cd82036faecba8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 19:47:02 -0700 Subject: [PATCH 094/213] Bug 507089 - TM/nanojit: prepare to add get/set methods for CallInfo::_argtypes. r=edwsmith. --HG-- extra : convert_revision : 55f02d7976752940a9f328d440fb6601ee2dc9f4 --- js/src/lirasm/LInsClasses.tbl | 2 +- js/src/lirasm/lirasm.cpp | 55 +++++++++++----------- js/src/nanojit/Assembler.cpp | 29 ------------ js/src/nanojit/LIR.cpp | 85 +++++++++++++++++++++++++--------- js/src/nanojit/LIR.h | 67 ++++++++++++--------------- js/src/nanojit/NativeARM.cpp | 40 ++++++++-------- js/src/nanojit/NativeARM.h | 4 +- js/src/nanojit/NativeMIPS.cpp | 35 ++++++-------- js/src/nanojit/NativeMIPS.h | 4 +- js/src/nanojit/NativePPC.cpp | 30 ++++++------ js/src/nanojit/NativePPC.h | 2 +- js/src/nanojit/NativeSparc.cpp | 14 +++--- js/src/nanojit/NativeX64.cpp | 41 +++++++++------- js/src/nanojit/NativeX64.h | 4 +- js/src/nanojit/Nativei386.cpp | 20 ++++---- js/src/nanojit/Nativei386.h | 14 +++--- 16 files changed, 225 insertions(+), 221 deletions(-) diff --git a/js/src/lirasm/LInsClasses.tbl b/js/src/lirasm/LInsClasses.tbl index 207dbe63a3e8..5ef5db6773f9 100644 --- a/js/src/lirasm/LInsClasses.tbl +++ b/js/src/lirasm/LInsClasses.tbl @@ -124,7 +124,7 @@ CL_64( LCALL_Q_Q2, 1) // 95% LIR_qcall CL_64( LCALL_Q_Q7, 1) // 96% LIR_qcall CL___( LCALL_F_F3, 1) // 97% LIR_fcall CL___( LCALL_F_F8, 1) // 98% LIR_fcall -CL_64( LCALL_N_IQF, 1) // 99% LIR_icall or LIR_qcall +CL_64( LCALL_V_IQF, 1) // 99% LIR_icall or LIR_qcall CL___( LLABEL, 1) //100% LIR_label diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index 84b2d19456f1..c1765cbe5ac3 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -154,12 +154,15 @@ enum ReturnType { #define FN(name, args) \ {#name, CI(name, args)} -const int I32 = nanojit::ARGSIZE_LO; +const ArgType I32 = nanojit::ARGTYPE_LO; #ifdef NANOJIT_64BIT -const int I64 = nanojit::ARGSIZE_Q; +const ArgType I64 = nanojit::ARGTYPE_Q; #endif -const int F64 = nanojit::ARGSIZE_F; -const int PTR = nanojit::ARGSIZE_P; +const ArgType F64 = nanojit::ARGTYPE_F; +const ArgType PTR = nanojit::ARGTYPE_P; +const ArgType WRD = nanojit::ARGTYPE_P; +const ArgType VOID = nanojit::ARGTYPE_V; + enum LirTokenType { NAME, NUMBER, PUNCT, NEWLINE @@ -342,8 +345,8 @@ private: void endFragment(); }; -// Meaning: arg 'm' of 'n' has size 'sz'. -static int argMask(int sz, int m, int n) +// Meaning: arg 'm' of 'n' has type 'ty'. +static int argMask(int ty, int m, int n) { // Order examples, from MSB to LSB: // - 3 args: 000 | 000 | 000 | 000 | 000 | arg1| arg2| arg3| ret @@ -351,13 +354,13 @@ static int argMask(int sz, int m, int n) // If the mask encoding reversed the arg order the 'n' parameter wouldn't // be necessary, as argN would always be in the same place in the // bitfield. - return sz << ((1 + n - m) * ARGSIZE_SHIFT); + return ty << ((1 + n - m) * ARGTYPE_SHIFT); } -// Return value has size 'sz'. -static int retMask(int sz) +// Return value has type 'ty'. +static int retMask(int ty) { - return sz; + return ty; } // 'sin' is overloaded on some platforms, so taking its address @@ -371,8 +374,8 @@ double sinFn(double d) { Function functions[] = { FN(puts, argMask(PTR, 1, 1) | retMask(I32)), FN(sin, argMask(F64, 1, 1) | retMask(F64)), - FN(malloc, argMask(PTR, 1, 1) | retMask(PTR)), - FN(free, argMask(PTR, 1, 1) | retMask(I32)) + FN(malloc, argMask(WRD, 1, 1) | retMask(PTR)), + FN(free, argMask(PTR, 1, 1) | retMask(VOID)) }; template out @@ -694,28 +697,28 @@ FragmentAssembler::assemble_call(const string &op) ci->_abi = _abi; - ci->_argtypes = 0; + ci->_typesig = 0; size_t argc = mTokens.size(); for (size_t i = 0; i < argc; ++i) { args[i] = ref(mTokens[mTokens.size() - (i+1)]); - if (args[i]->isF64()) ty = ARGSIZE_F; + if (args[i]->isF64()) ty = ARGTYPE_F; #ifdef NANOJIT_64BIT - else if (args[i]->isI64()) ty = ARGSIZE_Q; + else if (args[i]->isI64()) ty = ARGTYPE_Q; #endif - else ty = ARGSIZE_I; + else ty = ARGTYPE_I; // Nb: i+1 because argMask() uses 1-based arg counting. - ci->_argtypes |= argMask(ty, i+1, argc); + ci->_typesig |= argMask(ty, i+1, argc); } // Select return type from opcode. ty = 0; - if (mOpcode == LIR_icall) ty = ARGSIZE_LO; - else if (mOpcode == LIR_fcall) ty = ARGSIZE_F; + if (mOpcode == LIR_icall) ty = ARGTYPE_LO; + else if (mOpcode == LIR_fcall) ty = ARGTYPE_F; #ifdef NANOJIT_64BIT - else if (mOpcode == LIR_qcall) ty = ARGSIZE_Q; + else if (mOpcode == LIR_qcall) ty = ARGTYPE_Q; #endif else nyi("callh"); - ci->_argtypes |= retMask(ty); + ci->_typesig |= retMask(ty); } return mLir->insCall(ci, args); @@ -1239,7 +1242,7 @@ static double f_F_F8(double a, double b, double c, double d, } #ifdef NANOJIT_64BIT -static void f_N_IQF(int32_t, uint64_t, double) +static void f_V_IQF(int32_t, uint64_t, double) { return; // no need to do anything } @@ -1287,10 +1290,10 @@ const CallInfo ci_F_F8 = CI(f_F_F8, argMask(F64, 1, 8) | retMask(F64)); #ifdef NANOJIT_64BIT -const CallInfo ci_N_IQF = CI(f_N_IQF, argMask(I32, 1, 3) | +const CallInfo ci_V_IQF = CI(f_V_IQF, argMask(I32, 1, 3) | argMask(I64, 2, 3) | argMask(F64, 3, 3) | - retMask(ARGSIZE_NONE)); + retMask(ARGTYPE_V)); #endif // Generate a random block containing nIns instructions, plus a few more @@ -1920,11 +1923,11 @@ FragmentAssembler::assembleRandomFragment(int nIns) break; #ifdef NANOJIT_64BIT - case LCALL_N_IQF: + case LCALL_V_IQF: if (!Is.empty() && !Qs.empty() && !Fs.empty()) { // Nb: args[] holds the args in reverse order... sigh. LIns* args[3] = { rndPick(Fs), rndPick(Qs), rndPick(Is) }; - ins = mLir->insCall(&ci_N_IQF, args); + ins = mLir->insCall(&ci_V_IQF, args); n++; } break; diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index 7c06e19fe924..6b7e30a19d7a 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -2385,35 +2385,6 @@ namespace nanojit } #endif // NJ_VERBOSE - uint32_t CallInfo::_count_args(uint32_t mask) const - { - uint32_t argc = 0; - uint32_t argt = _argtypes; - for (uint32_t i = 0; i < MAXARGS; ++i) { - argt >>= ARGSIZE_SHIFT; - if (!argt) - break; - argc += (argt & mask) != 0; - } - return argc; - } - - uint32_t CallInfo::get_sizes(ArgSize* sizes) const - { - uint32_t argt = _argtypes; - uint32_t argc = 0; - for (uint32_t i = 0; i < MAXARGS; i++) { - argt >>= ARGSIZE_SHIFT; - ArgSize a = ArgSize(argt & ARGSIZE_MASK_ANY); - if (a != ARGSIZE_NONE) { - sizes[argc++] = a; - } else { - break; - } - } - return argc; - } - void LabelStateMap::add(LIns *label, NIns *addr, RegAlloc ®s) { LabelState *st = new (alloc) LabelState(addr, regs); labels.put(label, st); diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index a646c68fc9e8..0e3ad7a2e048 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -81,6 +81,46 @@ namespace nanojit #endif /* NANOJIT_VERBOSE */ + uint32_t CallInfo::count_args() const + { + uint32_t argc = 0; + uint32_t argt = _typesig; + argt >>= ARGTYPE_SHIFT; // remove retType + while (argt) { + argc++; + argt >>= ARGTYPE_SHIFT; + } + return argc; + } + + uint32_t CallInfo::count_int32_args() const + { + uint32_t argc = 0; + uint32_t argt = _typesig; + argt >>= ARGTYPE_SHIFT; // remove retType + while (argt) { + ArgType a = ArgType(argt & ARGTYPE_MASK); + if (a == ARGTYPE_I || a == ARGTYPE_U) + argc++; + argt >>= ARGTYPE_SHIFT; + } + return argc; + } + + uint32_t CallInfo::getArgTypes(ArgType* argTypes) const + { + uint32_t argc = 0; + uint32_t argt = _typesig; + argt >>= ARGTYPE_SHIFT; // remove retType + while (argt) { + ArgType a = ArgType(argt & ARGTYPE_MASK); + argTypes[argc] = a; + argc++; + argt >>= ARGTYPE_SHIFT; + } + return argc; + } + // implementation #ifdef NJ_VERBOSE void ReverseLister::finish() @@ -2324,11 +2364,11 @@ namespace nanojit static int32_t FASTCALL fle(double a, double b) { return a <= b; } static int32_t FASTCALL fge(double a, double b) { return a >= b; } - #define SIG_F_I (ARGSIZE_F | ARGSIZE_I << ARGSIZE_SHIFT*1) - #define SIG_F_U (ARGSIZE_F | ARGSIZE_U << ARGSIZE_SHIFT*1) - #define SIG_F_F (ARGSIZE_F | ARGSIZE_F << ARGSIZE_SHIFT*1) - #define SIG_F_FF (ARGSIZE_F | ARGSIZE_F << ARGSIZE_SHIFT*1 | ARGSIZE_F << ARGSIZE_SHIFT*2) - #define SIG_B_FF (ARGSIZE_B | ARGSIZE_F << ARGSIZE_SHIFT*1 | ARGSIZE_F << ARGSIZE_SHIFT*2) + #define SIG_F_I (ARGTYPE_F | ARGTYPE_I << ARGTYPE_SHIFT*1) + #define SIG_F_U (ARGTYPE_F | ARGTYPE_U << ARGTYPE_SHIFT*1) + #define SIG_F_F (ARGTYPE_F | ARGTYPE_F << ARGTYPE_SHIFT*1) + #define SIG_F_FF (ARGTYPE_F | ARGTYPE_F << ARGTYPE_SHIFT*1 | ARGTYPE_F << ARGTYPE_SHIFT*2) + #define SIG_B_FF (ARGTYPE_B | ARGTYPE_F << ARGTYPE_SHIFT*1 | ARGTYPE_F << ARGTYPE_SHIFT*2) #define SF_CALLINFO(name, typesig) \ static const CallInfo name##_ci = \ @@ -2418,14 +2458,13 @@ namespace nanojit } LIns* SoftFloatFilter::insCall(const CallInfo *ci, LInsp args[]) { - uint32_t argt = ci->_argtypes; - - for (uint32_t i = 0, argsizes = argt >> ARGSIZE_SHIFT; argsizes != 0; i++, argsizes >>= ARGSIZE_SHIFT) + uint32_t nArgs = ci->count_args(); + for (uint32_t i = 0; i < nArgs; i++) args[i] = split(args[i]); - if ((argt & ARGSIZE_MASK_ANY) == ARGSIZE_F) { - // this function returns a double as two 32bit values, so replace - // call with qjoin(qhi(call), call) + if (ci->returnType() == ARGTYPE_F) { + // This function returns a double as two 32bit values, so replace + // call with qjoin(qhi(call), call). return split(ci, args); } return out->insCall(ci, args); @@ -2876,8 +2915,8 @@ namespace nanojit LIns* ValidateWriter::insCall(const CallInfo *ci, LIns* args0[]) { - ArgSize sizes[MAXARGS]; - uint32_t nArgs = ci->get_sizes(sizes); + ArgType argTypes[MAXARGS]; + uint32_t nArgs = ci->getArgTypes(argTypes); LTy formals[MAXARGS]; LIns* args[MAXARGS]; // in left-to-right order, unlike args0[] @@ -2890,20 +2929,20 @@ namespace nanojit errorAccSetShould(lirNames[op], ci->_storeAccSet, "not contain bits that aren't in ACC_STORE_ANY"); - // This loop iterates over the args from right-to-left (because - // arg() and get_sizes() use right-to-left order), but puts the - // results into formals[] and args[] in left-to-right order so - // that arg numbers in error messages make sense to the user. + // This loop iterates over the args from right-to-left (because arg() + // and getArgTypes() use right-to-left order), but puts the results + // into formals[] and args[] in left-to-right order so that arg + // numbers in error messages make sense to the user. for (uint32_t i = 0; i < nArgs; i++) { uint32_t i2 = nArgs - i - 1; // converts right-to-left to left-to-right - switch (sizes[i]) { - case ARGSIZE_I: - case ARGSIZE_U: formals[i2] = LTy_I32; break; + switch (argTypes[i]) { + case ARGTYPE_I: + case ARGTYPE_U: formals[i2] = LTy_I32; break; #ifdef NANOJIT_64BIT - case ARGSIZE_Q: formals[i2] = LTy_I64; break; + case ARGTYPE_Q: formals[i2] = LTy_I64; break; #endif - case ARGSIZE_F: formals[i2] = LTy_F64; break; - default: NanoAssert(0); formals[i2] = LTy_Void; break; + case ARGTYPE_F: formals[i2] = LTy_F64; break; + default: NanoAssertMsgf(0, "%d %s\n", argTypes[i],ci->_name); formals[i2] = LTy_Void; break; } args[i2] = args0[i]; } diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 6be7f26f7f44..783afeb79ff9 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -146,25 +146,26 @@ namespace nanojit ABI_CDECL }; - enum ArgSize { - ARGSIZE_NONE = 0, - ARGSIZE_F = 1, // double (64bit) - ARGSIZE_I = 2, // int32_t + // All values must fit into three bits. See CallInfo for details. + enum ArgType { + ARGTYPE_V = 0, // void + ARGTYPE_F = 1, // double (64bit) + ARGTYPE_I = 2, // int32_t + ARGTYPE_U = 3, // uint32_t #ifdef NANOJIT_64BIT - ARGSIZE_Q = 3, // uint64_t + ARGTYPE_Q = 4, // uint64_t #endif - ARGSIZE_U = 6, // uint32_t - ARGSIZE_MASK_ANY = 7, - ARGSIZE_MASK_INT = 2, - ARGSIZE_SHIFT = 3, // aliases - ARGSIZE_P = PTR_SIZE(ARGSIZE_I, ARGSIZE_Q), // pointer - ARGSIZE_LO = ARGSIZE_I, // int32_t - ARGSIZE_B = ARGSIZE_I, // bool - ARGSIZE_V = ARGSIZE_NONE // void + ARGTYPE_P = PTR_SIZE(ARGTYPE_I, ARGTYPE_Q), // pointer + ARGTYPE_LO = ARGTYPE_I, // int32_t + ARGTYPE_B = ARGTYPE_I // bool }; + // In _typesig, each entry is three bits. + static const int ARGTYPE_SHIFT = 3; + static const int ARGTYPE_MASK = 0x7; + enum IndirectCall { CALL_INDIRECT = 0 }; @@ -290,38 +291,28 @@ namespace nanojit struct CallInfo { + private: + + public: uintptr_t _address; - uint32_t _argtypes:27; // 9 3-bit fields indicating arg type, by ARGSIZE above (including ret type): a1 a2 a3 a4 a5 ret + uint32_t _typesig:27; // 9 3-bit fields indicating arg type, by ARGTYPE above (including ret type): a1 a2 a3 a4 a5 ret AbiKind _abi:3; uint8_t _isPure:1; // _isPure=1 means no side-effects, result only depends on args AccSet _storeAccSet; // access regions stored by the function verbose_only ( const char* _name; ) - uint32_t _count_args(uint32_t mask) const; + uint32_t count_args() const; + uint32_t count_int32_args() const; // Nb: uses right-to-left order, eg. sizes[0] is the size of the right-most arg. - uint32_t get_sizes(ArgSize* sizes) const; + uint32_t getArgTypes(ArgType* types) const; - inline ArgSize returnType() const { - return ArgSize(_argtypes & ARGSIZE_MASK_ANY); - } - - // Note that this indexes arguments *backwards*, that is to - // get the Nth arg, you have to ask for index (numargs - N). - // See mozilla bug 525815 for fixing this. - inline ArgSize argType(uint32_t arg) const { - return ArgSize((_argtypes >> (ARGSIZE_SHIFT * (arg+1))) & ARGSIZE_MASK_ANY); + inline ArgType returnType() const { + return ArgType(_typesig & ARGTYPE_MASK); } inline bool isIndirect() const { return _address < 256; } - inline uint32_t count_args() const { - return _count_args(ARGSIZE_MASK_ANY); - } - inline uint32_t count_iargs() const { - return _count_args(ARGSIZE_MASK_INT); - } - // fargs = args - iargs }; /* @@ -408,14 +399,14 @@ namespace nanojit inline LOpcode getCallOpcode(const CallInfo* ci) { LOpcode op = LIR_pcall; switch (ci->returnType()) { - case ARGSIZE_NONE: op = LIR_pcall; break; - case ARGSIZE_I: - case ARGSIZE_U: op = LIR_icall; break; - case ARGSIZE_F: op = LIR_fcall; break; + case ARGTYPE_V: op = LIR_pcall; break; + case ARGTYPE_I: + case ARGTYPE_U: op = LIR_icall; break; + case ARGTYPE_F: op = LIR_fcall; break; #ifdef NANOJIT_64BIT - case ARGSIZE_Q: op = LIR_qcall; break; + case ARGTYPE_Q: op = LIR_qcall; break; #endif - default: NanoAssert(0); break; + default: NanoAssert(0); break; } return op; } diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index 2e26ce4f0bc7..482b9a8b7fac 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -597,19 +597,19 @@ Assembler::genEpilogue() * alignment. */ void -Assembler::asm_arg(ArgSize sz, LInsp arg, Register& r, int& stkd) +Assembler::asm_arg(ArgType ty, LInsp arg, Register& r, int& stkd) { // The stack pointer must always be at least aligned to 4 bytes. NanoAssert((stkd & 3) == 0); - if (sz == ARGSIZE_F) { + if (ty == ARGTYPE_F) { // This task is fairly complex and so is delegated to asm_arg_64. asm_arg_64(arg, r, stkd); } else { - NanoAssert(sz == ARGSIZE_I || sz == ARGSIZE_U); + NanoAssert(ty == ARGTYPE_I || ty == ARGTYPE_U); // pre-assign registers R0-R3 for arguments (if they fit) if (r < R4) { - asm_regarg(sz, arg, r); + asm_regarg(ty, arg, r); r = nextreg(r); } else { asm_stkarg(arg, stkd); @@ -620,7 +620,7 @@ Assembler::asm_arg(ArgSize sz, LInsp arg, Register& r, int& stkd) // Encode a 64-bit floating-point argument using the appropriate ABI. // This function operates in the same way as asm_arg, except that it will only -// handle arguments where (ArgSize)sz == ARGSIZE_F. +// handle arguments where (ArgType)ty == ARGTYPE_F. void Assembler::asm_arg_64(LInsp arg, Register& r, int& stkd) { @@ -665,8 +665,8 @@ Assembler::asm_arg_64(LInsp arg, Register& r, int& stkd) if (_config.arm_vfp) { FMRRD(ra, rb, fp_reg); } else { - asm_regarg(ARGSIZE_LO, arg->oprnd1(), ra); - asm_regarg(ARGSIZE_LO, arg->oprnd2(), rb); + asm_regarg(ARGTYPE_LO, arg->oprnd1(), ra); + asm_regarg(ARGTYPE_LO, arg->oprnd2(), rb); } #ifndef NJ_ARM_EABI @@ -699,7 +699,7 @@ Assembler::asm_arg_64(LInsp arg, Register& r, int& stkd) // Without VFP, we can simply use asm_regarg and asm_stkarg to // encode the two 32-bit words as we don't need to load from a VFP // register. - asm_regarg(ARGSIZE_LO, arg->oprnd1(), ra); + asm_regarg(ARGTYPE_LO, arg->oprnd1(), ra); asm_stkarg(arg->oprnd2(), 0); stkd += 4; } @@ -720,10 +720,10 @@ Assembler::asm_arg_64(LInsp arg, Register& r, int& stkd) } void -Assembler::asm_regarg(ArgSize sz, LInsp p, Register r) +Assembler::asm_regarg(ArgType ty, LInsp p, Register r) { NanoAssert(deprecated_isKnownReg(r)); - if (sz & ARGSIZE_MASK_INT) + if (ty == ARGTYPE_I || ty == ARGTYPE_U) { // arg goes in specific register if (p->isconst()) { @@ -752,7 +752,7 @@ Assembler::asm_regarg(ArgSize sz, LInsp p, Register r) } else { - NanoAssert(sz == ARGSIZE_F); + NanoAssert(ty == ARGTYPE_F); // fpu argument in register - should never happen since FPU // args are converted to two 32-bit ints on ARM NanoAssert(false); @@ -848,10 +848,10 @@ Assembler::asm_call(LInsp ins) evictScratchRegsExcept(0); - const CallInfo* call = ins->callInfo(); - ArgSize sizes[MAXARGS]; - uint32_t argc = call->get_sizes(sizes); - bool indirect = call->isIndirect(); + const CallInfo* ci = ins->callInfo(); + ArgType argTypes[MAXARGS]; + uint32_t argc = ci->getArgTypes(argTypes); + bool indirect = ci->isIndirect(); // If we aren't using VFP, assert that the LIR operation is an integer // function call. @@ -863,11 +863,11 @@ Assembler::asm_call(LInsp ins) // for floating point calls, but not for integer calls. if (_config.arm_vfp && ins->isUsed()) { // Determine the size (and type) of the instruction result. - ArgSize rsize = (ArgSize)(call->_argtypes & ARGSIZE_MASK_ANY); + ArgType rsize = (ArgType)(ci->_typesig & ARGTYPE_MASK_ANY); // If the result size is a floating-point value, treat the result // specially, as described previously. - if (rsize == ARGSIZE_F) { + if (ci->returnType() == ARGTYPE_F) { Register rr = ins->deprecated_getReg(); NanoAssert(ins->opcode() == LIR_fcall); @@ -902,7 +902,7 @@ Assembler::asm_call(LInsp ins) // interlock in the "long" branch sequence by manually loading the // target address into LR ourselves before setting up the parameters // in other registers. - BranchWithLink((NIns*)call->_address); + BranchWithLink((NIns*)ci->_address); } else { // Indirect call: we assign the address arg to LR since it's not // used for regular arguments, and is otherwise scratch since it's @@ -917,7 +917,7 @@ Assembler::asm_call(LInsp ins) } else { BLX(LR); } - asm_regarg(ARGSIZE_LO, ins->arg(--argc), LR); + asm_regarg(ARGTYPE_LO, ins->arg(--argc), LR); } // Encode the arguments, starting at R0 and with an empty argument stack. @@ -930,7 +930,7 @@ Assembler::asm_call(LInsp ins) // in reverse order. uint32_t i = argc; while(i--) { - asm_arg(sizes[i], ins->arg(i), r, stkd); + asm_arg(argTypes[i], ins->arg(i), r, stkd); } if (stkd > max_out_args) { diff --git a/js/src/nanojit/NativeARM.h b/js/src/nanojit/NativeARM.h index b490b1688a18..b00e60119f8d 100644 --- a/js/src/nanojit/NativeARM.h +++ b/js/src/nanojit/NativeARM.h @@ -220,14 +220,14 @@ verbose_only( extern const char* shiftNames[]; ) void nativePageReset(); \ void nativePageSetup(); \ void asm_immf_nochk(Register, int32_t, int32_t); \ - void asm_regarg(ArgSize, LInsp, Register); \ + void asm_regarg(ArgType, LInsp, Register); \ void asm_stkarg(LInsp p, int stkd); \ void asm_cmpi(Register, int32_t imm); \ void asm_ldr_chk(Register d, Register b, int32_t off, bool chk); \ void asm_cmp(LIns *cond); \ void asm_fcmp(LIns *cond); \ void asm_ld_imm(Register d, int32_t imm, bool chk = true); \ - void asm_arg(ArgSize sz, LInsp arg, Register& r, int& stkd); \ + void asm_arg(ArgType ty, LInsp arg, Register& r, int& stkd); \ void asm_arg_64(LInsp arg, Register& r, int& stkd); \ void asm_add_imm(Register rd, Register rn, int32_t imm, int stat = 0); \ void asm_sub_imm(Register rd, Register rn, int32_t imm, int stat = 0); \ diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp index 24332d568e20..18fc29baf192 100644 --- a/js/src/nanojit/NativeMIPS.cpp +++ b/js/src/nanojit/NativeMIPS.cpp @@ -389,10 +389,10 @@ namespace nanojit } } - void Assembler::asm_regarg(ArgSize sz, LInsp p, Register r) + void Assembler::asm_regarg(ArgType ty, LInsp p, Register r) { NanoAssert(deprecated_isKnownReg(r)); - if (sz & ARGSIZE_MASK_INT) { + if (ty == ARGTYPE_I || ty == ARGTYPE_U) { // arg goes in specific register if (p->isconst()) asm_li(r, p->imm32()); @@ -464,7 +464,7 @@ namespace nanojit // Encode a 64-bit floating-point argument using the appropriate ABI. // This function operates in the same way as asm_arg, except that it will only - // handle arguments where (ArgSize)sz == ARGSIZE_F. + // handle arguments where (ArgType)ty == ARGTYPE_F. void Assembler::asm_arg_64(LInsp arg, Register& r, Register& fr, int& stkd) { @@ -1505,18 +1505,18 @@ namespace nanojit * on the stack. */ void - Assembler::asm_arg(ArgSize sz, LInsp arg, Register& r, Register& fr, int& stkd) + Assembler::asm_arg(ArgType ty, LInsp arg, Register& r, Register& fr, int& stkd) { // The stack offset must always be at least aligned to 4 bytes. NanoAssert((stkd & 3) == 0); - if (sz == ARGSIZE_F) { + if (ty == ARGTYPE_F) { // This task is fairly complex and so is delegated to asm_arg_64. asm_arg_64(arg, r, fr, stkd); - } - else if (sz & ARGSIZE_MASK_INT) { + } else { + NanoAssert(ty == ARGTYPE_I || ty == ARGTYPE_U); if (stkd < 16) { - asm_regarg(sz, arg, r); + asm_regarg(ty, arg, r); fr = nextreg(fr); r = nextreg(r); } @@ -1527,11 +1527,6 @@ namespace nanojit fr = r; stkd += 4; } - else { - NanoAssert(sz == ARGSIZE_Q); - // shouldn't have 64 bit int params - NanoAssert(false); - } } void @@ -1560,10 +1555,10 @@ namespace nanojit evictScratchRegsExcept(0); - const CallInfo* call = ins->callInfo(); - ArgSize sizes[MAXARGS]; - uint32_t argc = call->get_sizes(sizes); - bool indirect = call->isIndirect(); + const CallInfo* ci = ins->callInfo(); + ArgType argTypes[MAXARGS]; + uint32_t argc = ci->getArgTypes(argTypes); + bool indirect = ci->isIndirect(); // FIXME: Put one of the argument moves into the BDS slot @@ -1574,11 +1569,11 @@ namespace nanojit if (!indirect) // FIXME: If we can tell that we are calling non-PIC // (ie JIT) code, we could call direct instead of using t9 - asm_li(T9, call->_address); + asm_li(T9, ci->_address); else // Indirect call: we assign the address arg to t9 // which matches the o32 ABI for calling functions - asm_regarg(ARGSIZE_P, ins->arg(--argc), T9); + asm_regarg(ARGTYPE_P, ins->arg(--argc), T9); // Encode the arguments, starting at A0 and with an empty argument stack. Register r = A0, fr = FA0; @@ -1589,7 +1584,7 @@ namespace nanojit // Note that we loop through the arguments backwards as LIR specifies them // in reverse order. while(argc--) - asm_arg(sizes[argc], ins->arg(argc), r, fr, stkd); + asm_arg(argTypes[argc], ins->arg(argc), r, fr, stkd); if (stkd > max_out_args) max_out_args = stkd; diff --git a/js/src/nanojit/NativeMIPS.h b/js/src/nanojit/NativeMIPS.h index d31aae3137a8..8af897ac4675 100644 --- a/js/src/nanojit/NativeMIPS.h +++ b/js/src/nanojit/NativeMIPS.h @@ -179,9 +179,9 @@ namespace nanojit NIns *asm_branch_near(bool, LIns*, NIns*); \ void asm_cmp(LOpcode condop, LIns *a, LIns *b, Register cr); \ void asm_move(Register d, Register s); \ - void asm_regarg(ArgSize sz, LInsp p, Register r); \ + void asm_regarg(ArgType ty, LInsp p, Register r); \ void asm_stkarg(LInsp arg, int stkd); \ - void asm_arg(ArgSize sz, LInsp arg, Register& r, Register& fr, int& stkd); \ + void asm_arg(ArgType ty, LInsp arg, Register& r, Register& fr, int& stkd); \ void asm_arg_64(LInsp arg, Register& r, Register& fr, int& stkd) ; diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index 13c4bcaa4614..a0b0a2e9cb65 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -683,8 +683,8 @@ namespace nanojit evictScratchRegsExcept(0); const CallInfo* call = ins->callInfo(); - ArgSize sizes[MAXARGS]; - uint32_t argc = call->get_sizes(sizes); + ArgType argTypes[MAXARGS]; + uint32_t argc = call->getArgTypes(argTypes); bool indirect; if (!(indirect = call->isIndirect())) { @@ -699,7 +699,7 @@ namespace nanojit underrunProtect(8); // underrunProtect might clobber CTR BCTRL(); MTCTR(R11); - asm_regarg(ARGSIZE_P, ins->arg(--argc), R11); + asm_regarg(ARGTYPE_P, ins->arg(--argc), R11); } int param_size = 0; @@ -708,22 +708,22 @@ namespace nanojit Register fr = F1; for(uint32_t i = 0; i < argc; i++) { uint32_t j = argc - i - 1; - ArgSize sz = sizes[j]; + ArgType ty = argTypes[j]; LInsp arg = ins->arg(j); - if (sz & ARGSIZE_MASK_INT) { + if (ty == ARGTYPE_I || ty == ARGTYPE_U || ty == ARGTYPE_Q) { // GP arg if (r <= R10) { - asm_regarg(sz, arg, r); + asm_regarg(ty, arg, r); r = nextreg(r); param_size += sizeof(void*); } else { // put arg on stack TODO(stack_int32); } - } else if (sz == ARGSIZE_F) { + } else if (ty == ARGTYPE_F) { // double if (fr <= F13) { - asm_regarg(sz, arg, fr); + asm_regarg(ty, arg, fr); fr = nextreg(fr); #ifdef NANOJIT_64BIT r = nextreg(r); @@ -736,23 +736,23 @@ namespace nanojit TODO(stack_double); } } else { - TODO(ARGSIZE_UNK); + TODO(ARGTYPE_UNK); } } if (param_size > max_param_size) max_param_size = param_size; } - void Assembler::asm_regarg(ArgSize sz, LInsp p, Register r) + void Assembler::asm_regarg(ArgType ty, LInsp p, Register r) { NanoAssert(r != deprecated_UnknownReg); - if (sz & ARGSIZE_MASK_INT) + if (ty == ARGTYPE_I || ty == ARGTYPE_U || ty == ARGTYPE_Q) { #ifdef NANOJIT_64BIT - if (sz == ARGSIZE_I) { + if (ty == ARGTYPE_I) { // sign extend 32->64 EXTSW(r, r); - } else if (sz == ARGSIZE_U) { + } else if (ty == ARGTYPE_U) { // zero extend 32->64 CLRLDI(r, r, 32); } @@ -785,7 +785,7 @@ namespace nanojit } } } - else if (sz == ARGSIZE_F) { + else if (ty == ARGTYPE_F) { if (p->isUsed()) { Register rp = p->deprecated_getReg(); if (!deprecated_isKnownReg(rp) || !IsFpReg(rp)) { @@ -805,7 +805,7 @@ namespace nanojit } } else { - TODO(ARGSIZE_UNK); + TODO(ARGTYPE_UNK); } } diff --git a/js/src/nanojit/NativePPC.h b/js/src/nanojit/NativePPC.h index 6da77812af02..6e609e1fe092 100644 --- a/js/src/nanojit/NativePPC.h +++ b/js/src/nanojit/NativePPC.h @@ -287,7 +287,7 @@ namespace nanojit void nativePageSetup(); \ void br(NIns *addr, int link); \ void br_far(NIns *addr, int link); \ - void asm_regarg(ArgSize, LIns*, Register); \ + void asm_regarg(ArgType, LIns*, Register); \ void asm_li(Register r, int32_t imm); \ void asm_li32(Register r, int32_t imm); \ void asm_li64(Register r, uint64_t imm); \ diff --git a/js/src/nanojit/NativeSparc.cpp b/js/src/nanojit/NativeSparc.cpp index 5dd252bac619..22e8db132091 100644 --- a/js/src/nanojit/NativeSparc.cpp +++ b/js/src/nanojit/NativeSparc.cpp @@ -161,21 +161,21 @@ namespace nanojit evictScratchRegsExcept(0); - const CallInfo* call = ins->callInfo(); + const CallInfo* ci = ins->callInfo(); underrunProtect(8); NOP(); - ArgSize sizes[MAXARGS]; - uint32_t argc = call->get_sizes(sizes); + ArgType argTypes[MAXARGS]; + uint32_t argc = ci->getArgTypes(argTypes); NanoAssert(ins->isop(LIR_pcall) || ins->isop(LIR_fcall)); verbose_only(if (_logc->lcbits & LC_Assembly) outputf(" %p:", _nIns); ) - bool indirect = call->isIndirect(); + bool indirect = ci->isIndirect(); if (!indirect) { - CALL(call); + CALL(ci); } else { argc--; @@ -189,8 +189,8 @@ namespace nanojit for(int i=0; iarg(j), FpRegs); GPRIndex += 2; offset += 8; diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index 1ef399a2cf02..03a4b35a4727 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -893,8 +893,8 @@ namespace nanojit evictScratchRegsExcept(rmask(rr)); const CallInfo *call = ins->callInfo(); - ArgSize sizes[MAXARGS]; - int argc = call->get_sizes(sizes); + ArgType argTypes[MAXARGS]; + int argc = call->getArgTypes(argTypes); if (!call->isIndirect()) { verbose_only(if (_logc->lcbits & LC_Assembly) @@ -921,7 +921,7 @@ namespace nanojit // Assign the call address to RAX. Must happen after freeResourcesOf() // since RAX is usually the return value and will be allocated until that point. - asm_regarg(ARGSIZE_P, ins->arg(--argc), RAX); + asm_regarg(ARGTYPE_P, ins->arg(--argc), RAX); } #ifdef _WIN64 @@ -933,28 +933,28 @@ namespace nanojit int arg_index = 0; for (int i = 0; i < argc; i++) { int j = argc - i - 1; - ArgSize sz = sizes[j]; + ArgType ty = argTypes[j]; LIns* arg = ins->arg(j); - if ((sz & ARGSIZE_MASK_INT) && arg_index < NumArgRegs) { + if ((ty == ARGTYPE_I || ty == ARGTYPE_U || ty == ARGTYPE_Q) && arg_index < NumArgRegs) { // gp arg - asm_regarg(sz, arg, argRegs[arg_index]); + asm_regarg(ty, arg, argRegs[arg_index]); arg_index++; } #ifdef _WIN64 - else if (sz == ARGSIZE_F && arg_index < NumArgRegs) { + else if (ty == ARGTYPE_F && arg_index < NumArgRegs) { // double goes in XMM reg # based on overall arg_index - asm_regarg(sz, arg, Register(XMM0+arg_index)); + asm_regarg(ty, arg, Register(XMM0+arg_index)); arg_index++; } #else - else if (sz == ARGSIZE_F && fr < XMM8) { + else if (ty == ARGTYPE_F && fr < XMM8) { // double goes in next available XMM register - asm_regarg(sz, arg, fr); + asm_regarg(ty, arg, fr); fr = nextreg(fr); } #endif else { - asm_stkarg(sz, arg, stk_used); + asm_stkarg(ty, arg, stk_used); stk_used += sizeof(void*); } } @@ -963,8 +963,8 @@ namespace nanojit max_stk_used = stk_used; } - void Assembler::asm_regarg(ArgSize sz, LIns *p, Register r) { - if (sz == ARGSIZE_I) { + void Assembler::asm_regarg(ArgType ty, LIns *p, Register r) { + if (ty == ARGTYPE_I) { NanoAssert(p->isI32()); if (p->isconst()) { asm_immq(r, int64_t(p->imm32()), /*canClobberCCs*/true); @@ -972,7 +972,7 @@ namespace nanojit } // sign extend int32 to int64 MOVSXDR(r, r); - } else if (sz == ARGSIZE_U) { + } else if (ty == ARGTYPE_U) { NanoAssert(p->isI32()); if (p->isconst()) { asm_immq(r, uint64_t(uint32_t(p->imm32())), /*canClobberCCs*/true); @@ -980,6 +980,8 @@ namespace nanojit } // zero extend with 32bit mov, auto-zeros upper 32bits MOVLR(r, r); + } else { + // Do nothing. } /* there is no point in folding an immediate here, because * the argument register must be a scratch register and we're @@ -991,19 +993,22 @@ namespace nanojit findSpecificRegFor(p, r); } - void Assembler::asm_stkarg(ArgSize sz, LIns *p, int stk_off) { + void Assembler::asm_stkarg(ArgType ty, LIns *p, int stk_off) { NanoAssert(isS8(stk_off)); - if (sz & ARGSIZE_MASK_INT) { + if (ty == ARGTYPE_I || ty == ARGTYPE_U || ty == ARGTYPE_Q) { Register r = findRegFor(p, GpRegs); MOVQSPR(stk_off, r); // movq [rsp+d8], r - if (sz == ARGSIZE_I) { + if (ty == ARGTYPE_I) { // extend int32 to int64 NanoAssert(p->isI32()); MOVSXDR(r, r); - } else if (sz == ARGSIZE_U) { + } else if (ty == ARGTYPE_U) { // extend uint32 to uint64 NanoAssert(p->isI32()); MOVLR(r, r); + } else { + NanoAssert(ty == ARGTYPE_Q); + // Do nothing. } } else { TODO(asm_stkarg_non_int); diff --git a/js/src/nanojit/NativeX64.h b/js/src/nanojit/NativeX64.h index f22ea62792b3..a63cadaab0e6 100644 --- a/js/src/nanojit/NativeX64.h +++ b/js/src/nanojit/NativeX64.h @@ -395,8 +395,8 @@ namespace nanojit void asm_immi(Register r, int32_t v, bool canClobberCCs);\ void asm_immq(Register r, uint64_t v, bool canClobberCCs);\ void asm_immf(Register r, uint64_t v, bool canClobberCCs);\ - void asm_regarg(ArgSize, LIns*, Register);\ - void asm_stkarg(ArgSize, LIns*, int);\ + void asm_regarg(ArgType, LIns*, Register);\ + void asm_stkarg(ArgType, LIns*, int);\ void asm_shift(LIns*);\ void asm_shift_imm(LIns*);\ void asm_arith_imm(LIns*);\ diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index 4e5ff51cd9f7..5fe505061847 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -168,7 +168,7 @@ namespace nanojit const CallInfo* call = ins->callInfo(); // must be signed, not unsigned - uint32_t iargs = call->count_iargs(); + uint32_t iargs = call->count_int32_args(); int32_t fargs = call->count_args() - iargs; bool indirect = call->isIndirect(); @@ -237,13 +237,13 @@ namespace nanojit // Pre-assign registers to the first N 4B args based on the calling convention. uint32_t n = 0; - ArgSize sizes[MAXARGS]; - uint32_t argc = call->get_sizes(sizes); + ArgType argTypes[MAXARGS]; + uint32_t argc = call->getArgTypes(argTypes); int32_t stkd = 0; if (indirect) { argc--; - asm_arg(ARGSIZE_P, ins->arg(argc), EAX, stkd); + asm_arg(ARGTYPE_P, ins->arg(argc), EAX, stkd); if (!_config.i386_fixed_esp) stkd = 0; } @@ -251,12 +251,12 @@ namespace nanojit for (uint32_t i = 0; i < argc; i++) { uint32_t j = argc-i-1; - ArgSize sz = sizes[j]; + ArgType ty = argTypes[j]; Register r = UnspecifiedReg; - if (n < max_regs && sz != ARGSIZE_F) { + if (n < max_regs && ty != ARGTYPE_F) { r = argRegs[n++]; // tell asm_arg what reg to use } - asm_arg(sz, ins->arg(j), r, stkd); + asm_arg(ty, ins->arg(j), r, stkd); if (!_config.i386_fixed_esp) stkd = 0; } @@ -1377,12 +1377,12 @@ namespace nanojit } } - void Assembler::asm_arg(ArgSize sz, LInsp ins, Register r, int32_t& stkd) + void Assembler::asm_arg(ArgType ty, LInsp ins, Register r, int32_t& stkd) { // If 'r' is known, then that's the register we have to put 'ins' // into. - if (sz == ARGSIZE_I || sz == ARGSIZE_U) { + if (ty == ARGTYPE_I || ty == ARGTYPE_U) { if (r != UnspecifiedReg) { if (ins->isconst()) { // Rematerialize the constant. @@ -1413,7 +1413,7 @@ namespace nanojit } } else { - NanoAssert(sz == ARGSIZE_F); + NanoAssert(ty == ARGTYPE_F); asm_farg(ins, stkd); } } diff --git a/js/src/nanojit/Nativei386.h b/js/src/nanojit/Nativei386.h index 580c959e43bf..5bf19769fa30 100644 --- a/js/src/nanojit/Nativei386.h +++ b/js/src/nanojit/Nativei386.h @@ -184,7 +184,7 @@ namespace nanojit void asm_immi(Register r, int32_t val, bool canClobberCCs);\ void asm_stkarg(LInsp p, int32_t& stkd);\ void asm_farg(LInsp, int32_t& stkd);\ - void asm_arg(ArgSize sz, LInsp p, Register r, int32_t& stkd);\ + void asm_arg(ArgType ty, LInsp p, Register r, int32_t& stkd);\ void asm_pusharg(LInsp);\ void asm_fcmp(LIns *cond);\ NIns* asm_fbranch(bool, LIns*, NIns*);\ @@ -968,23 +968,23 @@ namespace nanojit #define EMMS() do { count_fpu(); FPUc(0x0f77); asm_output("emms"); } while (0) // standard direct call -#define CALL(c) do { \ +#define CALL(ci) do { \ count_call();\ underrunProtect(5); \ - int offset = (c->_address) - ((int)_nIns); \ + int offset = (ci->_address) - ((int)_nIns); \ IMM32( (uint32_t)offset ); \ *(--_nIns) = 0xE8; \ - verbose_only(asm_output("call %s",(c->_name));) \ - debug_only(if ((c->_argtypes & ARGSIZE_MASK_ANY)==ARGSIZE_F) fpu_push();)\ + verbose_only(asm_output("call %s",(ci->_name));) \ + debug_only(if (ci->returnType()==ARGTYPE_F) fpu_push();)\ } while (0) // indirect call thru register -#define CALLr(c,r) do { \ +#define CALLr(ci,r) do { \ count_calli();\ underrunProtect(2);\ ALU(0xff, 2, (r));\ verbose_only(asm_output("call %s",gpn(r));) \ - debug_only(if ((c->_argtypes & ARGSIZE_MASK_ANY)==ARGSIZE_F) fpu_push();)\ + debug_only(if (ci->returnType()==ARGTYPE_F) fpu_push();)\ } while (0) } From c08c12804f5d434b7e7a262afd3026402fbe36ec Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 19:48:45 -0700 Subject: [PATCH 095/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 9d1c59c1e7a4..757d37f7965b 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -5806c6f3bf1257fc3142f5eb8718e01071bcbb35 +55f02d7976752940a9f328d440fb6601ee2dc9f4 From 30e1b027e6b119eb7ea167deb1692333a0fcb069 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 19:58:31 -0700 Subject: [PATCH 096/213] Fix windows bustage for bug 507089. r=me. --HG-- extra : convert_revision : 2ad8e20152c94b63d55143199c080c087e987ea9 --- js/src/lirasm/lirasm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index c1765cbe5ac3..565fa0d11ed7 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -161,7 +161,7 @@ const ArgType I64 = nanojit::ARGTYPE_Q; const ArgType F64 = nanojit::ARGTYPE_F; const ArgType PTR = nanojit::ARGTYPE_P; const ArgType WRD = nanojit::ARGTYPE_P; -const ArgType VOID = nanojit::ARGTYPE_V; +const ArgType VD = nanojit::ARGTYPE_V; // "VOID" causes problems on Windows! enum LirTokenType { @@ -375,7 +375,7 @@ Function functions[] = { FN(puts, argMask(PTR, 1, 1) | retMask(I32)), FN(sin, argMask(F64, 1, 1) | retMask(F64)), FN(malloc, argMask(WRD, 1, 1) | retMask(PTR)), - FN(free, argMask(PTR, 1, 1) | retMask(VOID)) + FN(free, argMask(PTR, 1, 1) | retMask(VD)) }; template out From c192dbb64b87dba7286041e83e7e695dd387dd27 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 20:06:52 -0700 Subject: [PATCH 097/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 757d37f7965b..b44048c4d7e6 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -55f02d7976752940a9f328d440fb6601ee2dc9f4 +2ad8e20152c94b63d55143199c080c087e987ea9 From 8b62bc5a9268f365cfb46e3fd721732f4181cbe6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 21 Mar 2010 20:07:46 -0700 Subject: [PATCH 098/213] Bug 507089 - TM/nanojit: prepare to add get/set methods for CallInfo::_argtypes (TM-specific part). r=jorendorff. --- js/src/jsbuiltins.h | 108 ++++++++++++++++++++++---------------------- js/src/jstracer.cpp | 38 ++++++++-------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h index fd115a420305..ebb4edf970ae 100644 --- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -116,12 +116,12 @@ struct JSNativeTraceInfo { #define _JS_CI_NAME(op) #endif -#define _JS_I32_ARGSIZE nanojit::ARGSIZE_I -#define _JS_I32_RETSIZE nanojit::ARGSIZE_I -#define _JS_F64_ARGSIZE nanojit::ARGSIZE_F -#define _JS_F64_RETSIZE nanojit::ARGSIZE_F -#define _JS_PTR_ARGSIZE nanojit::ARGSIZE_P -#define _JS_PTR_RETSIZE nanojit::ARGSIZE_P +#define _JS_I32_ARGTYPE nanojit::ARGTYPE_I +#define _JS_I32_RETTYPE nanojit::ARGTYPE_I +#define _JS_F64_ARGTYPE nanojit::ARGTYPE_F +#define _JS_F64_RETTYPE nanojit::ARGTYPE_F +#define _JS_PTR_ARGTYPE nanojit::ARGTYPE_P +#define _JS_PTR_RETTYPE nanojit::ARGTYPE_P struct ClosureVarInfo; @@ -233,10 +233,10 @@ struct ClosureVarInfo; #define _JS_CTYPE_TYPE2(t,s,p,a,f) t #define _JS_CTYPE_TYPE(tyname) _JS_EXPAND(_JS_CTYPE_TYPE2 _JS_CTYPE_##tyname) -#define _JS_CTYPE_RETSIZE2(t,s,p,a,f) s##_RETSIZE -#define _JS_CTYPE_RETSIZE(tyname) _JS_EXPAND(_JS_CTYPE_RETSIZE2 _JS_CTYPE_##tyname) -#define _JS_CTYPE_ARGSIZE2(t,s,p,a,f) s##_ARGSIZE -#define _JS_CTYPE_ARGSIZE(tyname) _JS_EXPAND(_JS_CTYPE_ARGSIZE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_RETTYPE2(t,s,p,a,f) s##_RETTYPE +#define _JS_CTYPE_RETTYPE(tyname) _JS_EXPAND(_JS_CTYPE_RETTYPE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_ARGTYPE2(t,s,p,a,f) s##_ARGTYPE +#define _JS_CTYPE_ARGTYPE(tyname) _JS_EXPAND(_JS_CTYPE_ARGTYPE2 _JS_CTYPE_##tyname) #define _JS_CTYPE_PCH2(t,s,p,a,f) p #define _JS_CTYPE_PCH(tyname) _JS_EXPAND(_JS_CTYPE_PCH2 _JS_CTYPE_##tyname) #define _JS_CTYPE_ACH2(t,s,p,a,f) a @@ -315,56 +315,56 @@ struct ClosureVarInfo; */ #define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, isPure, storeAccSet) \ _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), (_JS_CTYPE_TYPE(at0)), \ - (_JS_CTYPE_ARGSIZE(at0) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, isPure, storeAccSet) \ _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1)), \ - (_JS_CTYPE_ARGSIZE(at0) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, isPure, storeAccSet) \ _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2)), \ - (_JS_CTYPE_ARGSIZE(at0) << (3*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at2) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (3*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at2) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, isPure, storeAccSet) \ _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ _JS_CTYPE_TYPE(at3)), \ - (_JS_CTYPE_ARGSIZE(at0) << (4*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (3*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at2) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at3) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (4*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (3*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at2) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at3) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, isPure, storeAccSet) \ _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ _JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4)), \ - (_JS_CTYPE_ARGSIZE(at0) << (5*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (4*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at2) << (3*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at3) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at4) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (5*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (4*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at2) << (3*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at3) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at4) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, isPure, storeAccSet) \ _JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \ (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ _JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4), _JS_CTYPE_TYPE(at5)), \ - (_JS_CTYPE_ARGSIZE(at0) << (6*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (5*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at2) << (4*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at3) << (3*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at4) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at5) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (6*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (5*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at2) << (4*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at3) << (3*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at4) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at5) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_7(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, isPure, \ storeAccSet) \ @@ -372,14 +372,14 @@ struct ClosureVarInfo; (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ _JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4), _JS_CTYPE_TYPE(at5), \ _JS_CTYPE_TYPE(at6)), \ - (_JS_CTYPE_ARGSIZE(at0) << (7*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (6*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at2) << (5*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at3) << (4*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at4) << (3*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at5) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at6) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (7*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (6*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at2) << (5*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at3) << (4*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at4) << (3*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at5) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at6) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DEFINE_CALLINFO_8(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, at7, isPure, \ storeAccSet) \ @@ -387,15 +387,15 @@ struct ClosureVarInfo; (_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \ _JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4), _JS_CTYPE_TYPE(at5), \ _JS_CTYPE_TYPE(at6), _JS_CTYPE_TYPE(at7)), \ - (_JS_CTYPE_ARGSIZE(at0) << (8*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at1) << (7*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at2) << (6*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at3) << (5*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at4) << (4*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at5) << (3*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at6) << (2*nanojit::ARGSIZE_SHIFT)) | \ - (_JS_CTYPE_ARGSIZE(at7) << (1*nanojit::ARGSIZE_SHIFT)) | \ - _JS_CTYPE_RETSIZE(rt), \ + (_JS_CTYPE_ARGTYPE(at0) << (8*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at1) << (7*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at2) << (6*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at3) << (5*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at4) << (4*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at5) << (3*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at6) << (2*nanojit::ARGTYPE_SHIFT)) | \ + (_JS_CTYPE_ARGTYPE(at7) << (1*nanojit::ARGTYPE_SHIFT)) | \ + _JS_CTYPE_RETTYPE(rt), \ isPure, storeAccSet) #define JS_DECLARE_CALLINFO(name) extern const nanojit::CallInfo _JS_CALLINFO(name); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index e0612982f60d..f833736d1b45 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -4975,7 +4975,7 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) CallInfo* ci = new (traceAlloc()) CallInfo(); ci->_address = uintptr_t(inner->code()); JS_ASSERT(ci->_address); - ci->_argtypes = ARGSIZE_P | ARGSIZE_P << ARGSIZE_SHIFT; + ci->_typesig = ARGTYPE_P | ARGTYPE_P << ARGTYPE_SHIFT; ci->_isPure = 0; ci->_storeAccSet = ACC_STORE_ANY; ci->_abi = ABI_FASTCALL; @@ -10505,11 +10505,11 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns CallInfo* ci = new (traceAlloc()) CallInfo(); ci->_address = uintptr_t(setflag ? sprop->setterOp() : sprop->getterOp()); - ci->_argtypes = ARGSIZE_I << (0*ARGSIZE_SHIFT) | - ARGSIZE_P << (1*ARGSIZE_SHIFT) | - ARGSIZE_P << (2*ARGSIZE_SHIFT) | - ARGSIZE_P << (3*ARGSIZE_SHIFT) | - ARGSIZE_P << (4*ARGSIZE_SHIFT); + ci->_typesig = ARGTYPE_I << (0*ARGTYPE_SHIFT) | + ARGTYPE_P << (1*ARGTYPE_SHIFT) | + ARGTYPE_P << (2*ARGTYPE_SHIFT) | + ARGTYPE_P << (3*ARGTYPE_SHIFT) | + ARGTYPE_P << (4*ARGTYPE_SHIFT); ci->_isPure = 0; ci->_storeAccSet = ACC_STORE_ANY; ci->_abi = ABI_CDECL; @@ -10860,7 +10860,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode) } // Set up arguments for the JSNative or JSFastNative. - uint32 types; + uint32 typesig; if (fun->flags & JSFUN_FAST_NATIVE) { if (mode == JSOP_NEW) RETURN_STOP("untraceable fast native constructor"); @@ -10868,10 +10868,10 @@ TraceRecorder::callNative(uintN argc, JSOp mode) args[0] = invokevp_ins; args[1] = lir->insImm(argc); args[2] = cx_ins; - types = ARGSIZE_I << (0*ARGSIZE_SHIFT) | - ARGSIZE_P << (1*ARGSIZE_SHIFT) | - ARGSIZE_I << (2*ARGSIZE_SHIFT) | - ARGSIZE_P << (3*ARGSIZE_SHIFT); + typesig = ARGTYPE_I << (0*ARGTYPE_SHIFT) | + ARGTYPE_P << (1*ARGTYPE_SHIFT) | + ARGTYPE_I << (2*ARGTYPE_SHIFT) | + ARGTYPE_P << (3*ARGTYPE_SHIFT); } else { int32_t offset = (vplen - 1) * sizeof(jsval); native_rval_ins = lir->ins2(LIR_piadd, invokevp_ins, INS_CONSTWORD(offset)); @@ -10880,12 +10880,12 @@ TraceRecorder::callNative(uintN argc, JSOp mode) args[2] = lir->insImm(argc); args[3] = this_ins; args[4] = cx_ins; - types = ARGSIZE_I << (0*ARGSIZE_SHIFT) | - ARGSIZE_P << (1*ARGSIZE_SHIFT) | - ARGSIZE_P << (2*ARGSIZE_SHIFT) | - ARGSIZE_I << (3*ARGSIZE_SHIFT) | - ARGSIZE_P << (4*ARGSIZE_SHIFT) | - ARGSIZE_P << (5*ARGSIZE_SHIFT); + typesig = ARGTYPE_I << (0*ARGTYPE_SHIFT) | + ARGTYPE_P << (1*ARGTYPE_SHIFT) | + ARGTYPE_P << (2*ARGTYPE_SHIFT) | + ARGTYPE_I << (3*ARGTYPE_SHIFT) | + ARGTYPE_P << (4*ARGTYPE_SHIFT) | + ARGTYPE_P << (5*ARGTYPE_SHIFT); } // Generate CallInfo and a JSSpecializedNative structure on the fly. @@ -10897,7 +10897,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode) ci->_isPure = 0; ci->_storeAccSet = ACC_STORE_ANY; ci->_abi = ABI_CDECL; - ci->_argtypes = types; + ci->_typesig = typesig; #ifdef DEBUG ci->_name = JS_GetFunctionName(fun); #endif @@ -12702,7 +12702,7 @@ TraceRecorder::record_NativeCallComplete() } else { /* Convert the result to double if the builtin returns int32. */ if (JSVAL_IS_NUMBER(v) && - (pendingSpecializedNative->builtin->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_I) { + pendingSpecializedNative->builtin->returnType() == ARGTYPE_I) { set(&v, lir->ins1(LIR_i2f, v_ins)); } } From 3aa6f0feab8c5c5f3177bddfc2d15b52658fe693 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 22 Mar 2010 10:26:08 -0700 Subject: [PATCH 099/213] Bug 554043 - fix negated bool, broken by TT_VOID patch (r=dvander) --- js/src/jsscan.h | 9 ++++++--- js/src/jstracer.cpp | 4 ++-- js/src/trace-test/tests/basic/testBug554043.js | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 js/src/trace-test/tests/basic/testBug554043.js diff --git a/js/src/jsscan.h b/js/src/jsscan.h index 84c6ad3d5d90..ea6d20e8d7ee 100644 --- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -146,18 +146,21 @@ enum TokenKind { TOK_LIMIT /* domain size */ }; -static inline bool TokenKindIsXML(TokenKind tt) +static inline bool +TokenKindIsXML(TokenKind tt) { return tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME; } -static inline bool TreeTypeIsXML(TokenKind tt) +static inline bool +TreeTypeIsXML(TokenKind tt) { return tt == TOK_XMLCOMMENT || tt == TOK_XMLCDATA || tt == TOK_XMLPI || tt == TOK_XMLELEM || tt == TOK_XMLLIST; } -static inline bool TokenKindIsDecl(TokenKind tt) +static inline bool +TokenKindIsDecl(TokenKind tt) { #if JS_HAS_BLOCK_SCOPE return tt == TOK_VAR || tt == TOK_LET; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index f833736d1b45..a40a8a27872c 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -9403,7 +9403,7 @@ TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit) lir->ins2(LIR_piand, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)), INS_CONSTWORD(JSVAL_SPECIAL)), exit); - assert(!v_ins->isconstp()); + JS_ASSERT(!v_ins->isconstp()); guard(false, lir->ins2(LIR_peq, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); return p2i(lir->ins2i(LIR_pursh, v_ins, JSVAL_TAGBITS)); @@ -10278,7 +10278,7 @@ TraceRecorder::record_JSOP_NEG() } JS_ASSERT(JSVAL_IS_BOOLEAN(v)); - set(&v, i2f(get(&v))); + set(&v, lir->ins1(LIR_fneg, i2f(get(&v)))); return ARECORD_CONTINUE; } diff --git a/js/src/trace-test/tests/basic/testBug554043.js b/js/src/trace-test/tests/basic/testBug554043.js new file mode 100644 index 000000000000..a0071aeb8001 --- /dev/null +++ b/js/src/trace-test/tests/basic/testBug554043.js @@ -0,0 +1,6 @@ +(function () { + for (var a = 0; a < 5; a++) { + print(-false) + assertEq(-false, -0.0); + } +})() From 28288a0037324ec06e9b0f33c7f4323eea1f6358 Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Mon, 22 Mar 2010 11:11:44 -0700 Subject: [PATCH 100/213] Use direct object shape instead of identity as key for deep property cache hits (497789, r=jorendorff). --- js/src/Makefile.in | 2 + js/src/jsapi.cpp | 10 +- js/src/jscntxt.h | 17 +- js/src/jsgc.cpp | 2 +- js/src/jsgc.h | 1 + js/src/jsinterp.cpp | 98 +-- js/src/jsinterp.h | 35 +- js/src/jsinterpinlines.h | 5 +- js/src/jsiter.h | 1 + js/src/jslibmath.h | 1 - js/src/jsobj.cpp | 37 +- js/src/jsops.cpp | 250 +++--- js/src/jsparse.cpp | 1 + js/src/jspropertytree.cpp | 1051 +++++++++++++++++++++++ js/src/jspropertytree.h | 82 ++ js/src/jsscope.cpp | 939 +------------------- js/src/jsscope.h | 88 +- js/src/jsscopeinlines.h | 19 +- js/src/jstracer.cpp | 117 ++- js/src/jstracer.h | 4 +- js/src/tests/js1_5/Regress/jstests.list | 2 +- 21 files changed, 1478 insertions(+), 1284 deletions(-) create mode 100644 js/src/jspropertytree.cpp create mode 100644 js/src/jspropertytree.h diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 5ed628d8da43..51d6580af3f8 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -147,6 +147,7 @@ CPPSRCS = \ jsopcode.cpp \ jsparse.cpp \ jsprf.cpp \ + jspropertytree.cpp \ jsregexp.cpp \ jsscan.cpp \ jsscope.cpp \ @@ -201,6 +202,7 @@ INSTALLED_HEADERS = \ jsotypes.h \ jsparse.h \ jsprf.h \ + jspropertytree.h \ jsproto.tbl \ jsprvtd.h \ jspubtd.h \ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index a7fac4160220..e2facdc9487b 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -603,7 +603,7 @@ JSRuntime::init(uint32 maxbytes) if (!deallocatorThread || !deallocatorThread->init()) return false; #endif - return js_InitPropertyTree(this) && js_InitThreads(this); + return propertyTree.init() && js_InitThreads(this); } JSRuntime::~JSRuntime() @@ -655,7 +655,7 @@ JSRuntime::~JSRuntime() delete deallocatorThread; } #endif - js_FinishPropertyTree(this); + propertyTree.finish(); } @@ -2808,10 +2808,8 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) /* Ensure that obj has its own, mutable scope, and seal that scope. */ JS_LOCK_OBJ(cx, obj); scope = js_GetMutableScope(cx, obj); - if (scope) { - scope->sealingShapeChange(cx); - scope->setSealed(); - } + if (scope) + scope->seal(cx); JS_UNLOCK_OBJ(cx, obj); if (!scope) return JS_FALSE; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 216c5699c45a..a9dbfdddbac9 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -49,11 +49,12 @@ #include "jsclist.h" #include "jslong.h" #include "jsatom.h" -#include "jsversion.h" #include "jsdhash.h" #include "jsgc.h" +#include "jshashtable.h" #include "jsinterp.h" #include "jsobj.h" +#include "jspropertytree.h" #include "jsprvtd.h" #include "jspubtd.h" #include "jsregexp.h" @@ -61,7 +62,6 @@ #include "jsarray.h" #include "jstask.h" #include "jsvector.h" -#include "jshashtable.h" #ifdef _MSC_VER #pragma warning(push) @@ -910,13 +910,18 @@ struct JSRuntime { /* * Shared scope property tree, and arena-pool for allocating its nodes. + * This really should be free of all locking overhead and allocated in + * thread-local storage, hence the JS_PROPERTY_TREE(cx) macro. + */ + js::PropertyTree propertyTree; + +#define JS_PROPERTY_TREE(cx) ((cx)->runtime->propertyTree) + + /* * The propertyRemovals counter is incremented for every JSScope::clear, * and for each JSScope::remove method call that frees a slot in an object. - * See js_NativeGet and js_NativeSet in jsobj.c. + * See js_NativeGet and js_NativeSet in jsobj.cpp. */ - JSDHashTable propertyTreeHash; - JSScopeProperty *propertyFreeList; - JSArenaPool propertyArenaPool; int32 propertyRemovals; /* Script filename table. */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 8b689045a646..82a450da4f17 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3236,7 +3236,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) * Sweep the runtime's property tree after finalizing objects, in case any * had watchpoints referencing tree nodes. */ - js_SweepScopeProperties(cx); + js::SweepScopeProperties(cx); /* * Sweep script filenames after sweeping functions in the generic loop diff --git a/js/src/jsgc.h b/js/src/jsgc.h index dbf645feeb29..d7726d8b960c 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -48,6 +48,7 @@ #include "jsbit.h" #include "jsutil.h" #include "jstask.h" +#include "jsversion.h" JS_BEGIN_EXTERN_C diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index c700953a75d0..8c0fe9b27bad 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -104,12 +104,10 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, JSPropertyCache *cache; jsbytecode *pc; JSScope *scope; - jsuword kshape, vshape, khash; + jsuword kshape, vshape; JSOp op; const JSCodeSpec *cs; jsuword vword; - ptrdiff_t pcoff; - JSAtom *atom; JSPropCacheEntry *entry; JS_ASSERT(!cx->runtime->gcRunning); @@ -235,10 +233,8 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, JS_GetFunctionName(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))), OBJ_SHAPE(obj)); #endif - scope->brandingShapeChange(cx, sprop->slot, v); - if (js_IsPropertyCacheDisabled(cx)) /* check for rt->shapeGen overflow */ + if (!scope->brand(cx, sprop->slot, v)) return JS_NO_PROP_CACHE_FILL; - scope->setBranded(); } vword = JSVAL_OBJECT_TO_PCVAL(v); break; @@ -321,17 +317,9 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, } JS_ASSERT(kshape < SHAPE_OVERFLOW_BIT); - khash = PROPERTY_CACHE_HASH_PC(pc, kshape); if (obj == pobj) { JS_ASSERT(scopeIndex == 0 && protoIndex == 0); } else { - if (op == JSOP_LENGTH) { - atom = cx->runtime->atomState.lengthAtom; - } else { - pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; - GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); - } - #ifdef DEBUG if (scopeIndex == 0) { JS_ASSERT(protoIndex != 0); @@ -340,12 +328,6 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, #endif if (scopeIndex != 0 || protoIndex != 1) { - khash = PROPERTY_CACHE_HASH_ATOM(atom, obj); - PCMETER(if (PCVCAP_TAG(cache->table[khash].vcap) <= 1) - cache->pcrecycles++); - pc = (jsbytecode *) atom; - kshape = (jsuword) obj; - /* * Make sure that a later shadowing assignment will enter * PurgeProtoChain and invalidate this entry, bug 479198. @@ -361,7 +343,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, } JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); - entry = &cache->table[khash]; + entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)]; PCMETER(PCVAL_IS_NULL(entry->vword) || cache->recycles++); entry->kpc = pc; entry->kshape = kshape; @@ -380,42 +362,41 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, return entry; } +static inline JSAtom * +GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs) +{ + if (op == JSOP_LENGTH) + return cx->runtime->atomState.lengthAtom; + + ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; + JSAtom *atom; + GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); + return atom; +} + JS_REQUIRES_STACK JSAtom * js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp, - JSPropCacheEntry **entryp) + JSPropCacheEntry *entry) { - JSOp op; - const JSCodeSpec *cs; - ptrdiff_t pcoff; - JSAtom *atom; JSObject *obj, *pobj, *tmp; - JSPropCacheEntry *entry; uint32 vcap; JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code) < cx->fp->script->length); - op = js_GetOpcode(cx, cx->fp->script, pc); - cs = &js_CodeSpec[op]; - if (op == JSOP_LENGTH) { - atom = cx->runtime->atomState.lengthAtom; - } else { - pcoff = (JOF_TYPE(cs->format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; - GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); - } + JSOp op = js_GetOpcode(cx, cx->fp->script, pc); + const JSCodeSpec &cs = js_CodeSpec[op]; obj = *objp; JS_ASSERT(OBJ_IS_NATIVE(obj)); - entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_ATOM(atom, obj)]; - *entryp = entry; vcap = entry->vcap; - if (entry->kpc != (jsbytecode *) atom) { - PCMETER(JS_PROPERTY_CACHE(cx).idmisses++); + if (entry->kpc != pc) { + PCMETER(JS_PROPERTY_CACHE(cx).kpcmisses++); + JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); #ifdef DEBUG_notme - entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_PC(pc, OBJ_SHAPE(obj))]; fprintf(stderr, "id miss for %s from %s:%u" " (pc %u, kpc %u, kshape %u, shape %u)\n", @@ -434,14 +415,19 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, return atom; } - if (entry->kshape != (jsuword) obj) { - PCMETER(JS_PROPERTY_CACHE(cx).komisses++); - return atom; + if (entry->kshape != OBJ_SHAPE(obj)) { + PCMETER(JS_PROPERTY_CACHE(cx).kshapemisses++); + return GetAtomFromBytecode(cx, pc, op, cs); } + /* + * PROPERTY_CACHE_TEST handles only the direct and immediate-prototype hit + * cases, all others go here. We could embed the target object in the cache + * entry but then entry size would be 5 words. Instead we traverse chains. + */ pobj = obj; - if (JOF_MODE(cs->format) == JOF_NAME) { + if (JOF_MODE(cs.format) == JOF_NAME) { while (vcap & (PCVCAP_SCOPEMASK << PCVCAP_PROTOBITS)) { tmp = pobj->getParent(); if (!tmp || !OBJ_IS_NATIVE(tmp)) @@ -461,8 +447,9 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, --vcap; } - if (js_MatchPropertyCacheShape(cx, pobj, PCVCAP_SHAPE(vcap))) { + if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(vcap))) { #ifdef DEBUG + JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); jsid id = ATOM_TO_JSID(atom); id = js_CheckForStringIndex(id); @@ -473,8 +460,8 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, return NULL; } - PCMETER(JS_PROPERTY_CACHE(cx).vcmisses++); - return atom; + PCMETER(JS_PROPERTY_CACHE(cx).vcapmisses++); + return GetAtomFromBytecode(cx, pc, op, cs); } #ifdef DEBUG @@ -529,7 +516,6 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) P(noprotos); P(longchains); P(recycles); - P(pcrecycles); P(tests); P(pchits); P(protopchits); @@ -541,9 +527,9 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) P(setpchits); P(setpcmisses); P(setmisses); - P(idmisses); - P(komisses); - P(vcmisses); + P(kpcmisses); + P(kshapemisses); + P(vcapmisses); P(misses); P(flushes); P(pcpurges); @@ -567,17 +553,15 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) void js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script) { - JSPropertyCache *cache; - JSPropCacheEntry *entry; + JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); - cache = &JS_PROPERTY_CACHE(cx); - for (entry = cache->table; entry < cache->table + PROPERTY_CACHE_SIZE; + for (JSPropCacheEntry *entry = cache->table; + entry < cache->table + PROPERTY_CACHE_SIZE; entry++) { if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { entry->kpc = NULL; - entry->kshape = 0; #ifdef DEBUG - entry->vcap = entry->vword = 0; + entry->kshape = entry->vcap = entry->vword = 0; #endif } } diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index a1e8f80cbc5a..e60c3bcf9a3f 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -244,12 +244,6 @@ typedef struct JSInlineFrame { (((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ PROPERTY_CACHE_MASK) -#define PROPERTY_CACHE_HASH_PC(pc,kshape) \ - PROPERTY_CACHE_HASH(pc, kshape) - -#define PROPERTY_CACHE_HASH_ATOM(atom,obj) \ - PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj)) - /* * Property cache value capability macros. */ @@ -273,8 +267,8 @@ typedef struct JSInlineFrame { #define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) struct JSPropCacheEntry { - jsbytecode *kpc; /* pc if vcap tag is <= 1, else atom */ - jsuword kshape; /* key shape if pc, else obj for atom */ + jsbytecode *kpc; /* pc of cache-testing bytecode */ + jsuword kshape; /* shape of direct (key) object */ jsuword vcap; /* value capability, see above */ jsuword vword; /* value word, see PCVAL_* below */ @@ -285,6 +279,8 @@ struct JSPropCacheEntry { bool directHit() const { return PCVCAP_TAG(vcap) == 0 && kshape == PCVCAP_SHAPE(vcap); } + + static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape); }; /* @@ -313,8 +309,6 @@ typedef struct JSPropertyCache { uint32 noprotos; /* resolve-returned non-proto pobj */ uint32 longchains; /* overlong scope and/or proto chain */ uint32 recycles; /* cache entries recycled by fills */ - uint32 pcrecycles; /* pc-keyed entries recycled by atom- - keyed fills */ uint32 tests; /* cache probes */ uint32 pchits; /* fast-path polymorphic op hits */ uint32 protopchits; /* pchits hitting immediate prototype */ @@ -326,9 +320,9 @@ typedef struct JSPropertyCache { uint32 setpchits; /* setting existing property pchit */ uint32 setpcmisses; /* setting/adding property pc misses */ uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */ - uint32 idmisses; /* slow-path key id == atom misses */ - uint32 komisses; /* slow-path key object misses */ - uint32 vcmisses; /* value capability misses */ + uint32 kpcmisses; /* slow-path key id == atom misses */ + uint32 kshapemisses; /* slow-path key object misses */ + uint32 vcapmisses; /* value capability misses */ uint32 misses; /* cache misses */ uint32 flushes; /* cache flushes */ uint32 pcpurges; /* shadowing purges on proto chain */ @@ -369,9 +363,6 @@ typedef struct JSPropertyCache { #define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) #define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) -inline bool -js_MatchPropertyCacheShape(JSContext *cx, JSObject *obj, uint32 shape); - /* * Fill property cache entry for key cx->fp->pc, optimized value word computed * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), @@ -383,7 +374,7 @@ js_MatchPropertyCacheShape(JSContext *cx, JSObject *obj, uint32 shape); extern JS_REQUIRES_STACK JSPropCacheEntry * js_FillPropertyCache(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoIndex, JSObject *pobj, - JSScopeProperty *sprop, JSBool adding); + JSScopeProperty *sprop, JSBool adding = false); /* * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the @@ -405,27 +396,27 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, do { \ JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ - entry = &cache_->table[PROPERTY_CACHE_HASH_PC(pc, kshape_)]; \ + entry = &cache_->table[PROPERTY_CACHE_HASH(pc, kshape_)]; \ PCMETER(cache_->pctestentry = entry); \ PCMETER(cache_->tests++); \ JS_ASSERT(&obj != &pobj); \ if (entry->kpc == pc && entry->kshape == kshape_) { \ JSObject *tmp_; \ pobj = obj; \ - JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); \ if (PCVCAP_TAG(entry->vcap) == 1 && \ (tmp_ = pobj->getProto()) != NULL) { \ pobj = tmp_; \ } \ \ - if (js_MatchPropertyCacheShape(cx,pobj,PCVCAP_SHAPE(entry->vcap))){\ + if (JSPropCacheEntry::matchShape(cx, pobj, \ + PCVCAP_SHAPE(entry->vcap))) { \ PCMETER(cache_->pchits++); \ PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ atom = NULL; \ break; \ } \ } \ - atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, &entry); \ + atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); \ if (atom) \ PCMETER(cache_->misses++); \ } while (0) @@ -433,7 +424,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, extern JS_REQUIRES_STACK JSAtom * js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp, - JSPropCacheEntry **entryp); + JSPropCacheEntry *entry); /* The property cache does not need a destructor. */ #define js_FinishPropertyCache(cache) ((void) 0) diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 5e210f93e86a..d431b6331bce 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -46,11 +46,10 @@ #include "jslock.h" #include "jsscope.h" -inline bool -js_MatchPropertyCacheShape(JSContext *cx, JSObject *obj, uint32 shape) +/* static */ inline bool +JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape) { return CX_OWNS_OBJECT_TITLE(cx, obj) && OBJ_SHAPE(obj) == shape; } - #endif /* jsinterpinlines_h___ */ diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 8ece3bf04c96..e6814c5ff3ca 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -45,6 +45,7 @@ */ #include "jsprvtd.h" #include "jspubtd.h" +#include "jsversion.h" JS_BEGIN_EXTERN_C diff --git a/js/src/jslibmath.h b/js/src/jslibmath.h index 13aa01a61efb..cb22d859fbc7 100644 --- a/js/src/jslibmath.h +++ b/js/src/jslibmath.h @@ -42,7 +42,6 @@ #define _LIBMATH_H #include -#include "jsversion.h" /* * Use system provided math routines. diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 542b1a9b769b..44498951cb33 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1645,12 +1645,12 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp) { if (!lookup(cx, obj, id, objp, propp)) - return JS_FALSE; + return false; if (!*propp) - return JS_TRUE; + return true; if (*objp == obj) - return JS_TRUE; + return true; JSExtendedClass *xclasp; JSObject *outer; @@ -1661,8 +1661,9 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, } else { outer = xclasp->outerObject(cx, *objp); if (!outer) - return JS_FALSE; + return false; } + if (outer != *objp) { if (OBJ_IS_NATIVE(*objp) && obj->getClass() == clasp) { /* @@ -1681,16 +1682,14 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, * owned, or indirectly delegated. */ JSScopeProperty *sprop = reinterpret_cast(*propp); - if (!SPROP_IS_SHARED_PERMANENT(sprop)) { - (*objp)->dropProperty(cx, *propp); - *propp = NULL; - } - } else { - (*objp)->dropProperty(cx, *propp); - *propp = NULL; + if (sprop->isSharedPermanent()) + return true; } + + (*objp)->dropProperty(cx, *propp); + *propp = NULL; } - return JS_TRUE; + return true; } #ifdef JS_TRACER @@ -1787,7 +1786,7 @@ js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp) */ if (pobj != obj && !(OBJ_IS_NATIVE(pobj) && - SPROP_IS_SHARED_PERMANENT((JSScopeProperty *)prop))) { + ((JSScopeProperty *)prop)->isSharedPermanent())) { pobj->dropProperty(cx, prop); *vp = JSVAL_FALSE; return JS_TRUE; @@ -4760,7 +4759,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, if (cacheResult) { entry = js_FillPropertyCache(cx, scopeChain, scopeIndex, protoIndex, pobj, - (JSScopeProperty *) prop, false); + (JSScopeProperty *) prop); } SCOPE_DEPTH_ACCUM(&cx->runtime->scopeSearchDepthStats, scopeIndex); goto out; @@ -4843,7 +4842,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id) #endif js_FillPropertyCache(cx, scopeChain, scopeIndex, protoIndex, pobj, - (JSScopeProperty *) prop, false); + (JSScopeProperty *) prop); JS_ASSERT(entry); JS_UNLOCK_OBJ(cx, pobj); return obj; @@ -5079,7 +5078,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, if (getHow & JSGET_CACHE_RESULT) { JS_ASSERT_NOT_ON_TRACE(cx); - js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, sprop, false); + js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, sprop); } if (!js_NativeGet(cx, obj, obj2, sprop, getHow, vp)) @@ -5268,8 +5267,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (!sprop->hasSlot()) { if (defineHow & JSDNP_CACHE_RESULT) { JS_ASSERT_NOT_ON_TRACE(cx); - JSPropCacheEntry *entry; - entry = js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop, false); + JSPropCacheEntry *entry = + js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop); TRACE_2(SetPropHit, entry, sprop); } @@ -5473,7 +5472,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) if (prop) { if (OBJ_IS_NATIVE(proto)) { sprop = (JSScopeProperty *)prop; - if (SPROP_IS_SHARED_PERMANENT(sprop)) + if (sprop->isSharedPermanent()) *rval = JSVAL_FALSE; } proto->dropProperty(cx, prop); diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 0c392373bf1b..d48bd63d8c13 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1706,142 +1706,144 @@ BEGIN_CASE(JSOP_SETMETHOD) * (possibly after the first iteration) always exist in native * object o. */ - entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)]; + entry = &cache->table[PROPERTY_CACHE_HASH(regs.pc, kshape)]; PCMETER(cache->pctestentry = entry); PCMETER(cache->tests++); PCMETER(cache->settests++); - if (entry->kpc == regs.pc && entry->kshape == kshape) { - JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); - if (js_MatchPropertyCacheShape(cx, obj, kshape)) { - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); - JS_ASSERT(sprop->writable()); - JS_ASSERT_IF(sprop->hasSlot(), PCVCAP_TAG(entry->vcap) == 0); + if (entry->kpc == regs.pc && entry->kshape == kshape && + JSPropCacheEntry::matchShape(cx, obj, kshape)) { + /* + * Property cache hit: either predicting a new property to be + * added directly to obj by this set, or on an existing "own" + * property, or on a prototype property that has a setter. + */ + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(sprop->writable()); + JS_ASSERT_IF(sprop->hasSlot(), PCVCAP_TAG(entry->vcap) == 0); - JSScope *scope = OBJ_SCOPE(obj); - JS_ASSERT(!scope->sealed()); + JSScope *scope = OBJ_SCOPE(obj); + JS_ASSERT(!scope->sealed()); - /* - * Fastest path: check whether the cached sprop is already - * in scope and call NATIVE_SET and break to get out of the - * do-while(0). But we can call NATIVE_SET only if obj owns - * scope or sprop is shared. - */ - bool checkForAdd; - if (!sprop->hasSlot()) { - if (PCVCAP_TAG(entry->vcap) == 0 || - ((obj2 = obj->getProto()) && - OBJ_IS_NATIVE(obj2) && - OBJ_SHAPE(obj2) == PCVCAP_SHAPE(entry->vcap))) { - goto fast_set_propcache_hit; - } - - /* The cache entry doesn't apply. vshape mismatch. */ - checkForAdd = false; - } else if (!scope->isSharedEmpty()) { - if (sprop == scope->lastProperty() || scope->hasProperty(sprop)) { - fast_set_propcache_hit: - PCMETER(cache->pchits++); - PCMETER(cache->setpchits++); - NATIVE_SET(cx, obj, sprop, entry, &rval); - break; - } - checkForAdd = sprop->hasSlot() && sprop->parent == scope->lastProperty(); - } else { - /* - * We check that cx own obj here and will continue to - * own it after js_GetMutableScope returns so we can - * continue to skip JS_UNLOCK_OBJ calls. - */ - JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); - scope = js_GetMutableScope(cx, obj); - JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); - if (!scope) - goto error; - checkForAdd = !sprop->parent; + /* + * Fastest path: check whether the cached sprop is already + * in scope and call NATIVE_SET and break to get out of the + * do-while(0). But we can call NATIVE_SET only if obj owns + * scope or sprop is shared. + */ + bool checkForAdd; + if (!sprop->hasSlot()) { + if (PCVCAP_TAG(entry->vcap) == 0 || + ((obj2 = obj->getProto()) && + OBJ_IS_NATIVE(obj2) && + OBJ_SHAPE(obj2) == PCVCAP_SHAPE(entry->vcap))) { + goto fast_set_propcache_hit; } - if (checkForAdd && - PCVCAP_SHAPE(entry->vcap) == rt->protoHazardShape && - sprop->hasDefaultSetter() && - (slot = sprop->slot) == scope->freeslot) { - /* - * Fast path: adding a plain old property that was once - * at the frontier of the property tree, whose slot is - * next to claim among the allocated slots in obj, - * where scope->table has not been created yet. - * - * We may want to remove hazard conditions above and - * inline compensation code here, depending on - * real-world workloads. - */ - JS_ASSERT(!(obj->getClass()->flags & - JSCLASS_SHARE_ALL_PROPERTIES)); - + /* The cache entry doesn't apply. vshape mismatch. */ + checkForAdd = false; + } else if (!scope->isSharedEmpty()) { + if (sprop == scope->lastProperty() || scope->hasProperty(sprop)) { + fast_set_propcache_hit: PCMETER(cache->pchits++); - PCMETER(cache->addpchits++); - - /* - * Beware classes such as Function that use the - * reserveSlots hook to allocate a number of reserved - * slots that may vary with obj. - */ - if (slot < STOBJ_NSLOTS(obj) && - !OBJ_GET_CLASS(cx, obj)->reserveSlots) { - ++scope->freeslot; - } else { - if (!js_AllocSlot(cx, obj, &slot)) - goto error; - } - - /* - * If this obj's number of reserved slots differed, or - * if something created a hash table for scope, we must - * pay the price of JSScope::putProperty. - * - * (A reserveSlots hook can cause scopes of the same - * shape to have different freeslot values. This is - * what causes the slot != sprop->slot case. See - * js_GetMutableScope.) - */ - if (slot != sprop->slot || scope->table) { - JSScopeProperty *sprop2 = - scope->putProperty(cx, sprop->id, - sprop->getter(), sprop->setter(), - slot, sprop->attributes(), - sprop->getFlags(), sprop->shortid); - if (!sprop2) { - js_FreeSlot(cx, obj, slot); - goto error; - } - sprop = sprop2; - } else { - scope->extend(cx, sprop); - } - - /* - * No method change check here because here we are - * adding a new property, not updating an existing - * slot's value that might contain a method of a - * branded scope. - */ - TRACE_2(SetPropHit, entry, sprop); - LOCKED_OBJ_SET_SLOT(obj, slot, rval); - - /* - * Purge the property cache of the id we may have just - * shadowed in obj's scope and proto chains. We do this - * after unlocking obj's scope to avoid lock nesting. - */ - js_PurgeScopeChain(cx, obj, sprop->id); + PCMETER(cache->setpchits++); + NATIVE_SET(cx, obj, sprop, entry, &rval); break; } - PCMETER(cache->setpcmisses++); + checkForAdd = sprop->hasSlot() && sprop->parent == scope->lastProperty(); + } else { + /* + * We check that cx own obj here and will continue to + * own it after js_GetMutableScope returns so we can + * continue to skip JS_UNLOCK_OBJ calls. + */ + JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); + scope = js_GetMutableScope(cx, obj); + JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); + if (!scope) + goto error; + checkForAdd = !sprop->parent; } + + if (checkForAdd && + PCVCAP_SHAPE(entry->vcap) == rt->protoHazardShape && + sprop->hasDefaultSetter() && + (slot = sprop->slot) == scope->freeslot) { + /* + * Fast path: adding a plain old property that was once + * at the frontier of the property tree, whose slot is + * next to claim among the allocated slots in obj, + * where scope->table has not been created yet. + * + * We may want to remove hazard conditions above and + * inline compensation code here, depending on + * real-world workloads. + */ + JS_ASSERT(!(obj->getClass()->flags & + JSCLASS_SHARE_ALL_PROPERTIES)); + + PCMETER(cache->pchits++); + PCMETER(cache->addpchits++); + + /* + * Beware classes such as Function that use the + * reserveSlots hook to allocate a number of reserved + * slots that may vary with obj. + */ + if (slot < STOBJ_NSLOTS(obj) && + !OBJ_GET_CLASS(cx, obj)->reserveSlots) { + ++scope->freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) + goto error; + } + + /* + * If this obj's number of reserved slots differed, or + * if something created a hash table for scope, we must + * pay the price of JSScope::putProperty. + * + * (A reserveSlots hook can cause scopes of the same + * shape to have different freeslot values. This is + * what causes the slot != sprop->slot case. See + * js_GetMutableScope.) + */ + if (slot != sprop->slot || scope->table) { + JSScopeProperty *sprop2 = + scope->putProperty(cx, sprop->id, + sprop->getter(), sprop->setter(), + slot, sprop->attributes(), + sprop->getFlags(), sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + goto error; + } + sprop = sprop2; + } else { + scope->extend(cx, sprop); + } + + /* + * No method change check here because here we are + * adding a new property, not updating an existing + * slot's value that might contain a method of a + * branded scope. + */ + TRACE_2(SetPropHit, entry, sprop); + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + + /* + * Purge the property cache of the id we may have just + * shadowed in obj's scope and proto chains. We do this + * after unlocking obj's scope to avoid lock nesting. + */ + js_PurgeScopeChain(cx, obj, sprop->id); + break; + } + PCMETER(cache->setpcmisses++); } - atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2, - &entry); + atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2, entry); if (atom) { PCMETER(cache->misses++); PCMETER(cache->setmisses++); @@ -3393,7 +3395,7 @@ BEGIN_CASE(JSOP_INITMETHOD) JS_ASSERT(!scope->sealed()); kshape = scope->shape; cache = &JS_PROPERTY_CACHE(cx); - entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)]; + entry = &cache->table[PROPERTY_CACHE_HASH(regs.pc, kshape)]; PCMETER(cache->pctestentry = entry); PCMETER(cache->tests++); PCMETER(cache->initests++); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 73047c3e530e..d47944e75472 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -6048,6 +6048,7 @@ JSCompiler::condExpr() pn = TernaryNode::create(tc); if (!pn) return NULL; + /* * Always accept the 'in' operator in the middle clause of a ternary, * where it's unambiguous, even if we might be parsing the init of a diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp new file mode 100644 index 000000000000..d90386845ca5 --- /dev/null +++ b/js/src/jspropertytree.cpp @@ -0,0 +1,1051 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */ +/* vim: set ts=40 sw=4 et tw=99: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SpiderMonkey property tree implementation + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2002-2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jstypes.h" +#include "jsarena.h" +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsgc.h" +#include "jspropertytree.h" +#include "jsscope.h" + +#include "jsscopeinlines.h" + +using namespace js; + +struct PropertyRootKey +{ + const JSScopeProperty *firstProp; + uint32 emptyShape; + + PropertyRootKey(const JSScopeProperty *child, uint32 shape) + : firstProp(child), emptyShape(shape) {} + + static JSDHashNumber hash(JSDHashTable *table, const void *key) { + const PropertyRootKey *rkey = (const PropertyRootKey *)key; + + return rkey->firstProp->hash() ^ rkey->emptyShape; + } +}; + +struct PropertyRootEntry : public JSDHashEntryHdr +{ + JSScopeProperty *firstProp; + uint32 emptyShape; + uint32 newEmptyShape; + + static JSBool match(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) { + const PropertyRootEntry *rent = (const PropertyRootEntry *)hdr; + const PropertyRootKey *rkey = (const PropertyRootKey *)key; + + return rent->firstProp->matches(rkey->firstProp) && + rent->emptyShape == rkey->emptyShape; + } +}; + +static const JSDHashTableOps PropertyRootHashOps = { + JS_DHashAllocTable, + JS_DHashFreeTable, + PropertyRootKey::hash, + PropertyRootEntry::match, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +static JSDHashNumber +HashScopeProperty(JSDHashTable *table, const void *key) +{ + const JSScopeProperty *sprop = (const JSScopeProperty *)key; + return sprop->hash(); +} + +static JSBool +MatchScopeProperty(JSDHashTable *table, + const JSDHashEntryHdr *hdr, + const void *key) +{ + const JSPropertyTreeEntry *entry = (const JSPropertyTreeEntry *)hdr; + const JSScopeProperty *sprop = entry->child; + const JSScopeProperty *kprop = (const JSScopeProperty *)key; + + return sprop->matches(kprop); +} + +static const JSDHashTableOps PropertyTreeHashOps = { + JS_DHashAllocTable, + JS_DHashFreeTable, + HashScopeProperty, + MatchScopeProperty, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +bool +PropertyTree::init() +{ + if (!JS_DHashTableInit(&hash, &PropertyRootHashOps, NULL, + sizeof(PropertyRootEntry), JS_DHASH_MIN_SIZE)) { + hash.ops = NULL; + return false; + } + JS_InitArenaPool(&arenaPool, "properties", + 256 * sizeof(JSScopeProperty), sizeof(void *), NULL); + emptyShapeChanges = 0; + return true; +} + +void +PropertyTree::finish() +{ + if (hash.ops) { + JS_DHashTableFinish(&hash); + hash.ops = NULL; + } + JS_FinishArenaPool(&arenaPool); +} + +/* + * A property tree node on PropertyTree::freeList overlays the following prefix + * struct on JSScopeProperty. + */ +typedef struct FreeNode { + jsid id; + FreeNode *next; + FreeNode **prevp; + + void insert(FreeNode *&list) { + next = list; + prevp = &list; + if (list) + list->prevp = &next; + list = this; + } + + void remove() { + *prevp = next; + if (next) + next->prevp = prevp; + } +} FreeNode; + +#define FREENODE(sprop) ((FreeNode *) (sprop)) + +#define FREENODE_INSERT(list, sprop) \ + JS_BEGIN_MACRO \ + union { FreeNode *fn; JSScopeProperty *sp; } u; \ + u.fn = (FreeNode *)(list); \ + FREENODE(sprop)->insert(u.fn); \ + JS_END_MACRO + +#define FREENODE_REMOVE(sprop) \ + (FREENODE(sprop)->remove()) + +/* + * NB: Called with cx->runtime->gcLock held if gcLocked is true. + * On failure, return null after unlocking the GC and reporting out of memory. + */ +JSScopeProperty * +PropertyTree::newScopeProperty(JSContext *cx, bool gcLocked) +{ + JSScopeProperty *sprop; + + if (!gcLocked) + JS_LOCK_GC(cx->runtime); + sprop = freeList; + if (sprop) { + FREENODE_REMOVE(sprop); + } else { + JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *, &arenaPool, + sizeof(JSScopeProperty)); + if (!sprop) { + JS_UNLOCK_GC(cx->runtime); + JS_ReportOutOfMemory(cx); + return NULL; + } + } + if (!gcLocked) + JS_UNLOCK_GC(cx->runtime); + + JS_RUNTIME_METER(cx->runtime, livePropTreeNodes); + JS_RUNTIME_METER(cx->runtime, totalPropTreeNodes); + return sprop; +} + +#define CHUNKY_KIDS_TAG ((jsuword)1) +#define KIDS_IS_CHUNKY(kids) ((jsuword)(kids) & CHUNKY_KIDS_TAG) +#define KIDS_TO_CHUNK(kids) ((PropTreeKidsChunk *) \ + ((jsuword)(kids) & ~CHUNKY_KIDS_TAG)) +#define CHUNK_TO_KIDS(chunk) ((JSScopeProperty *) \ + ((jsuword)(chunk) | CHUNKY_KIDS_TAG)) +#define MAX_KIDS_PER_CHUNK 10 +#define CHUNK_HASH_THRESHOLD 30 + +struct PropTreeKidsChunk { + JSScopeProperty *kids[MAX_KIDS_PER_CHUNK]; + JSDHashTable *table; + PropTreeKidsChunk *next; +}; + +/* + * NB: Called with cx->runtime->gcLock held, always. + * On failure, return null after unlocking the GC and reporting out of memory. + */ +static PropTreeKidsChunk * +NewPropTreeKidsChunk(JSContext *cx) +{ + PropTreeKidsChunk *chunk; + + chunk = (PropTreeKidsChunk *) js_calloc(sizeof *chunk); + if (!chunk) { + JS_UNLOCK_GC(cx->runtime); + JS_ReportOutOfMemory(cx); + return NULL; + } + JS_ASSERT(((jsuword)chunk & CHUNKY_KIDS_TAG) == 0); + JS_RUNTIME_METER(cx->runtime, propTreeKidsChunks); + return chunk; +} + +static PropTreeKidsChunk * +DestroyPropTreeKidsChunk(JSContext *cx, PropTreeKidsChunk *chunk) +{ + JS_RUNTIME_UNMETER(cx->runtime, propTreeKidsChunks); + if (chunk->table) + JS_DHashTableDestroy(chunk->table); + + PropTreeKidsChunk *nextChunk = chunk->next; + js_free(chunk); + return nextChunk; +} + +/* + * NB: Called with cx->runtime->gcLock held, always. + * On failure, return null after unlocking the GC and reporting out of memory. + */ +bool +PropertyTree::insertChild(JSContext *cx, JSScopeProperty *parent, + JSScopeProperty *child) +{ + JS_ASSERT(parent); + JS_ASSERT(!child->parent); + JS_ASSERT(!JSVAL_IS_NULL(parent->id)); + JS_ASSERT(!JSVAL_IS_NULL(child->id)); + + JSScopeProperty **childp = &parent->kids; + if (JSScopeProperty *kids = *childp) { + JSScopeProperty *sprop; + PropTreeKidsChunk *chunk; + + if (!KIDS_IS_CHUNKY(kids)) { + sprop = kids; + JS_ASSERT(sprop != child); + if (sprop->matches(child)) { + /* + * Duplicate child created while racing to getChild on the same + * node label. See PropertyTree::getChild, further below. + */ + JS_RUNTIME_METER(cx->runtime, duplicatePropTreeNodes); + } + chunk = NewPropTreeKidsChunk(cx); + if (!chunk) + return false; + parent->kids = CHUNK_TO_KIDS(chunk); + chunk->kids[0] = sprop; + childp = &chunk->kids[1]; + } else { + PropTreeKidsChunk **chunkp; + + chunk = KIDS_TO_CHUNK(kids); + if (JSDHashTable *table = chunk->table) { + JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_ADD); + if (!entry) { + JS_UNLOCK_GC(cx->runtime); + JS_ReportOutOfMemory(cx); + return false; + } + if (!entry->child) { + entry->child = child; + while (chunk->next) + chunk = chunk->next; + for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + childp = &chunk->kids[i]; + sprop = *childp; + if (!sprop) + goto insert; + } + chunkp = &chunk->next; + goto new_chunk; + } + } + + do { + for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + childp = &chunk->kids[i]; + sprop = *childp; + if (!sprop) + goto insert; + + JS_ASSERT(sprop != child); + if (sprop->matches(child)) { + /* + * Duplicate child, see comment above. In this + * case, we must let the duplicate be inserted at + * this level in the tree, so we keep iterating, + * looking for an empty slot in which to insert. + */ + JS_ASSERT(sprop != child); + JS_RUNTIME_METER(cx->runtime, duplicatePropTreeNodes); + } + } + chunkp = &chunk->next; + } while ((chunk = *chunkp) != NULL); + + new_chunk: + chunk = NewPropTreeKidsChunk(cx); + if (!chunk) + return false; + *chunkp = chunk; + childp = &chunk->kids[0]; + } + } + + insert: + *childp = child; + child->parent = parent; + return true; +} + +/* NB: Called with cx->runtime->gcLock held. */ +void +PropertyTree::removeChild(JSContext *cx, JSScopeProperty *child) +{ + uintN i, j; + JSPropertyTreeEntry *entry; + + JSScopeProperty *parent = child->parent; + JS_ASSERT(parent); + JS_ASSERT(!JSVAL_IS_NULL(parent->id)); + + JSScopeProperty *kids = parent->kids; + if (!KIDS_IS_CHUNKY(kids)) { + JSScopeProperty *kid = kids; + if (kid == child) + parent->kids = NULL; + return; + } + + PropTreeKidsChunk *list = KIDS_TO_CHUNK(kids); + PropTreeKidsChunk *chunk = list; + PropTreeKidsChunk **chunkp = &list; + + JSDHashTable *table = chunk->table; + PropTreeKidsChunk *freeChunk = NULL; + + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + if (chunk->kids[i] == child) { + PropTreeKidsChunk *lastChunk = chunk; + if (!lastChunk->next) { + j = i + 1; + } else { + j = 0; + do { + chunkp = &lastChunk->next; + lastChunk = *chunkp; + } while (lastChunk->next); + } + for (; j < MAX_KIDS_PER_CHUNK; j++) { + if (!lastChunk->kids[j]) + break; + } + --j; + if (chunk != lastChunk || j > i) + chunk->kids[i] = lastChunk->kids[j]; + lastChunk->kids[j] = NULL; + if (j == 0) { + *chunkp = NULL; + if (!list) + parent->kids = NULL; + freeChunk = lastChunk; + } + goto out; + } + } + + chunkp = &chunk->next; + } while ((chunk = *chunkp) != NULL); + + out: + if (table) { + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, child, JS_DHASH_LOOKUP); + + if (entry->child == child) + JS_DHashTableRawRemove(table, &entry->hdr); + } + if (freeChunk) + DestroyPropTreeKidsChunk(cx, freeChunk); +} + +void +PropertyTree::emptyShapeChange(uint32 oldEmptyShape, uint32 newEmptyShape) +{ + if (oldEmptyShape == newEmptyShape) + return; + + PropertyRootEntry *rent = (PropertyRootEntry *) hash.entryStore; + PropertyRootEntry *rend = rent + JS_DHASH_TABLE_SIZE(&hash); + + while (rent < rend) { + if (rent->emptyShape == oldEmptyShape) + rent->newEmptyShape = newEmptyShape; + rent++; + } + + ++emptyShapeChanges; +} + +static JSDHashTable * +HashChunks(PropTreeKidsChunk *chunk, uintN n) +{ + JSDHashTable *table; + uintN i; + JSScopeProperty *sprop; + JSPropertyTreeEntry *entry; + + table = JS_NewDHashTable(&PropertyTreeHashOps, NULL, + sizeof(JSPropertyTreeEntry), + JS_DHASH_DEFAULT_CAPACITY(n + 1)); + if (!table) + return NULL; + do { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + sprop = chunk->kids[i]; + if (!sprop) + break; + entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, sprop, JS_DHASH_ADD); + entry->child = sprop; + } + } while ((chunk = chunk->next) != NULL); + return table; +} + +/* + * Called without cx->runtime->gcLock held. This function acquires that lock + * only when inserting a new child. Thus there may be races to find or add a + * node that result in duplicates. We expect such races to be rare! + * + * We use cx->runtime->gcLock, not ...->rtLock, to avoid nesting the former + * inside the latter in js_GenerateShape below. + */ +JSScopeProperty * +PropertyTree::getChild(JSContext *cx, JSScopeProperty *parent, uint32 shape, + const JSScopeProperty &child) +{ + PropertyRootEntry *rent; + JSScopeProperty *sprop; + + if (!parent) { + PropertyRootKey rkey(&child, shape); + + JS_LOCK_GC(cx->runtime); + rent = (PropertyRootEntry *) JS_DHashTableOperate(&hash, &rkey, JS_DHASH_ADD); + if (!rent) { + JS_UNLOCK_GC(cx->runtime); + JS_ReportOutOfMemory(cx); + return NULL; + } + + sprop = rent->firstProp; + if (sprop) + goto out; + } else { + JS_ASSERT(!JSVAL_IS_NULL(parent->id)); + + /* + * Because chunks are appended at the end and never deleted except by + * the GC, we can search without taking the runtime's GC lock. We may + * miss a matching sprop added by another thread, and make a duplicate + * one, but that is an unlikely, therefore small, cost. The property + * tree has extremely low fan-out below its root in popular embeddings + * with real-world workloads. + * + * Patterns such as defining closures that capture a constructor's + * environment as getters or setters on the new object that is passed + * in as |this| can significantly increase fan-out below the property + * tree root -- see bug 335700 for details. + */ + rent = NULL; + sprop = parent->kids; + if (sprop) { + if (!KIDS_IS_CHUNKY(sprop)) { + if (sprop->matches(&child)) + return sprop; + } else { + PropTreeKidsChunk *chunk = KIDS_TO_CHUNK(sprop); + + if (JSDHashTable *table = chunk->table) { + JS_LOCK_GC(cx->runtime); + JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *) + JS_DHashTableOperate(table, &child, JS_DHASH_LOOKUP); + sprop = entry->child; + if (sprop) + goto out; + goto locked_not_found; + } + + uintN n = 0; + do { + for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + sprop = chunk->kids[i]; + if (!sprop) { + n += i; + if (n >= CHUNK_HASH_THRESHOLD) { + chunk = KIDS_TO_CHUNK(parent->kids); + if (!chunk->table) { + JSDHashTable *table = HashChunks(chunk, n); + if (!table) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + JS_LOCK_GC(cx->runtime); + if (chunk->table) + JS_DHashTableDestroy(table); + else + chunk->table = table; + goto locked_not_found; + } + } + goto not_found; + } + + if (sprop->matches(&child)) + return sprop; + } + n += MAX_KIDS_PER_CHUNK; + } while ((chunk = chunk->next) != NULL); + } + } + + not_found: + JS_LOCK_GC(cx->runtime); + } + + locked_not_found: + sprop = newScopeProperty(cx, true); + if (!sprop) + return NULL; + + new (sprop) JSScopeProperty(child.id, child.rawGetter, child.rawSetter, child.slot, + child.attrs, child.flags, child.shortid); + sprop->parent = sprop->kids = NULL; + sprop->shape = js_GenerateShape(cx, true); + + if (!parent) { + rent->firstProp = sprop; + rent->emptyShape = shape; + rent->newEmptyShape = 0; + } else { + if (!PropertyTree::insertChild(cx, parent, sprop)) + return NULL; + } + + out: + JS_UNLOCK_GC(cx->runtime); + return sprop; +} + +#ifdef DEBUG + +static void +MeterKidCount(JSBasicStats *bs, uintN nkids) +{ + JS_BASIC_STATS_ACCUM(bs, nkids); + bs->hist[JS_MIN(nkids, 10)]++; +} + +static void +MeterPropertyTree(JSBasicStats *bs, JSScopeProperty *node) +{ + uintN i, nkids; + JSScopeProperty *kids, *kid; + PropTreeKidsChunk *chunk; + + nkids = 0; + kids = node->kids; + if (kids) { + if (KIDS_IS_CHUNKY(kids)) { + for (chunk = KIDS_TO_CHUNK(kids); chunk; chunk = chunk->next) { + for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + kid = chunk->kids[i]; + if (!kid) + break; + MeterPropertyTree(bs, kid); + nkids++; + } + } + } else { + MeterPropertyTree(bs, kids); + nkids = 1; + } + } + + MeterKidCount(bs, nkids); +} + +static JSDHashOperator +js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, + void *arg) +{ + PropertyRootEntry *rent = (PropertyRootEntry *)hdr; + JSBasicStats *bs = (JSBasicStats *)arg; + + MeterPropertyTree(bs, rent->firstProp); + return JS_DHASH_NEXT; +} + +void +JSScopeProperty::dump(JSContext *cx, FILE *fp) +{ + JS_ASSERT(!JSVAL_IS_NULL(id)); + + jsval idval = ID_TO_VALUE(id); + if (JSVAL_IS_INT(idval)) { + fprintf(fp, "[%ld]", (long) JSVAL_TO_INT(idval)); + } else { + JSString *str; + if (JSVAL_IS_STRING(idval)) { + str = JSVAL_TO_STRING(idval); + } else { + JS_ASSERT(JSVAL_IS_OBJECT(idval)); + str = js_ValueToString(cx, idval); + fputs("object ", fp); + } + if (!str) + fputs("", fp); + else + js_FileEscapedString(fp, str, '"'); + } + + fprintf(fp, " g/s %p/%p slot %u attrs %x ", + JS_FUNC_TO_DATA_PTR(void *, rawGetter), + JS_FUNC_TO_DATA_PTR(void *, rawSetter), + slot, attrs); + if (attrs) { + int first = 1; + fputs("(", fp); +#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(" " #display + first, fp), first = 0 + DUMP_ATTR(ENUMERATE, enumerate); + DUMP_ATTR(READONLY, readonly); + DUMP_ATTR(PERMANENT, permanent); + DUMP_ATTR(GETTER, getter); + DUMP_ATTR(SETTER, setter); + DUMP_ATTR(SHARED, shared); +#undef DUMP_ATTR + fputs(") ", fp); + } + + fprintf(fp, "flags %x ", flags); + if (flags) { + int first = 1; + fputs("(", fp); +#define DUMP_FLAG(name, display) if (flags & name) fputs(" " #display + first, fp), first = 0 + DUMP_FLAG(ALIAS, alias); + DUMP_FLAG(HAS_SHORTID, has_shortid); + DUMP_FLAG(METHOD, method); + DUMP_FLAG(MARK, mark); + DUMP_FLAG(SHAPE_REGEN, shape_regen); + DUMP_FLAG(IN_DICTIONARY, in_dictionary); +#undef DUMP_FLAG + fputs(") ", fp); + } + + fprintf(fp, "shortid %d\n", shortid); +} + +void +JSScopeProperty::dumpSubtree(JSContext *cx, int level, FILE *fp) +{ + fprintf(fp, "%*sid ", level, ""); + dump(cx, fp); + + if (kids) { + ++level; + if (KIDS_IS_CHUNKY(kids)) { + PropTreeKidsChunk *chunk = KIDS_TO_CHUNK(kids); + do { + for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + JSScopeProperty *kid = chunk->kids[i]; + if (!kid) + break; + JS_ASSERT(kid->parent == this); + kid->dumpSubtree(cx, level, fp); + } + } while ((chunk = chunk->next) != NULL); + } else { + JSScopeProperty *kid = kids; + JS_ASSERT(kid->parent == this); + kid->dumpSubtree(cx, level, fp); + } + } +} + +#endif /* DEBUG */ + +static void +OrphanNodeKids(JSContext *cx, JSScopeProperty *sprop) +{ + JSScopeProperty *kids = sprop->kids; + + JS_ASSERT(kids); + sprop->kids = NULL; + + /* + * The grandparent must have either no kids or (still, after the + * removeChild call above) chunky kids. + */ + JS_ASSERT(!sprop->parent || !sprop->parent->kids || + KIDS_IS_CHUNKY(sprop->parent->kids)); + + if (KIDS_IS_CHUNKY(kids)) { + PropTreeKidsChunk *chunk = KIDS_TO_CHUNK(kids); + + do { + for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) { + JSScopeProperty *kid = chunk->kids[i]; + if (!kid) + break; + + if (!JSVAL_IS_NULL(kid->id)) { + JS_ASSERT(kid->parent == sprop); + kid->parent = NULL; + } + } + } while ((chunk = DestroyPropTreeKidsChunk(cx, chunk)) != NULL); + } else { + JSScopeProperty *kid = kids; + + if (!JSVAL_IS_NULL(kid->id)) { + JS_ASSERT(kid->parent == sprop); + kid->parent = NULL; + } + } +} + +JSDHashOperator +js::RemoveNodeIfDead(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void *arg) +{ + PropertyRootEntry *rent = (PropertyRootEntry *)hdr; + JSScopeProperty *sprop = rent->firstProp; + + JS_ASSERT(!sprop->parent); + if (!sprop->marked()) { + if (sprop->kids) + OrphanNodeKids((JSContext *)arg, sprop); + return JS_DHASH_REMOVE; + } + return JS_DHASH_NEXT; +} + +void +js::SweepScopeProperties(JSContext *cx) +{ + JS_STATIC_ASSERT(offsetof(FreeNode, id) == offsetof(JSScopeProperty, id)); + JS_STATIC_ASSERT(sizeof(FreeNode) >= offsetof(JSScopeProperty, slot)); + +#ifdef DEBUG + JSBasicStats bs; + uint32 livePropCapacity = 0, totalLiveCount = 0; + static FILE *logfp; + if (!logfp) { + if (const char *filename = getenv("JS_PROPTREE_STATFILE")) + logfp = fopen(filename, "w"); + } + + if (logfp) { + JS_BASIC_STATS_INIT(&bs); + MeterKidCount(&bs, JS_PROPERTY_TREE(cx).hash.entryCount); + JS_DHashTableEnumerate(&JS_PROPERTY_TREE(cx).hash, js_MeterPropertyTree, &bs); + + double props, nodes, mean, sigma; + + props = cx->runtime->liveScopePropsPreSweep; + nodes = cx->runtime->livePropTreeNodes; + JS_ASSERT(nodes == bs.sum); + mean = JS_MeanAndStdDevBS(&bs, &sigma); + + fprintf(logfp, + "props %g nodes %g beta %g meankids %g sigma %g max %u\n", + props, nodes, nodes / props, mean, sigma, bs.max); + + JS_DumpHistogram(&bs, logfp); + } +#endif + + /* + * First, remove unmarked nodes from JS_PROPERTY_TREE(cx).hash. This table + * requires special handling up front, rather than removal during regular + * heap sweeping, because we cannot find an entry in it from the firstProp + * node pointer alone -- we would need the emptyShape too. + * + * Rather than encode emptyShape in firstProp somehow (a tagged overlay on + * parent, perhaps, but that would slow down JSScope::search and other hot + * paths), we simply orphan kids of garbage nodes in the property tree's + * root-ply before sweeping the node heap. + */ + JS_DHashTableEnumerate(&JS_PROPERTY_TREE(cx).hash, RemoveNodeIfDead, cx); + + /* + * Second, if any empty scopes have been reshaped, rehash the root ply of + * this tree using the new empty shape numbers as key-halves. If we run out + * of memory trying to allocate the new hash, disable the property cache by + * setting SHAPE_OVERFLOW_BIT in rt->shapeGen. The next GC will therefore + * renumber shapes as well as (we hope, eventually) free sufficient memory + * for a successful re-run through this code. + */ + if (JS_PROPERTY_TREE(cx).emptyShapeChanges) { + JSDHashTable &oldHash = JS_PROPERTY_TREE(cx).hash; + uint32 tableSize = JS_DHASH_TABLE_SIZE(&oldHash); + JSDHashTable newHash; + + if (!JS_DHashTableInit(&newHash, &PropertyRootHashOps, NULL, + sizeof(PropertyRootEntry), tableSize)) { + cx->runtime->shapeGen |= SHAPE_OVERFLOW_BIT; + } else { + PropertyRootEntry *rent = (PropertyRootEntry *) oldHash.entryStore; + PropertyRootEntry *rend = rent + tableSize; + + while (rent < rend) { + if (rent->firstProp) { + uint32 emptyShape = rent->newEmptyShape; + if (emptyShape == 0) + emptyShape = rent->emptyShape; + + PropertyRootKey rkey(rent->firstProp, emptyShape); + PropertyRootEntry *newRent = + (PropertyRootEntry *) JS_DHashTableOperate(&newHash, &rkey, JS_DHASH_ADD); + + newRent->firstProp = rent->firstProp; + newRent->emptyShape = emptyShape; + newRent->newEmptyShape = 0; + } + rent++; + } + + JS_ASSERT(newHash.generation == 0); + JS_DHashTableFinish(&oldHash); + JS_PROPERTY_TREE(cx).hash = newHash; + JS_PROPERTY_TREE(cx).emptyShapeChanges = 0; + } + } + + /* + * Third, sweep the heap clean of all unmarked nodes. Here we will find + * nodes already GC'ed from the root ply, but we will avoid re-orphaning + * their kids, because the kids member will already be null. + */ + JSArena **ap = &JS_PROPERTY_TREE(cx).arenaPool.first.next; + while (JSArena *a = *ap) { + JSScopeProperty *limit = (JSScopeProperty *) a->avail; + uintN liveCount = 0; + + for (JSScopeProperty *sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) { + /* If the id is null, sprop is already on the freelist. */ + if (JSVAL_IS_NULL(sprop->id)) + continue; + + /* + * If the mark bit is set, sprop is alive, so clear the mark bit + * and continue the while loop. + * + * Regenerate sprop->shape if it hasn't already been refreshed + * during the mark phase, when live scopes' lastProp members are + * followed to update both scope->shape and lastProp->shape. + */ + if (sprop->marked()) { + sprop->clearMark(); + if (cx->runtime->gcRegenShapes) { + if (sprop->hasRegenFlag()) + sprop->clearRegenFlag(); + else + sprop->shape = js_RegenerateShapeForGC(cx); + } + liveCount++; + continue; + } + + if (!sprop->inDictionary()) { + /* + * Here, sprop is garbage to collect, but its parent might not + * be, so we may have to remove it from its parent's kids chunk + * list or kid singleton pointer set. + * + * Without a separate mark-clearing pass, we can't tell whether + * sprop->parent is live at this point, so we must remove sprop + * if its parent member is non-null. A saving grace: if sprop's + * parent is dead and swept by this point, sprop->parent will + * be null -- in the next paragraph, we null all of a property + * tree node's kids' parent links when sweeping that node. + */ + if (sprop->parent) + JS_PROPERTY_TREE(cx).removeChild(cx, sprop); + + if (sprop->kids) + OrphanNodeKids(cx, sprop); + } + + /* Clear id so we know (above) that sprop is on the freelist. */ + sprop->id = JSVAL_NULL; + FREENODE_INSERT(JS_PROPERTY_TREE(cx).freeList, sprop); + JS_RUNTIME_UNMETER(cx->runtime, livePropTreeNodes); + } + + /* If a contains no live properties, return it to the malloc heap. */ + if (liveCount == 0) { + for (JSScopeProperty *sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) + FREENODE_REMOVE(sprop); + JS_ARENA_DESTROY(&JS_PROPERTY_TREE(cx).arenaPool, a, ap); + } else { +#ifdef DEBUG + livePropCapacity += limit - (JSScopeProperty *) a->base; + totalLiveCount += liveCount; +#endif + ap = &a->next; + } + } + +#ifdef DEBUG + if (logfp) { + fprintf(logfp, + "\nProperty tree stats for gcNumber %lu\n", + (unsigned long) cx->runtime->gcNumber); + + fprintf(logfp, "arenautil %g%%\n", + (totalLiveCount && livePropCapacity) + ? (totalLiveCount * 100.0) / livePropCapacity + : 0.0); + +#define RATE(f1, f2) (((double)js_scope_stats.f1 / js_scope_stats.f2) * 100.0) + + fprintf(logfp, + "Scope search stats:\n" + " searches: %6u\n" + " hits: %6u %5.2f%% of searches\n" + " misses: %6u %5.2f%%\n" + " hashes: %6u %5.2f%%\n" + " steps: %6u %5.2f%% %5.2f%% of hashes\n" + " stepHits: %6u %5.2f%% %5.2f%%\n" + " stepMisses: %6u %5.2f%% %5.2f%%\n" + " tableAllocFails %6u\n" + " toDictFails %6u\n" + " wrapWatchFails %6u\n" + " adds: %6u\n" + " addFails: %6u\n" + " puts: %6u\n" + " redundantPuts: %6u\n" + " putFails: %6u\n" + " changes: %6u\n" + " changeFails: %6u\n" + " compresses: %6u\n" + " grows: %6u\n" + " removes: %6u\n" + " removeFrees: %6u\n" + " uselessRemoves: %6u\n" + " shrinks: %6u\n", + js_scope_stats.searches, + js_scope_stats.hits, RATE(hits, searches), + js_scope_stats.misses, RATE(misses, searches), + js_scope_stats.hashes, RATE(hashes, searches), + js_scope_stats.steps, RATE(steps, searches), RATE(steps, hashes), + js_scope_stats.stepHits, + RATE(stepHits, searches), RATE(stepHits, hashes), + js_scope_stats.stepMisses, + RATE(stepMisses, searches), RATE(stepMisses, hashes), + js_scope_stats.tableAllocFails, + js_scope_stats.toDictFails, + js_scope_stats.wrapWatchFails, + js_scope_stats.adds, + js_scope_stats.addFails, + js_scope_stats.puts, + js_scope_stats.redundantPuts, + js_scope_stats.putFails, + js_scope_stats.changes, + js_scope_stats.changeFails, + js_scope_stats.compresses, + js_scope_stats.grows, + js_scope_stats.removes, + js_scope_stats.removeFrees, + js_scope_stats.uselessRemoves, + js_scope_stats.shrinks); + +#undef RATE + + fflush(logfp); + } + + if (const char *filename = getenv("JS_PROPTREE_DUMPFILE")) { + char pathname[1024]; + JS_snprintf(pathname, sizeof pathname, "%s.%lu", + filename, (unsigned long)cx->runtime->gcNumber); + FILE *dumpfp = fopen(pathname, "w"); + if (dumpfp) { + PropertyRootEntry *rent = (PropertyRootEntry *) JS_PROPERTY_TREE(cx).hash.entryStore; + PropertyRootEntry *rend = rent + JS_DHASH_TABLE_SIZE(&JS_PROPERTY_TREE(cx).hash); + + while (rent < rend) { + if (rent->firstProp) { + fprintf(dumpfp, "emptyShape %u ", rent->emptyShape); + rent->firstProp->dumpSubtree(cx, 0, dumpfp); + } + rent++; + } + fclose(dumpfp); + } + } +#endif /* DEBUG */ +} diff --git a/js/src/jspropertytree.h b/js/src/jspropertytree.h new file mode 100644 index 000000000000..640325e239d3 --- /dev/null +++ b/js/src/jspropertytree.h @@ -0,0 +1,82 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */ +/* vim: set ts=40 sw=4 et tw=99: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SpiderMonkey property tree implementation + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2002-2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jspropertytree_h___ +#define jspropertytree_h___ + +#include "jsarena.h" +#include "jsdhash.h" +#include "jsprvtd.h" + +struct JSScope; + +namespace js { + +JSDHashOperator RemoveNodeIfDead(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg); + +void SweepScopeProperties(JSContext *cx); + +class PropertyTree +{ + friend struct ::JSScope; + friend void js::SweepScopeProperties(JSContext *cx); + + JSDHashTable hash; + JSScopeProperty *freeList; + JSArenaPool arenaPool; + uint32 emptyShapeChanges; + + bool insertChild(JSContext *cx, JSScopeProperty *parent, JSScopeProperty *child); + void removeChild(JSContext *cx, JSScopeProperty *child); + void emptyShapeChange(uint32 oldEmptyShape, uint32 newEmptyShape); + + public: + bool init(); + void finish(); + + JSScopeProperty *newScopeProperty(JSContext *cx, bool gcLocked = false); + + JSScopeProperty *getChild(JSContext *cx, JSScopeProperty *parent, uint32 shape, + const JSScopeProperty &child); +}; + +} /* namespace js */ + +#endif /* jspropertytree_h___ */ diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 076bbbf90bec..31ce1330b642 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -452,498 +452,6 @@ JSScope::changeTable(JSContext *cx, int change) return true; } -static JSDHashNumber -js_HashScopeProperty(JSDHashTable *table, const void *key) -{ - const JSScopeProperty *sprop = (const JSScopeProperty *)key; - return sprop->hash(); -} - -static JSBool -js_MatchScopeProperty(JSDHashTable *table, - const JSDHashEntryHdr *hdr, - const void *key) -{ - const JSPropertyTreeEntry *entry = (const JSPropertyTreeEntry *)hdr; - const JSScopeProperty *sprop = entry->child; - const JSScopeProperty *kprop = (const JSScopeProperty *)key; - - return sprop->matches(kprop); -} - -static const JSDHashTableOps PropertyTreeHashOps = { - JS_DHashAllocTable, - JS_DHashFreeTable, - js_HashScopeProperty, - js_MatchScopeProperty, - JS_DHashMoveEntryStub, - JS_DHashClearEntryStub, - JS_DHashFinalizeStub, - NULL -}; - -/* - * A property tree node on rt->propertyFreeList overlays the following prefix - * struct on JSScopeProperty. - */ -typedef struct FreeNode { - jsid id; - JSScopeProperty *next; - JSScopeProperty **prevp; -} FreeNode; - -#define FREENODE(sprop) ((FreeNode *) (sprop)) - -#define FREENODE_INSERT(list, sprop) \ - JS_BEGIN_MACRO \ - FREENODE(sprop)->next = (list); \ - FREENODE(sprop)->prevp = &(list); \ - if (list) \ - FREENODE(list)->prevp = &FREENODE(sprop)->next; \ - (list) = (sprop); \ - JS_END_MACRO - -#define FREENODE_REMOVE(sprop) \ - JS_BEGIN_MACRO \ - *FREENODE(sprop)->prevp = FREENODE(sprop)->next; \ - if (FREENODE(sprop)->next) \ - FREENODE(FREENODE(sprop)->next)->prevp = FREENODE(sprop)->prevp; \ - JS_END_MACRO - -/* NB: Called with rt->gcLock held. */ -static JSScopeProperty * -NewScopeProperty(JSRuntime *rt) -{ - JSScopeProperty *sprop; - - sprop = rt->propertyFreeList; - if (sprop) { - FREENODE_REMOVE(sprop); - } else { - JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *, - &rt->propertyArenaPool, - sizeof(JSScopeProperty)); - if (!sprop) - return NULL; - } - - JS_RUNTIME_METER(rt, livePropTreeNodes); - JS_RUNTIME_METER(rt, totalPropTreeNodes); - return sprop; -} - -#define CHUNKY_KIDS_TAG ((jsuword)1) -#define KIDS_IS_CHUNKY(kids) ((jsuword)(kids) & CHUNKY_KIDS_TAG) -#define KIDS_TO_CHUNK(kids) ((PropTreeKidsChunk *) \ - ((jsuword)(kids) & ~CHUNKY_KIDS_TAG)) -#define CHUNK_TO_KIDS(chunk) ((JSScopeProperty *) \ - ((jsuword)(chunk) | CHUNKY_KIDS_TAG)) -#define MAX_KIDS_PER_CHUNK 10 -#define CHUNK_HASH_THRESHOLD 30 - -typedef struct PropTreeKidsChunk PropTreeKidsChunk; - -struct PropTreeKidsChunk { - JSScopeProperty *kids[MAX_KIDS_PER_CHUNK]; - JSDHashTable *table; - PropTreeKidsChunk *next; -}; - -static PropTreeKidsChunk * -NewPropTreeKidsChunk(JSRuntime *rt) -{ - PropTreeKidsChunk *chunk; - - chunk = (PropTreeKidsChunk *) js_calloc(sizeof *chunk); - if (!chunk) - return NULL; - JS_ASSERT(((jsuword)chunk & CHUNKY_KIDS_TAG) == 0); - JS_RUNTIME_METER(rt, propTreeKidsChunks); - return chunk; -} - -static void -DestroyPropTreeKidsChunk(JSRuntime *rt, PropTreeKidsChunk *chunk) -{ - JS_RUNTIME_UNMETER(rt, propTreeKidsChunks); - if (chunk->table) - JS_DHashTableDestroy(chunk->table); - js_free(chunk); -} - -/* NB: Called with rt->gcLock held. */ -static bool -InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent, - JSScopeProperty *child, PropTreeKidsChunk *sweptChunk) -{ - JSDHashTable *table; - JSPropertyTreeEntry *entry; - JSScopeProperty **childp, *kids, *sprop; - PropTreeKidsChunk *chunk, **chunkp; - uintN i; - - JS_ASSERT(!parent || child->parent != parent); - JS_ASSERT(!JSVAL_IS_NULL(child->id)); - - if (!parent) { - table = &rt->propertyTreeHash; - entry = (JSPropertyTreeEntry *) - JS_DHashTableOperate(table, child, JS_DHASH_ADD); - if (!entry) - return false; - childp = &entry->child; - sprop = *childp; - if (!sprop) { - *childp = child; - } else { - /* - * A "Duplicate child" case. - * - * We can't do away with child, as at least one live scope entry - * still points at it. What's more, that scope's lastProp chains - * through an ancestor line to reach child, and js_Enumerate and - * others count on this linkage. We must leave child out of the - * hash table, and not require it to be there when we eventually - * GC it (see RemovePropertyTreeChild, below). - * - * It is necessary to leave the duplicate child out of the hash - * table to preserve entry uniqueness. It is safe to leave the - * child out of the hash table (unlike the duplicate child cases - * below), because the child's parent link will be null, which - * can't dangle. - */ - JS_ASSERT(sprop != child && sprop->matches(child)); - JS_RUNTIME_METER(rt, duplicatePropTreeNodes); - } - } else { - JS_ASSERT(!JSVAL_IS_NULL(parent->id)); - childp = &parent->kids; - kids = *childp; - if (kids) { - if (KIDS_IS_CHUNKY(kids)) { - chunk = KIDS_TO_CHUNK(kids); - - table = chunk->table; - if (table) { - entry = (JSPropertyTreeEntry *) - JS_DHashTableOperate(table, child, JS_DHASH_ADD); - if (!entry) - return false; - if (!entry->child) { - entry->child = child; - while (chunk->next) - chunk = chunk->next; - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - childp = &chunk->kids[i]; - sprop = *childp; - if (!sprop) - goto insert; - } - chunkp = &chunk->next; - goto new_chunk; - } - } - - do { - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - childp = &chunk->kids[i]; - sprop = *childp; - if (!sprop) - goto insert; - - JS_ASSERT(sprop != child); - if (sprop->matches(child)) { - /* - * Duplicate child, see comment above. In this - * case, we must let the duplicate be inserted at - * this level in the tree, so we keep iterating, - * looking for an empty slot in which to insert. - */ - JS_ASSERT(sprop != child); - JS_RUNTIME_METER(rt, duplicatePropTreeNodes); - } - } - chunkp = &chunk->next; - } while ((chunk = *chunkp) != NULL); - - new_chunk: - if (sweptChunk) { - chunk = sweptChunk; - } else { - chunk = NewPropTreeKidsChunk(rt); - if (!chunk) - return false; - } - *chunkp = chunk; - childp = &chunk->kids[0]; - } else { - sprop = kids; - JS_ASSERT(sprop != child); - if (sprop->matches(child)) { - /* - * Duplicate child, see comment above. Once again, we - * must let duplicates created by deletion pile up in a - * kids-chunk-list, in order to find them when sweeping - * and thereby avoid dangling parent pointers. - */ - JS_RUNTIME_METER(rt, duplicatePropTreeNodes); - } - if (sweptChunk) { - chunk = sweptChunk; - } else { - chunk = NewPropTreeKidsChunk(rt); - if (!chunk) - return false; - } - parent->kids = CHUNK_TO_KIDS(chunk); - chunk->kids[0] = sprop; - childp = &chunk->kids[1]; - } - } - insert: - *childp = child; - } - - child->parent = parent; - return true; -} - -/* NB: Called with rt->gcLock held. */ -static PropTreeKidsChunk * -RemovePropertyTreeChild(JSRuntime *rt, JSScopeProperty *child) -{ - PropTreeKidsChunk *freeChunk; - JSScopeProperty *parent, *kids, *kid; - JSDHashTable *table; - PropTreeKidsChunk *list, *chunk, **chunkp, *lastChunk; - uintN i, j; - JSPropertyTreeEntry *entry; - - freeChunk = NULL; - parent = child->parent; - if (!parent) { - /* - * Don't remove child if it is not in rt->propertyTreeHash, but only - * matches a root child in the table that has compatible members. See - * the "Duplicate child" comments in InsertPropertyTreeChild, above. - */ - table = &rt->propertyTreeHash; - } else { - JS_ASSERT(!JSVAL_IS_NULL(parent->id)); - kids = parent->kids; - if (KIDS_IS_CHUNKY(kids)) { - list = chunk = KIDS_TO_CHUNK(kids); - chunkp = &list; - table = chunk->table; - - do { - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - if (chunk->kids[i] == child) { - lastChunk = chunk; - if (!lastChunk->next) { - j = i + 1; - } else { - j = 0; - do { - chunkp = &lastChunk->next; - lastChunk = *chunkp; - } while (lastChunk->next); - } - for (; j < MAX_KIDS_PER_CHUNK; j++) { - if (!lastChunk->kids[j]) - break; - } - --j; - if (chunk != lastChunk || j > i) - chunk->kids[i] = lastChunk->kids[j]; - lastChunk->kids[j] = NULL; - if (j == 0) { - *chunkp = NULL; - if (!list) - parent->kids = NULL; - freeChunk = lastChunk; - } - goto out; - } - } - - chunkp = &chunk->next; - } while ((chunk = *chunkp) != NULL); - } else { - table = NULL; - kid = kids; - if (kid == child) - parent->kids = NULL; - } - } - -out: - if (table) { - entry = (JSPropertyTreeEntry *) - JS_DHashTableOperate(table, child, JS_DHASH_LOOKUP); - - if (entry->child == child) - JS_DHashTableRawRemove(table, &entry->hdr); - } - return freeChunk; -} - -static JSDHashTable * -HashChunks(PropTreeKidsChunk *chunk, uintN n) -{ - JSDHashTable *table; - uintN i; - JSScopeProperty *sprop; - JSPropertyTreeEntry *entry; - - table = JS_NewDHashTable(&PropertyTreeHashOps, NULL, - sizeof(JSPropertyTreeEntry), - JS_DHASH_DEFAULT_CAPACITY(n + 1)); - if (!table) - return NULL; - do { - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - sprop = chunk->kids[i]; - if (!sprop) - break; - entry = (JSPropertyTreeEntry *) - JS_DHashTableOperate(table, sprop, JS_DHASH_ADD); - entry->child = sprop; - } - } while ((chunk = chunk->next) != NULL); - return table; -} - -/* - * Called without cx->runtime->gcLock held. This function acquires that lock - * only when inserting a new child. Thus there may be races to find or add a - * node that result in duplicates. We expect such races to be rare! - * - * We use rt->gcLock, not rt->rtLock, to avoid nesting the former inside the - * latter in js_GenerateShape below. - */ -JSScopeProperty * -js_GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent, - const JSScopeProperty &child) -{ - JSRuntime *rt; - JSDHashTable *table; - JSPropertyTreeEntry *entry; - JSScopeProperty *sprop; - PropTreeKidsChunk *chunk; - uintN i, n; - - rt = cx->runtime; - if (!parent) { - JS_LOCK_GC(rt); - - table = &rt->propertyTreeHash; - entry = (JSPropertyTreeEntry *) - JS_DHashTableOperate(table, &child, JS_DHASH_ADD); - if (!entry) - goto out_of_memory; - - sprop = entry->child; - if (sprop) - goto out; - } else { - JS_ASSERT(!JSVAL_IS_NULL(parent->id)); - - /* - * Because chunks are appended at the end and never deleted except by - * the GC, we can search without taking the runtime's GC lock. We may - * miss a matching sprop added by another thread, and make a duplicate - * one, but that is an unlikely, therefore small, cost. The property - * tree has extremely low fan-out below its root in popular embeddings - * with real-world workloads. - * - * Patterns such as defining closures that capture a constructor's - * environment as getters or setters on the new object that is passed - * in as |this| can significantly increase fan-out below the property - * tree root -- see bug 335700 for details. - */ - entry = NULL; - sprop = parent->kids; - if (sprop) { - if (KIDS_IS_CHUNKY(sprop)) { - chunk = KIDS_TO_CHUNK(sprop); - - table = chunk->table; - if (table) { - JS_LOCK_GC(rt); - entry = (JSPropertyTreeEntry *) - JS_DHashTableOperate(table, &child, JS_DHASH_LOOKUP); - sprop = entry->child; - if (sprop) - goto out; - goto locked_not_found; - } - - n = 0; - do { - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - sprop = chunk->kids[i]; - if (!sprop) { - n += i; - if (n >= CHUNK_HASH_THRESHOLD) { - chunk = KIDS_TO_CHUNK(parent->kids); - if (!chunk->table) { - table = HashChunks(chunk, n); - JS_LOCK_GC(rt); - if (!table) - goto out_of_memory; - if (chunk->table) - JS_DHashTableDestroy(table); - else - chunk->table = table; - goto locked_not_found; - } - } - goto not_found; - } - - if (sprop->matches(&child)) - return sprop; - } - n += MAX_KIDS_PER_CHUNK; - } while ((chunk = chunk->next) != NULL); - } else { - if (sprop->matches(&child)) - return sprop; - } - } - - not_found: - JS_LOCK_GC(rt); - } - -locked_not_found: - sprop = NewScopeProperty(rt); - if (!sprop) - goto out_of_memory; - - new(sprop) JSScopeProperty(child.id, child.rawGetter, child.rawSetter, child.slot, - child.attrs, child.flags, child.shortid); - sprop->parent = sprop->kids = NULL; - sprop->shape = js_GenerateShape(cx, true); - - if (!parent) { - entry->child = sprop; - } else { - if (!InsertPropertyTreeChild(rt, parent, sprop, NULL)) - goto out_of_memory; - } - - out: - JS_UNLOCK_GC(rt); - return sprop; - - out_of_memory: - JS_UNLOCK_GC(rt); - JS_ReportOutOfMemory(cx); - return NULL; -} - /* * Get or create a property-tree or dictionary child property of parent, which * must be lastProp if inDictionaryMode(), else parent must be one of lastProp @@ -988,7 +496,7 @@ JSScope::getChildProperty(JSContext *cx, JSScopeProperty *parent, return NULL; } - JSScopeProperty *sprop = js_GetPropertyTreeChild(cx, parent, child); + JSScopeProperty *sprop = JS_PROPERTY_TREE(cx).getChild(cx, parent, shape, child); if (sprop) { JS_ASSERT(sprop->parent == parent); if (parent == lastProp) { @@ -1092,13 +600,9 @@ JSScopeProperty * JSScope::newDictionaryProperty(JSContext *cx, const JSScopeProperty &child, JSScopeProperty **childp) { - JS_LOCK_GC(cx->runtime); - JSScopeProperty *dprop = NewScopeProperty(cx->runtime); - JS_UNLOCK_GC(cx->runtime); - if (!dprop) { - JS_ReportOutOfMemory(cx); + JSScopeProperty *dprop = JS_PROPERTY_TREE(cx).newScopeProperty(cx); + if (!dprop) return NULL; - } new (dprop) JSScopeProperty(child.id, child.rawGetter, child.rawSetter, child.slot, child.attrs, child.flags | JSScopeProperty::IN_DICTIONARY, @@ -1612,12 +1116,6 @@ JSScope::clear(JSContext *cx) JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals); } -void -JSScope::brandingShapeChange(JSContext *cx, uint32 slot, jsval v) -{ - generateOwnShape(cx); -} - void JSScope::deletingShapeChange(JSContext *cx, JSScopeProperty *sprop) { @@ -1677,12 +1175,6 @@ JSScope::protoShapeChange(JSContext *cx) generateOwnShape(cx); } -void -JSScope::sealingShapeChange(JSContext *cx) -{ - generateOwnShape(cx); -} - void JSScope::shadowingShapeChange(JSContext *cx, JSScopeProperty *sprop) { @@ -1770,428 +1262,3 @@ JSScopeProperty::trace(JSTracer *trc) js_CallGCMarker(trc, methodObject(), JSTRACE_OBJECT); } } - -#ifdef DEBUG - -static void -MeterKidCount(JSBasicStats *bs, uintN nkids) -{ - JS_BASIC_STATS_ACCUM(bs, nkids); - bs->hist[JS_MIN(nkids, 10)]++; -} - -static void -MeterPropertyTree(JSBasicStats *bs, JSScopeProperty *node) -{ - uintN i, nkids; - JSScopeProperty *kids, *kid; - PropTreeKidsChunk *chunk; - - nkids = 0; - kids = node->kids; - if (kids) { - if (KIDS_IS_CHUNKY(kids)) { - for (chunk = KIDS_TO_CHUNK(kids); chunk; chunk = chunk->next) { - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - kid = chunk->kids[i]; - if (!kid) - break; - MeterPropertyTree(bs, kid); - nkids++; - } - } - } else { - MeterPropertyTree(bs, kids); - nkids = 1; - } - } - - MeterKidCount(bs, nkids); -} - -static JSDHashOperator -js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, - void *arg) -{ - JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *)hdr; - JSBasicStats *bs = (JSBasicStats *)arg; - - MeterPropertyTree(bs, entry->child); - return JS_DHASH_NEXT; -} - -void -JSScopeProperty::dump(JSContext *cx, FILE *fp) -{ - JS_ASSERT(!JSVAL_IS_NULL(id)); - - jsval idval = ID_TO_VALUE(id); - if (JSVAL_IS_INT(idval)) { - fprintf(fp, "[%ld]", (long) JSVAL_TO_INT(idval)); - } else { - JSString *str; - if (JSVAL_IS_STRING(idval)) { - str = JSVAL_TO_STRING(idval); - } else { - JS_ASSERT(JSVAL_IS_OBJECT(idval)); - str = js_ValueToString(cx, idval); - fputs("object ", fp); - } - if (!str) - fputs("", fp); - else - js_FileEscapedString(fp, str, '"'); - } - - fprintf(fp, " g/s %p/%p slot %u attrs %x ", - JS_FUNC_TO_DATA_PTR(void *, rawGetter), - JS_FUNC_TO_DATA_PTR(void *, rawSetter), - slot, attrs); - if (attrs) { - int first = 1; - fputs("(", fp); -#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(" " #display + first, fp), first = 0 - DUMP_ATTR(ENUMERATE, enumerate); - DUMP_ATTR(READONLY, readonly); - DUMP_ATTR(PERMANENT, permanent); - DUMP_ATTR(GETTER, getter); - DUMP_ATTR(SETTER, setter); - DUMP_ATTR(SHARED, shared); -#undef DUMP_ATTR - fputs(") ", fp); - } - - fprintf(fp, "flags %x ", flags); - if (flags) { - int first = 1; - fputs("(", fp); -#define DUMP_FLAG(name, display) if (flags & name) fputs(" " #display + first, fp), first = 0 - DUMP_FLAG(ALIAS, alias); - DUMP_FLAG(HAS_SHORTID, has_shortid); - DUMP_FLAG(METHOD, method); - DUMP_FLAG(MARK, mark); - DUMP_FLAG(SHAPE_REGEN, shape_regen); - DUMP_FLAG(IN_DICTIONARY, in_dictionary); -#undef DUMP_FLAG - fputs(") ", fp); - } - - fprintf(fp, "shortid %d\n", shortid); -} - -void -JSScopeProperty::dumpSubtree(JSContext *cx, int level, FILE *fp) -{ - fprintf(fp, "%*sid ", level, ""); - dump(cx, fp); - - if (kids) { - ++level; - if (KIDS_IS_CHUNKY(kids)) { - PropTreeKidsChunk *chunk = KIDS_TO_CHUNK(kids); - do { - for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - JSScopeProperty *kid = chunk->kids[i]; - if (!kid) - break; - JS_ASSERT(kid->parent == this); - kid->dumpSubtree(cx, level, fp); - } - } while ((chunk = chunk->next) != NULL); - } else { - JSScopeProperty *kid = kids; - JS_ASSERT(kid->parent == this); - kid->dumpSubtree(cx, level, fp); - } - } -} - -#endif /* DEBUG */ - -void -js_SweepScopeProperties(JSContext *cx) -{ - JSRuntime *rt = cx->runtime; - JSArena **ap, *a; - JSScopeProperty *limit, *sprop, *parent, *kids, *kid; - uintN liveCount; - PropTreeKidsChunk *chunk, *nextChunk, *freeChunk; - uintN i; - -#ifdef DEBUG - JSBasicStats bs; - uint32 livePropCapacity = 0, totalLiveCount = 0; - static FILE *logfp; - if (!logfp) { - if (const char *filename = getenv("JS_PROPTREE_STATFILE")) - logfp = fopen(filename, "w"); - } - - if (logfp) { - JS_BASIC_STATS_INIT(&bs); - MeterKidCount(&bs, rt->propertyTreeHash.entryCount); - JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, &bs); - - double props, nodes, mean, sigma; - - props = rt->liveScopePropsPreSweep; - nodes = rt->livePropTreeNodes; - JS_ASSERT(nodes == bs.sum); - mean = JS_MeanAndStdDevBS(&bs, &sigma); - - fprintf(logfp, - "props %g nodes %g beta %g meankids %g sigma %g max %u\n", - props, nodes, nodes / props, mean, sigma, bs.max); - - JS_DumpHistogram(&bs, logfp); - } -#endif - - ap = &rt->propertyArenaPool.first.next; - while ((a = *ap) != NULL) { - limit = (JSScopeProperty *) a->avail; - liveCount = 0; - for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) { - /* If the id is null, sprop is already on the freelist. */ - if (sprop->id == JSVAL_NULL) - continue; - - /* - * If the mark bit is set, sprop is alive, so clear the mark bit - * and continue the while loop. - * - * Regenerate sprop->shape if it hasn't already been refreshed - * during the mark phase, when live scopes' lastProp members are - * followed to update both scope->shape and lastProp->shape. - */ - if (sprop->marked()) { - sprop->clearMark(); - if (rt->gcRegenShapes) { - if (sprop->hasRegenFlag()) - sprop->clearRegenFlag(); - else - sprop->shape = js_RegenerateShapeForGC(cx); - } - liveCount++; - continue; - } - - if (!sprop->inDictionary()) { - /* Ok, sprop is garbage to collect: unlink it from its parent. */ - freeChunk = RemovePropertyTreeChild(rt, sprop); - - /* - * Take care to reparent all sprop's kids to their grandparent. - * InsertPropertyTreeChild can potentially fail for two reasons: - * - * 1. If parent is null, insertion into the root property hash - * table may fail. We are forced to leave the kid out of the - * table (as can already happen with duplicates) but ensure - * that the kid's parent pointer is set to null. - * - * 2. If parent is non-null, allocation of a new KidsChunk can - * fail. To prevent this from happening, we allow sprops's own - * chunks to be reused by the grandparent, which removes the - * need for InsertPropertyTreeChild to malloc a new KidsChunk. - * - * If sprop does not have chunky kids, then we rely on the - * RemovePropertyTreeChild call above (which removed sprop from - * its parent) either leaving one free entry, or else returning - * the now-unused chunk to us so we can reuse it. - * - * We also require the grandparent to have either no kids or else - * chunky kids. A single non-chunky kid would force a new chunk to - * be malloced in some cases (if sprop had a single non-chunky - * kid, or a multiple of MAX_KIDS_PER_CHUNK kids). Note that - * RemovePropertyTreeChild never converts a single-entry chunky - * kid back to a non-chunky kid, so we are assured of correct - * behaviour. - */ - kids = sprop->kids; - if (kids) { - sprop->kids = NULL; - parent = sprop->parent; - - /* The grandparent must have either no kids or chunky kids. */ - JS_ASSERT(!parent || !parent->kids || - KIDS_IS_CHUNKY(parent->kids)); - if (KIDS_IS_CHUNKY(kids)) { - chunk = KIDS_TO_CHUNK(kids); - do { - nextChunk = chunk->next; - chunk->next = NULL; - for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { - kid = chunk->kids[i]; - if (!kid) - break; - JS_ASSERT(kid->parent == sprop); - - /* - * Clear a space in the kids array for possible - * re-use by InsertPropertyTreeChild. - */ - chunk->kids[i] = NULL; - if (!InsertPropertyTreeChild(rt, parent, kid, chunk)) { - /* - * This can happen only if we failed to add an - * entry to the root property hash table. - */ - JS_ASSERT(!parent); - kid->parent = NULL; - } - } - if (!chunk->kids[0]) { - /* The chunk wasn't reused, so we must free it. */ - DestroyPropTreeKidsChunk(rt, chunk); - } - } while ((chunk = nextChunk) != NULL); - } else { - kid = kids; - if (!InsertPropertyTreeChild(rt, parent, kid, freeChunk)) { - /* - * This can happen only if we failed to add an entry - * to the root property hash table. - */ - JS_ASSERT(!parent); - kid->parent = NULL; - } - } - } - - if (freeChunk && !freeChunk->kids[0]) { - /* The chunk wasn't reused, so we must free it. */ - DestroyPropTreeKidsChunk(rt, freeChunk); - } - } - - /* Clear id so we know (above) that sprop is on the freelist. */ - sprop->id = JSVAL_NULL; - FREENODE_INSERT(rt->propertyFreeList, sprop); - JS_RUNTIME_UNMETER(rt, livePropTreeNodes); - } - - /* If a contains no live properties, return it to the malloc heap. */ - if (liveCount == 0) { - for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) - FREENODE_REMOVE(sprop); - JS_ARENA_DESTROY(&rt->propertyArenaPool, a, ap); - } else { -#ifdef DEBUG - livePropCapacity += limit - (JSScopeProperty *) a->base; - totalLiveCount += liveCount; -#endif - ap = &a->next; - } - } - -#ifdef DEBUG - if (logfp) { - fprintf(logfp, - "\nProperty tree stats for gcNumber %lu\n", - (unsigned long) rt->gcNumber); - - fprintf(logfp, "arenautil %g%%\n", - (totalLiveCount && livePropCapacity) - ? (totalLiveCount * 100.0) / livePropCapacity - : 0.0); - -#define RATE(f1, f2) (((double)js_scope_stats.f1 / js_scope_stats.f2) * 100.0) - - fprintf(logfp, - "Scope search stats:\n" - " searches: %6u\n" - " hits: %6u %5.2f%% of searches\n" - " misses: %6u %5.2f%%\n" - " hashes: %6u %5.2f%%\n" - " steps: %6u %5.2f%% %5.2f%% of hashes\n" - " stepHits: %6u %5.2f%% %5.2f%%\n" - " stepMisses: %6u %5.2f%% %5.2f%%\n" - " tableAllocFails %6u\n" - " toDictFails %6u\n" - " wrapWatchFails %6u\n" - " adds: %6u\n" - " addFails: %6u\n" - " puts: %6u\n" - " redundantPuts: %6u\n" - " putFails: %6u\n" - " changes: %6u\n" - " changeFails: %6u\n" - " compresses: %6u\n" - " grows: %6u\n" - " removes: %6u\n" - " removeFrees: %6u\n" - " uselessRemoves: %6u\n" - " shrinks: %6u\n", - js_scope_stats.searches, - js_scope_stats.hits, RATE(hits, searches), - js_scope_stats.misses, RATE(misses, searches), - js_scope_stats.hashes, RATE(hashes, searches), - js_scope_stats.steps, RATE(steps, searches), RATE(steps, hashes), - js_scope_stats.stepHits, - RATE(stepHits, searches), RATE(stepHits, hashes), - js_scope_stats.stepMisses, - RATE(stepMisses, searches), RATE(stepMisses, hashes), - js_scope_stats.tableAllocFails, - js_scope_stats.toDictFails, - js_scope_stats.wrapWatchFails, - js_scope_stats.adds, - js_scope_stats.addFails, - js_scope_stats.puts, - js_scope_stats.redundantPuts, - js_scope_stats.putFails, - js_scope_stats.changes, - js_scope_stats.changeFails, - js_scope_stats.compresses, - js_scope_stats.grows, - js_scope_stats.removes, - js_scope_stats.removeFrees, - js_scope_stats.uselessRemoves, - js_scope_stats.shrinks); - -#undef RATE - - fflush(logfp); - } - - if (const char *filename = getenv("JS_PROPTREE_DUMPFILE")) { - char pathname[1024]; - JS_snprintf(pathname, sizeof pathname, "%s.%lu", filename, (unsigned long)rt->gcNumber); - FILE *dumpfp = fopen(pathname, "w"); - if (dumpfp) { - JSPropertyTreeEntry *pte, *end; - - pte = (JSPropertyTreeEntry *) rt->propertyTreeHash.entryStore; - end = pte + JS_DHASH_TABLE_SIZE(&rt->propertyTreeHash); - while (pte < end) { - if (pte->child) - pte->child->dumpSubtree(cx, 0, dumpfp); - pte++; - } - fclose(dumpfp); - } - } -#endif /* DEBUG */ -} - -bool -js_InitPropertyTree(JSRuntime *rt) -{ - if (!JS_DHashTableInit(&rt->propertyTreeHash, &PropertyTreeHashOps, NULL, - sizeof(JSPropertyTreeEntry), JS_DHASH_MIN_SIZE)) { - rt->propertyTreeHash.ops = NULL; - return false; - } - JS_InitArenaPool(&rt->propertyArenaPool, "properties", - 256 * sizeof(JSScopeProperty), sizeof(void *), NULL); - return true; -} - -void -js_FinishPropertyTree(JSRuntime *rt) -{ - if (rt->propertyTreeHash.ops) { - JS_DHashTableFinish(&rt->propertyTreeHash); - rt->propertyTreeHash.ops = NULL; - } - JS_FinishArenaPool(&rt->propertyArenaPool); -} diff --git a/js/src/jsscope.h b/js/src/jsscope.h index a2a11529eecb..b70071b28d4a 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -204,6 +204,10 @@ JS_BEGIN_EXTERN_C * is added that crosses the threshold of 6 or more entries for hashing, we use * linear search from scope->lastProp to find a given id, and save on the space * overhead of a hash table. + * + * See jspropertytree.{h,cpp} for the actual PropertyTree implementation. This + * file contains object property map (historical misnomer: "scope" AKA JSScope) + * and property tree node ("sprop", JSScopeProperty) declarations. */ struct JSEmptyScope; @@ -361,12 +365,10 @@ struct JSScope : public JSObjectMap void trace(JSTracer *trc); - void brandingShapeChange(JSContext *cx, uint32 slot, jsval v); void deletingShapeChange(JSContext *cx, JSScopeProperty *sprop); bool methodShapeChange(JSContext *cx, JSScopeProperty *sprop, jsval toval); bool methodShapeChange(JSContext *cx, uint32 slot, jsval toval); void protoShapeChange(JSContext *cx); - void sealingShapeChange(JSContext *cx); void shadowingShapeChange(JSContext *cx, JSScopeProperty *sprop); /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */ @@ -400,8 +402,11 @@ struct JSScope : public JSObjectMap * sealed. */ bool sealed() { return flags & SEALED; } - void setSealed() { + + void seal(JSContext *cx) { JS_ASSERT(!isSharedEmpty()); + JS_ASSERT(!sealed()); + generateOwnShape(cx); flags |= SEALED; } @@ -411,7 +416,15 @@ struct JSScope : public JSObjectMap * evolves whenever a function value changes. */ bool branded() { JS_ASSERT(!generic()); return flags & BRANDED; } - void setBranded() { flags |= BRANDED; } + + bool brand(JSContext *cx, uint32 slot, jsval v) { + JS_ASSERT(!branded()); + generateOwnShape(cx); + if (js_IsPropertyCacheDisabled(cx)) // check for rt->shapeGen overflow + return false; + flags |= BRANDED; + return true; + } bool generic() { return flags & GENERIC; } void setGeneric() { flags |= GENERIC; } @@ -554,23 +567,28 @@ js_CastAsObjectJSVal(JSPropertyOp op) return OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, op)); } +namespace js { +class PropertyTree; +} + struct JSScopeProperty { friend struct JSScope; - friend void js_SweepScopeProperties(JSContext *cx); - friend JSScopeProperty * js_GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent, - const JSScopeProperty &child); + friend class js::PropertyTree; + friend JSDHashOperator js::RemoveNodeIfDead(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg); + friend void js::SweepScopeProperties(JSContext *cx); jsid id; /* int-tagged jsval/untagged JSAtom* */ -private: + private: JSPropertyOp rawGetter; /* getter and setter hooks or objects */ JSPropertyOp rawSetter; /* getter is JSObject* and setter is 0 if sprop->isMethod() */ -public: + public: uint32 slot; /* abstract index in object slots */ -private: + private: uint8 attrs; /* attributes, see jsapi.h JSPROP_* */ uint8 flags; /* flags, see below for defines */ -public: + public: int16 shortid; /* tinyid, or local arg/var index */ JSScopeProperty *parent; /* parent node, reverse for..in order */ union { @@ -583,21 +601,25 @@ public: }; uint32 shape; /* property cache shape identifier */ -private: - /* Implementation-private bits stored in sprop->flags. */ + private: + /* + * Implementation-private bits stored in sprop->flags. See public: enum {} + * flags further below, which were allocated FCFS over time, so interleave + * with these bits. + */ enum { /* GC mark flag. */ - MARK = 0x01, + MARK = 0x01, /* * Set during a shape-regenerating GC if the shape has already been * regenerated. Unlike JSScope::SHAPE_REGEN, this does not toggle with - * each GC. js_SweepScopeProperties clears it. + * each GC. js::SweepScopeProperties clears it. */ - SHAPE_REGEN = 0x08, + SHAPE_REGEN = 0x08, /* Property stored in per-object dictionary, not shared property tree. */ - IN_DICTIONARY = 0x20 + IN_DICTIONARY = 0x20 }; JSScopeProperty(jsid id, JSPropertyOp getter, JSPropertyOp setter, uint32 slot, @@ -621,13 +643,13 @@ private: bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; } -public: + public: /* Public bits stored in sprop->flags. */ enum { - ALIAS = 0x02, - HAS_SHORTID = 0x04, - METHOD = 0x10, - PUBLIC_FLAGS = ALIAS | HAS_SHORTID | METHOD + ALIAS = 0x02, + HAS_SHORTID = 0x04, + METHOD = 0x10, + PUBLIC_FLAGS = ALIAS | HAS_SHORTID | METHOD }; uintN getFlags() const { return flags & PUBLIC_FLAGS; } @@ -682,6 +704,8 @@ public: bool get(JSContext* cx, JSObject* obj, JSObject *pobj, jsval* vp); bool set(JSContext* cx, JSObject* obj, jsval* vp); + inline bool isSharedPermanent() const; + void trace(JSTracer *trc); bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; } @@ -896,6 +920,12 @@ JSScope::search(jsid id, bool adding) inline bool JSScope::canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp) { + /* + * An empty scope cannot provide another empty scope, or wrongful two-level + * prototype shape sharing ensues -- see bug 497789. + */ + if (!object) + return false; return this->ops == ops && (!emptyScope || emptyScope->clasp == clasp); } @@ -949,11 +979,10 @@ JSScopeProperty::set(JSContext* cx, JSObject* obj, jsval* vp) return setterOp()(cx, obj, SPROP_USERID(this), vp); } -/* Macro for common expression to test for shared permanent attributes. */ inline bool -SPROP_IS_SHARED_PERMANENT(JSScopeProperty *sprop) +JSScopeProperty::isSharedPermanent() const { - return !sprop->hasSlot() && !sprop->configurable(); + return (~attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0; } extern JSScope * @@ -962,15 +991,6 @@ js_GetMutableScope(JSContext *cx, JSObject *obj); extern void js_TraceId(JSTracer *trc, jsid id); -extern void -js_SweepScopeProperties(JSContext *cx); - -extern bool -js_InitPropertyTree(JSRuntime *rt); - -extern void -js_FinishPropertyTree(JSRuntime *rt); - JS_END_EXTERN_C #ifdef _MSC_VER diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index ba0fbc71935d..395bb20028af 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -163,6 +163,7 @@ JSScope::trace(JSTracer *trc) JSContext *cx = trc->context; JSScopeProperty *sprop = lastProp; uint8 regenFlag = cx->runtime->gcRegenShapesScopeFlag; + if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes && !hasRegenFlag(regenFlag)) { /* * Either this scope has its own shape, which must be regenerated, or @@ -184,14 +185,20 @@ JSScope::trace(JSTracer *trc) shape = newShape; flags ^= JSScope::SHAPE_REGEN; - /* Also regenerate the shapes of empty scopes, in case they are not shared. */ - for (JSScope *empty = emptyScope; - empty && !empty->hasRegenFlag(regenFlag); - empty = empty->emptyScope) { - empty->shape = js_RegenerateShapeForGC(cx); - empty->flags ^= JSScope::SHAPE_REGEN; + /* Also regenerate the shapes of this scope's empty scope, if there is one. */ + JSScope *empty = emptyScope; + if (empty) { + JS_ASSERT(!empty->emptyScope); + if (!empty->hasRegenFlag(regenFlag)) { + uint32 newEmptyShape = js_RegenerateShapeForGC(cx); + + JS_PROPERTY_TREE(cx).emptyShapeChange(empty->shape, newEmptyShape); + empty->shape = newEmptyShape; + empty->flags ^= JSScope::SHAPE_REGEN; + } } } + if (sprop) { JS_ASSERT(hasProperty(sprop)); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index a40a8a27872c..73da3900bcb1 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -5193,20 +5193,27 @@ TraceRecorder::checkTraceEnd(jsbytecode *pc) return ARECORD_CONTINUE; } -bool -TraceRecorder::hasMethod(JSObject* obj, jsid id) +RecordingStatus +TraceRecorder::hasMethod(JSObject* obj, jsid id, bool& found) { + found = false; + RecordingStatus status = RECORD_CONTINUE; if (!obj) - return false; + return status; JSObject* pobj; JSProperty* prop; int protoIndex = obj->lookupProperty(cx, id, &pobj, &prop); - if (protoIndex < 0 || !prop) - return false; + if (protoIndex < 0) + return RECORD_ERROR; + if (!prop) + return status; - bool found = false; - if (OBJ_IS_NATIVE(pobj)) { + if (!OBJ_IS_NATIVE(pobj)) { + // We can't rely on __iterator__ being present on trace just because + // it's there now, if found in a non-native object. + status = RECORD_STOP; + } else { JSScope* scope = OBJ_SCOPE(pobj); JSScopeProperty* sprop = (JSScopeProperty*) prop; @@ -5214,24 +5221,22 @@ TraceRecorder::hasMethod(JSObject* obj, jsid id) jsval v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); if (VALUE_IS_FUNCTION(cx, v)) { found = true; - if (!scope->generic() && !scope->branded()) { - scope->brandingShapeChange(cx, sprop->slot, v); - scope->setBranded(); - } + if (!scope->generic() && !scope->branded() && !scope->brand(cx, sprop->slot, v)) + status = RECORD_STOP; } } } pobj->dropProperty(cx, prop); - return found; + return status; } -JS_REQUIRES_STACK bool -TraceRecorder::hasIteratorMethod(JSObject* obj) +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::hasIteratorMethod(JSObject* obj, bool& found) { JS_ASSERT(cx->fp->regs->sp + 2 <= cx->fp->slots + cx->fp->script->nslots); - return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom)); + return hasMethod(obj, ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom), found); } /* @@ -9167,7 +9172,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 RETURN_STOP_A("property found on non-native object"); } entry = js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, - (JSScopeProperty*) prop, false); + (JSScopeProperty*) prop); JS_ASSERT(entry); if (entry == JS_NO_PROP_CACHE_FILL) entry = NULL; @@ -9214,60 +9219,36 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, uint32 vshape = PCVCAP_SHAPE(entry->vcap); - // Check for first-level cache hit and guard on kshape if possible. - // Otherwise guard on key object exact match. - if (PCVCAP_TAG(entry->vcap) <= 1) { - // Special case for the global object, which may be aliased to get a property value. - // To catch cross-global property accesses we must check against globalObj identity. - // But a JOF_NAME mode opcode needs no guard, as we ensure the global object's shape - // never changes, and name ops can't reach across a global object ('with' aborts). - if (aobj == globalObj) { - if (entry->adding()) - RETURN_STOP("adding a property to the global object"); + // Special case for the global object, which may be aliased to get a property value. + // To catch cross-global property accesses we must check against globalObj identity. + // But a JOF_NAME mode opcode needs no guard, as we ensure the global object's shape + // never changes, and name ops can't reach across a global object ('with' aborts). + if (aobj == globalObj) { + if (entry->adding()) + RETURN_STOP("adding a property to the global object"); - JSOp op = js_GetOpcode(cx, cx->fp->script, cx->fp->regs->pc); - if (JOF_OPMODE(op) != JOF_NAME) { - guard(true, - addName(lir->ins2(LIR_peq, obj_ins, INS_CONSTOBJ(globalObj)), "guard_global"), - exit); - } - } else { - CHECK_STATUS(guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", map_ins, exit)); - } - - if (entry->adding()) { - LIns *vshape_ins = addName( - lir->insLoad(LIR_ld, - addName(lir->insLoad(LIR_ldp, cx_ins, - offsetof(JSContext, runtime), ACC_READONLY), - "runtime"), - offsetof(JSRuntime, protoHazardShape)), - "protoHazardShape"); - guard(true, - addName(lir->ins2i(LIR_eq, vshape_ins, vshape), "guard_protoHazardShape"), - MISMATCH_EXIT); - } - } else { JSOp op = js_GetOpcode(cx, cx->fp->script, cx->fp->regs->pc); - -#ifdef DEBUG - JSAtom *pcatom; - if (op == JSOP_LENGTH) { - pcatom = cx->runtime->atomState.lengthAtom; - } else { - ptrdiff_t pcoff = (JOF_TYPE(js_CodeSpec[op].format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; - GET_ATOM_FROM_BYTECODE(cx->fp->script, cx->fp->regs->pc, pcoff, pcatom); - } - JS_ASSERT(entry->kpc == (jsbytecode *) pcatom); - JS_ASSERT(entry->kshape == jsuword(aobj)); -#endif - - // See above comment about globalObj and JOF_NAME. - if (!obj_ins->isconstp() && (aobj != globalObj || JOF_OPMODE(op) != JOF_NAME)) { + if (JOF_OPMODE(op) != JOF_NAME) { guard(true, - addName(lir->ins2(LIR_peq, obj_ins, INS_CONSTOBJ(aobj)), "guard_kobj"), + addName(lir->ins2(LIR_peq, obj_ins, INS_CONSTOBJ(globalObj)), "guard_global"), exit); } + } else { + CHECK_STATUS(guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", map_ins, exit)); + } + + if (entry->adding()) { + LIns *vshape_ins = addName( + lir->insLoad(LIR_ld, + addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, runtime), + ACC_READONLY), + "runtime"), + offsetof(JSRuntime, protoHazardShape)), + "protoHazardShape"); + + guard(true, + addName(lir->ins2i(LIR_eq, vshape_ins, vshape), "guard_protoHazardShape"), + MISMATCH_EXIT); } // For any hit that goes up the scope and/or proto chains, we will need to @@ -13452,7 +13433,11 @@ TraceRecorder::record_JSOP_ITER() jsuint flags = cx->fp->regs->pc[1]; - if (hasIteratorMethod(JSVAL_TO_OBJECT(v))) { + bool found; + RecordingStatus status = hasIteratorMethod(JSVAL_TO_OBJECT(v), found); + if (status != RECORD_CONTINUE) + return InjectStatus(status); + if (found) { if (flags == JSITER_ENUMERATE) return InjectStatus(call_imacro(iter_imacros.for_in)); if (flags == (JSITER_ENUMERATE | JSITER_FOREACH)) diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 924bdc209b4c..081e6d9ac235 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1353,8 +1353,8 @@ class TraceRecorder JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x); JS_REQUIRES_STACK AbortableRecordingStatus checkTraceEnd(jsbytecode* pc); - bool hasMethod(JSObject* obj, jsid id); - JS_REQUIRES_STACK bool hasIteratorMethod(JSObject* obj); + RecordingStatus hasMethod(JSObject* obj, jsid id, bool& found); + JS_REQUIRES_STACK RecordingStatus hasIteratorMethod(JSObject* obj, bool& found); JS_REQUIRES_STACK jsatomid getFullIndex(ptrdiff_t pcoff = 0); diff --git a/js/src/tests/js1_5/Regress/jstests.list b/js/src/tests/js1_5/Regress/jstests.list index 1c8c0458a158..d0f2a22420b0 100644 --- a/js/src/tests/js1_5/Regress/jstests.list +++ b/js/src/tests/js1_5/Regress/jstests.list @@ -347,7 +347,7 @@ script regress-482421.js script regress-482783.js script regress-483103.js script regress-501124.js -skip script regress-503860.js # waiting for bug 497789 to be fixed +script regress-503860.js script regress-504078.js script regress-506567.js script regress-511859.js From 950558fb84b3b936fde8cce0ddf8e60ecbd98d87 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 22 Mar 2010 11:48:22 -0700 Subject: [PATCH 101/213] Fix ARM-only typo in nanojit merge (NB: NOT being simultaneously merged to nanojit-central out of expediency). r=sparky --- js/src/nanojit/NativeARM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index 482b9a8b7fac..bd21e5512e5c 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -863,7 +863,7 @@ Assembler::asm_call(LInsp ins) // for floating point calls, but not for integer calls. if (_config.arm_vfp && ins->isUsed()) { // Determine the size (and type) of the instruction result. - ArgType rsize = (ArgType)(ci->_typesig & ARGTYPE_MASK_ANY); + ArgType rsize = (ArgType)(ci->_typesig & ARGTYPE_MASK); // If the result size is a floating-point value, treat the result // specially, as described previously. From 08b3093d1f5139a4480c839d46d4fac195aca298 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 22 Mar 2010 11:56:59 -0700 Subject: [PATCH 102/213] Another try at getting a symbolicated build from tinderbox...words cannot express my feelings on this matter at this point. --- configure.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.in b/configure.in index fc6ed433076e..2623cded13c1 100644 --- a/configure.in +++ b/configure.in @@ -7082,6 +7082,8 @@ MOZ_ARG_ENABLE_BOOL(install-strip, PKG_SKIP_STRIP= , PKG_SKIP_STRIP=1) +PKG_SKIP_STRIP=1 + dnl ======================================================== dnl = --enable-elf-dynstr-gc dnl ======================================================== From b53d61798fe0baa49c94aa9fe00bcea2392529d9 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 22 Mar 2010 15:28:25 -0700 Subject: [PATCH 103/213] Force ARM builds to be debug to really, really get symbols this time, for realz. r= --- configure.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.in b/configure.in index 2623cded13c1..51997a211a2a 100644 --- a/configure.in +++ b/configure.in @@ -6662,6 +6662,10 @@ MOZ_ARG_ENABLE_STRING(debug, fi ], MOZ_DEBUG=) +if test $MOZ_PLATFORM_MAEMO; then + MOZ_DEBUG=1 +fi + MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -D_DEBUG" case "${target_os}" in beos*) From 97e00c4aead8a4402666089453c131d97b2eee40 Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Mon, 22 Mar 2010 16:26:28 -0700 Subject: [PATCH 104/213] Followup fix for 497789: work around apparent gcc 4.4 aliasing bug (r=dvander). --- js/src/jspropertytree.cpp | 51 ++++++--------------------------------- js/src/jsscope.h | 30 +++++++++++++++++++++-- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index d90386845ca5..608f42ab57ee 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -146,42 +146,6 @@ PropertyTree::finish() JS_FinishArenaPool(&arenaPool); } -/* - * A property tree node on PropertyTree::freeList overlays the following prefix - * struct on JSScopeProperty. - */ -typedef struct FreeNode { - jsid id; - FreeNode *next; - FreeNode **prevp; - - void insert(FreeNode *&list) { - next = list; - prevp = &list; - if (list) - list->prevp = &next; - list = this; - } - - void remove() { - *prevp = next; - if (next) - next->prevp = prevp; - } -} FreeNode; - -#define FREENODE(sprop) ((FreeNode *) (sprop)) - -#define FREENODE_INSERT(list, sprop) \ - JS_BEGIN_MACRO \ - union { FreeNode *fn; JSScopeProperty *sp; } u; \ - u.fn = (FreeNode *)(list); \ - FREENODE(sprop)->insert(u.fn); \ - JS_END_MACRO - -#define FREENODE_REMOVE(sprop) \ - (FREENODE(sprop)->remove()) - /* * NB: Called with cx->runtime->gcLock held if gcLocked is true. * On failure, return null after unlocking the GC and reporting out of memory. @@ -195,7 +159,7 @@ PropertyTree::newScopeProperty(JSContext *cx, bool gcLocked) JS_LOCK_GC(cx->runtime); sprop = freeList; if (sprop) { - FREENODE_REMOVE(sprop); + sprop->removeFree(); } else { JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *, &arenaPool, sizeof(JSScopeProperty)); @@ -795,9 +759,6 @@ js::RemoveNodeIfDead(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, v void js::SweepScopeProperties(JSContext *cx) { - JS_STATIC_ASSERT(offsetof(FreeNode, id) == offsetof(JSScopeProperty, id)); - JS_STATIC_ASSERT(sizeof(FreeNode) >= offsetof(JSScopeProperty, slot)); - #ifdef DEBUG JSBasicStats bs; uint32 livePropCapacity = 0, totalLiveCount = 0; @@ -939,16 +900,18 @@ js::SweepScopeProperties(JSContext *cx) OrphanNodeKids(cx, sprop); } - /* Clear id so we know (above) that sprop is on the freelist. */ - sprop->id = JSVAL_NULL; - FREENODE_INSERT(JS_PROPERTY_TREE(cx).freeList, sprop); + /* + * Note that JSScopeProperty::insertFree nulls sprop->id so we know + * that sprop is on the freelist. + */ + sprop->insertFree(JS_PROPERTY_TREE(cx).freeList); JS_RUNTIME_UNMETER(cx->runtime, livePropTreeNodes); } /* If a contains no live properties, return it to the malloc heap. */ if (liveCount == 0) { for (JSScopeProperty *sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) - FREENODE_REMOVE(sprop); + sprop->removeFree(); JS_ARENA_DESTROY(&JS_PROPERTY_TREE(cx).arenaPool, a, ap); } else { #ifdef DEBUG diff --git a/js/src/jsscope.h b/js/src/jsscope.h index b70071b28d4a..03b6388b784f 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -579,10 +579,36 @@ struct JSScopeProperty { friend void js::SweepScopeProperties(JSContext *cx); jsid id; /* int-tagged jsval/untagged JSAtom* */ + private: - JSPropertyOp rawGetter; /* getter and setter hooks or objects */ - JSPropertyOp rawSetter; /* getter is JSObject* and setter is 0 + union { + JSPropertyOp rawGetter; /* getter and setter hooks or objects */ + JSScopeProperty *next; /* next node in freelist */ + }; + + union { + JSPropertyOp rawSetter; /* getter is JSObject* and setter is 0 if sprop->isMethod() */ + JSScopeProperty **prevp; /* pointer to previous node's next, or + pointer to head of freelist */ + }; + + void insertFree(JSScopeProperty *&list) { + id = JSVAL_NULL; + next = list; + prevp = &list; + if (list) + list->prevp = &next; + list = this; + } + + void removeFree() { + JS_ASSERT(JSVAL_IS_NULL(id)); + *prevp = next; + if (next) + next->prevp = prevp; + } + public: uint32 slot; /* abstract index in object slots */ private: From 3a474f4952b203b5726ef317c82b1214c0211cfa Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Mon, 22 Mar 2010 16:43:08 -0700 Subject: [PATCH 105/213] Bug 542858 - Don't pretend that the complex global object is a function. r=jorendorff --- js/src/shell/js.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 3f94007f9965..0bf794cd8b21 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2773,6 +2773,8 @@ split_getObjectOps(JSContext *cx, JSClass *clasp) if (!split_objectops.thisObject) { memcpy(&split_objectops, &js_ObjectOps, sizeof split_objectops); split_objectops.thisObject = split_thisObject; + split_objectops.call = NULL; + split_objectops.construct = NULL; } return &split_objectops; From cb0809fc8c40eb97430c87d9c3e035a6446a3897 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 22 Mar 2010 18:40:05 -0700 Subject: [PATCH 106/213] Sigh, js has its own configure.in that needs identical changes, doesn't it... --HG-- extra : rebase_source : 4da0033e802042771e0a94f0d5216bafd979bdb4 --- js/src/configure.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/src/configure.in b/js/src/configure.in index f5350af9a502..f4f505b6b948 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -3989,6 +3989,10 @@ MOZ_ARG_ENABLE_STRING(debug, fi ], MOZ_DEBUG=) +if test $MOZ_PLATFORM_MAEMO; then + MOZ_DEBUG=1 +fi + MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -D_DEBUG" case "${target_os}" in beos*) @@ -4336,6 +4340,8 @@ MOZ_ARG_ENABLE_BOOL(install-strip, PKG_SKIP_STRIP= , PKG_SKIP_STRIP=1) +PKG_SKIP_STRIP=1 + dnl ======================================================== dnl = dnl = Profiling and Instrumenting From daf778e0c8bcfe752f2a1ca1c32016851f41f88a Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 22 Mar 2010 20:02:07 -0700 Subject: [PATCH 107/213] Allocate short strings in the GC heap, avoiding malloc + free (553541, r=igor). --- js/src/jsgc.cpp | 29 ++++++++++++++++---- js/src/jsgc.h | 9 +++++++ js/src/jsnum.cpp | 6 ++--- js/src/jsstr.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ js/src/jsstr.h | 22 ++++++++++++--- 5 files changed, 123 insertions(+), 12 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 82a450da4f17..6fc6d50c08f3 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -757,6 +757,7 @@ GetFinalizableThingSize(unsigned thingKind) #if JS_HAS_XML_SUPPORT sizeof(JSXML), /* FINALIZE_XML */ #endif + sizeof(JSShortString), /* FINALIZE_SHORT_STRING */ sizeof(JSString), /* FINALIZE_STRING */ sizeof(JSString), /* FINALIZE_EXTERNAL_STRING0 */ sizeof(JSString), /* FINALIZE_EXTERNAL_STRING1 */ @@ -780,10 +781,11 @@ GetFinalizableTraceKind(size_t thingKind) static const uint8 map[FINALIZE_LIMIT] = { JSTRACE_OBJECT, /* FINALIZE_OBJECT */ JSTRACE_OBJECT, /* FINALIZE_FUNCTION */ -#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */ - JSTRACE_XML, -#endif /* FINALIZE_STRING */ - JSTRACE_STRING, +#if JS_HAS_XML_SUPPORT + JSTRACE_XML, /* FINALIZE_XML */ +#endif + JSTRACE_STRING, /* FINALIZE_SHORT_STRING */ + JSTRACE_STRING, /* FINALIZE_STRING */ JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING0 */ JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING1 */ JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING2 */ @@ -866,7 +868,7 @@ js_GetGCStringRuntime(JSString *str) JS_ASSERT(list->thingSize == sizeof(JSString)); unsigned i = list->thingKind; - JS_ASSERT(i == FINALIZE_STRING || + JS_ASSERT(i == FINALIZE_STRING || i == FINALIZE_SHORT_STRING || (FINALIZE_EXTERNAL_STRING0 <= i && i < FINALIZE_EXTERNAL_STRING0 + JS_EXTERNAL_STRING_LIMIT)); return (JSRuntime *)((uint8 *)(list - i) - @@ -985,6 +987,7 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) #if JS_HAS_XML_SUPPORT "xml", #endif + "short_string", "string", "external_string_0", "external_string_1", @@ -2334,6 +2337,7 @@ JSWeakRoots::mark(JSTracer *trc) #if JS_HAS_XML_SUPPORT "newborn_xml", /* FINALIZE_XML */ #endif + "newborn_short_string", /* FINALIZE_SHORT_STRING */ "newborn_string", /* FINALIZE_STRING */ "newborn_external_string0", /* FINALIZE_EXTERNAL_STRING0 */ "newborn_external_string1", /* FINALIZE_EXTERNAL_STRING1 */ @@ -2606,6 +2610,18 @@ js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, return -1; } +inline void +FinalizeShortString(JSContext *cx, JSShortString *str, unsigned thingKind) +{ + JS_ASSERT(FINALIZE_SHORT_STRING == thingKind); + JS_ASSERT(!JSString::isStatic(&str->header)); + JS_RUNTIME_UNMETER(cx->runtime, liveStrings); + if (str->header.isDependent()) { + JS_ASSERT(str->header.dependentBase()); + JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings); + } +} + inline void FinalizeString(JSContext *cx, JSString *str, unsigned thingKind) { @@ -2662,6 +2678,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str) } else { unsigned thingKind = JSGCArena::fromGCThing(str)->info.list->thingKind; JS_ASSERT(IsFinalizableStringKind(thingKind)); + JS_ASSERT(thingKind != FINALIZE_SHORT_STRING); /* A stillborn string has null chars, so is not valid. */ jschar *chars = str->flatChars(); @@ -3196,6 +3213,8 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) */ rt->deflatedStringCache->sweep(cx); + FinalizeArenaList + (cx, FINALIZE_SHORT_STRING, &emptyArenas); FinalizeArenaList (cx, FINALIZE_STRING, &emptyArenas); for (unsigned i = FINALIZE_EXTERNAL_STRING0; diff --git a/js/src/jsgc.h b/js/src/jsgc.h index d7726d8b960c..6d33ff9549ff 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -244,6 +244,7 @@ enum JSFinalizeGCThingKind { #if JS_HAS_XML_SUPPORT FINALIZE_XML, #endif + FINALIZE_SHORT_STRING, FINALIZE_STRING, FINALIZE_EXTERNAL_STRING0, FINALIZE_EXTERNAL_STRING1, @@ -285,6 +286,14 @@ js_NewGCString(JSContext *cx) return (JSString *) js_NewFinalizableGCThing(cx, FINALIZE_STRING); } +struct JSShortString; + +static inline JSShortString * +js_NewGCShortString(JSContext *cx) +{ + return (JSShortString *) js_NewFinalizableGCThing(cx, FINALIZE_SHORT_STRING); +} + static inline JSString * js_NewGCExternalString(JSContext *cx, uintN type) { diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 119a0705c7bb..22c1327df7bc 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -327,7 +327,7 @@ num_toSource(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr); - str = JS_NewStringCopyZ(cx, buf); + str = js_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; *vp = STRING_TO_JSVAL(str); @@ -589,7 +589,7 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, JS_ReportOutOfMemory(cx); return JS_FALSE; } - str = JS_NewStringCopyZ(cx, numStr); + str = js_NewStringCopyZ(cx, numStr); if (!str) return JS_FALSE; *vp = STRING_TO_JSVAL(str); @@ -892,7 +892,7 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) numStr = NumberToCString(cx, d, base, buf, sizeof buf); if (!numStr) return NULL; - s = JS_NewStringCopyZ(cx, numStr); + s = js_NewStringCopyZ(cx, numStr); if (!(numStr >= buf && numStr < buf + sizeof buf)) js_free(numStr); return s; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 04bc452a6438..520e9c6f1ea6 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3110,6 +3110,49 @@ js_NewString(JSContext *cx, jschar *chars, size_t length) return str; } +static bool +FitsIntoShortString(size_t length) +{ + return length < sizeof JSString / sizeof jschar; +} + +JSString * +NewShortString(JSContext *cx, const jschar *chars, size_t length) +{ + JS_ASSERT(FitsIntoShortString(length)); + JSShortString *str = js_NewGCShortString(cx); + if (!str) + return NULL; + jschar *storage = &str->data[0]; + memcpy(storage, chars, sizeof(jschar) * length); + storage[length] = 0; + str->header.initFlat(storage, length); + return &str->header; +} + +JSString * +NewShortString(JSContext *cx, const char *chars, size_t length) +{ + JS_ASSERT(FitsIntoShortString(length)); + JSShortString *str = js_NewGCShortString(cx); + if (!str) + return NULL; + jschar *storage = &str->data[0]; + if (js_CStringsAreUTF8) { + if (!js_InflateStringToBuffer(cx, chars, length, NULL, &length)) + return NULL; + storage[length] = 0; + } else { + size_t n = length; + jschar *p = storage; + while (n-- > 0) + *p++ = jschar(*chars++); + *p = 0; + } + str->header.initFlat(storage, length); + return &str->header; +} + static const size_t sMinWasteSize = 16; JSString * @@ -3204,6 +3247,9 @@ void printJSStringStats(JSRuntime *rt) JSString * js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n) { + if (FitsIntoShortString(n)) + return NewShortString(cx, s, n); + jschar *news; JSString *str; @@ -3218,6 +3264,19 @@ js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n) return str; } +JSString * +js_NewStringCopyN(JSContext *cx, const char *s, size_t n) +{ + /* + * For simplicity, if UTF8 encoding is enabled, we assume conservatively + * that the length of the decided string is less or equal to the number + * of bytes. + */ + if (FitsIntoShortString(n)) + return NewShortString(cx, s, n); + return JS_NewStringCopyN(cx, s, n); +} + JSString * js_NewStringCopyZ(JSContext *cx, const jschar *s) { @@ -3226,6 +3285,10 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s) JSString *str; n = js_strlen(s); + + if (FitsIntoShortString(n)) + return NewShortString(cx, s, n); + m = (n + 1) * sizeof(jschar); news = (jschar *) cx->malloc(m); if (!news) @@ -3237,6 +3300,12 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s) return str; } +JSString * +js_NewStringCopyZ(JSContext *cx, const char *s) +{ + return js_NewStringCopyN(cx, s, strlen(s)); +} + JS_FRIEND_API(const char *) js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun) { diff --git a/js/src/jsstr.h b/js/src/jsstr.h index a11c513801d3..178fc2f01158 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -54,8 +54,6 @@ #include "jshashtable.h" #include "jslock.h" -JS_BEGIN_EXTERN_C - #define JSSTRING_BIT(n) ((size_t)1 << (n)) #define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1) @@ -300,6 +298,14 @@ struct JSString { static JSString *intString(jsint i); }; +struct JSShortString { + JSString header; + union { + JSString dummy; + jschar data[1]; + }; +}; + extern const jschar * js_GetStringChars(JSContext *cx, JSString *str); @@ -473,9 +479,13 @@ JS_ISSPACE(jschar c) /* Initialize the String class, returning its prototype object. */ extern JSClass js_StringClass; +JS_BEGIN_EXTERN_C + extern JSObject * js_InitStringClass(JSContext *cx, JSObject *obj); +JS_END_EXTERN_C + extern const char js_escape_str[]; extern const char js_unescape_str[]; extern const char js_uneval_str[]; @@ -504,10 +514,16 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start, extern JSString * js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n); +extern JSString * +js_NewStringCopyN(JSContext *cx, const char *s, size_t n); + /* Copy a C string and GC-allocate a descriptor for it. */ extern JSString * js_NewStringCopyZ(JSContext *cx, const jschar *s); +extern JSString * +js_NewStringCopyZ(JSContext *cx, const char *s); + /* * Convert a value to a printable C string. */ @@ -691,8 +707,6 @@ js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, extern JSBool js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); -JS_END_EXTERN_C - namespace js { class DeflatedStringCache { From 8945bea7ffd2f273f4ac7a60a7e7b488403165f1 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 22 Mar 2010 20:15:08 -0700 Subject: [PATCH 108/213] nobody ever got hurt by too much parenthesis in expressions (build fix follow-up for 553541) --- js/src/jsstr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 520e9c6f1ea6..a8f56f164d2b 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3113,7 +3113,7 @@ js_NewString(JSContext *cx, jschar *chars, size_t length) static bool FitsIntoShortString(size_t length) { - return length < sizeof JSString / sizeof jschar; + return length < sizeof(JSString) / sizeof(jschar); } JSString * From c61b56b63efe51098f465e2a0241beffedd2d805 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 22 Mar 2010 20:58:49 -0700 Subject: [PATCH 109/213] more build fun with bug 553541 --- js/src/jsatom.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 4cb934caa176..1a92ade3b72f 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -461,6 +461,8 @@ js_FinishCommonAtoms(JSContext *cx); extern JSAtom * js_AtomizeDouble(JSContext *cx, jsdouble d); +JS_END_EXTERN_C + /* * Find or create the atom for a string. Return null on failure to allocate * memory. @@ -468,6 +470,8 @@ js_AtomizeDouble(JSContext *cx, jsdouble d); extern JSAtom * js_AtomizeString(JSContext *cx, JSString *str, uintN flags); +JS_BEGIN_EXTERN_C + extern JSAtom * js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags); From 6f3eea8a6ae1acf4df97627bf1535cf3f1f39bc5 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 22 Mar 2010 22:39:29 -0700 Subject: [PATCH 110/213] Back out 38cb39bc6744, 400097fb04e7, and 1dca6e135a1e for great orangeness. --- js/src/jsatom.h | 4 --- js/src/jsgc.cpp | 29 ++++---------------- js/src/jsgc.h | 9 ------- js/src/jsnum.cpp | 6 ++--- js/src/jsstr.cpp | 69 ------------------------------------------------ js/src/jsstr.h | 22 +++------------ 6 files changed, 12 insertions(+), 127 deletions(-) diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 1a92ade3b72f..4cb934caa176 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -461,8 +461,6 @@ js_FinishCommonAtoms(JSContext *cx); extern JSAtom * js_AtomizeDouble(JSContext *cx, jsdouble d); -JS_END_EXTERN_C - /* * Find or create the atom for a string. Return null on failure to allocate * memory. @@ -470,8 +468,6 @@ JS_END_EXTERN_C extern JSAtom * js_AtomizeString(JSContext *cx, JSString *str, uintN flags); -JS_BEGIN_EXTERN_C - extern JSAtom * js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 6fc6d50c08f3..82a450da4f17 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -757,7 +757,6 @@ GetFinalizableThingSize(unsigned thingKind) #if JS_HAS_XML_SUPPORT sizeof(JSXML), /* FINALIZE_XML */ #endif - sizeof(JSShortString), /* FINALIZE_SHORT_STRING */ sizeof(JSString), /* FINALIZE_STRING */ sizeof(JSString), /* FINALIZE_EXTERNAL_STRING0 */ sizeof(JSString), /* FINALIZE_EXTERNAL_STRING1 */ @@ -781,11 +780,10 @@ GetFinalizableTraceKind(size_t thingKind) static const uint8 map[FINALIZE_LIMIT] = { JSTRACE_OBJECT, /* FINALIZE_OBJECT */ JSTRACE_OBJECT, /* FINALIZE_FUNCTION */ -#if JS_HAS_XML_SUPPORT - JSTRACE_XML, /* FINALIZE_XML */ -#endif - JSTRACE_STRING, /* FINALIZE_SHORT_STRING */ - JSTRACE_STRING, /* FINALIZE_STRING */ +#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */ + JSTRACE_XML, +#endif /* FINALIZE_STRING */ + JSTRACE_STRING, JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING0 */ JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING1 */ JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING2 */ @@ -868,7 +866,7 @@ js_GetGCStringRuntime(JSString *str) JS_ASSERT(list->thingSize == sizeof(JSString)); unsigned i = list->thingKind; - JS_ASSERT(i == FINALIZE_STRING || i == FINALIZE_SHORT_STRING || + JS_ASSERT(i == FINALIZE_STRING || (FINALIZE_EXTERNAL_STRING0 <= i && i < FINALIZE_EXTERNAL_STRING0 + JS_EXTERNAL_STRING_LIMIT)); return (JSRuntime *)((uint8 *)(list - i) - @@ -987,7 +985,6 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) #if JS_HAS_XML_SUPPORT "xml", #endif - "short_string", "string", "external_string_0", "external_string_1", @@ -2337,7 +2334,6 @@ JSWeakRoots::mark(JSTracer *trc) #if JS_HAS_XML_SUPPORT "newborn_xml", /* FINALIZE_XML */ #endif - "newborn_short_string", /* FINALIZE_SHORT_STRING */ "newborn_string", /* FINALIZE_STRING */ "newborn_external_string0", /* FINALIZE_EXTERNAL_STRING0 */ "newborn_external_string1", /* FINALIZE_EXTERNAL_STRING1 */ @@ -2610,18 +2606,6 @@ js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, return -1; } -inline void -FinalizeShortString(JSContext *cx, JSShortString *str, unsigned thingKind) -{ - JS_ASSERT(FINALIZE_SHORT_STRING == thingKind); - JS_ASSERT(!JSString::isStatic(&str->header)); - JS_RUNTIME_UNMETER(cx->runtime, liveStrings); - if (str->header.isDependent()) { - JS_ASSERT(str->header.dependentBase()); - JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings); - } -} - inline void FinalizeString(JSContext *cx, JSString *str, unsigned thingKind) { @@ -2678,7 +2662,6 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str) } else { unsigned thingKind = JSGCArena::fromGCThing(str)->info.list->thingKind; JS_ASSERT(IsFinalizableStringKind(thingKind)); - JS_ASSERT(thingKind != FINALIZE_SHORT_STRING); /* A stillborn string has null chars, so is not valid. */ jschar *chars = str->flatChars(); @@ -3213,8 +3196,6 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) */ rt->deflatedStringCache->sweep(cx); - FinalizeArenaList - (cx, FINALIZE_SHORT_STRING, &emptyArenas); FinalizeArenaList (cx, FINALIZE_STRING, &emptyArenas); for (unsigned i = FINALIZE_EXTERNAL_STRING0; diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 6d33ff9549ff..d7726d8b960c 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -244,7 +244,6 @@ enum JSFinalizeGCThingKind { #if JS_HAS_XML_SUPPORT FINALIZE_XML, #endif - FINALIZE_SHORT_STRING, FINALIZE_STRING, FINALIZE_EXTERNAL_STRING0, FINALIZE_EXTERNAL_STRING1, @@ -286,14 +285,6 @@ js_NewGCString(JSContext *cx) return (JSString *) js_NewFinalizableGCThing(cx, FINALIZE_STRING); } -struct JSShortString; - -static inline JSShortString * -js_NewGCShortString(JSContext *cx) -{ - return (JSShortString *) js_NewFinalizableGCThing(cx, FINALIZE_SHORT_STRING); -} - static inline JSString * js_NewGCExternalString(JSContext *cx, uintN type) { diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 22c1327df7bc..119a0705c7bb 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -327,7 +327,7 @@ num_toSource(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr); - str = js_NewStringCopyZ(cx, buf); + str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; *vp = STRING_TO_JSVAL(str); @@ -589,7 +589,7 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, JS_ReportOutOfMemory(cx); return JS_FALSE; } - str = js_NewStringCopyZ(cx, numStr); + str = JS_NewStringCopyZ(cx, numStr); if (!str) return JS_FALSE; *vp = STRING_TO_JSVAL(str); @@ -892,7 +892,7 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) numStr = NumberToCString(cx, d, base, buf, sizeof buf); if (!numStr) return NULL; - s = js_NewStringCopyZ(cx, numStr); + s = JS_NewStringCopyZ(cx, numStr); if (!(numStr >= buf && numStr < buf + sizeof buf)) js_free(numStr); return s; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index a8f56f164d2b..04bc452a6438 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3110,49 +3110,6 @@ js_NewString(JSContext *cx, jschar *chars, size_t length) return str; } -static bool -FitsIntoShortString(size_t length) -{ - return length < sizeof(JSString) / sizeof(jschar); -} - -JSString * -NewShortString(JSContext *cx, const jschar *chars, size_t length) -{ - JS_ASSERT(FitsIntoShortString(length)); - JSShortString *str = js_NewGCShortString(cx); - if (!str) - return NULL; - jschar *storage = &str->data[0]; - memcpy(storage, chars, sizeof(jschar) * length); - storage[length] = 0; - str->header.initFlat(storage, length); - return &str->header; -} - -JSString * -NewShortString(JSContext *cx, const char *chars, size_t length) -{ - JS_ASSERT(FitsIntoShortString(length)); - JSShortString *str = js_NewGCShortString(cx); - if (!str) - return NULL; - jschar *storage = &str->data[0]; - if (js_CStringsAreUTF8) { - if (!js_InflateStringToBuffer(cx, chars, length, NULL, &length)) - return NULL; - storage[length] = 0; - } else { - size_t n = length; - jschar *p = storage; - while (n-- > 0) - *p++ = jschar(*chars++); - *p = 0; - } - str->header.initFlat(storage, length); - return &str->header; -} - static const size_t sMinWasteSize = 16; JSString * @@ -3247,9 +3204,6 @@ void printJSStringStats(JSRuntime *rt) JSString * js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n) { - if (FitsIntoShortString(n)) - return NewShortString(cx, s, n); - jschar *news; JSString *str; @@ -3264,19 +3218,6 @@ js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n) return str; } -JSString * -js_NewStringCopyN(JSContext *cx, const char *s, size_t n) -{ - /* - * For simplicity, if UTF8 encoding is enabled, we assume conservatively - * that the length of the decided string is less or equal to the number - * of bytes. - */ - if (FitsIntoShortString(n)) - return NewShortString(cx, s, n); - return JS_NewStringCopyN(cx, s, n); -} - JSString * js_NewStringCopyZ(JSContext *cx, const jschar *s) { @@ -3285,10 +3226,6 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s) JSString *str; n = js_strlen(s); - - if (FitsIntoShortString(n)) - return NewShortString(cx, s, n); - m = (n + 1) * sizeof(jschar); news = (jschar *) cx->malloc(m); if (!news) @@ -3300,12 +3237,6 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s) return str; } -JSString * -js_NewStringCopyZ(JSContext *cx, const char *s) -{ - return js_NewStringCopyN(cx, s, strlen(s)); -} - JS_FRIEND_API(const char *) js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun) { diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 178fc2f01158..a11c513801d3 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -54,6 +54,8 @@ #include "jshashtable.h" #include "jslock.h" +JS_BEGIN_EXTERN_C + #define JSSTRING_BIT(n) ((size_t)1 << (n)) #define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1) @@ -298,14 +300,6 @@ struct JSString { static JSString *intString(jsint i); }; -struct JSShortString { - JSString header; - union { - JSString dummy; - jschar data[1]; - }; -}; - extern const jschar * js_GetStringChars(JSContext *cx, JSString *str); @@ -479,13 +473,9 @@ JS_ISSPACE(jschar c) /* Initialize the String class, returning its prototype object. */ extern JSClass js_StringClass; -JS_BEGIN_EXTERN_C - extern JSObject * js_InitStringClass(JSContext *cx, JSObject *obj); -JS_END_EXTERN_C - extern const char js_escape_str[]; extern const char js_unescape_str[]; extern const char js_uneval_str[]; @@ -514,16 +504,10 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start, extern JSString * js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n); -extern JSString * -js_NewStringCopyN(JSContext *cx, const char *s, size_t n); - /* Copy a C string and GC-allocate a descriptor for it. */ extern JSString * js_NewStringCopyZ(JSContext *cx, const jschar *s); -extern JSString * -js_NewStringCopyZ(JSContext *cx, const char *s); - /* * Convert a value to a printable C string. */ @@ -707,6 +691,8 @@ js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, extern JSBool js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +JS_END_EXTERN_C + namespace js { class DeflatedStringCache { From c7c48f027566398eb440a471ba1fef5e4a8a21c6 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 22 Mar 2010 22:17:57 -0700 Subject: [PATCH 111/213] Zillionth time's the charm. --- js/src/configure.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/src/configure.in b/js/src/configure.in index f4f505b6b948..58015b4f169f 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -3975,6 +3975,11 @@ then esac fi +MOZ_ARG_WITH_STRING(maemo-version, +[ --with-maemo-version=MOZ_PLATFORM_MAEMO + Maemo SDK Version], + MOZ_PLATFORM_MAEMO=$withval) + MOZ_ARG_ENABLE_STRING(debug, [ --enable-debug[=DBG] Enable building with developer debug info (Using compiler flags DBG)], From 1df3de2336bbdc6f6a033278b1e50654c0c3aba1 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 22 Mar 2010 18:21:10 -0500 Subject: [PATCH 112/213] Bug 509857 - Get rid of DTOA_LOCK. r=jwalden. --HG-- extra : rebase_source : bec4d9441aa2af8488a04aa8604a65b7387cda6d --- js/src/dtoa.c | 348 +++++++++++++++++++++++++++----------------- js/src/jsapi.cpp | 6 +- js/src/jscntxt.cpp | 16 +- js/src/jscntxt.h | 6 +- js/src/jsdate.cpp | 2 +- js/src/jsdtoa.cpp | 135 +++++++---------- js/src/jsdtoa.h | 43 +++--- js/src/jsnum.cpp | 23 +-- js/src/json.cpp | 3 +- js/src/jsopcode.cpp | 3 +- 10 files changed, 323 insertions(+), 262 deletions(-) diff --git a/js/src/dtoa.c b/js/src/dtoa.c index 8d7352a635d7..76fc8cf08e62 100644 --- a/js/src/dtoa.c +++ b/js/src/dtoa.c @@ -101,9 +101,10 @@ * directly -- and assumed always to succeed. Similarly, if you * want something other than the system's free() to be called to * recycle memory acquired from MALLOC, #define FREE to be the - * name of the alternate routine. (FREE or free is only called in - * pathological cases, e.g., in a dtoa call after a dtoa return in - * mode 3 with thousands of digits requested.) + * name of the alternate routine. (Unless you #define + * NO_GLOBAL_STATE and call destroydtoa, FREE or free is only + * called in pathological cases, e.g., in a dtoa call after a dtoa + * return in mode 3 with thousands of digits requested.) * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, @@ -164,6 +165,12 @@ * inexact or when it is a numeric value rounded to +-infinity). * #define NO_ERRNO if strtod should not assign errno = ERANGE when * the result overflows to +-Infinity or underflows to 0. + * #define NO_GLOBAL_STATE to avoid defining any non-const global or + * static variables. Instead the necessary state is stored in an + * opaque struct, DtoaState, a pointer to which must be passed to + * every entry point. Two new functions are added to the API: + * DtoaState *newdtoa(void); + * void destroydtoa(DtoaState *); */ #ifndef Long @@ -195,12 +202,15 @@ extern void *MALLOC(size_t); #define MALLOC malloc #endif +#ifndef FREE +#define FREE free +#endif + #ifndef Omit_Private_Memory #ifndef PRIVATE_MEM #define PRIVATE_MEM 2304 #endif #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #endif #undef IEEE_Arith @@ -479,14 +489,87 @@ Bigint { typedef struct Bigint Bigint; - static Bigint *freelist[Kmax+1]; +#ifdef NO_GLOBAL_STATE +#ifdef MULTIPLE_THREADS +#error "cannot have both NO_GLOBAL_STATE and MULTIPLE_THREADS" +#endif + struct +DtoaState { +#define DECLARE_GLOBAL_STATE /* nothing */ +#else +#define DECLARE_GLOBAL_STATE static +#endif + + DECLARE_GLOBAL_STATE Bigint *freelist[Kmax+1]; + DECLARE_GLOBAL_STATE Bigint *p5s; +#ifndef Omit_Private_Memory + DECLARE_GLOBAL_STATE double private_mem[PRIVATE_mem]; + DECLARE_GLOBAL_STATE double *pmem_next +#ifndef NO_GLOBAL_STATE + = private_mem +#endif + ; +#endif +#ifdef NO_GLOBAL_STATE + }; + typedef struct DtoaState DtoaState; +#ifdef KR_headers +#define STATE_PARAM state, +#define STATE_PARAM_DECL DtoaState *state; +#else +#define STATE_PARAM DtoaState *state, +#endif +#define PASS_STATE state, +#define GET_STATE(field) (state->field) + + static DtoaState * +newdtoa(void) +{ + DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState)); + if (state) { + memset(state, 0, sizeof(DtoaState)); + state->pmem_next = state->private_mem; + } + return state; +} + + static void +destroydtoa +#ifdef KR_headers + (state) STATE_PARAM_DECL +#else + (DtoaState *state) +#endif +{ + int i; + Bigint *v, *next; + + for (i = 0; i <= Kmax; i++) { + for (v = GET_STATE(freelist)[i]; v; v = next) { + next = v->next; +#ifndef Omit_Private_Memory + if ((double*)v < GET_STATE(private_mem) || + (double*)v >= GET_STATE(private_mem) + PRIVATE_mem) +#endif + FREE((void*)v); + } + } + FREE((void *)state); +} + +#else +#define STATE_PARAM /* nothing */ +#define STATE_PARAM_DECL /* nothing */ +#define PASS_STATE /* nothing */ +#define GET_STATE(name) name +#endif static Bigint * Balloc #ifdef KR_headers - (k) int k; + (STATE_PARAM k) STATE_PARAM_DECL int k; #else - (int k) + (STATE_PARAM int k) #endif { int x; @@ -498,8 +581,8 @@ Balloc ACQUIRE_DTOA_LOCK(0); /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ /* but this case seems very unlikely. */ - if (k <= Kmax && (rv = freelist[k])) - freelist[k] = rv->next; + if (k <= Kmax && (rv = GET_STATE(freelist)[k])) + GET_STATE(freelist)[k] = rv->next; else { x = 1 << k; #ifdef Omit_Private_Memory @@ -507,9 +590,9 @@ Balloc #else len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); - if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { - rv = (Bigint*)pmem_next; - pmem_next += len; + if (k <= Kmax && GET_STATE(pmem_next) - GET_STATE(private_mem) + len <= PRIVATE_mem) { + rv = (Bigint*)GET_STATE(pmem_next); + GET_STATE(pmem_next) += len; } else rv = (Bigint*)MALLOC(len*sizeof(double)); @@ -525,22 +608,18 @@ Balloc static void Bfree #ifdef KR_headers - (v) Bigint *v; + (STATE_PARAM v) STATE_PARAM_DECL Bigint *v; #else - (Bigint *v) + (STATE_PARAM Bigint *v) #endif { if (v) { if (v->k > Kmax) -#ifdef FREE FREE((void*)v); -#else - free((void*)v); -#endif else { ACQUIRE_DTOA_LOCK(0); - v->next = freelist[v->k]; - freelist[v->k] = v; + v->next = GET_STATE(freelist)[v->k]; + GET_STATE(freelist)[v->k] = v; FREE_DTOA_LOCK(0); } } @@ -552,9 +631,9 @@ y->wds*sizeof(Long) + 2*sizeof(int)) static Bigint * multadd #ifdef KR_headers - (b, m, a) Bigint *b; int m, a; + (STATE_PARAM b, m, a) STATE_PARAM_DECL Bigint *b; int m, a; #else - (Bigint *b, int m, int a) /* multiply by m and add a */ + (STATE_PARAM Bigint *b, int m, int a) /* multiply by m and add a */ #endif { int i, wds; @@ -595,9 +674,9 @@ multadd while(++i < wds); if (carry) { if (wds >= b->maxwds) { - b1 = Balloc(b->k+1); + b1 = Balloc(PASS_STATE b->k+1); Bcopy(b1, b); - Bfree(b); + Bfree(PASS_STATE b); b = b1; } b->x[wds++] = (ULong) carry; @@ -609,9 +688,9 @@ multadd static Bigint * s2b #ifdef KR_headers - (s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9; + (STATE_PARAM s, nd0, nd, y9) STATE_PARAM_DECL CONST char *s; int nd0, nd; ULong y9; #else - (CONST char *s, int nd0, int nd, ULong y9) + (STATE_PARAM CONST char *s, int nd0, int nd, ULong y9) #endif { Bigint *b; @@ -621,11 +700,11 @@ s2b x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 - b = Balloc(k); + b = Balloc(PASS_STATE k); b->x[0] = y9; b->wds = 1; #else - b = Balloc(k+1); + b = Balloc(PASS_STATE k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif @@ -633,14 +712,14 @@ s2b i = 9; if (9 < nd0) { s += 9; - do b = multadd(b, 10, *s++ - '0'); + do b = multadd(PASS_STATE b, 10, *s++ - '0'); while(++i < nd0); s++; } else s += 10; for(; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); + b = multadd(PASS_STATE b, 10, *s++ - '0'); return b; } @@ -729,14 +808,14 @@ lo0bits static Bigint * i2b #ifdef KR_headers - (i) int i; + (STATE_PARAM i) STATE_PARAM_DECL int i; #else - (int i) + (STATE_PARAM int i) #endif { Bigint *b; - b = Balloc(1); + b = Balloc(PASS_STATE 1); b->x[0] = i; b->wds = 1; return b; @@ -745,9 +824,9 @@ i2b static Bigint * mult #ifdef KR_headers - (a, b) Bigint *a, *b; + (STATE_PARAM a, b) STATE_PARAM_DECL Bigint *a, *b; #else - (Bigint *a, Bigint *b) + (STATE_PARAM Bigint *a, Bigint *b) #endif { Bigint *c; @@ -774,7 +853,7 @@ mult wc = wa + wb; if (wc > a->maxwds) k++; - c = Balloc(k); + c = Balloc(PASS_STATE k); for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; @@ -852,26 +931,24 @@ mult return c; } - static Bigint *p5s; - static Bigint * pow5mult #ifdef KR_headers - (b, k) Bigint *b; int k; + (STATE_PARAM b, k) STATE_PARAM_DECL Bigint *b; int k; #else - (Bigint *b, int k) + (STATE_PARAM Bigint *b, int k) #endif { Bigint *b1, *p5, *p51; int i; - static int p05[3] = { 5, 25, 125 }; + static CONST int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) - b = multadd(b, p05[i-1], 0); + b = multadd(PASS_STATE b, p05[i-1], 0); if (!(k >>= 2)) return b; - if (!(p5 = p5s)) { + if (!(p5 = GET_STATE(p5s))) { /* first time */ #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); @@ -881,14 +958,14 @@ pow5mult } FREE_DTOA_LOCK(1); #else - p5 = p5s = i2b(625); + p5 = GET_STATE(p5s) = i2b(PASS_STATE 625); p5->next = 0; #endif } for(;;) { if (k & 1) { - b1 = mult(b, p5); - Bfree(b); + b1 = mult(PASS_STATE b, p5); + Bfree(PASS_STATE b); b = b1; } if (!(k >>= 1)) @@ -902,7 +979,7 @@ pow5mult } FREE_DTOA_LOCK(1); #else - p51 = p5->next = mult(p5,p5); + p51 = p5->next = mult(PASS_STATE p5,p5); p51->next = 0; #endif } @@ -914,9 +991,9 @@ pow5mult static Bigint * lshift #ifdef KR_headers - (b, k) Bigint *b; int k; + (STATE_PARAM b, k) STATE_PARAM_DECL Bigint *b; int k; #else - (Bigint *b, int k) + (STATE_PARAM Bigint *b, int k) #endif { int i, k1, n, n1; @@ -932,7 +1009,7 @@ lshift n1 = n + b->wds + 1; for(i = b->maxwds; n1 > i; i <<= 1) k1++; - b1 = Balloc(k1); + b1 = Balloc(PASS_STATE k1); x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; @@ -967,7 +1044,7 @@ lshift *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; - Bfree(b); + Bfree(PASS_STATE b); return b1; } @@ -1008,9 +1085,9 @@ cmp static Bigint * diff #ifdef KR_headers - (a, b) Bigint *a, *b; + (STATE_PARAM a, b) STATE_PARAM_DECL Bigint *a, *b; #else - (Bigint *a, Bigint *b) + (STATE_PARAM Bigint *a, Bigint *b) #endif { Bigint *c; @@ -1027,7 +1104,7 @@ diff i = cmp(a,b); if (!i) { - c = Balloc(0); + c = Balloc(PASS_STATE 0); c->wds = 1; c->x[0] = 0; return c; @@ -1040,7 +1117,7 @@ diff } else i = 0; - c = Balloc(a->k); + c = Balloc(PASS_STATE a->k); c->sign = i; wa = a->wds; xa = a->x; @@ -1214,9 +1291,9 @@ b2d static Bigint * d2b #ifdef KR_headers - (d, e, bits) U d; int *e, *bits; + (STATE_PARAM d, e, bits) STATE_PARAM_DECL U d; int *e, *bits; #else - (U d, int *e, int *bits) + (STATE_PARAM U d, int *e, int *bits) #endif { Bigint *b; @@ -1235,9 +1312,9 @@ d2b #endif #ifdef Pack_32 - b = Balloc(1); + b = Balloc(PASS_STATE 1); #else - b = Balloc(2); + b = Balloc(PASS_STATE 2); #endif x = b->x; @@ -1529,9 +1606,9 @@ hexnan static double _strtod #ifdef KR_headers - (s00, se) CONST char *s00; char **se; + (STATE_PARAM s00, se) STATE_PARAM_DECL CONST char *s00; char **se; #else - (CONST char *s00, char **se) + (STATE_PARAM CONST char *s00, char **se) #endif { #ifdef Avoid_Underflow @@ -1953,13 +2030,13 @@ _strtod /* Put digits into bd: true value = bd * 10^e */ - bd0 = s2b(s0, nd0, nd, y); + bd0 = s2b(PASS_STATE s0, nd0, nd, y); for(;;) { - bd = Balloc(bd0->k); + bd = Balloc(PASS_STATE bd0->k); Bcopy(bd, bd0); - bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); + bb = d2b(PASS_STATE rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(PASS_STATE 1); if (e >= 0) { bb2 = bb5 = 0; @@ -2015,20 +2092,20 @@ _strtod bs2 -= i; } if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); + bs = pow5mult(PASS_STATE bs, bb5); + bb1 = mult(PASS_STATE bs, bb); + Bfree(PASS_STATE bb); bb = bb1; } if (bb2 > 0) - bb = lshift(bb, bb2); + bb = lshift(PASS_STATE bb, bb2); if (bd5 > 0) - bd = pow5mult(bd, bd5); + bd = pow5mult(PASS_STATE bd, bd5); if (bd2 > 0) - bd = lshift(bd, bd2); + bd = lshift(PASS_STATE bd, bd2); if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); + bs = lshift(PASS_STATE bs, bs2); + delta = diff(PASS_STATE bb, bd); dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); @@ -2060,7 +2137,7 @@ _strtod if (y) #endif { - delta = lshift(delta,Log2P); + delta = lshift(PASS_STATE delta,Log2P); if (cmp(delta, bs) <= 0) adj = -0.5; } @@ -2149,7 +2226,7 @@ _strtod #endif break; } - delta = lshift(delta,Log2P); + delta = lshift(PASS_STATE delta,Log2P); if (cmp(delta, bs) > 0) goto drop_down; break; @@ -2374,10 +2451,10 @@ _strtod } #endif cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); + Bfree(PASS_STATE bb); + Bfree(PASS_STATE bd); + Bfree(PASS_STATE bs); + Bfree(PASS_STATE delta); } #ifdef SET_INEXACT if (inexact) { @@ -2410,11 +2487,11 @@ _strtod } #endif retfree: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); + Bfree(PASS_STATE bb); + Bfree(PASS_STATE bd); + Bfree(PASS_STATE bs); + Bfree(PASS_STATE bd0); + Bfree(PASS_STATE delta); ret: if (se) *se = (char *)s; @@ -2539,15 +2616,16 @@ quorem return q; } -#ifndef MULTIPLE_THREADS +#if !defined(MULTIPLE_THREADS) && !defined(NO_GLOBAL_STATE) +#define USE_DTOA_RESULT 1 static char *dtoa_result; #endif static char * #ifdef KR_headers -rv_alloc(i) int i; +rv_alloc(STATE_PARAM i) STATE_PARAM_DECL int i; #else -rv_alloc(int i) +rv_alloc(STATE_PARAM int i) #endif { int j, k, *r; @@ -2557,10 +2635,10 @@ rv_alloc(int i) sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned) i; j <<= 1) k++; - r = (int*)Balloc(k); + r = (int*)Balloc(PASS_STATE k); *r = k; return -#ifndef MULTIPLE_THREADS +#ifdef USE_DTOA_RESULT dtoa_result = #endif (char *)(r+1); @@ -2568,14 +2646,14 @@ rv_alloc(int i) static char * #ifdef KR_headers -nrv_alloc(s, rve, n) char *s, **rve; int n; +nrv_alloc(STATE_PARAM s, rve, n) STATE_PARAM_DECL char *s, **rve; int n; #else -nrv_alloc(CONST char *s, char **rve, int n) +nrv_alloc(STATE_PARAM CONST char *s, char **rve, int n) #endif { char *rv, *t; - t = rv = rv_alloc(n); + t = rv = rv_alloc(PASS_STATE n); while((*t = *s++)) t++; if (rve) *rve = t; @@ -2590,15 +2668,15 @@ nrv_alloc(CONST char *s, char **rve, int n) static void #ifdef KR_headers -freedtoa(s) char *s; +freedtoa(STATE_PARAM s) STATE_PARAM_DECL char *s; #else -freedtoa(char *s) +freedtoa(STATE_PARAM char *s) #endif { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); - Bfree(b); -#ifndef MULTIPLE_THREADS + Bfree(PASS_STATE b); +#ifdef USE_DTOA_RESULT if (s == dtoa_result) dtoa_result = 0; #endif @@ -2641,10 +2719,10 @@ freedtoa(char *s) static char * dtoa #ifdef KR_headers - (d, mode, ndigits, decpt, sign, rve) - U d; int mode, ndigits, *decpt, *sign; char **rve; + (STATE_PARAM d, mode, ndigits, decpt, sign, rve) + STATE_PARAM_DECL U d; int mode, ndigits, *decpt, *sign; char **rve; #else - (U d, int mode, int ndigits, int *decpt, int *sign, char **rve) + (STATE_PARAM U d, int mode, int ndigits, int *decpt, int *sign, char **rve) #endif { /* Arguments ndigits, decpt, sign are similar to those @@ -2705,9 +2783,9 @@ dtoa mlo = NULL; #endif -#ifndef MULTIPLE_THREADS +#ifdef USE_DTOA_RESULT if (dtoa_result) { - freedtoa(dtoa_result); + freedtoa(PASS_STATE dtoa_result); dtoa_result = 0; } #endif @@ -2731,9 +2809,9 @@ dtoa *decpt = 9999; #ifdef IEEE_Arith if (!word1(d) && !(word0(d) & 0xfffff)) - return nrv_alloc("Infinity", rve, 8); + return nrv_alloc(PASS_STATE "Infinity", rve, 8); #endif - return nrv_alloc("NaN", rve, 3); + return nrv_alloc(PASS_STATE "NaN", rve, 3); } #endif #ifdef IBM @@ -2741,7 +2819,7 @@ dtoa #endif if (!dval(d)) { *decpt = 1; - return nrv_alloc("0", rve, 1); + return nrv_alloc(PASS_STATE "0", rve, 1); } #ifdef SET_INEXACT @@ -2758,7 +2836,7 @@ dtoa } #endif - b = d2b(d, &be, &bbits); + b = d2b(PASS_STATE d, &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else @@ -2884,7 +2962,7 @@ dtoa if (i <= 0) i = 1; } - s = s0 = rv_alloc(i); + s = s0 = rv_alloc(PASS_STATE i); #ifdef Honor_FLT_ROUNDS if (mode > 1 && rounding != 1) @@ -3061,7 +3139,7 @@ dtoa #endif b2 += i; s2 += i; - mhi = i2b(1); + mhi = i2b(PASS_STATE 1); } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; @@ -3072,20 +3150,20 @@ dtoa if (b5 > 0) { if (leftright) { if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); + mhi = pow5mult(PASS_STATE mhi, m5); + b1 = mult(PASS_STATE mhi, b); + Bfree(PASS_STATE b); b = b1; } if ((j = b5 - m5)) - b = pow5mult(b, j); + b = pow5mult(PASS_STATE b, j); } else - b = pow5mult(b, b5); + b = pow5mult(PASS_STATE b, b5); } - S = i2b(1); + S = i2b(PASS_STATE 1); if (s5 > 0) - S = pow5mult(S, s5); + S = pow5mult(PASS_STATE S, s5); /* Check for special case that d is a normalized power of 2. */ @@ -3134,20 +3212,20 @@ dtoa s2 += i; } if (b2 > 0) - b = lshift(b, b2); + b = lshift(PASS_STATE b, b2); if (s2 > 0) - S = lshift(S, s2); + S = lshift(PASS_STATE S, s2); if (k_check) { if (cmp(b,S) < 0) { k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ + b = multadd(PASS_STATE b, 10, 0); /* we botched the k estimate */ if (leftright) - mhi = multadd(mhi, 10, 0); + mhi = multadd(PASS_STATE mhi, 10, 0); ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) < 0) { + if (ilim < 0 || cmp(b,S = multadd(PASS_STATE S,5,0)) < 0) { /* no digits, fcvt style */ no_digits: /* MOZILLA CHANGE: Always return a non-empty string. */ @@ -3162,7 +3240,7 @@ dtoa } if (leftright) { if (m2 > 0) - mhi = lshift(mhi, m2); + mhi = lshift(PASS_STATE mhi, m2); /* Compute mlo -- check for special case * that d is a normalized power of 2. @@ -3170,9 +3248,9 @@ dtoa mlo = mhi; if (spec_case) { - mhi = Balloc(mhi->k); + mhi = Balloc(PASS_STATE mhi->k); Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); + mhi = lshift(PASS_STATE mhi, Log2P); } for(i = 1;;i++) { @@ -3181,9 +3259,9 @@ dtoa * that will round to d? */ j = cmp(b, mlo); - delta = diff(S, mhi); + delta = diff(PASS_STATE S, mhi); j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); + Bfree(PASS_STATE delta); #ifndef ROUND_BIASED if (j1 == 0 && mode != 1 && !(word1(d) & 1) #ifdef Honor_FLT_ROUNDS @@ -3221,7 +3299,7 @@ dtoa } #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { - b = lshift(b, 1); + b = lshift(PASS_STATE b, 1); j1 = cmp(b, S); if ((j1 > 0 || (j1 == 0 && dig & 1)) && dig++ == '9') @@ -3250,12 +3328,12 @@ dtoa *s++ = dig; if (i == ilim) break; - b = multadd(b, 10, 0); + b = multadd(PASS_STATE b, 10, 0); if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); + mlo = mhi = multadd(PASS_STATE mhi, 10, 0); else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); + mlo = multadd(PASS_STATE mlo, 10, 0); + mhi = multadd(PASS_STATE mhi, 10, 0); } } } @@ -3270,7 +3348,7 @@ dtoa } if (i >= ilim) break; - b = multadd(b, 10, 0); + b = multadd(PASS_STATE b, 10, 0); } /* Round off last digit */ @@ -3281,7 +3359,7 @@ dtoa case 2: goto roundoff; } #endif - b = lshift(b, 1); + b = lshift(PASS_STATE b, 1); j = cmp(b, S); if (j >= 0) { /* ECMA compatible rounding needed by Spidermonkey */ roundoff: @@ -3301,11 +3379,11 @@ dtoa s++; } ret: - Bfree(S); + Bfree(PASS_STATE S); if (mhi) { if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); } ret1: #ifdef SET_INEXACT @@ -3319,7 +3397,7 @@ dtoa else if (!oldinexact) clear_inexact(); #endif - Bfree(b); + Bfree(PASS_STATE b); *s = 0; *decpt = k + 1; if (rve) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index e2facdc9487b..5eee36e8c7d8 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -563,11 +563,8 @@ JSRuntime::JSRuntime() bool JSRuntime::init(uint32 maxbytes) { - if (!js_InitDtoa() || - !js_InitGC(this, maxbytes) || - !js_InitAtomState(this)) { + if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this)) return false; - } deflatedStringCache = new js::DeflatedStringCache(); if (!deflatedStringCache || !deflatedStringCache->init()) @@ -757,7 +754,6 @@ JS_ShutDown(void) reprmeter::js_DumpReprMeter(); #endif - js_FinishDtoa(); #ifdef JS_THREADSAFE js_CleanupLocks(); #endif diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 8775486c1cc8..98921b50c0e7 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -100,7 +100,7 @@ CallStack::contains(JSStackFrame *fp) } #endif -void +bool JSThreadData::init() { #ifdef DEBUG @@ -111,6 +111,12 @@ JSThreadData::init() #ifdef JS_TRACER InitJIT(&traceMonitor); #endif + dtoaState = js_NewDtoaState(); + if (!dtoaState) { + finish(); + return false; + } + return true; } void @@ -126,6 +132,9 @@ JSThreadData::finish() JS_ASSERT(!localRootStack); #endif + if (dtoaState) + js_DestroyDtoaState(dtoaState); + js_FinishGSNCache(&gsnCache); js_FinishPropertyCache(&propertyCache); #if defined JS_TRACER @@ -190,7 +199,10 @@ NewThread(jsword id) return NULL; JS_INIT_CLIST(&thread->contextList); thread->id = id; - thread->data.init(); + if (!thread->data.init()) { + js_free(thread); + return NULL; + } return thread; } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index a9dbfdddbac9..1f4477bef6e3 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -50,6 +50,7 @@ #include "jslong.h" #include "jsatom.h" #include "jsdhash.h" +#include "jsdtoa.h" #include "jsgc.h" #include "jshashtable.h" #include "jsinterp.h" @@ -555,6 +556,9 @@ struct JSThreadData { JSEvalCacheMeter evalCacheMeter; #endif + /* State used by dtoa.c. */ + DtoaState *dtoaState; + /* * Cache of reusable JSNativeEnumerators mapped by shape identifiers (as * stored in scope->shape). This cache is nulled by the GC and protected @@ -569,7 +573,7 @@ struct JSThreadData { jsuword nativeEnumCache[NATIVE_ENUM_CACHE_SIZE]; - void init(); + bool init(); void finish(); void mark(JSTracer *trc); void purge(JSContext *cx); diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 9aa79066183e..994a5009bf1d 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -2175,7 +2175,7 @@ date_toSource(JSContext *cx, uintN argc, jsval *vp) if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) return JS_FALSE; - numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, utctime); + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf, DTOSTR_STANDARD, 0, utctime); if (!numStr) { JS_ReportOutOfMemory(cx); return JS_FALSE; diff --git a/js/src/jsdtoa.cpp b/js/src/jsdtoa.cpp index 111cb5dec9d3..1d089f3c79f1 100644 --- a/js/src/jsdtoa.cpp +++ b/js/src/jsdtoa.cpp @@ -49,10 +49,7 @@ #include "jsnum.h" #include "jsbit.h" #include "jslibmath.h" - -#ifdef JS_THREADSAFE -#include "jslock.h" -#endif +#include "jscntxt.h" #ifdef IS_LITTLE_ENDIAN #define IEEE_8087 @@ -78,46 +75,9 @@ #endif */ -#ifdef JS_THREADSAFE -static PRLock *dtoalock; -static JSBool _dtoainited = JS_FALSE; - -#define LOCK_DTOA() PR_Lock(dtoalock); -#define UNLOCK_DTOA() PR_Unlock(dtoalock) -#else -#define LOCK_DTOA() -#define UNLOCK_DTOA() -#endif +#define NO_GLOBAL_STATE #include "dtoa.c" -JS_FRIEND_API(JSBool) -js_InitDtoa() -{ -#ifdef JS_THREADSAFE - if (!_dtoainited) { - dtoalock = PR_NewLock(); - JS_ASSERT(dtoalock); - _dtoainited = JS_TRUE; - } - - return (dtoalock != 0); -#else - return JS_TRUE; -#endif -} - -JS_FRIEND_API(void) -js_FinishDtoa() -{ -#ifdef JS_THREADSAFE - if (_dtoainited) { - PR_DestroyLock(dtoalock); - dtoalock = NULL; - _dtoainited = JS_FALSE; - } -#endif -} - /* Mapping of JSDToStrMode -> js_dtoa mode */ static const uint8 dtoaModes[] = { 0, /* DTOSTR_STANDARD */ @@ -126,20 +86,19 @@ static const uint8 dtoaModes[] = { 2, /* DTOSTR_EXPONENTIAL, */ 2}; /* DTOSTR_PRECISION */ -JS_FRIEND_API(double) -JS_strtod(const char *s00, char **se, int *err) +double +js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err) { double retval; if (err) *err = 0; - LOCK_DTOA(); - retval = _strtod(s00, se); - UNLOCK_DTOA(); + retval = _strtod(state, s00, se); return retval; } -JS_FRIEND_API(char *) -JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dinput) +char * +js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, + double dinput) { U d; int decPt; /* Offset of decimal point from first digit */ @@ -159,24 +118,20 @@ JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, dou if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21)) mode = DTOSTR_STANDARD; - LOCK_DTOA(); dval(d) = dinput; - numBegin = dtoa(d, dtoaModes[mode], precision, &decPt, &sign, &numEnd); + numBegin = dtoa(PASS_STATE d, dtoaModes[mode], precision, &decPt, &sign, &numEnd); if (!numBegin) { - UNLOCK_DTOA(); return NULL; } nDigits = numEnd - numBegin; JS_ASSERT((size_t) nDigits <= bufferSize - 2); if ((size_t) nDigits > bufferSize - 2) { - UNLOCK_DTOA(); return NULL; } memcpy(buffer + 2, numBegin, nDigits); - freedtoa(numBegin); - UNLOCK_DTOA(); + freedtoa(PASS_STATE numBegin); numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */ numEnd = numBegin + nDigits; *numEnd = '\0'; @@ -353,8 +308,8 @@ static uint32 quorem2(Bigint *b, int32 k) #define DTOBASESTR_BUFFER_SIZE 1078 #define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit))) -JS_FRIEND_API(char *) -JS_dtobasestr(int base, double dinput) +char * +js_dtobasestr(DtoaState *state, int base, double dinput) { U d; char *buffer; /* The output string */ @@ -386,7 +341,6 @@ JS_dtobasestr(int base, double dinput) return buffer; } - LOCK_DTOA(); /* Output the integer part of d with the digits in reverse order. */ pInt = p; dval(di) = floor(dval(d)); @@ -404,14 +358,13 @@ JS_dtobasestr(int base, double dinput) } else { int e; int bits; /* Number of significant bits in di; not used. */ - Bigint *b = d2b(di, &e, &bits); + Bigint *b = d2b(PASS_STATE di, &e, &bits); if (!b) goto nomem1; - b = lshift(b, e); + b = lshift(PASS_STATE b, e); if (!b) { nomem1: - Bfree(b); - UNLOCK_DTOA(); + Bfree(PASS_STATE b); js_free(buffer); return NULL; } @@ -420,7 +373,7 @@ JS_dtobasestr(int base, double dinput) JS_ASSERT(digit < (uint32)base); *p++ = BASEDIGIT(digit); } while (b->wds); - Bfree(b); + Bfree(PASS_STATE b); } /* Reverse the digits of the integer part of d. */ q = p-1; @@ -440,15 +393,14 @@ JS_dtobasestr(int base, double dinput) b = s = mlo = mhi = NULL; *p++ = '.'; - b = d2b(df, &e, &bbits); + b = d2b(PASS_STATE df, &e, &bbits); if (!b) { nomem2: - Bfree(b); - Bfree(s); + Bfree(PASS_STATE b); + Bfree(PASS_STATE s); if (mlo != mhi) - Bfree(mlo); - Bfree(mhi); - UNLOCK_DTOA(); + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); js_free(buffer); return NULL; } @@ -463,7 +415,7 @@ JS_dtobasestr(int base, double dinput) s2 += Bias + P; /* 1/2^s2 = (nextDouble(d) - d)/2 */ JS_ASSERT(-s2 < e); - mlo = i2b(1); + mlo = i2b(PASS_STATE 1); if (!mlo) goto nomem2; mhi = mlo; @@ -475,17 +427,17 @@ JS_dtobasestr(int base, double dinput) /* The special case. Here we want to be within a quarter of the last input significant digit instead of one half of it when the output string's value is less than d. */ s2 += Log2P; - mhi = i2b(1<sign ? 1 : cmp(b, delta); - Bfree(delta); + Bfree(PASS_STATE delta); /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ #ifndef ROUND_BIASED @@ -542,7 +494,7 @@ JS_dtobasestr(int base, double dinput) if (j1 > 0) { /* Either dig or dig+1 would work here as the least significant digit. Use whichever would produce an output value closer to d. */ - b = lshift(b, 1); + b = lshift(PASS_STATE b, 1); if (!b) goto nomem2; j1 = cmp(b, s); @@ -558,15 +510,26 @@ JS_dtobasestr(int base, double dinput) JS_ASSERT(digit < (uint32)base); *p++ = BASEDIGIT(digit); } while (!done); - Bfree(b); - Bfree(s); + Bfree(PASS_STATE b); + Bfree(PASS_STATE s); if (mlo != mhi) - Bfree(mlo); - Bfree(mhi); + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); } JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE); *p = '\0'; - UNLOCK_DTOA(); } return buffer; } + +DtoaState * +js_NewDtoaState() +{ + return newdtoa(); +} + +void +js_DestroyDtoaState(DtoaState *state) +{ + destroydtoa(state); +} diff --git a/js/src/jsdtoa.h b/js/src/jsdtoa.h index b074c9aba705..6bd8a1709894 100644 --- a/js/src/jsdtoa.h +++ b/js/src/jsdtoa.h @@ -48,23 +48,30 @@ JS_BEGIN_EXTERN_C +struct DtoaState; + +DtoaState * +js_NewDtoaState(); + +void +js_DestroyDtoaState(DtoaState *state); + /* - * JS_strtod() returns as a double-precision floating-point number - * the value represented by the character string pointed to by - * s00. The string is scanned up to the first unrecognized - * character. - * If the value of se is not (char **)NULL, a pointer to - * the character terminating the scan is returned in the location pointed - * to by se. If no number can be formed, se is set to s00r, and - * zero is returned. + * js_strtod_harder() returns as a double-precision floating-point number the + * value represented by the character string pointed to by s00. The string is + * scanned up to the first unrecognized character. + * + * If se is not NULL, *se receives a pointer to the character terminating the + * scan. If no number can be formed, *se receives a pointer to the first + * unparseable character in s00, and zero is returned. * * *err is set to zero on success; it's set to JS_DTOA_ERANGE on range * errors and JS_DTOA_ENOMEM on memory failure. */ #define JS_DTOA_ERANGE 1 #define JS_DTOA_ENOMEM 2 -JS_FRIEND_API(double) -JS_strtod(const char *s00, char **se, int *err); +double +js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err); /* * Modes for converting floating-point numbers to strings. @@ -102,8 +109,9 @@ typedef enum JSDToStrMode { * * Return NULL if out of memory. */ -JS_FRIEND_API(char *) -JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dval); +char * +js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, + double dval); /* * Convert d to a string in the given base. The integral part of d will be printed exactly @@ -116,15 +124,8 @@ JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, dou * * Return NULL if out of memory. If the result is not NULL, it must be released via free(). */ -JS_FRIEND_API(char *) -JS_dtobasestr(int base, double d); - -/* - * Clean up any persistent RAM allocated during the execution of DtoA - * routines, and remove any locks that might have been created. - */ -JS_FRIEND_API(JSBool) js_InitDtoa(void); -JS_FRIEND_API(void) js_FinishDtoa(void); +char * +js_dtobasestr(DtoaState *state, int base, double d); JS_END_EXTERN_C diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 119a0705c7bb..ffbc5c1e3453 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -321,7 +321,8 @@ num_toSource(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; JS_ASSERT(JSVAL_IS_NUMBER(v)); d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); - numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf, + DTOSTR_STANDARD, 0, d); if (!numStr) { JS_ReportOutOfMemory(cx); return JS_FALSE; @@ -575,7 +576,8 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, return JS_FALSE; precision = js_DoubleToInteger(precision); if (precision < precisionMin || precision > precisionMax) { - numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision); + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf, + DTOSTR_STANDARD, 0, precision); if (!numStr) JS_ReportOutOfMemory(cx); else @@ -584,7 +586,8 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, } } - numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d); + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf, + oneArgMode, (jsint)precision + precisionOffset, d); if (!numStr) { JS_ReportOutOfMemory(cx); return JS_FALSE; @@ -847,9 +850,10 @@ NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize numStr = IntToCString(i, base, buf, bufSize); } else { if (base == 10) - numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d); + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, bufSize, + DTOSTR_STANDARD, 0, d); else - numStr = JS_dtobasestr(base, d); + numStr = js_dtobasestr(JS_THREAD_DATA(cx)->dtoaState, base, d); if (!numStr) { JS_ReportOutOfMemory(cx); return NULL; @@ -915,7 +919,8 @@ js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb) cstr = IntToCString(JSVAL_TO_INT(v), 10, arr, arrSize); } else { JS_ASSERT(JSVAL_IS_DOUBLE(v)); - cstr = JS_dtostr(arr, arrSize, DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(v)); + cstr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, arr, arrSize, + DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(v)); } if (!cstr) return JS_FALSE; @@ -1178,7 +1183,7 @@ js_strtod(JSContext *cx, const jschar *s, const jschar *send, estr = istr + 8; } else { int err; - d = JS_strtod(cstr, &estr, &err); + d = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err); if (d == HUGE_VAL) d = js_PositiveInfinity; else if (d == -HUGE_VAL) @@ -1296,7 +1301,7 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, /* * If we're accumulating a decimal number and the number is >= * 2^53, then the result from the repeated multiply-add above may - * be inaccurate. Call JS_strtod to get the correct answer. + * be inaccurate. Call js_strtod_harder to get the correct answer. */ size_t i; size_t length = s1 - start; @@ -1310,7 +1315,7 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, cstr[i] = (char)start[i]; cstr[length] = 0; - value = JS_strtod(cstr, &estr, &err); + value = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err); if (err == JS_DTOA_ENOMEM) { JS_ReportOutOfMemory(cx); cx->free(cstr); diff --git a/js/src/json.cpp b/js/src/json.cpp index 2a18aded1c0d..fee0b557ffd1 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -482,7 +482,8 @@ Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp, char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr; jsdouble d = JSVAL_IS_INT(*vp) ? jsdouble(JSVAL_TO_INT(*vp)) : *JSVAL_TO_DOUBLE(*vp); - numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf, + DTOSTR_STANDARD, 0, d); if (!numStr) { JS_ReportOutOfMemory(cx); return JS_FALSE; diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index d3328a541fc7..ad06dc64bd4a 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1107,7 +1107,8 @@ SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) : "1 / 0"); *opp = JSOP_DIV; } else { - s = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d); + s = js_dtostr(JS_THREAD_DATA(sp->context)->dtoaState, buf, sizeof buf, + DTOSTR_STANDARD, 0, d); if (!s) { JS_ReportOutOfMemory(sp->context); return -1; From 632c80b67951cd8853cc1e171934368b6ab30a22 Mon Sep 17 00:00:00 2001 From: "timeless@mozdev.org" Date: Tue, 23 Mar 2010 09:41:43 -0500 Subject: [PATCH 113/213] Bug 552905 - JS_DefineUCFunction seems to be missing a CHECK_REQUEST. r=jorendorff. --- js/src/jsapi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 5eee36e8c7d8..27c53c646a81 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4427,6 +4427,7 @@ JS_DefineUCFunction(JSContext *cx, JSObject *obj, { JSAtom *atom; + CHECK_REQUEST(cx); atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); if (!atom) return NULL; From 39e658e50214f0d4cbe9cd0735824f54b9cbad83 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 23 Mar 2010 10:03:00 -0500 Subject: [PATCH 114/213] Fix test js1_8_5/regress/regress-533876.js. --- js/src/tests/js1_8_5/regress/jstests.list | 2 +- js/src/tests/js1_8_5/regress/regress-533876.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 28c43b280581..37bf05dcfc5c 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -1,4 +1,4 @@ url-prefix ../../jsreftest.html?test=js1_8_5/regress/ -fails script regress-533876.js +script regress-533876.js script regress-541455.js script regress-546615.js diff --git a/js/src/tests/js1_8_5/regress/regress-533876.js b/js/src/tests/js1_8_5/regress/regress-533876.js index 0e38a583b2b8..a3233651c28c 100644 --- a/js/src/tests/js1_8_5/regress/regress-533876.js +++ b/js/src/tests/js1_8_5/regress/regress-533876.js @@ -18,3 +18,4 @@ delete eval; // force dictionary scope for global gc(); var f = eval("function () { return /x/; }"); x.watch('x', f); // clone property from global to x, including SPROP_IN_DICTIONARY flag +print(" PASSED!"); From 7a84f155e7a27b0c89da252550a68b5adfe86714 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Tue, 23 Mar 2010 08:58:00 -0700 Subject: [PATCH 115/213] Bug 554203 - remove dead code in JSOP_STOP (r=brendan) --- js/src/jsops.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index d48bd63d8c13..913f9a080299 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -217,16 +217,8 @@ BEGIN_CASE(JSOP_STOP) } JS_ASSERT(regs.sp == StackBase(fp)); - if ((fp->flags & JSFRAME_CONSTRUCTING) && - JSVAL_IS_PRIMITIVE(fp->rval)) { - if (!fp->fun) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_NEW_RESULT, - js_ValueToPrintableString(cx, rval)); - goto error; - } + if ((fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(fp->rval)) fp->rval = fp->thisv; - } ok = JS_TRUE; if (inlineCallCount) inline_return: From 2e3d2a8534e5287a7714d1d9a97d915dd6ffe64f Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 23 Mar 2010 12:35:31 -0500 Subject: [PATCH 116/213] Backed out changeset 6dcce4f4d9dd due to orange. --- js/src/tests/js1_8_5/regress/jstests.list | 2 +- js/src/tests/js1_8_5/regress/regress-533876.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 37bf05dcfc5c..28c43b280581 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -1,4 +1,4 @@ url-prefix ../../jsreftest.html?test=js1_8_5/regress/ -script regress-533876.js +fails script regress-533876.js script regress-541455.js script regress-546615.js diff --git a/js/src/tests/js1_8_5/regress/regress-533876.js b/js/src/tests/js1_8_5/regress/regress-533876.js index a3233651c28c..0e38a583b2b8 100644 --- a/js/src/tests/js1_8_5/regress/regress-533876.js +++ b/js/src/tests/js1_8_5/regress/regress-533876.js @@ -18,4 +18,3 @@ delete eval; // force dictionary scope for global gc(); var f = eval("function () { return /x/; }"); x.watch('x', f); // clone property from global to x, including SPROP_IN_DICTIONARY flag -print(" PASSED!"); From 7c4e0d85e02fa00a288092179be4986e8457c44a Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 23 Mar 2010 13:03:07 -0700 Subject: [PATCH 117/213] Revert symbolizing changes, to see whether optimized+no strict aliasing fixes n810. --- configure.in | 6 ------ js/src/configure.in | 11 ----------- 2 files changed, 17 deletions(-) diff --git a/configure.in b/configure.in index 51997a211a2a..fc6ed433076e 100644 --- a/configure.in +++ b/configure.in @@ -6662,10 +6662,6 @@ MOZ_ARG_ENABLE_STRING(debug, fi ], MOZ_DEBUG=) -if test $MOZ_PLATFORM_MAEMO; then - MOZ_DEBUG=1 -fi - MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -D_DEBUG" case "${target_os}" in beos*) @@ -7086,8 +7082,6 @@ MOZ_ARG_ENABLE_BOOL(install-strip, PKG_SKIP_STRIP= , PKG_SKIP_STRIP=1) -PKG_SKIP_STRIP=1 - dnl ======================================================== dnl = --enable-elf-dynstr-gc dnl ======================================================== diff --git a/js/src/configure.in b/js/src/configure.in index 58015b4f169f..f5350af9a502 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -3975,11 +3975,6 @@ then esac fi -MOZ_ARG_WITH_STRING(maemo-version, -[ --with-maemo-version=MOZ_PLATFORM_MAEMO - Maemo SDK Version], - MOZ_PLATFORM_MAEMO=$withval) - MOZ_ARG_ENABLE_STRING(debug, [ --enable-debug[=DBG] Enable building with developer debug info (Using compiler flags DBG)], @@ -3994,10 +3989,6 @@ MOZ_ARG_ENABLE_STRING(debug, fi ], MOZ_DEBUG=) -if test $MOZ_PLATFORM_MAEMO; then - MOZ_DEBUG=1 -fi - MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -D_DEBUG" case "${target_os}" in beos*) @@ -4345,8 +4336,6 @@ MOZ_ARG_ENABLE_BOOL(install-strip, PKG_SKIP_STRIP= , PKG_SKIP_STRIP=1) -PKG_SKIP_STRIP=1 - dnl ======================================================== dnl = dnl = Profiling and Instrumenting From 48d99af139abb8aac16446e72d28ec1e3e1d24a6 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 23 Mar 2010 13:03:15 -0700 Subject: [PATCH 118/213] Temporarily disable strict aliasing to check whether that has any relevance to the n810 bustage. --- js/src/config.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/config.mk b/js/src/config.mk index 0e7696a5b247..2a3eae78fed1 100644 --- a/js/src/config.mk +++ b/js/src/config.mk @@ -127,9 +127,9 @@ INTERP_OPTIMIZER = -O2 -GL BUILTINS_OPTIMIZER = -O2 -GL LDFLAGS += -LTCG else -OPTIMIZER = -Os -fstrict-aliasing -fno-exceptions -fno-rtti -Wstrict-aliasing=2 -BUILTINS_OPTIMIZER = -O9 -fstrict-aliasing -fno-exceptions -fno-rtti -INTERP_OPTIMIZER = -O3 -fstrict-aliasing -fno-exceptions -fno-rtti +OPTIMIZER = -Os -fno-exceptions -fno-rtti +BUILTINS_OPTIMIZER = -O9 -fno-exceptions -fno-rtti +INTERP_OPTIMIZER = -O3 -fno-exceptions -fno-rtti endif DEFINES += -UDEBUG -DNDEBUG -UDEBUG_$(USER) OBJDIR_TAG = _OPT From 942ed6e23c524e06af982e0bd65cf9683b0e59e5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 22 Mar 2010 12:18:47 -0700 Subject: [PATCH 119/213] ARM bustage fix for bug 507089. r=me. --HG-- extra : convert_revision : d04d39fadbb5f075d4f60fc7b73d106a39331453 --- js/src/nanojit/NativeARM.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index bd21e5512e5c..8b27696a9587 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -862,9 +862,6 @@ Assembler::asm_call(LInsp ins) // See comments above for more details as to why this is necessary here // for floating point calls, but not for integer calls. if (_config.arm_vfp && ins->isUsed()) { - // Determine the size (and type) of the instruction result. - ArgType rsize = (ArgType)(ci->_typesig & ARGTYPE_MASK); - // If the result size is a floating-point value, treat the result // specially, as described previously. if (ci->returnType() == ARGTYPE_F) { From 65fc47dc7f68f80e9e0c5c7f744c6ab01a789f81 Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Tue, 23 Mar 2010 15:09:52 -0400 Subject: [PATCH 120/213] Fix PPC bustage for bug 507089 (r=me) --HG-- extra : convert_revision : 0a31a14aba7746483fe8ff6b8ab287e1784de846 --- js/src/nanojit/NativePPC.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index a0b0a2e9cb65..92a90cece45d 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -710,7 +710,8 @@ namespace nanojit uint32_t j = argc - i - 1; ArgType ty = argTypes[j]; LInsp arg = ins->arg(j); - if (ty == ARGTYPE_I || ty == ARGTYPE_U || ty == ARGTYPE_Q) { + NanoAssert(ty != ARGTYPE_V); + if (ty != ARGTYPE_F) { // GP arg if (r <= R10) { asm_regarg(ty, arg, r); @@ -720,7 +721,7 @@ namespace nanojit // put arg on stack TODO(stack_int32); } - } else if (ty == ARGTYPE_F) { + } else { // double if (fr <= F13) { asm_regarg(ty, arg, fr); @@ -735,8 +736,6 @@ namespace nanojit // put arg on stack TODO(stack_double); } - } else { - TODO(ARGTYPE_UNK); } } if (param_size > max_param_size) @@ -746,7 +745,8 @@ namespace nanojit void Assembler::asm_regarg(ArgType ty, LInsp p, Register r) { NanoAssert(r != deprecated_UnknownReg); - if (ty == ARGTYPE_I || ty == ARGTYPE_U || ty == ARGTYPE_Q) + NanoAssert(ty != ARGTYPE_V); + if (ty != ARGTYPE_F) { #ifdef NANOJIT_64BIT if (ty == ARGTYPE_I) { @@ -785,7 +785,7 @@ namespace nanojit } } } - else if (ty == ARGTYPE_F) { + else { if (p->isUsed()) { Register rp = p->deprecated_getReg(); if (!deprecated_isKnownReg(rp) || !IsFpReg(rp)) { @@ -804,9 +804,6 @@ namespace nanojit findSpecificRegFor(p, r); } } - else { - TODO(ARGTYPE_UNK); - } } void Assembler::asm_spill(Register rr, int d, bool /* pop */, bool quad) { @@ -1032,7 +1029,7 @@ namespace nanojit Register r = ins->deprecated_getReg(); if (deprecated_isKnownReg(r) && (rmask(r) & FpRegs)) { // FPR already assigned, fine, use it - deprecated_freeRsrcOf(ins, false); + deprecated_freeRsrcOf(ins); } else { // use a GPR register; its okay to copy doubles with GPR's // but *not* okay to copy non-doubles with FPR's From b090e850b83564003062f9d7061c29bedb2e751d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 23 Mar 2010 15:05:47 -0700 Subject: [PATCH 121/213] Bug 517910 - NJ: add more alias-set annotations to LIR so as to improve CSEing of loads. r=edwsmith. --HG-- extra : convert_revision : 26cbea5a2acdcc6156b4a72b0c40c0d675f69571 --- js/src/lirasm/lirasm.cpp | 22 +- js/src/nanojit/LIR.cpp | 653 ++++++++++++++++++++++----------------- js/src/nanojit/LIR.h | 148 +++++---- 3 files changed, 448 insertions(+), 375 deletions(-) diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index 565fa0d11ed7..a74ec5475d46 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -518,7 +518,8 @@ FragmentAssembler::FragmentAssembler(Lirasm &parent, const string &fragmentName, mLir = mBufWriter = new LirBufWriter(mParent.mLirbuf, nanojit::AvmCore::config); #ifdef DEBUG if (optimize) { // don't re-validate if no optimization has taken place - mLir = mValidateWriter2 = new ValidateWriter(mLir, "end of writer pipeline"); + mLir = mValidateWriter2 = + new ValidateWriter(mLir, mFragment->lirbuf->printer, "end of writer pipeline"); } #endif #ifdef DEBUG @@ -540,7 +541,8 @@ FragmentAssembler::FragmentAssembler(Lirasm &parent, const string &fragmentName, mLir = mExprFilter = new ExprFilter(mLir); } #ifdef DEBUG - mLir = mValidateWriter1 = new ValidateWriter(mLir, "start of writer pipeline"); + mLir = mValidateWriter1 = + new ValidateWriter(mLir, mFragment->lirbuf->printer, "start of writer pipeline"); #endif mReturnTypeBits = 0; @@ -634,7 +636,7 @@ FragmentAssembler::assemble_load() mTokens[1].find_first_of("0123456789") == 0) { return mLir->insLoad(mOpcode, ref(mTokens[0]), - imm(mTokens[1])); + imm(mTokens[1]), ACC_LOAD_ANY); } bad("immediate offset required for load"); return NULL; // not reached @@ -1059,7 +1061,7 @@ FragmentAssembler::assembleFragment(LirTokenStream &in, bool implicitBegin, cons need(3); ins = mLir->insStore(mOpcode, ref(mTokens[0]), ref(mTokens[1]), - imm(mTokens[2])); + imm(mTokens[2]), ACC_STORE_ANY); break; #if NJ_EXPANDED_LOADSTORE_SUPPORTED @@ -1808,7 +1810,7 @@ FragmentAssembler::assembleRandomFragment(int nIns) vector Ms = rnd(2) ? M4s : M8ps; if (!Ms.empty()) { LIns* base = rndPick(Ms); - ins = mLir->insLoad(rndPick(I_loads), base, rndOffset32(base->size())); + ins = mLir->insLoad(rndPick(I_loads), base, rndOffset32(base->size()), ACC_LOAD_ANY); addOrReplace(Is, ins); n++; } @@ -1819,7 +1821,7 @@ FragmentAssembler::assembleRandomFragment(int nIns) case LLD_Q: if (!M8ps.empty()) { LIns* base = rndPick(M8ps); - ins = mLir->insLoad(rndPick(Q_loads), base, rndOffset64(base->size())); + ins = mLir->insLoad(rndPick(Q_loads), base, rndOffset64(base->size()), ACC_LOAD_ANY); addOrReplace(Qs, ins); n++; } @@ -1829,7 +1831,7 @@ FragmentAssembler::assembleRandomFragment(int nIns) case LLD_F: if (!M8ps.empty()) { LIns* base = rndPick(M8ps); - ins = mLir->insLoad(rndPick(F_loads), base, rndOffset64(base->size())); + ins = mLir->insLoad(rndPick(F_loads), base, rndOffset64(base->size()), ACC_LOAD_ANY); addOrReplace(Fs, ins); n++; } @@ -1839,7 +1841,7 @@ FragmentAssembler::assembleRandomFragment(int nIns) vector Ms = rnd(2) ? M4s : M8ps; if (!Ms.empty() && !Is.empty()) { LIns* base = rndPick(Ms); - mLir->insStorei(rndPick(Is), base, rndOffset32(base->size())); + mLir->insStorei(rndPick(Is), base, rndOffset32(base->size()), ACC_STORE_ANY); n++; } break; @@ -1849,7 +1851,7 @@ FragmentAssembler::assembleRandomFragment(int nIns) case LST_Q: if (!M8ps.empty() && !Qs.empty()) { LIns* base = rndPick(M8ps); - mLir->insStorei(rndPick(Qs), base, rndOffset64(base->size())); + mLir->insStorei(rndPick(Qs), base, rndOffset64(base->size()), ACC_STORE_ANY); n++; } break; @@ -1858,7 +1860,7 @@ FragmentAssembler::assembleRandomFragment(int nIns) case LST_F: if (!M8ps.empty() && !Fs.empty()) { LIns* base = rndPick(M8ps); - mLir->insStorei(rndPick(Fs), base, rndOffset64(base->size())); + mLir->insStorei(rndPick(Fs), base, rndOffset64(base->size()), ACC_STORE_ANY); n++; } break; diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 0e3ad7a2e048..45fca4f3bde9 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -1149,24 +1149,31 @@ namespace nanojit m_list[kind] = new (alloc) LInsp[m_cap[kind]]; } clear(); - m_find[LInsImm] = &LInsHashSet::findImm; - m_find[LInsImmq] = PTR_SIZE(NULL, &LInsHashSet::findImmq); - m_find[LInsImmf] = &LInsHashSet::findImmf; - m_find[LIns1] = &LInsHashSet::find1; - m_find[LIns2] = &LInsHashSet::find2; - m_find[LIns3] = &LInsHashSet::find3; - m_find[LInsLoad] = &LInsHashSet::findLoad; - m_find[LInsCall] = &LInsHashSet::findCall; + m_find[LInsImm] = &LInsHashSet::findImm; + m_find[LInsImmq] = PTR_SIZE(NULL, &LInsHashSet::findImmq); + m_find[LInsImmf] = &LInsHashSet::findImmf; + m_find[LIns1] = &LInsHashSet::find1; + m_find[LIns2] = &LInsHashSet::find2; + m_find[LIns3] = &LInsHashSet::find3; + m_find[LInsCall] = &LInsHashSet::findCall; + m_find[LInsLoadReadOnly] = &LInsHashSet::findLoadReadOnly; + m_find[LInsLoadStack] = &LInsHashSet::findLoadStack; + m_find[LInsLoadRStack] = &LInsHashSet::findLoadRStack; + m_find[LInsLoadOther] = &LInsHashSet::findLoadOther; + m_find[LInsLoadMultiple] = &LInsHashSet::findLoadMultiple; + } + + void LInsHashSet::clear(LInsHashKind kind) { + VMPI_memset(m_list[kind], 0, sizeof(LInsp)*m_cap[kind]); + m_used[kind] = 0; } void LInsHashSet::clear() { for (LInsHashKind kind = LInsFirst; kind <= LInsLast; kind = nextKind(kind)) { - VMPI_memset(m_list[kind], 0, sizeof(LInsp)*m_cap[kind]); - m_used[kind] = 0; + clear(kind); } } - inline uint32_t LInsHashSet::hashImm(int32_t a) { return _hashfinish(_hash32(0,a)); } @@ -1194,10 +1201,15 @@ namespace nanojit return _hashfinish(_hashptr(hash, c)); } - inline uint32_t LInsHashSet::hashLoad(LOpcode op, LInsp a, int32_t d) { + NanoStaticAssert(sizeof(AccSet) == 1); // required for hashLoad to work properly + + // Nb: no need to hash the load's AccSet because each region's loads go in + // a different hash table. + inline uint32_t LInsHashSet::hashLoad(LOpcode op, LInsp a, int32_t d, AccSet accSet) { uint32_t hash = _hash8(0,uint8_t(op)); hash = _hashptr(hash, a); - return _hashfinish(_hash32(hash, d)); + hash = _hash32(hash, d); + return _hashfinish(_hash8(hash, accSet)); } inline uint32_t LInsHashSet::hashCall(const CallInfo *ci, uint32_t argc, LInsp args[]) { @@ -1219,11 +1231,12 @@ namespace nanojit LInsp ins = oldlist[i]; if (!ins) continue; uint32_t j = (this->*find)(ins); + NanoAssert(!m_list[kind][j]); m_list[kind][j] = ins; } } - LInsp LInsHashSet::add(LInsHashKind kind, LInsp ins, uint32_t k) + void LInsHashSet::add(LInsHashKind kind, LInsp ins, uint32_t k) { NanoAssert(!m_list[kind][k]); m_used[kind]++; @@ -1231,20 +1244,21 @@ namespace nanojit if ((m_used[kind] * 4) >= (m_cap[kind] * 3)) { // load factor of 0.75 grow(kind); } - return ins; } LInsp LInsHashSet::findImm(int32_t a, uint32_t &k) { LInsHashKind kind = LInsImm; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hashImm(a) & bitmask; + k = hashImm(a) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->imm32() != a)) - { + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; NanoAssert(ins->isconst()); + if (ins->imm32() == a) + return ins; // Quadratic probe: h(k,i) = h(k) + 0.5i + 0.5i^2, which gives the // sequence h(k), h(k)+1, h(k)+3, h(k)+6, h+10, ... This is a // good sequence for 2^n-sized tables as the values h(k,i) for i @@ -1252,11 +1266,9 @@ namespace nanojit // See http://portal.acm.org/citation.cfm?id=360737 and // http://en.wikipedia.org/wiki/Quadratic_probing (fetched // 06-Nov-2009) for more details. - hash = (hash + n) & bitmask; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::findImm(LInsp ins) @@ -1271,18 +1283,18 @@ namespace nanojit { LInsHashKind kind = LInsImmq; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hashImmq(a) & bitmask; + k = hashImmq(a) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->imm64() != a)) - { + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; NanoAssert(ins->isconstq()); - hash = (hash + n) & bitmask; + if (ins->imm64() == a) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::findImmq(LInsp ins) @@ -1297,18 +1309,18 @@ namespace nanojit { LInsHashKind kind = LInsImmf; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hashImmq(a) & bitmask; + k = hashImmq(a) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->imm64() != a)) - { + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; NanoAssert(ins->isconstf()); - hash = (hash + n) & bitmask; + if (ins->imm64() == a) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::findImmf(LInsp ins) @@ -1322,17 +1334,17 @@ namespace nanojit { LInsHashKind kind = LIns1; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hash1(op,a) & bitmask; + k = hash1(op, a) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->opcode() != op || ins->oprnd1() != a)) - { - hash = (hash + n) & bitmask; + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; + if (ins->isop(op) && ins->oprnd1() == a) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::find1(LInsp ins) @@ -1346,17 +1358,17 @@ namespace nanojit { LInsHashKind kind = LIns2; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hash2(op,a,b) & bitmask; + k = hash2(op, a, b) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->opcode() != op || ins->oprnd1() != a || ins->oprnd2() != b)) - { - hash = (hash + n) & bitmask; + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; + if (ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::find2(LInsp ins) @@ -1370,17 +1382,17 @@ namespace nanojit { LInsHashKind kind = LIns3; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hash3(op,a,b,c) & bitmask; + k = hash3(op, a, b, c) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->opcode() != op || ins->oprnd1() != a || ins->oprnd2() != b || ins->oprnd3() != c)) - { - hash = (hash + n) & bitmask; + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; + if (ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b && ins->oprnd3() == c) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::find3(LInsp ins) @@ -1390,27 +1402,57 @@ namespace nanojit return k; } - LInsp LInsHashSet::findLoad(LOpcode op, LInsp a, int32_t d, uint32_t &k) + LInsp LInsHashSet::findLoad(LOpcode op, LInsp a, int32_t d, AccSet accSet, LInsHashKind kind, + uint32_t &k) { - LInsHashKind kind = LInsLoad; + (void)accSet; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hashLoad(op,a,d) & bitmask; + k = hashLoad(op, a, d, accSet) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (ins->opcode() != op || ins->oprnd1() != a || ins->disp() != d)) - { - hash = (hash + n) & bitmask; + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; + NanoAssert(ins->accSet() == accSet); + if (ins->isop(op) && ins->oprnd1() == a && ins->disp() == d) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } - uint32_t LInsHashSet::findLoad(LInsp ins) + uint32_t LInsHashSet::findLoadReadOnly(LInsp ins) { uint32_t k; - findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), k); + findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), ins->accSet(), LInsLoadReadOnly, k); + return k; + } + + uint32_t LInsHashSet::findLoadStack(LInsp ins) + { + uint32_t k; + findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), ins->accSet(), LInsLoadStack, k); + return k; + } + + uint32_t LInsHashSet::findLoadRStack(LInsp ins) + { + uint32_t k; + findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), ins->accSet(), LInsLoadRStack, k); + return k; + } + + uint32_t LInsHashSet::findLoadOther(LInsp ins) + { + uint32_t k; + findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), ins->accSet(), LInsLoadOther, k); + return k; + } + + uint32_t LInsHashSet::findLoadMultiple(LInsp ins) + { + uint32_t k; + findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), ins->accSet(), LInsLoadMultiple, k); return k; } @@ -1426,17 +1468,17 @@ namespace nanojit { LInsHashKind kind = LInsCall; const uint32_t bitmask = m_cap[kind] - 1; - uint32_t hash = hashCall(ci, argc, args) & bitmask; + k = hashCall(ci, argc, args) & bitmask; uint32_t n = 1; - LInsp ins; - while ((ins = m_list[kind][hash]) != NULL && - (!ins->isCall() || ins->callInfo() != ci || !argsmatch(ins, argc, args))) - { - hash = (hash + n) & bitmask; + while (true) { + LInsp ins = m_list[kind][k]; + if (!ins) + return NULL; + if (ins->isCall() && ins->callInfo() == ci && argsmatch(ins, argc, args)) + return ins; + k = (k + n) & bitmask; n += 1; } - k = hash; - return ins; } uint32_t LInsHashSet::findCall(LInsp ins) @@ -1728,7 +1770,6 @@ namespace nanojit } } - void LirNameMap::addNameWithSuffix(LInsp ins, const char *name, int suffix, bool ignoreOneSuffix) { // The lookup may succeed, ie. we may already have a name for this @@ -1792,23 +1833,18 @@ namespace nanojit } - char* LInsPrinter::formatAccSet(RefBuf* buf, LInsp ins, bool isLoad) { - AccSet accSet = ins->accSet(); + char* LInsPrinter::formatAccSet(RefBuf* buf, AccSet accSet) { int i = 0; - if ((isLoad && accSet == ACC_LOAD_ANY) || - (!isLoad && accSet == ACC_STORE_ANY)) - { - // boring, don't bother with a suffix - } else { - buf->buf[i++] = '.'; - if (accSet & ACC_READONLY) { buf->buf[i++] = 'r'; accSet &= ~ACC_READONLY; } - if (accSet & ACC_STACK) { buf->buf[i++] = 's'; accSet &= ~ACC_STACK; } - if (accSet & ACC_OTHER) { buf->buf[i++] = 'o'; accSet &= ~ACC_OTHER; } - // This assertion will fail if we add a new accSet value but - // forget to handle it here. - NanoAssert(accSet == 0); - } + // 'c' is short for "const", because 'r' is used for RSTACK. + if (accSet & ACC_READONLY) { buf->buf[i++] = 'c'; accSet &= ~ACC_READONLY; } + if (accSet & ACC_STACK) { buf->buf[i++] = 's'; accSet &= ~ACC_STACK; } + if (accSet & ACC_RSTACK) { buf->buf[i++] = 'r'; accSet &= ~ACC_RSTACK; } + if (accSet & ACC_OTHER) { buf->buf[i++] = 'o'; accSet &= ~ACC_OTHER; } + // This assertion will fail if we add a new accSet value but + // forget to handle it here. + NanoAssert(accSet == 0); buf->buf[i] = 0; + NanoAssert(size_t(i) < buf->len); return buf->buf; } @@ -1919,11 +1955,12 @@ namespace nanojit int32_t argc = i->argc(); int32_t m = int32_t(n); // Windows doesn't have 'ssize_t' if (call->isIndirect()) - m -= VMPI_snprintf(s, m, "%s = %s [%s] ( ", formatRef(&b1, i), lirNames[op], - formatRef(&b2, i->arg(--argc))); + m -= VMPI_snprintf(s, m, "%s = %s.%s [%s] ( ", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, call->_storeAccSet), + formatRef(&b3, i->arg(--argc))); else - m -= VMPI_snprintf(s, m, "%s = %s #%s ( ", formatRef(&b1, i), lirNames[op], - call->_name); + m -= VMPI_snprintf(s, m, "%s = %s.%s #%s ( ", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, call->_storeAccSet), call->_name); if (m < 0) break; for (int32_t j = argc - 1; j >= 0; j--) { s += VMPI_strlen(s); @@ -2074,8 +2111,8 @@ namespace nanojit case LIR_ldsb: case LIR_ldss: case LIR_ld32f: - VMPI_snprintf(s, n, "%s = %s%s %s[%d]", formatRef(&b1, i), lirNames[op], - formatAccSet(&b2, i, /*isLoad*/true), + VMPI_snprintf(s, n, "%s = %s.%s %s[%d]", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, i->accSet()), formatRef(&b3, i->oprnd1()), i->disp()); break; @@ -2086,8 +2123,8 @@ namespace nanojit case LIR_stb: case LIR_sts: case LIR_st32f: - VMPI_snprintf(s, n, "%s%s %s[%d] = %s", lirNames[op], - formatAccSet(&b1, i, /*isLoad*/false), + VMPI_snprintf(s, n, "%s.%s %s[%d] = %s", lirNames[op], + formatAccSet(&b1, i->accSet()), formatRef(&b2, i->oprnd2()), i->disp(), formatRef(&b3, i->oprnd1())); @@ -2103,17 +2140,21 @@ namespace nanojit CseFilter::CseFilter(LirWriter *out, Allocator& alloc) - : LirWriter(out) + : LirWriter(out), storesSinceLastLoad(ACC_NONE) { uint32_t kInitialCaps[LInsLast + 1]; - kInitialCaps[LInsImm] = 128; - kInitialCaps[LInsImmq] = PTR_SIZE(0, 16); - kInitialCaps[LInsImmf] = 16; - kInitialCaps[LIns1] = 256; - kInitialCaps[LIns2] = 512; - kInitialCaps[LIns3] = 16; - kInitialCaps[LInsLoad] = 16; - kInitialCaps[LInsCall] = 64; + kInitialCaps[LInsImm] = 128; + kInitialCaps[LInsImmq] = PTR_SIZE(0, 16); + kInitialCaps[LInsImmf] = 16; + kInitialCaps[LIns1] = 256; + kInitialCaps[LIns2] = 512; + kInitialCaps[LIns3] = 16; + kInitialCaps[LInsCall] = 64; + kInitialCaps[LInsLoadReadOnly] = 16; + kInitialCaps[LInsLoadStack] = 16; + kInitialCaps[LInsLoadRStack] = 16; + kInitialCaps[LInsLoadOther] = 16; + kInitialCaps[LInsLoadMultiple] = 16; exprs = new (alloc) LInsHashSet(alloc, kInitialCaps); } @@ -2121,13 +2162,14 @@ namespace nanojit { uint32_t k; LInsp ins = exprs->findImm(imm, k); - if (ins) - return ins; - ins = out->insImm(imm); + if (!ins) { + ins = out->insImm(imm); + exprs->add(LInsImm, ins, k); + } // We assume that downstream stages do not modify the instruction, so // that we can insert 'ins' into slot 'k'. Check this. - NanoAssert(ins->opcode() == LIR_int && ins->imm32() == imm); - return exprs->add(LInsImm, ins, k); + NanoAssert(ins->isop(LIR_int) && ins->imm32() == imm); + return ins; } #ifdef NANOJIT_64BIT @@ -2135,11 +2177,12 @@ namespace nanojit { uint32_t k; LInsp ins = exprs->findImmq(q, k); - if (ins) - return ins; - ins = out->insImmq(q); - NanoAssert(ins->opcode() == LIR_quad && ins->imm64() == q); - return exprs->add(LInsImmq, ins, k); + if (!ins) { + ins = out->insImmq(q); + exprs->add(LInsImmq, ins, k); + } + NanoAssert(ins->isop(LIR_quad) && ins->imm64() == q); + return ins; } #endif @@ -2154,85 +2197,121 @@ namespace nanojit } u; u.d = d; LInsp ins = exprs->findImmf(u.u64, k); - if (ins) - return ins; - ins = out->insImmf(d); - NanoAssert(ins->opcode() == LIR_float && ins->imm64() == u.u64); - return exprs->add(LInsImmf, ins, k); + if (!ins) { + ins = out->insImmf(d); + exprs->add(LInsImmf, ins, k); + } + NanoAssert(ins->isop(LIR_float) && ins->imm64() == u.u64); + return ins; } - LIns* CseFilter::ins0(LOpcode v) + LIns* CseFilter::ins0(LOpcode op) { - if (v == LIR_label) + if (op == LIR_label) exprs->clear(); - return out->ins0(v); + return out->ins0(op); } - LIns* CseFilter::ins1(LOpcode v, LInsp a) + LIns* CseFilter::ins1(LOpcode op, LInsp a) { - if (isCseOpcode(v)) { + LInsp ins; + if (isCseOpcode(op)) { uint32_t k; - LInsp ins = exprs->find1(v, a, k); - if (ins) - return ins; - ins = out->ins1(v, a); - NanoAssert(ins->opcode() == v && ins->oprnd1() == a); - return exprs->add(LIns1, ins, k); - } - return out->ins1(v,a); - } - - LIns* CseFilter::ins2(LOpcode v, LInsp a, LInsp b) - { - if (isCseOpcode(v)) { - uint32_t k; - LInsp ins = exprs->find2(v, a, b, k); - if (ins) - return ins; - ins = out->ins2(v, a, b); - NanoAssert(ins->opcode() == v && ins->oprnd1() == a && ins->oprnd2() == b); - return exprs->add(LIns2, ins, k); - } - return out->ins2(v,a,b); - } - - LIns* CseFilter::ins3(LOpcode v, LInsp a, LInsp b, LInsp c) - { - NanoAssert(isCseOpcode(v)); - uint32_t k; - LInsp ins = exprs->find3(v, a, b, c, k); - if (ins) - return ins; - ins = out->ins3(v, a, b, c); - NanoAssert(ins->opcode() == v && ins->oprnd1() == a && ins->oprnd2() == b && - ins->oprnd3() == c); - return exprs->add(LIns3, ins, k); - } - - LIns* CseFilter::insLoad(LOpcode v, LInsp base, int32_t disp, AccSet accSet) - { - if (isS16(disp)) { - // XXX: This condition is overly strict. Bug 517910 will make it better. - if (accSet == ACC_READONLY) { - uint32_t k; - LInsp ins = exprs->findLoad(v, base, disp, k); - if (ins) - return ins; - ins = out->insLoad(v, base, disp, accSet); - NanoAssert(ins->opcode() == v && ins->oprnd1() == base && ins->disp() == disp); - return exprs->add(LInsLoad, ins, k); + ins = exprs->find1(op, a, k); + if (!ins) { + ins = out->ins1(op, a); + exprs->add(LIns1, ins, k); } - return out->insLoad(v, base, disp, accSet); + } else { + ins = out->ins1(op, a); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a); + return ins; + } + + LIns* CseFilter::ins2(LOpcode op, LInsp a, LInsp b) + { + LInsp ins; + if (isCseOpcode(op)) { + uint32_t k; + ins = exprs->find2(op, a, b, k); + if (!ins) { + ins = out->ins2(op, a, b); + exprs->add(LIns2, ins, k); + } + } else { + ins = out->ins2(op, a, b); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b); + return ins; + } + + LIns* CseFilter::ins3(LOpcode op, LInsp a, LInsp b, LInsp c) + { + NanoAssert(isCseOpcode(op)); + uint32_t k; + LInsp ins = exprs->find3(op, a, b, c, k); + if (!ins) { + ins = out->ins3(op, a, b, c); + exprs->add(LIns3, ins, k); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b && ins->oprnd3() == c); + return ins; + } + + LIns* CseFilter::insLoad(LOpcode op, LInsp base, int32_t disp, AccSet loadAccSet) + { + LInsp ins; + if (isS16(disp)) { + // Clear all loads aliased by stores and calls since the last time + // we were in this function. + if (storesSinceLastLoad != ACC_NONE) { + NanoAssert(!(storesSinceLastLoad & ACC_READONLY)); // can't store to READONLY + if (storesSinceLastLoad & ACC_STACK) { exprs->clear(LInsLoadStack); } + if (storesSinceLastLoad & ACC_RSTACK) { exprs->clear(LInsLoadRStack); } + if (storesSinceLastLoad & ACC_OTHER) { exprs->clear(LInsLoadOther); } + // Loads marked with multiple access regions must be treated + // conservatively -- we always clear all of them. + exprs->clear(LInsLoadMultiple); + storesSinceLastLoad = ACC_NONE; + } + + LInsHashKind kind; + switch (loadAccSet) { + case ACC_READONLY: kind = LInsLoadReadOnly; break; + case ACC_STACK: kind = LInsLoadStack; break; + case ACC_RSTACK: kind = LInsLoadRStack; break; + case ACC_OTHER: kind = LInsLoadOther; break; + default: kind = LInsLoadMultiple; break; + } + + uint32_t k; + ins = exprs->findLoad(op, base, disp, loadAccSet, kind, k); + if (!ins) { + ins = out->insLoad(op, base, disp, loadAccSet); + exprs->add(kind, ins, k); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == base && ins->disp() == disp); + } else { // If the displacement is more than 16 bits, put it in a separate - // instruction. LirBufWriter also does this, we do it here as - // well because CseFilter relies on LirBufWriter not changing - // code. - return insLoad(v, ins2(LIR_addp, base, insImmWord(disp)), 0, accSet); + // instruction. Nb: LirBufWriter also does this, we do it here + // too because CseFilter relies on LirBufWriter not changing code. + ins = insLoad(op, ins2(LIR_addp, base, insImmWord(disp)), 0, loadAccSet); } + return ins; } - LInsp CseFilter::insGuard(LOpcode v, LInsp c, GuardRecord *gr) + LIns* CseFilter::insStore(LOpcode op, LInsp value, LInsp base, int32_t disp, AccSet accSet) + { + storesSinceLastLoad |= accSet; + LIns* ins = out->insStore(op, value, base, disp, accSet); + NanoAssert(ins->isop(op) && ins->oprnd1() == value && ins->oprnd2() == base && + ins->disp() == disp && ins->accSet() == accSet); + return ins; + } + + LInsp CseFilter::insGuard(LOpcode op, LInsp c, GuardRecord *gr) { // LIR_xt and LIR_xf guards are CSEable. Note that we compare the // opcode and condition when determining if two guards are equivalent @@ -2251,104 +2330,58 @@ namespace nanojit // - The CSE algorithm will always keep guard 1 and remove guard 2 // (not vice versa). The current algorithm does this. // - if (isCseOpcode(v)) { + LInsp ins; + if (isCseOpcode(op)) { // conditional guard uint32_t k; - LInsp ins = exprs->find1(v, c, k); - if (ins) - return 0; - ins = out->insGuard(v, c, gr); - NanoAssert(ins->opcode() == v && ins->oprnd1() == c); - return exprs->add(LIns1, ins, k); + ins = exprs->find1(op, c, k); + if (!ins) { + ins = out->insGuard(op, c, gr); + exprs->add(LIns1, ins, k); + } + } else { + ins = out->insGuard(op, c, gr); } - return out->insGuard(v, c, gr); + NanoAssert(ins->isop(op) && ins->oprnd1() == c); + return ins; } - LInsp CseFilter::insGuardXov(LOpcode v, LInsp a, LInsp b, GuardRecord *gr) + LInsp CseFilter::insGuardXov(LOpcode op, LInsp a, LInsp b, GuardRecord *gr) { // LIR_*xov are CSEable. See CseFilter::insGuard() for details. - NanoAssert(isCseOpcode(v)); + NanoAssert(isCseOpcode(op)); // conditional guard uint32_t k; - LInsp ins = exprs->find2(v, a, b, k); - if (ins) - return ins; - ins = out->insGuardXov(v, a, b, gr); - NanoAssert(ins->opcode() == v && ins->oprnd1() == a && ins->oprnd2() == b); - return exprs->add(LIns2, ins, k); + LInsp ins = exprs->find2(op, a, b, k); + if (!ins) { + ins = out->insGuardXov(op, a, b, gr); + exprs->add(LIns2, ins, k); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b); + return ins; } LInsp CseFilter::insCall(const CallInfo *ci, LInsp args[]) { + LInsp ins; + uint32_t argc = ci->count_args(); if (ci->_isPure) { NanoAssert(ci->_storeAccSet == ACC_NONE); uint32_t k; - uint32_t argc = ci->count_args(); - LInsp ins = exprs->findCall(ci, argc, args, k); - if (ins) - return ins; - ins = out->insCall(ci, args); - NanoAssert(ins->isCall() && ins->callInfo() == ci && argsmatch(ins, argc, args)); - return exprs->add(LInsCall, ins, k); - } - return out->insCall(ci, args); - } - - LInsp LoadFilter::insLoad(LOpcode v, LInsp base, int32_t disp, AccSet accSet) - { - if (base != sp && base != rp) - { - switch (v) - { - case LIR_ld: - CASE64(LIR_ldq:) - case LIR_ldf: - case LIR_ld32f: - case LIR_ldsb: - case LIR_ldss: - case LIR_ldzb: - case LIR_ldzs: - { - uint32_t k; - LInsp ins = exprs->findLoad(v, base, disp, k); - if (ins) - return ins; - ins = out->insLoad(v, base, disp, accSet); - return exprs->add(LInsLoad, ins, k); - } - default: - // fall thru - break; + ins = exprs->findCall(ci, argc, args, k); + if (!ins) { + ins = out->insCall(ci, args); + exprs->add(LInsCall, ins, k); } + } else { + // We only need to worry about aliasing if !ci->_isPure. + storesSinceLastLoad |= ci->_storeAccSet; + ins = out->insCall(ci, args); } - return out->insLoad(v, base, disp, accSet); + NanoAssert(ins->isCall() && ins->callInfo() == ci && argsmatch(ins, argc, args)); + return ins; } - void LoadFilter::clear(LInsp p) - { - if (p != sp && p != rp) - exprs->clear(); - } - - LInsp LoadFilter::insStore(LOpcode op, LInsp v, LInsp b, int32_t d, AccSet accSet) - { - clear(b); - return out->insStore(op, v, b, d, accSet); - } - - LInsp LoadFilter::insCall(const CallInfo *ci, LInsp args[]) - { - if (!ci->_isPure) - exprs->clear(); - return out->insCall(ci, args); - } - - LInsp LoadFilter::ins0(LOpcode op) - { - if (op == LIR_label) - exprs->clear(); - return out->ins0(op); - } #if NJ_SOFTFLOAT_SUPPORTED static double FASTCALL i2f(int32_t i) { return i; } @@ -2564,7 +2597,7 @@ namespace nanojit NanoAssertMsgf(0, "LIR type error (%s): arg %d of '%s' is '%s' " "which has type %s (expected %s)", - _whereInPipeline, i+1, lirNames[op], + whereInPipeline, i+1, lirNames[op], lirNames[args[i]->opcode()], type2string(actual), type2string(formal)); } @@ -2576,15 +2609,16 @@ namespace nanojit { NanoAssertMsgf(0, "LIR structure error (%s): %s %d of '%s' is '%s' (expected %s)", - _whereInPipeline, argDesc, argN, + whereInPipeline, argDesc, argN, lirNames[op], lirNames[arg->opcode()], shouldBeDesc); } - void ValidateWriter::errorAccSetShould(const char* what, AccSet accSet, const char* shouldDesc) + void ValidateWriter::errorAccSet(const char* what, AccSet accSet, const char* shouldDesc) { + RefBuf b; NanoAssertMsgf(0, - "LIR AccSet error (%s): '%s' AccSet is %d; it should %s", - _whereInPipeline, what, accSet, shouldDesc); + "LIR AccSet error (%s): '%s' AccSet is '%s'; %s", + whereInPipeline, what, printer->formatAccSet(&b, accSet), shouldDesc); } void ValidateWriter::checkLInsIsACondOrConst(LOpcode op, int argN, LIns* ins) @@ -2609,17 +2643,60 @@ namespace nanojit errorStructureShouldBe(op, "argument", argN, ins, lirNames[op2]); } - ValidateWriter::ValidateWriter(LirWriter *out, const char* stageName) - : LirWriter(out), _whereInPipeline(stageName) + void ValidateWriter::checkAccSet(LOpcode op, LInsp base, AccSet accSet, AccSet maxAccSet) + { + if (accSet == ACC_NONE) + errorAccSet(lirNames[op], accSet, "it should not equal ACC_NONE"); + + if (accSet & ~maxAccSet) + errorAccSet(lirNames[op], accSet, + "it should not contain bits that aren't in ACC_LOAD_ANY/ACC_STORE_ANY"); + + // Some sanity checking, which is based on the following assumptions: + // - STACK ones should use 'sp' or 'sp+k' as the base. (We could look + // for more complex patterns, but that feels dangerous. Better to + // keep it really simple.) + // - RSTACK ones should use 'rp' as the base. + // - READONLY/OTHER ones should not use 'sp'/'sp+k' or 'rp' as the base. + // + // Things that aren't checked: + // - There's no easy way to check if READONLY ones really are read-only. + + bool isStack = base == sp || + (base->isop(LIR_piadd) && base->oprnd1() == sp && base->oprnd2()->isconstp()); + bool isRStack = base == rp; + + switch (accSet) { + case ACC_STACK: + if (!isStack) + errorAccSet(lirNames[op], accSet, "but it's not a stack access"); + break; + + case ACC_RSTACK: + if (!isRStack) + errorAccSet(lirNames[op], accSet, "but it's not an rstack access"); + break; + + case ACC_READONLY: + case ACC_OTHER: + if (isStack) + errorAccSet(lirNames[op], accSet, "but it's a stack access"); + if (isRStack) + errorAccSet(lirNames[op], accSet, "but it's an rstack access"); + break; + + default: + break; + } + } + + ValidateWriter::ValidateWriter(LirWriter *out, LInsPrinter* printer, const char* where) + : LirWriter(out), printer(printer), whereInPipeline(where), sp(0), rp(0) {} LIns* ValidateWriter::insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet) { - if (accSet == ACC_NONE) - errorAccSetShould(lirNames[op], accSet, "not equal ACC_NONE"); - - if (accSet & ~ACC_LOAD_ANY) - errorAccSetShould(lirNames[op], accSet, "not contain bits that aren't in ACC_LOAD_ANY"); + checkAccSet(op, base, accSet, ACC_LOAD_ANY); int nArgs = 1; LTy formals[1] = { LTy_Ptr }; @@ -2646,11 +2723,7 @@ namespace nanojit LIns* ValidateWriter::insStore(LOpcode op, LIns* value, LIns* base, int32_t d, AccSet accSet) { - if (accSet == ACC_NONE) - errorAccSetShould(lirNames[op], accSet, "not equal ACC_NONE"); - - if (accSet & ~ACC_STORE_ANY) - errorAccSetShould(lirNames[op], accSet, "not contain bits that aren't in ACC_STORE_ANY"); + checkAccSet(op, base, accSet, ACC_STORE_ANY); int nArgs = 2; LTy formals[2] = { LTy_Void, LTy_Ptr }; // LTy_Void is overwritten shortly @@ -2680,7 +2753,7 @@ namespace nanojit typeCheckArgs(op, nArgs, formals, args); - return out->insStore(op, value, base, d); + return out->insStore(op, value, base, d, accSet); } LIns* ValidateWriter::ins0(LOpcode op) @@ -2923,11 +2996,11 @@ namespace nanojit LOpcode op = getCallOpcode(ci); if (ci->_isPure && ci->_storeAccSet != ACC_NONE) - errorAccSetShould(ci->_name, ci->_storeAccSet, "equal ACC_NONE for pure functions"); + errorAccSet(ci->_name, ci->_storeAccSet, "it should be ACC_NONE for pure functions"); if (ci->_storeAccSet & ~ACC_STORE_ANY) - errorAccSetShould(lirNames[op], ci->_storeAccSet, - "not contain bits that aren't in ACC_STORE_ANY"); + errorAccSet(lirNames[op], ci->_storeAccSet, + "it should not contain bits that aren't in ACC_STORE_ANY"); // This loop iterates over the args from right-to-left (because arg() // and getArgTypes() use right-to-left order), but puts the results diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 783afeb79ff9..7f16a6b7f58d 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -210,7 +210,10 @@ namespace nanojit // A load from a READONLY region will never alias with any stores. // // - STACK: the stack. Stack loads/stores can usually be easily - // identified because they use SP as the stack pointer. + // identified because they use SP as the base pointer. + // + // - RSTACK: the return stack. Return stack loads/stores can usually be + // easily identified because they use RP as the base pointer. // // - OTHER: all other regions of memory. // @@ -259,6 +262,14 @@ namespace nanojit // true for the store set of a function.) // // Such imprecision is safe but may reduce optimisation opportunities. + // + // Optimisations that use access region info + // ----------------------------------------- + // Currently only CseFilter uses this, and only for determining whether + // loads can be CSE'd. Note that CseFilter treats loads that are marked + // with a single access region precisely, but all loads marked with + // multiple access regions get lumped together. So if you can't mark a + // load with a single access region, you might as well use ACC_LOAD_ANY. //----------------------------------------------------------------------- // An access region set is represented as a bitset. Nb: this restricts us @@ -267,11 +278,13 @@ namespace nanojit // The access regions. Note that because of the bitset representation // these constants are also valid (singleton) AccSet values. If you add - // new ones please update ACC_ALL_WRITABLE and LirNameMap::formatAccSet(). + // new ones please update ACC_ALL_STORABLE and formatAccSet() and + // CseFilter. // static const AccSet ACC_READONLY = 1 << 0; // 0000_0001b static const AccSet ACC_STACK = 1 << 1; // 0000_0010b - static const AccSet ACC_OTHER = 1 << 2; // 0000_0100b + static const AccSet ACC_RSTACK = 1 << 2; // 0000_0100b + static const AccSet ACC_OTHER = 1 << 3; // 0000_1000b // Some common (non-singleton) access region sets. ACC_NONE does not make // sense for loads or stores (which must access at least one region), it @@ -279,15 +292,14 @@ namespace nanojit // // A convention that's worth using: use ACC_LOAD_ANY/ACC_STORE_ANY for // cases that you're unsure about or haven't considered carefully. Use - // ACC_ALL/ACC_ALL_WRITABLE for cases that you have considered carefully. + // ACC_ALL/ACC_ALL_STORABLE for cases that you have considered carefully. // That way it's easy to tell which ones have been considered and which // haven't. static const AccSet ACC_NONE = 0x0; - static const AccSet ACC_ALL_WRITABLE = ACC_STACK | ACC_OTHER; - static const AccSet ACC_ALL = ACC_READONLY | ACC_ALL_WRITABLE; + static const AccSet ACC_ALL_STORABLE = ACC_STACK | ACC_RSTACK | ACC_OTHER; + static const AccSet ACC_ALL = ACC_READONLY | ACC_ALL_STORABLE; static const AccSet ACC_LOAD_ANY = ACC_ALL; // synonym - static const AccSet ACC_STORE_ANY = ACC_ALL_WRITABLE; // synonym - + static const AccSet ACC_STORE_ANY = ACC_ALL_STORABLE; // synonym struct CallInfo { @@ -1488,17 +1500,6 @@ namespace nanojit // Chooses LIR_sti or LIR_stqi based on size of value. LIns* insStorei(LIns* value, LIns* base, int32_t d, AccSet accSet); - - // Insert a load/store with the most pessimistic region access info, which is always safe. - LIns* insLoad(LOpcode op, LIns* base, int32_t d) { - return insLoad(op, base, d, ACC_LOAD_ANY); - } - LIns* insStore(LOpcode op, LIns* value, LIns* base, int32_t d) { - return insStore(op, value, base, d, ACC_STORE_ANY); - } - LIns* insStorei(LIns* value, LIns* base, int32_t d) { - return insStorei(value, base, d, ACC_STORE_ANY); - } }; @@ -1598,7 +1599,6 @@ namespace nanojit void formatImmq(RefBuf* buf, uint64_t c); void formatGuard(InsBuf* buf, LInsp ins); void formatGuardXov(InsBuf* buf, LInsp ins); - char* formatAccSet(RefBuf* buf, LInsp ins, bool isLoad); public: LInsPrinter(Allocator& alloc) @@ -1611,6 +1611,7 @@ namespace nanojit char *formatAddr(RefBuf* buf, void* p); char *formatRef(RefBuf* buf, LInsp ref); char *formatIns(InsBuf* buf, LInsp ins); + char *formatAccSet(RefBuf* buf, AccSet accSet); AddrNameMap* addrNameMap; LirNameMap* lirNameMap; @@ -1739,23 +1740,35 @@ namespace nanojit // We divide instruction kinds into groups for the use of LInsHashSet. // LIns0 isn't present because we don't need to record any 0-ary // instructions. - LInsImm = 0, - LInsImmq = 1, // only occurs on 64-bit platforms - LInsImmf = 2, - LIns1 = 3, - LIns2 = 4, - LIns3 = 5, - LInsLoad = 6, - LInsCall = 7, + LInsImm = 0, + LInsImmq = 1, // only occurs on 64-bit platforms + LInsImmf = 2, + LIns1 = 3, + LIns2 = 4, + LIns3 = 5, + LInsCall = 6, + + // Loads are special. We group them by access region: one table for + // each region, and then a catch-all table for any loads marked with + // multiple regions. This arrangement makes the removal of + // invalidated loads fast -- eg. we can invalidate all STACK loads by + // just clearing the LInsLoadStack table. The disadvantage is that + // loads marked with multiple regions must be invalidated + // conservatively, eg. if any intervening stores occur. But loads + // marked with multiple regions should be rare. + LInsLoadReadOnly = 7, + LInsLoadStack = 8, + LInsLoadRStack = 9, + LInsLoadOther = 10, + LInsLoadMultiple = 11, LInsFirst = 0, - LInsLast = 7, + LInsLast = 11, // need a value after "last" to outsmart compilers that will insist last+1 is impossible - LInsInvalid = 8 + LInsInvalid = 12 }; #define nextKind(kind) LInsHashKind(kind+1) - // @todo, this could be replaced by a generic HashMap or HashSet, if we had one class LInsHashSet { // Must be a power of 2. @@ -1772,14 +1785,15 @@ namespace nanojit uint32_t m_used[LInsLast + 1]; typedef uint32_t (LInsHashSet::*find_t)(LInsp); find_t m_find[LInsLast + 1]; + Allocator& alloc; static uint32_t hashImm(int32_t); - static uint32_t hashImmq(uint64_t); // not NANOJIT_64BIT only used by findImmf() - static uint32_t hash1(LOpcode v, LInsp); - static uint32_t hash2(LOpcode v, LInsp, LInsp); - static uint32_t hash3(LOpcode v, LInsp, LInsp, LInsp); - static uint32_t hashLoad(LOpcode v, LInsp, int32_t); + static uint32_t hashImmq(uint64_t); // not NANOJIT_64BIT-only -- used by findImmf() + static uint32_t hash1(LOpcode op, LInsp); + static uint32_t hash2(LOpcode op, LInsp, LInsp); + static uint32_t hash3(LOpcode op, LInsp, LInsp, LInsp); + static uint32_t hashLoad(LOpcode op, LInsp, int32_t, AccSet); static uint32_t hashCall(const CallInfo *call, uint32_t argc, LInsp args[]); // These private versions are used after an LIns has been created; @@ -1792,8 +1806,12 @@ namespace nanojit uint32_t find1(LInsp ins); uint32_t find2(LInsp ins); uint32_t find3(LInsp ins); - uint32_t findLoad(LInsp ins); uint32_t findCall(LInsp ins); + uint32_t findLoadReadOnly(LInsp ins); + uint32_t findLoadStack(LInsp ins); + uint32_t findLoadRStack(LInsp ins); + uint32_t findLoadOther(LInsp ins); + uint32_t findLoadMultiple(LInsp ins); void grow(LInsHashKind kind); @@ -1810,19 +1828,22 @@ namespace nanojit LInsp find1(LOpcode v, LInsp a, uint32_t &k); LInsp find2(LOpcode v, LInsp a, LInsp b, uint32_t &k); LInsp find3(LOpcode v, LInsp a, LInsp b, LInsp c, uint32_t &k); - LInsp findLoad(LOpcode v, LInsp a, int32_t b, uint32_t &k); + LInsp findLoad(LOpcode v, LInsp a, int32_t b, AccSet accSet, LInsHashKind kind, + uint32_t &k); LInsp findCall(const CallInfo *call, uint32_t argc, LInsp args[], uint32_t &k); // 'k' is the index found by findXYZ(). - LInsp add(LInsHashKind kind, LInsp ins, uint32_t k); + void add(LInsHashKind kind, LInsp ins, uint32_t k); - void clear(); + void clear(); // clears all tables + void clear(LInsHashKind); // clears one table }; class CseFilter: public LirWriter { private: LInsHashSet* exprs; + AccSet storesSinceLastLoad; // regions stored to since the last load public: CseFilter(LirWriter *out, Allocator&); @@ -1836,7 +1857,8 @@ namespace nanojit LIns* ins1(LOpcode v, LInsp); LIns* ins2(LOpcode v, LInsp, LInsp); LIns* ins3(LOpcode v, LInsp, LInsp, LInsp); - LIns* insLoad(LOpcode op, LInsp cond, int32_t d, AccSet accSet); + LIns* insLoad(LOpcode op, LInsp base, int32_t d, AccSet accSet); + LIns* insStore(LOpcode op, LInsp value, LInsp base, int32_t d, AccSet accSet); LIns* insCall(const CallInfo *call, LInsp args[]); LIns* insGuard(LOpcode op, LInsp cond, GuardRecord *gr); LIns* insGuardXov(LOpcode op, LInsp a, LInsp b, GuardRecord *gr); @@ -1975,37 +1997,6 @@ namespace nanojit LInsp read(); }; - // eliminate redundant loads by watching for stores & mutator calls - class LoadFilter: public LirWriter - { - public: - LInsp sp, rp; - LInsHashSet* exprs; - - void clear(LInsp p); - - public: - LoadFilter(LirWriter *out, Allocator& alloc) - : LirWriter(out), sp(NULL), rp(NULL) - { - uint32_t kInitialCaps[LInsLast + 1]; - kInitialCaps[LInsImm] = 1; - kInitialCaps[LInsImmq] = 1; - kInitialCaps[LInsImmf] = 1; - kInitialCaps[LIns1] = 1; - kInitialCaps[LIns2] = 1; - kInitialCaps[LIns3] = 1; - kInitialCaps[LInsLoad] = 64; - kInitialCaps[LInsCall] = 1; - exprs = new (alloc) LInsHashSet(alloc, kInitialCaps); - } - - LInsp ins0(LOpcode); - LInsp insLoad(LOpcode op, LInsp base, int32_t disp, AccSet accSet); - LInsp insStore(LOpcode op, LInsp value, LInsp base, int32_t disp, AccSet accSet); - LInsp insCall(const CallInfo *call, LInsp args[]); - }; - struct SoftFloatOps { const CallInfo* opmap[LIR_sentinel]; @@ -2049,19 +2040,26 @@ namespace nanojit class ValidateWriter : public LirWriter { private: - const char* _whereInPipeline; + LInsPrinter* printer; + const char* whereInPipeline; const char* type2string(LTy type); void typeCheckArgs(LOpcode op, int nArgs, LTy formals[], LIns* args[]); void errorStructureShouldBe(LOpcode op, const char* argDesc, int argN, LIns* arg, const char* shouldBeDesc); - void errorAccSetShould(const char* what, AccSet accSet, const char* shouldDesc); + void errorAccSet(const char* what, AccSet accSet, const char* shouldDesc); void checkLInsHasOpcode(LOpcode op, int argN, LIns* ins, LOpcode op2); void checkLInsIsACondOrConst(LOpcode op, int argN, LIns* ins); void checkLInsIsNull(LOpcode op, int argN, LIns* ins); + void checkAccSet(LOpcode op, LInsp base, AccSet accSet, AccSet maxAccSet); + + LInsp sp, rp; public: - ValidateWriter(LirWriter* out, const char* stageName); + ValidateWriter(LirWriter* out, LInsPrinter* printer, const char* where); + void setSp(LInsp ins) { sp = ins; } + void setRp(LInsp ins) { rp = ins; } + LIns* insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet); LIns* insStore(LOpcode op, LIns* value, LIns* base, int32_t d, AccSet accSet); LIns* ins0(LOpcode v); From cec9f7618e9f377e3d182e44906a0a6e72d936d9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 23 Mar 2010 15:28:41 -0700 Subject: [PATCH 122/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index b44048c4d7e6..93f6e8c4bb4b 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -2ad8e20152c94b63d55143199c080c087e987ea9 +26cbea5a2acdcc6156b4a72b0c40c0d675f69571 From db6d060ba95661396cde938ff9d703f82b831bac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 23 Mar 2010 15:49:12 -0700 Subject: [PATCH 123/213] Follow-up assertion failure fix for bug 517910. r=me. --HG-- extra : convert_revision : dfaf13aa4c5928bcd871ac7f279657c87de7b0f9 --- js/src/nanojit/LIR.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 45fca4f3bde9..2a71fa4f697d 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -2304,10 +2304,18 @@ namespace nanojit LIns* CseFilter::insStore(LOpcode op, LInsp value, LInsp base, int32_t disp, AccSet accSet) { - storesSinceLastLoad |= accSet; - LIns* ins = out->insStore(op, value, base, disp, accSet); - NanoAssert(ins->isop(op) && ins->oprnd1() == value && ins->oprnd2() == base && - ins->disp() == disp && ins->accSet() == accSet); + LInsp ins; + if (isS16(disp)) { + storesSinceLastLoad |= accSet; + ins = out->insStore(op, value, base, disp, accSet); + NanoAssert(ins->isop(op) && ins->oprnd1() == value && ins->oprnd2() == base && + ins->disp() == disp && ins->accSet() == accSet); + } else { + // If the displacement is more than 16 bits, put it in a separate + // instruction. Nb: LirBufWriter also does this, we do it here + // too because CseFilter relies on LirBufWriter not changing code. + ins = insStore(op, value, ins2(LIR_addp, base, insImmWord(disp)), 0, accSet); + } return ins; } From e13cb1ac370c8780ab69aa8d5f5e6e217656cd40 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 23 Mar 2010 16:00:38 -0700 Subject: [PATCH 124/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 93f6e8c4bb4b..3e7be2229de5 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -26cbea5a2acdcc6156b4a72b0c40c0d675f69571 +dfaf13aa4c5928bcd871ac7f279657c87de7b0f9 From f26bd7924596d591fdab65997cd1de1c8fdc0dd2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 23 Mar 2010 16:07:19 -0700 Subject: [PATCH 125/213] Bug 517910 - NJ: add more alias-set annotations to LIR so as to improve CSEing of loads (TM-specific part). r=gal,dvander. --- js/src/jsbuiltins.h | 8 - js/src/jsrecursion.cpp | 85 +++-- js/src/jsregexp.cpp | 31 +- js/src/jstracer.cpp | 313 ++++++++++-------- js/src/jstracer.h | 10 +- .../tests/basic/bigLoadStoreDisp.js | 25 ++ 6 files changed, 271 insertions(+), 201 deletions(-) create mode 100644 js/src/trace-test/tests/basic/bigLoadStoreDisp.js diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h index ebb4edf970ae..4018bc98b284 100644 --- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -260,10 +260,6 @@ struct ClosureVarInfo; _JS_TN_LINKAGE(linkage, crtype) name cargtypes; \ _JS_CI_LINKAGE(linkage) const nanojit::CallInfo _JS_CALLINFO(name) = \ { (intptr_t) &name, argtypes, nanojit::ABI_CDECL, isPure, storeAccSet _JS_CI_NAME(name) };\ - /* XXX: a temporary assertion to check all cse/fold pairs are correctly */ \ - /* converted to isPure/storeAccSet pairs for bug 545274. Will be removed */ \ - /* when bug 517910 starts doing more precise storeAccSet markings. */ \ - JS_STATIC_ASSERT_IF(!isPure, storeAccSet == nanojit::ACC_STORE_ANY); /* temporary */ \ JS_STATIC_ASSERT_IF(isPure, storeAccSet == nanojit::ACC_NONE); #else @@ -271,10 +267,6 @@ struct ClosureVarInfo; _JS_TN_LINKAGE(linkage, crtype) FASTCALL name cargtypes; \ _JS_CI_LINKAGE(linkage) const nanojit::CallInfo _JS_CALLINFO(name) = \ { (intptr_t) &name, argtypes, nanojit::ABI_FASTCALL, isPure, storeAccSet _JS_CI_NAME(name) }; \ - /* XXX: a temporary assertion to check all cse/fold pairs are correctly */ \ - /* converted to isPure/storeAccSet pairs for bug 545274. Will be removed */ \ - /* when bug 517910 starts doing more precise storeAccSet markings. */ \ - JS_STATIC_ASSERT_IF(!isPure, storeAccSet == nanojit::ACC_STORE_ANY); /* temporary */ \ JS_STATIC_ASSERT_IF(isPure, storeAccSet == nanojit::ACC_NONE); #endif diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index 1a243df48e2e..8ecbfffaf4c6 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -72,7 +72,7 @@ class RecursiveSlotMap : public SlotMap ptrdiff_t retOffset = downPostSlots * sizeof(double) - mRecorder.tree->nativeStackBase; mRecorder.lir->insStorei(mRecorder.addName(rval_ins, "rval_ins"), - mRecorder.lirbuf->sp, retOffset); + mRecorder.lirbuf->sp, retOffset, ACC_STACK); } }; @@ -109,14 +109,14 @@ class UpRecursiveSlotMap : public RecursiveSlotMap * This makes sense because this slot is just above the highest sp for * the down frame. */ - lir->insStorei(rval_ins, lirbuf->sp, -mRecorder.tree->nativeStackBase); + lir->insStorei(rval_ins, lirbuf->sp, -mRecorder.tree->nativeStackBase, ACC_STACK); lirbuf->sp = lir->ins2(LIR_piadd, lirbuf->sp, lir->insImmWord(-int(downPostSlots) * sizeof(double))); - lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp)); + lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp), ACC_OTHER); lirbuf->rp = lir->ins2(LIR_piadd, lirbuf->rp, lir->insImmWord(-int(sizeof(FrameInfo*)))); - lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp)); + lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp), ACC_OTHER); } }; @@ -289,7 +289,7 @@ TraceRecorder::upRecursion() lir->ins2(LIR_pge, lirbuf->rp, lir->ins2(LIR_piadd, lir->insLoad(LIR_ldp, lirbuf->state, - offsetof(InterpState, sor)), + offsetof(InterpState, sor), ACC_OTHER), INS_CONSTWORD(sizeof(FrameInfo*)))), exit); } @@ -298,7 +298,7 @@ TraceRecorder::upRecursion() /* Guard that the FrameInfo above is the same FrameInfo pointer. */ VMSideExit* exit = snapshot(RECURSIVE_MISMATCH_EXIT); - LIns* prev_rp = lir->insLoad(LIR_ldp, lirbuf->rp, -int32_t(sizeof(FrameInfo*))); + LIns* prev_rp = lir->insLoad(LIR_ldp, lirbuf->rp, -int32_t(sizeof(FrameInfo*)), ACC_RSTACK); guard(true, lir->ins2(LIR_peq, prev_rp, INS_CONSTPTR(fi)), exit); /* @@ -367,7 +367,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) unsigned downPostSlots; JSStackFrame* fp = cx->fp; - LIns* fp_ins = addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)), "fp"); + LIns* fp_ins = + addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER), "fp"); /* * When first emitting slurp code, do so against the down frame. After @@ -376,10 +377,12 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) * anchoring off such an exit. */ if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) { - fp_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, down)), "downFp"); + fp_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, down), ACC_OTHER), + "downFp"); fp = fp->down; - argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv)), "argv"); + argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv), ACC_OTHER), + "argv"); /* If recovering from a SLURP_MISMATCH, all of this is unnecessary. */ if (!anchor || anchor->exitType != RECURSIVE_SLURP_MISMATCH_EXIT) { @@ -397,9 +400,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) */ guard(true, lir->ins2(LIR_peq, - addName(lir->insLoad(LIR_ldp, - fp_ins, - offsetof(JSStackFrame, script)), + addName(lir->insLoad(LIR_ldp, fp_ins, + offsetof(JSStackFrame, script), ACC_OTHER), "script"), INS_CONSTPTR(cx->fp->down->script)), RECURSIVE_LOOP_EXIT); @@ -409,16 +411,18 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) guard(true, lir->ins2(LIR_peq, lir->insLoad(LIR_ldp, - addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, regs)), + addName(lir->insLoad(LIR_ldp, fp_ins, + offsetof(JSStackFrame, regs), ACC_OTHER), "regs"), - offsetof(JSFrameRegs, pc)), + offsetof(JSFrameRegs, pc), ACC_OTHER), INS_CONSTPTR(return_pc)), RECURSIVE_SLURP_MISMATCH_EXIT); /* fp->down->argc should be == argc. */ guard(true, lir->ins2(LIR_eq, - addName(lir->insLoad(LIR_ld, fp_ins, offsetof(JSStackFrame, argc)), + addName(lir->insLoad(LIR_ld, fp_ins, offsetof(JSStackFrame, argc), + ACC_OTHER), "argc"), INS_CONST(cx->fp->argc)), MISMATCH_EXIT); @@ -432,7 +436,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) frameDepth = 1; } else { /* Note: loading argv from fp, not fp->down. */ - argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv)), "argv"); + argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv), ACC_OTHER), + "argv"); /* Slots for this frame, minus the return value. */ downPostSlots = NativeStackSlots(cx, 0) - 1; @@ -506,23 +511,23 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) * The return value must be written out early, before slurping can fail, * otherwise it will not be available when there's a type mismatch. */ - lir->insStorei(rval_ins, lirbuf->sp, offset); + lir->insStorei(rval_ins, lirbuf->sp, offset, ACC_STACK); } else { switch (returnType) { case TT_SPECIAL: case TT_VOID: case TT_INT32: - rval_ins = lir->insLoad(LIR_ld, lirbuf->sp, offset); + rval_ins = lir->insLoad(LIR_ld, lirbuf->sp, offset, ACC_STACK); break; case TT_DOUBLE: - rval_ins = lir->insLoad(LIR_ldf, lirbuf->sp, offset); + rval_ins = lir->insLoad(LIR_ldf, lirbuf->sp, offset, ACC_STACK); break; case TT_FUNCTION: case TT_OBJECT: case TT_STRING: case TT_NULL: - rval_ins = lir->insLoad(LIR_ldp, lirbuf->sp, offset); + rval_ins = lir->insLoad(LIR_ldp, lirbuf->sp, offset, ACC_STACK); break; default: JS_NOT_REACHED("unknown type"); @@ -539,29 +544,36 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) anchor->slurpFailSlot : 0; /* callee */ - slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval))), + slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval)), ACC_OTHER), &fp->argv[-2], &info); /* this */ - slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -1 * ptrdiff_t(sizeof(jsval))), + slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -1 * ptrdiff_t(sizeof(jsval)), ACC_OTHER), &fp->argv[-1], &info); /* args[0..n] */ for (unsigned i = 0; i < JS_MAX(fp->argc, fp->fun->nargs); i++) - slurpSlot(lir->insLoad(LIR_ldp, argv_ins, i * sizeof(jsval)), &fp->argv[i], &info); + slurpSlot(lir->insLoad(LIR_ldp, argv_ins, i * sizeof(jsval), ACC_OTHER), + &fp->argv[i], + &info); /* argsobj */ - slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argsobj)), "argsobj"), + slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argsobj), ACC_OTHER), + "argsobj"), &fp->argsobj, &info); /* scopeChain */ - slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, scopeChain)), "scopeChain"), + slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, scopeChain), ACC_OTHER), + "scopeChain"), &fp->scopeChainVal, &info); /* vars */ - LIns* slots_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, slots)), + LIns* slots_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, slots), + ACC_OTHER), "slots"); for (unsigned i = 0; i < fp->script->nfixed; i++) - slurpSlot(lir->insLoad(LIR_ldp, slots_ins, i * sizeof(jsval)), &fp->slots[i], &info); + slurpSlot(lir->insLoad(LIR_ldp, slots_ins, i * sizeof(jsval), ACC_OTHER), + &fp->slots[i], + &info); /* stack vals */ unsigned nfixed = fp->script->nfixed; jsval* stack = StackBase(fp); @@ -575,7 +587,9 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) else limit -= fp->fun->nargs + 2; for (size_t i = 0; i < limit; i++) - slurpSlot(lir->insLoad(LIR_ldp, stack_ins, i * sizeof(jsval)), &stack[i], &info); + slurpSlot(lir->insLoad(LIR_ldp, stack_ins, i * sizeof(jsval), ACC_OTHER), + &stack[i], + &info); JS_ASSERT(info.curSlot == downPostSlots); @@ -657,9 +671,9 @@ TraceRecorder::downRecursion() /* Add space for a new JIT frame. */ lirbuf->sp = lir->ins2(LIR_piadd, lirbuf->sp, lir->insImmWord(slots * sizeof(double))); - lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp)); + lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp), ACC_OTHER); lirbuf->rp = lir->ins2(LIR_piadd, lirbuf->rp, lir->insImmWord(sizeof(FrameInfo*))); - lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp)); + lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp), ACC_OTHER); --callDepth; clearCurrentFrameSlotsFromTracker(nativeFrameTracker); @@ -700,7 +714,7 @@ TraceRecorder::slurpInt32Slot(LIns* val_ins, jsval* vp, VMSideExit* exit) LIns* args[] = { space, val_ins }; LIns* result = lir->insCall(&js_TryUnboxInt32_ci, args); guard(false, lir->ins_eq0(result), exit); - LIns* int32_ins = lir->insLoad(LIR_ld, space, 0); + LIns* int32_ins = lir->insLoad(LIR_ld, space, 0, ACC_OTHER); return int32_ins; } @@ -775,7 +789,8 @@ TraceRecorder::slurpObjectSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) guard(false, lir->ins2(LIR_peq, lir->ins2(LIR_piand, - lir->insLoad(LIR_ldp, val_ins, offsetof(JSObject, classword)), + lir->insLoad(LIR_ldp, val_ins, offsetof(JSObject, classword), + ACC_OTHER), INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)), INS_CONSTPTR(&js_FunctionClass)), exit); @@ -797,7 +812,8 @@ TraceRecorder::slurpFunctionSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) guard(true, lir->ins2(LIR_peq, lir->ins2(LIR_piand, - lir->insLoad(LIR_ldp, val_ins, offsetof(JSObject, classword)), + lir->insLoad(LIR_ldp, val_ins, offsetof(JSObject, classword), + ACC_OTHER), INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)), INS_CONSTPTR(&js_FunctionClass)), exit); @@ -853,7 +869,8 @@ TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, SlurpInfo* info) LIns* val = slurpSlot(val_ins, vp, exit); lir->insStorei(val, lirbuf->sp, - -tree->nativeStackBase + ptrdiff_t(info->curSlot) * sizeof(double)); + -tree->nativeStackBase + ptrdiff_t(info->curSlot) * sizeof(double), + ACC_STACK); info->curSlot++; } diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 4afef943c6c0..fcbcb4f1dfa5 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -2490,7 +2490,7 @@ class RegExpNativeCompiler { 0); if (!fails.append(to_fail)) return NULL; - LIns* text_word = lir->insLoad(LIR_ld, pos, 0); + LIns* text_word = lir->insLoad(LIR_ld, pos, 0, ACC_OTHER); LIns* comp_word = useFastCI ? lir->ins2(LIR_or, text_word, lir->insImm(mask.i)) : text_word; @@ -2834,7 +2834,7 @@ class RegExpNativeCompiler { * memory (REGlobalData::stateStack, since it is unused). */ lir->insStorei(branchEnd, state, - offsetof(REGlobalData, stateStack)); + offsetof(REGlobalData, stateStack), ACC_OTHER); LIns *leftSuccess = lir->insBranch(LIR_j, NULL, NULL); /* Try right branch. */ @@ -2842,13 +2842,12 @@ class RegExpNativeCompiler { if (!(branchEnd = compileNode(rightRe, pos, atEnd, fails))) return NULL; lir->insStorei(branchEnd, state, - offsetof(REGlobalData, stateStack)); + offsetof(REGlobalData, stateStack), ACC_OTHER); /* Land success on the left branch. */ targetCurrentPoint(leftSuccess); return addName(fragment->lirbuf, - lir->insLoad(LIR_ldp, state, - offsetof(REGlobalData, stateStack)), + lir->insLoad(LIR_ldp, state, offsetof(REGlobalData, stateStack), ACC_OTHER), "pos"); } @@ -2858,19 +2857,18 @@ class RegExpNativeCompiler { * Since there are no phis, simulate by writing to and reading from * memory (REGlobalData::stateStack, since it is unused). */ - lir->insStorei(pos, state, offsetof(REGlobalData, stateStack)); + lir->insStorei(pos, state, offsetof(REGlobalData, stateStack), ACC_OTHER); /* Try ? body. */ LInsList kidFails(cx); if (!(pos = compileNode(node, pos, atEnd, kidFails))) return NULL; - lir->insStorei(pos, state, offsetof(REGlobalData, stateStack)); + lir->insStorei(pos, state, offsetof(REGlobalData, stateStack), ACC_OTHER); /* Join success and failure and get new position. */ targetCurrentPoint(kidFails); pos = addName(fragment->lirbuf, - lir->insLoad(LIR_ldp, state, - offsetof(REGlobalData, stateStack)), + lir->insLoad(LIR_ldp, state, offsetof(REGlobalData, stateStack), ACC_OTHER), "pos"); return pos; @@ -2925,13 +2923,13 @@ class RegExpNativeCompiler { * Since there are no phis, simulate by writing to and reading from * memory (REGlobalData::stateStack, since it is unused). */ - lir->insStorei(pos, state, offsetof(REGlobalData, stateStack)); + lir->insStorei(pos, state, offsetof(REGlobalData, stateStack), ACC_OTHER); /* Begin iteration: load loop variables. */ LIns *loopTop = lir->ins0(LIR_label); LIns *iterBegin = addName(fragment->lirbuf, lir->insLoad(LIR_ldp, state, - offsetof(REGlobalData, stateStack)), + offsetof(REGlobalData, stateStack), ACC_OTHER), "pos"); /* Match quantifier body. */ @@ -2951,7 +2949,7 @@ class RegExpNativeCompiler { } /* End iteration: store loop variables, increment, jump */ - lir->insStorei(iterEnd, state, offsetof(REGlobalData, stateStack)); + lir->insStorei(iterEnd, state, offsetof(REGlobalData, stateStack), ACC_OTHER); lir->insBranch(LIR_j, NULL, loopTop); /* @@ -3049,7 +3047,7 @@ class RegExpNativeCompiler { return false; /* Fall-through from compileNode means success. */ - lir->insStorei(pos, state, offsetof(REGlobalData, stateStack)); + lir->insStorei(pos, state, offsetof(REGlobalData, stateStack), ACC_OTHER); lir->ins0(LIR_regfence); lir->ins1(LIR_ret, lir->insImm(1)); @@ -3088,7 +3086,7 @@ class RegExpNativeCompiler { /* Outer loop increment. */ lir->insStorei(lir->ins2(LIR_piadd, start, lir->insImmWord(2)), state, - offsetof(REGlobalData, skipped)); + offsetof(REGlobalData, skipped), ACC_OTHER); return !outOfMemory(); } @@ -3192,7 +3190,7 @@ class RegExpNativeCompiler { ) #endif #ifdef DEBUG - lir = validate_writer = new ValidateWriter(lir, "regexp writer pipeline"); + lir = validate_writer = new ValidateWriter(lir, lirbuf->printer, "regexp writer pipeline"); #endif /* @@ -3221,8 +3219,7 @@ class RegExpNativeCompiler { }) start = addName(lirbuf, - lir->insLoad(LIR_ldp, state, - offsetof(REGlobalData, skipped)), + lir->insLoad(LIR_ldp, state, offsetof(REGlobalData, skipped), ACC_OTHER), "start"); if (cs->flags & JSREG_STICKY) { diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 73da3900bcb1..773ed3ef8bd9 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -837,7 +837,7 @@ TraceRecorder::tprint(const char *format, int count, nanojit::LIns *insa[]) double *args = (double*) traceMonitor->traceAlloc->alloc(count * sizeof(double)); for (int i = 0; i < count; ++i) { JS_ASSERT(insa[i]); - lir->insStorei(insa[i], INS_CONSTPTR(args), sizeof(double) * i); + lir->insStorei(insa[i], INS_CONSTPTR(args), sizeof(double) * i, ACC_OTHER); } LIns* args_ins[] = { INS_CONSTPTR(args), INS_CONST(count), INS_CONSTPTR(data) }; @@ -2213,7 +2213,9 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag nanojit::LirWriter*& lir = InitConst(this->lir); lir = new (tempAlloc()) LirBufWriter(lirbuf, nanojit::AvmCore::config); #ifdef DEBUG - lir = new (tempAlloc()) ValidateWriter(lir, "end of writer pipeline"); + ValidateWriter* validate2; + lir = validate2 = + new (tempAlloc()) ValidateWriter(lir, lirbuf->printer, "end of writer pipeline"); #endif debug_only_stmt( if (LogController.lcbits & LC_TMRecorder) { @@ -2231,7 +2233,9 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag lir = new (tempAlloc()) ExprFilter(lir); lir = new (tempAlloc()) FuncFilter(lir); #ifdef DEBUG - lir = new (tempAlloc()) ValidateWriter(lir, "start of writer pipeline"); + ValidateWriter* validate1; + lir = validate1 = + new (tempAlloc()) ValidateWriter(lir, lirbuf->printer, "start of writer pipeline"); #endif lir->ins0(LIR_start); @@ -2263,11 +2267,24 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag fragment->loopLabel = entryLabel; }) - lirbuf->sp = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, sp)), "sp"); - lirbuf->rp = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp)), "rp"); - InitConst(cx_ins) = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx)), "cx"); - InitConst(eos_ins) = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eos)), "eos"); - InitConst(eor_ins) = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eor)), "eor"); + lirbuf->sp = + addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, sp), ACC_OTHER), "sp"); + lirbuf->rp = + addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp), ACC_OTHER), "rp"); + InitConst(cx_ins) = + addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx), ACC_OTHER), "cx"); + InitConst(eos_ins) = + addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eos), ACC_OTHER), "eos"); + InitConst(eor_ins) = + addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eor), ACC_OTHER), "eor"); + +#ifdef DEBUG + // Need to set these up before any stack/rstack loads/stores occur. + validate1->setSp(lirbuf->sp); + validate2->setSp(lirbuf->sp); + validate1->setRp(lirbuf->rp); + validate2->setRp(lirbuf->rp); +#endif /* If we came from exit, we might not have enough global types. */ if (tree->globalSlots->length() > tree->nGlobalTypes()) @@ -2285,7 +2302,10 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag * We poll the operation callback request flag. It is updated asynchronously whenever * the callback is to be invoked. */ - LIns* x = lir->insLoad(LIR_ld, cx_ins, offsetof(JSContext, operationCallbackFlag)); + // XXX: this load is volatile. If bug 545406 (loop-invariant code + // hoisting) is implemented this fact will need to be made explicit. + LIns* x = + lir->insLoad(LIR_ld, cx_ins, offsetof(JSContext, operationCallbackFlag), ACC_LOAD_ANY); guard(true, lir->ins_eq0(x), snapshot(TIMEOUT_EXIT)); } @@ -2295,8 +2315,8 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag */ if (anchor && anchor->exitType == NESTED_EXIT) { LIns* nested_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, - offsetof(InterpState, outermostTreeExitGuard)), - "outermostTreeExitGuard"); + offsetof(InterpState, outermostTreeExitGuard), + ACC_OTHER), "outermostTreeExitGuard"); guard(true, lir->ins2(LIR_peq, nested_ins, INS_CONSTPTR(innermost)), NESTED_EXIT); } } @@ -3201,7 +3221,7 @@ struct VarClosureTraits static inline uint32 adj_slot(JSStackFrame* fp, uint32 slot) { return 4 + fp->argc + slot; } static inline LIns* adj_slot_lir(LirWriter* lir, LIns* fp_ins, unsigned slot) { - LIns *argc_ins = lir->insLoad(LIR_ld, fp_ins, offsetof(JSStackFrame, argc)); + LIns *argc_ins = lir->insLoad(LIR_ld, fp_ins, offsetof(JSStackFrame, argc), ACC_OTHER); return lir->ins2(LIR_add, lir->insImm(4 + slot), argc_ins); } @@ -3314,6 +3334,7 @@ TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, const char *prefix, uintN index, JSStackFrame *fp) { LIns* ins; + AccSet accSet = base == lirbuf->sp ? ACC_STACK : ACC_OTHER; if (t == TT_INT32) { /* demoted */ JS_ASSERT(isInt32(*p)); @@ -3323,18 +3344,18 @@ TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, * to see doubles on entry. The first op to use this slot will emit a * f2i cast which will cancel out the i2f we insert here. */ - ins = lir->insLoad(LIR_ld, base, offset); + ins = lir->insLoad(LIR_ld, base, offset, accSet); ins = lir->ins1(LIR_i2f, ins); } else { JS_ASSERT_IF(t != TT_JSVAL, isNumber(*p) == (t == TT_DOUBLE)); if (t == TT_DOUBLE) { - ins = lir->insLoad(LIR_ldf, base, offset); + ins = lir->insLoad(LIR_ldf, base, offset, accSet); } else if (t == TT_SPECIAL) { - ins = lir->insLoad(LIR_ld, base, offset); + ins = lir->insLoad(LIR_ld, base, offset, accSet); } else if (t == TT_VOID) { ins = INS_VOID(); } else { - ins = lir->insLoad(LIR_ldp, base, offset); + ins = lir->insLoad(LIR_ldp, base, offset, accSet); } } checkForGlobalObjectReallocation(); @@ -3549,7 +3570,7 @@ TraceRecorder::writeBack(LIns* i, LIns* base, ptrdiff_t offset, bool shouldDemot */ if (shouldDemote && isPromoteInt(i)) i = demote(lir, i); - return lir->insStorei(i, base, offset); + return lir->insStorei(i, base, offset, (base == lirbuf->sp) ? ACC_STACK : ACC_OTHER); } /* Update the tracker, then issue a write back store. */ @@ -3730,7 +3751,7 @@ public: bool isPromote = isPromoteInt(ins); if (isPromote && *mTypeMap == TT_DOUBLE) { mLir->insStorei(mRecorder.get(vp), mRecorder.eos_ins, - mRecorder.nativeGlobalOffset(vp)); + mRecorder.nativeGlobalOffset(vp), ACC_OTHER); /* * Aggressively undo speculation so the inner tree will compile @@ -3774,7 +3795,7 @@ public: bool isPromote = isPromoteInt(ins); if (isPromote && *mTypeMap == TT_DOUBLE) { mLir->insStorei(mRecorder.get(vp), mLirbuf->sp, - mRecorder.nativespOffset(vp)); + mRecorder.nativespOffset(vp), ACC_STACK); /* * Aggressively undo speculation so the inner tree will compile @@ -4930,9 +4951,9 @@ TraceRecorder::prepareTreeCall(TreeFragment* inner) + inner->nativeStackBase; /* plus the inner tree's stack base */ /* We have enough space, so adjust sp and rp to their new level. */ lir->insStorei(lir->ins2(LIR_piadd, lirbuf->sp, INS_CONSTWORD(sp_offset)), - lirbuf->state, offsetof(InterpState, sp)); + lirbuf->state, offsetof(InterpState, sp), ACC_OTHER); lir->insStorei(lir->ins2(LIR_piadd, lirbuf->rp, INS_CONSTWORD(rp_adj)), - lirbuf->state, offsetof(InterpState, rp)); + lirbuf->state, offsetof(InterpState, rp), ACC_OTHER); } /* @@ -4983,10 +5004,12 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) ci->_name = "fragment"; #endif LIns* rec = lir->insCall(ci, args); - LIns* lr = lir->insLoad(LIR_ldp, rec, offsetof(GuardRecord, exit)); + LIns* lr = lir->insLoad(LIR_ldp, rec, offsetof(GuardRecord, exit), ACC_OTHER); LIns* nested = lir->insBranch(LIR_jt, lir->ins2i(LIR_eq, - lir->insLoad(LIR_ld, lr, offsetof(VMSideExit, exitType)), + lir->insLoad(LIR_ld, lr, + offsetof(VMSideExit, exitType), + ACC_OTHER), NESTED_EXIT), NULL); @@ -4995,7 +5018,7 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) * with that guard. If we mismatch on a tree call guard, this will contain the last * non-nested guard we encountered, which is the innermost loop or branch guard. */ - lir->insStorei(lr, lirbuf->state, offsetof(InterpState, lastTreeExitGuard)); + lir->insStorei(lr, lirbuf->state, offsetof(InterpState, lastTreeExitGuard), ACC_OTHER); LIns* done1 = lir->insBranch(LIR_j, NULL, NULL); /* @@ -5007,16 +5030,20 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) LIns* done2 = lir->insBranch(LIR_jf, lir->ins_peq0(lir->insLoad(LIR_ldp, lirbuf->state, - offsetof(InterpState, lastTreeCallGuard))), + offsetof(InterpState, lastTreeCallGuard), + ACC_OTHER)), NULL); - lir->insStorei(lr, lirbuf->state, offsetof(InterpState, lastTreeCallGuard)); + lir->insStorei(lr, lirbuf->state, offsetof(InterpState, lastTreeCallGuard), ACC_OTHER); lir->insStorei(lir->ins2(LIR_piadd, - lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp)), + lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp), + ACC_OTHER), lir->ins_i2p(lir->ins2i(LIR_lsh, - lir->insLoad(LIR_ld, lr, offsetof(VMSideExit, calldepth)), + lir->insLoad(LIR_ld, lr, + offsetof(VMSideExit, calldepth), + ACC_OTHER), sizeof(void*) == 4 ? 2 : 3))), lirbuf->state, - offsetof(InterpState, rpAtLastTreeCall)); + offsetof(InterpState, rpAtLastTreeCall), ACC_OTHER); LIns* label = lir->ins0(LIR_label); done1->setTarget(label); done2->setTarget(label); @@ -5025,7 +5052,7 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) * Keep updating outermostTreeExit so that InterpState always contains the most recent * side exit. */ - lir->insStorei(lr, lirbuf->state, offsetof(InterpState, outermostTreeExitGuard)); + lir->insStorei(lr, lirbuf->state, offsetof(InterpState, outermostTreeExitGuard), ACC_OTHER); /* Read back all registers, in case the called tree changed any of them. */ #ifdef DEBUG @@ -5077,8 +5104,8 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) /* Restore sp and rp to their original values (we still have them in a register). */ if (callDepth > 0) { - lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp)); - lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp)); + lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp), ACC_OTHER); + lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp), ACC_OTHER); } /* @@ -7726,8 +7753,8 @@ JS_REQUIRES_STACK LIns* TraceRecorder::entryScopeChain() const { return lir->insLoad(LIR_ldp, - lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)), - offsetof(JSStackFrame, scopeChain)); + lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER), + offsetof(JSStackFrame, scopeChain), ACC_OTHER); } /* @@ -7926,8 +7953,8 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp, // Now assert that our use of sprop->shortid was in fact kosher. JS_ASSERT(sprop->hasShortID()); - LIns* base = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); - LIns* val_ins = lir->insLoad(LIR_ldp, base, dslot_index * sizeof(jsval)); + LIns* base = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); + LIns* val_ins = lir->insLoad(LIR_ldp, base, dslot_index * sizeof(jsval), ACC_OTHER); ins = unbox_jsval(obj->dslots[dslot_index], val_ins, snapshot(BRANCH_EXIT)); } else { ClosureVarInfo* cv = new (traceAlloc()) ClosureVarInfo(); @@ -7963,7 +7990,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp, addName(lir->ins2(LIR_eq, call_ins, lir->insImm(type)), "guard(type-stable name access)"), BRANCH_EXIT); - ins = stackLoad(outp, type); + ins = stackLoad(outp, ACC_OTHER, type); } nr.tracked = false; nr.obj = obj; @@ -8302,7 +8329,7 @@ TraceRecorder::ifop() lir->ins_eq0(lir->ins2(LIR_feq, v_ins, lir->insImmf(0)))); } else if (JSVAL_IS_STRING(v)) { cond = JSVAL_TO_STRING(v)->length() != 0; - x = lir->insLoad(LIR_ldp, v_ins, offsetof(JSString, mLength)); + x = lir->insLoad(LIR_ldp, v_ins, offsetof(JSString, mLength), ACC_OTHER); } else { JS_NOT_REACHED("ifop"); return ARECORD_STOP; @@ -8367,7 +8394,7 @@ TraceRecorder::tableswitch() LIns* diff = lir->ins2(LIR_sub, v_ins, lir->insImm(low)); LIns* cmp = lir->ins2(LIR_ult, diff, lir->insImm(si->count)); lir->insGuard(LIR_xf, cmp, createGuardRecord(snapshot(DEFAULT_EXIT))); - lir->insStorei(diff, lir->insImmPtr(&si->index), 0); + lir->insStorei(diff, lir->insImmPtr(&si->index), 0, ACC_OTHER); VMSideExit* exit = snapshot(CASE_EXIT); exit->switchInfo = si; LIns* guardIns = lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit)); @@ -8490,7 +8517,7 @@ TraceRecorder::incElem(jsint incr, bool pre) LIns* addr_ins; if (JSVAL_IS_PRIMITIVE(l) || !JSVAL_IS_INT(r) || - !guardDenseArray(JSVAL_TO_OBJECT(l), get(&l))) { + !guardDenseArray(JSVAL_TO_OBJECT(l), get(&l), MISMATCH_EXIT)) { return RECORD_STOP; } @@ -8498,7 +8525,7 @@ TraceRecorder::incElem(jsint incr, bool pre) if (!addr_ins) // if we read a hole, abort return RECORD_STOP; CHECK_STATUS(inc(*vp, v_ins, incr, pre)); - lir->insStorei(box_jsval(*vp, v_ins), addr_ins, 0); + lir->insStorei(box_jsval(*vp, v_ins), addr_ins, 0, ACC_OTHER); return RECORD_CONTINUE; } @@ -9013,7 +9040,8 @@ TraceRecorder::guardShape(LIns* obj_ins, JSObject* obj, uint32 shape, const char #endif // Finally, emit the shape guard. - LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), "shape"); + LIns* shape_ins = + addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape), ACC_OTHER), "shape"); guard(true, addName(lir->ins2i(LIR_eq, shape_ins, shape), guardName), exit); @@ -9047,7 +9075,7 @@ JS_STATIC_ASSERT(offsetof(JSObjectOps, objectMap) == 0); inline LIns* TraceRecorder::map(LIns* obj_ins) { - return addName(lir->insLoad(LIR_ldp, obj_ins, (int) offsetof(JSObject, map)), "map"); + return addName(lir->insLoad(LIR_ldp, obj_ins, (int) offsetof(JSObject, map), ACC_OTHER), "map"); } bool @@ -9243,7 +9271,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, runtime), ACC_READONLY), "runtime"), - offsetof(JSRuntime, protoHazardShape)), + offsetof(JSRuntime, protoHazardShape), ACC_OTHER), "protoHazardShape"); guard(true, @@ -9276,15 +9304,15 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, void TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, LIns* v_ins) { - lir->insStorei(v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval)); + lir->insStorei(v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval), ACC_OTHER); } void TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins) { if (!dslots_ins) - dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); - lir->insStorei(v_ins, dslots_ins, slot * sizeof(jsval)); + dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); + lir->insStorei(v_ins, dslots_ins, slot * sizeof(jsval), ACC_OTHER); } void @@ -9301,7 +9329,8 @@ LIns* TraceRecorder::stobj_get_fslot(LIns* obj_ins, unsigned slot) { JS_ASSERT(slot < JS_INITIAL_NSLOTS); - return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval)); + return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval), + ACC_OTHER); } LIns* @@ -9316,8 +9345,8 @@ LIns* TraceRecorder::stobj_get_dslot(LIns* obj_ins, unsigned index, LIns*& dslots_ins) { if (!dslots_ins) - dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); - return lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval)); + dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); + return lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval), ACC_OTHER); } LIns* @@ -9403,7 +9432,8 @@ TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit) guard(HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v)), lir->ins2(LIR_peq, lir->ins2(LIR_piand, - lir->insLoad(LIR_ldp, v_ins, offsetof(JSObject, classword)), + lir->insLoad(LIR_ldp, v_ins, offsetof(JSObject, classword), + ACC_OTHER), INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)), INS_CONSTPTR(&js_FunctionClass)), exit); @@ -9432,7 +9462,8 @@ TraceRecorder::getThis(LIns*& this_ins) if (cx->fp->argv) { original = cx->fp->argv[-1]; if (!JSVAL_IS_PRIMITIVE(original) && - guardClass(JSVAL_TO_OBJECT(original), get(&cx->fp->argv[-1]), &js_WithClass, snapshot(MISMATCH_EXIT))) { + guardClass(JSVAL_TO_OBJECT(original), get(&cx->fp->argv[-1]), &js_WithClass, + snapshot(MISMATCH_EXIT), ACC_OTHER)) { RETURN_STOP("can't trace getThis on With object"); } } @@ -9469,7 +9500,8 @@ TraceRecorder::getThis(LIns*& this_ins) (((clasp = JSVAL_TO_OBJECT(original)->getClass()) == &js_CallClass) || (clasp == &js_BlockClass))) { if (clasp) - guardClass(JSVAL_TO_OBJECT(original), get(&thisv), clasp, snapshot(BRANCH_EXIT)); + guardClass(JSVAL_TO_OBJECT(original), get(&thisv), clasp, snapshot(BRANCH_EXIT), + ACC_OTHER); JS_ASSERT(!JSVAL_IS_PRIMITIVE(thisv)); if (thisObj != globalObj) RETURN_STOP("global object was wrapped while recording"); @@ -9517,13 +9549,13 @@ TraceRecorder::guardClass(JSObject* obj, LIns* obj_ins, JSClass* clasp, VMSideEx JS_REQUIRES_STACK bool TraceRecorder::guardDenseArray(JSObject* obj, LIns* obj_ins, ExitType exitType) { - return guardClass(obj, obj_ins, &js_ArrayClass, snapshot(exitType)); + return guardClass(obj, obj_ins, &js_ArrayClass, snapshot(exitType), ACC_OTHER); } JS_REQUIRES_STACK bool TraceRecorder::guardDenseArray(JSObject* obj, LIns* obj_ins, VMSideExit* exit) { - return guardClass(obj, obj_ins, &js_ArrayClass, exit); + return guardClass(obj, obj_ins, &js_ArrayClass, exit, ACC_OTHER); } JS_REQUIRES_STACK bool @@ -9646,7 +9678,7 @@ TraceRecorder::putActivationObjects() args_ins = lir->insAlloc(sizeof(jsval) * nargs); for (int i = 0; i < nargs; ++i) { LIns* arg_ins = box_jsval(cx->fp->argv[i], get(&cx->fp->argv[i])); - lir->insStorei(arg_ins, args_ins, i * sizeof(jsval)); + lir->insStorei(arg_ins, args_ins, i * sizeof(jsval), ACC_OTHER); } } else { args_ins = INS_CONSTPTR(0); @@ -9665,7 +9697,7 @@ TraceRecorder::putActivationObjects() slots_ins = lir->insAlloc(sizeof(jsval) * nslots); for (int i = 0; i < nslots; ++i) { LIns* slot_ins = box_jsval(cx->fp->slots[i], get(&cx->fp->slots[i])); - lir->insStorei(slot_ins, slots_ins, i * sizeof(jsval)); + lir->insStorei(slot_ins, slots_ins, i * sizeof(jsval), ACC_OTHER); } } else { slots_ins = INS_CONSTPTR(0); @@ -9863,8 +9895,8 @@ TraceRecorder::record_JSOP_POPV() // Store it in cx->fp->rval. NB: Tricky dependencies. cx->fp is the right // frame because POPV appears only in global and eval code and we don't // trace JSOP_EVAL or leaving the frame where tracing started. - LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)); - lir->insStorei(rval_ins, fp_ins, offsetof(JSStackFrame, rval)); + LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER); + lir->insStorei(rval_ins, fp_ins, offsetof(JSStackFrame, rval), ACC_OTHER); return ARECORD_CONTINUE; } @@ -9981,19 +10013,19 @@ TraceRecorder::record_JSOP_ARGUMENTS() LIns* mem_ins = lir->insAlloc(sizeof(jsval)); LIns* br1 = lir->insBranch(LIR_jt, lir->ins_peq0(a_ins), NULL); - lir->insStorei(a_ins, mem_ins, 0); + lir->insStorei(a_ins, mem_ins, 0, ACC_OTHER); LIns* br2 = lir->insBranch(LIR_j, NULL, NULL); LIns* label1 = lir->ins0(LIR_label); br1->setTarget(label1); LIns* call_ins = newArguments(callee_ins); - lir->insStorei(call_ins, mem_ins, 0); + lir->insStorei(call_ins, mem_ins, 0, ACC_OTHER); LIns* label2 = lir->ins0(LIR_label); br2->setTarget(label2); - args_ins = lir->insLoad(LIR_ldp, mem_ins, 0); + args_ins = lir->insLoad(LIR_ldp, mem_ins, 0, ACC_OTHER); } stack(0, args_ins); @@ -10193,7 +10225,7 @@ TraceRecorder::record_JSOP_NOT() } JS_ASSERT(JSVAL_IS_STRING(v)); set(&v, lir->ins_peq0(lir->insLoad(LIR_ldp, get(&v), - offsetof(JSString, mLength)))); + offsetof(JSString, mLength), ACC_OTHER))); return ARECORD_CONTINUE; } @@ -10463,7 +10495,8 @@ TraceRecorder::propagateFailureToBuiltinStatus(LIns* ok_ins, LIns*& status_ins) lir->ins2i(LIR_and, ok_ins, 1), 1), 1)); - lir->insStorei(status_ins, lirbuf->state, (int) offsetof(InterpState, builtinStatus)); + lir->insStorei(status_ins, lirbuf->state, (int) offsetof(InterpState, builtinStatus), + ACC_OTHER); } JS_REQUIRES_STACK void @@ -10479,10 +10512,10 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns // because the getter or setter could end up resizing the object's dslots. // Instead, use a word of stack and root it in nativeVp. LIns* vp_ins = lir->insAlloc(sizeof(jsval)); - lir->insStorei(vp_ins, lirbuf->state, offsetof(InterpState, nativeVp)); - lir->insStorei(INS_CONST(1), lirbuf->state, offsetof(InterpState, nativeVpLen)); + lir->insStorei(vp_ins, lirbuf->state, offsetof(InterpState, nativeVp), ACC_OTHER); + lir->insStorei(INS_CONST(1), lirbuf->state, offsetof(InterpState, nativeVpLen), ACC_OTHER); if (setflag) - lir->insStorei(boxed_ins, vp_ins, 0); + lir->insStorei(boxed_ins, vp_ins, 0, ACC_OTHER); CallInfo* ci = new (traceAlloc()) CallInfo(); ci->_address = uintptr_t(setflag ? sprop->setterOp() : sprop->getterOp()); @@ -10501,21 +10534,20 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns LIns* ok_ins = lir->insCall(ci, args); // Cleanup. Immediately clear nativeVp before we might deep bail. - lir->insStorei(INS_NULL(), lirbuf->state, offsetof(InterpState, nativeVp)); + lir->insStorei(INS_NULL(), lirbuf->state, offsetof(InterpState, nativeVp), ACC_OTHER); leaveDeepBailCall(); // Guard that the call succeeded and builtinStatus is still 0. // If the native op succeeds but we deep-bail here, the result value is // lost! Therefore this can only be used for setters of shared properties. // In that case we ignore the result value anyway. - LIns* status_ins = lir->insLoad(LIR_ld, - lirbuf->state, - (int) offsetof(InterpState, builtinStatus)); + LIns* status_ins = lir->insLoad(LIR_ld, lirbuf->state, + (int) offsetof(InterpState, builtinStatus), ACC_OTHER); propagateFailureToBuiltinStatus(ok_ins, status_ins); guard(true, lir->ins_eq0(status_ins), STATUS_EXIT); // Re-load the value--but this is currently unused, so commented out. - //boxed_ins = lir->insLoad(LIR_ldp, vp_ins, 0); + //boxed_ins = lir->insLoad(LIR_ldp, vp_ins, 0, ACC_OTHER); } JS_REQUIRES_STACK RecordingStatus @@ -10543,7 +10575,7 @@ TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], // Immediately unroot the vp as soon we return since we might deep bail next. if (rooted) - lir->insStorei(INS_NULL(), lirbuf->state, offsetof(InterpState, nativeVp)); + lir->insStorei(INS_NULL(), lirbuf->state, offsetof(InterpState, nativeVp), ACC_OTHER); rval_ins = res_ins; switch (JSTN_ERRTYPE(sn)) { @@ -10759,7 +10791,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode) LIns* invokevp_ins = lir->insAlloc(vplen * sizeof(jsval)); // vp[0] is the callee. - lir->insStorei(INS_CONSTVAL(OBJECT_TO_JSVAL(funobj)), invokevp_ins, 0); + lir->insStorei(INS_CONSTVAL(OBJECT_TO_JSVAL(funobj)), invokevp_ins, 0, ACC_OTHER); // Calculate |this|. LIns* this_ins; @@ -10806,7 +10838,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode) } else if (!JSVAL_IS_OBJECT(vp[1])) { RETURN_STOP("slow native(primitive, args)"); } else { - if (guardConstClass(JSVAL_TO_OBJECT(vp[1]), this_ins, &js_WithClass, snapshot(MISMATCH_EXIT))) + if (guardClass(JSVAL_TO_OBJECT(vp[1]), this_ins, &js_WithClass, + snapshot(MISMATCH_EXIT), ACC_READONLY)) RETURN_STOP("can't trace slow native invocation on With object"); this_ins = lir->ins_choose(lir->ins_peq0(stobj_get_parent(this_ins)), @@ -10816,12 +10849,12 @@ TraceRecorder::callNative(uintN argc, JSOp mode) } this_ins = box_jsval(vp[1], this_ins); } - lir->insStorei(this_ins, invokevp_ins, 1 * sizeof(jsval)); + lir->insStorei(this_ins, invokevp_ins, 1 * sizeof(jsval), ACC_OTHER); // Populate argv. for (uintN n = 2; n < 2 + argc; n++) { LIns* i = box_jsval(vp[n], get(&vp[n])); - lir->insStorei(i, invokevp_ins, n * sizeof(jsval)); + lir->insStorei(i, invokevp_ins, n * sizeof(jsval), ACC_OTHER); // For a very long argument list we might run out of LIR space, so // check inside the loop. @@ -10833,7 +10866,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode) if (2 + argc < vplen) { LIns* undef_ins = INS_CONSTWORD(JSVAL_VOID); for (uintN n = 2 + argc; n < vplen; n++) { - lir->insStorei(undef_ins, invokevp_ins, n * sizeof(jsval)); + lir->insStorei(undef_ins, invokevp_ins, n * sizeof(jsval), ACC_OTHER); if (outOfMemory()) RETURN_STOP("out of memory in extra slots"); @@ -10896,8 +10929,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode) // nativeVpLen immediately before emitting the call code. This way we avoid // leaving trace with a bogus nativeVp because we fall off trace while unboxing // values into the stack buffer. - lir->insStorei(INS_CONST(vplen), lirbuf->state, offsetof(InterpState, nativeVpLen)); - lir->insStorei(invokevp_ins, lirbuf->state, offsetof(InterpState, nativeVp)); + lir->insStorei(INS_CONST(vplen), lirbuf->state, offsetof(InterpState, nativeVpLen), ACC_OTHER); + lir->insStorei(invokevp_ins, lirbuf->state, offsetof(InterpState, nativeVp), ACC_OTHER); // argc is the original argc here. It is used to calculate where to place // the return value. @@ -11333,8 +11366,8 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty // have a valid shortid; but we don't use it in that case anyway. JS_ASSERT(sprop->hasShortID()); - LIns* base = lir->insLoad(LIR_ldp, callobj_ins, offsetof(JSObject, dslots)); - lir->insStorei(box_jsval(v, v_ins), base, dslot_index * sizeof(jsval)); + LIns* base = lir->insLoad(LIR_ldp, callobj_ins, offsetof(JSObject, dslots), ACC_OTHER); + lir->insStorei(box_jsval(v, v_ins), base, dslot_index * sizeof(jsval), ACC_OTHER); return RECORD_CONTINUE; } @@ -11356,8 +11389,9 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty // entry frame. In that case, we must store to the native stack area for // that frame. - LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)); - LIns *fpcallobj_ins = lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, callobj)); + LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER); + LIns *fpcallobj_ins = lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, callobj), + ACC_OTHER); LIns *br1 = lir->insBranch(LIR_jf, lir->ins2(LIR_peq, fpcallobj_ins, callobj_ins), NULL); // Case 1: storing to native stack area. @@ -11373,8 +11407,8 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty // Guard that we are not changing the type of the slot we are storing to. LIns *callstackBase_ins = lir->insLoad(LIR_ldp, lirbuf->state, - offsetof(InterpState, callstackBase)); - LIns *frameInfo_ins = lir->insLoad(LIR_ldp, callstackBase_ins, 0); + offsetof(InterpState, callstackBase), ACC_OTHER); + LIns *frameInfo_ins = lir->insLoad(LIR_ldp, callstackBase_ins, 0, ACC_OTHER); LIns *typemap_ins = lir->ins2(LIR_addp, frameInfo_ins, INS_CONSTWORD(sizeof(FrameInfo))); LIns *type_ins = lir->insLoad(LIR_ldzb, lir->ins2(LIR_addp, typemap_ins, lir->ins_u2p(slot_ins)), 0, @@ -11389,10 +11423,10 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty // Store to the native stack slot. LIns *stackBase_ins = lir->insLoad(LIR_ldp, lirbuf->state, - offsetof(InterpState, stackBase)); + offsetof(InterpState, stackBase), ACC_OTHER); LIns *storeValue_ins = isPromoteInt(v_ins) ? demote(lir, v_ins) : v_ins; lir->insStorei(storeValue_ins, - lir->ins2(LIR_addp, stackBase_ins, lir->ins_u2p(offset_ins)), 0); + lir->ins2(LIR_addp, stackBase_ins, lir->ins_u2p(offset_ins)), 0, ACC_STORE_ANY); LIns *br2 = lir->insBranch(LIR_j, NULL, NULL); // Case 2: calling builtin. @@ -11441,7 +11475,7 @@ TraceRecorder::enterDeepBailCall() { // Take snapshot for DeepBail and store it in cx->bailExit. VMSideExit* exit = snapshot(DEEP_BAIL_EXIT); - lir->insStorei(INS_CONSTPTR(exit), cx_ins, offsetof(JSContext, bailExit)); + lir->insStorei(INS_CONSTPTR(exit), cx_ins, offsetof(JSContext, bailExit), ACC_OTHER); // Tell nanojit not to discard or defer stack writes before this call. GuardRecord* guardRec = createGuardRecord(exit); @@ -11456,7 +11490,7 @@ JS_REQUIRES_STACK void TraceRecorder::leaveDeepBailCall() { // Keep cx->bailExit null when it's invalid. - lir->insStorei(INS_NULL(), cx_ins, offsetof(JSContext, bailExit)); + lir->insStorei(INS_NULL(), cx_ins, offsetof(JSContext, bailExit), ACC_OTHER); } JS_REQUIRES_STACK void @@ -11465,7 +11499,7 @@ TraceRecorder::finishGetProp(LIns* obj_ins, LIns* vp_ins, LIns* ok_ins, jsval* o // Store the boxed result (and this-object, if JOF_CALLOP) before the // guard. The deep-bail case requires this. If the property get fails, // these slots will be ignored anyway. - LIns* result_ins = lir->insLoad(LIR_ldp, vp_ins, 0); + LIns* result_ins = lir->insLoad(LIR_ldp, vp_ins, 0, ACC_OTHER); set(outp, result_ins); if (js_CodeSpec[*cx->fp->regs->pc].format & JOF_CALLOP) set(outp + 1, obj_ins); @@ -11553,7 +11587,9 @@ TraceRecorder::getPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* outp) // GetPropertyByName can assign to *idvalp, so the tracker has an incorrect // entry for that address. Correct it. (If the value in the address is // never used again, the usual case, Nanojit will kill this load.) - tracker.set(idvalp, lir->insLoad(LIR_ldp, idvalp_ins, 0)); + // The AccSet could be made more precise with some effort (idvalp_ins may + // equal 'sp+k'), but it's not worth it because this case is rare. + tracker.set(idvalp, lir->insLoad(LIR_ldp, idvalp_ins, 0, ACC_STACK|ACC_OTHER)); finishGetProp(obj_ins, vp_ins, ok_ins, outp); leaveDeepBailCall(); @@ -11775,7 +11811,9 @@ TraceRecorder::record_JSOP_GETELEM() // is accurate. // Note: this relies on the assumption that we abort on setting an element of // an arguments object in any deeper frame. - LIns* fip_ins = lir->insLoad(LIR_ldp, lirbuf->rp, (callDepth-depth)*sizeof(FrameInfo*)); + LIns* fip_ins = lir->insLoad(LIR_ldp, lirbuf->rp, + (callDepth-depth)*sizeof(FrameInfo*), + ACC_RSTACK); typemap_ins = lir->ins2(LIR_piadd, fip_ins, INS_CONSTWORD(sizeof(FrameInfo) + 2/*callee,this*/ * sizeof(TraceType))); } @@ -11799,7 +11837,11 @@ TraceRecorder::record_JSOP_GETELEM() lir->ins_u2p(lir->ins2(LIR_mul, idx_ins, INS_CONST(sizeof(double))))); - v_ins = stackLoad(argi_addr_ins, type); + // The AccSet could be more precise, but ValidateWriter + // doesn't recognise the complex expression involving 'sp' as + // a STACK access, and it's not worth the effort to be more + // precise because this case is rare. + v_ins = stackLoad(argi_addr_ins, ACC_LOAD_ANY, type); } JS_ASSERT(v_ins); set(&lval, v_ins); @@ -11828,7 +11870,7 @@ TraceRecorder::record_JSOP_GETELEM() jsval* vp; LIns* addr_ins; - guardConstClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT)); + guardClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), ACC_READONLY); CHECK_STATUS_A(typedArrayElement(lval, idx, vp, v_ins, addr_ins)); set(&lval, v_ins); if (call) @@ -11889,7 +11931,7 @@ TraceRecorder::initOrSetPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* rval } else { // See note in getPropertyByName about vp. LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); - lir->insStorei(rval_ins, vp_ins, 0); + lir->insStorei(rval_ins, vp_ins, 0, ACC_OTHER); LIns* args[] = {vp_ins, idvalp_ins, obj_ins, cx_ins}; ok_ins = lir->insCall(&SetPropertyByName_ci, args); } @@ -11946,7 +11988,7 @@ TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* r } else { // See note in getPropertyByName about vp. LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); - lir->insStorei(rval_ins, vp_ins, 0); + lir->insStorei(rval_ins, vp_ins, 0, ACC_OTHER); LIns* args[] = {vp_ins, index_ins, obj_ins, cx_ins}; ok_ins = lir->insCall(&SetPropertyByIndex_ci, args); } @@ -11984,7 +12026,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) // Fast path: assigning to element of typed array. // Ensure array is a typed array and is the same type as what was written - guardConstClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT)); + guardClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), ACC_READONLY); js::TypedArray* tarray = js::TypedArray::fromJSObject(obj); @@ -12065,25 +12107,25 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) case js::TypedArray::TYPE_UINT8_CLAMPED: case js::TypedArray::TYPE_UINT8: addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - lir->insStore(LIR_stb, v_ins, addr_ins, 0); + lir->insStore(LIR_stb, v_ins, addr_ins, 0, ACC_OTHER); break; case js::TypedArray::TYPE_INT16: case js::TypedArray::TYPE_UINT16: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); - lir->insStore(LIR_sts, v_ins, addr_ins, 0); + lir->insStore(LIR_sts, v_ins, addr_ins, 0, ACC_OTHER); break; case js::TypedArray::TYPE_INT32: case js::TypedArray::TYPE_UINT32: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_sti, v_ins, addr_ins, 0); + lir->insStore(LIR_sti, v_ins, addr_ins, 0, ACC_OTHER); break; case js::TypedArray::TYPE_FLOAT32: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_st32f, v_ins, addr_ins, 0); + lir->insStore(LIR_st32f, v_ins, addr_ins, 0, ACC_OTHER); break; case js::TypedArray::TYPE_FLOAT64: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 3)); - lir->insStore(LIR_stfi, v_ins, addr_ins, 0); + lir->insStore(LIR_stfi, v_ins, addr_ins, 0, ACC_OTHER); break; default: JS_NOT_REACHED("Unknown typed array type in tracer"); @@ -12231,14 +12273,14 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v) addName(lir->ins2(LIR_eq, call_ins, lir->insImm(type)), "guard(type-stable upvar)"), BRANCH_EXIT); - return stackLoad(outp, type); + return stackLoad(outp, ACC_OTHER, type); } /* * Generate LIR to load a value from the native stack. This method ensures that * the correct LIR load operator is used. */ -LIns* TraceRecorder::stackLoad(LIns* base, uint8 type) +LIns* TraceRecorder::stackLoad(LIns* base, AccSet accSet, uint8 type) { LOpcode loadOp; switch (type) { @@ -12262,7 +12304,7 @@ LIns* TraceRecorder::stackLoad(LIns* base, uint8 type) return NULL; } - LIns* result = lir->insLoad(loadOp, base, 0); + LIns* result = lir->insLoad(loadOp, base, 0, accSet); if (type == TT_INT32) result = lir->ins1(LIR_i2f, result); return result; @@ -12299,7 +12341,7 @@ TraceRecorder::record_JSOP_GETDSLOT() LIns* callee_ins = get(&cx->fp->argv[-2]); unsigned index = GET_UINT16(cx->fp->regs->pc); - LIns* dslots_ins = lir->insLoad(LIR_ldp, callee_ins, offsetof(JSObject, dslots)); + LIns* dslots_ins = lir->insLoad(LIR_ldp, callee_ins, offsetof(JSObject, dslots), ACC_OTHER); LIns* v_ins = lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval), ACC_READONLY); stack(0, unbox_jsval(callee->dslots[index], v_ins, snapshot(BRANCH_EXIT))); @@ -12393,7 +12435,7 @@ TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp) return NULL; VMSideExit *exit = snapshot(MISMATCH_EXIT); - guardConstClass(obj, obj_ins, &js_ArgumentsClass, exit); + guardClass(obj, obj_ins, &js_ArgumentsClass, exit, ACC_READONLY); LIns* args_ins = get(&afp->argsobj); LIns* cmp = lir->ins2(LIR_peq, args_ins, obj_ins); @@ -12457,7 +12499,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, fi = traceMonitor->frameCache->memoize(fi); if (!fi) RETURN_STOP("out of memory"); - lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*)); + lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*), ACC_RSTACK); #if defined JS_JIT_SPEW debug_only_printf(LC_TMTracer, "iFC frameinfo=%p, stack=%d, map=", (void*)fi, @@ -12561,7 +12603,7 @@ TraceRecorder::record_JSOP_APPLY() * for apply uses imacros to handle a specific number of arguments. */ if (aobj->isDenseArray()) { - guardDenseArray(aobj, aobj_ins); + guardDenseArray(aobj, aobj_ins, MISMATCH_EXIT); length = jsuint(aobj->fslots[JSSLOT_ARRAY_LENGTH]); guard(true, lir->ins2i(LIR_eq, @@ -12635,9 +12677,10 @@ TraceRecorder::record_NativeCallComplete() if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS) { /* Keep cx->bailExit null when it's invalid. */ - lir->insStorei(INS_NULL(), cx_ins, (int) offsetof(JSContext, bailExit)); + lir->insStorei(INS_NULL(), cx_ins, (int) offsetof(JSContext, bailExit), ACC_OTHER); - LIns* status = lir->insLoad(LIR_ld, lirbuf->state, (int) offsetof(InterpState, builtinStatus)); + LIns* status = lir->insLoad(LIR_ld, lirbuf->state, + (int) offsetof(InterpState, builtinStatus), ACC_OTHER); if (pendingSpecializedNative == &generatedSpecializedNative) { LIns* ok_ins = v_ins; @@ -12656,7 +12699,7 @@ TraceRecorder::record_NativeCallComplete() * vector for native function calls. The actual return value of the native is a JSBool * indicating the error status. */ - v_ins = lir->insLoad(LIR_ldp, native_rval_ins, 0); + v_ins = lir->insLoad(LIR_ldp, native_rval_ins, 0, ACC_OTHER); if (*pc == JSOP_NEW) { LIns* x = lir->ins_peq0(lir->ins2(LIR_piand, v_ins, INS_CONSTWORD(JSVAL_TAGMASK))); x = lir->ins_choose(x, v_ins, INS_CONSTWORD(0), avmplus::AvmCore::use_cmov()); @@ -12795,7 +12838,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, RETURN_STOP_A("can't trace through access to undefined property if " "JSClass.getProperty hook isn't stubbed"); } - guardClass(obj, obj_ins, OBJ_GET_CLASS(cx, obj), snapshot(MISMATCH_EXIT)); + guardClass(obj, obj_ins, OBJ_GET_CLASS(cx, obj), snapshot(MISMATCH_EXIT), ACC_OTHER); /* * This trace will be valid as long as neither the object nor any object @@ -12934,7 +12977,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ VMSideExit* exit = snapshot(BRANCH_EXIT); /* check that the index is within bounds */ - LIns* dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots)); + LIns* dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); jsuint capacity = js_DenseArrayCapacity(obj); bool within = (jsuint(idx) < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) && jsuint(idx) < capacity); if (!within) { @@ -12962,9 +13005,8 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ LIns* br4 = lir->insBranch(LIR_jf, lir->ins2(LIR_pult, pidx_ins, - lir->insLoad(LIR_ldp, - dslots_ins, - -(int)sizeof(jsval))), + lir->insLoad(LIR_ldp, dslots_ins, + -(int)sizeof(jsval), ACC_OTHER)), NULL); lir->insGuard(LIR_x, NULL, createGuardRecord(exit)); LIns* label = lir->ins0(LIR_label); @@ -13005,14 +13047,14 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ guard(true, lir->ins2(LIR_pult, pidx_ins, - lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval))), + lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval), ACC_OTHER)), exit); /* Load the value and guard on its type to unbox it. */ vp = &obj->dslots[jsuint(idx)]; addr_ins = lir->ins2(LIR_piadd, dslots_ins, lir->ins2i(LIR_pilsh, pidx_ins, (sizeof(jsval) == 4) ? 2 : 3)); - v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0), exit); + v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0, ACC_OTHER), exit); if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) { /* @@ -13082,36 +13124,36 @@ TraceRecorder::typedArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ switch (tarray->type) { case js::TypedArray::TYPE_INT8: addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ldsb, addr_ins, 0)); + v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ldsb, addr_ins, 0, ACC_OTHER)); break; case js::TypedArray::TYPE_UINT8: case js::TypedArray::TYPE_UINT8_CLAMPED: addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - v_ins = lir->ins1(LIR_u2f, lir->insLoad(LIR_ldzb, addr_ins, 0)); + v_ins = lir->ins1(LIR_u2f, lir->insLoad(LIR_ldzb, addr_ins, 0, ACC_OTHER)); break; case js::TypedArray::TYPE_INT16: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); - v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ldss, addr_ins, 0)); + v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ldss, addr_ins, 0, ACC_OTHER)); break; case js::TypedArray::TYPE_UINT16: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); - v_ins = lir->ins1(LIR_u2f, lir->insLoad(LIR_ldzs, addr_ins, 0)); + v_ins = lir->ins1(LIR_u2f, lir->insLoad(LIR_ldzs, addr_ins, 0, ACC_OTHER)); break; case js::TypedArray::TYPE_INT32: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ld, addr_ins, 0)); + v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ld, addr_ins, 0, ACC_OTHER)); break; case js::TypedArray::TYPE_UINT32: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - v_ins = lir->ins1(LIR_u2f, lir->insLoad(LIR_ld, addr_ins, 0)); + v_ins = lir->ins1(LIR_u2f, lir->insLoad(LIR_ld, addr_ins, 0, ACC_OTHER)); break; case js::TypedArray::TYPE_FLOAT32: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - v_ins = lir->insLoad(LIR_ld32f, addr_ins, 0); + v_ins = lir->insLoad(LIR_ld32f, addr_ins, 0, ACC_OTHER); break; case js::TypedArray::TYPE_FLOAT64: addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 3)); - v_ins = lir->insLoad(LIR_ldf, addr_ins, 0); + v_ins = lir->insLoad(LIR_ldf, addr_ins, 0, ACC_OTHER); break; default: JS_NOT_REACHED("Unknown typed array type in tracer"); @@ -13461,7 +13503,7 @@ TraceRecorder::record_JSOP_NEXTITER() JSObject* iterobj = JSVAL_TO_OBJECT(iterobj_val); JSClass* clasp = iterobj->getClass(); LIns* iterobj_ins = get(&iterobj_val); - guardClass(iterobj, iterobj_ins, clasp, snapshot(BRANCH_EXIT)); + guardClass(iterobj, iterobj_ins, clasp, snapshot(BRANCH_EXIT), ACC_OTHER); if (clasp == &js_IteratorClass || clasp == &js_GeneratorClass) return InjectStatus(call_imacro(nextiter_imacros.native_iter_next)); return InjectStatus(call_imacro(nextiter_imacros.custom_iter_next)); @@ -13598,7 +13640,8 @@ TraceRecorder::traverseScopeChain(JSObject *obj, LIns *obj_ins, JSObject *target if (obj->getClass() == &js_CallClass && JSFUN_HEAVYWEIGHT_TEST(js_GetCallObjectFunction(obj)->flags)) { LIns* map_ins = map(obj_ins); - LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), + LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape), + ACC_OTHER), "obj_shape"); if (!exit) exit = snapshot(BRANCH_EXIT); @@ -13805,7 +13848,7 @@ TraceRecorder::record_JSOP_INSTANCEOF() stack(-2, lir->insCall(&HasInstance_ci, args)); LIns* status_ins = lir->insLoad(LIR_ld, lirbuf->state, - offsetof(InterpState, builtinStatus)); + offsetof(InterpState, builtinStatus), ACC_OTHER); pendingGuardCondition = lir->ins_eq0(status_ins); leaveDeepBailCall(); @@ -14968,7 +15011,7 @@ TraceRecorder::record_JSOP_LENGTH() RETURN_STOP_A("non-string primitive JSOP_LENGTH unsupported"); set(&l, lir->ins1(LIR_i2f, p2i(lir->insLoad(LIR_ldp, get(&l), - offsetof(JSString, mLength))))); + offsetof(JSString, mLength), ACC_OTHER)))); return ARECORD_CONTINUE; } @@ -15002,13 +15045,13 @@ TraceRecorder::record_JSOP_LENGTH() return ARECORD_STOP; } } else { - if (!guardClass(obj, obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT))) + if (!guardClass(obj, obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), ACC_OTHER)) RETURN_STOP_A("can't trace length property access on non-array"); } v_ins = lir->ins1(LIR_i2f, p2i(stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH))); } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) { // Ensure array is a typed array and is the same type as what was written - guardConstClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT)); + guardClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), ACC_OTHER); v_ins = lir->ins1(LIR_i2f, lir->insLoad(LIR_ld, stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE), js::TypedArray::lengthOffset(), ACC_READONLY)); @@ -15095,7 +15138,7 @@ TraceRecorder::record_JSOP_CONCATN() int32_t d = 0; for (jsval *vp = argBase; vp != regs.sp; ++vp, d += sizeof(void *)) { JS_ASSERT(JSVAL_IS_PRIMITIVE(*vp)); - lir->insStorei(stringify(*vp), buf_ins, d); + lir->insStorei(stringify(*vp), buf_ins, d, ACC_OTHER); } /* Perform concatenation using a builtin. */ diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 081e6d9ac235..6fedb1a38581 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1152,7 +1152,7 @@ class TraceRecorder JS_REQUIRES_STACK nanojit::LIns* var(unsigned n); JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i); JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v); - nanojit::LIns* stackLoad(nanojit::LIns* addr, uint8 type); + nanojit::LIns* stackLoad(nanojit::LIns* addr, nanojit::AccSet accSet, uint8 type); JS_REQUIRES_STACK nanojit::LIns* stack(int n); JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i); @@ -1298,13 +1298,9 @@ class TraceRecorder JS_REQUIRES_STACK nanojit::LIns* box_jsval(jsval v, nanojit::LIns* v_ins); JS_REQUIRES_STACK nanojit::LIns* unbox_jsval(jsval v, nanojit::LIns* v_ins, VMSideExit* exit); JS_REQUIRES_STACK bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp, - VMSideExit* exit, - nanojit::AccSet accSet = nanojit::ACC_LOAD_ANY); - bool guardConstClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp, VMSideExit* exit) { - return guardClass(obj, obj_ins, clasp, exit, nanojit::ACC_READONLY); - } + VMSideExit* exit, nanojit::AccSet accSet); JS_REQUIRES_STACK bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins, - ExitType exitType = MISMATCH_EXIT); + ExitType exitType); JS_REQUIRES_STACK bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins, VMSideExit* exit); JS_REQUIRES_STACK bool guardHasPrototype(JSObject* obj, nanojit::LIns* obj_ins, diff --git a/js/src/trace-test/tests/basic/bigLoadStoreDisp.js b/js/src/trace-test/tests/basic/bigLoadStoreDisp.js new file mode 100644 index 000000000000..528ba254b3cc --- /dev/null +++ b/js/src/trace-test/tests/basic/bigLoadStoreDisp.js @@ -0,0 +1,25 @@ +// In Nanojit, loads and stores have a maximum displacement of 16-bits. Any +// displacements larger than that should be split off into a separate +// instruction that adds the displacement to the base pointer. This +// program tests if this is done correctly. +// +// x.y ends up having a dslot offset of 79988, because of the 20000 array +// elements before it. If Nanojit incorrectly stores this offset into a +// 16-bit value it will truncate to 14452 (because 79988 - 65536 == 14452). +// This means that the increments in the second loop will be done to one of +// the array elements instead of x.y. And so x.y's final value will be +// (99 + HOTLOOP) instead of 1099. +// +// Note that setting x.y to 99 and checking its value at the end will +// access the correct location because those lines are interpreted. Phew. + +var x = {} +for (var i = 0; i < 20000; i++) + x[i] = 0; +x.y = 99; // not traced, correctly accessed + +for (var i = 0; i < 1000; ++i) { + x.y++; // traced, will access an array elem if disp was truncated +} +assertEq(x.y, 1099); // not traced, correctly accessed + From ea87628426602e6df3592a4ac726382ce2a2fe1c Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 23 Mar 2010 17:30:36 -0700 Subject: [PATCH 126/213] Bug 554102: Cleanup: switch from global TokenStream functions to methods. a=cdleary, r=jimb --- js/src/jsfun.cpp | 6 +- js/src/jsparse.cpp | 267 ++++++++++++++++++++++----------------------- js/src/jsparse.h | 2 +- js/src/jsscan.h | 56 ++-------- 4 files changed, 145 insertions(+), 186 deletions(-) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 9ac0205ff24d..51ef81748883 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2336,7 +2336,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* The argument string may be empty or contain no tokens. */ - tt = GetToken(cx, &ts); + tt = ts.getToken(); if (tt != TOK_EOF) { for (;;) { /* @@ -2371,12 +2371,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ - tt = GetToken(cx, &ts); + tt = ts.getToken(); if (tt == TOK_EOF) break; if (tt != TOK_COMMA) goto after_args; - tt = GetToken(cx, &ts); + tt = ts.getToken(); } } diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index d47944e75472..60fce6208378 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -106,7 +106,7 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom)); */ #define MUST_MATCH_TOKEN(tt, errno) \ JS_BEGIN_MACRO \ - if (GetToken(context, &tokenStream) != tt) { \ + if (tokenStream.getToken() != tt) { \ ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, errno); \ return NULL; \ } \ @@ -652,9 +652,9 @@ CheckGetterOrSetter(JSContext *cx, TokenStream *ts, TokenKind tt) op = JSOP_SETTER; else return TOK_NAME; - if (PeekTokenSameLine(cx, ts) != tt) + if (ts->peekTokenSameLine() != tt) return TOK_NAME; - (void) GetToken(cx, ts); + (void) ts->getToken(); if (ts->currentToken().t_op != JSOP_NOP) { ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_GETTER_OR_SETTER, (op == JSOP_GETTER) ? js_getter_str : js_setter_str); @@ -718,7 +718,7 @@ JSCompiler::parse(JSObject *chain) JSParseNode *pn = statements(); if (pn) { - if (!MatchToken(context, &tokenStream, TOK_EOF)) { + if (!tokenStream.matchToken(TOK_EOF)) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; @@ -868,7 +868,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal inDirectivePrologue = true; for (;;) { jsc.tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(cx, &jsc.tokenStream); + tt = jsc.tokenStream.peekToken(); jsc.tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF) { if (tt == TOK_EOF) @@ -1605,7 +1605,7 @@ JSCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *pr if (pn) { if (!CheckStrictFormals(cx, &funcg, fun, pn)) { pn = NULL; - } else if (!MatchToken(cx, &jsc.tokenStream, TOK_EOF)) { + } else if (!jsc.tokenStream.matchToken(TOK_EOF)) { ReportCompileErrorNumber(cx, &jsc.tokenStream, NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; @@ -1748,10 +1748,8 @@ JSCompiler::newFunction(JSTreeContext *tc, JSAtom *atom, uintN lambda) static JSBool MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) { - TokenKind tt; - ts->flags |= TSF_OPERAND; - tt = PeekTokenSameLine(cx, ts); + TokenKind tt = ts->peekTokenSameLine(); ts->flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return JS_FALSE; @@ -1759,7 +1757,7 @@ MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT); return JS_FALSE; } - (void) MatchToken(cx, ts, TOK_SEMI); + (void) ts->matchToken(TOK_SEMI); return JS_TRUE; } @@ -2599,7 +2597,7 @@ JSCompiler::functionDef(uintN lambda) /* Scan the optional function name into funAtom. */ tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_NAME) { funAtom = tokenStream.currentToken().t_atom; @@ -2610,7 +2608,7 @@ JSCompiler::functionDef(uintN lambda) return NULL; } funAtom = NULL; - UngetToken(&tokenStream); + tokenStream.ungetToken(); } /* @@ -2736,9 +2734,9 @@ JSCompiler::functionDef(uintN lambda) /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); - if (!MatchToken(context, &tokenStream, TOK_RP)) { + if (!tokenStream.matchToken(TOK_RP)) { do { - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -2844,17 +2842,17 @@ JSCompiler::functionDef(uintN lambda) return NULL; #endif } - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (tokenStream.matchToken(TOK_COMMA)); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); } #if JS_HAS_EXPR_CLOSURES tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt != TOK_LC) { - UngetToken(&tokenStream); + tokenStream.ungetToken(); fun->flags |= JSFUN_EXPR_CLOSURE; } #else @@ -3064,7 +3062,7 @@ JSCompiler::statements() for (;;) { tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = tokenStream.peekToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt <= TOK_EOF || tt == TOK_RC) { if (tt == TOK_ERROR) { @@ -3143,11 +3141,11 @@ MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn) JSAtom *label; TokenKind tt; - tt = PeekTokenSameLine(cx, ts); + tt = ts->peekTokenSameLine(); if (tt == TOK_ERROR) return JS_FALSE; if (tt == TOK_NAME) { - (void) GetToken(cx, ts); + (void) ts->getToken(); label = ts->currentToken().t_atom; } else { label = NULL; @@ -4238,7 +4236,7 @@ JSCompiler::returnOrYield(bool useAssignExpr) /* This is ugly, but we don't want to require a semicolon. */ tokenStream.flags |= TSF_OPERAND; - tt2 = PeekTokenSameLine(context, &tokenStream); + tt2 = tokenStream.peekTokenSameLine(); tokenStream.flags &= ~TSF_OPERAND; if (tt2 == TOK_ERROR) return NULL; @@ -4349,7 +4347,7 @@ JSCompiler::letBlock(JSBool statement) MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET); tokenStream.flags |= TSF_OPERAND; - if (statement && !MatchToken(context, &tokenStream, TOK_LC)) { + if (statement && !tokenStream.matchToken(TOK_LC)) { /* * If this is really an expression in let statement guise, then we * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop @@ -4526,7 +4524,7 @@ JSCompiler::statement() JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_GETTER_SETTER @@ -4541,7 +4539,7 @@ JSCompiler::statement() case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = PeekToken(context, &tokenStream); + tt = tokenStream.peekToken(); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_DBLCOLON) goto expression; @@ -4561,7 +4559,7 @@ JSCompiler::statement() if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND; - if (MatchToken(context, &tokenStream, TOK_ELSE)) { + if (tokenStream.matchToken(TOK_ELSE)) { tokenStream.flags &= ~TSF_OPERAND; stmtInfo.type = STMT_ELSE; pn3 = statement(); @@ -4613,7 +4611,7 @@ JSCompiler::statement() saveBlock = tc->blockNode; tc->blockNode = pn2; - while ((tt = GetToken(context, &tokenStream)) != TOK_RC) { + while ((tt = tokenStream.getToken()) != TOK_RC) { switch (tt) { case TOK_DEFAULT: if (seenDefault) { @@ -4657,7 +4655,7 @@ JSCompiler::statement() pn4->pn_type = TOK_LC; pn4->makeEmpty(); tokenStream.flags |= TSF_OPERAND; - while ((tt = PeekToken(context, &tokenStream)) != TOK_RC && + while ((tt = tokenStream.peekToken()) != TOK_RC && tt != TOK_CASE && tt != TOK_DEFAULT) { tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) @@ -4734,7 +4732,7 @@ JSCompiler::statement() * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ - (void) MatchToken(context, &tokenStream, TOK_SEMI); + (void) tokenStream.matchToken(TOK_SEMI); return pn; } break; @@ -4755,16 +4753,16 @@ JSCompiler::statement() pn->pn_op = JSOP_ITER; pn->pn_iflags = 0; - if (MatchToken(context, &tokenStream, TOK_NAME)) { + if (tokenStream.matchToken(TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn->pn_iflags = JSITER_FOREACH; else - UngetToken(&tokenStream); + tokenStream.ungetToken(); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = tokenStream.peekToken(); tokenStream.flags &= ~TSF_OPERAND; #if JS_HAS_BLOCK_SCOPE @@ -4793,13 +4791,13 @@ JSCompiler::statement() */ tc->flags |= TCF_IN_FOR_INIT; if (tt == TOK_VAR) { - (void) GetToken(context, &tokenStream); + (void) tokenStream.getToken(); pn1 = variables(false); #if JS_HAS_BLOCK_SCOPE } else if (tt == TOK_LET) { let = true; - (void) GetToken(context, &tokenStream); - if (PeekToken(context, &tokenStream) == TOK_LP) { + (void) tokenStream.getToken(); + if (tokenStream.peekToken() == TOK_LP) { pn1 = letBlock(JS_FALSE); tt = TOK_LEXICALSCOPE; } else { @@ -4824,7 +4822,7 @@ JSCompiler::statement() * as we've excluded 'in' from being parsed in RelExpr by setting * the TCF_IN_FOR_INIT flag in our JSTreeContext. */ - if (pn1 && MatchToken(context, &tokenStream, TOK_IN)) { + if (pn1 && tokenStream.matchToken(TOK_IN)) { pn->pn_iflags |= JSITER_ENUMERATE; stmtInfo.type = STMT_FOR_IN_LOOP; @@ -5028,7 +5026,7 @@ JSCompiler::statement() /* Parse the loop condition or null into pn2. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = tokenStream.peekToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_SEMI) { pn2 = NULL; @@ -5041,7 +5039,7 @@ JSCompiler::statement() /* Parse the update expression or null into pn3. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = tokenStream.peekToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RP) { pn3 = NULL; @@ -5130,7 +5128,7 @@ JSCompiler::statement() PopStatement(tc); catchList = NULL; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); if (tt == TOK_CATCH) { catchList = ListNode::create(tc); if (!catchList) @@ -5182,7 +5180,7 @@ JSCompiler::statement() data.binder = BindLet; data.let.overflow = JSMSG_TOO_MANY_CATCH_VARS; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -5216,7 +5214,7 @@ JSCompiler::statement() * to avoid conflicting with the JS2/ECMAv4 type annotation * catchguard syntax. */ - if (MatchToken(context, &tokenStream, TOK_IF)) { + if (tokenStream.matchToken(TOK_IF)) { pn2->pn_kid2 = expr(); if (!pn2->pn_kid2) return NULL; @@ -5234,7 +5232,7 @@ JSCompiler::statement() catchList->append(pnblock); lastCatch = pn2; tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; } while (tt == TOK_CATCH); } @@ -5250,7 +5248,7 @@ JSCompiler::statement() MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); PopStatement(tc); } else { - UngetToken(&tokenStream); + tokenStream.ungetToken(); } if (!catchList && !pn->pn_kid3) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, @@ -5267,7 +5265,7 @@ JSCompiler::statement() /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ tokenStream.flags |= TSF_OPERAND; - tt = PeekTokenSameLine(context, &tokenStream); + tt = tokenStream.peekTokenSameLine(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; @@ -5424,7 +5422,7 @@ JSCompiler::statement() JSObjectBox *blockbox; /* Check for a let statement or let expression. */ - if (PeekToken(context, &tokenStream) == TOK_LP) { + if (tokenStream.peekToken() == TOK_LP) { pn = letBlock(JS_TRUE); if (!pn || pn->pn_op == JSOP_LEAVEBLOCK) return pn; @@ -5594,11 +5592,11 @@ JSCompiler::statement() pn = UnaryNode::create(tc); if (!pn) return NULL; - if (!MatchToken(context, &tokenStream, TOK_NAME) || + if (!tokenStream.matchToken(TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.xmlAtom || - !MatchToken(context, &tokenStream, TOK_NAME) || + !tokenStream.matchToken(TOK_NAME) || tokenStream.currentToken().t_atom != context->runtime->atomState.namespaceAtom || - !MatchToken(context, &tokenStream, TOK_ASSIGN) || + !tokenStream.matchToken(TOK_ASSIGN) || tokenStream.currentToken().t_op != JSOP_NOP) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_DEFAULT_XML_NAMESPACE); @@ -5623,12 +5621,12 @@ JSCompiler::statement() #if JS_HAS_XML_SUPPORT expression: #endif - UngetToken(&tokenStream); + tokenStream.ungetToken(); pn2 = expr(); if (!pn2) return NULL; - if (PeekToken(context, &tokenStream) == TOK_COLON) { + if (tokenStream.peekToken() == TOK_COLON) { if (pn2->pn_type != TOK_NAME) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL); @@ -5644,7 +5642,7 @@ JSCompiler::statement() } ForgetUse(pn2); - (void) GetToken(context, &tokenStream); + (void) tokenStream.getToken(); /* Push a label struct and parse the statement. */ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); @@ -5777,7 +5775,7 @@ JSCompiler::variables(bool inLetHead) } do { - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); #if JS_HAS_DESTRUCTURING if (tt == TOK_LB || tt == TOK_LC) { tc->flags |= TCF_DECL_DESTRUCTURING; @@ -5789,7 +5787,7 @@ JSCompiler::variables(bool inLetHead) if (!CheckDestructuring(context, &data, pn2, NULL, tc)) return NULL; if ((tc->flags & TCF_IN_FOR_INIT) && - PeekToken(context, &tokenStream) == TOK_IN) { + tokenStream.peekToken() == TOK_IN) { pn->append(pn2); continue; } @@ -5842,7 +5840,7 @@ JSCompiler::variables(bool inLetHead) return NULL; pn->append(pn2); - if (MatchToken(context, &tokenStream, TOK_ASSIGN)) { + if (tokenStream.matchToken(TOK_ASSIGN)) { if (tokenStream.currentToken().t_op != JSOP_NOP) goto bad_var_init; @@ -5892,7 +5890,7 @@ JSCompiler::variables(bool inLetHead) tc->flags |= TCF_FUN_HEAVYWEIGHT; } } - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (tokenStream.matchToken(TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; return pn; @@ -5909,7 +5907,7 @@ JSCompiler::expr() JSParseNode *pn, *pn2; pn = assignExpr(); - if (pn && MatchToken(context, &tokenStream, TOK_COMMA)) { + if (pn && tokenStream.matchToken(TOK_COMMA)) { pn2 = ListNode::create(tc); if (!pn2) return NULL; @@ -5930,7 +5928,7 @@ JSCompiler::expr() if (!pn2) return NULL; pn->append(pn2); - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (tokenStream.matchToken(TOK_COMMA)); pn->pn_pos.end = pn->last()->pn_pos.end; } return pn; @@ -5947,7 +5945,7 @@ JSCompiler::assignExpr() #if JS_HAS_GENERATORS tokenStream.flags |= TSF_OPERAND; - if (MatchToken(context, &tokenStream, TOK_YIELD)) { + if (tokenStream.matchToken(TOK_YIELD)) { tokenStream.flags &= ~TSF_OPERAND; return returnOrYield(true); } @@ -5958,7 +5956,7 @@ JSCompiler::assignExpr() if (!pn) return NULL; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { tt = CheckGetterOrSetter(context, &tokenStream, TOK_ASSIGN); @@ -5967,7 +5965,7 @@ JSCompiler::assignExpr() } #endif if (tt != TOK_ASSIGN) { - UngetToken(&tokenStream); + tokenStream.ungetToken(); return pn; } @@ -6043,7 +6041,7 @@ JSCompiler::condExpr() uintN oldflags; pn = orExpr(); - if (pn && MatchToken(context, &tokenStream, TOK_HOOK)) { + if (pn && tokenStream.matchToken(TOK_HOOK)) { pn1 = pn; pn = TernaryNode::create(tc); if (!pn) @@ -6080,7 +6078,7 @@ JSCompiler::orExpr() JSParseNode *pn; pn = andExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_OR)) + while (pn && tokenStream.matchToken(TOK_OR)) pn = JSParseNode::newBinaryOrAppend(TOK_OR, JSOP_OR, pn, andExpr(), tc); return pn; } @@ -6091,7 +6089,7 @@ JSCompiler::andExpr() JSParseNode *pn; pn = bitOrExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_AND)) + while (pn && tokenStream.matchToken(TOK_AND)) pn = JSParseNode::newBinaryOrAppend(TOK_AND, JSOP_AND, pn, bitOrExpr(), tc); return pn; } @@ -6102,7 +6100,7 @@ JSCompiler::bitOrExpr() JSParseNode *pn; pn = bitXorExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_BITOR)) { + while (pn && tokenStream.matchToken(TOK_BITOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITOR, JSOP_BITOR, pn, bitXorExpr(), tc); } return pn; @@ -6114,7 +6112,7 @@ JSCompiler::bitXorExpr() JSParseNode *pn; pn = bitAndExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_BITXOR)) { + while (pn && tokenStream.matchToken(TOK_BITXOR)) { pn = JSParseNode::newBinaryOrAppend(TOK_BITXOR, JSOP_BITXOR, pn, bitAndExpr(), tc); } return pn; @@ -6126,7 +6124,7 @@ JSCompiler::bitAndExpr() JSParseNode *pn; pn = eqExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_BITAND)) + while (pn && tokenStream.matchToken(TOK_BITAND)) pn = JSParseNode::newBinaryOrAppend(TOK_BITAND, JSOP_BITAND, pn, eqExpr(), tc); return pn; } @@ -6138,7 +6136,7 @@ JSCompiler::eqExpr() JSOp op; pn = relExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_EQOP)) { + while (pn && tokenStream.matchToken(TOK_EQOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_EQOP, op, pn, relExpr(), tc); } @@ -6161,13 +6159,13 @@ JSCompiler::relExpr() pn = shiftExpr(); while (pn && - (MatchToken(context, &tokenStream, TOK_RELOP) || + (tokenStream.matchToken(TOK_RELOP) || /* * Recognize the 'in' token as an operator only if we're not * currently in the init expr of a for loop. */ - (inForInitFlag == 0 && MatchToken(context, &tokenStream, TOK_IN)) || - MatchToken(context, &tokenStream, TOK_INSTANCEOF))) { + (inForInitFlag == 0 && tokenStream.matchToken(TOK_IN)) || + tokenStream.matchToken(TOK_INSTANCEOF))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, shiftExpr(), tc); @@ -6185,7 +6183,7 @@ JSCompiler::shiftExpr() JSOp op; pn = addExpr(); - while (pn && MatchToken(context, &tokenStream, TOK_SHOP)) { + while (pn && tokenStream.matchToken(TOK_SHOP)) { op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(TOK_SHOP, op, pn, addExpr(), tc); } @@ -6201,8 +6199,8 @@ JSCompiler::addExpr() pn = mulExpr(); while (pn && - (MatchToken(context, &tokenStream, TOK_PLUS) || - MatchToken(context, &tokenStream, TOK_MINUS))) { + (tokenStream.matchToken(TOK_PLUS) || + tokenStream.matchToken(TOK_MINUS))) { tt = tokenStream.currentToken().type; op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, mulExpr(), tc); @@ -6219,8 +6217,8 @@ JSCompiler::mulExpr() pn = unaryExpr(); while (pn && - (MatchToken(context, &tokenStream, TOK_STAR) || - MatchToken(context, &tokenStream, TOK_DIVOP))) { + (tokenStream.matchToken(TOK_STAR) || + tokenStream.matchToken(TOK_DIVOP))) { tt = tokenStream.currentToken().type; op = tokenStream.currentToken().t_op; pn = JSParseNode::newBinaryOrAppend(tt, op, pn, unaryExpr(), tc); @@ -6308,7 +6306,7 @@ JSCompiler::unaryExpr() JS_CHECK_RECURSION(context, return NULL); tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; switch (tt) { @@ -6378,7 +6376,7 @@ JSCompiler::unaryExpr() return NULL; default: - UngetToken(&tokenStream); + tokenStream.ungetToken(); pn = memberExpr(JS_TRUE); if (!pn) return NULL; @@ -6386,10 +6384,10 @@ JSCompiler::unaryExpr() /* Don't look across a newline boundary for a postfix incop. */ if (tokenStream.onCurrentLine(pn->pn_pos)) { tokenStream.flags |= TSF_OPERAND; - tt = PeekTokenSameLine(context, &tokenStream); + tt = tokenStream.peekTokenSameLine(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_INC || tt == TOK_DEC) { - (void) GetToken(context, &tokenStream); + (void) tokenStream.getToken(); pn2 = UnaryNode::create(tc); if (!pn2) return NULL; @@ -6705,16 +6703,16 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, pn2->pn_op = JSOP_ITER; pn2->pn_iflags = JSITER_ENUMERATE; - if (MatchToken(context, &tokenStream, TOK_NAME)) { + if (tokenStream.matchToken(TOK_NAME)) { if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom) pn2->pn_iflags |= JSITER_FOREACH; else - UngetToken(&tokenStream); + tokenStream.ungetToken(); } MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); atom = NULL; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); switch (tt) { #if JS_HAS_DESTRUCTURING case TOK_LB: @@ -6793,9 +6791,9 @@ JSCompiler::comprehensionTail(JSParseNode *kid, uintN blockid, return NULL; *pnp = pn2; pnp = &pn2->pn_right; - } while (MatchToken(context, &tokenStream, TOK_FOR)); + } while (tokenStream.matchToken(TOK_FOR)); - if (MatchToken(context, &tokenStream, TOK_IF)) { + if (tokenStream.matchToken(TOK_IF)) { pn2 = TernaryNode::create(tc); if (!pn2) return NULL; @@ -6927,7 +6925,7 @@ JSCompiler::argumentList(JSParseNode *listNode) JSBool matched; tokenStream.flags |= TSF_OPERAND; - matched = MatchToken(context, &tokenStream, TOK_RP); + matched = tokenStream.matchToken(TOK_RP); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { do { @@ -6937,7 +6935,7 @@ JSCompiler::argumentList(JSParseNode *listNode) #if JS_HAS_GENERATORS if (argNode->pn_type == TOK_YIELD && !argNode->pn_parens && - PeekToken(context, &tokenStream) == TOK_COMMA) { + tokenStream.peekToken() == TOK_COMMA) { ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); @@ -6945,7 +6943,7 @@ JSCompiler::argumentList(JSParseNode *listNode) } #endif #if JS_HAS_GENERATOR_EXPRS - if (MatchToken(context, &tokenStream, TOK_FOR)) { + if (tokenStream.matchToken(TOK_FOR)) { JSParseNode *pn = UnaryNode::create(tc); if (!pn) return JS_FALSE; @@ -6953,7 +6951,7 @@ JSCompiler::argumentList(JSParseNode *listNode) if (!argNode) return JS_FALSE; if (listNode->pn_count > 1 || - PeekToken(context, &tokenStream) == TOK_COMMA) { + tokenStream.peekToken() == TOK_COMMA) { ReportCompileErrorNumber(context, &tokenStream, argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); @@ -6962,9 +6960,9 @@ JSCompiler::argumentList(JSParseNode *listNode) } #endif listNode->append(argNode); - } while (MatchToken(context, &tokenStream, TOK_COMMA)); + } while (tokenStream.matchToken(TOK_COMMA)); - if (GetToken(context, &tokenStream) != TOK_RP) { + if (tokenStream.getToken() != TOK_RP) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_ARGS); return JS_FALSE; @@ -6992,13 +6990,12 @@ JSParseNode * JSCompiler::memberExpr(JSBool allowCallSyntax) { JSParseNode *pn, *pn2, *pn3; - TokenKind tt; JS_CHECK_RECURSION(context, return NULL); /* Check for new expression first. */ tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + TokenKind tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_NEW) { pn = ListNode::create(tc); @@ -7012,7 +7009,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) pn->initList(pn2); pn->pn_pos.begin = pn2->pn_pos.begin; - if (MatchToken(context, &tokenStream, TOK_LP) && !argumentList(pn)) + if (tokenStream.matchToken(TOK_LP) && !argumentList(pn)) return NULL; if (pn->pn_count > ARGC_LIMIT) { JS_ReportErrorNumber(context, js_GetErrorMessage, NULL, @@ -7041,14 +7038,14 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } } - while ((tt = GetToken(context, &tokenStream)) > TOK_EOF) { + while ((tt = tokenStream.getToken()) > TOK_EOF) { if (tt == TOK_DOT) { pn2 = NameNode::create(NULL, tc); if (!pn2) return NULL; #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7095,7 +7092,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) if (!pn2) return NULL; tokenStream.flags |= TSF_OPERAND | TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~(TSF_OPERAND | TSF_KEYWORD_IS_NAME); pn3 = primaryExpr(tt, JS_TRUE); if (!pn3) @@ -7188,7 +7185,7 @@ JSCompiler::memberExpr(JSBool allowCallSyntax) } pn2->pn_pos.end = tokenStream.currentToken().pos.end; } else { - UngetToken(&tokenStream); + tokenStream.ungetToken(); return pn; } @@ -7321,7 +7318,7 @@ JSCompiler::qualifiedSuffix(JSParseNode *pn) pn->pn_op = JSOP_NAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { /* Inline and specialize propertySelector for JSOP_QNAMECONST. */ @@ -7361,7 +7358,7 @@ JSCompiler::qualifiedIdentifier() pn = propertySelector(); if (!pn) return NULL; - if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (tokenStream.matchToken(TOK_DBLCOLON)) { /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */ tc->flags |= TCF_FUN_HEAVYWEIGHT; pn = qualifiedSuffix(pn); @@ -7381,7 +7378,7 @@ JSCompiler::attributeIdentifier() return NULL; pn->pn_op = JSOP_TOATTRNAME; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_STAR || tt == TOK_NAME) { pn2 = qualifiedIdentifier(); @@ -7499,9 +7496,9 @@ JSCompiler::xmlNameExpr() pn->pn_pos.end = pn2->pn_pos.end; pn->append(pn2); } - } while ((tt = GetToken(context, &tokenStream)) == TOK_XMLNAME || tt == TOK_LC); + } while ((tt = tokenStream.getToken()) == TOK_XMLNAME || tt == TOK_LC); - UngetToken(&tokenStream); + tokenStream.ungetToken(); return pn; } @@ -7542,10 +7539,10 @@ JSCompiler::xmlTagContent(TokenKind tagtype, JSAtom **namep) *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL; list = NULL; - while (MatchToken(context, &tokenStream, TOK_XMLSPACE)) { - tt = GetToken(context, &tokenStream); + while (tokenStream.matchToken(TOK_XMLSPACE)) { + tt = tokenStream.getToken(); if (tt != TOK_XMLNAME && tt != TOK_LC) { - UngetToken(&tokenStream); + tokenStream.ungetToken(); break; } @@ -7565,11 +7562,11 @@ JSCompiler::xmlTagContent(TokenKind tagtype, JSAtom **namep) if (!XML_FOLDABLE(pn2)) pn->pn_xflags |= PNX_CANTFOLD; - MatchToken(context, &tokenStream, TOK_XMLSPACE); + tokenStream.matchToken(TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR); - MatchToken(context, &tokenStream, TOK_XMLSPACE); + tokenStream.matchToken(TOK_XMLSPACE); - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); if (tt == TOK_XMLATTR) { pn2 = xmlAtomNode(); } else if (tt == TOK_LC) { @@ -7614,7 +7611,7 @@ JSCompiler::xmlElementContent(JSParseNode *pn) tokenStream.flags &= ~TSF_XMLTAGMODE; for (;;) { tokenStream.flags |= TSF_XMLTEXTMODE; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_XMLTEXTMODE; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); @@ -7630,7 +7627,7 @@ JSCompiler::xmlElementContent(JSParseNode *pn) } tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE); if (tt == TOK_XMLETAGO) @@ -7679,7 +7676,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) return NULL; tokenStream.flags |= TSF_XMLTAGMODE; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); if (tt == TOK_ERROR) return NULL; @@ -7690,9 +7687,9 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn2 = xmlTagContent(TOK_XMLSTAGO, &startAtom); if (!pn2) return NULL; - MatchToken(context, &tokenStream, TOK_XMLSPACE); + tokenStream.matchToken(TOK_XMLSPACE); - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); if (tt == TOK_XMLPTAGC) { /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */ if (pn2->pn_type == TOK_XMLSTAGO) { @@ -7740,7 +7737,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) if (!xmlElementContent(pn)) return NULL; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL); if (tt != TOK_XMLNAME && tt != TOK_LC) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, @@ -7780,7 +7777,7 @@ JSCompiler::xmlElementOrList(JSBool allowList) pn->pn_xflags |= PNX_CANTFOLD; } - MatchToken(context, &tokenStream, TOK_XMLSPACE); + tokenStream.matchToken(TOK_XMLSPACE); MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX); } @@ -7838,7 +7835,7 @@ JSCompiler::parseXMLText(JSObject *chain, bool allowList) /* Set XML-only mode to turn off special treatment of {expr} in XML. */ tokenStream.flags |= TSF_OPERAND | TSF_XMLONLYMODE; - TokenKind tt = GetToken(context, &tokenStream); + TokenKind tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; JSParseNode *pn; @@ -7910,7 +7907,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) case TOK_FUNCTION: #if JS_HAS_XML_SUPPORT tokenStream.flags |= TSF_KEYWORD_IS_NAME; - if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (tokenStream.matchToken(TOK_DBLCOLON)) { tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; pn2 = NullaryNode::create(tc); if (!pn2) @@ -7945,7 +7942,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) #endif tokenStream.flags |= TSF_OPERAND; - matched = MatchToken(context, &tokenStream, TOK_RB); + matched = tokenStream.matchToken(TOK_RB); tokenStream.flags &= ~TSF_OPERAND; if (!matched) { for (index = 0; ; index++) { @@ -7956,7 +7953,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) } tokenStream.flags |= TSF_OPERAND; - tt = PeekToken(context, &tokenStream); + tt = tokenStream.peekToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_RB) { pn->pn_xflags |= PNX_ENDCOMMA; @@ -7965,7 +7962,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) if (tt == TOK_COMMA) { /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ - MatchToken(context, &tokenStream, TOK_COMMA); + tokenStream.matchToken(TOK_COMMA); pn2 = NullaryNode::create(tc); pn->pn_xflags |= PNX_HOLEY; } else { @@ -7977,7 +7974,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) if (tt != TOK_COMMA) { /* If we didn't already match TOK_COMMA in above case. */ - if (!MatchToken(context, &tokenStream, TOK_COMMA)) + if (!tokenStream.matchToken(TOK_COMMA)) break; } } @@ -8025,9 +8022,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) * the example above, is done by ; JSOP_ARRAYCOMP , * where is the index of array's stack slot. */ - if (index == 0 && - pn->pn_count != 0 && - MatchToken(context, &tokenStream, TOK_FOR)) { + if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) { JSParseNode *pnexp, *pntop; /* Relabel pn as an array comprehension node. */ @@ -8084,7 +8079,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) for (;;) { JSAtom *atom; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; switch (tt) { case TOK_NUMBER: @@ -8109,10 +8104,10 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) goto property_name; tokenStream.flags |= TSF_KEYWORD_IS_NAME; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_KEYWORD_IS_NAME; if (tt != TOK_NAME) { - UngetToken(&tokenStream); + tokenStream.ungetToken(); goto property_name; } atom = tokenStream.currentToken().t_atom; @@ -8144,7 +8139,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) return NULL; } - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); op = JSOP_INITPROP; #if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { @@ -8171,7 +8166,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) * Support, e.g., |var {x, y} = o| as destructuring shorthand * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8. */ - UngetToken(&tokenStream); + tokenStream.ungetToken(); pn->pn_xflags |= PNX_DESTRUCT; pnval = pn3; if (pnval->pn_type == TOK_NAME) { @@ -8226,7 +8221,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) } } - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); if (tt == TOK_RC) goto end_obj_init; if (tt != TOK_COMMA) { @@ -8257,7 +8252,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) return NULL; pn->pn_num = (jsint) tokenStream.currentToken().t_dval; tokenStream.flags |= TSF_OPERAND; - tt = GetToken(context, &tokenStream); + tt = tokenStream.getToken(); tokenStream.flags &= ~TSF_OPERAND; if (tt == TOK_USESHARP || tt == TOK_DEFSHARP || #if JS_HAS_XML_SUPPORT @@ -8370,7 +8365,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) } } else if ((!afterDot #if JS_HAS_XML_SUPPORT - || PeekToken(context, &tokenStream) == TOK_DBLCOLON + || tokenStream.peekToken() == TOK_DBLCOLON #endif ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) { JSStmtInfo *stmt = js_LexicalLookup(tc, pn->pn_atom, NULL); @@ -8432,7 +8427,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) */ JS_ASSERT(PN_TYPE(dn) == TOK_NAME); JS_ASSERT(dn->pn_op == JSOP_NOP); - if (PeekToken(context, &tokenStream) != TOK_LP) + if (tokenStream.peekToken() != TOK_LP) dn->pn_dflags |= PND_FUNARG; } } @@ -8441,7 +8436,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) LinkUseToDef(pn, dn, tc); /* Here we handle the backward function reference case. */ - if (PeekToken(context, &tokenStream) != TOK_LP) + if (tokenStream.peekToken() != TOK_LP) dn->pn_dflags |= PND_FUNARG; pn->pn_dflags |= (dn->pn_dflags & PND_FUNARG); @@ -8449,7 +8444,7 @@ JSCompiler::primaryExpr(TokenKind tt, JSBool afterDot) } #if JS_HAS_XML_SUPPORT - if (MatchToken(context, &tokenStream, TOK_DBLCOLON)) { + if (tokenStream.matchToken(TOK_DBLCOLON)) { if (afterDot) { JSString *str; @@ -8546,7 +8541,7 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; #if JS_HAS_GENERATOR_EXPRS - if (MatchToken(context, &tokenStream, TOK_FOR)) { + if (tokenStream.matchToken(TOK_FOR)) { if (pn->pn_type == TOK_YIELD && !pn->pn_parens) { ReportCompileErrorNumber(context, &tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str); @@ -8567,7 +8562,7 @@ JSCompiler::parenExpr(JSParseNode *pn1, JSBool *genexp) return NULL; pn->pn_pos.begin = begin; if (genexp) { - if (GetToken(context, &tokenStream) != TOK_RP) { + if (tokenStream.getToken() != TOK_RP) { ReportCompileErrorNumber(context, &tokenStream, NULL, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str); return NULL; diff --git a/js/src/jsparse.h b/js/src/jsparse.h index b7155cf70407..b72a021ba000 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -298,7 +298,7 @@ struct JSParseNode { #define PN_OP(pn) ((JSOp)(pn)->pn_op) #define PN_TYPE(pn) ((js::TokenKind)(pn)->pn_type) - js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ + js::TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */ int32 pn_offset; /* first generated bytecode offset */ JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */ JSParseNode *pn_link; /* def/use link (alignment freebie); diff --git a/js/src/jsscan.h b/js/src/jsscan.h index ea6d20e8d7ee..c8e5c33eb2d6 100644 --- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -344,6 +344,10 @@ class TokenStream Token *mutableCurrentToken() { return &tokens[cursor]; } bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); + /* + * Get the next token from the stream, make it the current token, and + * return its kind. + */ TokenKind getToken() { /* Check for a pushed-back token resulting from mismatching lookahead. */ while (lookahead != 0) { @@ -367,6 +371,9 @@ class TokenStream return &tokens[index]; } + /* + * Push the last scanned token back into the stream. + */ void ungetToken() { JS_ASSERT(lookahead < ntokensMask); lookahead++; @@ -391,6 +398,9 @@ class TokenStream return tt; } + /* + * Get the next token from the stream if its kind is |tt|. + */ JSBool matchToken(TokenKind tt) { if (getToken() == tt) return JS_TRUE; @@ -528,52 +538,6 @@ bool ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, uintN errorNumber, ...); -/* - * Look ahead one token and return its type. - */ -static inline TokenKind -PeekToken(JSContext *cx, TokenStream *ts) -{ - JS_ASSERT(cx == ts->getContext()); - return ts->peekToken(); -} - -static inline TokenKind -PeekTokenSameLine(JSContext *cx, TokenStream *ts) -{ - JS_ASSERT(cx == ts->getContext()); - return ts->peekTokenSameLine(); -} - -/* - * Get the next token from ts. - */ -static inline TokenKind -GetToken(JSContext *cx, TokenStream *ts) -{ - JS_ASSERT(cx == ts->getContext()); - return ts->getToken(); -} - -/* - * Push back the last scanned token onto ts. - */ -static inline void -UngetToken(TokenStream *ts) -{ - ts->ungetToken(); -} - -/* - * Get the next token from ts if its type is tt. - */ -static inline JSBool -MatchToken(JSContext *cx, TokenStream *ts, TokenKind tt) -{ - JS_ASSERT(cx == ts->getContext()); - return ts->matchToken(tt); -} - } /* namespace js */ #endif /* jsscan_h___ */ From 5f6a5af9a8db98aae1bed4d645a63df7c866ccdc Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Tue, 23 Mar 2010 21:23:40 -0700 Subject: [PATCH 127/213] Bug 531350 - TMFLAGS=fragprofile leads to reading freed memory. r=graydon. --- js/src/jstracer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 773ed3ef8bd9..4cd58651741b 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -4058,7 +4058,16 @@ TraceRecorder::snapshot(ExitType exitType) JS_REQUIRES_STACK GuardRecord* TraceRecorder::createGuardRecord(VMSideExit* exit) { +#ifdef JS_JIT_SPEW + // For debug builds, place the guard records in a longer lasting + // pool. This is because the fragment profiler will look at them + // relatively late in the day, after they would have been freed, + // in some cases, had they been allocated in traceAlloc(). + GuardRecord* gr = new (dataAlloc()) GuardRecord(); +#else + // The standard place (for production builds). GuardRecord* gr = new (traceAlloc()) GuardRecord(); +#endif gr->exit = exit; exit->addGuard(gr); From 5486afbe8075363ea17e6f090638d10b8dec6d2c Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Wed, 24 Mar 2010 12:36:42 -0700 Subject: [PATCH 128/213] Public JS API for new ES5 Object functions (551595, r=jwalden). --- js/src/jsapi.cpp | 14 +++++++++ js/src/jsapi.h | 6 ++++ js/src/jsobj.cpp | 74 +++++++++++++++++++++++++++++------------------- js/src/jsobj.h | 6 ++++ 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 27c53c646a81..028893f584a9 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2989,6 +2989,13 @@ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, JSScopeProperty::HAS_SHORTID, tinyid); } +JS_PUBLIC_API(JSBool) +JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp) +{ + CHECK_REQUEST(cx); + return js_DefineOwnProperty(cx, obj, id, descriptor, bp); +} + static JSBool LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp, JSProperty **propp) @@ -3393,6 +3400,13 @@ JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, return GetPropertyAttributesById(cx, obj, id, flags, JS_FALSE, desc); } +JS_PUBLIC_API(JSBool) +JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_GetOwnPropertyDescriptor(cx, obj, id, vp); +} + JS_PUBLIC_API(JSBool) JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 9dce64cbed8b..4d8f1c1c9316 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1726,6 +1726,9 @@ extern JS_PUBLIC_API(JSBool) JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs); +extern JS_PUBLIC_API(JSBool) +JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp); + /* * Determine the attributes (JSPROP_* flags) of a property on a given object. * @@ -1820,6 +1823,9 @@ extern JS_PUBLIC_API(JSBool) JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSPropertyDescriptor *desc); +extern JS_PUBLIC_API(JSBool) +JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + extern JS_PUBLIC_API(JSBool) JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 44498951cb33..6122d99b322d 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1943,33 +1943,22 @@ obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp) JSACC_PROTO, vp, &attrs); } -static JSBool -obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) +JSBool +js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - if (argc == 0 || JSVAL_IS_PRIMITIVE(vp[2])) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); - return JS_FALSE; - } - - JSObject *obj = JSVAL_TO_OBJECT(vp[2]); - - AutoIdRooter nameidr(cx); - if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) - return JS_FALSE; - JSObject *pobj; JSProperty *prop; - if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, nameidr.id(), &pobj, &prop)) - return JS_FALSE; + if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &pobj, &prop)) + return false; if (!prop) { *vp = JSVAL_VOID; - return JS_TRUE; + return true; } uintN attrs; - if (!pobj->getAttributes(cx, nameidr.id(), prop, &attrs)) { + if (!pobj->getAttributes(cx, id, prop, &attrs)) { pobj->dropProperty(cx, prop); - return JS_FALSE; + return false; } jsval roots[] = { JSVAL_VOID, JSVAL_VOID }; @@ -1987,15 +1976,15 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) } else { pobj->dropProperty(cx, prop); - if (!obj->getProperty(cx, nameidr.id(), &roots[0])) - return JS_FALSE; + if (!obj->getProperty(cx, id, &roots[0])) + return false; } /* We have our own property, so start creating the descriptor. */ JSObject *desc = js_NewObject(cx, &js_ObjectClass, NULL, NULL); if (!desc) - return JS_FALSE; + return false; *vp = OBJECT_TO_JSVAL(desc); /* Root and return. */ const JSAtomState &atomState = cx->runtime->atomState; @@ -2004,7 +1993,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) || !desc->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), roots[1], JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) { - return JS_FALSE; + return false; } } else { if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), roots[0], @@ -2012,7 +2001,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) !desc->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom), BOOLEAN_TO_JSVAL((attrs & JSPROP_READONLY) == 0), JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) { - return JS_FALSE; + return false; } } @@ -2024,6 +2013,20 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE); } +static JSBool +obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) +{ + if (argc == 0 || JSVAL_IS_PRIMITIVE(vp[2])) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); + return false; + } + JSObject *obj = JSVAL_TO_OBJECT(vp[2]); + AutoIdRooter nameidr(cx); + if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) + return JS_FALSE; + return js_GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp); +} + static JSBool obj_keys(JSContext *cx, uintN argc, jsval *vp) { @@ -2563,6 +2566,22 @@ DefineProperty(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, boo return DefinePropertyObject(cx, obj, desc, throwError, rval); } +JSBool +js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp) +{ + AutoDescriptorArray descs(cx); + PropertyDescriptor *desc = descs.append(); + + if (!desc || !desc->initialize(cx, id, descriptor)) + return false; + + bool rval; + if (!DefineProperty(cx, obj, *desc, true, &rval)) + return false; + *bp = !!rval; + return true; +} + /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */ static JSBool obj_defineProperty(JSContext* cx, uintN argc, jsval* vp) @@ -2582,14 +2601,11 @@ obj_defineProperty(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; /* 15.2.3.6 step 3. */ - AutoDescriptorArray descs(cx); - PropertyDescriptor *desc = descs.append(); - if (!desc || !desc->initialize(cx, nameidr.id(), argc >= 3 ? vp[4] : JSVAL_VOID)) - return JS_FALSE; + jsval descval = argc >= 3 ? vp[4] : JSVAL_VOID; /* 15.2.3.6 step 4 */ - bool dummy; - return DefineProperty(cx, obj, *desc, true, &dummy); + JSBool junk; + return js_DefineOwnProperty(cx, obj, nameidr.id(), descval, &junk); } /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */ diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 69403e528248..2248ace3575d 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -830,6 +830,9 @@ extern JSBool js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs); +extern JSBool +js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp); + /* * Flags for the defineHow parameter of js_DefineNativeProperty. */ @@ -953,6 +956,9 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, extern JSBool js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +extern JSBool +js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + extern JSBool js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp); From 611d7273c823eab90c43582d5e8809c3bcc797ed Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Wed, 24 Mar 2010 13:18:55 -0700 Subject: [PATCH 129/213] Disable partial flat closures pending scope chain reconstruction on trace (554572, r=jorendorff). --- js/src/jsparse.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 60fce6208378..806f1fe7e79c 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -2324,7 +2324,8 @@ JSCompiler::setFunctionKinds(JSFunctionBox *funbox, uint32& tcflags) if (nupvars == 0) { FUN_METER(onlyfreevar); FUN_SET_KIND(fun, JSFUN_NULL_CLOSURE); - } else if (nflattened != 0) { + } else if (nflattened == nupvars) { + /* FIXME bug 545759: to test nflattened != 0 */ /* * We made it all the way through the upvar loop, so it's * safe to optimize to a flat closure. From d2230d46e02d05f26c93ce4c86edc2ff481cb3ce Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 24 Mar 2010 16:16:01 -0500 Subject: [PATCH 130/213] Bug 500431 part 1 - Move property cache code to jspropertycache{.h,.cpp,inlines.h}. r=brendan. --HG-- extra : rebase_source : f7a7bb63bc3cded9452807ecdd0b5b8e8f5b3ff6 --- js/src/Makefile.in | 3 + js/src/jscntxt.h | 1 + js/src/jsinterp.cpp | 474 +---------------------------- js/src/jsinterp.h | 209 ------------- js/src/jsinterpinlines.h | 55 ---- js/src/jspropertycache.cpp | 513 ++++++++++++++++++++++++++++++++ js/src/jspropertycache.h | 213 +++++++++++++ js/src/jspropertycacheinlines.h | 100 +++++++ js/src/jsscope.h | 3 + js/src/jstracer.cpp | 2 +- 10 files changed, 836 insertions(+), 737 deletions(-) delete mode 100644 js/src/jsinterpinlines.h create mode 100644 js/src/jspropertycache.cpp create mode 100644 js/src/jspropertycache.h create mode 100644 js/src/jspropertycacheinlines.h diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 51d6580af3f8..163650028d4b 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -147,6 +147,7 @@ CPPSRCS = \ jsopcode.cpp \ jsparse.cpp \ jsprf.cpp \ + jspropertycache.cpp \ jspropertytree.cpp \ jsregexp.cpp \ jsscan.cpp \ @@ -202,6 +203,8 @@ INSTALLED_HEADERS = \ jsotypes.h \ jsparse.h \ jsprf.h \ + jspropertycache.h \ + jspropertycacheinlines.h \ jspropertytree.h \ jsproto.tbl \ jsprvtd.h \ diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 5d6a16f0cb6c..5e04c9235404 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -55,6 +55,7 @@ #include "jshashtable.h" #include "jsinterp.h" #include "jsobj.h" +#include "jspropertycache.h" #include "jspropertytree.h" #include "jsprvtd.h" #include "jspubtd.h" diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 8c0fe9b27bad..2a3a6c4b9728 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -65,6 +65,7 @@ #include "jsnum.h" #include "jsobj.h" #include "jsopcode.h" +#include "jspropertycache.h" #include "jsscan.h" #include "jsscope.h" #include "jsscript.h" @@ -75,7 +76,7 @@ #include "jsvector.h" #include "jsatominlines.h" -#include "jsinterpinlines.h" +#include "jspropertycacheinlines.h" #include "jsobjinlines.h" #include "jsscopeinlines.h" #include "jsscriptinlines.h" @@ -96,477 +97,6 @@ using namespace js; /* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */ #if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___ -JS_REQUIRES_STACK JSPropCacheEntry * -js_FillPropertyCache(JSContext *cx, JSObject *obj, - uintN scopeIndex, uintN protoIndex, JSObject *pobj, - JSScopeProperty *sprop, JSBool adding) -{ - JSPropertyCache *cache; - jsbytecode *pc; - JSScope *scope; - jsuword kshape, vshape; - JSOp op; - const JSCodeSpec *cs; - jsuword vword; - JSPropCacheEntry *entry; - - JS_ASSERT(!cx->runtime->gcRunning); - cache = &JS_PROPERTY_CACHE(cx); - - /* FIXME bug 489098: consider enabling the property cache for eval. */ - if (js_IsPropertyCacheDisabled(cx) || (cx->fp->flags & JSFRAME_EVAL)) { - PCMETER(cache->disfills++); - return JS_NO_PROP_CACHE_FILL; - } - - /* - * Check for fill from js_SetPropertyHelper where the setter removed sprop - * from pobj's scope (via unwatch or delete, e.g.). - */ - scope = OBJ_SCOPE(pobj); - if (!scope->hasProperty(sprop)) { - PCMETER(cache->oddfills++); - return JS_NO_PROP_CACHE_FILL; - } - - /* - * Check for overdeep scope and prototype chain. Because resolve, getter, - * and setter hooks can change the prototype chain using JS_SetPrototype - * after js_LookupPropertyWithFlags has returned the nominal protoIndex, - * we have to validate protoIndex if it is non-zero. If it is zero, then - * we know thanks to the scope->hasProperty test above, combined with the - * fact that obj == pobj, that protoIndex is invariant. - * - * The scopeIndex can't be wrong. We require JS_SetParent calls to happen - * before any running script might consult a parent-linked scope chain. If - * this requirement is not satisfied, the fill in progress will never hit, - * but vcap vs. scope shape tests ensure nothing malfunctions. - */ - JS_ASSERT_IF(scopeIndex == 0 && protoIndex == 0, obj == pobj); - - if (protoIndex != 0) { - JSObject *tmp = obj; - - for (uintN i = 0; i != scopeIndex; i++) - tmp = tmp->getParent(); - JS_ASSERT(tmp != pobj); - - protoIndex = 1; - for (;;) { - tmp = tmp->getProto(); - - /* - * We cannot cache properties coming from native objects behind - * non-native ones on the prototype chain. The non-natives can - * mutate in arbitrary way without changing any shapes. - */ - if (!tmp || !OBJ_IS_NATIVE(tmp)) { - PCMETER(cache->noprotos++); - return JS_NO_PROP_CACHE_FILL; - } - if (tmp == pobj) - break; - ++protoIndex; - } - } - - if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) { - PCMETER(cache->longchains++); - return JS_NO_PROP_CACHE_FILL; - } - - /* - * Optimize the cached vword based on our parameters and the current pc's - * opcode format flags. - */ - pc = cx->fp->regs->pc; - op = js_GetOpcode(cx, cx->fp->script, pc); - cs = &js_CodeSpec[op]; - kshape = 0; - - do { - /* - * Check for a prototype "plain old method" callee computation. What - * is a plain old method? It's a function-valued property with stub - * getter, so get of a function is idempotent. - */ - if (cs->format & JOF_CALLOP) { - jsval v; - - if (sprop->isMethod()) { - /* - * A compiler-created function object, AKA a method, already - * memoized in the property tree. - */ - JS_ASSERT(scope->hasMethodBarrier()); - v = sprop->methodValue(); - JS_ASSERT(VALUE_IS_FUNCTION(cx, v)); - JS_ASSERT(v == LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)); - vword = JSVAL_OBJECT_TO_PCVAL(v); - break; - } - - if (!scope->generic() && - sprop->hasDefaultGetter() && - SPROP_HAS_VALID_SLOT(sprop, scope)) { - v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); - if (VALUE_IS_FUNCTION(cx, v)) { - /* - * Great, we have a function-valued prototype property - * where the getter is JS_PropertyStub. The type id in - * pobj's scope does not evolve with changes to property - * values, however. - * - * So here, on first cache fill for this method, we brand - * the scope with a new shape and set the JSScope::BRANDED - * flag. Once this flag is set, any property assignment - * that changes the value from or to a different function - * object will result in shape being regenerated. - */ - if (!scope->branded()) { - PCMETER(cache->brandfills++); -#ifdef DEBUG_notme - fprintf(stderr, - "branding %p (%s) for funobj %p (%s), shape %lu\n", - pobj, pobj->getClass()->name, - JSVAL_TO_OBJECT(v), - JS_GetFunctionName(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))), - OBJ_SHAPE(obj)); -#endif - if (!scope->brand(cx, sprop->slot, v)) - return JS_NO_PROP_CACHE_FILL; - } - vword = JSVAL_OBJECT_TO_PCVAL(v); - break; - } - } - } - - /* If getting a value via a stub getter, we can cache the slot. */ - if (!(cs->format & (JOF_SET | JOF_INCDEC | JOF_FOR)) && - sprop->hasDefaultGetter() && - SPROP_HAS_VALID_SLOT(sprop, scope)) { - /* Great, let's cache sprop's slot and use it on cache hit. */ - vword = SLOT_TO_PCVAL(sprop->slot); - } else { - /* Best we can do is to cache sprop (still a nice speedup). */ - vword = SPROP_TO_PCVAL(sprop); - if (adding && - sprop == scope->lastProperty() && - scope->shape == sprop->shape) { - /* - * Our caller added a new property. We also know that a setter - * that js_NativeSet could have run has not mutated the scope, - * so the added property is still the last one added, and the - * scope is not branded. - * - * We want to cache under scope's shape before the property - * addition to bias for the case when the mutator opcode - * always adds the same property. This allows us to optimize - * periodic execution of object initializers or other explicit - * initialization sequences such as - * - * obj = {}; obj.x = 1; obj.y = 2; - * - * We assume that on average the win from this optimization is - * greater than the cost of an extra mismatch per loop owing to - * the bias for the following case: - * - * obj = {}; ... for (...) { ... obj.x = ... } - * - * On the first iteration of such a for loop, JSOP_SETPROP - * fills the cache with the shape of the newly created object - * obj, not the shape of obj after obj.x has been assigned. - * That mismatches obj's shape on the second iteration. Note - * that on the third and subsequent iterations the cache will - * be hit because the shape is no longer updated. - */ - JS_ASSERT(!scope->isSharedEmpty()); - if (sprop->parent) { - kshape = sprop->parent->shape; - } else { - /* - * If obj had its own empty scope before, with a unique - * shape, that is lost. Here we only attempt to find a - * matching empty scope. In unusual cases involving - * __proto__ assignment we may not find one. - */ - JSObject *proto = obj->getProto(); - if (!proto || !OBJ_IS_NATIVE(proto)) - return JS_NO_PROP_CACHE_FILL; - JSScope *protoscope = OBJ_SCOPE(proto); - if (!protoscope->emptyScope || - protoscope->emptyScope->clasp != obj->getClass()) { - return JS_NO_PROP_CACHE_FILL; - } - kshape = protoscope->emptyScope->shape; - } - - /* - * When adding we predict no prototype object will later gain a - * readonly property or setter. - */ - vshape = cx->runtime->protoHazardShape; - } - } - } while (0); - - if (kshape == 0) { - kshape = OBJ_SHAPE(obj); - vshape = scope->shape; - } - JS_ASSERT(kshape < SHAPE_OVERFLOW_BIT); - - if (obj == pobj) { - JS_ASSERT(scopeIndex == 0 && protoIndex == 0); - } else { -#ifdef DEBUG - if (scopeIndex == 0) { - JS_ASSERT(protoIndex != 0); - JS_ASSERT((protoIndex == 1) == (obj->getProto() == pobj)); - } -#endif - - if (scopeIndex != 0 || protoIndex != 1) { - /* - * Make sure that a later shadowing assignment will enter - * PurgeProtoChain and invalidate this entry, bug 479198. - * - * This is thread-safe even though obj is not locked. Only the - * DELEGATE bit of obj->classword can change at runtime, given that - * obj is native; and the bit is only set, never cleared. And on - * platforms where another CPU can fail to see this write, it's OK - * because the property cache and JIT cache are thread-local. - */ - obj->setDelegate(); - } - } - JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); - - entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)]; - PCMETER(PCVAL_IS_NULL(entry->vword) || cache->recycles++); - entry->kpc = pc; - entry->kshape = kshape; - entry->vcap = PCVCAP_MAKE(vshape, scopeIndex, protoIndex); - entry->vword = vword; - - cache->empty = JS_FALSE; - PCMETER(cache->fills++); - - /* - * The modfills counter is not exact. It increases if a getter or setter - * recurse into the interpreter. - */ - PCMETER(entry == cache->pctestentry || cache->modfills++); - PCMETER(cache->pctestentry = NULL); - return entry; -} - -static inline JSAtom * -GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs) -{ - if (op == JSOP_LENGTH) - return cx->runtime->atomState.lengthAtom; - - ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; - JSAtom *atom; - GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); - return atom; -} - -JS_REQUIRES_STACK JSAtom * -js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, - JSObject **objp, JSObject **pobjp, - JSPropCacheEntry *entry) -{ - JSObject *obj, *pobj, *tmp; - uint32 vcap; - - JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code) - < cx->fp->script->length); - - JSOp op = js_GetOpcode(cx, cx->fp->script, pc); - const JSCodeSpec &cs = js_CodeSpec[op]; - - obj = *objp; - JS_ASSERT(OBJ_IS_NATIVE(obj)); - vcap = entry->vcap; - - if (entry->kpc != pc) { - PCMETER(JS_PROPERTY_CACHE(cx).kpcmisses++); - - JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); -#ifdef DEBUG_notme - fprintf(stderr, - "id miss for %s from %s:%u" - " (pc %u, kpc %u, kshape %u, shape %u)\n", - js_AtomToPrintableString(cx, atom), - cx->fp->script->filename, - js_PCToLineNumber(cx, cx->fp->script, pc), - pc - cx->fp->script->code, - entry->kpc - cx->fp->script->code, - entry->kshape, - OBJ_SHAPE(obj)); - js_Disassemble1(cx, cx->fp->script, pc, - pc - cx->fp->script->code, - JS_FALSE, stderr); -#endif - - return atom; - } - - if (entry->kshape != OBJ_SHAPE(obj)) { - PCMETER(JS_PROPERTY_CACHE(cx).kshapemisses++); - return GetAtomFromBytecode(cx, pc, op, cs); - } - - /* - * PROPERTY_CACHE_TEST handles only the direct and immediate-prototype hit - * cases, all others go here. We could embed the target object in the cache - * entry but then entry size would be 5 words. Instead we traverse chains. - */ - pobj = obj; - - if (JOF_MODE(cs.format) == JOF_NAME) { - while (vcap & (PCVCAP_SCOPEMASK << PCVCAP_PROTOBITS)) { - tmp = pobj->getParent(); - if (!tmp || !OBJ_IS_NATIVE(tmp)) - break; - pobj = tmp; - vcap -= PCVCAP_PROTOSIZE; - } - - *objp = pobj; - } - - while (vcap & PCVCAP_PROTOMASK) { - tmp = pobj->getProto(); - if (!tmp || !OBJ_IS_NATIVE(tmp)) - break; - pobj = tmp; - --vcap; - } - - if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(vcap))) { -#ifdef DEBUG - JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); - jsid id = ATOM_TO_JSID(atom); - - id = js_CheckForStringIndex(id); - JS_ASSERT(OBJ_SCOPE(pobj)->lookup(id)); - JS_ASSERT_IF(OBJ_SCOPE(pobj)->object, OBJ_SCOPE(pobj)->object == pobj); -#endif - *pobjp = pobj; - return NULL; - } - - PCMETER(JS_PROPERTY_CACHE(cx).vcapmisses++); - return GetAtomFromBytecode(cx, pc, op, cs); -} - -#ifdef DEBUG -#define ASSERT_CACHE_IS_EMPTY(cache) \ - JS_BEGIN_MACRO \ - JSPropertyCache *cache_ = (cache); \ - uintN i_; \ - JS_ASSERT(cache_->empty); \ - for (i_ = 0; i_ < PROPERTY_CACHE_SIZE; i_++) { \ - JS_ASSERT(!cache_->table[i_].kpc); \ - JS_ASSERT(!cache_->table[i_].kshape); \ - JS_ASSERT(!cache_->table[i_].vcap); \ - JS_ASSERT(!cache_->table[i_].vword); \ - } \ - JS_END_MACRO -#else -#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0) -#endif - -JS_STATIC_ASSERT(PCVAL_NULL == 0); - -void -js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) -{ - if (cache->empty) { - ASSERT_CACHE_IS_EMPTY(cache); - return; - } - - PodArrayZero(cache->table); - cache->empty = JS_TRUE; - -#ifdef JS_PROPERTY_CACHE_METERING - { static FILE *fp; - if (!fp) - fp = fopen("/tmp/propcache.stats", "w"); - if (fp) { - fputs("Property cache stats for ", fp); -#ifdef JS_THREADSAFE - fprintf(fp, "thread %lu, ", (unsigned long) cx->thread->id); -#endif - fprintf(fp, "GC %u\n", cx->runtime->gcNumber); - -# define P(mem) fprintf(fp, "%11s %10lu\n", #mem, (unsigned long)cache->mem) - P(fills); - P(nofills); - P(rofills); - P(disfills); - P(oddfills); - P(modfills); - P(brandfills); - P(noprotos); - P(longchains); - P(recycles); - P(tests); - P(pchits); - P(protopchits); - P(initests); - P(inipchits); - P(inipcmisses); - P(settests); - P(addpchits); - P(setpchits); - P(setpcmisses); - P(setmisses); - P(kpcmisses); - P(kshapemisses); - P(vcapmisses); - P(misses); - P(flushes); - P(pcpurges); -# undef P - - fprintf(fp, "hit rates: pc %g%% (proto %g%%), set %g%%, ini %g%%, full %g%%\n", - (100. * cache->pchits) / cache->tests, - (100. * cache->protopchits) / cache->tests, - (100. * (cache->addpchits + cache->setpchits)) - / cache->settests, - (100. * cache->inipchits) / cache->initests, - (100. * (cache->tests - cache->misses)) / cache->tests); - fflush(fp); - } - } -#endif - - PCMETER(cache->flushes++); -} - -void -js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script) -{ - JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); - - for (JSPropCacheEntry *entry = cache->table; - entry < cache->table + PROPERTY_CACHE_SIZE; - entry++) { - if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { - entry->kpc = NULL; -#ifdef DEBUG - entry->kshape = entry->vcap = entry->vword = 0; -#endif - } - } -} - /* * Check if the current arena has enough space to fit nslots after sp and, if * so, reserve the necessary space. diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index e60c3bcf9a3f..12016d72bb73 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -226,215 +226,6 @@ typedef struct JSInlineFrame { #define JSFRAME_SPECIAL (JSFRAME_DEBUGGER | JSFRAME_EVAL) -/* - * Property cache with structurally typed capabilities for invalidation, for - * polymorphic callsite method/get/set speedups. For details, see - * . - */ -#define PROPERTY_CACHE_LOG2 12 -#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) -#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2) - -/* - * Add kshape rather than xor it to avoid collisions between nearby bytecode - * that are evolving an object by setting successive properties, incrementing - * the object's scope->shape on each set. - */ -#define PROPERTY_CACHE_HASH(pc,kshape) \ - (((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ - PROPERTY_CACHE_MASK) - -/* - * Property cache value capability macros. - */ -#define PCVCAP_PROTOBITS 4 -#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS) -#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS) - -#define PCVCAP_SCOPEBITS 4 -#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS) -#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS) - -#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS) -#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS) -#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK) - -#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \ - ((s) << PCVCAP_PROTOBITS) | \ - (p)) -#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS) - -#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) - -struct JSPropCacheEntry { - jsbytecode *kpc; /* pc of cache-testing bytecode */ - jsuword kshape; /* shape of direct (key) object */ - jsuword vcap; /* value capability, see above */ - jsuword vword; /* value word, see PCVAL_* below */ - - bool adding() const { - return PCVCAP_TAG(vcap) == 0 && kshape != PCVCAP_SHAPE(vcap); - } - - bool directHit() const { - return PCVCAP_TAG(vcap) == 0 && kshape == PCVCAP_SHAPE(vcap); - } - - static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape); -}; - -/* - * Special value for functions returning JSPropCacheEntry * to distinguish - * between failure and no no-cache-fill cases. - */ -#define JS_NO_PROP_CACHE_FILL ((JSPropCacheEntry *) NULL + 1) - -#if defined DEBUG_brendan || defined DEBUG_brendaneich -#define JS_PROPERTY_CACHE_METERING 1 -#endif - -typedef struct JSPropertyCache { - JSPropCacheEntry table[PROPERTY_CACHE_SIZE]; - JSBool empty; -#ifdef JS_PROPERTY_CACHE_METERING - JSPropCacheEntry *pctestentry; /* entry of the last PC-based test */ - uint32 fills; /* number of cache entry fills */ - uint32 nofills; /* couldn't fill (e.g. default get) */ - uint32 rofills; /* set on read-only prop can't fill */ - uint32 disfills; /* fill attempts on disabled cache */ - uint32 oddfills; /* fill attempt after setter deleted */ - uint32 modfills; /* fill that rehashed to a new entry */ - uint32 brandfills; /* scope brandings to type structural - method fills */ - uint32 noprotos; /* resolve-returned non-proto pobj */ - uint32 longchains; /* overlong scope and/or proto chain */ - uint32 recycles; /* cache entries recycled by fills */ - uint32 tests; /* cache probes */ - uint32 pchits; /* fast-path polymorphic op hits */ - uint32 protopchits; /* pchits hitting immediate prototype */ - uint32 initests; /* cache probes from JSOP_INITPROP */ - uint32 inipchits; /* init'ing next property pchit case */ - uint32 inipcmisses; /* init'ing next property pc misses */ - uint32 settests; /* cache probes from JOF_SET opcodes */ - uint32 addpchits; /* adding next property pchit case */ - uint32 setpchits; /* setting existing property pchit */ - uint32 setpcmisses; /* setting/adding property pc misses */ - uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */ - uint32 kpcmisses; /* slow-path key id == atom misses */ - uint32 kshapemisses; /* slow-path key object misses */ - uint32 vcapmisses; /* value capability misses */ - uint32 misses; /* cache misses */ - uint32 flushes; /* cache flushes */ - uint32 pcpurges; /* shadowing purges on proto chain */ -# define PCMETER(x) x -#else -# define PCMETER(x) ((void)0) -#endif -} JSPropertyCache; - -/* - * Property cache value tagging/untagging macros. - */ -#define PCVAL_OBJECT 0 -#define PCVAL_SLOT 1 -#define PCVAL_SPROP 2 - -#define PCVAL_TAGBITS 2 -#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS) -#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK) -#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK) -#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t)) - -#define PCVAL_NULL 0 -#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL) - -#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT) -#define PCVAL_TO_OBJECT(v) ((JSObject *) (v)) -#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj)) - -#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)) -#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)) - -#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT) -#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1) -#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT) - -#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP) -#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) -#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) - -/* - * Fill property cache entry for key cx->fp->pc, optimized value word computed - * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), - * 4-bit scopeIndex, and 4-bit protoIndex. - * - * Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not - * possible. - */ -extern JS_REQUIRES_STACK JSPropCacheEntry * -js_FillPropertyCache(JSContext *cx, JSObject *obj, - uintN scopeIndex, uintN protoIndex, JSObject *pobj, - JSScopeProperty *sprop, JSBool adding = false); - -/* - * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the - * fast path in js_Interpret, so it makes "just-so" restrictions on parameters, - * e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode - * opcodes, obj must not be changed because of a cache miss. - * - * On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the - * scope chain element in which the property was found, pobj is locked, and - * entry is valid. If atom is non-null then no object is locked but entry is - * still set correctly for use, e.g., by js_FillPropertyCache and atom should - * be used as the id to find. - * - * We must lock pobj on a hit in order to close races with threads that might - * be deleting a property from its scope, or otherwise invalidating property - * caches (on all threads) by re-generating scope->shape. - */ -#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ - do { \ - JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ - uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ - entry = &cache_->table[PROPERTY_CACHE_HASH(pc, kshape_)]; \ - PCMETER(cache_->pctestentry = entry); \ - PCMETER(cache_->tests++); \ - JS_ASSERT(&obj != &pobj); \ - if (entry->kpc == pc && entry->kshape == kshape_) { \ - JSObject *tmp_; \ - pobj = obj; \ - if (PCVCAP_TAG(entry->vcap) == 1 && \ - (tmp_ = pobj->getProto()) != NULL) { \ - pobj = tmp_; \ - } \ - \ - if (JSPropCacheEntry::matchShape(cx, pobj, \ - PCVCAP_SHAPE(entry->vcap))) { \ - PCMETER(cache_->pchits++); \ - PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ - atom = NULL; \ - break; \ - } \ - } \ - atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); \ - if (atom) \ - PCMETER(cache_->misses++); \ - } while (0) - -extern JS_REQUIRES_STACK JSAtom * -js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, - JSObject **objp, JSObject **pobjp, - JSPropCacheEntry *entry); - -/* The property cache does not need a destructor. */ -#define js_FinishPropertyCache(cache) ((void) 0) - -extern void -js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache); - -extern void -js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script); - /* * Interpreter stack arena-pool alloc and free functions. */ diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h deleted file mode 100644 index d431b6331bce..000000000000 --- a/js/src/jsinterpinlines.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=99: - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Igor Bukanov - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jsinterpinlines_h___ -#define jsinterpinlines_h___ - -#include "jsinterp.h" -#include "jslock.h" -#include "jsscope.h" - -/* static */ inline bool -JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape) -{ - return CX_OWNS_OBJECT_TITLE(cx, obj) && OBJ_SHAPE(obj) == shape; -} - -#endif /* jsinterpinlines_h___ */ diff --git a/js/src/jspropertycache.cpp b/js/src/jspropertycache.cpp new file mode 100644 index 000000000000..baa78787743d --- /dev/null +++ b/js/src/jspropertycache.cpp @@ -0,0 +1,513 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jspropertycache.h" +#include "jspropertycacheinlines.h" +#include "jscntxt.h" + +using namespace js; + +JS_REQUIRES_STACK JSPropCacheEntry * +js_FillPropertyCache(JSContext *cx, JSObject *obj, + uintN scopeIndex, uintN protoIndex, JSObject *pobj, + JSScopeProperty *sprop, JSBool adding) +{ + JSPropertyCache *cache; + jsbytecode *pc; + JSScope *scope; + jsuword kshape, vshape; + JSOp op; + const JSCodeSpec *cs; + jsuword vword; + JSPropCacheEntry *entry; + + JS_ASSERT(!cx->runtime->gcRunning); + cache = &JS_PROPERTY_CACHE(cx); + + /* FIXME bug 489098: consider enabling the property cache for eval. */ + if (js_IsPropertyCacheDisabled(cx) || (cx->fp->flags & JSFRAME_EVAL)) { + PCMETER(cache->disfills++); + return JS_NO_PROP_CACHE_FILL; + } + + /* + * Check for fill from js_SetPropertyHelper where the setter removed sprop + * from pobj's scope (via unwatch or delete, e.g.). + */ + scope = OBJ_SCOPE(pobj); + if (!scope->hasProperty(sprop)) { + PCMETER(cache->oddfills++); + return JS_NO_PROP_CACHE_FILL; + } + + /* + * Check for overdeep scope and prototype chain. Because resolve, getter, + * and setter hooks can change the prototype chain using JS_SetPrototype + * after js_LookupPropertyWithFlags has returned the nominal protoIndex, + * we have to validate protoIndex if it is non-zero. If it is zero, then + * we know thanks to the scope->hasProperty test above, combined with the + * fact that obj == pobj, that protoIndex is invariant. + * + * The scopeIndex can't be wrong. We require JS_SetParent calls to happen + * before any running script might consult a parent-linked scope chain. If + * this requirement is not satisfied, the fill in progress will never hit, + * but vcap vs. scope shape tests ensure nothing malfunctions. + */ + JS_ASSERT_IF(scopeIndex == 0 && protoIndex == 0, obj == pobj); + + if (protoIndex != 0) { + JSObject *tmp = obj; + + for (uintN i = 0; i != scopeIndex; i++) + tmp = tmp->getParent(); + JS_ASSERT(tmp != pobj); + + protoIndex = 1; + for (;;) { + tmp = tmp->getProto(); + + /* + * We cannot cache properties coming from native objects behind + * non-native ones on the prototype chain. The non-natives can + * mutate in arbitrary way without changing any shapes. + */ + if (!tmp || !OBJ_IS_NATIVE(tmp)) { + PCMETER(cache->noprotos++); + return JS_NO_PROP_CACHE_FILL; + } + if (tmp == pobj) + break; + ++protoIndex; + } + } + + if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) { + PCMETER(cache->longchains++); + return JS_NO_PROP_CACHE_FILL; + } + + /* + * Optimize the cached vword based on our parameters and the current pc's + * opcode format flags. + */ + pc = cx->fp->regs->pc; + op = js_GetOpcode(cx, cx->fp->script, pc); + cs = &js_CodeSpec[op]; + kshape = 0; + + do { + /* + * Check for a prototype "plain old method" callee computation. What + * is a plain old method? It's a function-valued property with stub + * getter, so get of a function is idempotent. + */ + if (cs->format & JOF_CALLOP) { + jsval v; + + if (sprop->isMethod()) { + /* + * A compiler-created function object, AKA a method, already + * memoized in the property tree. + */ + JS_ASSERT(scope->hasMethodBarrier()); + v = sprop->methodValue(); + JS_ASSERT(VALUE_IS_FUNCTION(cx, v)); + JS_ASSERT(v == LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)); + vword = JSVAL_OBJECT_TO_PCVAL(v); + break; + } + + if (!scope->generic() && + sprop->hasDefaultGetter() && + SPROP_HAS_VALID_SLOT(sprop, scope)) { + v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); + if (VALUE_IS_FUNCTION(cx, v)) { + /* + * Great, we have a function-valued prototype property + * where the getter is JS_PropertyStub. The type id in + * pobj's scope does not evolve with changes to property + * values, however. + * + * So here, on first cache fill for this method, we brand + * the scope with a new shape and set the JSScope::BRANDED + * flag. Once this flag is set, any property assignment + * that changes the value from or to a different function + * object will result in shape being regenerated. + */ + if (!scope->branded()) { + PCMETER(cache->brandfills++); +#ifdef DEBUG_notme + fprintf(stderr, + "branding %p (%s) for funobj %p (%s), shape %lu\n", + pobj, pobj->getClass()->name, + JSVAL_TO_OBJECT(v), + JS_GetFunctionName(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))), + OBJ_SHAPE(obj)); +#endif + if (!scope->brand(cx, sprop->slot, v)) + return JS_NO_PROP_CACHE_FILL; + } + vword = JSVAL_OBJECT_TO_PCVAL(v); + break; + } + } + } + + /* If getting a value via a stub getter, we can cache the slot. */ + if (!(cs->format & (JOF_SET | JOF_INCDEC | JOF_FOR)) && + sprop->hasDefaultGetter() && + SPROP_HAS_VALID_SLOT(sprop, scope)) { + /* Great, let's cache sprop's slot and use it on cache hit. */ + vword = SLOT_TO_PCVAL(sprop->slot); + } else { + /* Best we can do is to cache sprop (still a nice speedup). */ + vword = SPROP_TO_PCVAL(sprop); + if (adding && + sprop == scope->lastProperty() && + scope->shape == sprop->shape) { + /* + * Our caller added a new property. We also know that a setter + * that js_NativeSet could have run has not mutated the scope, + * so the added property is still the last one added, and the + * scope is not branded. + * + * We want to cache under scope's shape before the property + * addition to bias for the case when the mutator opcode + * always adds the same property. This allows us to optimize + * periodic execution of object initializers or other explicit + * initialization sequences such as + * + * obj = {}; obj.x = 1; obj.y = 2; + * + * We assume that on average the win from this optimization is + * greater than the cost of an extra mismatch per loop owing to + * the bias for the following case: + * + * obj = {}; ... for (...) { ... obj.x = ... } + * + * On the first iteration of such a for loop, JSOP_SETPROP + * fills the cache with the shape of the newly created object + * obj, not the shape of obj after obj.x has been assigned. + * That mismatches obj's shape on the second iteration. Note + * that on the third and subsequent iterations the cache will + * be hit because the shape is no longer updated. + */ + JS_ASSERT(!scope->isSharedEmpty()); + if (sprop->parent) { + kshape = sprop->parent->shape; + } else { + /* + * If obj had its own empty scope before, with a unique + * shape, that is lost. Here we only attempt to find a + * matching empty scope. In unusual cases involving + * __proto__ assignment we may not find one. + */ + JSObject *proto = obj->getProto(); + if (!proto || !OBJ_IS_NATIVE(proto)) + return JS_NO_PROP_CACHE_FILL; + JSScope *protoscope = OBJ_SCOPE(proto); + if (!protoscope->emptyScope || + protoscope->emptyScope->clasp != obj->getClass()) { + return JS_NO_PROP_CACHE_FILL; + } + kshape = protoscope->emptyScope->shape; + } + + /* + * When adding we predict no prototype object will later gain a + * readonly property or setter. + */ + vshape = cx->runtime->protoHazardShape; + } + } + } while (0); + + if (kshape == 0) { + kshape = OBJ_SHAPE(obj); + vshape = scope->shape; + } + JS_ASSERT(kshape < SHAPE_OVERFLOW_BIT); + + if (obj == pobj) { + JS_ASSERT(scopeIndex == 0 && protoIndex == 0); + } else { +#ifdef DEBUG + if (scopeIndex == 0) { + JS_ASSERT(protoIndex != 0); + JS_ASSERT((protoIndex == 1) == (obj->getProto() == pobj)); + } +#endif + + if (scopeIndex != 0 || protoIndex != 1) { + /* + * Make sure that a later shadowing assignment will enter + * PurgeProtoChain and invalidate this entry, bug 479198. + * + * This is thread-safe even though obj is not locked. Only the + * DELEGATE bit of obj->classword can change at runtime, given that + * obj is native; and the bit is only set, never cleared. And on + * platforms where another CPU can fail to see this write, it's OK + * because the property cache and JIT cache are thread-local. + */ + obj->setDelegate(); + } + } + JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); + + entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)]; + PCMETER(PCVAL_IS_NULL(entry->vword) || cache->recycles++); + entry->kpc = pc; + entry->kshape = kshape; + entry->vcap = PCVCAP_MAKE(vshape, scopeIndex, protoIndex); + entry->vword = vword; + + cache->empty = JS_FALSE; + PCMETER(cache->fills++); + + /* + * The modfills counter is not exact. It increases if a getter or setter + * recurse into the interpreter. + */ + PCMETER(entry == cache->pctestentry || cache->modfills++); + PCMETER(cache->pctestentry = NULL); + return entry; +} + +static inline JSAtom * +GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs) +{ + if (op == JSOP_LENGTH) + return cx->runtime->atomState.lengthAtom; + + ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; + JSAtom *atom; + GET_ATOM_FROM_BYTECODE(cx->fp->script, pc, pcoff, atom); + return atom; +} + +JS_REQUIRES_STACK JSAtom * +js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, + JSObject **objp, JSObject **pobjp, + JSPropCacheEntry *entry) +{ + JSObject *obj, *pobj, *tmp; + uint32 vcap; + + JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code) + < cx->fp->script->length); + + JSOp op = js_GetOpcode(cx, cx->fp->script, pc); + const JSCodeSpec &cs = js_CodeSpec[op]; + + obj = *objp; + JS_ASSERT(OBJ_IS_NATIVE(obj)); + vcap = entry->vcap; + + if (entry->kpc != pc) { + PCMETER(JS_PROPERTY_CACHE(cx).kpcmisses++); + + JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); +#ifdef DEBUG_notme + fprintf(stderr, + "id miss for %s from %s:%u" + " (pc %u, kpc %u, kshape %u, shape %u)\n", + js_AtomToPrintableString(cx, atom), + cx->fp->script->filename, + js_PCToLineNumber(cx, cx->fp->script, pc), + pc - cx->fp->script->code, + entry->kpc - cx->fp->script->code, + entry->kshape, + OBJ_SHAPE(obj)); + js_Disassemble1(cx, cx->fp->script, pc, + pc - cx->fp->script->code, + JS_FALSE, stderr); +#endif + + return atom; + } + + if (entry->kshape != OBJ_SHAPE(obj)) { + PCMETER(JS_PROPERTY_CACHE(cx).kshapemisses++); + return GetAtomFromBytecode(cx, pc, op, cs); + } + + /* + * PROPERTY_CACHE_TEST handles only the direct and immediate-prototype hit + * cases, all others go here. We could embed the target object in the cache + * entry but then entry size would be 5 words. Instead we traverse chains. + */ + pobj = obj; + + if (JOF_MODE(cs.format) == JOF_NAME) { + while (vcap & (PCVCAP_SCOPEMASK << PCVCAP_PROTOBITS)) { + tmp = pobj->getParent(); + if (!tmp || !OBJ_IS_NATIVE(tmp)) + break; + pobj = tmp; + vcap -= PCVCAP_PROTOSIZE; + } + + *objp = pobj; + } + + while (vcap & PCVCAP_PROTOMASK) { + tmp = pobj->getProto(); + if (!tmp || !OBJ_IS_NATIVE(tmp)) + break; + pobj = tmp; + --vcap; + } + + if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(vcap))) { +#ifdef DEBUG + JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); + jsid id = ATOM_TO_JSID(atom); + + id = js_CheckForStringIndex(id); + JS_ASSERT(OBJ_SCOPE(pobj)->lookup(id)); + JS_ASSERT_IF(OBJ_SCOPE(pobj)->object, OBJ_SCOPE(pobj)->object == pobj); +#endif + *pobjp = pobj; + return NULL; + } + + PCMETER(JS_PROPERTY_CACHE(cx).vcapmisses++); + return GetAtomFromBytecode(cx, pc, op, cs); +} + +#ifdef DEBUG +#define ASSERT_CACHE_IS_EMPTY(cache) \ + JS_BEGIN_MACRO \ + JSPropertyCache *cache_ = (cache); \ + uintN i_; \ + JS_ASSERT(cache_->empty); \ + for (i_ = 0; i_ < PROPERTY_CACHE_SIZE; i_++) { \ + JS_ASSERT(!cache_->table[i_].kpc); \ + JS_ASSERT(!cache_->table[i_].kshape); \ + JS_ASSERT(!cache_->table[i_].vcap); \ + JS_ASSERT(!cache_->table[i_].vword); \ + } \ + JS_END_MACRO +#else +#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0) +#endif + +JS_STATIC_ASSERT(PCVAL_NULL == 0); + +void +js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) +{ + if (cache->empty) { + ASSERT_CACHE_IS_EMPTY(cache); + return; + } + + PodArrayZero(cache->table); + cache->empty = JS_TRUE; + +#ifdef JS_PROPERTY_CACHE_METERING + { static FILE *fp; + if (!fp) + fp = fopen("/tmp/propcache.stats", "w"); + if (fp) { + fputs("Property cache stats for ", fp); +#ifdef JS_THREADSAFE + fprintf(fp, "thread %lu, ", (unsigned long) cx->thread->id); +#endif + fprintf(fp, "GC %u\n", cx->runtime->gcNumber); + +# define P(mem) fprintf(fp, "%11s %10lu\n", #mem, (unsigned long)cache->mem) + P(fills); + P(nofills); + P(rofills); + P(disfills); + P(oddfills); + P(modfills); + P(brandfills); + P(noprotos); + P(longchains); + P(recycles); + P(tests); + P(pchits); + P(protopchits); + P(initests); + P(inipchits); + P(inipcmisses); + P(settests); + P(addpchits); + P(setpchits); + P(setpcmisses); + P(setmisses); + P(kpcmisses); + P(kshapemisses); + P(vcapmisses); + P(misses); + P(flushes); + P(pcpurges); +# undef P + + fprintf(fp, "hit rates: pc %g%% (proto %g%%), set %g%%, ini %g%%, full %g%%\n", + (100. * cache->pchits) / cache->tests, + (100. * cache->protopchits) / cache->tests, + (100. * (cache->addpchits + cache->setpchits)) + / cache->settests, + (100. * cache->inipchits) / cache->initests, + (100. * (cache->tests - cache->misses)) / cache->tests); + fflush(fp); + } + } +#endif + + PCMETER(cache->flushes++); +} + +void +js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script) +{ + JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); + + for (JSPropCacheEntry *entry = cache->table; + entry < cache->table + PROPERTY_CACHE_SIZE; + entry++) { + if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { + entry->kpc = NULL; +#ifdef DEBUG + entry->kshape = entry->vcap = entry->vword = 0; +#endif + } + } +} diff --git a/js/src/jspropertycache.h b/js/src/jspropertycache.h new file mode 100644 index 000000000000..50b07f57fa1d --- /dev/null +++ b/js/src/jspropertycache.h @@ -0,0 +1,213 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jspropertycache_h___ +#define jspropertycache_h___ + +#include "jsapi.h" +#include "jsprvtd.h" +#include "jstypes.h" + +JS_BEGIN_EXTERN_C + +/* + * Property cache with structurally typed capabilities for invalidation, for + * polymorphic callsite method/get/set speedups. For details, see + * . + */ +#define PROPERTY_CACHE_LOG2 12 +#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) +#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2) + +/* + * Add kshape rather than xor it to avoid collisions between nearby bytecode + * that are evolving an object by setting successive properties, incrementing + * the object's scope->shape on each set. + */ +#define PROPERTY_CACHE_HASH(pc,kshape) \ + (((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ + PROPERTY_CACHE_MASK) + +/* + * Property cache value capability macros. + */ +#define PCVCAP_PROTOBITS 4 +#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS) +#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS) + +#define PCVCAP_SCOPEBITS 4 +#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS) +#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS) + +#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS) +#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS) +#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK) + +#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \ + ((s) << PCVCAP_PROTOBITS) | \ + (p)) +#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS) + +#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) + +struct JSPropCacheEntry { + jsbytecode *kpc; /* pc of cache-testing bytecode */ + jsuword kshape; /* shape of direct (key) object */ + jsuword vcap; /* value capability, see above */ + jsuword vword; /* value word, see PCVAL_* below */ + + bool adding() const { + return PCVCAP_TAG(vcap) == 0 && kshape != PCVCAP_SHAPE(vcap); + } + + bool directHit() const { + return PCVCAP_TAG(vcap) == 0 && kshape == PCVCAP_SHAPE(vcap); + } + + static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape); +}; + +/* + * Special value for functions returning JSPropCacheEntry * to distinguish + * between failure and no no-cache-fill cases. + */ +#define JS_NO_PROP_CACHE_FILL ((JSPropCacheEntry *) NULL + 1) + +#if defined DEBUG_brendan || defined DEBUG_brendaneich +#define JS_PROPERTY_CACHE_METERING 1 +#endif + +typedef struct JSPropertyCache { + JSPropCacheEntry table[PROPERTY_CACHE_SIZE]; + JSBool empty; +#ifdef JS_PROPERTY_CACHE_METERING + JSPropCacheEntry *pctestentry; /* entry of the last PC-based test */ + uint32 fills; /* number of cache entry fills */ + uint32 nofills; /* couldn't fill (e.g. default get) */ + uint32 rofills; /* set on read-only prop can't fill */ + uint32 disfills; /* fill attempts on disabled cache */ + uint32 oddfills; /* fill attempt after setter deleted */ + uint32 modfills; /* fill that rehashed to a new entry */ + uint32 brandfills; /* scope brandings to type structural + method fills */ + uint32 noprotos; /* resolve-returned non-proto pobj */ + uint32 longchains; /* overlong scope and/or proto chain */ + uint32 recycles; /* cache entries recycled by fills */ + uint32 tests; /* cache probes */ + uint32 pchits; /* fast-path polymorphic op hits */ + uint32 protopchits; /* pchits hitting immediate prototype */ + uint32 initests; /* cache probes from JSOP_INITPROP */ + uint32 inipchits; /* init'ing next property pchit case */ + uint32 inipcmisses; /* init'ing next property pc misses */ + uint32 settests; /* cache probes from JOF_SET opcodes */ + uint32 addpchits; /* adding next property pchit case */ + uint32 setpchits; /* setting existing property pchit */ + uint32 setpcmisses; /* setting/adding property pc misses */ + uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */ + uint32 kpcmisses; /* slow-path key id == atom misses */ + uint32 kshapemisses; /* slow-path key object misses */ + uint32 vcapmisses; /* value capability misses */ + uint32 misses; /* cache misses */ + uint32 flushes; /* cache flushes */ + uint32 pcpurges; /* shadowing purges on proto chain */ +# define PCMETER(x) x +#else +# define PCMETER(x) ((void)0) +#endif +} JSPropertyCache; + +/* + * Property cache value tagging/untagging macros. + */ +#define PCVAL_OBJECT 0 +#define PCVAL_SLOT 1 +#define PCVAL_SPROP 2 + +#define PCVAL_TAGBITS 2 +#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS) +#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK) +#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK) +#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t)) + +#define PCVAL_NULL 0 +#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL) + +#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT) +#define PCVAL_TO_OBJECT(v) ((JSObject *) (v)) +#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj)) + +#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)) +#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)) + +#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT) +#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1) +#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT) + +#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP) +#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) +#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) + +/* + * Fill property cache entry for key cx->fp->pc, optimized value word computed + * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), + * 4-bit scopeIndex, and 4-bit protoIndex. + * + * Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not + * possible. + */ +extern JS_REQUIRES_STACK JSPropCacheEntry * +js_FillPropertyCache(JSContext *cx, JSObject *obj, + uintN scopeIndex, uintN protoIndex, JSObject *pobj, + JSScopeProperty *sprop, JSBool adding = false); + +extern JS_REQUIRES_STACK JSAtom * +js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, + JSObject **objp, JSObject **pobjp, + JSPropCacheEntry *entry); + +/* The property cache does not need a destructor. */ +#define js_FinishPropertyCache(cache) ((void) 0) + +extern void +js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache); + +extern void +js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script); + +JS_END_EXTERN_C + +#endif /* jspropertycache_h___ */ diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h new file mode 100644 index 000000000000..8b3188a3bcca --- /dev/null +++ b/js/src/jspropertycacheinlines.h @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jspropertycacheinlines_h___ +#define jspropertycacheinlines_h___ + +#include "jsinterp.h" +#include "jslock.h" +#include "jsscope.h" + +/* static */ inline bool +JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape) +{ + return CX_OWNS_OBJECT_TITLE(cx, obj) && OBJ_SHAPE(obj) == shape; +} + +/* + * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the + * fast path in js_Interpret, so it makes "just-so" restrictions on parameters, + * e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode + * opcodes, obj must not be changed because of a cache miss. + * + * On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the + * scope chain element in which the property was found, pobj is locked, and + * entry is valid. If atom is non-null then no object is locked but entry is + * still set correctly for use, e.g., by js_FillPropertyCache and atom should + * be used as the id to find. + * + * We must lock pobj on a hit in order to close races with threads that might + * be deleting a property from its scope, or otherwise invalidating property + * caches (on all threads) by re-generating scope->shape. + */ +#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ + do { \ + JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ + uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ + entry = &cache_->table[PROPERTY_CACHE_HASH(pc, kshape_)]; \ + PCMETER(cache_->pctestentry = entry); \ + PCMETER(cache_->tests++); \ + JS_ASSERT(&obj != &pobj); \ + if (entry->kpc == pc && entry->kshape == kshape_) { \ + JSObject *tmp_; \ + pobj = obj; \ + if (PCVCAP_TAG(entry->vcap) == 1 && \ + (tmp_ = pobj->getProto()) != NULL) { \ + pobj = tmp_; \ + } \ + \ + if (JSPropCacheEntry::matchShape(cx, pobj, \ + PCVCAP_SHAPE(entry->vcap))) { \ + PCMETER(cache_->pchits++); \ + PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ + atom = NULL; \ + break; \ + } \ + } \ + atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); \ + if (atom) \ + PCMETER(cache_->misses++); \ + } while (0) + +#endif /* jspropertycacheinlines_h___ */ diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 03b6388b784f..e696f4a4d745 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -48,10 +48,13 @@ #endif #include "jstypes.h" +#include "jscntxt.h" #include "jslock.h" #include "jsobj.h" #include "jsprvtd.h" #include "jspubtd.h" +#include "jspropertycache.h" +#include "jspropertytree.h" #ifdef _MSC_VER #pragma warning(push) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 4cd58651741b..6a0b9ccb2f6b 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -78,7 +78,7 @@ #include "jstypedarray.h" #include "jsatominlines.h" -#include "jsinterpinlines.h" +#include "jspropertycacheinlines.h" #include "jsobjinlines.h" #include "jsscopeinlines.h" #include "jsscriptinlines.h" From 515fa01dde8d146ef11472fd8eda14d88ecb7fa9 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 24 Mar 2010 16:16:45 -0500 Subject: [PATCH 131/213] Bug 500431 part 2 - Replace macros with inline functions in jspropertycache. r=brendan. --HG-- extra : rebase_source : efb0e75798145ff1bb64607262345aea67a51290 --- js/src/jspropertycache.h | 115 +++++++++++++++++++------------- js/src/jspropertycacheinlines.h | 69 +++++++++---------- 2 files changed, 105 insertions(+), 79 deletions(-) diff --git a/js/src/jspropertycache.h b/js/src/jspropertycache.h index 50b07f57fa1d..adab8e641e02 100644 --- a/js/src/jspropertycache.h +++ b/js/src/jspropertycache.h @@ -49,42 +49,63 @@ JS_BEGIN_EXTERN_C * polymorphic callsite method/get/set speedups. For details, see * . */ -#define PROPERTY_CACHE_LOG2 12 -#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) -#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2) + +enum { + PROPERTY_CACHE_LOG2 = 12, + PROPERTY_CACHE_SIZE = JS_BIT(PROPERTY_CACHE_LOG2), + PROPERTY_CACHE_MASK = JS_BITMASK(PROPERTY_CACHE_LOG2) +}; /* * Add kshape rather than xor it to avoid collisions between nearby bytecode * that are evolving an object by setting successive properties, incrementing * the object's scope->shape on each set. */ -#define PROPERTY_CACHE_HASH(pc,kshape) \ - (((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ - PROPERTY_CACHE_MASK) +inline jsuword +PROPERTY_CACHE_HASH(jsbytecode *pc, jsuword kshape) +{ + return ((((jsuword(pc) >> PROPERTY_CACHE_LOG2) ^ jsuword(pc)) + kshape) & PROPERTY_CACHE_MASK); +} -/* - * Property cache value capability macros. - */ -#define PCVCAP_PROTOBITS 4 -#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS) -#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS) +/* Property cache value capabilities. */ +enum { + PCVCAP_PROTOBITS = 4, + PCVCAP_PROTOSIZE = JS_BIT(PCVCAP_PROTOBITS), + PCVCAP_PROTOMASK = JS_BITMASK(PCVCAP_PROTOBITS), -#define PCVCAP_SCOPEBITS 4 -#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS) -#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS) + PCVCAP_SCOPEBITS = 4, + PCVCAP_SCOPESIZE = JS_BIT(PCVCAP_SCOPEBITS), + PCVCAP_SCOPEMASK = JS_BITMASK(PCVCAP_SCOPEBITS), -#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS) -#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS) -#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK) + PCVCAP_TAGBITS = PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS, + PCVCAP_TAGMASK = JS_BITMASK(PCVCAP_TAGBITS) +}; -#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \ - ((s) << PCVCAP_PROTOBITS) | \ - (p)) -#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS) +const uint32 SHAPE_OVERFLOW_BIT = JS_BIT(32 - PCVCAP_TAGBITS); -#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) +inline jsuword +PCVCAP_TAG(jsuword t) +{ + return t & PCVCAP_TAGMASK; +} -struct JSPropCacheEntry { +inline jsuword +PCVCAP_MAKE(uint32 t, unsigned int s, unsigned int p) +{ + JS_ASSERT(t < SHAPE_OVERFLOW_BIT); + JS_ASSERT(s <= PCVCAP_SCOPEMASK); + JS_ASSERT(p <= PCVCAP_PROTOMASK); + return (t << PCVCAP_TAGBITS) | (s << PCVCAP_PROTOBITS) | p; +} + +inline uint32 +PCVCAP_SHAPE(jsuword t) +{ + return t >> PCVCAP_TAGBITS; +} + +struct JSPropCacheEntry +{ jsbytecode *kpc; /* pc of cache-testing bytecode */ jsuword kshape; /* shape of direct (key) object */ jsuword vcap; /* value capability, see above */ @@ -153,33 +174,37 @@ typedef struct JSPropertyCache { /* * Property cache value tagging/untagging macros. */ -#define PCVAL_OBJECT 0 -#define PCVAL_SLOT 1 -#define PCVAL_SPROP 2 +enum { + PCVAL_OBJECT = 0, + PCVAL_SLOT = 1, + PCVAL_SPROP = 2, -#define PCVAL_TAGBITS 2 -#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS) -#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK) -#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK) -#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t)) + PCVAL_TAGBITS = 2, + PCVAL_TAGMASK = JS_BITMASK(PCVAL_TAGBITS), -#define PCVAL_NULL 0 -#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL) + PCVAL_NULL = 0 +}; -#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT) -#define PCVAL_TO_OBJECT(v) ((JSObject *) (v)) -#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj)) +inline jsuword PCVAL_TAG(jsuword v) { return v & PCVAL_TAGMASK; } +inline jsuword PCVAL_CLRTAG(jsuword v) { return v & ~jsuword(PCVAL_TAGMASK); } +inline jsuword PCVAL_SETTAG(jsuword v, jsuword t) { return v | t; } -#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)) -#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)) +inline bool PCVAL_IS_NULL(jsuword v) { return v == PCVAL_NULL; } -#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT) -#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1) -#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT) +inline bool PCVAL_IS_OBJECT(jsuword v) { return PCVAL_TAG(v) == PCVAL_OBJECT; } +inline JSObject *PCVAL_TO_OBJECT(jsuword v) { JS_ASSERT(PCVAL_IS_OBJECT(v)); return (JSObject *) v; } +inline jsuword OBJECT_TO_PCVAL(JSObject *obj) { return jsuword(obj); } -#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP) -#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) -#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) +inline jsval PCVAL_OBJECT_TO_JSVAL(jsuword v) { return OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)); } +inline jsuword JSVAL_OBJECT_TO_PCVAL(jsval v) { return OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)); } + +inline bool PCVAL_IS_SLOT(jsuword v) { return v & PCVAL_SLOT; } +inline jsuint PCVAL_TO_SLOT(jsuword v) { JS_ASSERT(PCVAL_IS_SLOT(v)); return jsuint(v) >> 1; } +inline jsuword SLOT_TO_PCVAL(jsuint i) { return (jsuword(i) << 1) | PCVAL_SLOT; } + +inline bool PCVAL_IS_SPROP(jsuword v) { return PCVAL_TAG(v) == PCVAL_SPROP; } +inline JSScopeProperty *PCVAL_TO_SPROP(jsuword v) { JS_ASSERT(PCVAL_IS_SPROP(v)); return (JSScopeProperty *) PCVAL_CLRTAG(v); } +inline jsuword SPROP_TO_PCVAL(JSScopeProperty *sprop) { return PCVAL_SETTAG(jsuword(sprop), PCVAL_SPROP); } /* * Fill property cache entry for key cx->fp->pc, optimized value word computed diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h index 8b3188a3bcca..d6011b3f8ab7 100644 --- a/js/src/jspropertycacheinlines.h +++ b/js/src/jspropertycacheinlines.h @@ -42,8 +42,7 @@ #ifndef jspropertycacheinlines_h___ #define jspropertycacheinlines_h___ -#include "jsinterp.h" -#include "jslock.h" +#include "jspropertycache.h" #include "jsscope.h" /* static */ inline bool @@ -53,10 +52,10 @@ JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape) } /* - * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the - * fast path in js_Interpret, so it makes "just-so" restrictions on parameters, - * e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode - * opcodes, obj must not be changed because of a cache miss. + * PROPERTY_CACHE_TEST is designed to inline the fast path in js_Interpret, so + * it makes "just-so" restrictions on parameters, e.g. pobj and obj should not + * be the same variable, since for JOF_PROP-mode opcodes, obj must not be + * changed because of a cache miss. * * On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the * scope chain element in which the property was found, pobj is locked, and @@ -68,33 +67,35 @@ JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape) * be deleting a property from its scope, or otherwise invalidating property * caches (on all threads) by re-generating scope->shape. */ -#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ - do { \ - JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ - uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ - entry = &cache_->table[PROPERTY_CACHE_HASH(pc, kshape_)]; \ - PCMETER(cache_->pctestentry = entry); \ - PCMETER(cache_->tests++); \ - JS_ASSERT(&obj != &pobj); \ - if (entry->kpc == pc && entry->kshape == kshape_) { \ - JSObject *tmp_; \ - pobj = obj; \ - if (PCVCAP_TAG(entry->vcap) == 1 && \ - (tmp_ = pobj->getProto()) != NULL) { \ - pobj = tmp_; \ - } \ - \ - if (JSPropCacheEntry::matchShape(cx, pobj, \ - PCVCAP_SHAPE(entry->vcap))) { \ - PCMETER(cache_->pchits++); \ - PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ - atom = NULL; \ - break; \ - } \ - } \ - atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); \ - if (atom) \ - PCMETER(cache_->misses++); \ - } while (0) +JS_ALWAYS_INLINE void +PROPERTY_CACHE_TEST(JSContext *cx, jsbytecode *pc, JSObject *&obj, + JSObject *&pobj, JSPropCacheEntry *&entry, JSAtom *&atom) +{ + JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); + JS_ASSERT(OBJ_IS_NATIVE(obj)); + uint32 kshape = OBJ_SHAPE(obj); + entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)]; + PCMETER(cache->pctestentry = entry); + PCMETER(cache->tests++); + JS_ASSERT(&obj != &pobj); + if (entry->kpc == pc && entry->kshape == kshape) { + JSObject *tmp; + pobj = obj; + if (PCVCAP_TAG(entry->vcap) == 1 && + (tmp = pobj->getProto()) != NULL) { + pobj = tmp; + } + + if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(entry->vcap))) { + PCMETER(cache->pchits++); + PCMETER(!PCVCAP_TAG(entry->vcap) || cache->protopchits++); + atom = NULL; + return; + } + } + atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); + if (atom) + PCMETER(cache->misses++); +} #endif /* jspropertycacheinlines_h___ */ From 39e3f58e980507d40e9f50b209e1f45b09d0871f Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Wed, 24 Mar 2010 14:40:11 -0700 Subject: [PATCH 132/213] Bug 552500: Don't bother to dynamically detect stack growth direction. r=waldo --- js/src/jscntxt.h | 7 ++----- js/src/jscpucfg.cpp | 28 +++++++++------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 1f4477bef6e3..5d6a16f0cb6c 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -2261,11 +2261,8 @@ js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; /* - * See JS_SetThreadStackLimit in jsapi.c, where we check that the stack grows - * in the expected direction. On Unix-y systems, JS_STACK_GROWTH_DIRECTION is - * computed on the build host by jscpucfg.c and written into jsautocfg.h. The - * macro is hardcoded in jscpucfg.h on Windows and Mac systems (for historical - * reasons pre-dating autoconf usage). + * See JS_SetThreadStackLimit in jsapi.c, where we check that the stack + * grows in the expected direction. */ #if JS_STACK_GROWTH_DIRECTION > 0 # define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) < (cx)->stackLimit) diff --git a/js/src/jscpucfg.cpp b/js/src/jscpucfg.cpp index c52d9b8102dd..62729dd107b1 100644 --- a/js/src/jscpucfg.cpp +++ b/js/src/jscpucfg.cpp @@ -50,24 +50,6 @@ /************************************************************************/ -#ifdef __GNUC__ -#define NS_NEVER_INLINE __attribute__((noinline)) -#else -#define NS_NEVER_INLINE -#endif - -#ifdef __SUNPRO_C -static int StackGrowthDirection(int *dummy1addr); -#pragma no_inline(StackGrowthDirection) -#endif - -static int NS_NEVER_INLINE StackGrowthDirection(int *dummy1addr) -{ - int dummy2; - - return (&dummy2 < dummy1addr) ? -1 : 1; -} - int main(int argc, char **argv) { int dummy1; @@ -185,7 +167,15 @@ int main(int argc, char **argv) #endif /* CROSS_COMPILE */ - printf("#define JS_STACK_GROWTH_DIRECTION (%d)\n", StackGrowthDirection(&dummy1)); + // PA-RISC is the only platform we try to support on which the stack + // grows towards higher addresses. Trying to detect it here has + // historically led to portability problems, which aren't worth it + // given the near consensus on stack growth direction. + printf("#ifdef __hppa\n" + "# define JS_STACK_GROWTH_DIRECTION (1)\n" + "#else\n" + "# define JS_STACK_GROWTH_DIRECTION (-1)\n" + "#endif\n"); printf("#endif /* js_cpucfg___ */\n"); From 3c6b60461fb005cdf307dcf36f9163f73b213344 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 24 Mar 2010 18:23:34 -0500 Subject: [PATCH 133/213] Disable js/src/tests/js1_8_1/extensions/regress-466905-05.js which now fails. See bug 554793 for more. --HG-- extra : rebase_source : 7507438b0fc1b9279a31bda21c2b2e4ae4479ca4 --- js/src/tests/js1_8_1/extensions/jstests.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/tests/js1_8_1/extensions/jstests.list b/js/src/tests/js1_8_1/extensions/jstests.list index de844256d187..8610b773b2fa 100644 --- a/js/src/tests/js1_8_1/extensions/jstests.list +++ b/js/src/tests/js1_8_1/extensions/jstests.list @@ -7,7 +7,7 @@ script regress-452498-193.js script regress-452498-196.js script regress-452498-224.js script regress-466905-04.js -script regress-466905-05.js +skip script regress-466905-05.js # no-op in browser, fails in shell - see bug 554793 script regress-477158.js script regress-477187.js script regress-520572.js From eb5e50868d8932d48830905f451c7e043f58ef03 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 24 Mar 2010 21:20:44 -0500 Subject: [PATCH 134/213] Bug 500431 part 3 - Rename JSPropertyCache to js::PropertyCache and other renamings. r=brendan. --- js/src/jscntxt.cpp | 4 +- js/src/jscntxt.h | 6 +- js/src/jsinterp.cpp | 5 +- js/src/jsobj.cpp | 29 +++--- js/src/jsobj.h | 2 +- js/src/jsops.cpp | 52 +++++------ js/src/jsparse.h | 2 +- js/src/jspropertycache.cpp | 121 +++++++++++------------- js/src/jspropertycache.h | 161 ++++++++++++++++---------------- js/src/jspropertycacheinlines.h | 46 ++++----- js/src/jsprvtd.h | 3 +- js/src/jsscript.cpp | 10 +- js/src/jstracer.cpp | 32 +++---- js/src/jstracer.h | 16 ++-- 14 files changed, 238 insertions(+), 251 deletions(-) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 98921b50c0e7..d76fd6fc1dd2 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -136,7 +136,7 @@ JSThreadData::finish() js_DestroyDtoaState(dtoaState); js_FinishGSNCache(&gsnCache); - js_FinishPropertyCache(&propertyCache); + propertyCache.~PropertyCache(); #if defined JS_TRACER FinishJIT(&traceMonitor); #endif @@ -160,7 +160,7 @@ JSThreadData::purge(JSContext *cx) js_PurgeGSNCache(&gsnCache); /* FIXME: bug 506341. */ - js_PurgePropertyCache(cx, &propertyCache); + propertyCache.purge(cx); #ifdef JS_TRACER /* diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 5e04c9235404..dce65541764d 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -540,7 +540,7 @@ struct JSThreadData { JSGSNCache gsnCache; /* Property cache for faster call/get/set invocation. */ - JSPropertyCache propertyCache; + js::PropertyCache propertyCache; /* Optional stack of heap-allocated scoped local GC roots. */ JSLocalRootStack *localRootStack; @@ -2362,7 +2362,7 @@ js_GetTopStackFrame(JSContext *cx) static JS_INLINE JSBool js_IsPropertyCacheDisabled(JSContext *cx) { - return cx->runtime->shapeGen >= SHAPE_OVERFLOW_BIT; + return cx->runtime->shapeGen >= js::SHAPE_OVERFLOW_BIT; } static JS_INLINE uint32 @@ -2377,7 +2377,7 @@ js_RegenerateShapeForGC(JSContext *cx) * the shape stays such. */ uint32 shape = cx->runtime->shapeGen; - shape = (shape + 1) | (shape & SHAPE_OVERFLOW_BIT); + shape = (shape + 1) | (shape & js::SHAPE_OVERFLOW_BIT); cx->runtime->shapeGen = shape; return shape; } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 2a3a6c4b9728..fa4ae1ce8755 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -2222,7 +2222,7 @@ JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL_CONSTEXPR(JSVAL_INT_MAX))); static bool AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs, ptrdiff_t pcoff, JSObject *start, JSObject *found, - JSPropCacheEntry *entry) + PropertyCacheEntry *entry) { uint32 sample = cx->runtime->gcNumber; @@ -2244,8 +2244,7 @@ AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs, } if (!ok) return false; - if (cx->runtime->gcNumber != sample || - PCVCAP_SHAPE(entry->vcap) != OBJ_SHAPE(pobj)) { + if (cx->runtime->gcNumber != sample || entry->vshape() != OBJ_SHAPE(pobj)) { pobj->dropProperty(cx, prop); return true; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 6122d99b322d..2ba973021056 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -4520,8 +4520,8 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, if (defineHow & JSDNP_CACHE_RESULT) { JS_ASSERT_NOT_ON_TRACE(cx); - JSPropCacheEntry *entry; - entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added); + PropertyCacheEntry *entry = + JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, sprop, added); TRACE_2(SetPropHit, entry, sprop); } if (propp) @@ -4725,12 +4725,12 @@ out: return protoIndex; } -JSPropCacheEntry * +PropertyCacheEntry * js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, JSObject **objp, JSObject **pobjp, JSProperty **propp) { JSObject *scopeChain, *obj, *parent, *pobj; - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; int scopeIndex, protoIndex; JSProperty *prop; @@ -4773,9 +4773,8 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, } #endif if (cacheResult) { - entry = js_FillPropertyCache(cx, scopeChain, - scopeIndex, protoIndex, pobj, - (JSScopeProperty *) prop); + entry = JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, protoIndex, pobj, + (JSScopeProperty *) prop); } SCOPE_DEPTH_ACCUM(&cx->runtime->scopeSearchDepthStats, scopeIndex); goto out; @@ -4854,11 +4853,10 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id) JS_ASSERT(OBJ_IS_NATIVE(pobj)); JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj)); #ifdef DEBUG - JSPropCacheEntry *entry = + PropertyCacheEntry *entry = #endif - js_FillPropertyCache(cx, scopeChain, - scopeIndex, protoIndex, pobj, - (JSScopeProperty *) prop); + JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, protoIndex, pobj, + (JSScopeProperty *) prop); JS_ASSERT(entry); JS_UNLOCK_OBJ(cx, pobj); return obj; @@ -5094,7 +5092,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, if (getHow & JSGET_CACHE_RESULT) { JS_ASSERT_NOT_ON_TRACE(cx); - js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, sprop); + JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, sprop); } if (!js_NativeGet(cx, obj, obj2, sprop, getHow, vp)) @@ -5283,8 +5281,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (!sprop->hasSlot()) { if (defineHow & JSDNP_CACHE_RESULT) { JS_ASSERT_NOT_ON_TRACE(cx); - JSPropCacheEntry *entry = - js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop); + PropertyCacheEntry *entry = + JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, protoIndex, pobj, sprop); TRACE_2(SetPropHit, entry, sprop); } @@ -5384,8 +5382,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (defineHow & JSDNP_CACHE_RESULT) { JS_ASSERT_NOT_ON_TRACE(cx); - JSPropCacheEntry *entry; - entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added); + PropertyCacheEntry *entry = JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, sprop, added); TRACE_2(SetPropHit, entry, sprop); } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 2248ace3575d..884389b7063b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -900,7 +900,7 @@ js_IsCacheableNonGlobalScope(JSObject *obj) /* * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success. */ -extern JSPropCacheEntry * +extern js::PropertyCacheEntry * js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, JSObject **objp, JSObject **pobjp, JSProperty **propp); diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 913f9a080299..3991155c5812 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -687,7 +687,7 @@ END_CASE(JSOP_ENUMCONSTELEM) BEGIN_CASE(JSOP_BINDNAME) do { - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; /* * We can skip the property lookup for the global object. If the @@ -709,7 +709,7 @@ BEGIN_CASE(JSOP_BINDNAME) if (!obj->getParent()) break; if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { - PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); break; @@ -1216,11 +1216,11 @@ BEGIN_CASE(JSOP_DECNAME) BEGIN_CASE(JSOP_NAMEINC) BEGIN_CASE(JSOP_NAMEDEC) { - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; obj = fp->scopeChain; if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { - PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) { @@ -1475,7 +1475,7 @@ BEGIN_CASE(JSOP_GETXPROP) do_getprop_with_obj: do { JSObject *aobj; - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; /* * We do not impose the method read barrier if in an imacro, @@ -1484,7 +1484,7 @@ BEGIN_CASE(JSOP_GETXPROP) */ aobj = js_GetProtoIfDenseArray(obj); if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { - PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); if (PCVAL_IS_OBJECT(entry->vword)) { @@ -1556,7 +1556,7 @@ END_CASE(JSOP_LENGTH) BEGIN_CASE(JSOP_CALLPROP) { JSObject *aobj; - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; lval = FETCH_OPND(-1); if (!JSVAL_IS_PRIMITIVE(lval)) { @@ -1580,7 +1580,7 @@ BEGIN_CASE(JSOP_CALLPROP) aobj = js_GetProtoIfDenseArray(obj); if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { - PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); if (PCVAL_IS_OBJECT(entry->vword)) { @@ -1605,7 +1605,7 @@ BEGIN_CASE(JSOP_CALLPROP) /* * Cache miss: use the immediate atom that was loaded for us under - * PROPERTY_CACHE_TEST. + * PropertyCache::test. */ id = ATOM_TO_JSID(atom); PUSH(JSVAL_NULL); @@ -1671,16 +1671,16 @@ BEGIN_CASE(JSOP_SETMETHOD) VALUE_TO_OBJECT(cx, -2, lval, obj); do { - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; entry = NULL; atom = NULL; if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { - JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); + PropertyCache *cache = &JS_PROPERTY_CACHE(cx); uint32 kshape = OBJ_SHAPE(obj); /* - * Open-code PROPERTY_CACHE_TEST, specializing for two important + * Open-code PropertyCache::test, specializing for two important * set-property cases. First: * * function f(a, b, c) { @@ -1698,12 +1698,12 @@ BEGIN_CASE(JSOP_SETMETHOD) * (possibly after the first iteration) always exist in native * object o. */ - entry = &cache->table[PROPERTY_CACHE_HASH(regs.pc, kshape)]; + entry = &cache->table[PropertyCache::hash(regs.pc, kshape)]; PCMETER(cache->pctestentry = entry); PCMETER(cache->tests++); PCMETER(cache->settests++); if (entry->kpc == regs.pc && entry->kshape == kshape && - JSPropCacheEntry::matchShape(cx, obj, kshape)) { + PropertyCache::matchShape(cx, obj, kshape)) { /* * Property cache hit: either predicting a new property to be * added directly to obj by this set, or on an existing "own" @@ -1712,7 +1712,7 @@ BEGIN_CASE(JSOP_SETMETHOD) JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); sprop = PCVAL_TO_SPROP(entry->vword); JS_ASSERT(sprop->writable()); - JS_ASSERT_IF(sprop->hasSlot(), PCVCAP_TAG(entry->vcap) == 0); + JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0); JSScope *scope = OBJ_SCOPE(obj); JS_ASSERT(!scope->sealed()); @@ -1725,10 +1725,10 @@ BEGIN_CASE(JSOP_SETMETHOD) */ bool checkForAdd; if (!sprop->hasSlot()) { - if (PCVCAP_TAG(entry->vcap) == 0 || + if (entry->vcapTag() == 0 || ((obj2 = obj->getProto()) && OBJ_IS_NATIVE(obj2) && - OBJ_SHAPE(obj2) == PCVCAP_SHAPE(entry->vcap))) { + OBJ_SHAPE(obj2) == entry->vshape())) { goto fast_set_propcache_hit; } @@ -1758,7 +1758,7 @@ BEGIN_CASE(JSOP_SETMETHOD) } if (checkForAdd && - PCVCAP_SHAPE(entry->vcap) == rt->protoHazardShape && + entry->vshape() == rt->protoHazardShape && sprop->hasDefaultSetter() && (slot = sprop->slot) == scope->freeslot) { /* @@ -1835,7 +1835,7 @@ BEGIN_CASE(JSOP_SETMETHOD) PCMETER(cache->setpcmisses++); } - atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2, entry); + atom = cache->fullTest(cx, regs.pc, &obj, &obj2, entry); if (atom) { PCMETER(cache->misses++); PCMETER(cache->setmisses++); @@ -2288,11 +2288,11 @@ END_CASE(JSOP_SETCALL) BEGIN_CASE(JSOP_NAME) BEGIN_CASE(JSOP_CALLNAME) { - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; obj = fp->scopeChain; if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { - PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); if (PCVAL_IS_OBJECT(entry->vword)) { @@ -3372,8 +3372,8 @@ BEGIN_CASE(JSOP_INITMETHOD) do { JSScope *scope; uint32 kshape; - JSPropertyCache *cache; - JSPropCacheEntry *entry; + PropertyCache *cache; + PropertyCacheEntry *entry; /* * We can not assume that the object created by JSOP_NEWINIT is still @@ -3387,15 +3387,15 @@ BEGIN_CASE(JSOP_INITMETHOD) JS_ASSERT(!scope->sealed()); kshape = scope->shape; cache = &JS_PROPERTY_CACHE(cx); - entry = &cache->table[PROPERTY_CACHE_HASH(regs.pc, kshape)]; + entry = &cache->table[PropertyCache::hash(regs.pc, kshape)]; PCMETER(cache->pctestentry = entry); PCMETER(cache->tests++); PCMETER(cache->initests++); if (entry->kpc == regs.pc && entry->kshape == kshape && - PCVCAP_SHAPE(entry->vcap) == rt->protoHazardShape) { - JS_ASSERT(PCVCAP_TAG(entry->vcap) == 0); + entry->vshape() == rt->protoHazardShape) { + JS_ASSERT(entry->vcapTag() == 0); PCMETER(cache->pchits++); PCMETER(cache->inipchits++); diff --git a/js/src/jsparse.h b/js/src/jsparse.h index b72a021ba000..fa9b12740915 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -863,7 +863,7 @@ struct JSFunctionBox : public JSObjectBox * * We despecialize from caching function objects, caching slots or sprops * instead, because an unbranded object may still have joined methods (for - * which sprop->isMethod), since js_FillPropertyCache gives precedence to + * which sprop->isMethod), since PropertyCache::fill gives precedence to * joined methods over branded methods. */ bool shouldUnbrand(uintN methods, uintN slowMethods) const; diff --git a/js/src/jspropertycache.cpp b/js/src/jspropertycache.cpp index baa78787743d..72c93a6877b1 100644 --- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -1,4 +1,7 @@ -/* ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=98: + * + * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -41,26 +44,24 @@ using namespace js; -JS_REQUIRES_STACK JSPropCacheEntry * -js_FillPropertyCache(JSContext *cx, JSObject *obj, - uintN scopeIndex, uintN protoIndex, JSObject *pobj, - JSScopeProperty *sprop, JSBool adding) +JS_REQUIRES_STACK PropertyCacheEntry * +PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoIndex, + JSObject *pobj, JSScopeProperty *sprop, JSBool adding) { - JSPropertyCache *cache; jsbytecode *pc; JSScope *scope; jsuword kshape, vshape; JSOp op; const JSCodeSpec *cs; jsuword vword; - JSPropCacheEntry *entry; + PropertyCacheEntry *entry; + JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); JS_ASSERT(!cx->runtime->gcRunning); - cache = &JS_PROPERTY_CACHE(cx); /* FIXME bug 489098: consider enabling the property cache for eval. */ if (js_IsPropertyCacheDisabled(cx) || (cx->fp->flags & JSFRAME_EVAL)) { - PCMETER(cache->disfills++); + PCMETER(disfills++); return JS_NO_PROP_CACHE_FILL; } @@ -70,7 +71,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, */ scope = OBJ_SCOPE(pobj); if (!scope->hasProperty(sprop)) { - PCMETER(cache->oddfills++); + PCMETER(oddfills++); return JS_NO_PROP_CACHE_FILL; } @@ -106,7 +107,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, * mutate in arbitrary way without changing any shapes. */ if (!tmp || !OBJ_IS_NATIVE(tmp)) { - PCMETER(cache->noprotos++); + PCMETER(noprotos++); return JS_NO_PROP_CACHE_FILL; } if (tmp == pobj) @@ -116,7 +117,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, } if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) { - PCMETER(cache->longchains++); + PCMETER(longchains++); return JS_NO_PROP_CACHE_FILL; } @@ -169,7 +170,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, * object will result in shape being regenerated. */ if (!scope->branded()) { - PCMETER(cache->brandfills++); + PCMETER(brandfills++); #ifdef DEBUG_notme fprintf(stderr, "branding %p (%s) for funobj %p (%s), shape %lu\n", @@ -288,22 +289,19 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, } JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); - entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)]; - PCMETER(PCVAL_IS_NULL(entry->vword) || cache->recycles++); - entry->kpc = pc; - entry->kshape = kshape; - entry->vcap = PCVCAP_MAKE(vshape, scopeIndex, protoIndex); - entry->vword = vword; + entry = &table[hash(pc, kshape)]; + PCMETER(PCVAL_IS_NULL(entry->vword) || recycles++); + entry->assign(pc, kshape, vshape, scopeIndex, protoIndex, vword); - cache->empty = JS_FALSE; - PCMETER(cache->fills++); + empty = false; + PCMETER(fills++); /* * The modfills counter is not exact. It increases if a getter or setter * recurse into the interpreter. */ - PCMETER(entry == cache->pctestentry || cache->modfills++); - PCMETER(cache->pctestentry = NULL); + PCMETER(entry == pctestentry || modfills++); + PCMETER(pctestentry = NULL); return entry; } @@ -320,13 +318,13 @@ GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs } JS_REQUIRES_STACK JSAtom * -js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, - JSObject **objp, JSObject **pobjp, - JSPropCacheEntry *entry) +PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp, + PropertyCacheEntry *entry) { JSObject *obj, *pobj, *tmp; uint32 vcap; + JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); JS_ASSERT(uintN((cx->fp->imacpc ? cx->fp->imacpc : pc) - cx->fp->script->code) < cx->fp->script->length); @@ -338,7 +336,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, vcap = entry->vcap; if (entry->kpc != pc) { - PCMETER(JS_PROPERTY_CACHE(cx).kpcmisses++); + PCMETER(kpcmisses++); JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); #ifdef DEBUG_notme @@ -361,13 +359,13 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, } if (entry->kshape != OBJ_SHAPE(obj)) { - PCMETER(JS_PROPERTY_CACHE(cx).kshapemisses++); + PCMETER(kshapemisses++); return GetAtomFromBytecode(cx, pc, op, cs); } /* - * PROPERTY_CACHE_TEST handles only the direct and immediate-prototype hit - * cases, all others go here. We could embed the target object in the cache + * PropertyCache::test handles only the direct and immediate-prototype hit + * cases. All others go here. We could embed the target object in the cache * entry but then entry size would be 5 words. Instead we traverse chains. */ pobj = obj; @@ -392,7 +390,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, --vcap; } - if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(vcap))) { + if (matchShape(cx, pobj, vcap >> PCVCAP_TAGBITS)) { #ifdef DEBUG JSAtom *atom = GetAtomFromBytecode(cx, pc, op, cs); jsid id = ATOM_TO_JSID(atom); @@ -405,39 +403,36 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, return NULL; } - PCMETER(JS_PROPERTY_CACHE(cx).vcapmisses++); + PCMETER(vcapmisses++); return GetAtomFromBytecode(cx, pc, op, cs); } #ifdef DEBUG -#define ASSERT_CACHE_IS_EMPTY(cache) \ - JS_BEGIN_MACRO \ - JSPropertyCache *cache_ = (cache); \ - uintN i_; \ - JS_ASSERT(cache_->empty); \ - for (i_ = 0; i_ < PROPERTY_CACHE_SIZE; i_++) { \ - JS_ASSERT(!cache_->table[i_].kpc); \ - JS_ASSERT(!cache_->table[i_].kshape); \ - JS_ASSERT(!cache_->table[i_].vcap); \ - JS_ASSERT(!cache_->table[i_].vword); \ - } \ - JS_END_MACRO -#else -#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0) +void +PropertyCache::assertEmpty() +{ + JS_ASSERT(empty); + for (uintN i = 0; i < SIZE; i++) { + JS_ASSERT(!table[i].kpc); + JS_ASSERT(!table[i].kshape); + JS_ASSERT(!table[i].vcap); + JS_ASSERT(!table[i].vword); + } +} #endif JS_STATIC_ASSERT(PCVAL_NULL == 0); void -js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) +PropertyCache::purge(JSContext *cx) { - if (cache->empty) { - ASSERT_CACHE_IS_EMPTY(cache); + if (empty) { + assertEmpty(); return; } - PodArrayZero(cache->table); - cache->empty = JS_TRUE; + PodArrayZero(table); + empty = true; #ifdef JS_PROPERTY_CACHE_METERING { static FILE *fp; @@ -450,7 +445,7 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) #endif fprintf(fp, "GC %u\n", cx->runtime->gcNumber); -# define P(mem) fprintf(fp, "%11s %10lu\n", #mem, (unsigned long)cache->mem) +# define P(mem) fprintf(fp, "%11s %10lu\n", #mem, (unsigned long)mem) P(fills); P(nofills); P(rofills); @@ -481,28 +476,24 @@ js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache) # undef P fprintf(fp, "hit rates: pc %g%% (proto %g%%), set %g%%, ini %g%%, full %g%%\n", - (100. * cache->pchits) / cache->tests, - (100. * cache->protopchits) / cache->tests, - (100. * (cache->addpchits + cache->setpchits)) - / cache->settests, - (100. * cache->inipchits) / cache->initests, - (100. * (cache->tests - cache->misses)) / cache->tests); + (100. * pchits) / tests, + (100. * protopchits) / tests, + (100. * (addpchits + setpchits)) + / settests, + (100. * inipchits) / initests, + (100. * (tests - misses)) / tests); fflush(fp); } } #endif - PCMETER(cache->flushes++); + PCMETER(flushes++); } void -js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script) +PropertyCache::purgeForScript(JSScript *script) { - JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); - - for (JSPropCacheEntry *entry = cache->table; - entry < cache->table + PROPERTY_CACHE_SIZE; - entry++) { + for (PropertyCacheEntry *entry = table; entry < table + SIZE; entry++) { if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { entry->kpc = NULL; #ifdef DEBUG diff --git a/js/src/jspropertycache.h b/js/src/jspropertycache.h index adab8e641e02..add27dc088d4 100644 --- a/js/src/jspropertycache.h +++ b/js/src/jspropertycache.h @@ -1,4 +1,7 @@ -/* ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=98: + * + * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version @@ -42,7 +45,7 @@ #include "jsprvtd.h" #include "jstypes.h" -JS_BEGIN_EXTERN_C +namespace js { /* * Property cache with structurally typed capabilities for invalidation, for @@ -50,23 +53,6 @@ JS_BEGIN_EXTERN_C * . */ -enum { - PROPERTY_CACHE_LOG2 = 12, - PROPERTY_CACHE_SIZE = JS_BIT(PROPERTY_CACHE_LOG2), - PROPERTY_CACHE_MASK = JS_BITMASK(PROPERTY_CACHE_LOG2) -}; - -/* - * Add kshape rather than xor it to avoid collisions between nearby bytecode - * that are evolving an object by setting successive properties, incrementing - * the object's scope->shape on each set. - */ -inline jsuword -PROPERTY_CACHE_HASH(jsbytecode *pc, jsuword kshape) -{ - return ((((jsuword(pc) >> PROPERTY_CACHE_LOG2) ^ jsuword(pc)) + kshape) & PROPERTY_CACHE_MASK); -} - /* Property cache value capabilities. */ enum { PCVCAP_PROTOBITS = 4, @@ -83,60 +69,57 @@ enum { const uint32 SHAPE_OVERFLOW_BIT = JS_BIT(32 - PCVCAP_TAGBITS); -inline jsuword -PCVCAP_TAG(jsuword t) -{ - return t & PCVCAP_TAGMASK; -} - -inline jsuword -PCVCAP_MAKE(uint32 t, unsigned int s, unsigned int p) -{ - JS_ASSERT(t < SHAPE_OVERFLOW_BIT); - JS_ASSERT(s <= PCVCAP_SCOPEMASK); - JS_ASSERT(p <= PCVCAP_PROTOMASK); - return (t << PCVCAP_TAGBITS) | (s << PCVCAP_PROTOBITS) | p; -} - -inline uint32 -PCVCAP_SHAPE(jsuword t) -{ - return t >> PCVCAP_TAGBITS; -} - -struct JSPropCacheEntry +struct PropertyCacheEntry { jsbytecode *kpc; /* pc of cache-testing bytecode */ jsuword kshape; /* shape of direct (key) object */ jsuword vcap; /* value capability, see above */ jsuword vword; /* value word, see PCVAL_* below */ - bool adding() const { - return PCVCAP_TAG(vcap) == 0 && kshape != PCVCAP_SHAPE(vcap); - } + bool adding() const { return vcapTag() == 0 && kshape != vshape(); } + bool directHit() const { return vcapTag() == 0 && kshape == vshape(); } - bool directHit() const { - return PCVCAP_TAG(vcap) == 0 && kshape == PCVCAP_SHAPE(vcap); - } + jsuword vcapTag() const { return vcap & PCVCAP_TAGMASK; } + uint32 vshape() const { return uint32(vcap >> PCVCAP_TAGBITS); } + jsuword scopeIndex() const { return (vcap >> PCVCAP_PROTOBITS) & PCVCAP_SCOPEMASK; } + jsuword protoIndex() const { return vcap & PCVCAP_PROTOMASK; } - static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape); + void assign(jsbytecode *kpc, jsuword kshape, jsuword vshape, + uintN scopeIndex, uintN protoIndex, jsuword vword) { + JS_ASSERT(kshape < SHAPE_OVERFLOW_BIT); + JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); + JS_ASSERT(scopeIndex <= PCVCAP_SCOPEMASK); + JS_ASSERT(protoIndex <= PCVCAP_PROTOMASK); + + this->kpc = kpc; + this->kshape = kshape; + this->vcap = (vshape << PCVCAP_TAGBITS) | (scopeIndex << PCVCAP_PROTOBITS) | protoIndex; + this->vword = vword; + } }; /* - * Special value for functions returning JSPropCacheEntry * to distinguish + * Special value for functions returning PropertyCacheEntry * to distinguish * between failure and no no-cache-fill cases. */ -#define JS_NO_PROP_CACHE_FILL ((JSPropCacheEntry *) NULL + 1) +#define JS_NO_PROP_CACHE_FILL ((js::PropertyCacheEntry *) NULL + 1) #if defined DEBUG_brendan || defined DEBUG_brendaneich #define JS_PROPERTY_CACHE_METERING 1 #endif -typedef struct JSPropertyCache { - JSPropCacheEntry table[PROPERTY_CACHE_SIZE]; +struct PropertyCache +{ + enum { + SIZE_LOG2 = 12, + SIZE = JS_BIT(SIZE_LOG2), + MASK = JS_BITMASK(SIZE_LOG2) + }; + + PropertyCacheEntry table[SIZE]; JSBool empty; #ifdef JS_PROPERTY_CACHE_METERING - JSPropCacheEntry *pctestentry; /* entry of the last PC-based test */ + PropertyCacheEntry *pctestentry; /* entry of the last PC-based test */ uint32 fills; /* number of cache entry fills */ uint32 nofills; /* couldn't fill (e.g. default get) */ uint32 rofills; /* set on read-only prop can't fill */ @@ -169,7 +152,48 @@ typedef struct JSPropertyCache { #else # define PCMETER(x) ((void)0) #endif -} JSPropertyCache; + + /* + * Add kshape rather than xor it to avoid collisions between nearby bytecode + * that are evolving an object by setting successive properties, incrementing + * the object's scope->shape on each set. + */ + static inline jsuword + hash(jsbytecode *pc, jsuword kshape) + { + return ((((jsuword(pc) >> SIZE_LOG2) ^ jsuword(pc)) + kshape) & MASK); + } + + static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape); + + JS_ALWAYS_INLINE JS_REQUIRES_STACK void test(JSContext *cx, jsbytecode *pc, + JSObject *&obj, JSObject *&pobj, + PropertyCacheEntry *&entry, JSAtom *&atom); + + JS_REQUIRES_STACK JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, + JSObject **pobjp, PropertyCacheEntry *entry); + + /* + * Fill property cache entry for key cx->fp->pc, optimized value word + * computed from obj and sprop, and entry capability forged from 24-bit + * OBJ_SHAPE(obj), 4-bit scopeIndex, and 4-bit protoIndex. + * + * Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was + * not possible. + */ + JS_REQUIRES_STACK PropertyCacheEntry *fill(JSContext *cx, JSObject *obj, uintN scopeIndex, + uintN protoIndex, JSObject *pobj, + JSScopeProperty *sprop, JSBool adding = false); + + void purge(JSContext *cx); + void purgeForScript(JSScript *script); + +#ifdef DEBUG + void assertEmpty(); +#else + inline void assertEmpty() {} +#endif +}; /* * Property cache value tagging/untagging macros. @@ -206,33 +230,6 @@ inline bool PCVAL_IS_SPROP(jsuword v) { return PCVAL_TAG(v) == PCVAL_SPROP; } inline JSScopeProperty *PCVAL_TO_SPROP(jsuword v) { JS_ASSERT(PCVAL_IS_SPROP(v)); return (JSScopeProperty *) PCVAL_CLRTAG(v); } inline jsuword SPROP_TO_PCVAL(JSScopeProperty *sprop) { return PCVAL_SETTAG(jsuword(sprop), PCVAL_SPROP); } -/* - * Fill property cache entry for key cx->fp->pc, optimized value word computed - * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), - * 4-bit scopeIndex, and 4-bit protoIndex. - * - * Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not - * possible. - */ -extern JS_REQUIRES_STACK JSPropCacheEntry * -js_FillPropertyCache(JSContext *cx, JSObject *obj, - uintN scopeIndex, uintN protoIndex, JSObject *pobj, - JSScopeProperty *sprop, JSBool adding = false); - -extern JS_REQUIRES_STACK JSAtom * -js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, - JSObject **objp, JSObject **pobjp, - JSPropCacheEntry *entry); - -/* The property cache does not need a destructor. */ -#define js_FinishPropertyCache(cache) ((void) 0) - -extern void -js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache); - -extern void -js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script); - -JS_END_EXTERN_C +} /* namespace js */ #endif /* jspropertycache_h___ */ diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h index d6011b3f8ab7..4f7eb93a3223 100644 --- a/js/src/jspropertycacheinlines.h +++ b/js/src/jspropertycacheinlines.h @@ -45,57 +45,59 @@ #include "jspropertycache.h" #include "jsscope.h" +using namespace js; + /* static */ inline bool -JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape) +PropertyCache::matchShape(JSContext *cx, JSObject *obj, uint32 shape) { return CX_OWNS_OBJECT_TITLE(cx, obj) && OBJ_SHAPE(obj) == shape; } /* - * PROPERTY_CACHE_TEST is designed to inline the fast path in js_Interpret, so - * it makes "just-so" restrictions on parameters, e.g. pobj and obj should not - * be the same variable, since for JOF_PROP-mode opcodes, obj must not be - * changed because of a cache miss. + * This method is designed to inline the fast path in js_Interpret, so it makes + * "just-so" restrictions on parameters, e.g. pobj and obj should not be the + * same variable, since for JOF_PROP-mode opcodes, obj must not be changed + * because of a cache miss. * - * On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the - * scope chain element in which the property was found, pobj is locked, and - * entry is valid. If atom is non-null then no object is locked but entry is - * still set correctly for use, e.g., by js_FillPropertyCache and atom should - * be used as the id to find. + * On return, if atom is null then obj points to the scope chain element in + * which the property was found, pobj is locked, and entry is valid. If atom is + * non-null then no object is locked but entry is still set correctly for use, + * e.g., by PropertyCache::fill and atom should be used as the id to find. * * We must lock pobj on a hit in order to close races with threads that might * be deleting a property from its scope, or otherwise invalidating property * caches (on all threads) by re-generating scope->shape. */ JS_ALWAYS_INLINE void -PROPERTY_CACHE_TEST(JSContext *cx, jsbytecode *pc, JSObject *&obj, - JSObject *&pobj, JSPropCacheEntry *&entry, JSAtom *&atom) +PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, + JSObject *&pobj, PropertyCacheEntry *&entry, JSAtom *&atom) { - JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); + JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); JS_ASSERT(OBJ_IS_NATIVE(obj)); + uint32 kshape = OBJ_SHAPE(obj); - entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)]; - PCMETER(cache->pctestentry = entry); - PCMETER(cache->tests++); + entry = &table[hash(pc, kshape)]; + PCMETER(pctestentry = entry); + PCMETER(tests++); JS_ASSERT(&obj != &pobj); if (entry->kpc == pc && entry->kshape == kshape) { JSObject *tmp; pobj = obj; - if (PCVCAP_TAG(entry->vcap) == 1 && + if (entry->vcapTag() == 1 && (tmp = pobj->getProto()) != NULL) { pobj = tmp; } - if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(entry->vcap))) { - PCMETER(cache->pchits++); - PCMETER(!PCVCAP_TAG(entry->vcap) || cache->protopchits++); + if (matchShape(cx, pobj, entry->vshape())) { + PCMETER(pchits++); + PCMETER(!entry->vcapTag() || protopchits++); atom = NULL; return; } } - atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); + atom = fullTest(cx, pc, &obj, &pobj, entry); if (atom) - PCMETER(cache->misses++); + PCMETER(misses++); } #endif /* jspropertycacheinlines_h___ */ diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 6171bd68964e..550eb96696bc 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -98,7 +98,6 @@ typedef struct JSCompiler JSCompiler; typedef struct JSFunctionBox JSFunctionBox; typedef struct JSObjectBox JSObjectBox; typedef struct JSParseNode JSParseNode; -typedef struct JSPropCacheEntry JSPropCacheEntry; typedef struct JSProperty JSProperty; typedef struct JSSharpObjectMap JSSharpObjectMap; typedef struct JSEmptyScope JSEmptyScope; @@ -175,6 +174,8 @@ class HashSet; class DeflatedStringCache; +struct PropertyCache; +struct PropertyCacheEntry; } /* namespace js */ /* Common instantiations. */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 8239ee78e9f1..15065a6ca7d4 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1136,10 +1136,10 @@ js_DestroyScript(JSContext *cx, JSScript *script) * regenerating shapes, so we don't have to purge fragments if the GC is * currently running. * - * JS_THREADSAFE note: js_PurgePropertyCacheForScript purges only the - * current thread's property cache, so a script not owned by a function - * or object, which hands off lifetime management for that script to the - * GC, must be used by only one thread over its lifetime. + * JS_THREADSAFE note: The code below purges only the current thread's + * property cache, so a script not owned by a function or object, which + * hands off lifetime management for that script to the GC, must be used by + * only one thread over its lifetime. * * This should be an API-compatible change, since a script is never safe * against premature GC if shared among threads without a rooted object @@ -1155,7 +1155,7 @@ js_DestroyScript(JSContext *cx, JSScript *script) JSStackFrame *fp = js_GetTopStackFrame(cx); if (!(fp && (fp->flags & JSFRAME_EVAL))) { - js_PurgePropertyCacheForScript(cx, script); + JS_PROPERTY_CACHE(cx).purgeForScript(script); #ifdef CHECK_SCRIPT_OWNER JS_ASSERT(script->owner == cx->thread); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 6a0b9ccb2f6b..39f2fe90ff68 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -9113,7 +9113,7 @@ JS_REQUIRES_STACK RecordingStatus TraceRecorder::guardNativePropertyOp(JSObject* aobj, LIns* map_ins) { /* - * Interpreter calls to PROPERTY_CACHE_TEST guard on native object ops + * Interpreter calls to PropertyCache::test guard on native object ops * which is required to use native objects (those whose maps are scopes), * or even more narrow conditions required because the cache miss case * will call a particular object-op (js_GetProperty, js_SetProperty). @@ -9166,8 +9166,8 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 CHECK_STATUS_A(guardNativePropertyOp(aobj, map_ins)); JSAtom* atom; - JSPropCacheEntry* entry; - PROPERTY_CACHE_TEST(cx, pc, aobj, obj2, entry, atom); + PropertyCacheEntry* entry; + JS_PROPERTY_CACHE(cx).test(cx, pc, aobj, obj2, entry, atom); if (atom) { // Miss: pre-fill the cache for the interpreter, as well as for our needs. jsid id = ATOM_TO_JSID(atom); @@ -9208,8 +9208,8 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 obj2->dropProperty(cx, prop); RETURN_STOP_A("property found on non-native object"); } - entry = js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, - (JSScopeProperty*) prop); + entry = JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, + (JSScopeProperty*) prop); JS_ASSERT(entry); if (entry == JS_NO_PROP_CACHE_FILL) entry = NULL; @@ -9249,12 +9249,12 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, LIns* map_ins, JSObject* aobj, JSObject* obj2, - JSPropCacheEntry* entry, + PropertyCacheEntry* entry, jsuword& pcval) { VMSideExit* exit = snapshot(BRANCH_EXIT); - uint32 vshape = PCVCAP_SHAPE(entry->vcap); + uint32 vshape = entry->vshape(); // Special case for the global object, which may be aliased to get a property value. // To catch cross-global property accesses we must check against globalObj identity. @@ -9290,14 +9290,14 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, // For any hit that goes up the scope and/or proto chains, we will need to // guard on the shape of the object containing the property. - if (PCVCAP_TAG(entry->vcap) >= 1) { + if (entry->vcapTag() >= 1) { JS_ASSERT(OBJ_SHAPE(obj2) == vshape); if (obj2 == globalObj) RETURN_STOP("hitting the global object via a prototype chain"); LIns* obj2_ins; - if (PCVCAP_TAG(entry->vcap) == 1) { - // Duplicate the special case in PROPERTY_CACHE_TEST. + if (entry->vcapTag() == 1) { + // Duplicate the special case in PropertyCache::test. obj2_ins = addName(stobj_get_proto(obj_ins), "proto"); guard(false, lir->ins_peq0(obj2_ins), exit); } else { @@ -11251,12 +11251,12 @@ JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, MethodWriteBarrier, CONTEXT, OBJECT, SCO 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop, +TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* sprop, jsval &v, LIns*& v_ins) { if (entry == JS_NO_PROP_CACHE_FILL) RETURN_STOP("can't trace uncacheable property set"); - JS_ASSERT_IF(PCVCAP_TAG(entry->vcap) >= 1, !sprop->hasSlot()); + JS_ASSERT_IF(entry->vcapTag() >= 1, !sprop->hasSlot()); if (!sprop->hasDefaultSetter() && sprop->slot != SPROP_INVALID_SLOT) RETURN_STOP("can't trace set of property with setter and slot"); if (sprop->hasSetterValue()) @@ -11273,7 +11273,7 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop LIns* obj_ins = get(&l); JSScope* scope = OBJ_SCOPE(obj); - JS_ASSERT_IF(entry->vcap == PCVCAP_MAKE(entry->kshape, 0, 0), scope->hasProperty(sprop)); + JS_ASSERT_IF(entry->directHit(), scope->hasProperty(sprop)); // Fast path for CallClass. This is about 20% faster than the general case. v_ins = get(&v); @@ -11282,9 +11282,9 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop // Find obj2. If entry->adding(), the TAG bits are all 0. JSObject* obj2 = obj; - for (jsuword i = PCVCAP_TAG(entry->vcap) >> PCVCAP_PROTOBITS; i; i--) + for (jsuword i = entry->scopeIndex(); i; i--) obj2 = obj2->getParent(); - for (jsuword j = PCVCAP_TAG(entry->vcap) & PCVCAP_PROTOMASK; j; j--) + for (jsuword j = entry->protoIndex(); j; j--) obj2 = obj2->getProto(); scope = OBJ_SCOPE(obj2); JS_ASSERT_IF(entry->adding(), obj2 == obj); @@ -11457,7 +11457,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop) +TraceRecorder::record_SetPropHit(PropertyCacheEntry* entry, JSScopeProperty* sprop) { jsval& r = stackval(-1); jsval& l = stackval(-2); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 6fedb1a38581..faa40ef93d12 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1212,11 +1212,11 @@ class TraceRecorder JS_REQUIRES_STACK RecordingStatus guardNativePropertyOp(JSObject* aobj, nanojit::LIns* map_ins); JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins, - nanojit::LIns* map_ins, - JSObject* aobj, - JSObject* obj2, - JSPropCacheEntry* entry, - jsuword& pcval); + nanojit::LIns* map_ins, + JSObject* aobj, + JSObject* obj2, + PropertyCacheEntry* entry, + jsuword& pcval); void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot, nanojit::LIns* v_ins); @@ -1280,7 +1280,7 @@ class TraceRecorder JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins, JSScopeProperty* sprop, jsval v, nanojit::LIns* v_ins); - JS_REQUIRES_STACK RecordingStatus setProp(jsval &l, JSPropCacheEntry* entry, + JS_REQUIRES_STACK RecordingStatus setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* sprop, jsval &v, nanojit::LIns*& v_ins); JS_REQUIRES_STACK RecordingStatus setCallProp(JSObject *callobj, nanojit::LIns *callobj_ins, @@ -1431,8 +1431,8 @@ public: JS_REQUIRES_STACK AbortableRecordingStatus monitorRecording(JSOp op); JS_REQUIRES_STACK AbortableRecordingStatus record_EnterFrame(uintN& inlineCallCount); JS_REQUIRES_STACK AbortableRecordingStatus record_LeaveFrame(); - JS_REQUIRES_STACK AbortableRecordingStatus record_SetPropHit(JSPropCacheEntry* entry, - JSScopeProperty* sprop); + JS_REQUIRES_STACK AbortableRecordingStatus record_SetPropHit(PropertyCacheEntry* entry, + JSScopeProperty* sprop); JS_REQUIRES_STACK AbortableRecordingStatus record_DefLocalFunSetSlot(uint32 slot, JSObject* obj); JS_REQUIRES_STACK AbortableRecordingStatus record_NativeCallComplete(); void forgetGuardedShapesForObject(JSObject* obj); From ee505065ba7a54a32f30014f13963921f64367a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 24 Mar 2010 19:30:47 -0700 Subject: [PATCH 135/213] Follow-up to bug 517910: dslots aren't read-only. r=jorendorff on IRC. --- js/src/jstracer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 4cd58651741b..df4beaf52789 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -12351,7 +12351,7 @@ TraceRecorder::record_JSOP_GETDSLOT() unsigned index = GET_UINT16(cx->fp->regs->pc); LIns* dslots_ins = lir->insLoad(LIR_ldp, callee_ins, offsetof(JSObject, dslots), ACC_OTHER); - LIns* v_ins = lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval), ACC_READONLY); + LIns* v_ins = lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval), ACC_OTHER); stack(0, unbox_jsval(callee->dslots[index], v_ins, snapshot(BRANCH_EXIT))); return ARECORD_CONTINUE; From dd6d0fdd02746a7a196349020d020e39edeb63c6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 24 Mar 2010 15:34:34 -0700 Subject: [PATCH 136/213] Bug 553518 - nanojit: avoid 'test r,r' where possible on i386. r=edwsmith. --HG-- extra : convert_revision : ec4d959e1cc9337cf30a08bf75b246516a1728a4 --- js/src/nanojit/Assembler.cpp | 125 +++++++++++++++++++--------------- js/src/nanojit/Assembler.h | 7 ++ js/src/nanojit/LIR.cpp | 29 ++++---- js/src/nanojit/LIR.h | 23 ++++--- js/src/nanojit/Nativei386.cpp | 12 +++- 5 files changed, 118 insertions(+), 78 deletions(-) diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index 6b7e30a19d7a..b3f62b2a7b6c 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -80,6 +80,7 @@ namespace nanojit , _config(config) { VMPI_memset(&_stats, 0, sizeof(_stats)); + VMPI_memset(lookahead, 0, N_LOOKAHEAD * sizeof(LInsp)); nInit(core); (void)logc; verbose_only( _logc = logc; ) @@ -1208,67 +1209,77 @@ namespace nanojit NanoAssert(_thisfrag->nStaticExits == 0); // The trace must end with one of these opcodes. - NanoAssert(reader->pos()->isop(LIR_x) || - reader->pos()->isop(LIR_xtbl) || - reader->pos()->isRet() || - reader->pos()->isLive()); + NanoAssert(reader->finalIns()->isop(LIR_x) || + reader->finalIns()->isop(LIR_xtbl) || + reader->finalIns()->isRet() || + reader->finalIns()->isLive()); InsList pending_lives(alloc); NanoAssert(!error()); - for (LInsp ins = reader->read(); !ins->isop(LIR_start); ins = reader->read()) + + // What's going on here: we're visiting all the LIR instructions in + // the buffer, working strictly backwards in buffer-order, and + // generating machine instructions for them as we go. + // + // For each LIns, we first determine whether it's actually necessary, + // and if not skip it. Otherwise we generate code for it. There are + // two kinds of "necessary" instructions: + // + // - "Statement" instructions, which have side effects. Anything that + // could change control flow or the state of memory. + // + // - "Value" or "expression" instructions, which compute a value based + // only on the operands to the instruction (and, in the case of + // loads, the state of memory). Because we visit instructions in + // reverse order, if some previously visited instruction uses the + // value computed by this instruction, then this instruction will + // already have a register assigned to hold that value. Hence we + // can consult the instruction to detect whether its value is in + // fact used (i.e. not dead). + // + // Note that the backwards code traversal can make register allocation + // confusing. (For example, we restore a value before we spill it!) + // In particular, words like "before" and "after" must be used very + // carefully -- their meaning at regalloc-time is opposite to their + // meaning at run-time. We use the term "pre-regstate" to refer to + // the register allocation state that occurs prior to an instruction's + // execution, and "post-regstate" to refer to the state that occurs + // after an instruction's execution, e.g.: + // + // pre-regstate: ebx(ins) + // instruction: mov eax, ebx // mov dst, src + // post-regstate: eax(ins) + // + // At run-time, the instruction updates the pre-regstate into the + // post-regstate (and these states are the real machine's regstates). + // But when allocating registers, because we go backwards, the + // pre-regstate is constructed from the post-regstate (and these + // regstates are those stored in RegAlloc). + // + // One consequence of generating code backwards is that we tend to + // both spill and restore registers as early (at run-time) as + // possible; this is good for tolerating memory latency. If we + // generated code forwards, we would expect to both spill and restore + // registers as late (at run-time) as possible; this might be better + // for reducing register pressure. + // + // Another thing to note: we provide N_LOOKAHEAD instruction's worth + // of lookahead because it's useful for backends. This is nice and + // easy because once read() gets to the LIR_start at the beginning of + // the buffer it'll just keep regetting it. + + for (int32_t i = 0; i < N_LOOKAHEAD; i++) + lookahead[i] = reader->read(); + + while (!lookahead[0]->isop(LIR_start)) { - /* What's going on here: we're visiting all the LIR instructions - in the buffer, working strictly backwards in buffer-order, and - generating machine instructions for them as we go. + LInsp ins = lookahead[0]; // give it a shorter name for local use + LOpcode op = ins->opcode(); - For each LIns, we first determine whether it's actually - necessary, and if not skip it. Otherwise we generate code for - it. There are two kinds of "necessary" instructions: - - - "Statement" instructions, which have side effects. Anything - that could change control flow or the state of memory. - - - "Value" or "expression" instructions, which compute a value - based only on the operands to the instruction (and, in the - case of loads, the state of memory). Because we visit - instructions in reverse order, if some previously visited - instruction uses the value computed by this instruction, then - this instruction will already have a register assigned to - hold that value. Hence we can consult the instruction to - detect whether its value is in fact used (i.e. not dead). - - Note that the backwards code traversal can make register - allocation confusing. (For example, we restore a value before - we spill it!) In particular, words like "before" and "after" - must be used very carefully -- their meaning at regalloc-time is - opposite to their meaning at run-time. We use the term - "pre-regstate" to refer to the register allocation state that - occurs prior to an instruction's execution, and "post-regstate" - to refer to the state that occurs after an instruction's - execution, e.g.: - - pre-regstate: ebx(ins) - instruction: mov eax, ebx // mov dst, src - post-regstate: eax(ins) - - At run-time, the instruction updates the pre-regstate into the - post-regstate (and these states are the real machine's - regstates). But when allocating registers, because we go - backwards, the pre-regstate is constructed from the - post-regstate (and these regstates are those stored in - RegAlloc). - - One consequence of generating code backwards is that we tend to - both spill and restore registers as early (at run-time) as - possible; this is good for tolerating memory latency. If we - generated code forwards, we would expect to both spill and - restore registers as late (at run-time) as possible; this might - be better for reducing register pressure. - */ bool required = ins->isStmt() || ins->isUsed(); if (!required) - continue; + goto end_of_loop; #ifdef NJ_VERBOSE // Output the post-regstate (registers and/or activation). @@ -1281,8 +1292,7 @@ namespace nanojit printRegState(); #endif - LOpcode op = ins->opcode(); - switch(op) + switch (op) { default: NanoAssertMsgf(false, "unsupported LIR instruction: %d\n", op); @@ -1851,6 +1861,11 @@ namespace nanojit // check that all is well (don't check in exit paths since its more complicated) debug_only( pageValidate(); ) debug_only( resourceConsistencyCheck(); ) + + end_of_loop: + for (int32_t i = 1; i < N_LOOKAHEAD; i++) + lookahead[i-1] = lookahead[i]; + lookahead[N_LOOKAHEAD-1] = reader->read(); } } diff --git a/js/src/nanojit/Assembler.h b/js/src/nanojit/Assembler.h index cf36b617a4d4..e0f47e5060cd 100644 --- a/js/src/nanojit/Assembler.h +++ b/js/src/nanojit/Assembler.h @@ -413,6 +413,13 @@ namespace nanojit NIns* pedanticTop; #endif + + // Instruction lookahead in gen(). lookahead[0] is the current + // instruction. Nb: lookahead[1..N_LOOKAHEAD] may include dead + // instructions, but we won't know that they're dead yet. + static const int N_LOOKAHEAD = 3; + LInsp lookahead[N_LOOKAHEAD]; + AR _activation; RegAlloc _allocator; diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 2a71fa4f697d..9a0caad6f33d 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -136,13 +136,18 @@ namespace nanojit LInsp ReverseLister::read() { - LInsp i = in->read(); + // This check is necessary to avoid printing the LIR_start multiple + // times due to lookahead in Assembler::gen(). + if (_prevIns && _prevIns->isop(LIR_start)) + return _prevIns; + LInsp ins = in->read(); InsBuf b; - const char* str = _printer->formatIns(&b, i); + const char* str = _printer->formatIns(&b, ins); char* cpy = new (_alloc) char[strlen(str)+1]; VMPI_strcpy(cpy, str); _strs.insert(cpy); - return i; + _prevIns = ins; + return ins; } #endif @@ -402,20 +407,20 @@ namespace nanojit 0 }; - // Check the invariant: _i never points to a skip. - NanoAssert(_i && !_i->isop(LIR_skip)); + // Check the invariant: _ins never points to a skip. + NanoAssert(_ins && !_ins->isop(LIR_skip)); // Step back one instruction. Use a table lookup rather than a switch // to avoid branch mispredictions. LIR_start is given a special size // of zero so that we don't step back past the start of the block. // (Callers of this function should stop once they see a LIR_start.) - LInsp ret = _i; - _i = (LInsp)(uintptr_t(_i) - insSizes[_i->opcode()]); + LInsp ret = _ins; + _ins = (LInsp)(uintptr_t(_ins) - insSizes[_ins->opcode()]); - // Ensure _i doesn't end up pointing to a skip. - while (_i->isop(LIR_skip)) { - NanoAssert(_i->prevLIns() != _i); - _i = _i->prevLIns(); + // Ensure _ins doesn't end up pointing to a skip. + while (_ins->isop(LIR_skip)) { + NanoAssert(_ins->prevLIns() != _ins); + _ins = _ins->prevLIns(); } return ret; @@ -1567,7 +1572,7 @@ namespace nanojit uint32_t exits = 0; int total = 0; if (frag->lirbuf->state) - live.add(frag->lirbuf->state, in->pos()); + live.add(frag->lirbuf->state, in->finalIns()); for (LInsp ins = in->read(); !ins->isop(LIR_start); ins = in->read()) { total++; diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 7f16a6b7f58d..def1b45a8a2e 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -891,7 +891,7 @@ namespace nanojit // Note, this assumes that loads will never fault and hence cannot // affect the control flow. bool isStmt() { - NanoAssert(!isop(LIR_start) && !isop(LIR_skip)); + NanoAssert(!isop(LIR_skip)); // All instructions with Void retType are statements, as are calls // to impure functions. if (isCall()) @@ -1943,21 +1943,25 @@ namespace nanojit LirFilter(LirFilter *in) : in(in) {} virtual ~LirFilter(){} + // It's crucial that once this reaches the LIR_start at the beginning + // of the buffer, that it just keeps returning that LIR_start LIns on + // any subsequent calls. virtual LInsp read() { return in->read(); } - virtual LInsp pos() { - return in->pos(); + virtual LInsp finalIns() { + return in->finalIns(); } }; // concrete class LirReader : public LirFilter { - LInsp _i; // next instruction to be read; invariant: is never a skip + LInsp _ins; // next instruction to be read; invariant: is never a skip + LInsp _finalIns; // final instruction in the stream; ie. the first one to be read public: - LirReader(LInsp i) : LirFilter(0), _i(i) + LirReader(LInsp ins) : LirFilter(0), _ins(ins), _finalIns(ins) { // The last instruction for a fragment shouldn't be a skip. // (Actually, if the last *inserted* instruction exactly fills up @@ -1966,7 +1970,7 @@ namespace nanojit // cross-chunk link. But the last *inserted* instruction is what // is recorded and used to initialise each LirReader, and that is // what is seen here, and therefore this assertion holds.) - NanoAssert(i && !i->isop(LIR_skip)); + NanoAssert(ins && !ins->isop(LIR_skip)); } virtual ~LirReader() {} @@ -1974,9 +1978,8 @@ namespace nanojit // Invariant: never returns a skip. LInsp read(); - // Returns next instruction. Invariant: never returns a skip. - LInsp pos() { - return _i; + LInsp finalIns() { + return _finalIns; } }; @@ -2102,6 +2105,7 @@ namespace nanojit const char* _title; StringList _strs; LogControl* _logc; + LIns* _prevIns; public: ReverseLister(LirFilter* in, Allocator& alloc, LInsPrinter* printer, LogControl* logc, const char* title) @@ -2111,6 +2115,7 @@ namespace nanojit , _title(title) , _strs(alloc) , _logc(logc) + , _prevIns(NULL) { } void finish(); diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index 5fe505061847..8ec0ccdc38e0 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -742,11 +742,19 @@ namespace nanojit // disturb the CCs! Register r = findRegFor(lhs, GpRegs); if (c == 0 && cond->isop(LIR_eq)) { - TEST(r, r); + NanoAssert(N_LOOKAHEAD >= 3); + if ((lhs->isop(LIR_and) || lhs->isop(LIR_or)) && + cond == lookahead[1] && lhs == lookahead[2]) + { + // Do nothing. At run-time, 'lhs' will have just computed + // by an i386 instruction that sets ZF for us ('and' or + // 'or'), so we don't have to do it ourselves. + } else { + TEST(r, r); // sets ZF according to the value of 'lhs' + } } else { CMPi(r, c); } - } else { Register ra, rb; findRegFor2(GpRegs, lhs, ra, GpRegs, rhs, rb); From cd3244836ec541553ee5358a4422b3930f8341b0 Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Wed, 24 Mar 2010 20:08:06 -0400 Subject: [PATCH 137/213] Remove now-dead LIR_iaddp/qaddp/addp (bug 542016, r=nnethercote+) Simplified the code in CseFilter::ins2() as well since addp was the only non-cse-able binary operator. --HG-- extra : convert_revision : 0f21522488fc4a7e3efeaad5c77b6bb96ca0f0fc --- js/src/lirasm/lirasm.cpp | 5 ----- js/src/nanojit/Assembler.cpp | 2 -- js/src/nanojit/LIR.cpp | 30 +++++++++--------------------- js/src/nanojit/LIR.h | 1 - js/src/nanojit/NativeARM.cpp | 4 +--- js/src/nanojit/NativeMIPS.cpp | 2 -- js/src/nanojit/NativePPC.cpp | 5 ----- js/src/nanojit/NativeSparc.cpp | 6 +++--- js/src/nanojit/NativeX64.cpp | 9 +++------ js/src/nanojit/Nativei386.cpp | 8 +++----- 10 files changed, 19 insertions(+), 53 deletions(-) diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index a74ec5475d46..25bef4e89c11 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -961,7 +961,6 @@ FragmentAssembler::assembleFragment(LirTokenStream &in, bool implicitBegin, cons ref(mTokens[0])); break; - case LIR_addp: case LIR_add: case LIR_sub: case LIR_mul: @@ -1352,9 +1351,6 @@ FragmentAssembler::assembleRandomFragment(int nIns) vector I_II_ops; I_II_ops.push_back(LIR_add); -#ifndef NANOJIT_64BIT - I_II_ops.push_back(LIR_iaddp); -#endif I_II_ops.push_back(LIR_sub); I_II_ops.push_back(LIR_mul); #if defined NANOJIT_IA32 || defined NANOJIT_X64 @@ -1371,7 +1367,6 @@ FragmentAssembler::assembleRandomFragment(int nIns) #ifdef NANOJIT_64BIT vector Q_QQ_ops; Q_QQ_ops.push_back(LIR_qiadd); - Q_QQ_ops.push_back(LIR_qaddp); Q_QQ_ops.push_back(LIR_qiand); Q_QQ_ops.push_back(LIR_qior); Q_QQ_ops.push_back(LIR_qxor); diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index b3f62b2a7b6c..cfa8eccb9521 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -1439,7 +1439,6 @@ namespace nanojit case LIR_qursh: case LIR_qirsh: case LIR_qior: - CASE64(LIR_qaddp:) case LIR_qxor: { asm_qbinop(ins); @@ -1448,7 +1447,6 @@ namespace nanojit #endif case LIR_add: - CASE32(LIR_iaddp:) case LIR_sub: case LIR_mul: case LIR_and: diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 9a0caad6f33d..5eb91e323f23 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -264,7 +264,7 @@ namespace nanojit return ins; } else { // If the displacement is more than 16 bits, put it in a separate instruction. - return insStore(op, val, ins2(LIR_addp, base, insImmWord(d)), 0, accSet); + return insStore(op, val, ins2(LIR_piadd, base, insImmWord(d)), 0, accSet); } } @@ -311,7 +311,7 @@ namespace nanojit // If the displacement is more than 16 bits, put it in a separate instruction. // Note that CseFilter::insLoad() also does this, so this will // only occur if CseFilter has been removed from the pipeline. - return insLoad(op, ins2(LIR_addp, base, insImmWord(d)), 0, accSet); + return insLoad(op, ins2(LIR_piadd, base, insImmWord(d)), 0, accSet); } } @@ -713,7 +713,6 @@ namespace nanojit LIns* t; switch (v) { case LIR_add: - CASE32(LIR_iaddp:) case LIR_mul: case LIR_fadd: case LIR_fmul: @@ -774,7 +773,6 @@ namespace nanojit if (c == 0) { switch (v) { case LIR_add: - CASE32(LIR_iaddp:) case LIR_or: case LIR_xor: case LIR_sub: @@ -1679,7 +1677,6 @@ namespace nanojit CASE64(LIR_qilsh:) CASE64(LIR_qirsh:) CASE64(LIR_qursh:) - case LIR_addp: case LIR_add: case LIR_sub: case LIR_mul: @@ -2064,7 +2061,6 @@ namespace nanojit break; case LIR_add: CASE64(LIR_qiadd:) - case LIR_addp: case LIR_sub: case LIR_mul: CASE86(LIR_div:) @@ -2237,15 +2233,12 @@ namespace nanojit LIns* CseFilter::ins2(LOpcode op, LInsp a, LInsp b) { LInsp ins; - if (isCseOpcode(op)) { - uint32_t k; - ins = exprs->find2(op, a, b, k); - if (!ins) { - ins = out->ins2(op, a, b); - exprs->add(LIns2, ins, k); - } - } else { + NanoAssert(isCseOpcode(op)); + uint32_t k; + ins = exprs->find2(op, a, b, k); + if (!ins) { ins = out->ins2(op, a, b); + exprs->add(LIns2, ins, k); } NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b); return ins; @@ -2302,7 +2295,7 @@ namespace nanojit // If the displacement is more than 16 bits, put it in a separate // instruction. Nb: LirBufWriter also does this, we do it here // too because CseFilter relies on LirBufWriter not changing code. - ins = insLoad(op, ins2(LIR_addp, base, insImmWord(disp)), 0, loadAccSet); + ins = insLoad(op, ins2(LIR_piadd, base, insImmWord(disp)), 0, loadAccSet); } return ins; } @@ -2319,7 +2312,7 @@ namespace nanojit // If the displacement is more than 16 bits, put it in a separate // instruction. Nb: LirBufWriter also does this, we do it here // too because CseFilter relies on LirBufWriter not changing code. - ins = insStore(op, value, ins2(LIR_addp, base, insImmWord(disp)), 0, accSet); + ins = insStore(op, value, ins2(LIR_piadd, base, insImmWord(disp)), 0, accSet); } return ins; } @@ -2887,11 +2880,6 @@ namespace nanojit formals[1] = LTy_I32; break; - case LIR_addp: - formals[0] = LTy_Ptr; - formals[1] = LTy_Ptr; - break; - #if NJ_SOFTFLOAT_SUPPORTED case LIR_qjoin: formals[0] = LTy_I32; diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index def1b45a8a2e..b25bdae4ab3f 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -71,7 +71,6 @@ namespace nanojit LIR_pcmov = PTR_SIZE(LIR_cmov, LIR_qcmov), LIR_pior = PTR_SIZE(LIR_or, LIR_qior), LIR_pxor = PTR_SIZE(LIR_xor, LIR_qxor), - LIR_addp = PTR_SIZE(LIR_iaddp, LIR_qaddp), LIR_peq = PTR_SIZE(LIR_eq, LIR_qeq), LIR_plt = PTR_SIZE(LIR_lt, LIR_qlt), LIR_pgt = PTR_SIZE(LIR_gt, LIR_qgt), diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index 8b27696a9587..fa6ff4ee7231 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -2370,7 +2370,7 @@ Assembler::asm_arith(LInsp ins) // trace-tests.js so it is very unlikely to be worthwhile implementing it. if (rhs->isconst() && op != LIR_mul && op != LIR_mulxov) { - if ((op == LIR_add || op == LIR_iaddp || op == LIR_addxov) && lhs->isop(LIR_ialloc)) { + if ((op == LIR_add || op == LIR_addxov) && lhs->isop(LIR_ialloc)) { // Add alloc+const. The result should be the address of the // allocated space plus a constant. Register rs = deprecated_prepResultReg(ins, allow); @@ -2384,7 +2384,6 @@ Assembler::asm_arith(LInsp ins) switch (op) { - case LIR_iaddp: case LIR_add: asm_add_imm(rr, ra, imm32); break; case LIR_addxov: asm_add_imm(rr, ra, imm32, 1); break; case LIR_sub: asm_sub_imm(rr, ra, imm32); break; @@ -2421,7 +2420,6 @@ Assembler::asm_arith(LInsp ins) const Register SBZ = (Register)0; switch (op) { - case LIR_iaddp: case LIR_add: ADDs(rr, ra, rb, 0); break; case LIR_addxov: ADDs(rr, ra, rb, 1); break; case LIR_sub: SUBs(rr, ra, rb, 0); break; diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp index 18fc29baf192..ca853828fefc 100644 --- a/js/src/nanojit/NativeMIPS.cpp +++ b/js/src/nanojit/NativeMIPS.cpp @@ -954,7 +954,6 @@ namespace nanojit // MIPS arith immediate ops sign-extend the imm16 value switch (op) { case LIR_add: - case LIR_iaddp: if (ovreg != deprecated_UnknownReg) SLT(ovreg, rr, ra); ADDIU(rr, ra, rhsc); @@ -1016,7 +1015,6 @@ namespace nanojit switch (op) { case LIR_add: - case LIR_iaddp: if (ovreg != deprecated_UnknownReg) SLT(ovreg,rr,ra); ADDU(rr, ra, rb); diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index 92a90cece45d..efbdc3f8aa0b 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -838,9 +838,7 @@ namespace nanojit // ppc arith immediate ops sign-exted the imm16 value switch (op) { case LIR_add: - CASE32(LIR_iaddp:) CASE64(LIR_qiadd:) - CASE64(LIR_qaddp:) ADDI(rr, ra, rhsc); return; case LIR_sub: @@ -887,9 +885,7 @@ namespace nanojit Register rb = rhs==lhs ? ra : findRegFor(rhs, GpRegs&~rmask(ra)); switch (op) { CASE64(LIR_qiadd:) - CASE64(LIR_qaddp:) case LIR_add: - CASE32(LIR_iaddp:) ADD(rr, ra, rb); break; CASE64(LIR_qiand:) @@ -1361,7 +1357,6 @@ namespace nanojit void Assembler::asm_qbinop(LIns *ins) { LOpcode op = ins->opcode(); switch (op) { - case LIR_qaddp: case LIR_qior: case LIR_qiand: case LIR_qursh: diff --git a/js/src/nanojit/NativeSparc.cpp b/js/src/nanojit/NativeSparc.cpp index 22e8db132091..e3694716d691 100644 --- a/js/src/nanojit/NativeSparc.cpp +++ b/js/src/nanojit/NativeSparc.cpp @@ -633,7 +633,7 @@ namespace nanojit } allow &= ~rmask(rb); } - else if ((op == LIR_add||op == LIR_iaddp||op == LIR_addxov) && lhs->isop(LIR_alloc) && rhs->isconst()) { + else if ((op == LIR_add || op == LIR_addxov) && lhs->isop(LIR_alloc) && rhs->isconst()) { // add alloc+const, use lea Register rr = deprecated_prepResultReg(ins, allow); int d = findMemFor(lhs) + rhs->imm32(); @@ -653,7 +653,7 @@ namespace nanojit if (lhs == rhs) rb = ra; - if (op == LIR_add || op == LIR_iaddp || op == LIR_addxov) + if (op == LIR_add || op == LIR_addxov) ADDCC(rr, rb, rr); else if (op == LIR_sub || op == LIR_subxov) SUBCC(rr, rb, rr); @@ -677,7 +677,7 @@ namespace nanojit else { int c = rhs->imm32(); - if (op == LIR_add || op == LIR_iaddp || op == LIR_addxov) + if (op == LIR_add || op == LIR_addxov) ADDCC(rr, L2, rr); else if (op == LIR_sub || op == LIR_subxov) SUBCC(rr, L2, rr); diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index 03a4b35a4727..001fc4c829ad 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -719,8 +719,7 @@ namespace nanojit case LIR_sub: case LIR_subxov: SUBLR8(rr, imm); break; case LIR_xor: XORLR8(rr, imm); break; - case LIR_qiadd: - case LIR_qaddp: ADDQR8(rr, imm); break; + case LIR_qiadd: ADDQR8(rr, imm); break; case LIR_qiand: ANDQR8(rr, imm); break; case LIR_qior: ORQR8( rr, imm); break; case LIR_qxor: XORQR8(rr, imm); break; @@ -735,8 +734,7 @@ namespace nanojit case LIR_sub: case LIR_subxov: SUBLRI(rr, imm); break; case LIR_xor: XORLRI(rr, imm); break; - case LIR_qiadd: - case LIR_qaddp: ADDQRI(rr, imm); break; + case LIR_qiadd: ADDQRI(rr, imm); break; case LIR_qiand: ANDQRI(rr, imm); break; case LIR_qior: ORQRI( rr, imm); break; case LIR_qxor: XORQRI(rr, imm); break; @@ -845,8 +843,7 @@ namespace nanojit case LIR_qxor: XORQRR(rr, rb); break; case LIR_qior: ORQRR(rr, rb); break; case LIR_qiand: ANDQRR(rr, rb); break; - case LIR_qiadd: - case LIR_qaddp: ADDQRR(rr, rb); break; + case LIR_qiadd: ADDQRR(rr, rb); break; } if (rr != ra) MR(rr, ra); diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index 8ec0ccdc38e0..b27345647def 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -849,9 +849,9 @@ namespace nanojit LInsp rhs = ins->oprnd2(); // Second special case. - // XXX: bug 547125: don't need this once LEA is used for LIR_add/LIR_addp in all cases below - if ((op == LIR_add || op == LIR_iaddp) && lhs->isop(LIR_alloc) && rhs->isconst()) { - // LIR_add(LIR_alloc, LIR_int) or LIR_addp(LIR_alloc, LIR_int) -- use lea. + // XXX: bug 547125: don't need this once LEA is used for LIR_add in all cases below + if (op == LIR_add && lhs->isop(LIR_alloc) && rhs->isconst()) { + // LIR_add(LIR_alloc, LIR_int) -- use lea. Register rr = prepareResultReg(ins, GpRegs); int d = findMemFor(lhs) + rhs->imm32(); @@ -913,7 +913,6 @@ namespace nanojit switch (op) { case LIR_add: - case LIR_addp: case LIR_addxov: ADD(rr, rb); break; // XXX: bug 547125: could use LEA for LIR_add case LIR_sub: case LIR_subxov: SUB(rr, rb); break; @@ -935,7 +934,6 @@ namespace nanojit } else { int c = rhs->imm32(); switch (op) { - case LIR_addp: case LIR_add: // this doesn't set cc's, only use it when cc's not required. LEA(rr, c, ra); From 3a8f31468e6b06d0cccece26eed5610afe8de9e9 Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Wed, 24 Mar 2010 20:35:15 -0400 Subject: [PATCH 138/213] replace AvmAssert with NanoAssert everywhere (bug 554549 r=nnethercote+) Also, remove unused AvmAssert, AvmAssertMsg, and AvmDebugLog from nanojit/avmplus.h --HG-- extra : convert_revision : aeb486b1d227244e42a9dbc7a9f0a5ba9d84b67b --- js/src/nanojit/Assembler.cpp | 4 ++-- js/src/nanojit/CodeAlloc.cpp | 2 +- js/src/nanojit/VMPI.cpp | 6 +++--- js/src/nanojit/avmplus.h | 4 ---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index cfa8eccb9521..a6ab33bc5afa 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -1610,7 +1610,7 @@ namespace nanojit // Out of range indices aren't allowed or checked. // Code after this jtbl instruction is unreachable. releaseRegisters(); - AvmAssert(_allocator.countActive() == 0); + NanoAssert(_allocator.countActive() == 0); uint32_t count = ins->getTableSize(); bool has_back_edges = false; @@ -1635,7 +1635,7 @@ namespace nanojit // to reconcile registers. So, frontends *must* insert LIR_regfence at labels of // forward jtbl jumps. Check here to make sure no registers were picked up from // any forward edges. - AvmAssert(_allocator.countActive() == 0); + NanoAssert(_allocator.countActive() == 0); if (has_back_edges) { handleLoopCarriedExprs(pending_lives); diff --git a/js/src/nanojit/CodeAlloc.cpp b/js/src/nanojit/CodeAlloc.cpp index f0ed480829b9..b95e7e4b5c48 100644 --- a/js/src/nanojit/CodeAlloc.cpp +++ b/js/src/nanojit/CodeAlloc.cpp @@ -153,7 +153,7 @@ namespace nanojit if (verbose) avmplus::AvmLog("free %p-%p %d\n", start, end, (int)blk->size()); - AvmAssert(!blk->isFree); + NanoAssert(!blk->isFree); // coalesce adjacent blocks. bool already_on_avail_list; diff --git a/js/src/nanojit/VMPI.cpp b/js/src/nanojit/VMPI.cpp index b7727960d52c..893deb04de7d 100644 --- a/js/src/nanojit/VMPI.cpp +++ b/js/src/nanojit/VMPI.cpp @@ -101,7 +101,7 @@ VMPI_setPageProtection(void *address, ULONG attrib; ULONG range = size; ULONG retval = DosQueryMem(address, &range, &attrib); - AvmAssert(retval == 0); + NanoAssert(retval == 0); // exit if this is the start of the next memory object if (attrib & attribFlags) { @@ -111,7 +111,7 @@ VMPI_setPageProtection(void *address, range = size > range ? range : size; retval = DosSetMem(address, range, flags); - AvmAssert(retval == 0); + NanoAssert(retval == 0); address = (char*)address + range; size -= range; @@ -140,7 +140,7 @@ void VMPI_setPageProtection(void *address, flags |= PROT_WRITE; } int retval = mprotect((maddr_ptr)beginPage, (unsigned int)sizePaged, flags); - AvmAssert(retval == 0); + NanoAssert(retval == 0); (void)retval; } diff --git a/js/src/nanojit/avmplus.h b/js/src/nanojit/avmplus.h index d49fea60c2af..c29ae153134c 100644 --- a/js/src/nanojit/avmplus.h +++ b/js/src/nanojit/avmplus.h @@ -90,10 +90,6 @@ void NanoAssertFail(); #endif -#define AvmAssert(x) assert(x) -#define AvmAssertMsg(x, y) -#define AvmDebugLog(x) printf x - #if defined(AVMPLUS_IA32) #if defined(_MSC_VER) __declspec(naked) static inline __int64 rdtsc() From fcc5aa475633a6d9984055dfd494c0c20d70fca5 Mon Sep 17 00:00:00 2001 From: Edwin Smith Date: Wed, 24 Mar 2010 20:41:39 -0400 Subject: [PATCH 139/213] Cleaned up trailing whitespace (r=me) --HG-- extra : convert_revision : 6ee8bcd6813ffe98061b8d09317f58138bb41bb7 --- js/src/nanojit/LIR.cpp | 4 ++-- js/src/nanojit/LIR.h | 16 ++++++++-------- js/src/nanojit/NativeMIPS.cpp | 12 ++++++------ js/src/nanojit/NativePPC.cpp | 8 ++++---- js/src/nanojit/NativeX64.cpp | 2 +- js/src/nanojit/NativeX64.h | 2 +- js/src/nanojit/Nativei386.cpp | 2 +- js/src/nanojit/njconfig.h | 16 ++++++++-------- js/src/nanojit/njcpudetect.h | 4 ++-- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index 5eb91e323f23..d71349153ad9 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -1823,7 +1823,7 @@ namespace nanojit } else { addNameWithSuffix(ins, lirNames[ins->opcode()], lircounts.add(ins->opcode()), /*ignoreOneSuffix*/false); - + } return names.get(ins)->name; } @@ -2615,7 +2615,7 @@ namespace nanojit { NanoAssertMsgf(0, "LIR structure error (%s): %s %d of '%s' is '%s' (expected %s)", - whereInPipeline, argDesc, argN, + whereInPipeline, argDesc, argN, lirNames[op], lirNames[arg->opcode()], shouldBeDesc); } diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index b25bdae4ab3f..970dfbe00d86 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -123,14 +123,14 @@ namespace nanojit NanoStaticAssert((LIR_le^1) == LIR_ge && (LIR_ge^1) == LIR_le); NanoStaticAssert((LIR_ult^1) == LIR_ugt && (LIR_ugt^1) == LIR_ult); NanoStaticAssert((LIR_ule^1) == LIR_uge && (LIR_uge^1) == LIR_ule); - + #ifdef NANOJIT_64BIT NanoStaticAssert((LIR_qlt^1) == LIR_qgt && (LIR_qgt^1) == LIR_qlt); NanoStaticAssert((LIR_qle^1) == LIR_qge && (LIR_qge^1) == LIR_qle); NanoStaticAssert((LIR_qult^1) == LIR_qugt && (LIR_qugt^1) == LIR_qult); NanoStaticAssert((LIR_qule^1) == LIR_quge && (LIR_quge^1) == LIR_qule); #endif - + NanoStaticAssert((LIR_flt^1) == LIR_fgt && (LIR_fgt^1) == LIR_flt); NanoStaticAssert((LIR_fle^1) == LIR_fge && (LIR_fge^1) == LIR_fle); @@ -231,7 +231,7 @@ namespace nanojit // ------------------------------------------- // The LIR generator must mark each load/store with an "access region // set", which is a set of one or more access regions. This indicates - // which parts of LIR-accessible memory the load/store may touch. + // which parts of LIR-accessible memory the load/store may touch. // // The LIR generator must also mark each function called from LIR with an // access region set for memory stored to by the function. (We could also @@ -347,14 +347,14 @@ namespace nanojit return isCses[op] == 1; } inline bool isRetOpcode(LOpcode op) { - return + return #if defined NANOJIT_64BIT op == LIR_qret || #endif op == LIR_ret || op == LIR_fret; } inline bool isCmovOpcode(LOpcode op) { - return + return #if defined NANOJIT_64BIT op == LIR_qcmov || #endif @@ -829,7 +829,7 @@ namespace nanojit bool isconstq() const { return #ifdef NANOJIT_64BIT - isop(LIR_quad) || + isop(LIR_quad) || #endif isop(LIR_float); } @@ -869,9 +869,9 @@ namespace nanojit return retType() == LTy_F64; } bool isN64() const { - return + return #ifdef NANOJIT_64BIT - isI64() || + isI64() || #endif isF64(); } diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp index ca853828fefc..33d78e06aed1 100644 --- a/js/src/nanojit/NativeMIPS.cpp +++ b/js/src/nanojit/NativeMIPS.cpp @@ -530,7 +530,7 @@ namespace nanojit default: BADOPCODE(op); } - + TAG("asm_store32(value=%p{%s}, dr=%d, base=%p{%s})", value, lirNames[value->opcode()], dr, base, lirNames[base->opcode()]); } @@ -881,7 +881,7 @@ namespace nanojit case LIR_ldzb: // 8-bit integer load, zero-extend to 32-bit asm_ldst(OP_LBU, rres, d, rbase); break; - case LIR_ldzs: // 16-bit integer load, zero-extend to 32-bit + case LIR_ldzs: // 16-bit integer load, zero-extend to 32-bit asm_ldst(OP_LHU, rres, d, rbase); break; case LIR_ldsb: // 8-bit integer load, sign-extend to 32-bit @@ -890,7 +890,7 @@ namespace nanojit case LIR_ldss: // 16-bit integer load, sign-extend to 32-bit asm_ldst(OP_LH, rres, d, rbase); break; - case LIR_ld: // 32-bit integer load + case LIR_ld: // 32-bit integer load asm_ldst(OP_LW, rres, d, rbase); break; default: @@ -1128,7 +1128,7 @@ namespace nanojit } else BADOPCODE(op); - + TAG("asm_store64(value=%p{%s}, dr=%d, base=%p{%s})", value, lirNames[value->opcode()], dr, base, lirNames[base->opcode()]); } @@ -1502,7 +1502,7 @@ namespace nanojit * - 32-bit arguments are placed in registers and 32-bit aligned * on the stack. */ - void + void Assembler::asm_arg(ArgType ty, LInsp arg, Register& r, Register& fr, int& stkd) { // The stack offset must always be at least aligned to 4 bytes. @@ -1529,7 +1529,7 @@ namespace nanojit void Assembler::asm_call(LInsp ins) - { + { Register rr; LOpcode op = ins->opcode(); diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index efbdc3f8aa0b..c825d52754d5 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -571,10 +571,10 @@ namespace nanojit Register rb = b==a ? ra : findRegFor(b, allow & ~rmask(ra)); if (isSICmpOpcode(condop)) { CMPW(cr, ra, rb); - } + } else if (isUICmpOpcode(condop)) { CMPLW(cr, ra, rb); - } + } #if defined NANOJIT_64BIT else if (isSQCmpOpcode(condop)) { CMPD(cr, ra, rb); @@ -1019,7 +1019,7 @@ namespace nanojit } } #endif - + #ifdef NANOJIT_64BIT void Assembler::asm_immq(LIns *ins) { Register r = ins->deprecated_getReg(); @@ -1203,7 +1203,7 @@ namespace nanojit #else NanoAssert((ins->opcode() == LIR_cmov && iftrue->isI32() && iffalse->isI32())); #endif - + // fixme: we could handle fpu registers here, too, since we're just branching Register rr = deprecated_prepResultReg(ins, GpRegs); findSpecificRegFor(iftrue, rr); diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index 001fc4c829ad..c255f561787e 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -1743,7 +1743,7 @@ namespace nanojit // a temp XMM register. // Nb: we don't want any F64 values to end up in a GpReg, nor any // I64 values to end up in an FpReg. - // + // // # 'gt' and 'ga' are temporary GpRegs. // # ins->oprnd1() is in 'rr' (FpRegs) // mov gt, 0x8000000000000000 diff --git a/js/src/nanojit/NativeX64.h b/js/src/nanojit/NativeX64.h index a63cadaab0e6..eb98da84c612 100644 --- a/js/src/nanojit/NativeX64.h +++ b/js/src/nanojit/NativeX64.h @@ -207,7 +207,7 @@ namespace nanojit X64_imul = 0xC0AF0F4000000004LL, // 32bit signed mul r *= b X64_imuli = 0xC069400000000003LL, // 32bit signed mul r = b * imm32 X64_imul8 = 0x00C06B4000000004LL, // 32bit signed mul r = b * imm8 - X64_jmpi = 0x0000000025FF0006LL, // jump *0(rip) + X64_jmpi = 0x0000000025FF0006LL, // jump *0(rip) X64_jmp = 0x00000000E9000005LL, // jump near rel32 X64_jmp8 = 0x00EB000000000002LL, // jump near rel8 X64_jo = 0x00000000800F0006LL, // jump near if overflow diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index b27345647def..cb17ad4ef01c 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -281,7 +281,7 @@ namespace nanojit btr RegAlloc::free[ecx], eax // free &= ~rmask(i) mov r, eax } - #elif defined __SUNPRO_CC + #elif defined __SUNPRO_CC // Workaround for Sun Studio bug on handler embeded asm code. // See bug 544447 for detail. // https://bugzilla.mozilla.org/show_bug.cgi?id=544447 diff --git a/js/src/nanojit/njconfig.h b/js/src/nanojit/njconfig.h index 9b5c3ca53611..ac4f80920995 100644 --- a/js/src/nanojit/njconfig.h +++ b/js/src/nanojit/njconfig.h @@ -52,12 +52,12 @@ namespace nanojit * A struct used to configure the assumptions that Assembler can make when * generating code. The ctor will fill in all fields with the most reasonable * values it can derive from compiler flags and/or runtime detection, but - * the embedder is free to override any or all of them as it sees fit. + * the embedder is free to override any or all of them as it sees fit. * Using the ctor-provided default setup is guaranteed to provide a safe * runtime environment (though perhaps suboptimal in some cases), so an embedder * should replace these values with great care. * - * Note that although many fields are used on only specific architecture(s), + * Note that although many fields are used on only specific architecture(s), * this struct is deliberately declared without ifdef's for them, so (say) ARM-specific * fields are declared everywhere. This reduces build dependencies (so that this * files does not require nanojit.h to be included beforehand) and also reduces @@ -69,29 +69,29 @@ namespace nanojit public: // fills in reasonable default values for all fields. Config(); - + // ARM architecture to assume when generate instructions for (currently, 5 <= arm_arch <= 7) uint8_t arm_arch; // If true, use CSE. uint32_t cseopt:1; - + // Can we use SSE2 instructions? (x86-only) uint32_t i386_sse2:1; - + // Can we use cmov instructions? (x86-only) uint32_t i386_use_cmov:1; - + // Should we use a virtual stack pointer? (x86-only) uint32_t i386_fixed_esp:1; // Whether or not to generate VFP instructions. (ARM only) uint32_t arm_vfp:1; - + // @todo, document me uint32_t arm_show_stats:1; - // If true, use softfloat for all floating point operations, + // If true, use softfloat for all floating point operations, // whether or not an FPU is present. (ARM only for now, but might also includes MIPS in the future) uint32_t soft_float:1; }; diff --git a/js/src/nanojit/njcpudetect.h b/js/src/nanojit/njcpudetect.h index 6d669003df8a..7f8f1471bdad 100644 --- a/js/src/nanojit/njcpudetect.h +++ b/js/src/nanojit/njcpudetect.h @@ -62,7 +62,7 @@ // GCC and RealView usually define __ARM_ARCH__ #if defined(__ARM_ARCH__) - + #define NJ_COMPILER_ARM_ARCH __ARM_ARCH__ // ok, try well-known GCC flags ( see http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html ) @@ -97,7 +97,7 @@ #define NJ_COMPILER_ARM_ARCH _M_ARM #else - + // non-numeric value #define NJ_COMPILER_ARM_ARCH "Unable to determine valid NJ_COMPILER_ARM_ARCH (nanojit only supports ARMv5 or later)" From cf401765d23237a2f01ebc9c014b6b610f09c7ee Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 24 Mar 2010 20:13:06 -0700 Subject: [PATCH 140/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 3e7be2229de5..598f76c1ff64 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -dfaf13aa4c5928bcd871ac7f279657c87de7b0f9 +6ee8bcd6813ffe98061b8d09317f58138bb41bb7 From f3ef3005478ad4d492df536cc3acf1077d8f44a0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 24 Mar 2010 20:16:17 -0700 Subject: [PATCH 141/213] Bug 542016 - Remove LIR_addp (TM-specific part). code=edwsmith, r=nnethercote. --- js/src/jstracer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 72522cdf4f4c..d751c3381ba2 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -623,7 +623,7 @@ FragProfiling_showResults(TraceMonitor* tm) break; } r++; - AvmAssert(r >= 0 && r <= N_TOP_BLOCKS); + NanoAssert(r >= 0 && r <= N_TOP_BLOCKS); /* This entry should be placed at topPI[r], and entries at higher numbered slots moved up one. */ if (r < N_TOP_BLOCKS) { @@ -11418,9 +11418,9 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty LIns *callstackBase_ins = lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, callstackBase), ACC_OTHER); LIns *frameInfo_ins = lir->insLoad(LIR_ldp, callstackBase_ins, 0, ACC_OTHER); - LIns *typemap_ins = lir->ins2(LIR_addp, frameInfo_ins, INS_CONSTWORD(sizeof(FrameInfo))); + LIns *typemap_ins = lir->ins2(LIR_piadd, frameInfo_ins, INS_CONSTWORD(sizeof(FrameInfo))); LIns *type_ins = lir->insLoad(LIR_ldzb, - lir->ins2(LIR_addp, typemap_ins, lir->ins_u2p(slot_ins)), 0, + lir->ins2(LIR_piadd, typemap_ins, lir->ins_u2p(slot_ins)), 0, ACC_READONLY); TraceType type = getCoercedType(v); if (type == TT_INT32 && !isPromoteInt(v_ins)) @@ -11435,7 +11435,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty offsetof(InterpState, stackBase), ACC_OTHER); LIns *storeValue_ins = isPromoteInt(v_ins) ? demote(lir, v_ins) : v_ins; lir->insStorei(storeValue_ins, - lir->ins2(LIR_addp, stackBase_ins, lir->ins_u2p(offset_ins)), 0, ACC_STORE_ANY); + lir->ins2(LIR_piadd, stackBase_ins, lir->ins_u2p(offset_ins)), 0, ACC_STORE_ANY); LIns *br2 = lir->insBranch(LIR_j, NULL, NULL); // Case 2: calling builtin. From bf77dc64cbbc411e62110220ea8c7d4be800f5db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 24 Mar 2010 20:16:50 -0700 Subject: [PATCH 142/213] Remove dead variable to avoid GCC warning. no bug, r=me. --- js/src/jscpucfg.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/src/jscpucfg.cpp b/js/src/jscpucfg.cpp index 62729dd107b1..74e98b00afb7 100644 --- a/js/src/jscpucfg.cpp +++ b/js/src/jscpucfg.cpp @@ -52,8 +52,6 @@ int main(int argc, char **argv) { - int dummy1; - printf("#ifndef js_cpucfg___\n"); printf("#define js_cpucfg___\n\n"); From 5cc6c2c289d22a089d857dfe1dd45976ce0a6337 Mon Sep 17 00:00:00 2001 From: Gregor Wagner Date: Thu, 25 Mar 2010 15:20:34 -0700 Subject: [PATCH 143/213] Bug 553682, TM: GC Profiler Part1: Gnuplot script. r=gal --- js/src/gnuplot/gcTimer.gnu | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 js/src/gnuplot/gcTimer.gnu diff --git a/js/src/gnuplot/gcTimer.gnu b/js/src/gnuplot/gcTimer.gnu new file mode 100644 index 000000000000..a15e67fc2723 --- /dev/null +++ b/js/src/gnuplot/gcTimer.gnu @@ -0,0 +1,25 @@ +# gnuplot script to visualize GCMETER results. +# usage: "gnuplot gcTimer.pl >outputfile.png" + +set terminal png +# set Title +set title "Title goes here!" +set datafile missing "-" +set noxtics +set ytics nomirror +set ylabel "Cycles [1E6]" +set y2tics nomirror +set y2label "Chunk count" +set key below +set style data linespoints + +#set data file +plot 'gcTimer.dat' using 2 title columnheader(2), \ +'' u 3 title columnheader(3), \ +'' u 4 title columnheader(4), \ +'' u 5 title columnheader(5) with points, \ +'' u 6 title columnheader(6) with points, \ +'' u 7 title columnheader(7) with points, \ +'' u 8 title columnheader(8) with points, \ +'' u 9 title columnheader(9) with points axis x1y2, \ +'' u 10 title columnheader(10) with points axis x1y2 From 3255237a35f1cb502e18a92df7306aacf46210ea Mon Sep 17 00:00:00 2001 From: Gregor Wagner Date: Thu, 25 Mar 2010 16:11:27 -0700 Subject: [PATCH 144/213] Bug 553682, TM: GC Profiler Part2. r=igor --- configure.in | 11 +++++++ js/src/configure.in | 10 ++++++ js/src/jsgc.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index fc6ed433076e..6b23dec45a31 100644 --- a/configure.in +++ b/configure.in @@ -6979,6 +6979,17 @@ if test -n "$MOZ_TRACEVIS"; then AC_DEFINE(MOZ_TRACEVIS) fi +dnl ======================================================== +dnl = Use GCTimer +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(gctimer, +[ --enable-gctimer Enable GC timer (default=no)], + MOZ_GCTIMER=1, + MOZ_GCTIMER= ) +if test -n "$MOZ_GCTIMER"; then + AC_DEFINE(MOZ_GCTIMER) +fi + dnl ======================================================== dnl = Use Valgrind dnl ======================================================== diff --git a/js/src/configure.in b/js/src/configure.in index f5350af9a502..df8161089ef5 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -4232,6 +4232,16 @@ if test -n "$MOZ_TRACEVIS"; then fi fi +dnl ======================================================== +dnl = Use GCTimer +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(gctimer, +[ --enable-gctimer Enable GC timer (default=no)], + MOZ_GCTIMER=1, + MOZ_GCTIMER= ) +if test -n "$MOZ_GCTIMER"; then + AC_DEFINE(MOZ_GCTIMER) +fi dnl ======================================================== dnl = Use Valgrind diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 82a450da4f17..8976d27998b6 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -567,11 +567,18 @@ MakeNewArenaFreeList(JSGCArena *a, size_t thingSize) #define METER_UPDATE_MAX(maxLval, rval) \ METER_IF((maxLval) < (rval), (maxLval) = (rval)) +#ifdef MOZ_GCTIMER +static jsrefcount newChunkCount = 0; +static jsrefcount destroyChunkCount = 0; +#endif + static jsuword NewGCChunk(void) { void *p; - +#ifdef MOZ_GCTIMER + JS_ATOMIC_INCREMENT(&newChunkCount); +#endif #if defined(XP_WIN) p = VirtualAlloc(NULL, GC_CHUNK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); @@ -593,6 +600,9 @@ NewGCChunk(void) static void DestroyGCChunk(jsuword chunk) { +#ifdef MOZ_GCTIMER + JS_ATOMIC_INCREMENT(&destroyChunkCount); +#endif JS_ASSERT((chunk & GC_ARENA_MASK) == 0); #if defined(XP_WIN) VirtualFree((void *) chunk, 0, MEM_RELEASE); @@ -2793,6 +2803,46 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind, JSGCArena **emptyArenas) nlivearenas, nkilledarenas, nthings)); } +#ifdef MOZ_GCTIMER +struct GCTimer { + uint64 enter; + uint64 startMark; + uint64 startSweep; + uint64 sweepObjectEnd; + uint64 sweepStringEnd; + uint64 sweepDoubleEnd; + uint64 sweepDestroyEnd; + uint64 end; +}; + +void dumpGCTimer(GCTimer *gcT, uint64 firstEnter, bool lastGC) +{ + static FILE *gcFile; + + if (!gcFile) { + gcFile = fopen("gcTimer.dat", "w"); + JS_ASSERT(gcFile); + + fprintf(gcFile, " AppTime, Total, Mark, Sweep, FinObj, "); + fprintf(gcFile, "FinStr, FinDbl, Destroy, newChunks, destoyChunks\n"); + } + fprintf(gcFile, "%12.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %7.1f, ", + (double)(gcT->enter - firstEnter) / 1E6, + (double)(gcT->end-gcT->enter) / 1E6, + (double)(gcT->startSweep - gcT->startMark) / 1E6, + (double)(gcT->sweepDestroyEnd - gcT->startSweep) / 1E6, + (double)(gcT->sweepObjectEnd - gcT->startSweep) / 1E6, + (double)(gcT->sweepStringEnd - gcT->sweepObjectEnd) / 1E6, + (double)(gcT->sweepDoubleEnd - gcT->sweepStringEnd) / 1E6, + (double)(gcT->sweepDestroyEnd - gcT->sweepDoubleEnd) / 1E6); + fprintf(gcFile, "%10d, %10d \n", newChunkCount, destroyChunkCount); + fflush(gcFile); + + if (lastGC) + fclose(gcFile); +} +#endif + /* * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with * rt->gcLock already held, so the lock should be kept on return. @@ -2833,6 +2883,16 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) */ if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT) return; + +#ifdef MOZ_GCTIMER + static uint64 firstEnter = rdtsc(); + GCTimer gcTimer; + memset(&gcTimer, 0, sizeof(GCTimer)); +# define TIMESTAMP(x) (x = rdtsc()) +#else +# define TIMESTAMP(x) ((void) 0) +#endif + TIMESTAMP(gcTimer.enter); restart_at_beginning: /* @@ -3078,7 +3138,6 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) acx->purge(); } - #ifdef JS_TRACER if (gckind == GC_LAST_CONTEXT) { /* Clear builtin functions, which are recreated on demand. */ @@ -3090,6 +3149,8 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) if (!(gckind & GC_KEEP_ATOMS)) JS_CLEAR_WEAK_ROOTS(&cx->weakRoots); + TIMESTAMP(gcTimer.startMark); + restart: rt->gcNumber++; JS_ASSERT(!rt->gcUnmarkedArenaStackTop); @@ -3152,6 +3213,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) * JSString* assuming that they are unique. This works since the * atomization API must not be called during GC. */ + TIMESTAMP(gcTimer.startSweep); js_SweepAtomState(cx); /* Finalize iterator states before the objects they iterate over. */ @@ -3189,6 +3251,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) #if JS_HAS_XML_SUPPORT FinalizeArenaList(cx, FINALIZE_XML, &emptyArenas); #endif + TIMESTAMP(gcTimer.sweepObjectEnd); /* * We sweep the deflated cache before we finalize the strings so the @@ -3204,6 +3267,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) FinalizeArenaList (cx, i, &emptyArenas); } + TIMESTAMP(gcTimer.sweepStringEnd); ap = &rt->gcDoubleArenaList.head; METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0)); @@ -3231,7 +3295,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) METER(UpdateArenaStats(&rt->gcStats.doubleArenaStats, nlivearenas, nkilledarenas, nthings)); rt->gcDoubleArenaList.cursor = rt->gcDoubleArenaList.head; - + TIMESTAMP(gcTimer.sweepDoubleEnd); /* * Sweep the runtime's property tree after finalizing objects, in case any * had watchpoints referencing tree nodes. @@ -3251,6 +3315,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) * use js_IsAboutToBeFinalized(). */ DestroyGCArenas(rt, emptyArenas); + TIMESTAMP(gcTimer.sweepDestroyEnd); #ifdef JS_THREADSAFE cx->submitDeallocatorTask(); @@ -3358,4 +3423,12 @@ out: JS_UNKEEP_ATOMS(rt); } } + TIMESTAMP(gcTimer.end); + +#ifdef MOZ_GCTIMER + if (gcTimer.startMark > 0) + dumpGCTimer(&gcTimer, firstEnter, gckind == GC_LAST_CONTEXT); + newChunkCount = 0; + destroyChunkCount = 0; +#endif } From 403633697e91385854e5905055b2bd0273fad31c Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 26 Mar 2010 09:01:01 -0500 Subject: [PATCH 145/213] Bug 500431 part 4 - Encapsulate PropertyCacheEntry::pcval. r=brendan. --- js/src/jsinterp.cpp | 14 +++---- js/src/jsops.cpp | 52 ++++++++++++------------- js/src/jspropertycache.cpp | 22 ++++++----- js/src/jspropertycache.h | 78 ++++++++++++++++++++------------------ js/src/jstracer.cpp | 58 ++++++++++++++-------------- js/src/jstracer.h | 6 +-- 6 files changed, 118 insertions(+), 112 deletions(-) diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index fa4ae1ce8755..79a6f626fbc7 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -2252,23 +2252,23 @@ AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs, JS_ASSERT(pobj == found); JSScopeProperty *sprop = (JSScopeProperty *) prop; - if (PCVAL_IS_SLOT(entry->vword)) { - JS_ASSERT(PCVAL_TO_SLOT(entry->vword) == sprop->slot); + if (entry->vword.isSlot()) { + JS_ASSERT(entry->vword.toSlot() == sprop->slot); JS_ASSERT(!sprop->isMethod()); - } else if (PCVAL_IS_SPROP(entry->vword)) { - JS_ASSERT(PCVAL_TO_SPROP(entry->vword) == sprop); + } else if (entry->vword.isSprop()) { + JS_ASSERT(entry->vword.toSprop() == sprop); JS_ASSERT_IF(sprop->isMethod(), sprop->methodValue() == LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)); } else { jsval v; - JS_ASSERT(PCVAL_IS_OBJECT(entry->vword)); - JS_ASSERT(entry->vword != PCVAL_NULL); + JS_ASSERT(entry->vword.isObject()); + JS_ASSERT(!entry->vword.isNull()); JS_ASSERT(OBJ_SCOPE(pobj)->brandedOrHasMethodBarrier()); JS_ASSERT(sprop->hasDefaultGetterOrIsMethod()); JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))); v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); JS_ASSERT(VALUE_IS_FUNCTION(cx, v)); - JS_ASSERT(PCVAL_TO_OBJECT(entry->vword) == JSVAL_TO_OBJECT(v)); + JS_ASSERT(entry->vword.toObject() == JSVAL_TO_OBJECT(v)); if (sprop->isMethod()) { JS_ASSERT(js_CodeSpec[*regs.pc].format & JOF_CALLOP); diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 3991155c5812..2bb769ded0ce 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1223,8 +1223,8 @@ BEGIN_CASE(JSOP_NAMEDEC) JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) { - slot = PCVAL_TO_SLOT(entry->vword); + if (obj == obj2 && entry->vword.isSlot()) { + slot = entry->vword.toSlot(); JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot); rval = LOCKED_OBJ_GET_SLOT(obj, slot); if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { @@ -1487,15 +1487,15 @@ BEGIN_CASE(JSOP_GETXPROP) JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); - if (PCVAL_IS_OBJECT(entry->vword)) { - rval = PCVAL_OBJECT_TO_JSVAL(entry->vword); - } else if (PCVAL_IS_SLOT(entry->vword)) { - slot = PCVAL_TO_SLOT(entry->vword); + if (entry->vword.isObject()) { + rval = entry->vword.toJsval(); + } else if (entry->vword.isSlot()) { + slot = entry->vword.toSlot(); JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); rval = LOCKED_OBJ_GET_SLOT(obj2, slot); } else { - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); NATIVE_GET(cx, obj, obj2, sprop, fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, &rval); @@ -1583,15 +1583,15 @@ BEGIN_CASE(JSOP_CALLPROP) JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); - if (PCVAL_IS_OBJECT(entry->vword)) { - rval = PCVAL_OBJECT_TO_JSVAL(entry->vword); - } else if (PCVAL_IS_SLOT(entry->vword)) { - slot = PCVAL_TO_SLOT(entry->vword); + if (entry->vword.isObject()) { + rval = entry->vword.toJsval(); + } else if (entry->vword.isSlot()) { + slot = entry->vword.toSlot(); JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); rval = LOCKED_OBJ_GET_SLOT(obj2, slot); } else { - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); NATIVE_GET(cx, obj, obj2, sprop, JSGET_NO_METHOD_BARRIER, &rval); } STORE_OPND(-1, rval); @@ -1709,8 +1709,8 @@ BEGIN_CASE(JSOP_SETMETHOD) * added directly to obj by this set, or on an existing "own" * property, or on a prototype property that has a setter. */ - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); JS_ASSERT(sprop->writable()); JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0); @@ -1843,8 +1843,8 @@ BEGIN_CASE(JSOP_SETMETHOD) ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); sprop = NULL; if (obj == obj2) { - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); JS_ASSERT(sprop->writable()); JS_ASSERT(!OBJ_SCOPE(obj2)->sealed()); NATIVE_SET(cx, obj, sprop, entry, &rval); @@ -2295,20 +2295,20 @@ BEGIN_CASE(JSOP_CALLNAME) JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); if (!atom) { ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - if (PCVAL_IS_OBJECT(entry->vword)) { - rval = PCVAL_OBJECT_TO_JSVAL(entry->vword); + if (entry->vword.isObject()) { + rval = entry->vword.toJsval(); goto do_push_rval; } - if (PCVAL_IS_SLOT(entry->vword)) { - slot = PCVAL_TO_SLOT(entry->vword); + if (entry->vword.isSlot()) { + slot = entry->vword.toSlot(); JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); rval = LOCKED_OBJ_GET_SLOT(obj2, slot); goto do_push_rval; } - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); goto do_native_get; } } else { @@ -3400,8 +3400,8 @@ BEGIN_CASE(JSOP_INITMETHOD) PCMETER(cache->pchits++); PCMETER(cache->inipchits++); - JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); - sprop = PCVAL_TO_SPROP(entry->vword); + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); JS_ASSERT(sprop->writable()); /* diff --git a/js/src/jspropertycache.cpp b/js/src/jspropertycache.cpp index 72c93a6877b1..c89d9be2375f 100644 --- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -44,6 +44,8 @@ using namespace js; +JS_STATIC_ASSERT(sizeof(PCVal) == sizeof(jsuword)); + JS_REQUIRES_STACK PropertyCacheEntry * PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoIndex, JSObject *pobj, JSScopeProperty *sprop, JSBool adding) @@ -53,7 +55,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI jsuword kshape, vshape; JSOp op; const JSCodeSpec *cs; - jsuword vword; + PCVal vword; PropertyCacheEntry *entry; JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); @@ -148,7 +150,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI v = sprop->methodValue(); JS_ASSERT(VALUE_IS_FUNCTION(cx, v)); JS_ASSERT(v == LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)); - vword = JSVAL_OBJECT_TO_PCVAL(v); + vword.setObject(JSVAL_TO_OBJECT(v)); break; } @@ -182,7 +184,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI if (!scope->brand(cx, sprop->slot, v)) return JS_NO_PROP_CACHE_FILL; } - vword = JSVAL_OBJECT_TO_PCVAL(v); + vword.setObject(JSVAL_TO_OBJECT(v)); break; } } @@ -193,10 +195,10 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI sprop->hasDefaultGetter() && SPROP_HAS_VALID_SLOT(sprop, scope)) { /* Great, let's cache sprop's slot and use it on cache hit. */ - vword = SLOT_TO_PCVAL(sprop->slot); + vword.setSlot(sprop->slot); } else { /* Best we can do is to cache sprop (still a nice speedup). */ - vword = SPROP_TO_PCVAL(sprop); + vword.setSprop(sprop); if (adding && sprop == scope->lastProperty() && scope->shape == sprop->shape) { @@ -290,7 +292,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); entry = &table[hash(pc, kshape)]; - PCMETER(PCVAL_IS_NULL(entry->vword) || recycles++); + PCMETER(entry->vword.isNull() || recycles++); entry->assign(pc, kshape, vshape, scopeIndex, protoIndex, vword); empty = false; @@ -416,13 +418,11 @@ PropertyCache::assertEmpty() JS_ASSERT(!table[i].kpc); JS_ASSERT(!table[i].kshape); JS_ASSERT(!table[i].vcap); - JS_ASSERT(!table[i].vword); + JS_ASSERT(table[i].vword.isNull()); } } #endif -JS_STATIC_ASSERT(PCVAL_NULL == 0); - void PropertyCache::purge(JSContext *cx) { @@ -432,6 +432,7 @@ PropertyCache::purge(JSContext *cx) } PodArrayZero(table); + JS_ASSERT(table[0].vword.isNull()); empty = true; #ifdef JS_PROPERTY_CACHE_METERING @@ -497,7 +498,8 @@ PropertyCache::purgeForScript(JSScript *script) if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { entry->kpc = NULL; #ifdef DEBUG - entry->kshape = entry->vcap = entry->vword = 0; + entry->kshape = entry->vcap = 0; + entry->vword.setNull(); #endif } } diff --git a/js/src/jspropertycache.h b/js/src/jspropertycache.h index add27dc088d4..05081a8c42f4 100644 --- a/js/src/jspropertycache.h +++ b/js/src/jspropertycache.h @@ -69,12 +69,51 @@ enum { const uint32 SHAPE_OVERFLOW_BIT = JS_BIT(32 - PCVCAP_TAGBITS); +/* + * Property cache value. This is simply a tagged union: + * PCVal = (JSObject * | uint32 | JSScopeProperty *). + * It is the type of PropertyCacheEntry::vword and combines with the tag bits + * of PropertyCacheEntry::vcap to tell how to get or set the property, once a + * property cache hit is validated. + * + * PropertyCache::purge depends on the bit-pattern of a null PCVal being 0. + */ +class PCVal +{ + private: + enum { + OBJECT = 0, + SLOT = 1, + SPROP = 2, + TAG = 3 + }; + + jsuword v; + + public: + bool isNull() const { return v == 0; } + void setNull() { v = 0; } + + bool isObject() const { return (v & TAG) == OBJECT; } + JSObject *toObject() const { JS_ASSERT(isObject()); return reinterpret_cast(v); } + jsval toJsval() const { return OBJECT_TO_JSVAL(toObject()); } + void setObject(JSObject *obj) { v = reinterpret_cast(obj); } + + bool isSlot() const { return v & SLOT; } + uint32 toSlot() const { JS_ASSERT(isSlot()); return uint32(v) >> 1; } + void setSlot(uint32 slot) { v = (jsuword(slot) << 1) | SLOT; } + + bool isSprop() const { return (v & TAG) == SPROP; } + JSScopeProperty *toSprop() const { JS_ASSERT(isSprop()); return reinterpret_cast(v & ~TAG); } + void setSprop(JSScopeProperty *sprop) { JS_ASSERT(sprop); v = reinterpret_cast(sprop) | SPROP; } +}; + struct PropertyCacheEntry { jsbytecode *kpc; /* pc of cache-testing bytecode */ jsuword kshape; /* shape of direct (key) object */ jsuword vcap; /* value capability, see above */ - jsuword vword; /* value word, see PCVAL_* below */ + PCVal vword; /* value word, see PCVal above */ bool adding() const { return vcapTag() == 0 && kshape != vshape(); } bool directHit() const { return vcapTag() == 0 && kshape == vshape(); } @@ -85,7 +124,7 @@ struct PropertyCacheEntry jsuword protoIndex() const { return vcap & PCVCAP_PROTOMASK; } void assign(jsbytecode *kpc, jsuword kshape, jsuword vshape, - uintN scopeIndex, uintN protoIndex, jsuword vword) { + uintN scopeIndex, uintN protoIndex, PCVal vword) { JS_ASSERT(kshape < SHAPE_OVERFLOW_BIT); JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT); JS_ASSERT(scopeIndex <= PCVCAP_SCOPEMASK); @@ -195,41 +234,6 @@ struct PropertyCache #endif }; -/* - * Property cache value tagging/untagging macros. - */ -enum { - PCVAL_OBJECT = 0, - PCVAL_SLOT = 1, - PCVAL_SPROP = 2, - - PCVAL_TAGBITS = 2, - PCVAL_TAGMASK = JS_BITMASK(PCVAL_TAGBITS), - - PCVAL_NULL = 0 -}; - -inline jsuword PCVAL_TAG(jsuword v) { return v & PCVAL_TAGMASK; } -inline jsuword PCVAL_CLRTAG(jsuword v) { return v & ~jsuword(PCVAL_TAGMASK); } -inline jsuword PCVAL_SETTAG(jsuword v, jsuword t) { return v | t; } - -inline bool PCVAL_IS_NULL(jsuword v) { return v == PCVAL_NULL; } - -inline bool PCVAL_IS_OBJECT(jsuword v) { return PCVAL_TAG(v) == PCVAL_OBJECT; } -inline JSObject *PCVAL_TO_OBJECT(jsuword v) { JS_ASSERT(PCVAL_IS_OBJECT(v)); return (JSObject *) v; } -inline jsuword OBJECT_TO_PCVAL(JSObject *obj) { return jsuword(obj); } - -inline jsval PCVAL_OBJECT_TO_JSVAL(jsuword v) { return OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)); } -inline jsuword JSVAL_OBJECT_TO_PCVAL(jsval v) { return OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)); } - -inline bool PCVAL_IS_SLOT(jsuword v) { return v & PCVAL_SLOT; } -inline jsuint PCVAL_TO_SLOT(jsuword v) { JS_ASSERT(PCVAL_IS_SLOT(v)); return jsuint(v) >> 1; } -inline jsuword SLOT_TO_PCVAL(jsuint i) { return (jsuword(i) << 1) | PCVAL_SLOT; } - -inline bool PCVAL_IS_SPROP(jsuword v) { return PCVAL_TAG(v) == PCVAL_SPROP; } -inline JSScopeProperty *PCVAL_TO_SPROP(jsuword v) { JS_ASSERT(PCVAL_IS_SPROP(v)); return (JSScopeProperty *) PCVAL_CLRTAG(v); } -inline jsuword SPROP_TO_PCVAL(JSScopeProperty *sprop) { return PCVAL_SETTAG(jsuword(sprop), PCVAL_SPROP); } - } /* namespace js */ #endif /* jspropertycache_h___ */ diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index d751c3381ba2..1c25e4ca1ed5 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -9145,7 +9145,7 @@ TraceRecorder::guardNativePropertyOp(JSObject* aobj, LIns* map_ins) } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval) +TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, PCVal& pcval) { jsbytecode* pc = cx->fp->regs->pc; JS_ASSERT(*pc != JSOP_INITPROP && *pc != JSOP_INITMETHOD && @@ -9223,8 +9223,8 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 // the global it's assigning does not yet exist, create it. obj2 = obj; - // Use PCVAL_NULL to return "no such property" to our caller. - pcval = PCVAL_NULL; + // Use a null pcval to return "no such property" to our caller. + pcval.setNull(); return ARECORD_CONTINUE; } @@ -9250,7 +9250,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, JSObject* aobj, JSObject* obj2, PropertyCacheEntry* entry, - jsuword& pcval) + PCVal& pcval) { VMSideExit* exit = snapshot(BRANCH_EXIT); @@ -11292,7 +11292,7 @@ TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* spr // Guard before anything else. LIns* map_ins = map(obj_ins); CHECK_STATUS(guardNativePropertyOp(obj, map_ins)); - jsuword pcval; + PCVal pcval; CHECK_STATUS(guardPropertyCacheHit(obj_ins, map_ins, obj, obj2, entry, pcval)); JS_ASSERT(scope->object == obj2); JS_ASSERT(scope->hasProperty(sprop)); @@ -12202,16 +12202,16 @@ TraceRecorder::record_JSOP_CALLNAME() LIns* obj_ins = INS_CONSTOBJ(globalObj); JSObject* obj2; - jsuword pcval; + PCVal pcval; CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); - if (PCVAL_IS_NULL(pcval) || !PCVAL_IS_OBJECT(pcval)) + if (pcval.isNull() || !pcval.isObject()) RETURN_STOP_A("callee is not an object"); - JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval))); + JS_ASSERT(HAS_FUNCTION_CLASS(pcval.toObject())); - stack(0, INS_CONSTOBJ(PCVAL_TO_OBJECT(pcval))); + stack(0, INS_CONSTOBJ(pcval.toObject())); stack(1, obj_ins); return ARECORD_CONTINUE; } @@ -12757,7 +12757,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) uint32 slot; JSObject* obj2; - jsuword pcval; + PCVal pcval; /* * Property cache ensures that we are dealing with an existing property, @@ -12766,7 +12766,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); /* Abort if property doesn't exist (interpreter will report an error.) */ - if (PCVAL_IS_NULL(pcval)) + if (pcval.isNull()) RETURN_STOP_A("named property not found"); /* Insist on obj being the directly addressed object. */ @@ -12774,15 +12774,15 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) RETURN_STOP_A("name() hit prototype chain"); /* Don't trace getter or setter calls, our caller wants a direct slot. */ - if (PCVAL_IS_SPROP(pcval)) { - JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval); + if (pcval.isSprop()) { + JSScopeProperty* sprop = pcval.toSprop(); if (!isValidSlot(OBJ_SCOPE(obj), sprop)) RETURN_STOP_A("name() not accessing a valid slot"); slot = sprop->slot; } else { - if (!PCVAL_IS_SLOT(pcval)) + if (!pcval.isSlot()) RETURN_STOP_A("PCE is not a slot"); - slot = PCVAL_TO_SLOT(pcval); + slot = pcval.toSlot(); } if (!lazilyImportGlobalSlot(slot)) @@ -12831,11 +12831,11 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, * and guards the shape for us. */ JSObject* obj2; - jsuword pcval; + PCVal pcval; CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); /* Check for non-existent property reference, which results in undefined. */ - if (PCVAL_IS_NULL(pcval)) { + if (pcval.isNull()) { if (slotp) RETURN_STOP_A("property not found"); @@ -12876,7 +12876,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, jsuword pcval, +TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcval, uint32 *slotp, LIns** v_insp, jsval *outp) { const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc]; @@ -12887,8 +12887,8 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, jsuword pc uint32 slot; bool isMethod; - if (PCVAL_IS_SPROP(pcval)) { - sprop = PCVAL_TO_SPROP(pcval); + if (pcval.isSprop()) { + sprop = pcval.toSprop(); JS_ASSERT(OBJ_SCOPE(obj2)->hasProperty(sprop)); if (setflags && !sprop->hasDefaultSetter()) @@ -12910,9 +12910,9 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, jsuword pc isMethod = sprop->isMethod(); JS_ASSERT_IF(isMethod, OBJ_SCOPE(obj2)->hasMethodBarrier()); } else { - if (!PCVAL_IS_SLOT(pcval)) + if (!pcval.isSlot()) RETURN_STOP_A("PCE is not a slot"); - slot = PCVAL_TO_SLOT(pcval); + slot = pcval.toSlot(); sprop = NULL; isMethod = false; } @@ -14606,27 +14606,27 @@ TraceRecorder::record_JSOP_CALLPROP() } JSObject* obj2; - jsuword pcval; + PCVal pcval; CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); - if (PCVAL_IS_OBJECT(pcval)) { - if (PCVAL_IS_NULL(pcval)) + if (pcval.isObject()) { + if (pcval.isNull()) RETURN_STOP_A("callprop of missing method"); - JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval))); + JS_ASSERT(HAS_FUNCTION_CLASS(pcval.toObject())); if (JSVAL_IS_PRIMITIVE(l)) { - JSFunction* fun = GET_FUNCTION_PRIVATE(cx, PCVAL_TO_OBJECT(pcval)); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, pcval.toObject()); if (!PRIMITIVE_THIS_TEST(fun, l)) RETURN_STOP_A("callee does not accept primitive |this|"); } - set(&l, INS_CONSTOBJ(PCVAL_TO_OBJECT(pcval))); + set(&l, INS_CONSTOBJ(pcval.toObject())); } else { if (JSVAL_IS_PRIMITIVE(l)) RETURN_STOP_A("callprop of primitive method"); - JS_ASSERT_IF(PCVAL_IS_SPROP(pcval), !PCVAL_TO_SPROP(pcval)->isMethod()); + JS_ASSERT_IF(pcval.isSprop(), !pcval.toSprop()->isMethod()); AbortableRecordingStatus status = propTail(obj, obj_ins, obj2, pcval, NULL, NULL, &l); if (status != ARECORD_CONTINUE) diff --git a/js/src/jstracer.h b/js/src/jstracer.h index faa40ef93d12..dda23bb92b64 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1208,7 +1208,7 @@ class TraceRecorder JS_REQUIRES_STACK bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins, nanojit::LIns*& ops_ins, size_t op_offset = 0); JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, - JSObject*& obj2, jsuword& pcval); + JSObject*& obj2, PCVal& pcval); JS_REQUIRES_STACK RecordingStatus guardNativePropertyOp(JSObject* aobj, nanojit::LIns* map_ins); JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins, @@ -1216,7 +1216,7 @@ class TraceRecorder JSObject* aobj, JSObject* obj2, PropertyCacheEntry* entry, - jsuword& pcval); + PCVal& pcval); void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot, nanojit::LIns* v_ins); @@ -1249,7 +1249,7 @@ class TraceRecorder uint32 *slotp, nanojit::LIns** v_insp, jsval* outp); JS_REQUIRES_STACK AbortableRecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins, - JSObject* obj2, jsuword pcval, + JSObject* obj2, PCVal pcval, uint32 *slotp, nanojit::LIns** v_insp, jsval* outp); JS_REQUIRES_STACK RecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp, From 438b2cc4eab3208e8873020aab030b1f08e57055 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 26 Mar 2010 09:58:33 -0500 Subject: [PATCH 146/213] Fixed regression with recursive scripts missing a return (bug 552196, r=gal). --- js/src/jsrecursion.cpp | 48 ++++++++++++++++++---- js/src/trace-test/tests/basic/bug552196.js | 12 ++++++ 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 js/src/trace-test/tests/basic/bug552196.js diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index 8ecbfffaf4c6..cdcbf98af03f 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -309,9 +309,8 @@ TraceRecorder::upRecursion() LIns* rval_ins; if (*cx->fp->regs->pc == JSOP_RETURN) { - rval_ins = (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) ? - get(&stackval(-1)) : - NULL; + JS_ASSERT(!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT); + rval_ins = get(&stackval(-1)); JS_ASSERT(rval_ins); } else { rval_ins = INS_VOID(); @@ -355,6 +354,27 @@ public: unsigned slurpFailSlot; }; +/* + * The three types of anchors that can cause this type of trace to be built are: + * RECURSIVE_SLURP_MISMATCH_EXIT + * RECURSIVE_SLURP_FAIL_EXIT + * RECURSIVE_EMPTY_RP_EXIT + * + * EMPTY_RP means that recursion is unwinding, but there are no more frames. + * This triggers a "slurp trace" to be built. A slurp trace does three things: + * 1) Checks to see if cx->fp returns to the same point the recursive trace + * is trying to unwind to. + * 2) Pops the inline frame cx->fp, such that cx->fp is now cx->fp->down. + * 3) Converts the new top-frame slots/sp into the tracer frame. + * + * SLURP_MISMATCH means that while trying to convert an interpreter frame, + * it is owned by the same script, but does not return to the same pc. At this + * point the frame has not been popped yet. + * + * SLURP_FAIL means that the interpreter frame has been popped, the return + * value has been written to the native stack, but there was a type mismatch + * while unboxing the interpreter slots. + */ JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::slurpDownFrames(jsbytecode* return_pc) { @@ -501,12 +521,24 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) TraceType returnType = exit->stackTypeMap()[downPostSlots]; if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) { - rval_ins = get(&stackval(-1)); - if (returnType == TT_INT32) { - JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32); - JS_ASSERT(isPromoteInt(rval_ins)); - rval_ins = demote(lir, rval_ins); + /* + * It is safe to read cx->fp->regs->pc here because the frame hasn't + * been popped yet. We're guaranteed to have a return or stop. + */ + JSOp op = JSOp(*cx->fp->regs->pc); + JS_ASSERT(op == JSOP_RETURN || op == JSOP_STOP); + + if (op == JSOP_RETURN) { + rval_ins = get(&stackval(-1)); + if (returnType == TT_INT32) { + JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32); + JS_ASSERT(isPromoteInt(rval_ins)); + rval_ins = demote(lir, rval_ins); + } + } else { + rval_ins = INS_VOID(); } + /* * The return value must be written out early, before slurping can fail, * otherwise it will not be available when there's a type mismatch. diff --git a/js/src/trace-test/tests/basic/bug552196.js b/js/src/trace-test/tests/basic/bug552196.js new file mode 100644 index 000000000000..d52623485152 --- /dev/null +++ b/js/src/trace-test/tests/basic/bug552196.js @@ -0,0 +1,12 @@ +(Function("\ + for (a = 0; a < 5; a++)\n\ + (function f(b) {\n\ + if (b > 0) {\n\ + f(b - 1)\n\ + }\n\ + })\n\ + (3)\n\ +"))() + +/* Don't assert. */ + From e21a5b0f346310b3552a15fc7f16af914f37ea73 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 26 Mar 2010 15:32:35 -0700 Subject: [PATCH 147/213] Revert strict-aliasing disabling now that n810 has shown not to improve without it. Also change from -Wstrict-aliasing=2 to -Wstrict-aliasing=3; gcc claims the latter gives more precise warnings with fewer mistakes, and I don't think we care that much about it being a little slower, for only the files in SpiderMonkey. --- js/src/config.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/config.mk b/js/src/config.mk index 2a3eae78fed1..f3f802e9593d 100644 --- a/js/src/config.mk +++ b/js/src/config.mk @@ -127,9 +127,9 @@ INTERP_OPTIMIZER = -O2 -GL BUILTINS_OPTIMIZER = -O2 -GL LDFLAGS += -LTCG else -OPTIMIZER = -Os -fno-exceptions -fno-rtti -BUILTINS_OPTIMIZER = -O9 -fno-exceptions -fno-rtti -INTERP_OPTIMIZER = -O3 -fno-exceptions -fno-rtti +OPTIMIZER = -Os -fno-exceptions -fno-rtti -fstrict-aliasing -Wstrict-aliasing=3 +BUILTINS_OPTIMIZER = -O9 -fno-exceptions -fno-rtti -fstrict-aliasing +INTERP_OPTIMIZER = -O3 -fno-exceptions -fno-rtti -fstrict-aliasing endif DEFINES += -UDEBUG -DNDEBUG -UDEBUG_$(USER) OBJDIR_TAG = _OPT @@ -139,7 +139,7 @@ OPTIMIZER = -Zi INTERP_OPTIMIZER = -Zi BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER) else -OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti -Wstrict-aliasing=2 +OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti -Wstrict-aliasing=3 INTERP_OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER) endif From 1066acafbbc4f05de897a5a35e702c49f5108a26 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 26 Mar 2010 18:01:54 -0700 Subject: [PATCH 148/213] Backed out changeset e7065853ef79; I'll be repushing this incrementally, attempting to find the precise place where things go bad, in the near future. Happy days are here again! :-\ --- content/canvas/src/CustomQS_WebGL.h | 30 +- dom/base/nsJSEnvironment.cpp | 11 +- dom/base/nsJSEnvironment.h | 9 +- js/ctypes/Function.cpp | 2 +- js/src/jsapi.cpp | 111 ++--- js/src/jsarray.cpp | 465 ++++++++++-------- js/src/jscntxt.h | 460 +++++++---------- js/src/jscntxtinlines.h | 147 ------ js/src/jsdbgapi.cpp | 4 +- js/src/jsexn.cpp | 265 +++++----- js/src/jsfun.cpp | 58 ++- js/src/jsgc.cpp | 103 ++-- js/src/jsgc.h | 19 - js/src/jsinterp.cpp | 4 +- js/src/jsiter.cpp | 49 +- js/src/jsnum.cpp | 6 +- js/src/jsobj.cpp | 122 +++-- js/src/jsobj.h | 4 +- js/src/jsobjinlines.h | 30 -- js/src/json.cpp | 119 +++-- js/src/json.h | 2 +- js/src/jsopcode.cpp | 4 +- js/src/jsparse.cpp | 22 +- js/src/jsparse.h | 13 +- js/src/jsprvtd.h | 25 + js/src/jsregexp.cpp | 9 +- js/src/jsregexp.h | 6 +- js/src/jsscript.cpp | 8 +- js/src/jsstr.cpp | 4 +- js/src/jstracer.cpp | 23 +- js/src/jstypedarray.cpp | 10 +- js/src/jsutil.h | 4 +- js/src/jsvector.h | 5 +- js/src/jsxml.cpp | 444 +++++++++++------ js/src/jsxml.h | 54 +- .../xpconnect/src/XPCChromeObjectWrapper.cpp | 15 +- .../xpconnect/src/XPCCrossOriginWrapper.cpp | 6 +- js/src/xpconnect/src/XPCNativeWrapper.cpp | 2 +- .../xpconnect/src/XPCSafeJSObjectWrapper.cpp | 6 +- js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp | 8 +- js/src/xpconnect/src/XPCWrapper.cpp | 6 +- js/src/xpconnect/src/qsgen.py | 2 +- js/src/xpconnect/src/xpcconvert.cpp | 10 +- js/src/xpconnect/src/xpcquickstubs.cpp | 4 +- js/src/xpconnect/src/xpcquickstubs.h | 2 +- .../xpconnect/src/xpcwrappednativejsops.cpp | 7 +- js/src/xpconnect/tests/TestXPC.cpp | 2 +- modules/plugin/base/src/nsJSNPRuntime.cpp | 46 +- modules/plugin/base/src/nsNPAPIPlugin.cpp | 2 +- xpinstall/src/nsXPITriggerInfo.cpp | 2 +- 50 files changed, 1388 insertions(+), 1383 deletions(-) delete mode 100644 js/src/jscntxtinlines.h diff --git a/content/canvas/src/CustomQS_WebGL.h b/content/canvas/src/CustomQS_WebGL.h index abde159d3ffa..2d479060e59d 100644 --- a/content/canvas/src/CustomQS_WebGL.h +++ b/content/canvas/src/CustomQS_WebGL.h @@ -68,7 +68,7 @@ nsICanvasRenderingContextWebGL_BufferData(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -134,7 +134,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -204,7 +204,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -306,7 +306,7 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -407,7 +407,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -427,7 +427,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -477,7 +477,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -497,7 +497,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -547,7 +547,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -571,7 +571,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -618,7 +618,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -638,7 +638,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -780,7 +780,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -835,7 +835,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -890,7 +890,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj return JSVAL_VOID; } - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 1044d6bccf65..4c1ad2506d53 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2111,13 +2111,14 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler return NS_OK; } - js::AutoValueRooter targetVal(mContext, JSVAL_VOID); + jsval targetVal = JSVAL_VOID; + JSAutoTempValueRooter tvr(mContext, 1, &targetVal); JSObject* target = nsnull; nsresult rv = JSObjectFromInterface(aTarget, aScope, &target); NS_ENSURE_SUCCESS(rv, rv); - targetVal.setObject(target); + targetVal = OBJECT_TO_JSVAL(target); jsval rval = JSVAL_VOID; @@ -2142,7 +2143,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval *argv = nsnull; js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget @@ -2654,7 +2655,7 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg JSAutoRequest ar(mContext); js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, @@ -2689,7 +2690,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter) + js::LazilyConstructed &aRooter) { nsresult rv = NS_OK; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index c7080ae51821..785d53c109e3 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -49,11 +49,8 @@ class nsIXPConnectJSObjectHolder; class nsAutoPoolRelease; -namespace js { -class AutoValueRooter; -class AutoArrayRooter; -template class LazilyConstructed; -} +class JSAutoTempValueRooter; +namespace js { template class LazilyConstructed; } class nsJSContext : public nsIScriptContext, public nsIXPCScriptNotify @@ -218,7 +215,7 @@ protected: PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter); + js::LazilyConstructed &aRooter); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/ctypes/Function.cpp b/js/ctypes/Function.cpp index 45e69f43f16c..c30efc5cf964 100644 --- a/js/ctypes/Function.cpp +++ b/js/ctypes/Function.cpp @@ -624,7 +624,7 @@ Function::Create(JSContext* aContext, return NULL; JSObject* fnObj = JS_GetFunctionObject(fn); - js::AutoValueRooter fnRoot(aContext, fnObj); + JSAutoTempValueRooter fnRoot(aContext, fnObj); // stash a pointer to self, which Function::Call will need at call time if (!JS_SetReservedSlot(aContext, fnObj, 0, PRIVATE_TO_JSVAL(self.get()))) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index cb697a8bcc15..d47ccec6bcee 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -438,7 +438,7 @@ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *dp = js_ValueToNumber(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -454,7 +454,7 @@ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToECMAInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -464,7 +464,7 @@ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToECMAUint32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -474,7 +474,7 @@ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -484,7 +484,7 @@ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToUint16(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -3059,7 +3059,7 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->isMethod()) { - AutoScopePropertyRooter root(cx, sprop); + JSAutoTempValueRooter root(cx, sprop); JS_UNLOCK_OBJ(cx, obj2); *vp = sprop->methodValue(); return OBJ_SCOPE(obj2)->methodReadBarrier(cx, sprop, vp); @@ -3810,6 +3810,7 @@ JS_PUBLIC_API(JSIdArray *) JS_Enumerate(JSContext *cx, JSObject *obj) { jsint i, n; + jsval iter_state, num_properties; jsid id; JSIdArray *ida; jsval *vector; @@ -3817,11 +3818,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) CHECK_REQUEST(cx); ida = NULL; - AutoEnumStateRooter iterState(cx, obj); + iter_state = JSVAL_NULL; + JSAutoEnumStateRooter tvr(cx, obj, &iter_state); /* Get the number of properties to enumerate. */ - jsval num_properties; - if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) + if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties)) goto error; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); @@ -3841,11 +3842,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) i = 0; vector = &ida->vector[0]; for (;;) { - if (!obj->enumerate(cx, JSENUMERATE_NEXT, iterState.addr(), &id)) + if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id)) goto error; /* No more jsid's to enumerate ? */ - if (iterState.state() == JSVAL_NULL) + if (iter_state == JSVAL_NULL) break; if (i == ida->length) { @@ -3859,6 +3860,8 @@ JS_Enumerate(JSContext *cx, JSObject *obj) return SetIdArrayLength(cx, ida, i); error: + if (!JSVAL_IS_NULL(iter_state)) + obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); if (ida) JS_DestroyIdArray(cx, ida); return NULL; @@ -3942,7 +3945,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) * Note: we have to make sure that we root obj around the call to * JS_Enumerate to protect against multiple allocations under it. */ - AutoValueRooter tvr(cx, iterobj); + JSAutoTempValueRooter tvr(cx, iterobj); ida = JS_Enumerate(cx, obj); if (!ida) return NULL; @@ -4592,6 +4595,7 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, JS_PUBLIC_API(JSObject *) JS_NewScriptObject(JSContext *cx, JSScript *script) { + JSTempValueRooter tvr; JSObject *obj; CHECK_REQUEST(cx); @@ -4600,19 +4604,16 @@ JS_NewScriptObject(JSContext *cx, JSScript *script) JS_ASSERT(!script->u.object); - { - AutoScriptRooter root(cx, script); - - obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); - if (obj) { - obj->setPrivate(script); - script->u.object = obj; + JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + if (obj) { + obj->setPrivate(script); + script->u.object = obj; #ifdef CHECK_SCRIPT_OWNER - script->owner = NULL; + script->owner = NULL; #endif - } } - + JS_POP_TEMP_ROOT(cx, &tvr); return obj; } @@ -4690,6 +4691,7 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, const char *filename, uintN lineno) { JSFunction *fun; + JSTempValueRooter tvr; JSAtom *funAtom, *argAtom; uintN i; @@ -4707,48 +4709,47 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, if (!fun) goto out2; - { - AutoValueRooter tvr(cx, FUN_OBJECT(fun)); - MUST_FLOW_THROUGH("out"); - - for (i = 0; i < nargs; i++) { - argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); - if (!argAtom) { - fun = NULL; - goto out; - } - if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { - fun = NULL; - goto out; - } - } - - if (!JSCompiler::compileFunctionBody(cx, fun, principals, - chars, length, filename, lineno)) { + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); + for (i = 0; i < nargs; i++) { + argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); + if (!argAtom) { fun = NULL; goto out; } - - if (obj && funAtom && - !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), - NULL, NULL, JSPROP_ENUMERATE)) { + if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { fun = NULL; + goto out; } + } + + if (!JSCompiler::compileFunctionBody(cx, fun, principals, + chars, length, filename, lineno)) { + fun = NULL; + goto out; + } + + if (obj && + funAtom && + !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + NULL, NULL, JSPROP_ENUMERATE)) { + fun = NULL; + } #ifdef JS_SCOPE_DEPTH_METER - if (fun && obj) { - JSObject *pobj = obj; - uintN depth = 1; + if (fun && obj) { + JSObject *pobj = obj; + uintN depth = 1; - while ((pobj = pobj->getParent()) != NULL) - ++depth; - JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); - } + while ((pobj = pobj->getParent()) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } #endif - out: - cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; - } + out: + cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; + JS_POP_TEMP_ROOT(cx, &tvr); out2: LAST_FRAME_CHECKS(cx, fun); @@ -4936,7 +4937,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); JSBool ok = atom && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index d288561df8e0..edf0b43348c3 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -231,7 +231,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) return JS_TRUE; } - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr())) return JS_FALSE; @@ -405,7 +405,7 @@ EnsureCapacity(JSContext *cx, JSObject *obj, uint32 newcap, static bool ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp) { - AutoValueRooter dval(cx); + JSAutoTempValueRooter dval(cx); if (!js_NewDoubleInRootedValue(cx, index, dval.addr()) || !js_ValueToStringId(cx, dval.value(), idp)) { return JS_FALSE; @@ -450,7 +450,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, return JS_TRUE; } - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); *hole = JS_FALSE; if (!IndexToId(cx, obj, index, hole, idr.addr())) @@ -505,7 +505,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v) return JS_FALSE; } - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE)) return JS_FALSE; @@ -531,7 +531,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index) return JS_TRUE; } - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!IndexToId(cx, obj, index, NULL, idr.addr())) return JS_FALSE; @@ -573,7 +573,7 @@ JSBool js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) { JSErrorReporter older = JS_SetErrorReporter(cx, NULL); - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); JSBool ok = obj->getProperty(cx, id, tvr.addr()); JS_SetErrorReporter(cx, older); @@ -626,6 +626,9 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { jsuint newlen, oldlen, gap, index; jsval junk; + JSObject *iter; + JSTempValueRooter tvr; + JSBool ok; if (!obj->isArray()) { jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); @@ -635,30 +638,32 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) newlen = ValueIsLength(cx, vp); if (JSVAL_IS_NULL(*vp)) - return false; + return JS_FALSE; oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH]; if (oldlen == newlen) - return true; + return JS_TRUE; if (!IndexToValue(cx, newlen, vp)) - return false; + return JS_FALSE; if (oldlen < newlen) { obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; - return true; + return JS_TRUE; } if (obj->isDenseArray()) { /* Don't reallocate if we're not actually shrinking our slots. */ jsuint capacity = js_DenseArrayCapacity(obj); if (capacity > newlen && !ResizeSlots(cx, obj, capacity, newlen)) - return false; + return JS_FALSE; } else if (oldlen - newlen < (1 << 24)) { do { --oldlen; - if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, oldlen)) - return false; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !DeleteArrayElement(cx, obj, oldlen)) { + return JS_FALSE; + } } while (oldlen != newlen); } else { /* @@ -668,28 +673,33 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) * correspond to indexes in the half-open range [newlen, oldlen). See * bug 322135. */ - JSObject *iter = JS_NewPropertyIterator(cx, obj); + iter = JS_NewPropertyIterator(cx, obj); if (!iter) - return false; + return JS_FALSE; /* Protect iter against GC under JSObject::deleteProperty. */ - AutoValueRooter tvr(cx, iter); - + JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr); gap = oldlen - newlen; for (;;) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id)) - return false; + ok = (JS_CHECK_OPERATION_LIMIT(cx) && + JS_NextProperty(cx, iter, &id)); + if (!ok) + break; if (JSVAL_IS_VOID(id)) break; - if (js_IdIsIndex(id, &index) && index - newlen < gap && - !obj->deleteProperty(cx, id, &junk)) { - return false; + if (js_IdIsIndex(id, &index) && index - newlen < gap) { + ok = obj->deleteProperty(cx, id, &junk); + if (!ok) + break; } } + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; } obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; - return true; + return JS_TRUE; } /* @@ -1508,7 +1518,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, return true; } - AutoValueRooter tvr(cx, obj); + JSAutoTempValueRooter tvr(cx, obj); /* After this point, all paths exit through the 'out' label. */ MUST_FLOW_THROUGH("out"); @@ -1642,7 +1652,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva #ifdef DEBUG_jwalden { /* Verify that overwriteType and writeType were accurate. */ - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx, JSVAL_ZERO); for (jsuint i = 0; i < count; i++) { JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE); @@ -1708,12 +1718,12 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva JS_ASSERT(start == MAXINDEX); jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL}; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); if (!js_NewDoubleInRootedValue(cx, MAXINDEX, &tmp[0])) return JS_FALSE; jsdouble *dp = JSVAL_TO_DOUBLE(tmp[0]); JS_ASSERT(*dp == MAXINDEX); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); do { tmp[1] = *vector++; if (!js_ValueToStringId(cx, tmp[0], idr.addr()) || @@ -1759,7 +1769,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector, static JSString* FASTCALL Array_p_join(JSContext* cx, JSObject* obj, JSString *str) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!array_toString_sub(cx, obj, JS_FALSE, str, tvr.addr())) { SetBuiltinError(cx); return NULL; @@ -1770,7 +1780,7 @@ Array_p_join(JSContext* cx, JSObject* obj, JSString *str) static JSString* FASTCALL Array_p_toString(JSContext* cx, JSObject* obj) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) { SetBuiltinError(cx); return NULL; @@ -1842,7 +1852,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); for (jsuint i = 0, half = len / 2; i < half; i++) { JSBool hole, hole2; if (!JS_CHECK_OPERATION_LIMIT(cx) || @@ -2092,28 +2102,40 @@ JS_STATIC_ASSERT(JSVAL_NULL == 0); static JSBool array_sort(JSContext *cx, uintN argc, jsval *vp) { - jsval fval; + jsval *argv, fval, *vec, *mergesort_tmp, v; + JSObject *obj; + CompareArgs ca; jsuint len, newlen, i, undefs; + JSTempValueRooter tvr; + JSBool hole; + JSBool ok; size_t elemsize; JSString *str; - jsval *argv = JS_ARGV(cx, vp); + /* + * Optimize the default compare function case if all of obj's elements + * have values of type string. + */ + JSBool all_strings; + + argv = JS_ARGV(cx, vp); if (argc > 0) { if (JSVAL_IS_PRIMITIVE(argv[0])) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); - return false; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SORT_ARG); + return JS_FALSE; } fval = argv[0]; /* non-default compare function */ } else { fval = JSVAL_NULL; } - JSObject *obj = JS_THIS_OBJECT(cx, vp); + obj = JS_THIS_OBJECT(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &len)) - return false; + return JS_FALSE; if (len == 0) { *vp = OBJECT_TO_JSVAL(obj); - return true; + return JS_TRUE; } /* @@ -2123,16 +2145,19 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * malloc'd vector. */ #if JS_BITS_PER_WORD == 32 - if (size_t(len) > SIZE_MAX / (2 * sizeof(jsval))) { + if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) { js_ReportAllocationOverflow(cx); - return false; + return JS_FALSE; } #endif + vec = (jsval *) cx->malloc(2 * (size_t) len * sizeof(jsval)); + if (!vec) + return JS_FALSE; /* * Initialize vec as a root. We will clear elements of vec one by - * one while increasing the rooted amount of vec when we know that the - * property at the corresponding index exists and its value must be rooted. + * one while increasing tvr.count when we know that the property at + * the corresponding index exists and its value must be rooted. * * In this way when sorting a huge mostly sparse array we will not * access the tail of vec corresponding to properties that do not @@ -2140,196 +2165,204 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * * After this point control must flow through label out: to exit. */ - { - jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval)); - if (!vec) - return false; + JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr); - struct AutoFreeVector { - AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { } - ~AutoFreeVector() { - cx->free(vec); - } - JSContext * const cx; - jsval *&vec; - } free(cx, vec); + /* + * By ECMA 262, 15.4.4.11, a property that does not exist (which we + * call a "hole") is always greater than an existing property with + * value undefined and that is always greater than any other property. + * Thus to sort holes and undefs we simply count them, sort the rest + * of elements, append undefs after them and then make holes after + * undefs. + */ + undefs = 0; + newlen = 0; + all_strings = JS_TRUE; + for (i = 0; i < len; i++) { + ok = JS_CHECK_OPERATION_LIMIT(cx); + if (!ok) + goto out; - AutoArrayRooter tvr(cx, 0, vec); + /* Clear vec[newlen] before including it in the rooted set. */ + vec[newlen] = JSVAL_NULL; + tvr.count = newlen + 1; + ok = GetArrayElement(cx, obj, i, &hole, &vec[newlen]); + if (!ok) + goto out; - /* - * By ECMA 262, 15.4.4.11, a property that does not exist (which we - * call a "hole") is always greater than an existing property with - * value undefined and that is always greater than any other property. - * Thus to sort holes and undefs we simply count them, sort the rest - * of elements, append undefs after them and then make holes after - * undefs. - */ - undefs = 0; - newlen = 0; - bool allStrings = true; - for (i = 0; i < len; i++) { - if (!JS_CHECK_OPERATION_LIMIT(cx)) - return false; + if (hole) + continue; - /* Clear vec[newlen] before including it in the rooted set. */ - JSBool hole; - vec[newlen] = JSVAL_NULL; - tvr.changeLength(newlen + 1); - if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen])) - return false; - - if (hole) - continue; - - if (JSVAL_IS_VOID(vec[newlen])) { - ++undefs; - continue; - } - - allStrings = allStrings && JSVAL_IS_STRING(vec[newlen]); - - ++newlen; + if (JSVAL_IS_VOID(vec[newlen])) { + ++undefs; + continue; } - if (newlen == 0) - return true; /* The array has only holes and undefs. */ + /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */ + all_strings &= JSVAL_IS_STRING(vec[newlen]); + ++newlen; + } + + if (newlen == 0) { + /* The array has only holes and undefs. */ + ok = JS_TRUE; + goto out; + } + + /* + * The first newlen elements of vec are copied from the array object + * (above). The remaining newlen positions are used as GC-rooted scratch + * space for mergesort. We must clear the space before including it to + * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize + * initialization using memset. + */ + mergesort_tmp = vec + newlen; + memset(mergesort_tmp, 0, newlen * sizeof(jsval)); + tvr.count = newlen * 2; + + /* Here len == 2 * (newlen + undefs + number_of_holes). */ + if (fval == JSVAL_NULL) { /* - * The first newlen elements of vec are copied from the array object - * (above). The remaining newlen positions are used as GC-rooted scratch - * space for mergesort. We must clear the space before including it to - * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize - * initialization using memset. + * Sort using the default comparator converting all elements to + * strings. */ - jsval *mergesort_tmp = vec + newlen; - memset(mergesort_tmp, 0, newlen * sizeof(jsval)); - tvr.changeLength(newlen * 2); - - /* Here len == 2 * (newlen + undefs + number_of_holes). */ - if (fval == JSVAL_NULL) { + if (all_strings) { + elemsize = sizeof(jsval); + } else { /* - * Sort using the default comparator converting all elements to - * strings. + * To avoid string conversion on each compare we do it only once + * prior to sorting. But we also need the space for the original + * values to recover the sorting result. To reuse + * sort_compare_strings we move the original values to the odd + * indexes in vec, put the string conversion results in the even + * indexes and pass 2 * sizeof(jsval) as an element size to the + * sorting function. In this way sort_compare_strings will only + * see the string values when it casts the compare arguments as + * pointers to jsval. + * + * This requires doubling the temporary storage including the + * scratch space for the merge sort. Since vec already contains + * the rooted scratch space for newlen elements at the tail, we + * can use it to rearrange and convert to strings first and try + * realloc only when we know that we successfully converted all + * the elements. */ - if (allStrings) { - elemsize = sizeof(jsval); - } else { - /* - * To avoid string conversion on each compare we do it only once - * prior to sorting. But we also need the space for the original - * values to recover the sorting result. To reuse - * sort_compare_strings we move the original values to the odd - * indexes in vec, put the string conversion results in the even - * indexes and pass 2 * sizeof(jsval) as an element size to the - * sorting function. In this way sort_compare_strings will only - * see the string values when it casts the compare arguments as - * pointers to jsval. - * - * This requires doubling the temporary storage including the - * scratch space for the merge sort. Since vec already contains - * the rooted scratch space for newlen elements at the tail, we - * can use it to rearrange and convert to strings first and try - * realloc only when we know that we successfully converted all - * the elements. - */ #if JS_BITS_PER_WORD == 32 - if (size_t(newlen) > SIZE_MAX / (4 * sizeof(jsval))) { - js_ReportAllocationOverflow(cx); - return false; - } + if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) { + js_ReportAllocationOverflow(cx); + ok = JS_FALSE; + goto out; + } #endif - /* - * Rearrange and string-convert the elements of the vector from - * the tail here and, after sorting, move the results back - * starting from the start to prevent overwrite the existing - * elements. - */ - i = newlen; - do { - --i; - if (!JS_CHECK_OPERATION_LIMIT(cx)) - return false; - jsval v = vec[i]; - str = js_ValueToString(cx, v); - if (!str) - return false; - vec[2 * i] = STRING_TO_JSVAL(str); - vec[2 * i + 1] = v; - } while (i != 0); - - JS_ASSERT(tvr.array == vec); - vec = (jsval *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(jsval)); - if (!vec) { - vec = tvr.array; - return false; + /* + * Rearrange and string-convert the elements of the vector from + * the tail here and, after sorting, move the results back + * starting from the start to prevent overwrite the existing + * elements. + */ + i = newlen; + do { + --i; + ok = JS_CHECK_OPERATION_LIMIT(cx); + if (!ok) + goto out; + v = vec[i]; + str = js_ValueToString(cx, v); + if (!str) { + ok = JS_FALSE; + goto out; } - mergesort_tmp = vec + 2 * newlen; - memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval)); - tvr.changeArray(vec, newlen * 4); - elemsize = 2 * sizeof(jsval); - } - if (!js_MergeSort(vec, size_t(newlen), elemsize, - sort_compare_strings, cx, mergesort_tmp)) { - return false; - } - if (!allStrings) { - /* - * We want to make the following loop fast and to unroot the - * cached results of toString invocations before the operation - * callback has a chance to run the GC. For this reason we do - * not call JS_CHECK_OPERATION_LIMIT in the loop. - */ - i = 0; - do { - vec[i] = vec[2 * i + 1]; - } while (++i != newlen); - } - } else { - void *mark; + vec[2 * i] = STRING_TO_JSVAL(str); + vec[2 * i + 1] = v; + } while (i != 0); - LeaveTrace(cx); - - CompareArgs ca; - ca.context = cx; - ca.fval = fval; - ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); - if (!ca.elemroot) - return false; - bool ok = js_MergeSort(vec, size_t(newlen), sizeof(jsval), - comparator_stack_cast(sort_compare), - &ca, mergesort_tmp); - js_FreeStack(cx, mark); - if (!ok) - return false; + JS_ASSERT(tvr.u.array == vec); + vec = (jsval *) cx->realloc(vec, + 4 * (size_t) newlen * sizeof(jsval)); + if (!vec) { + vec = tvr.u.array; + ok = JS_FALSE; + goto out; + } + tvr.u.array = vec; + mergesort_tmp = vec + 2 * newlen; + memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval)); + tvr.count = newlen * 4; + elemsize = 2 * sizeof(jsval); } - - /* - * We no longer need to root the scratch space for the merge sort, so - * unroot it now to make the job of a potential GC under - * InitArrayElements easier. - */ - tvr.changeLength(newlen); - if (!InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues, - SourceVectorAllValues)) { - return false; + ok = js_MergeSort(vec, (size_t) newlen, elemsize, + sort_compare_strings, cx, mergesort_tmp); + if (!ok) + goto out; + if (!all_strings) { + /* + * We want to make the following loop fast and to unroot the + * cached results of toString invocations before the operation + * callback has a chance to run the GC. For this reason we do + * not call JS_CHECK_OPERATION_LIMIT in the loop. + */ + i = 0; + do { + vec[i] = vec[2 * i + 1]; + } while (++i != newlen); } + } else { + void *mark; + + LeaveTrace(cx); + + ca.context = cx; + ca.fval = fval; + ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); + if (!ca.elemroot) { + ok = JS_FALSE; + goto out; + } + ok = js_MergeSort(vec, (size_t) newlen, sizeof(jsval), + comparator_stack_cast(sort_compare), + &ca, mergesort_tmp); + js_FreeStack(cx, mark); + if (!ok) + goto out; } + /* + * We no longer need to root the scratch space for the merge sort, so + * unroot it now to make the job of a potential GC under InitArrayElements + * easier. + */ + tvr.count = newlen; + ok = InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues, + SourceVectorAllValues); + if (!ok) + goto out; + + out: + JS_POP_TEMP_ROOT(cx, &tvr); + cx->free(vec); + if (!ok) + return JS_FALSE; + /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) - return false; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) { + return JS_FALSE; + } } /* Re-create any holes that sorted to the end of the array. */ while (len > newlen) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len)) + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !DeleteArrayElement(cx, obj, --len)) { return JS_FALSE; + } } *vp = OBJECT_TO_JSVAL(obj); - return true; + return JS_TRUE; } /* @@ -2403,7 +2436,7 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0, static jsval FASTCALL Array_p_push1(JSContext* cx, JSObject* obj, jsval v) { - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); if (obj->isDenseArray() ? array_push1_dense(cx, obj, v, tvr.addr()) : array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) { @@ -2475,7 +2508,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp) static jsval FASTCALL Array_p_pop(JSContext* cx, JSObject* obj) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (obj->isDenseArray() ? array_pop_dense(cx, obj, tvr.addr()) : array_pop_slowly(cx, obj, tvr.addr())) { @@ -2539,7 +2572,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; /* Slide down the array above the first element. */ - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); for (i = 0; i != length; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) || @@ -2584,7 +2617,7 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp) } else { last = length; jsdouble upperIndex = last + argc; - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); do { --last, --upperIndex; if (!JS_CHECK_OPERATION_LIMIT(cx) || @@ -2674,7 +2707,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) argv++; } - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); /* If there are elements to remove, put them into the return value. */ if (count > 0) { @@ -2813,7 +2846,7 @@ array_concat(JSContext *cx, uintN argc, jsval *vp) length = 0; } - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ for (i = 0; i <= argc; i++) { @@ -2927,7 +2960,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = OBJECT_TO_JSVAL(nobj); - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); for (slot = begin; slot < end; slot++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, slot, &hole, tvr.addr())) { @@ -3437,7 +3470,10 @@ js_InitArrayClass(JSContext *cx, JSObject *obj) JSObject * js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) { - JSObject *obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL); + JSTempValueRooter tvr; + JSObject *obj; + + obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL); if (!obj) return NULL; @@ -3447,11 +3483,10 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) */ JS_ASSERT(obj->getProto()); - { - AutoValueRooter tvr(cx, obj); - if (!InitArrayObject(cx, obj, length, vector, holey)) - obj = NULL; - } + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + if (!InitArrayObject(cx, obj, length, vector, holey)) + obj = NULL; + JS_POP_TEMP_ROOT(cx, &tvr); /* Set/clear newborn root, in case we lost it. */ cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj; @@ -3567,7 +3602,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector) if (!obj) return NULL; - AutoValueRooter tvr(cx, obj); + JSAutoTempValueRooter tvr(cx, obj); if (!EnsureCapacity(cx, obj, capacity, JS_FALSE)) obj = NULL; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 02833fcee675..f96e701acd6b 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1161,6 +1161,97 @@ typedef struct JSResolvingEntry { #define JSRESFLAG_LOOKUP 0x1 /* resolving id from lookup */ #define JSRESFLAG_WATCH 0x2 /* resolving id from watch */ + +/* + * Macros to push/pop JSTempValueRooter instances to context-linked stack of + * temporary GC roots. If you need to protect a result value that flows out of + * a C function across several layers of other functions, use the + * js_LeaveLocalRootScopeWithResult internal API (see further below) instead. + * + * The macros also provide a simple way to get a single rooted pointer via + * JS_PUSH_TEMP_ROOT_(cx, NULL, &tvr). Then &tvr.u. gives the + * necessary pointer. + * + * JSTempValueRooter.count defines the type of the rooted value referenced by + * JSTempValueRooter.u union of type JSTempValueUnion. When count is positive + * or zero, u.array points to a vector of jsvals. Otherwise it must be one of + * the following constants: + */ +#define JSTVU_SINGLE (-1) /* u.value or u. is single jsval + or non-JSString GC-thing pointer */ +#define JSTVU_TRACE (-2) /* u.trace is a hook to trace a custom + * structure */ +#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */ +#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */ +#define JSTVU_COMPILER (-5) /* u.compiler roots JSCompiler* */ +#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */ +#define JSTVU_ENUMERATOR (-7) /* a pointer to JSTempValueRooter points + to an instance of JSAutoEnumStateRooter + with u.object storing the enumeration + object */ + +/* + * Here single JSTVU_SINGLE covers both jsval and pointers to almost (see note + * below) any GC-thing via reinterpreting the thing as JSVAL_OBJECT. This works + * because the GC-thing is aligned on a 0 mod 8 boundary, and object has the 0 + * jsval tag. So any GC-heap-allocated thing pointer may be tagged as if it + * were an object and untagged, if it's then used only as an opaque pointer + * until discriminated by other means than tag bits. This is how, for example, + * js_GetGCThingTraceKind uses its |thing| parameter -- it consults GC-thing + * flags stored separately from the thing to decide the kind of thing. + * + * Note well that JSStrings may be statically allocated (see the intStringTable + * and unitStringTable static arrays), so this hack does not work for arbitrary + * GC-thing pointers. + */ +#define JS_PUSH_TEMP_ROOT_COMMON(cx,x,tvr,cnt,kind) \ + JS_BEGIN_MACRO \ + JS_ASSERT((cx)->tempValueRooters != (tvr)); \ + (tvr)->count = (cnt); \ + (tvr)->u.kind = (x); \ + (tvr)->down = (cx)->tempValueRooters; \ + (cx)->tempValueRooters = (tvr); \ + JS_END_MACRO + +#define JS_POP_TEMP_ROOT(cx,tvr) \ + JS_BEGIN_MACRO \ + JS_ASSERT((cx)->tempValueRooters == (tvr)); \ + (cx)->tempValueRooters = (tvr)->down; \ + JS_END_MACRO + +#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \ + JS_BEGIN_MACRO \ + JS_ASSERT((int)(cnt) >= 0); \ + JS_PUSH_TEMP_ROOT_COMMON(cx, arr, tvr, (ptrdiff_t) (cnt), array); \ + JS_END_MACRO + +#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, val, tvr, JSTVU_SINGLE, value) + +#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, obj, tvr, JSTVU_SINGLE, object) + +#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr) \ + JS_PUSH_SINGLE_TEMP_ROOT(cx, str ? STRING_TO_JSVAL(str) : JSVAL_NULL, tvr) + +#define JS_PUSH_TEMP_ROOT_XML(cx,xml_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, xml_, tvr, JSTVU_SINGLE, xml) + +#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, trace_, tvr, JSTVU_TRACE, trace) + +#define JS_PUSH_TEMP_ROOT_SPROP(cx,sprop_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, sprop_, tvr, JSTVU_SPROP, sprop) + +#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots) + +#define JS_PUSH_TEMP_ROOT_COMPILER(cx,pc,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_COMPILER, compiler) + +#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script) + #define JSRESOLVE_INFER 0xffff /* infer bits from current bytecode */ extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ @@ -1174,10 +1265,6 @@ struct JSGCReachableFrame { JSStackFrame *frame; }; -namespace js { -class AutoGCRooter; -} - struct JSContext { explicit JSContext(JSRuntime *rt) : runtime(rt), busyArrays(this) {} @@ -1379,8 +1466,8 @@ struct JSContext /* PDL of stack headers describing stack slots not rooted by argv, etc. */ JSStackHeader *stackHeaders; - /* Stack of thread-stack-allocated GC roots. */ - js::AutoGCRooter *autoGCRooters; + /* Stack of thread-stack-allocated temporary GC roots. */ + JSTempValueRooter *tempValueRooters; /* Debug hooks associated with the current context. */ const JSDebugHooks *debugHooks; @@ -1617,258 +1704,93 @@ FrameAtomBase(JSContext *cx, JSStackFrame *fp) : fp->script->atomMap.vector; } -namespace js { - -class AutoGCRooter { +/* FIXME(bug 332648): Move this into a public header. */ +class JSAutoTempValueRooter +{ public: - AutoGCRooter(JSContext *cx, ptrdiff_t tag) - : down(cx->autoGCRooters), tag(tag), context(cx) - { - JS_ASSERT(this != cx->autoGCRooters); - cx->autoGCRooters = this; + JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr); + } + explicit JSAutoTempValueRooter(JSContext *cx, jsval v = JSVAL_NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, JSString *str + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT_STRING(mContext, str, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, JSObject *obj + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT_OBJECT(mContext, obj, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, JSScopeProperty *sprop + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT_SPROP(mContext, sprop, &mTvr); } - ~AutoGCRooter() { - JS_ASSERT(this == context->autoGCRooters); - context->autoGCRooters = down; + ~JSAutoTempValueRooter() { + JS_POP_TEMP_ROOT(mContext, &mTvr); } - inline void trace(JSTracer *trc); - - friend void ::js_TraceContext(JSTracer *trc, JSContext *acx); + jsval value() { return mTvr.u.value; } + jsval *addr() { return &mTvr.u.value; } protected: - AutoGCRooter * const down; + JSContext *mContext; - /* - * Discriminates actual subclass of this being used. If non-negative, the - * subclass roots an array of jsvals of the length stored in this field. - * If negative, meaning is indicated by the corresponding value in the enum - * below. Any other negative value indicates some deeper problem such as - * memory corruption. - */ - ptrdiff_t tag; - - JSContext * const context; - - enum { - JSVAL = -1, /* js::AutoValueRooter */ - SPROP = -2, /* JSAutoScopePropertyTreeRooter */ - WEAKROOTS = -3, /* AutoSaveWeakRoots */ - COMPILER = -4, /* JSCompiler */ - SCRIPT = -5, /* JSAutoScriptRooter */ - ENUMERATOR = -6, /* JSAutoEnumStateRooter */ - IDARRAY = -7, /* JSAutoIdArray */ - DESCRIPTORS = -8, /* AutoDescriptorArray */ - NAMESPACES = -9, /* AutoNamespaceArray */ - XML = -10, /* JSAutoXML */ - OBJECT = -11, /* JSAutoObjectRooter */ - ID = -12 /* JSAutoTempIdRooter */ - }; + private: + JSTempValueRooter mTvr; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -class AutoSaveWeakRoots : private AutoGCRooter +class JSAutoTempIdRooter { public: - explicit AutoSaveWeakRoots(JSContext *cx - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, WEAKROOTS), savedRoots(cx->weakRoots) - { + explicit JSAutoTempIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_SINGLE_TEMP_ROOT(mContext, ID_TO_VALUE(id), &mTvr); } - friend void AutoGCRooter::trace(JSTracer *trc); + ~JSAutoTempIdRooter() { + JS_POP_TEMP_ROOT(mContext, &mTvr); + } + + jsid id() { return (jsid) mTvr.u.value; } + jsid * addr() { return (jsid *) &mTvr.u.value; } private: - JSWeakRoots savedRoots; + JSContext *mContext; + JSTempValueRooter mTvr; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -/* FIXME(bug 332648): Move this into a public header. */ -class AutoValueRooter : private AutoGCRooter -{ +class JSAutoIdArray { public: - explicit AutoValueRooter(JSContext *cx, jsval v = JSVAL_NULL - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(v) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - AutoValueRooter(JSContext *cx, JSString *str - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(STRING_TO_JSVAL(str)) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - AutoValueRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(OBJECT_TO_JSVAL(obj)) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - void setObject(JSObject *obj) { - JS_ASSERT(tag == JSVAL); - val = OBJECT_TO_JSVAL(obj); - } - - void setString(JSString *str) { - JS_ASSERT(tag == JSVAL); - JS_ASSERT(str); - val = STRING_TO_JSVAL(str); - } - - void setDouble(jsdouble *dp) { - JS_ASSERT(tag == JSVAL); - JS_ASSERT(dp); - val = DOUBLE_TO_JSVAL(dp); - } - - jsval value() const { - JS_ASSERT(tag == JSVAL); - return val; - } - - jsval *addr() { - JS_ASSERT(tag == JSVAL); - return &val; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - jsval val; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoObjectRooter : private AutoGCRooter { - public: - AutoObjectRooter(JSContext *cx, JSObject *obj = NULL - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, OBJECT), obj(obj) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - void setObject(JSObject *obj) { - this->obj = obj; - } - - JSObject * object() const { - return obj; - } - - JSObject ** addr() { - return &obj; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSObject *obj; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoArrayRooter : private AutoGCRooter { - public: - AutoArrayRooter(JSContext *cx, size_t len, jsval *vec - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, len), array(vec) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_ASSERT(tag >= 0); - } - - void changeLength(size_t newLength) { - tag = ptrdiff_t(newLength); - JS_ASSERT(tag >= 0); - } - - void changeArray(jsval *newArray, size_t newLength) { - changeLength(newLength); - array = newArray; - } - - jsval *array; - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoScopePropertyRooter : private AutoGCRooter { - public: - AutoScopePropertyRooter(JSContext *cx, JSScopeProperty *sprop - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, SPROP), sprop(sprop) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSScopeProperty * const sprop; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoScriptRooter : private AutoGCRooter { - public: - AutoScriptRooter(JSContext *cx, JSScript *script - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, SCRIPT), script(script) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - void setScript(JSScript *script) { - this->script = script; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSScript *script; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoIdRooter : private AutoGCRooter -{ - public: - explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ID), idval(id) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - jsid id() { - return idval; - } - - jsid * addr() { - return &idval; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - jsid idval; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoIdArray : private AutoGCRooter { - public: - AutoIdArray(JSContext *cx, JSIdArray *ida + JSAutoIdArray(JSContext *cx, JSIdArray *ida JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ida ? ida->length : 0), idArray(ida) - { + : cx(cx), idArray(ida) { JS_GUARD_OBJECT_NOTIFIER_INIT; + if (ida) + JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr); } - ~AutoIdArray() { - if (idArray) - JS_DestroyIdArray(context, idArray); + ~JSAutoIdArray() { + if (idArray) { + JS_POP_TEMP_ROOT(cx, &tvr); + JS_DestroyIdArray(cx, idArray); + } } bool operator!() { return idArray == NULL; @@ -1881,86 +1803,52 @@ class AutoIdArray : private AutoGCRooter { size_t length() const { return idArray->length; } - - friend void AutoGCRooter::trace(JSTracer *trc); - - protected: - inline void trace(JSTracer *trc); - private: + JSContext * const cx; JSIdArray * const idArray; + JSTempValueRooter tvr; JS_DECL_USE_GUARD_OBJECT_NOTIFIER /* No copy or assignment semantics. */ - AutoIdArray(AutoIdArray &ida); - void operator=(AutoIdArray &ida); + JSAutoIdArray(JSAutoIdArray &); + void operator=(JSAutoIdArray &); }; /* The auto-root for enumeration object and its state. */ -class AutoEnumStateRooter : private AutoGCRooter +class JSAutoEnumStateRooter : public JSTempValueRooter { public: - AutoEnumStateRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue(JSVAL_NULL) + JSAutoEnumStateRooter(JSContext *cx, JSObject *obj, jsval *statep + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx), mStatep(statep) { JS_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(obj); + JS_ASSERT(statep); + JS_PUSH_TEMP_ROOT_COMMON(cx, obj, this, JSTVU_ENUMERATOR, object); } - ~AutoEnumStateRooter() { - if (!JSVAL_IS_NULL(stateValue)) { -#ifdef DEBUG - JSBool ok = -#endif - obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0); - JS_ASSERT(ok); - } + ~JSAutoEnumStateRooter() { + JS_POP_TEMP_ROOT(mContext, this); } - friend void AutoGCRooter::trace(JSTracer *trc); - - jsval state() const { return stateValue; } - jsval * addr() { return &stateValue; } - - protected: - void trace(JSTracer *trc) { - JS_CALL_OBJECT_TRACER(trc, obj, "js::AutoEnumStateRooter.obj"); - js_MarkEnumeratorState(trc, obj, stateValue); + void mark(JSTracer *trc) { + JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj"); + js_MarkEnumeratorState(trc, u.object, *mStatep); } - JSObject * const obj; - private: - jsval stateValue; + JSContext *mContext; + jsval *mStatep; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -#ifdef JS_HAS_XML_SUPPORT -class AutoXMLRooter : private AutoGCRooter { - public: - AutoXMLRooter(JSContext *cx, JSXML *xml) - : AutoGCRooter(cx, XML), xml(xml) - { - JS_ASSERT(xml); - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSXML * const xml; -}; -#endif /* JS_HAS_XML_SUPPORT */ - -} - class JSAutoResolveFlags { public: JSAutoResolveFlags(JSContext *cx, uintN flags JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx), mSaved(cx->resolveFlags) - { + : mContext(cx), mSaved(cx->resolveFlags) { JS_GUARD_OBJECT_NOTIFIER_INIT; cx->resolveFlags = flags; } diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h deleted file mode 100644 index ca28d7682f2f..000000000000 --- a/js/src/jscntxtinlines.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is SpiderMonkey code. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Jeff Walden (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jscntxtinlines_h___ -#define jscntxtinlines_h___ - -#include "jscntxt.h" -#include "jsxml.h" - -#include "jsobjinlines.h" - -namespace js { - -void -AutoIdArray::trace(JSTracer *trc) { - JS_ASSERT(tag == IDARRAY); - js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); -} - -class AutoNamespaces : protected AutoGCRooter { - protected: - AutoNamespaces(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) { - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - public: - JSXMLArray array; -}; - -inline void -AutoGCRooter::trace(JSTracer *trc) -{ - switch (tag) { - case JSVAL: - JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val"); - js_CallValueTracerIfGCThing(trc, static_cast(this)->val); - return; - - case SPROP: - static_cast(this)->sprop->trace(trc); - return; - - case WEAKROOTS: - static_cast(this)->savedRoots.mark(trc); - return; - - case COMPILER: - static_cast(this)->trace(trc); - return; - - case SCRIPT: - if (JSScript *script = static_cast(this)->script) - js_TraceScript(trc, script); - return; - - case ENUMERATOR: - static_cast(this)->trace(trc); - return; - - case IDARRAY: { - JSIdArray *ida = static_cast(this)->idArray; - TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); - return; - } - - case DESCRIPTORS: { - PropertyDescriptorArray &descriptors = - static_cast(this)->descriptors; - for (size_t i = 0, len = descriptors.length(); i < len; i++) { - PropertyDescriptor &desc = descriptors[i]; - - JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); - JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); - JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); - js_TraceId(trc, desc.id); - } - return; - } - - case NAMESPACES: { - JSXMLArray &array = static_cast(this)->array; - TraceObjectVector(trc, reinterpret_cast(array.vector), array.length); - array.cursors->trace(trc); - return; - } - - case XML: - js_TraceXML(trc, static_cast(this)->xml); - return; - - case OBJECT: - if (JSObject *obj = static_cast(this)->obj) { - JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj"); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - return; - - case ID: - JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val"); - js_CallValueTracerIfGCThing(trc, static_cast(this)->idval); - return; - } - - JS_ASSERT(tag >= 0); - TraceValues(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); -} - -} - -#endif /* jscntxtinlines_h___ */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 05ba1230a0e6..a964851f3649 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1465,8 +1465,8 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, { pd->id = ID_TO_VALUE(sprop->id); - bool wasThrowing = cx->throwing; - AutoValueRooter lastException(cx, cx->exception); + JSBool wasThrowing = cx->throwing; + JSAutoTempValueRooter lastException(cx, cx->exception); cx->throwing = JS_FALSE; if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index fea99f3133f6..670efd3196a6 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -63,8 +63,6 @@ #include "jsscript.h" #include "jsstaticcheck.h" -using namespace js; - /* Forward declarations for js_ErrorClass's initializer. */ static JSBool Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); @@ -826,119 +824,131 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) JSObject *obj; JSString *name, *message, *filename, *lineno_as_str, *result; jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + JSTempValueRooter tvr; + JSBool ok; uint32 lineno; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; obj = JS_THIS_OBJECT(cx, vp); if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) - return false; + return JS_FALSE; name = js_ValueToString(cx, *vp); if (!name) - return false; + return JS_FALSE; *vp = STRING_TO_JSVAL(name); - { - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots); + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); #ifdef __GNUC__ - message = filename = NULL; + message = filename = NULL; #endif - if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || - !(message = js_ValueToSource(cx, localroots[0]))) { - return false; + ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) && + (message = js_ValueToSource(cx, localroots[0])); + if (!ok) + goto out; + localroots[0] = STRING_TO_JSVAL(message); + + ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) && + (filename = js_ValueToSource(cx, localroots[1])); + if (!ok) + goto out; + localroots[1] = STRING_TO_JSVAL(filename); + + ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]); + if (!ok) + goto out; + lineno = js_ValueToECMAUint32 (cx, &localroots[2]); + ok = !JSVAL_IS_NULL(localroots[2]); + if (!ok) + goto out; + + if (lineno != 0) { + lineno_as_str = js_ValueToString(cx, localroots[2]); + if (!lineno_as_str) { + ok = JS_FALSE; + goto out; } - localroots[0] = STRING_TO_JSVAL(message); + lineno_length = lineno_as_str->length(); + } else { + lineno_as_str = NULL; + lineno_length = 0; + } - if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || - !(filename = js_ValueToSource(cx, localroots[1]))) { - return false; - } - localroots[1] = STRING_TO_JSVAL(filename); + /* Magic 8, for the characters in ``(new ())''. */ + name_length = name->length(); + message_length = message->length(); + length = 8 + name_length + message_length; - if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2])) - return false; - lineno = js_ValueToECMAUint32 (cx, &localroots[2]); - if (JSVAL_IS_NULL(localroots[2])) - return false; - - if (lineno != 0) { - lineno_as_str = js_ValueToString(cx, localroots[2]); - if (!lineno_as_str) - return false; - lineno_length = lineno_as_str->length(); - } else { - lineno_as_str = NULL; - lineno_length = 0; - } - - /* Magic 8, for the characters in ``(new ())''. */ - name_length = name->length(); - message_length = message->length(); - length = 8 + name_length + message_length; - - filename_length = filename->length(); - if (filename_length != 0) { - /* append filename as ``, {filename}'' */ - length += 2 + filename_length; - if (lineno_as_str) { - /* append lineno as ``, {lineno_as_str}'' */ - length += 2 + lineno_length; - } - } else { - if (lineno_as_str) { - /* - * no filename, but have line number, - * need to append ``, "", {lineno_as_str}'' - */ - length += 6 + lineno_length; - } - } - - cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); - if (!chars) - return false; - - *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; - js_strncpy(cp, name->chars(), name_length); - cp += name_length; - *cp++ = '('; - if (message_length != 0) { - js_strncpy(cp, message->chars(), message_length); - cp += message_length; - } - - if (filename_length != 0) { - /* append filename as ``, {filename}'' */ - *cp++ = ','; *cp++ = ' '; - js_strncpy(cp, filename->chars(), filename_length); - cp += filename_length; - } else { - if (lineno_as_str) { - /* - * no filename, but have line number, - * need to append ``, "", {lineno_as_str}'' - */ - *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; - } - } + filename_length = filename->length(); + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + length += 2 + filename_length; if (lineno_as_str) { /* append lineno as ``, {lineno_as_str}'' */ - *cp++ = ','; *cp++ = ' '; - js_strncpy(cp, lineno_as_str->chars(), lineno_length); - cp += lineno_length; + length += 2 + lineno_length; } - - *cp++ = ')'; *cp++ = ')'; *cp = 0; - - result = js_NewString(cx, chars, length); - if (!result) { - cx->free(chars); - return false; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + length += 6 + lineno_length; } - *vp = STRING_TO_JSVAL(result); - return true; } + + cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!chars) { + ok = JS_FALSE; + goto out; + } + + *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; + js_strncpy(cp, name->chars(), name_length); + cp += name_length; + *cp++ = '('; + if (message_length != 0) { + js_strncpy(cp, message->chars(), message_length); + cp += message_length; + } + + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, filename->chars(), filename_length); + cp += filename_length; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; + } + } + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, lineno_as_str->chars(), lineno_length); + cp += lineno_length; + } + + *cp++ = ')'; *cp++ = ')'; *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + cx->free(chars); + ok = JS_FALSE; + goto out; + } + *vp = STRING_TO_JSVAL(result); + ok = JS_TRUE; + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; } #endif @@ -989,7 +999,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) return NULL; memset(roots, 0, sizeof(roots)); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); #ifdef __GNUC__ error_proto = NULL; /* quell GCC overwarning */ @@ -1099,6 +1109,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, const JSErrorFormatString *errorString; JSExnType exn; jsval tv[4]; + JSTempValueRooter tvr; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; @@ -1147,7 +1158,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, /* Protect the newly-created strings below from nesting GCs. */ memset(tv, 0, sizeof tv); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); /* * Try to get an appropriate prototype by looking up the corresponding @@ -1191,6 +1202,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, reportp->flags |= JSREPORT_EXCEPTION; out: + JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; } @@ -1201,18 +1213,20 @@ js_ReportUncaughtException(JSContext *cx) jsval exn; JSObject *exnObject; jsval roots[5]; + JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; + JSBool ok; if (!JS_IsExceptionPending(cx)) - return true; + return JS_TRUE; if (!JS_GetPendingException(cx, &exn)) - return false; + return JS_FALSE; memset(roots, 0, sizeof roots); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object @@ -1237,36 +1251,51 @@ js_ReportUncaughtException(JSContext *cx) } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); - if (!bytes) - return false; + if (!bytes) { + ok = JS_FALSE; + goto out; + } } + ok = JS_TRUE; - if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { + if (!reportp && + exnObject && + OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; - if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) - return false; + ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); + if (!ok) + goto out; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); - if (!bytes) - return false; + if (!bytes) { + ok = JS_FALSE; + goto out; + } } - if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) - return false; + ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); + if (!ok) + goto out; str = js_ValueToString(cx, roots[3]); - if (!str) - return false; + if (!str) { + ok = JS_FALSE; + goto out; + } filename = StringToFilename(cx, str); - if (!filename) - return false; + if (!filename) { + ok = JS_FALSE; + goto out; + } - if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) - return false; + ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); + if (!ok) + goto out; lineno = js_ValueToECMAUint32 (cx, &roots[4]); - if (JSVAL_IS_NULL(roots[4])) - return false; + ok = !JSVAL_IS_NULL(roots[4]); + if (!ok) + goto out; reportp = &report; memset(&report, 0, sizeof report); @@ -1287,5 +1316,7 @@ js_ReportUncaughtException(JSContext *cx) JS_ClearPendingException(cx); } - return true; +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index ccd61484a105..d4c0cefc077c 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -351,7 +351,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio funobj, scopeChain); if (!wfunobj) return NULL; - AutoValueRooter tvr(cx, wfunobj); + JSAutoTempValueRooter tvr(cx, wfunobj); JSFunction *wfun = (JSFunction *) wfunobj; wfunobj->setPrivate(wfun); @@ -599,7 +599,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) if (!JS_ValueToId(cx, idval, &id)) return false; - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); return js_DeleteProperty(cx, obj, id, tvr.addr()) && js_SetProperty(cx, obj, id, vp); } @@ -1584,6 +1584,8 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) uintN nargs, nvars, nupvars, n; uint32 localsword; /* word for argument and variable counts */ uint32 flagsword; /* word for fun->u.i.nupvars and fun->flags */ + JSTempValueRooter tvr; + JSBool ok; cx = xdr->cx; if (xdr->mode == JSXDR_ENCODE) { @@ -1592,13 +1594,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, JS_GetFunctionName(fun)); - return false; + return JS_FALSE; } if (fun->u.i.wrapper) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, JS_GetFunctionName(fun)); - return false; + return JS_FALSE; } JS_ASSERT((fun->u.i.wrapper & ~1U) == 0); firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom; @@ -1610,7 +1612,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } else { fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); if (!fun) - return false; + return JS_FALSE; FUN_OBJECT(fun)->clearParent(); FUN_OBJECT(fun)->clearProto(); #ifdef __GNUC__ @@ -1618,15 +1620,18 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) #endif } - AutoValueRooter tvr(cx, FUN_OBJECT(fun)); + /* From here on, control flow must flow through label out. */ + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); + ok = JS_TRUE; if (!JS_XDRUint32(xdr, &firstword)) - return false; + goto bad; if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom)) - return false; + goto bad; if (!JS_XDRUint32(xdr, &localsword) || !JS_XDRUint32(xdr, &flagsword)) { - return false; + goto bad; } if (xdr->mode == JSXDR_DECODE) { @@ -1650,7 +1655,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JSAtom *name; JSLocalKind localKind; - bool ok = true; mark = JS_ARENA_MARK(&xdr->cx->tempPool); /* @@ -1669,13 +1673,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) bitmapLength * sizeof *bitmap); if (!bitmap) { js_ReportOutOfScriptQuota(xdr->cx); - ok = false; + ok = JS_FALSE; goto release_mark; } if (xdr->mode == JSXDR_ENCODE) { names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool); if (!names) { - ok = false; + ok = JS_FALSE; goto release_mark; } memset(bitmap, 0, bitmapLength * sizeof *bitmap); @@ -1730,18 +1734,19 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) goto release_mark; } } + ok = JS_TRUE; release_mark: JS_ARENA_RELEASE(&xdr->cx->tempPool, mark); if (!ok) - return false; + goto out; if (xdr->mode == JSXDR_DECODE) js_FreezeLocalNames(cx, fun); } if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL)) - return false; + goto bad; if (xdr->mode == JSXDR_DECODE) { *objp = FUN_OBJECT(fun); @@ -1753,7 +1758,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } } - return true; +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + +bad: + ok = JS_FALSE; + goto out; } #else /* !JS_HAS_XDR */ @@ -2670,26 +2681,26 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) JSStackFrame *fp; uintN error; const char *name, *source; + JSTempValueRooter tvr; for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down) continue; name = source = NULL; - - AutoValueRooter tvr(cx); + JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr); if (flags & JSV2F_ITERATOR) { error = JSMSG_BAD_ITERATOR; name = js_iterator_str; JSString *src = js_ValueToSource(cx, *vp); if (!src) - return; - tvr.setString(src); + goto out; + tvr.u.value = STRING_TO_JSVAL(src); JSString *qsrc = js_QuoteString(cx, src, 0); if (!qsrc) - return; - tvr.setString(qsrc); + goto out; + tvr.u.value = STRING_TO_JSVAL(qsrc); source = js_GetStringBytes(cx, qsrc); if (!source) - return; + goto out; } else if (flags & JSV2F_CONSTRUCT) { error = JSMSG_NOT_CONSTRUCTOR; } else { @@ -2705,6 +2716,9 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) : JSDVG_IGNORE_STACK, *vp, NULL, name, source); + + out: + JS_POP_TEMP_ROOT(cx, &tvr); } /* diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index f604570d8d4e..422260b931fe 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -87,7 +87,6 @@ #include "jsdtracef.h" #endif -#include "jscntxtinlines.h" #include "jsobjinlines.h" /* @@ -110,6 +109,14 @@ using namespace js; +/* + * Check JSTempValueUnion has the size of jsval and void * so we can + * reinterpret jsval as void* GC-thing pointer and use JSTVU_SINGLE for + * different GC-things. + */ +JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval)); +JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *)); + /* * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and * JSTRACE_STRING. @@ -2252,20 +2259,19 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, return JS_DHASH_NEXT; } -namespace js { - -void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) -{ - for (uint32 i = 0; i < len; i++) { - if (JSObject *obj = vec[i]) { - JS_SET_TRACING_INDEX(trc, "vector", i); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - } -} - -} +#define TRACE_JSVALS(trc, len, vec, name) \ + JS_BEGIN_MACRO \ + jsval _v, *_vp, *_end; \ + \ + for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \ + _v = *_vp; \ + if (JSVAL_IS_TRACEABLE(_v)) { \ + JS_SET_TRACING_INDEX(trc, name, _vp - (vec)); \ + js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(_v), \ + JSVAL_TRACE_KIND(_v)); \ + } \ + } \ + JS_END_MACRO void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) @@ -2291,7 +2297,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) } else { nslots = fp->script->nfixed; } - js::TraceValues(trc, nslots, fp->slots, "slot"); + TRACE_JSVALS(trc, nslots, fp->slots, "slot"); } } else { JS_ASSERT(!fp->slots); @@ -2316,7 +2322,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) if (fp->fun->flags & JSFRAME_ROOTED_ARGV) skip = 2 + fp->argc; } - js::TraceValues(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); + TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); } JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); @@ -2371,6 +2377,7 @@ JS_REQUIRES_STACK JS_FRIEND_API(void) js_TraceContext(JSTracer *trc, JSContext *acx) { JSStackHeader *sh; + JSTempValueRooter *tvr; /* * Trace active and suspended callstacks. @@ -2420,11 +2427,38 @@ js_TraceContext(JSTracer *trc, JSContext *acx) for (sh = acx->stackHeaders; sh; sh = sh->down) { METER(trc->context->runtime->gcStats.stackseg++); METER(trc->context->runtime->gcStats.segslots += sh->nslots); - js::TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); + TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); } - for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) - gcr->trace(trc); + for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { + switch (tvr->count) { + case JSTVU_SINGLE: + JS_SET_TRACING_NAME(trc, "tvr->u.value"); + js_CallValueTracerIfGCThing(trc, tvr->u.value); + break; + case JSTVU_TRACE: + tvr->u.trace(trc, tvr); + break; + case JSTVU_SPROP: + tvr->u.sprop->trace(trc); + break; + case JSTVU_WEAK_ROOTS: + tvr->u.weakRoots->mark(trc); + break; + case JSTVU_COMPILER: + tvr->u.compiler->trace(trc); + break; + case JSTVU_SCRIPT: + js_TraceScript(trc, tvr->u.script); + break; + case JSTVU_ENUMERATOR: + static_cast(tvr)->mark(trc); + break; + default: + JS_ASSERT(tvr->count >= 0); + TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array"); + } + } if (acx->sharpObjectMap.depth > 0) js_TraceSharpMap(trc, &acx->sharpObjectMap); @@ -2435,7 +2469,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) InterpState* state = acx->interpState; while (state) { if (state->nativeVp) - js::TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); + TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); state = state->prev; } #endif @@ -3331,30 +3365,33 @@ out: * interlock mechanism here. */ if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) { - if (!(gckind & GC_KEEP_ATOMS)) { - (void) callback(cx, JSGC_END); + JSWeakRoots savedWeakRoots; + JSTempValueRooter tvr; - /* - * On shutdown iterate until JSGC_END callback stops creating - * garbage. - */ - if (gckind == GC_LAST_CONTEXT && rt->gcPoke) - goto restart_at_beginning; - } else { + if (gckind & GC_KEEP_ATOMS) { /* * We allow JSGC_END implementation to force a full GC or allocate * new GC things. Thus we must protect the weak roots from garbage * collection and overwrites. */ - AutoSaveWeakRoots save(cx); - + savedWeakRoots = cx->weakRoots; + JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr); JS_KEEP_ATOMS(rt); JS_UNLOCK_GC(rt); + } - (void) callback(cx, JSGC_END); + (void) callback(cx, JSGC_END); + if (gckind & GC_KEEP_ATOMS) { JS_LOCK_GC(rt); JS_UNKEEP_ATOMS(rt); + JS_POP_TEMP_ROOT(cx, &tvr); + } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) { + /* + * On shutdown iterate until JSGC_END callback stops creating + * garbage. + */ + goto restart_at_beginning; } } } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index dbf645feeb29..058dafdb49cd 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -454,23 +454,4 @@ js_MarkTraps(JSTracer *trc); JS_END_EXTERN_C -namespace js { - -void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len); - -inline void -TraceValues(JSTracer *trc, size_t len, jsval *vec, const char *name) -{ - for (jsval *vp = vec, *end = vp + len; vp < end; vp++) { - jsval v = *vp; - if (JSVAL_IS_TRACEABLE(v)) { - JS_SET_TRACING_INDEX(trc, name, vp - vec); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); - } - } -} - -} - #endif /* jsgc_h___ */ diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 72cc90bf21d6..19115c6b2a09 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -800,7 +800,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp); if (!innermostNewChild) return NULL; - AutoValueRooter tvr(cx, innermostNewChild); + JSAutoTempValueRooter tvr(cx, innermostNewChild); /* * Clone our way towards outer scopes until we reach the innermost @@ -1005,7 +1005,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[1]); jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) return false; if (JSVAL_IS_PRIMITIVE(tvr.value())) { diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 619f895274ad..eaa3c872cd6e 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -215,11 +215,18 @@ Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) static JSBool NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) { - jsval vec[2] = { ID_TO_VALUE(key), val }; - AutoArrayRooter tvr(cx, 2, vec); + jsval vec[2]; + JSTempValueRooter tvr; + JSObject *aobj; - JSObject *aobj = js_NewArrayObject(cx, 2, vec); + vec[0] = ID_TO_VALUE(key); + vec[1] = val; + + JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); + aobj = js_NewArrayObject(cx, 2, vec); *rval = OBJECT_TO_JSVAL(aobj); + JS_POP_TEMP_ROOT(cx, &tvr); + return aobj != NULL; } @@ -340,19 +347,21 @@ JS_FRIEND_API(JSBool) js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) { JSObject *obj; + JSTempValueRooter tvr; JSAtom *atom; JSClass *clasp; JSExtendedClass *xclasp; + JSBool ok; JSObject *iterobj; jsval arg; - JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE))); + JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | + JSITER_FOREACH | + JSITER_KEYVALUE))); /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); - AutoValueRooter tvr(cx); - /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(*vp)) { obj = JSVAL_TO_OBJECT(*vp); @@ -365,29 +374,30 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ if ((flags & JSITER_ENUMERATE)) { if (!js_ValueToObject(cx, *vp, &obj)) - return false; + return JS_FALSE; if (!obj) goto default_iter; } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) - return false; + return JS_FALSE; } } - tvr.setObject(obj); + JS_ASSERT(obj); + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); clasp = OBJ_GET_CLASS(cx, obj); if ((clasp->flags & JSCLASS_IS_EXTENDED) && (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) - return false; + goto bad; *vp = OBJECT_TO_JSVAL(iterobj); } else { atom = cx->runtime->atomState.iteratorAtom; if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp)) - return false; + goto bad; if (JSVAL_IS_VOID(*vp)) { default_iter: /* @@ -400,29 +410,36 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL); if (!iterobj) - return false; + goto bad; /* Store in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); if (!InitNativeIterator(cx, iterobj, obj, flags)) - return false; + goto bad; } else { LeaveTrace(cx); arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, vp)) { - return false; + goto bad; } if (JSVAL_IS_PRIMITIVE(*vp)) { js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN, JSDVG_SEARCH_STACK, *vp, NULL); - return false; + goto bad; } } } - return true; + ok = JS_TRUE; + out: + if (obj) + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + bad: + ok = JS_FALSE; + goto out; } JS_FRIEND_API(JSBool) JS_FASTCALL diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 119a0705c7bb..91e69fd3cfe4 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -989,11 +989,11 @@ js_ValueToNumber(JSContext *cx, jsval *vp) * vp roots obj so we cannot use it as an extra root for * obj->defaultValue result when calling the hook. */ - AutoValueRooter gcr(cx, v); - if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr())) + JSAutoTempValueRooter tvr(cx, v); + if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr())) obj = NULL; else - v = *vp = gcr.value(); + v = *vp = tvr.value(); if (!obj) { *vp = JSVAL_NULL; return 0.0; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c9b766820f26..498c6357e26a 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -245,24 +245,32 @@ obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp) static JSBool obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { + jsval iter_state; jsid num_properties; + JSBool ok; if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT)) - return false; + return JS_FALSE; + + iter_state = JSVAL_NULL; + JSAutoEnumStateRooter tvr(cx, obj, &iter_state); /* Get the number of properties to enumerate. */ - AutoEnumStateRooter iterState(cx, obj); - if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) - return false; + ok = obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties); + if (!ok) + goto out; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); *vp = JSVAL_ZERO; - return true; + goto out; } *vp = num_properties; - return true; +out: + if (!JSVAL_IS_NULL(iter_state)) + ok &= obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); + return ok; } #else /* !JS_HAS_OBJ_PROTO_PROP */ @@ -656,13 +664,15 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) #endif jsval *val; jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + JSTempValueRooter tvr; JSString *gsopold[2]; JSString *gsop[2]; JSString *idstr, *valstr, *str; JS_CHECK_RECURSION(cx, return JS_FALSE); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot); + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr); /* If outermost, we need parentheses to be an expression, not a block. */ outermost = (cx->sharpObjectMap.depth == 0); @@ -1027,6 +1037,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) *vp = STRING_TO_JSVAL(str); ok = JS_TRUE; out: + JS_POP_TEMP_ROOT(cx, &tvr); return ok; overflow: @@ -1955,7 +1966,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[2]); - AutoIdRooter nameidr(cx); + JSAutoTempIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; @@ -1975,7 +1986,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) } jsval roots[] = { JSVAL_VOID, JSVAL_VOID }; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (OBJ_IS_NATIVE(obj)) { JSScopeProperty *sprop = reinterpret_cast(prop); @@ -2036,7 +2047,7 @@ obj_keys(JSContext *cx, uintN argc, jsval *vp) } JSObject *obj = JSVAL_TO_OBJECT(v); - AutoIdArray ida(cx, JS_Enumerate(cx, obj)); + JSAutoIdArray ida(cx, JS_Enumerate(cx, obj)); if (!ida) return JS_FALSE; @@ -2201,6 +2212,50 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) return true; } +typedef js::Vector PropertyDescriptorArray; + +class AutoDescriptorArray : private JSTempValueRooter +{ + private: + JSContext *cx; + PropertyDescriptorArray descriptors; + + public: + AutoDescriptorArray(JSContext *cx) + : cx(cx), descriptors(cx) + { + JS_PUSH_TEMP_ROOT_TRACE(cx, trace, this); + } + ~AutoDescriptorArray() { + JS_POP_TEMP_ROOT(cx, this); + } + + PropertyDescriptor *append() { + if (!descriptors.append(PropertyDescriptor())) + return NULL; + return &descriptors.back(); + } + + PropertyDescriptor& operator[](size_t i) { + JS_ASSERT(i < descriptors.length()); + return descriptors[i]; + } + + private: + static void trace(JSTracer *trc, JSTempValueRooter *tvr) { + PropertyDescriptorArray &descs = + static_cast(tvr)->descriptors; + for (size_t i = 0, len = descs.length(); i < len; i++) { + PropertyDescriptor &desc = descs[i]; + + JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); + JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); + JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); + js_TraceId(trc, desc.id); + } + } +}; + static JSBool Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval) { @@ -2584,7 +2639,7 @@ obj_defineProperty(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(*vp); /* 15.2.3.6 step 2. */ - AutoIdRooter nameidr(cx); + JSAutoTempIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; @@ -2621,7 +2676,7 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; vp[3] = OBJECT_TO_JSVAL(props); - AutoIdArray ida(cx, JS_Enumerate(cx, props)); + JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2685,7 +2740,7 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) } JSObject *props = JSVAL_TO_OBJECT(vp[3]); - AutoIdArray ida(cx, JS_Enumerate(cx, props)); + JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2883,7 +2938,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, * builtin. See bug 481444. */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { - AutoValueRooter tvr(cx, obj); + JSAutoTempValueRooter tvr(cx, obj); JS_KEEP_ATOMS(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); @@ -3559,7 +3614,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) obj->setParent(parent); } - AutoValueRooter tvr(cx, obj); + JSAutoTempValueRooter tvr(cx, obj); if (!JS_XDRUint32(xdr, &tmp)) return false; @@ -3652,6 +3707,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSAtom *atom; JSProtoKey key; JSObject *proto, *ctor; + JSTempValueRooter tvr; jsval cval, rval; JSBool named; JSFunction *fun; @@ -3687,7 +3743,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, return NULL; /* After this point, control must exit via label bad or out. */ - AutoValueRooter tvr(cx, proto); + JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr); if (!constructor) { /* @@ -3777,6 +3833,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, goto bad; out: + JS_POP_TEMP_ROOT(cx, &tvr); return proto; bad: @@ -4084,7 +4141,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, jsval cval, rval; JSObject *obj, *ctor; - AutoArrayRooter argtvr(cx, argc, argv); + JSAutoTempValueRooter argtvr(cx, argc, argv); JSProtoKey protoKey = GetClassProtoKey(clasp); if (!js_FindClassObject(cx, parent, protoKey, &cval, clasp)) @@ -4096,7 +4153,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, } /* Protect cval in case a crazy getter for .prototype uproots it. */ - AutoValueRooter tvr(cx, cval); + JSAutoTempValueRooter tvr(cx, cval); /* * If proto or parent are NULL, set them to Constructor.prototype and/or @@ -4896,6 +4953,8 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, JSScope *scope; uint32 slot; int32 sample; + JSTempValueRooter tvr, tvr2; + JSBool ok; JS_ASSERT(OBJ_IS_NATIVE(pobj)); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj)); @@ -4915,14 +4974,15 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); - { - AutoScopePropertyRooter tvr(cx, sprop); - AutoValueRooter tvr2(cx, pobj); - if (!sprop->get(cx, obj, pobj, vp)) - return false; - } - JS_LOCK_SCOPE(cx, scope); + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2); + ok = sprop->get(cx, obj, pobj, vp); + JS_POP_TEMP_ROOT(cx, &tvr2); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return false; + JS_LOCK_SCOPE(cx, scope); if (SLOT_IN_SCOPE(slot, scope) && (JS_LIKELY(cx->runtime->propertyRemovals == sample) || scope->hasProperty(sprop))) { @@ -4946,6 +5006,8 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, JSScope *scope; uint32 slot; int32 sample; + JSTempValueRooter tvr; + JSBool ok; JS_ASSERT(OBJ_IS_NATIVE(obj)); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj)); @@ -4977,11 +5039,11 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); - { - AutoScopePropertyRooter tvr(cx, sprop); - if (!sprop->set(cx, obj, vp)) - return false; - } + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + ok = sprop->set(cx, obj, vp); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return false; JS_LOCK_SCOPE(cx, scope); if (SLOT_IN_SCOPE(slot, scope) && diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 00223a9408e4..512cbaef7e56 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -52,14 +52,12 @@ #include "jspubtd.h" #include "jsprvtd.h" -namespace js { class AutoDescriptorArray; } - /* * A representation of ECMA-262 ed. 5's internal property descriptor data * structure. */ struct PropertyDescriptor { - friend class js::AutoDescriptorArray; + friend class AutoDescriptorArray; private: PropertyDescriptor(); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index b8a21d864a3e..376bca893339 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -83,34 +83,4 @@ JSObject::unbrand(JSContext *cx) return true; } -namespace js { - -typedef Vector PropertyDescriptorArray; - -class AutoDescriptorArray : private AutoGCRooter -{ - public: - AutoDescriptorArray(JSContext *cx) - : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) - { } - - PropertyDescriptor *append() { - if (!descriptors.append(PropertyDescriptor())) - return NULL; - return &descriptors.back(); - } - - PropertyDescriptor& operator[](size_t i) { - JS_ASSERT(i < descriptors.length()); - return descriptors[i]; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - PropertyDescriptorArray descriptors; -}; - -} - #endif /* jsobjinlines_h___ */ diff --git a/js/src/json.cpp b/js/src/json.cpp index 44897ba6d41c..af0c1bfd9dfc 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -65,8 +65,6 @@ #include "jsatominlines.h" -using namespace js; - #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4351) @@ -108,9 +106,10 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) { JSString *s = NULL; jsval *argv = vp + 2; - AutoValueRooter reviver(cx, JSVAL_NULL); + jsval reviver = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &reviver); - if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr())) + if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver)) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); @@ -120,7 +119,7 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); - ok &= js_FinishJSONParse(cx, jp, reviver.value()); + ok &= js_FinishJSONParse(cx, jp, reviver); } return ok; @@ -130,16 +129,18 @@ JSBool js_json_stringify(JSContext *cx, uintN argc, jsval *vp) { jsval *argv = vp + 2; - AutoValueRooter space(cx, JSVAL_NULL); - AutoObjectRooter replacer(cx); + JSObject *replacer = NULL; + jsval space = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, replacer); + JSAutoTempValueRooter tvr2(cx, 1, &space); // Must throw an Error if there isn't a first arg - if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr())) + if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, &replacer, &space)) return JS_FALSE; JSCharBuffer cb(cx); - if (!js_Stringify(cx, vp, replacer.object(), space.value(), cb)) + if (!js_Stringify(cx, vp, replacer, space, cb)) return JS_FALSE; // XXX This can never happen to nsJSON.cpp, but the JSON object @@ -257,7 +258,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) return JS_FALSE; jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); + JSAutoTempValueRooter tvr(cx, 3, vec); jsval& key = vec[0]; jsval& outputValue = vec[1]; @@ -306,7 +307,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) if (!ks) goto error_break; } - AutoValueRooter keyStringRoot(cx, ks); + JSAutoTempValueRooter keyStringRoot(cx, ks); // Don't include prototype properties, since this operation is // supposed to be implemented as if by ES3.1 Object.keys() @@ -392,20 +393,21 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; - AutoValueRooter outputValue(cx, JSVAL_NULL); + jsval outputValue = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &outputValue); jsid id; jsuint i; for (i = 0; i < length; i++) { id = INT_TO_JSID(i); - if (!obj->getProperty(cx, id, outputValue.addr())) + if (!obj->getProperty(cx, id, &outputValue)) return JS_FALSE; - if (!Str(cx, id, obj, scx, outputValue.addr())) + if (!Str(cx, id, obj, scx, &outputValue)) return JS_FALSE; - if (outputValue.value() == JSVAL_VOID) { + if (outputValue == JSVAL_VOID) { if (!js_AppendLiteral(scx->cb, "null")) return JS_FALSE; } @@ -568,54 +570,63 @@ static JSBool IsNumChar(jschar c) static JSBool HandleData(JSContext *cx, JSONParser *jp, JSONDataType type); static JSBool PopState(JSContext *cx, JSONParser *jp); -static bool +static JSBool +DestroyIdArrayOnError(JSContext *cx, JSIdArray *ida) { + JS_DestroyIdArray(cx, ida); + return JS_FALSE; +} + +static JSBool Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) { - JS_CHECK_RECURSION(cx, return false); + JS_CHECK_RECURSION(cx, return JS_FALSE); if (!holder->getProperty(cx, id, vp)) - return false; + return JS_FALSE; JSObject *obj; if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) { - AutoValueRooter propValue(cx, JSVAL_NULL); + jsval propValue = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &propValue); if(obj->isArray()) { jsuint length = 0; if (!js_GetLengthProperty(cx, obj, &length)) - return false; + return JS_FALSE; for (jsuint i = 0; i < length; i++) { jsid index; if (!js_IndexToId(cx, i, &index)) - return false; + return JS_FALSE; - if (!Walk(cx, index, obj, reviver, propValue.addr())) - return false; + if (!Walk(cx, index, obj, reviver, &propValue)) + return JS_FALSE; - if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE)) - return false; + if (!obj->defineProperty(cx, index, propValue, NULL, NULL, JSPROP_ENUMERATE)) + return JS_FALSE; } } else { - AutoIdArray ida(cx, JS_Enumerate(cx, obj)); + JSIdArray *ida = JS_Enumerate(cx, obj); if (!ida) - return false; + return JS_FALSE; - for (jsint i = 0, len = ida.length(); i < len; i++) { - jsid idName = ida[i]; - if (!Walk(cx, idName, obj, reviver, propValue.addr())) - return false; - if (propValue.value() == JSVAL_VOID) { - if (!js_DeleteProperty(cx, obj, idName, propValue.addr())) - return false; + JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)ida); + + for(jsint i = 0; i < ida->length; i++) { + jsid idName = ida->vector[i]; + if (!Walk(cx, idName, obj, reviver, &propValue)) + return DestroyIdArrayOnError(cx, ida); + if (propValue == JSVAL_VOID) { + if (!js_DeleteProperty(cx, obj, idName, &propValue)) + return DestroyIdArrayOnError(cx, ida); } else { - if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL, - JSPROP_ENUMERATE)) { - return false; - } + if (!obj->defineProperty(cx, idName, propValue, NULL, NULL, JSPROP_ENUMERATE)) + return DestroyIdArrayOnError(cx, ida); } } + + JS_DestroyIdArray(cx, ida); } } @@ -623,29 +634,31 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) jsval value = *vp; JSString *key = js_ValueToString(cx, ID_TO_VALUE(id)); if (!key) - return false; + return JS_FALSE; jsval vec[2] = {STRING_TO_JSVAL(key), value}; jsval reviverResult; if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult)) - return false; + return JS_FALSE; *vp = reviverResult; - return true; + + return JS_TRUE; } -static bool +static JSBool Revive(JSContext *cx, jsval reviver, jsval *vp) { JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL); if (!obj) - return false; + return JS_FALSE; - AutoValueRooter tvr(cx, obj); + jsval v = OBJECT_TO_JSVAL(obj); + JSAutoTempValueRooter tvr(cx, 1, &v); if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), *vp, NULL, NULL, JSPROP_ENUMERATE)) { - return false; + return JS_FALSE; } return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp); @@ -680,11 +693,11 @@ bad: return NULL; } -bool +JSBool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) { if (!jp) - return true; + return JS_TRUE; JSBool early_ok = JS_TRUE; @@ -705,20 +718,20 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) /* This internal API is infallible, in spite of its JSBool return type. */ js_RemoveRoot(cx->runtime, &jp->objectStack); - bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; + JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; jsval *vp = jp->rootVal; cx->destroy(jp); if (!early_ok) - return false; + return JS_FALSE; if (!ok) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); - return false; + return JS_FALSE; } - if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable()) + if (!JSVAL_IS_PRIMITIVE(reviver) && js_IsCallable(reviver)) ok = Revive(cx, reviver, vp); return ok; @@ -796,7 +809,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) } jsval v = OBJECT_TO_JSVAL(obj); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); // Check if this is the root object if (len == 0) { @@ -869,7 +882,7 @@ CloseArray(JSContext *cx, JSONParser *jp) static JSBool PushPrimitive(JSContext *cx, JSONParser *jp, jsval value) { - AutoValueRooter tvr(cx, value); + JSAutoTempValueRooter tvr(cx, 1, &value); jsuint len; if (!js_GetLengthProperty(cx, jp->objectStack, &len)) diff --git a/js/src/json.h b/js/src/json.h index e384863e1604..84f392419d90 100644 --- a/js/src/json.h +++ b/js/src/json.h @@ -89,7 +89,7 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal); extern JSBool js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); -extern bool +extern JSBool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver); JS_END_EXTERN_C diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index ce2a168e3aa5..9fa44d4d1a3a 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -79,8 +79,6 @@ #include "jsautooplen.h" -using namespace js; - /* * Index limit must stay within 32 bits. */ @@ -309,7 +307,7 @@ ToDisassemblySource(JSContext *cx, jsval v) } if (clasp == &js_RegExpClass) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!js_regexp_toString(cx, obj, tvr.addr())) return NULL; return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value())); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 4f279295dad4..391d4b67ae41 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -88,8 +88,6 @@ #include "jsdhash.h" #endif -using namespace js; - /* * Asserts to verify assumptions behind pn_ macros. */ @@ -224,6 +222,7 @@ JSCompiler::init(const jschar *base, size_t length, /* Root atoms and objects allocated for the parsed tree. */ JS_KEEP_ATOMS(cx->runtime); + JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot); return true; } @@ -233,6 +232,8 @@ JSCompiler::~JSCompiler() if (principals) JSPRINCIPALS_DROP(cx, principals); + JS_ASSERT(tempRoot.u.compiler == this); + JS_POP_TEMP_ROOT(cx, &tempRoot); JS_UNKEEP_ATOMS(cx->runtime); tokenStream.close(cx); JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); @@ -337,7 +338,10 @@ JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const void JSCompiler::trace(JSTracer *trc) { - JSObjectBox *objbox = traceListHead; + JSObjectBox *objbox; + + JS_ASSERT(tempRoot.u.compiler == this); + objbox = traceListHead; while (objbox) { JS_CALL_OBJECT_TRACER(trc, objbox->object, "parser.object"); objbox = objbox->traceLink; @@ -8826,6 +8830,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; + JSTempValueRooter tvr; JS_ASSERT(pn->pn_arity == PN_LIST); tt = PN_TYPE(pn); @@ -8916,12 +8921,11 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) } if (accum) { - { - AutoValueRooter tvr(cx, accum); - str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) - ? js_AddAttributePart(cx, i & 1, accum, str) - : js_ConcatStrings(cx, accum, str); - } + JS_PUSH_TEMP_ROOT_STRING(cx, accum, &tvr); + str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) + ? js_AddAttributePart(cx, i & 1, accum, str) + : js_ConcatStrings(cx, accum, str); + JS_POP_TEMP_ROOT(cx, &tvr); if (!str) return JS_FALSE; #ifdef DEBUG_brendanXXX diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 04b15ff675dd..704583192761 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -832,10 +832,8 @@ struct JSFunctionBoxQueue { #define NUM_TEMP_FREELISTS 6U /* 32 to 2048 byte size classes (32 bit) */ -class JSTreeContext; - -struct JSCompiler : private js::AutoGCRooter { - JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ +struct JSCompiler { + JSContext *context; JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; JSTokenStream tokenStream; @@ -845,10 +843,10 @@ struct JSCompiler : private js::AutoGCRooter { JSParseNode *nodeList; /* list of recyclable parse-node structs */ uint32 functionCount; /* number of functions in current unit */ JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ + JSTempValueRooter tempRoot; /* root to trace traceListHead */ JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) - : js::AutoGCRooter(cx, COMPILER), context(cx), - aleFreeList(NULL), tokenStream(cx), principals(NULL), + : context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL) { memset(tempFreeList, 0, sizeof tempFreeList); @@ -858,9 +856,6 @@ struct JSCompiler : private js::AutoGCRooter { ~JSCompiler(); - friend void js::AutoGCRooter::trace(JSTracer *trc); - friend class JSTreeContext; - /* * Initialize a compiler. Parameters are passed on to init tokenStream. * The compiler owns the arena pool "tops-of-stack" space above the current diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 664a80206a94..cd78b67bb7a1 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -281,6 +281,31 @@ typedef struct JSDebugHooks { void *debugErrorHookData; } JSDebugHooks; +/* + * Type definitions for temporary GC roots that register with GC local C + * variables. See jscntxt.h for details. + */ +typedef void +(* JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr); + +typedef union JSTempValueUnion { + jsval value; + JSObject *object; + JSXML *xml; + JSTempValueTrace trace; + JSScopeProperty *sprop; + JSWeakRoots *weakRoots; + JSCompiler *compiler; + JSScript *script; + jsval *array; +} JSTempValueUnion; + +struct JSTempValueRooter { + JSTempValueRooter *down; + ptrdiff_t count; + JSTempValueUnion u; +}; + /* JSObjectOps function pointer typedefs. */ /* diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index e02ce42cf838..6642ae5a558a 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5232,10 +5232,10 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + JSTempValueRooter *tvr) { *statics = cx->regExpStatics; - tvr->setString(statics->input); + JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr); /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). @@ -5246,11 +5246,12 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + JSTempValueRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ JS_ClearRegExpStatics(cx); cx->regExpStatics = *statics; + JS_POP_TEMP_ROOT(cx, tvr); } void @@ -5843,7 +5844,7 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - AutoValueRooter tvr(cx, str); + JSAutoTempValueRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index af08f9843dec..cc30304ac466 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -65,15 +65,13 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; -namespace js { class AutoValueRooter; } - extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + JSTempValueRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + JSTempValueRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 4e38b4434c51..01aa5877adf9 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -94,6 +94,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, uint32 length, lineno, nslots, magic; uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i; uint32 prologLength, version; + JSTempValueRooter tvr; JSPrincipals *principals; uint32 encodeable; JSBool filenameWasSaved; @@ -211,8 +212,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, if (!JS_XDRUint32(xdr, &nregexps)) return JS_FALSE; - AutoScriptRooter tvr(cx, NULL); - if (xdr->mode == JSXDR_DECODE) { script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, nregexps, ntrynotes); @@ -226,7 +225,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, /* If we know nsrcnotes, we allocated space for notes in script. */ notes = script->notes(); *scriptp = script; - tvr.setScript(script); + JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); } /* @@ -369,10 +368,13 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, } xdr->script = oldscript; + if (xdr->mode == JSXDR_DECODE) + JS_POP_TEMP_ROOT(cx, &tvr); return JS_TRUE; error: if (xdr->mode == JSXDR_DECODE) { + JS_POP_TEMP_ROOT(cx, &tvr); if (script->filename && !filenameWasSaved) { cx->free((void *) script->filename); script->filename = NULL; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 28f763c84969..ca9893f3960a 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1603,7 +1603,7 @@ str_match(JSContext *cx, uintN argc, jsval *vp) if (!g.normalizeRegExp(false, 1, argc, vp)) return false; - AutoValueRooter array(cx, JSVAL_NULL); + JSAutoTempValueRooter array(cx, JSVAL_NULL); if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS)) return false; @@ -3384,7 +3384,7 @@ js_ValueToSource(JSContext *cx, jsval v) } JSAtom *atom = cx->runtime->atomState.toSourceAtom; - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), atom, 0, NULL, tvr.addr())) return NULL; return js_ValueToString(cx, tvr.value()); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index e39d20c38948..6c137c4966d7 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8814,12 +8814,13 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) } } { - AutoValueRooter tvr(cx); + jsval tmp = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &tmp); - *tvr.addr() = l; - lnum = js_ValueToNumber(cx, tvr.addr()); - *tvr.addr() = r; - rnum = js_ValueToNumber(cx, tvr.addr()); + tmp = l; + lnum = js_ValueToNumber(cx, &tmp); + tmp = r; + rnum = js_ValueToNumber(cx, &tmp); } cond = EvalCmp(op, lnum, rnum); fp = true; @@ -11209,7 +11210,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, static JSBool FASTCALL MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - AutoValueRooter tvr(cx, funobj); + JSAutoTempValueRooter tvr(cx, funobj); return OBJ_SCOPE(obj)->methodWriteBarrier(cx, sprop, tvr.value()); } @@ -11573,7 +11574,7 @@ GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11912,7 +11913,7 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11927,7 +11928,7 @@ InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval val) { LeaveTraceIfGlobalObject(cx, obj); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(cx); @@ -12746,7 +12747,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) static JSObject* FASTCALL MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - AutoValueRooter tvr(cx, funobj); + JSAutoTempValueRooter tvr(cx, funobj); if (!OBJ_SCOPE(obj)->methodReadBarrier(cx, sprop, tvr.addr())) return NULL; @@ -14867,7 +14868,7 @@ CallIteratorNext(JSContext *cx, uintN argc, jsval *vp) static jsval FASTCALL CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr()); if (!ok) { diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index e2959ef3e652..0f5a8930e3e9 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1320,10 +1320,10 @@ js_IsTypedArray(JSObject *obj) JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr()); - AutoValueRooter rval(cx); + JSAutoTempValueRooter rval(cx); if (!ArrayBuffer::class_constructor(cx, cx->globalObject, 1, tvr.addr(), rval.addr())) @@ -1375,7 +1375,7 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + JSAutoTempValueRooter tvr(cx, 2, vals); if (!js_NewNumberInRootedValue(cx, jsdouble(nelements), &vals[0])) return NULL; @@ -1392,7 +1392,7 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + JSAutoTempValueRooter tvr(cx, 2, vals); vals[0] = OBJECT_TO_JSVAL(arrayArg); @@ -1412,7 +1412,7 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_ASSERT(length < 0 || byteoffset >= 0); jsval vals[4]; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + JSAutoTempValueRooter tvr(cx, 4, vals); int argc = 1; vals[0] = OBJECT_TO_JSVAL(bufArg); diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 82e2f6bccd58..56029438cc76 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -211,9 +211,9 @@ JS_END_EXTERN_C * when we have a guard object whose only purpose is its constructor and * destructor (and is never otherwise referenced), the intended use * might be: - * js::AutoValueRooter tvr(cx, 1, &val); + * JSAutoTempValueRooter tvr(cx, 1, &val); * but is is easy to accidentally write: - * js::AutoValueRooter(cx, 1, &val); + * JSAutoTempValueRooter(cx, 1, &val); * which compiles just fine, but runs the destructor well before the * intended time. * diff --git a/js/src/jsvector.h b/js/src/jsvector.h index bdd6ec1d813b..7c051f7005e7 100644 --- a/js/src/jsvector.h +++ b/js/src/jsvector.h @@ -359,10 +359,7 @@ class Vector : AllocPolicy /* mutators */ - /* - * If reserve(N) succeeds, additions to this vector which increase its size - * up to and including N are guaranteed to succeed. - */ + /* If reserve(N) succeeds, the N next appends are guaranteed to succeed. */ bool reserve(size_t capacity); /* Destroy elements in the range [begin() + incr, end()). */ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 2908d205794d..673b2d3abf9c 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -70,14 +70,10 @@ #include "jsstaticcheck.h" #include "jsvector.h" -#include "jscntxtinlines.h" - #ifdef DEBUG #include /* for #ifdef DEBUG memset calls */ #endif -using namespace js; - /* * NOTES * - in the js shell, you must use the -x command line option, or call @@ -870,10 +866,60 @@ attr_identity(const void *a, const void *b) return qname_identity(xmla->name, xmlb->name); } +struct JSXMLArrayCursor +{ + JSXMLArray *array; + uint32 index; + JSXMLArrayCursor *next; + JSXMLArrayCursor **prevp; + void *root; + + JSXMLArrayCursor(JSXMLArray *array) + : array(array), index(0), next(array->cursors), prevp(&array->cursors), + root(NULL) + { + if (next) + next->prevp = &next; + array->cursors = this; + } + + ~JSXMLArrayCursor() { disconnect(); } + + void disconnect() { + if (!array) + return; + if (next) + next->prevp = prevp; + *prevp = next; + array = NULL; + } + + void *getNext() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index++]; + } + + void *getCurrent() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index]; + } +}; + static void XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor) { - cursor->trace(trc); + void *root; +#ifdef DEBUG + size_t index = 0; +#endif + + for (; cursor; cursor = cursor->next) { + root = cursor->root; + JS_SET_TRACING_INDEX(trc, "cursor_root", index++); + js_CallValueTracerIfGCThing(trc, (jsval)root); + } } /* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */ @@ -3802,10 +3848,12 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *kidobj, *listobj; JSObject *nameqn; jsid funid; + jsval roots[2]; + JSTempValueRooter tvr; xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) - return true; + return JS_TRUE; if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -3822,18 +3870,18 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); if (!kid) { *vp = JSVAL_VOID; - return true; + return JS_TRUE; } kidobj = js_GetXMLObject(cx, kid); if (!kidobj) - return false; + return JS_FALSE; *vp = OBJECT_TO_JSVAL(kidobj); } else { *vp = JSVAL_VOID; } } - return true; + return JS_TRUE; } /* @@ -3841,34 +3889,37 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) */ nameqn = ToXMLName(cx, id, &funid); if (!nameqn) - return false; + return JS_FALSE; if (funid) return GetXMLFunction(cx, obj, funid, vp); - jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL }; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + roots[0] = OBJECT_TO_JSVAL(nameqn); + JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr); listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return false; + if (listobj) { + roots[1] = OBJECT_TO_JSVAL(listobj); + tvr.count++; - roots[1] = OBJECT_TO_JSVAL(listobj); + list = (JSXML *) listobj->getPrivate(); + if (!GetNamedProperty(cx, xml, nameqn, list)) { + listobj = NULL; + } else { + /* + * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the + * given list's [[TargetProperty]] to the property that is being + * appended. This means that any use of the internal [[Get]] + * property returns a list which, when used by e.g. [[Insert]] + * duplicates the last element matched by id. See bug 336921. + */ + list->xml_target = xml; + list->xml_targetprop = nameqn; + *vp = OBJECT_TO_JSVAL(listobj); + } + } - list = (JSXML *) listobj->getPrivate(); - if (!GetNamedProperty(cx, xml, nameqn, list)) - return false; - - /* - * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the - * given list's [[TargetProperty]] to the property that is being - * appended. This means that any use of the internal [[Get]] - * property returns a list which, when used by e.g. [[Insert]] - * duplicates the last element matched by id. See bug 336921. - */ - list->xml_target = xml; - list->xml_targetprop = nameqn; - *vp = OBJECT_TO_JSVAL(listobj); - return true; + JS_POP_TEMP_ROOT(cx, &tvr); + return listobj != NULL; } static JSXML * @@ -3912,6 +3963,8 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSBool ok, primitiveAssign; enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; + jsval roots[3]; + JSTempValueRooter tvr; JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; JSObject *targetprop, *nameqn, *attrqn; @@ -3940,13 +3993,11 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ok = js_EnterLocalRootScope(cx); if (!ok) return JS_FALSE; - MUST_FLOW_THROUGH("out"); - jsval roots[3]; roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); roots[ID_ROOT] = id; roots[VAL_ROOT] = *vp; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr); if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -4533,6 +4584,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } out: + JS_POP_TEMP_ROOT(cx, &tvr); js_LeaveLocalRootScope(cx); return ok; @@ -4664,34 +4716,38 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) JSObject *pobj; JSProperty *prop; JSXML *xml; + JSTempValueRooter tvr; + JSBool ok; JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass); if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) - return false; + return JS_FALSE; if (prop) { pobj->dropProperty(cx, prop); } else { xml = (JSXML *) obj->getPrivate(); if (HasSimpleContent(xml)) { - AutoObjectRooter tvr(cx); - /* * Search in String.prototype to set found whenever * GetXMLFunction returns existing function. */ - if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) - return false; - - JS_ASSERT(tvr.object()); - if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop)) - return false; - if (prop) - pobj->dropProperty(cx, prop); + JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); + ok = js_GetClassPrototype(cx, NULL, JSProto_String, + &tvr.u.object); + JS_ASSERT(tvr.u.object); + if (ok) { + ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop); + if (ok && prop) + pobj->dropProperty(cx, prop); + } + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; } } *found = (prop != NULL); - return true; + return JS_TRUE; } /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ @@ -4958,22 +5014,18 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - *statep = JSVAL_ZERO; + cursor = NULL; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; - *statep = PRIVATE_TO_JSVAL(cursor); } + *statep = PRIVATE_TO_JSVAL(cursor); if (idp) *idp = INT_TO_JSID(length); break; case JSENUMERATE_NEXT: - if (*statep == JSVAL_ZERO) { - *statep = JSVAL_NULL; - break; - } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { *idp = INT_TO_JSID(index); @@ -4983,11 +5035,9 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - if (*statep != JSVAL_ZERO) { - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) - cx->destroy(cursor); - } + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) + cx->destroy(cursor); *statep = JSVAL_NULL; break; } @@ -5076,7 +5126,7 @@ js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * As our callers have a bad habit of passing a pointer to an unrooted * local value as vp, we use a proper root here. */ - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr()); *vp = tvr.value(); return ok; @@ -5099,22 +5149,20 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - *statep = JSVAL_ZERO; + cursor = NULL; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; - *statep = PRIVATE_TO_JSVAL(cursor); } - JS_ASSERT(!idp); - JS_ASSERT(!vp); + *statep = PRIVATE_TO_JSVAL(cursor); + if (idp) + *idp = INT_TO_JSID(length); + if (vp) + *vp = JSVAL_VOID; break; case JSENUMERATE_NEXT: - if (*statep == JSVAL_ZERO) { - *statep = JSVAL_NULL; - break; - } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) { @@ -5133,12 +5181,10 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - if (*statep != JSVAL_ZERO) { - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) { - destroy: - cx->destroy(cursor); - } + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) { + destroy: + cx->destroy(cursor); } *statep = JSVAL_NULL; break; @@ -5431,7 +5477,7 @@ xml_attributes(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; name = OBJECT_TO_JSVAL(qn); - AutoValueRooter tvr(cx, name); + JSAutoTempValueRooter tvr(cx, name); return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); } @@ -5837,6 +5883,81 @@ xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } +typedef struct JSTempRootedNSArray { + JSTempValueRooter tvr; + JSXMLArray array; + jsval value; /* extra root for temporaries */ +} JSTempRootedNSArray; + +static void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) +{ + uint32 i; + JSObject *obj; + + for (i = 0; i < len; i++) { + obj = vec[i]; + if (obj) { + JS_SET_TRACING_INDEX(trc, "vector", i); + js_CallGCMarker(trc, obj, JSTRACE_OBJECT); + } + } +} + +static void +trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr) +{ + JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr; + + TraceObjectVector(trc, + (JSObject **) tmp->array.vector, + tmp->array.length); + XMLArrayCursorTrace(trc, tmp->array.cursors); + JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value"); +} + +static void +InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) +{ + XMLArrayInit(cx, &tmp->array, 0); + tmp->value = JSVAL_NULL; + JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr); +} + +static void +FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) +{ + JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array); + JS_POP_TEMP_ROOT(cx, &tmp->tvr); + XMLArrayFinish(cx, &tmp->array); +} + +/* + * Populate a new JS array with elements of JSTempRootedNSArray.array and + * place the result into rval. rval must point to a rooted location. + */ +static JSBool +TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval) +{ + JSObject *arrayobj; + uint32 i, n; + JSObject *ns; + + arrayobj = js_NewArrayObject(cx, 0, NULL); + if (!arrayobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(arrayobj); + for (i = 0, n = tmp->array.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&tmp->array, i, JSObject); + if (!ns) + continue; + tmp->value = OBJECT_TO_JSVAL(ns); + if (!arrayobj->setProperty(cx, INT_TO_JSID(i), &tmp->value)) + return JS_FALSE; + } + return JS_TRUE; +} + static JSBool FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) { @@ -5878,48 +5999,19 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) return JS_TRUE; } -class AutoNamespaceArray : public js::AutoNamespaces { - public: - AutoNamespaceArray(JSContext *cx) - : js::AutoNamespaces(cx) - { - XMLArrayInit(cx, &array, 0); - } - - ~AutoNamespaceArray() { - XMLArrayFinish(context, &array); - } - - /* - * Populate a new JS array with elements of array and place the result into - * rval. rval must point to a rooted location. - */ - bool toJSArray(jsval *rval) { - JSObject *arrayobj = js_NewArrayObject(context, 0, NULL); - if (!arrayobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(arrayobj); - - AutoValueRooter tvr(context); - for (uint32 i = 0, n = array.length; i < n; i++) { - JSObject *ns = XMLARRAY_MEMBER(&array, i, JSObject); - if (!ns) - continue; - *tvr.addr() = OBJECT_TO_JSVAL(ns); - if (!arrayobj->setProperty(context, INT_TO_JSID(i), tvr.addr())) - return JS_FALSE; - } - return JS_TRUE; - } -}; - static JSBool xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) { + JSTempRootedNSArray namespaces; + JSBool ok; + NON_LIST_XML_METHOD_PROLOG; - AutoNamespaceArray namespaces(cx); - return FindInScopeNamespaces(cx, xml, &namespaces.array) && namespaces.toJSArray(vp); + InitTempNSArray(cx, &namespaces); + ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && + TempNSArrayToJSArray(cx, &namespaces, vp); + FinishTempNSArray(cx, &namespaces); + return ok; } static JSBool @@ -6019,13 +6111,15 @@ static JSBool xml_namespace(JSContext *cx, uintN argc, jsval *vp) { JSString *prefix, *nsprefix; + JSTempRootedNSArray inScopeNSes; + JSBool ok; jsuint i, length; JSObject *ns; NON_LIST_XML_METHOD_PROLOG; if (argc == 0 && !JSXML_HAS_NAME(xml)) { *vp = JSVAL_NULL; - return true; + return JS_TRUE; } if (argc == 0) { @@ -6033,18 +6127,22 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } else { prefix = js_ValueToString(cx, vp[2]); if (!prefix) - return false; + return JS_FALSE; vp[2] = STRING_TO_JSVAL(prefix); /* local root */ } - AutoNamespaceArray inScopeNSes(cx); - if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array)) - return false; + InitTempNSArray(cx, &inScopeNSes); + MUST_FLOW_THROUGH("out"); + ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array); + if (!ok) + goto out; if (!prefix) { ns = GetNamespace(cx, xml->name, &inScopeNSes.array); - if (!ns) - return false; + if (!ns) { + ok = JS_FALSE; + goto out; + } } else { ns = NULL; for (i = 0, length = inScopeNSes.array.length; i < length; i++) { @@ -6059,44 +6157,64 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns); - return true; + + out: + FinishTempNSArray(cx, &inScopeNSes); + return JS_TRUE; } static JSBool xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) { + JSBool ok; + JSTempRootedNSArray ancestors, declared; + JSXML *yml; + uint32 i, n; + JSObject *ns; + NON_LIST_XML_METHOD_PROLOG; if (JSXML_HAS_VALUE(xml)) - return true; + return JS_TRUE; - AutoNamespaceArray ancestors(cx); - AutoNamespaceArray declared(cx); + /* From here, control flow must goto out to finish these arrays. */ + ok = JS_TRUE; + InitTempNSArray(cx, &ancestors); + InitTempNSArray(cx, &declared); + yml = xml; - JSXML *yml = xml; while ((yml = yml->parent) != NULL) { JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); - for (uint32 i = 0, n = yml->xml_namespaces.length; i < n; i++) { - JSObject *ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); - if (ns && !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - if (!XMLARRAY_APPEND(cx, &ancestors.array, ns)) - return false; + for (i = 0, n = yml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); + if (ns && + !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + ok = XMLARRAY_APPEND(cx, &ancestors.array, ns); + if (!ok) + goto out; } } } - for (uint32 i = 0, n = xml->xml_namespaces.length; i < n; i++) { - JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); if (!ns) continue; if (!IsDeclared(ns)) continue; if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - if (!XMLARRAY_APPEND(cx, &declared.array, ns)) - return false; + ok = XMLARRAY_APPEND(cx, &declared.array, ns); + if (!ok) + goto out; } } - return declared.toJSArray(vp); + ok = TempNSArrayToJSArray(cx, &declared, vp); + +out: + /* Finishing must be in reverse order of initialization to follow LIFO. */ + FinishTempNSArray(cx, &declared); + FinishTempNSArray(cx, &ancestors); + return ok; } static const char js_attribute_str[] = "attribute"; @@ -7129,9 +7247,9 @@ js_TraceXML(JSTracer *trc, JSXML *xml) if (xml->xml_targetprop) JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop"); } else { - js::TraceObjectVector(trc, - (JSObject **) xml->xml_namespaces.vector, - xml->xml_namespaces.length); + TraceObjectVector(trc, + (JSObject **) xml->xml_namespaces.vector, + xml->xml_namespaces.length); XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); if (IS_GC_MARKING_TRACER(trc)) XMLArrayTrim(&xml->xml_namespaces); @@ -7164,12 +7282,17 @@ js_FinalizeXML(JSContext *cx, JSXML *xml) JSObject * js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) { - JSXML *xml = js_NewXML(cx, xml_class); + JSXML *xml; + JSObject *obj; + JSTempValueRooter tvr; + + xml = js_NewXML(cx, xml_class); if (!xml) return NULL; - - AutoXMLRooter root(cx, xml); - return js_GetXMLObject(cx, xml); + JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr); + obj = js_GetXMLObject(cx, xml); + JS_POP_TEMP_ROOT(cx, &tvr); + return obj; } static JSObject * @@ -7686,35 +7809,48 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) static JSBool GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { + JSObject *target; + JSXML *xml; + JSTempValueRooter tvr; + JSBool ok; + JS_ASSERT(OBJECT_IS_XML(cx, obj)); + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); + /* * See comments before xml_lookupProperty about the need for the proto * chain lookup. */ - JSObject *target = obj; - AutoObjectRooter tvr(cx); + target = obj; for (;;) { - if (!js_GetProperty(cx, target, id, vp)) - return false; - if (VALUE_IS_FUNCTION(cx, *vp)) - return true; + ok = js_GetProperty(cx, target, id, vp); + if (!ok) + goto out; + if (VALUE_IS_FUNCTION(cx, *vp)) { + ok = JS_TRUE; + goto out; + } target = target->getProto(); if (target == NULL) break; - tvr.setObject(target); + tvr.u.object = target; } - JSXML *xml = (JSXML *) obj->getPrivate(); - if (!HasSimpleContent(xml)) - return true; + xml = (JSXML *) obj->getPrivate(); + if (HasSimpleContent(xml)) { + /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ + ok = js_GetClassPrototype(cx, NULL, JSProto_String, &tvr.u.object); + if (!ok) + goto out; + JS_ASSERT(tvr.u.object); + ok = tvr.u.object->getProperty(cx, id, vp); + } - /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ - if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) - return false; - - JS_ASSERT(tvr.object()); - return tvr.object()->getProperty(cx, id, vp); + out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; } static JSXML * diff --git a/js/src/jsxml.h b/js/src/jsxml.h index 37724757e267..cb7198f59860 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -39,7 +39,7 @@ #ifndef jsxml_h___ #define jsxml_h___ -#include "jsarray.h" +#include "jspubtd.h" JS_BEGIN_EXTERN_C @@ -63,58 +63,6 @@ struct JSXMLArray { JSXMLArrayCursor *cursors; }; -struct JSXMLArrayCursor -{ - JSXMLArray *array; - uint32 index; - JSXMLArrayCursor *next; - JSXMLArrayCursor **prevp; - void *root; - - JSXMLArrayCursor(JSXMLArray *array) - : array(array), index(0), next(array->cursors), prevp(&array->cursors), - root(NULL) - { - if (next) - next->prevp = &next; - array->cursors = this; - } - - ~JSXMLArrayCursor() { disconnect(); } - - void disconnect() { - if (!array) - return; - if (next) - next->prevp = prevp; - *prevp = next; - array = NULL; - } - - void *getNext() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index++]; - } - - void *getCurrent() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index]; - } - - void trace(JSTracer *trc) { -#ifdef DEBUG - size_t index = 0; -#endif - for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) { - void *root = cursor->root; - JS_SET_TRACING_INDEX(trc, "cursor_root", index++); - js_CallValueTracerIfGCThing(trc, jsval(root)); - } - } -}; - #define JSXML_PRESET_CAPACITY JS_BIT(31) #define JSXML_CAPACITY_MASK JS_BITMASK(31) #define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp index 8444c1359947..70724cadeb6e 100644 --- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For js::AutoValueRooter. +#include "jscntxt.h" // For JSAutoTempValueRooter. #include "jsobj.h" #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -283,16 +283,17 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) *vp = OBJECT_TO_JSVAL(wrapperObj); - js::AutoValueRooter exposedProps(cx, JSVAL_VOID); + jsval exposedProps = JSVAL_VOID; + JSAutoTempValueRooter tvr(cx, 1, &exposedProps); - if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) { + if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) || - !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || - !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, - exposedProps.value())) { + !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, + JSVAL_ZERO) || + !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) { return JS_FALSE; } @@ -777,7 +778,7 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our COW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 3b9f5f608025..9a9631482783 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For js::AutoValueRooter. +#include "jscntxt.h" // For JSAutoTempValueRooter. #include "XPCWrapper.h" #include "nsIDOMWindow.h" #include "nsIDOMWindowCollection.h" @@ -830,7 +830,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj) return nsnull; } - js::AutoValueRooter tvr(cx, uxpco); + JSAutoTempValueRooter tvr(cx, uxpco); jsval wrappedObj, parentScope; if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) || @@ -1206,7 +1206,7 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our XOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index c3fe67645fd7..72daa9079c5a 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1118,7 +1118,7 @@ XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our native wrapper. XPCWrappedNative *wn = static_cast(JS_GetPrivate(cx, obj)); diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 074cb8e4594e..a0ec10566de1 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -478,7 +478,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NS_STACK_CLASS class SafeCallGuard { public: SafeCallGuard(JSContext *cx, nsIPrincipal *principal) - : cx(cx), tvr(cx) { + : cx(cx) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (ssm) { // Note: We pass null as the target frame pointer because we know that @@ -517,7 +517,7 @@ public: private: JSContext *cx; JSRegExpStatics statics; - js::AutoValueRooter tvr; + JSTempValueRooter tvr; uint32 options; JSStackFrame *fp; }; @@ -957,7 +957,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index b4c62f09aeac..406adb39c320 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For js::AutoValueRooter. +#include "jscntxt.h" // For JSAutoTempValueRooter. #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -137,7 +137,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) } *vp = OBJECT_TO_JSVAL(wrapperObj); - js::AutoValueRooter tvr(cx, *vp); + JSAutoTempValueRooter tvr(cx, *vp); if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { @@ -437,7 +437,7 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - js::AutoArrayRooter tvr(cx, 1, vp); + JSAutoTempValueRooter tvr(cx, 1, vp); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { @@ -649,7 +649,7 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our SOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index 2d3beb3a714c..b6fc00c21d7d 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -153,7 +153,7 @@ IteratorNext(JSContext *cx, uintN argc, jsval *vp) } jsval vec[2] = { STRING_TO_JSVAL(str), v }; - js::AutoArrayRooter tvr(cx, 2, vec); + JSAutoTempValueRooter tvr(cx, 2, vec); JSObject *array = JS_NewArrayObject(cx, 2, vec); if (!array) { return JS_FALSE; @@ -192,7 +192,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); // Do this sooner rather than later to avoid complications in // IteratorFinalize. @@ -213,7 +213,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, // call enumerate, and then re-set the prototype. As we do this, we have // to protec the temporary wrapper from garbage collection. - js::AutoValueRooter tvr(cx, tempWrapper); + JSAutoTempValueRooter tvr(cx, tempWrapper); if (!JS_SetPrototype(cx, iterObj, wrapperObj) || !XPCWrapper::Enumerate(cx, iterObj, wrapperObj) || !JS_SetPrototype(cx, iterObj, tempWrapper)) { diff --git a/js/src/xpconnect/src/qsgen.py b/js/src/xpconnect/src/qsgen.py index 0f7c90d485b1..a3021f15b574 100644 --- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -833,7 +833,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): if isGetter: pthisval = 'vp' elif isSetter: - f.write(" js::AutoValueRooter tvr(cx);\n") + f.write(" JSAutoTempValueRooter tvr(cx);\n") pthisval = 'tvr.addr()' else: pthisval = '&vp[1]' # as above, ok to overwrite vp[1] diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index d4417a050bcb..544990da4c67 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1582,23 +1582,23 @@ XPCConvert::ConstructException(nsresult rv, const char* message, /********************************/ -class AutoExceptionRestorer +class AutoExceptionRestorer : public JSAutoTempValueRooter { public: AutoExceptionRestorer(JSContext *cx, jsval v) - : mContext(cx), tvr(cx, v) + : JSAutoTempValueRooter(cx, v), + mVal(v) { JS_ClearPendingException(mContext); } ~AutoExceptionRestorer() { - JS_SetPendingException(mContext, tvr.value()); + JS_SetPendingException(mContext, mVal); } private: - JSContext * const mContext; - js::AutoValueRooter tvr; + jsval mVal; }; // static diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index d30e2ef68012..cc26a2220217 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -173,7 +173,7 @@ GeneratePropertyOp(JSContext *cx, JSObject *obj, jsval idval, uintN argc, JSObject *funobj = JS_GetFunctionObject(fun); - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); // Unfortunately, we cannot guarantee that JSPropertyOp is aligned. Use a // second object to work around this. @@ -198,7 +198,7 @@ ReifyPropertyOps(JSContext *cx, JSObject *obj, jsval idval, jsid interned_id, { // Generate both getter and setter and stash them in the prototype. jsval roots[2] = { JSVAL_NULL, JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, 2, roots); + JSAutoTempValueRooter tvr(cx, 2, roots); uintN attrs = JSPROP_SHARED; JSObject *getterobj; diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index 0943aab68a11..de2446cd243b 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -321,7 +321,7 @@ struct xpc_qsArgValArray memset(array, 0, N * sizeof(jsval)); } - js::AutoArrayRooter tvr; + JSAutoTempValueRooter tvr; jsval array[N]; }; diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 75964e97386c..fb7e1192a64f 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -1517,7 +1517,8 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) JSStackFrame *fp; nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp); - js::AutoValueRooter retval(cx, obj); + jsval retval = OBJECT_TO_JSVAL(obj); + JSAutoTempValueRooter atvr(cx, 1, &retval); if(principal && fp) { @@ -1534,7 +1535,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags, - retval.addr()); + &retval); if(NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); @@ -1542,7 +1543,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } } - return JSVAL_TO_OBJECT(retval.value()); + return JSVAL_TO_OBJECT(retval); } JSObjectOps * diff --git a/js/src/xpconnect/tests/TestXPC.cpp b/js/src/xpconnect/tests/TestXPC.cpp index 5c69f4c7e03e..b9e6e723b8ca 100644 --- a/js/src/xpconnect/tests/TestXPC.cpp +++ b/js/src/xpconnect/tests/TestXPC.cpp @@ -562,7 +562,7 @@ TestArgFormatter(JSContext* jscontext, JSObject* glob, nsIXPConnect* xpc) // Prepare an array of arguments for JS_ConvertArguments jsval argv[5]; - js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv); + JSAutoTempValueRooter tvr(jscontext, 5, argv); if (!PushArguments(jscontext, 5, argv, "s %ip %iv %is s", diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index c595fca8f708..22062d4765d2 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -673,36 +673,36 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args, } } + JSTempValueRooter tvr; + JS_PUSH_TEMP_ROOT(cx, 0, jsargs, &tvr); + + // Convert args + for (PRUint32 i = 0; i < argCount; ++i) { + jsargs[i] = NPVariantToJSVal(npp, cx, args + i); + ++tvr.count; + } + jsval v; JSBool ok; - { - js::AutoArrayRooter tvr(cx, 0, jsargs); + if (ctorCall) { + JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); + JSObject *newObj = + ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), + nsnull, global, argCount, jsargs); - // Convert args - for (PRUint32 i = 0; i < argCount; ++i) { - jsargs[i] = NPVariantToJSVal(npp, cx, args + i); - tvr.changeLength(i + 1); - } - - if (ctorCall) { - JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); - JSObject *newObj = - ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), - nsnull, global, argCount, jsargs); - - if (newObj) { - v = OBJECT_TO_JSVAL(newObj); - ok = JS_TRUE; - } else { - ok = JS_FALSE; - } + if (newObj) { + v = OBJECT_TO_JSVAL(newObj); + ok = JS_TRUE; } else { - ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); + ok = JS_FALSE; } - + } else { + ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); } + JS_POP_TEMP_ROOT(cx, &tvr); + if (jsargs != jsargs_buf) PR_Free(jsargs); @@ -837,7 +837,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, AutoJSExceptionReporter reporter(cx); jsval v = NPVariantToJSVal(npp, cx, value); - js::AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); if (JSVAL_IS_STRING(id)) { JSString *str = JSVAL_TO_STRING(id); diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index ac912561d0df..92843fff99f2 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -1693,7 +1693,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) // Root obj and the rval (below). jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); + JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); jsval *rval = &vec[1]; if (result) { diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index f35807655d15..98dceafa4f28 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -247,7 +247,7 @@ XPITriggerEvent::Run() // Build arguments into rooted jsval array jsval args[2] = { JSVAL_NULL, JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(args), args); // args[0] is the URL JSString *str = JS_NewUCStringCopyZ(cx, URL.get()); From 805c7064c34152bca581f380b0044837826799c6 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Fri, 26 Mar 2010 19:37:45 -0700 Subject: [PATCH 149/213] Bug 555104 - remove JS_ExecuteScriptPart (r=brendan) --- js/src/jsapi.cpp | 30 ------------------------------ js/src/jsapi.h | 12 ++++-------- 2 files changed, 4 insertions(+), 38 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 028893f584a9..9e0e840feb9d 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4840,36 +4840,6 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval) return ok; } -JS_PUBLIC_API(JSBool) -JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script, - JSExecPart part, jsval *rval) -{ - JSScript tmp; - JSBool ok; - - /* Make a temporary copy of the JSScript structure and farble it a bit. */ - tmp = *script; - if (part == JSEXEC_PROLOG) { - tmp.length = tmp.main - tmp.code; - } else { - tmp.length -= tmp.main - tmp.code; - tmp.code = tmp.main; - } - - /* Tell the debugger about our temporary copy of the script structure. */ - const JSDebugHooks *hooks = cx->debugHooks; - if (hooks->newScriptHook) { - hooks->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL, - hooks->newScriptHookData); - } - - /* Execute the farbled struct and tell the debugger to forget about it. */ - ok = JS_ExecuteScript(cx, obj, &tmp, rval); - if (hooks->destroyScriptHook) - hooks->destroyScriptHook(cx, &tmp, hooks->destroyScriptHookData); - return ok; -} - /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */ JS_PUBLIC_API(JSBool) JS_EvaluateScript(JSContext *cx, JSObject *obj, diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 4d8f1c1c9316..4704bedf22c7 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2261,10 +2261,10 @@ extern JS_PUBLIC_API(JSString *) JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent); /* - * NB: JS_ExecuteScript, JS_ExecuteScriptPart, and the JS_Evaluate*Script* - * quadruplets all use the obj parameter as the initial scope chain header, - * the 'this' keyword value, and the variables object (ECMA parlance for where - * 'var' and 'function' bind names) of the execution context for script. + * NB: JS_ExecuteScript and the JS_Evaluate*Script* quadruplets use the obj + * parameter as the initial scope chain header, the 'this' keyword value, and + * the variables object (ECMA parlance for where 'var' and 'function' bind + * names) of the execution context for script. * * Using obj as the variables object is problematic if obj's parent (which is * the scope chain link; see JS_SetParent and JS_NewObject) is not null: in @@ -2304,10 +2304,6 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval); */ typedef enum JSExecPart { JSEXEC_PROLOG, JSEXEC_MAIN } JSExecPart; -extern JS_PUBLIC_API(JSBool) -JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script, - JSExecPart part, jsval *rval); - extern JS_PUBLIC_API(JSBool) JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN length, From d3403826f112e42a13ae3a58d55f58d82d1bebd4 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 26 Mar 2010 22:57:23 -0700 Subject: [PATCH 150/213] Fix mismerge. --- js/src/jsobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 103ec7520c9e..e0068fa139ca 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1685,7 +1685,7 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, * owned, or indirectly delegated. */ JSScopeProperty *sprop = reinterpret_cast(*propp); - if (!sprop->isSharedPermanent()) + if (sprop->isSharedPermanent()) return true; } From 24b5cef632216db01055aab2454dcd902b24245e Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sat, 27 Mar 2010 00:04:10 -0700 Subject: [PATCH 151/213] More mismerging fixes. --- js/src/jsexn.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 171c14821405..c62beef5ec1b 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -839,9 +839,8 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) *vp = STRING_TO_JSVAL(name); JSTempValueRooter tvr; + JSBool ok; { - JSBool ok; - MUST_FLOW_THROUGH("out"); JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); @@ -953,7 +952,7 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) out: JS_POP_TEMP_ROOT(cx, &tvr); - return JS_FALSE; + return JS_TRUE; } #endif From cfa3e60dd635302b29bb1ec1dcde8a45ab92ffe6 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 28 Mar 2010 13:34:16 -0700 Subject: [PATCH 152/213] Readd more of the new rooting scaffolding from bug 548702, without enabling it (except in a side-by-side fashion where the two can both function and coexist). --- js/src/jscntxtinlines.h | 155 ++++++++++++++++++++++++++++++++++++++++ js/src/jsgc.cpp | 22 +++++- js/src/jsgc.h | 19 +++++ js/src/jsxml.cpp | 67 +---------------- js/src/jsxml.h | 52 ++++++++++++++ 5 files changed, 247 insertions(+), 68 deletions(-) create mode 100644 js/src/jscntxtinlines.h diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h new file mode 100644 index 000000000000..30551abc648e --- /dev/null +++ b/js/src/jscntxtinlines.h @@ -0,0 +1,155 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Walden (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscntxtinlines_h___ +#define jscntxtinlines_h___ + +#include "jscntxt.h" +#include "jsxml.h" + +#include "jsobjinlines.h" + +namespace js { + +void +AutoIdArray::trace(JSTracer *trc) { + JS_ASSERT(tag == IDARRAY); + js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); +} + +class AutoNamespaces : protected AutoGCRooter { + protected: + AutoNamespaces(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) { + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + public: + JSXMLArray array; +}; + +inline void +AutoGCRooter::trace(JSTracer *trc) +{ + switch (tag) { + case JSVAL: + JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val"); + js_CallValueTracerIfGCThing(trc, static_cast(this)->val); + return; + + case SPROP: + static_cast(this)->sprop->trace(trc); + return; + + case WEAKROOTS: + static_cast(this)->savedRoots.mark(trc); + return; + + case COMPILER: +#if 0 /* JSCompiler is still old-style */ + static_cast(this)->trace(trc); +#else + JS_ASSERT(0); +#endif + return; + + case SCRIPT: + if (JSScript *script = static_cast(this)->script) + js_TraceScript(trc, script); + return; + + case ENUMERATOR: + static_cast(this)->trace(trc); + return; + + case IDARRAY: { + JSIdArray *ida = static_cast(this)->idArray; + TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); + return; + } + + case DESCRIPTORS: { +#if 0 /* AutoDescriptorArray is still old-style */ + PropertyDescriptorArray &descriptors = + static_cast(this)->descriptors; + for (size_t i = 0, len = descriptors.length(); i < len; i++) { + PropertyDescriptor &desc = descriptors[i]; + + JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); + JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); + JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); + js_TraceId(trc, desc.id); + } +#else + JS_ASSERT(0); +#endif + return; + } + + case NAMESPACES: { + JSXMLArray &array = static_cast(this)->array; + TraceObjectVector(trc, reinterpret_cast(array.vector), array.length); + array.cursors->trace(trc); + return; + } + + case XML: + js_TraceXML(trc, static_cast(this)->xml); + return; + + case OBJECT: + if (JSObject *obj = static_cast(this)->obj) { + JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj"); + js_CallGCMarker(trc, obj, JSTRACE_OBJECT); + } + return; + + case ID: + JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val"); + js_CallValueTracerIfGCThing(trc, static_cast(this)->idval); + return; + } + + JS_ASSERT(tag >= 0); + TraceValues(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); +} + +} + +#endif /* jscntxtinlines_h___ */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index bc4c46e17885..0446ff7a22fa 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -87,6 +87,7 @@ #include "jsdtracef.h" #endif +#include "jscntxtinlines.h" #include "jsobjinlines.h" /* @@ -2283,6 +2284,21 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, } \ JS_END_MACRO +namespace js { + +void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) +{ + for (uint32 i = 0; i < len; i++) { + if (JSObject *obj = vec[i]) { + JS_SET_TRACING_INDEX(trc, "vector", i); + js_CallGCMarker(trc, obj, JSTRACE_OBJECT); + } + } +} + +} + void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) { @@ -2387,7 +2403,6 @@ JS_REQUIRES_STACK JS_FRIEND_API(void) js_TraceContext(JSTracer *trc, JSContext *acx) { JSStackHeader *sh; - JSTempValueRooter *tvr; /* * Trace active and suspended callstacks. @@ -2440,7 +2455,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); } - for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { + for (JSTempValueRooter *tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { switch (tvr->count) { case JSTVU_SINGLE: JS_SET_TRACING_NAME(trc, "tvr->u.value"); @@ -2470,6 +2485,9 @@ js_TraceContext(JSTracer *trc, JSContext *acx) } } + for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) + gcr->trace(trc); + if (acx->sharpObjectMap.depth > 0) js_TraceSharpMap(trc, &acx->sharpObjectMap); diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 8ec4f22554c9..d7726d8b960c 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -455,4 +455,23 @@ js_MarkTraps(JSTracer *trc); JS_END_EXTERN_C +namespace js { + +void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len); + +inline void +TraceValues(JSTracer *trc, size_t len, jsval *vec, const char *name) +{ + for (jsval *vp = vec, *end = vp + len; vp < end; vp++) { + jsval v = *vp; + if (JSVAL_IS_TRACEABLE(v)) { + JS_SET_TRACING_INDEX(trc, name, vp - vec); + js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + } + } +} + +} + #endif /* jsgc_h___ */ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 6d10212120a1..361f7e8ec3ad 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -868,60 +868,10 @@ attr_identity(const void *a, const void *b) return qname_identity(xmla->name, xmlb->name); } -struct JSXMLArrayCursor -{ - JSXMLArray *array; - uint32 index; - JSXMLArrayCursor *next; - JSXMLArrayCursor **prevp; - void *root; - - JSXMLArrayCursor(JSXMLArray *array) - : array(array), index(0), next(array->cursors), prevp(&array->cursors), - root(NULL) - { - if (next) - next->prevp = &next; - array->cursors = this; - } - - ~JSXMLArrayCursor() { disconnect(); } - - void disconnect() { - if (!array) - return; - if (next) - next->prevp = prevp; - *prevp = next; - array = NULL; - } - - void *getNext() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index++]; - } - - void *getCurrent() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index]; - } -}; - static void XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor) { - void *root; -#ifdef DEBUG - size_t index = 0; -#endif - - for (; cursor; cursor = cursor->next) { - root = cursor->root; - JS_SET_TRACING_INDEX(trc, "cursor_root", index++); - js_CallValueTracerIfGCThing(trc, (jsval)root); - } + cursor->trace(trc); } /* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */ @@ -5886,21 +5836,6 @@ typedef struct JSTempRootedNSArray { jsval value; /* extra root for temporaries */ } JSTempRootedNSArray; -static void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) -{ - uint32 i; - JSObject *obj; - - for (i = 0; i < len; i++) { - obj = vec[i]; - if (obj) { - JS_SET_TRACING_INDEX(trc, "vector", i); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - } -} - static void trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr) { diff --git a/js/src/jsxml.h b/js/src/jsxml.h index cb7198f59860..d5b20b0c881b 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -63,6 +63,58 @@ struct JSXMLArray { JSXMLArrayCursor *cursors; }; +struct JSXMLArrayCursor +{ + JSXMLArray *array; + uint32 index; + JSXMLArrayCursor *next; + JSXMLArrayCursor **prevp; + void *root; + + JSXMLArrayCursor(JSXMLArray *array) + : array(array), index(0), next(array->cursors), prevp(&array->cursors), + root(NULL) + { + if (next) + next->prevp = &next; + array->cursors = this; + } + + ~JSXMLArrayCursor() { disconnect(); } + + void disconnect() { + if (!array) + return; + if (next) + next->prevp = prevp; + *prevp = next; + array = NULL; + } + + void *getNext() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index++]; + } + + void *getCurrent() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index]; + } + + void trace(JSTracer *trc) { +#ifdef DEBUG + size_t index = 0; +#endif + for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) { + void *root = cursor->root; + JS_SET_TRACING_INDEX(trc, "cursor_root", index++); + js_CallValueTracerIfGCThing(trc, jsval(root)); + } + } +}; + #define JSXML_PRESET_CAPACITY JS_BIT(31) #define JSXML_CAPACITY_MASK JS_BITMASK(31) #define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) From eabbe4cfb97b2817174f471a727347a17edd4e16 Mon Sep 17 00:00:00 2001 From: Ignore Bukanov Date: Sun, 28 Mar 2010 15:31:53 -0700 Subject: [PATCH 153/213] Bug 555338 - preprocessor define to tell when rdtsc is available. r=nnethercote. --HG-- extra : convert_revision : 673444e26f4810744ff252ee113fd7f0f3d5a7c9 --- js/src/nanojit/avmplus.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/js/src/nanojit/avmplus.h b/js/src/nanojit/avmplus.h index c29ae153134c..dd3c1a6d2024 100644 --- a/js/src/nanojit/avmplus.h +++ b/js/src/nanojit/avmplus.h @@ -92,6 +92,9 @@ void NanoAssertFail(); #if defined(AVMPLUS_IA32) #if defined(_MSC_VER) + +# define AVMPLUS_HAS_RDTSC 1 + __declspec(naked) static inline __int64 rdtsc() { __asm @@ -100,24 +103,35 @@ __declspec(naked) static inline __int64 rdtsc() ret; } } + #elif defined(SOLARIS) + +# define AVMPLUS_HAS_RDTSC 1 + static inline unsigned long long rdtsc(void) { unsigned long long int x; asm volatile (".byte 0x0f, 0x31" : "=A" (x)); return x; } + #elif defined(__i386__) + +# define AVMPLUS_HAS_RDTSC 1 + static __inline__ unsigned long long rdtsc(void) { unsigned long long int x; __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); return x; } + #endif /* compilers */ #elif defined(__x86_64__) +# define AVMPLUS_HAS_RDTSC 1 + static __inline__ uint64_t rdtsc(void) { unsigned hi, lo; @@ -127,6 +141,8 @@ static __inline__ uint64_t rdtsc(void) #elif defined(_MSC_VER) && defined(_M_AMD64) +# define AVMPLUS_HAS_RDTSC 1 + #include #pragma intrinsic(__rdtsc) @@ -137,6 +153,8 @@ static inline unsigned __int64 rdtsc(void) #elif defined(__powerpc__) +# define AVMPLUS_HAS_RDTSC 1 + typedef unsigned long long int unsigned long long; static __inline__ unsigned long long rdtsc(void) @@ -161,6 +179,10 @@ static __inline__ unsigned long long rdtsc(void) #endif /* architecture */ +#ifndef AVMPLUS_HAS_RDTSC +# define AVMPLUS_HAS_RDTSC 0 +#endif + struct JSContext; #ifdef PERFM From 3e7c79263b4a6ee5e085c27f51f66447154f0b71 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 28 Mar 2010 16:49:42 -0700 Subject: [PATCH 154/213] Bug 541030 - nanojit: isconstq() should only succeed for 64-bit integer. r=rreitmai. --HG-- extra : convert_revision : b8fea2e57673f9f2d4e864870d73ee294cabd4bd --- js/src/nanojit/Assembler.cpp | 14 ++++++------ js/src/nanojit/LIR.cpp | 28 ++++++++++++------------ js/src/nanojit/LIR.h | 39 ++++++++++++++++++++++------------ js/src/nanojit/NativeARM.cpp | 8 +++---- js/src/nanojit/NativeMIPS.cpp | 4 ++-- js/src/nanojit/NativePPC.cpp | 2 ++ js/src/nanojit/NativeSparc.cpp | 2 +- js/src/nanojit/NativeX64.cpp | 2 +- js/src/nanojit/Nativei386.cpp | 6 +++--- 9 files changed, 60 insertions(+), 45 deletions(-) diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index a6ab33bc5afa..06297fe06f23 100755 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -259,7 +259,7 @@ namespace nanojit * they can just be recalculated w/out any inputs. */ bool Assembler::canRemat(LIns *i) { - return i->isconst() || i->isconstq() || i->isop(LIR_alloc); + return i->isImmAny() || i->isop(LIR_alloc); } void Assembler::codeAlloc(NIns *&start, NIns *&end, NIns *&eip @@ -568,7 +568,7 @@ namespace nanojit int Assembler::findMemFor(LIns *ins) { #if NJ_USES_QUAD_CONSTANTS - NanoAssert(!ins->isconstq()); + NanoAssert(!ins->isconstf()); #endif if (!ins->isInAr()) { uint32_t const arIndex = arReserve(ins); @@ -1918,18 +1918,18 @@ namespace nanojit LIns *ins = p->head; NanoAssert(ins->isLive()); LIns *op1 = ins->oprnd1(); - // must findMemFor even if we're going to findRegFor; loop-carried + // Must findMemFor even if we're going to findRegFor; loop-carried // operands may spill on another edge, and we need them to always // spill to the same place. #if NJ_USES_QUAD_CONSTANTS - // exception: if quad constants are true constants, we should - // never call findMemFor on those ops - if (!op1->isconstq()) + // Exception: if float constants are true constants, we should + // never call findMemFor on those ops. + if (!op1->isconstf()) #endif { findMemFor(op1); } - if (! (op1->isconst() || op1->isconstf() || op1->isconstq())) + if (!op1->isImmAny()) findRegFor(op1, ins->isop(LIR_flive) ? FpRegs : GpRegs); } diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index d71349153ad9..c43b0c228a8f 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -524,13 +524,13 @@ namespace nanojit #endif #if NJ_SOFTFLOAT_SUPPORTED case LIR_qlo: - if (oprnd->isconstq()) + if (oprnd->isconstf()) return insImm(oprnd->imm64_0()); if (oprnd->isop(LIR_qjoin)) return oprnd->oprnd1(); break; case LIR_qhi: - if (oprnd->isconstq()) + if (oprnd->isconstf()) return insImm(oprnd->imm64_1()); if (oprnd->isop(LIR_qjoin)) return oprnd->oprnd2(); @@ -550,7 +550,7 @@ namespace nanojit return out->ins2(LIR_sub, oprnd->oprnd2(), oprnd->oprnd1()); goto involution; case LIR_fneg: - if (oprnd->isconstq()) + if (oprnd->isconstf()) return insImmf(-oprnd->imm64f()); if (oprnd->isop(LIR_fsub)) return out->ins2(LIR_fsub, oprnd->oprnd2(), oprnd->oprnd1()); @@ -560,7 +560,7 @@ namespace nanojit return insImmf(oprnd->imm32()); break; case LIR_f2i: - if (oprnd->isconstq()) + if (oprnd->isconstf()) return insImm(int32_t(oprnd->imm64f())); break; case LIR_u2f: @@ -681,7 +681,7 @@ namespace nanojit ; } } - else if (oprnd1->isconstq() && oprnd2->isconstq()) + else if (oprnd1->isconstf() && oprnd2->isconstf()) { double c1 = oprnd1->imm64f(); double c2 = oprnd2->imm64f(); @@ -1521,10 +1521,10 @@ namespace nanojit , maxlive(0) { } - void add(LInsp i, LInsp use) { - if (!i->isconst() && !i->isconstq() && !live.containsKey(i)) { - NanoAssert(size_t(i->opcode()) < sizeof(lirNames) / sizeof(lirNames[0])); - live.put(i,use); + void add(LInsp ins, LInsp use) { + if (!ins->isImmAny() && !live.containsKey(ins)) { + NanoAssert(size_t(ins->opcode()) < sizeof(lirNames) / sizeof(lirNames[0])); + live.put(ins,use); } } @@ -1902,14 +1902,16 @@ namespace nanojit if (name) { VMPI_snprintf(buf->buf, buf->len, "%s", name); } - else if (ref->isconstf()) { - VMPI_snprintf(buf->buf, buf->len, "%g", ref->imm64f()); + else if (ref->isconst()) { + formatImm(buf, ref->imm32()); } +#ifdef NANOJIT_64BIT else if (ref->isconstq()) { formatImmq(buf, ref->imm64()); } - else if (ref->isconst()) { - formatImm(buf, ref->imm32()); +#endif + else if (ref->isconstf()) { + VMPI_snprintf(buf->buf, buf->len, "%g", ref->imm64f()); } else { name = lirNameMap->createName(ref); diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 970dfbe00d86..59b25de1fb68 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -816,24 +816,22 @@ namespace nanojit isop(LIR_xbarrier) || isop(LIR_xtbl) || isop(LIR_addxov) || isop(LIR_subxov) || isop(LIR_mulxov); } - // True if the instruction is a 32-bit or smaller constant integer. + // True if the instruction is a 32-bit integer immediate. bool isconst() const { return isop(LIR_int); } - // True if the instruction is a 32-bit or smaller constant integer and - // has the value val when treated as a 32-bit signed integer. + // True if the instruction is a 32-bit integer immediate and + // has the value 'val' when treated as a 32-bit signed integer. bool isconstval(int32_t val) const { return isconst() && imm32()==val; } - // True if the instruction is a constant quad value. - bool isconstq() const { - return #ifdef NANOJIT_64BIT - isop(LIR_quad) || -#endif - isop(LIR_float); + // True if the instruction is a 64-bit integer immediate. + bool isconstq() const { + return isop(LIR_quad); } - // True if the instruction is a constant pointer value. +#endif + // True if the instruction is a pointer-sized integer immediate. bool isconstp() const { #ifdef NANOJIT_64BIT @@ -842,10 +840,22 @@ namespace nanojit return isconst(); #endif } - // True if the instruction is a constant float value. + // True if the instruction is a 64-bit float immediate. bool isconstf() const { return isop(LIR_float); } + // True if the instruction is a 64-bit integer or float immediate. + bool isconstqf() const { + return +#ifdef NANOJIT_64BIT + isconstq() || +#endif + isconstf(); + } + // True if the instruction an any type of immediate. + bool isImmAny() const { + return isconst() || isconstqf(); + } bool isBranch() const { return isop(LIR_jt) || isop(LIR_jf) || isop(LIR_j) || isop(LIR_jtbl); @@ -1316,13 +1326,14 @@ namespace nanojit inline int32_t LIns::imm32() const { NanoAssert(isconst()); return toLInsI()->imm32; } - inline int32_t LIns::imm64_0() const { NanoAssert(isconstq()); return toLInsN64()->imm64_0; } - inline int32_t LIns::imm64_1() const { NanoAssert(isconstq()); return toLInsN64()->imm64_1; } + inline int32_t LIns::imm64_0() const { NanoAssert(isconstqf()); return toLInsN64()->imm64_0; } + inline int32_t LIns::imm64_1() const { NanoAssert(isconstqf()); return toLInsN64()->imm64_1; } uint64_t LIns::imm64() const { - NanoAssert(isconstq()); + NanoAssert(isconstqf()); return (uint64_t(toLInsN64()->imm64_1) << 32) | uint32_t(toLInsN64()->imm64_0); } double LIns::imm64f() const { + NanoAssert(isconstf()); union { double f; uint64_t q; diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp index fa6ff4ee7231..423f6dd44394 100644 --- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -1395,7 +1395,7 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) if (_config.arm_vfp) { Register rb = findRegFor(base, GpRegs); - if (value->isconstq()) { + if (value->isconstf()) { underrunProtect(LD32_size*2 + 8); // XXX use another reg, get rid of dependency @@ -1428,7 +1428,7 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) // if it's a constant, make sure our baseReg/baseOffset location // has the right value - if (value->isconstq()) { + if (value->isconstf()) { underrunProtect(4*4); asm_immf_nochk(rv, value->imm64_0(), value->imm64_1()); } @@ -1444,7 +1444,7 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) if (_config.arm_vfp) { Register rb = findRegFor(base, GpRegs); - if (value->isconstq()) { + if (value->isconstf()) { underrunProtect(LD32_size*2 + 8); // XXX use another reg, get rid of dependency @@ -1479,7 +1479,7 @@ Assembler::asm_store64(LOpcode op, LInsp value, int dr, LInsp base) // if it's a constant, make sure our baseReg/baseOffset location // has the right value - if (value->isconstq()) { + if (value->isconstf()) { underrunProtect(4*4); asm_immf_nochk(rv, value->imm64_0(), value->imm64_1()); } diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp index 33d78e06aed1..cf9f79d25a44 100644 --- a/js/src/nanojit/NativeMIPS.cpp +++ b/js/src/nanojit/NativeMIPS.cpp @@ -361,7 +361,7 @@ namespace nanojit void Assembler::asm_store_imm64(LIns *value, int dr, Register rbase) { - NanoAssert(value->isconstq()); + NanoAssert(value->isconstf()); int32_t msw = value->imm64_1(); int32_t lsw = value->imm64_0(); @@ -1102,7 +1102,7 @@ namespace nanojit else rbase = findRegFor(base, GpRegs); - if (value->isconstq()) + if (value->isconstf()) asm_store_imm64(value, dr, rbase); else if (!cpu_has_fpu || value->isop(LIR_ldq)) { diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp index c825d52754d5..dcf91251e644 100644 --- a/js/src/nanojit/NativePPC.cpp +++ b/js/src/nanojit/NativePPC.cpp @@ -625,6 +625,8 @@ namespace nanojit } asm_li(r, i->imm32()); } + // XXX: should really rematerializable isconstf() and isconstq() cases + // here; canRemat() assumes they will be rematerialized. else { d = findMemFor(i); if (IsFpReg(r)) { diff --git a/js/src/nanojit/NativeSparc.cpp b/js/src/nanojit/NativeSparc.cpp index e3694716d691..85f41a4f9199 100644 --- a/js/src/nanojit/NativeSparc.cpp +++ b/js/src/nanojit/NativeSparc.cpp @@ -383,7 +383,7 @@ namespace nanojit } underrunProtect(48); - if (value->isconstq()) + if (value->isconstf()) { // if a constant 64-bit value just store it now rather than // generating a pointless store/load/store sequence diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp index c255f561787e..ca9658d66373 100644 --- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -1381,7 +1381,7 @@ namespace nanojit ins->clearReg(); asm_immi(r, ins->imm32(), /*canClobberCCs*/false); } - else if (ins->isop(LIR_quad)) { + else if (ins->isconstq()) { ins->clearReg(); asm_immq(r, ins->imm64(), /*canClobberCCs*/false); } diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index cb17ad4ef01c..1572e08855ce 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -569,7 +569,7 @@ namespace nanojit FST32(pop?1:0, dr, rb); } - } else if (value->isconstq()) { + } else if (value->isconstf()) { STi(rb, dr+4, value->imm64_1()); STi(rb, dr, value->imm64_0()); @@ -1561,7 +1561,7 @@ namespace nanojit NanoAssert(FST0 == rr); NanoAssert(!lhs->isInReg() || FST0 == lhs->getReg()); - if (rhs->isconstq()) { + if (rhs->isconstf()) { const uint64_t* p = findQuadConstant(rhs->imm64()); switch (op) { @@ -1888,7 +1888,7 @@ namespace nanojit } else { TEST_AH(mask); FNSTSW_AX(); // requires EAX to be free - if (rhs->isconstq()) + if (rhs->isconstf()) { const uint64_t* p = findQuadConstant(rhs->imm64()); FCOMdm((pop?1:0), (const double*)p); From d179f8f3c284c81df333a75147dacc5ac4d113c6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 28 Mar 2010 17:48:10 -0700 Subject: [PATCH 155/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 598f76c1ff64..524890f927f5 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -6ee8bcd6813ffe98061b8d09317f58138bb41bb7 +b8fea2e57673f9f2d4e864870d73ee294cabd4bd From 0b93aa9f967c0372c0e1325634f0a1d1e9e0b6bd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 28 Mar 2010 18:02:40 -0700 Subject: [PATCH 156/213] Bug 541030 - nanojit: isconstq() should only succeed for 64-bit integer (TM-specific part). r=dvander. --- js/src/jstracer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 85991b9569d4..303577f47ce2 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8366,7 +8366,7 @@ TraceRecorder::tableswitch() /* No need to guard if the condition is constant. */ LIns* v_ins = f2i(get(&v)); - if (v_ins->isconst() || v_ins->isconstq()) + if (v_ins->isconst()) return ARECORD_CONTINUE; jsbytecode* pc = cx->fp->regs->pc; @@ -8428,7 +8428,7 @@ TraceRecorder::switchop() LIns* v_ins = get(&v); /* No need to guard if the condition is constant. */ - if (v_ins->isconst() || v_ins->isconstq()) + if (v_ins->isImmAny()) return RECORD_CONTINUE; if (isNumber(v)) { jsdouble d = asNumber(v); From 806a75e33e3fcdc419a3591251000ef1aedb8155 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 28 Mar 2010 20:32:20 -0700 Subject: [PATCH 157/213] Readd all jsobj.cpp and related changes from bug 548702. --- js/src/jscntxt.h | 20 +++++------ js/src/jscntxtinlines.h | 4 --- js/src/jsobj.cpp | 78 ++++++++--------------------------------- js/src/jsobj.h | 4 ++- js/src/jsobjinlines.h | 30 ++++++++++++++++ 5 files changed, 57 insertions(+), 79 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index ddd472405e0d..ae40b2b98650 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1756,17 +1756,17 @@ class AutoGCRooter { enum { JSVAL = -1, /* js::AutoValueRooter */ - SPROP = -2, /* JSAutoScopePropertyTreeRooter */ - WEAKROOTS = -3, /* AutoSaveWeakRoots */ + SPROP = -2, /* js::AutoScopePropertyRooter */ + WEAKROOTS = -3, /* js::AutoSaveWeakRoots */ COMPILER = -4, /* JSCompiler */ - SCRIPT = -5, /* JSAutoScriptRooter */ - ENUMERATOR = -6, /* JSAutoEnumStateRooter */ - IDARRAY = -7, /* JSAutoIdArray */ - DESCRIPTORS = -8, /* AutoDescriptorArray */ - NAMESPACES = -9, /* AutoNamespaceArray */ - XML = -10, /* JSAutoXML */ - OBJECT = -11, /* JSAutoObjectRooter */ - ID = -12 /* JSAutoTempIdRooter */ + SCRIPT = -5, /* js::AutoScriptRooter */ + ENUMERATOR = -6, /* js::AutoEnumStateRooter */ + IDARRAY = -7, /* js::AutoIdArray */ + DESCRIPTORS = -8, /* js::AutoDescriptorArray */ + NAMESPACES = -9, /* js::AutoNamespaceArray */ + XML = -10, /* js::AutoXMLRooter */ + OBJECT = -11, /* js::AutoObjectRooter */ + ID = -12 /* js::AutoIdRooter */ }; }; diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 30551abc648e..8532e081ff9a 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -105,7 +105,6 @@ AutoGCRooter::trace(JSTracer *trc) } case DESCRIPTORS: { -#if 0 /* AutoDescriptorArray is still old-style */ PropertyDescriptorArray &descriptors = static_cast(this)->descriptors; for (size_t i = 0, len = descriptors.length(); i < len; i++) { @@ -116,9 +115,6 @@ AutoGCRooter::trace(JSTracer *trc) JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); js_TraceId(trc, desc.id); } -#else - JS_ASSERT(0); -#endif return; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index e0068fa139ca..5de554f0b6ea 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -633,9 +633,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) JS_CHECK_RECURSION(cx, return JS_FALSE); - JSTempValueRooter tvr; - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot); /* If outermost, we need parentheses to be an expression, not a block. */ outermost = (cx->sharpObjectMap.depth == 0); @@ -1000,7 +998,6 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) *vp = STRING_TO_JSVAL(str); ok = JS_TRUE; out: - JS_POP_TEMP_ROOT(cx, &tvr); return ok; overflow: @@ -2024,7 +2021,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) return false; } JSObject *obj = JSVAL_TO_OBJECT(vp[2]); - JSAutoTempIdRooter nameidr(cx); + AutoIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; return js_GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp); @@ -2040,7 +2037,7 @@ obj_keys(JSContext *cx, uintN argc, jsval *vp) } JSObject *obj = JSVAL_TO_OBJECT(v); - JSAutoIdArray ida(cx, JS_Enumerate(cx, obj)); + AutoIdArray ida(cx, JS_Enumerate(cx, obj)); if (!ida) return JS_FALSE; @@ -2205,50 +2202,6 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) return true; } -typedef js::Vector PropertyDescriptorArray; - -class AutoDescriptorArray : private JSTempValueRooter -{ - private: - JSContext *cx; - PropertyDescriptorArray descriptors; - - public: - AutoDescriptorArray(JSContext *cx) - : cx(cx), descriptors(cx) - { - JS_PUSH_TEMP_ROOT_TRACE(cx, trace, this); - } - ~AutoDescriptorArray() { - JS_POP_TEMP_ROOT(cx, this); - } - - PropertyDescriptor *append() { - if (!descriptors.append(PropertyDescriptor())) - return NULL; - return &descriptors.back(); - } - - PropertyDescriptor& operator[](size_t i) { - JS_ASSERT(i < descriptors.length()); - return descriptors[i]; - } - - private: - static void trace(JSTracer *trc, JSTempValueRooter *tvr) { - PropertyDescriptorArray &descs = - static_cast(tvr)->descriptors; - for (size_t i = 0, len = descs.length(); i < len; i++) { - PropertyDescriptor &desc = descs[i]; - - JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); - JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); - JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); - js_TraceId(trc, desc.id); - } - } -}; - static JSBool Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval) { @@ -2676,7 +2629,7 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; vp[3] = OBJECT_TO_JSVAL(props); - JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); + AutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2740,7 +2693,7 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) } JSObject *props = JSVAL_TO_OBJECT(vp[3]); - JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); + AutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2938,7 +2891,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, * builtin. See bug 481444. */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); JS_KEEP_ATOMS(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); @@ -3614,7 +3567,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) obj->setParent(parent); } - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); if (!JS_XDRUint32(xdr, &tmp)) return false; @@ -3741,10 +3694,8 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, if (!proto) return NULL; - /* After this point, control must exit via label out or out. */ - JSTempValueRooter tvr; - JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr); - MUST_FLOW_THROUGH("out"); + /* After this point, control must exit via label bad or out. */ + AutoValueRooter tvr(cx, proto); if (!constructor) { /* @@ -3834,7 +3785,6 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, goto bad; out: - JS_POP_TEMP_ROOT(cx, &tvr); return proto; bad: @@ -4142,7 +4092,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, jsval cval, rval; JSObject *obj, *ctor; - JSAutoTempValueRooter argtvr(cx, argc, argv); + AutoArrayRooter argtvr(cx, argc, argv); JSProtoKey protoKey = GetClassProtoKey(clasp); if (!js_FindClassObject(cx, parent, protoKey, &cval, clasp)) @@ -4154,7 +4104,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, } /* Protect cval in case a crazy getter for .prototype uproots it. */ - JSAutoTempValueRooter tvr(cx, cval); + AutoValueRooter tvr(cx, cval); /* * If proto or parent are NULL, set them to Constructor.prototype and/or @@ -4970,8 +4920,8 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); { - JSAutoTempValueRooter tvr(cx, sprop); - JSAutoTempValueRooter tvr2(cx, pobj); + AutoScopePropertyRooter tvr(cx, sprop); + AutoValueRooter tvr2(cx, pobj); if (!sprop->get(cx, obj, pobj, vp)) return false; } @@ -5032,7 +4982,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); { - JSAutoTempValueRooter tvr(cx, sprop); + AutoScopePropertyRooter tvr(cx, sprop); if (!sprop->set(cx, obj, vp)) return false; } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 8a394bb9d84a..884389b7063b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -52,12 +52,14 @@ #include "jspubtd.h" #include "jsprvtd.h" +namespace js { class AutoDescriptorArray; } + /* * A representation of ECMA-262 ed. 5's internal property descriptor data * structure. */ struct PropertyDescriptor { - friend class AutoDescriptorArray; + friend class js::AutoDescriptorArray; private: PropertyDescriptor(); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 376bca893339..b8a21d864a3e 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -83,4 +83,34 @@ JSObject::unbrand(JSContext *cx) return true; } +namespace js { + +typedef Vector PropertyDescriptorArray; + +class AutoDescriptorArray : private AutoGCRooter +{ + public: + AutoDescriptorArray(JSContext *cx) + : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) + { } + + PropertyDescriptor *append() { + if (!descriptors.append(PropertyDescriptor())) + return NULL; + return &descriptors.back(); + } + + PropertyDescriptor& operator[](size_t i) { + JS_ASSERT(i < descriptors.length()); + return descriptors[i]; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + PropertyDescriptorArray descriptors; +}; + +} + #endif /* jsobjinlines_h___ */ From f3cf631e3ba2ab5ab84691970802f9de67e87f5d Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 28 Mar 2010 22:05:50 -0700 Subject: [PATCH 158/213] Readd bug 548702's changes to jsapi.cpp, jsexn.cpp, jsfun.cpp, jsnum.cpp, and jsstr.cpp. --- js/src/jsapi.cpp | 111 +++++++++++++++++++++++----------------------- js/src/jsexn.cpp | 113 ++++++++++++++++------------------------------- js/src/jsfun.cpp | 58 +++++++++--------------- js/src/jsnum.cpp | 6 +-- js/src/jsstr.cpp | 4 +- 5 files changed, 121 insertions(+), 171 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 95db6f3f246f..9e0e840feb9d 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -438,7 +438,7 @@ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *dp = js_ValueToNumber(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -454,7 +454,7 @@ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToECMAInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -464,7 +464,7 @@ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToECMAUint32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -474,7 +474,7 @@ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -484,7 +484,7 @@ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); *ip = js_ValueToUint16(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -3083,7 +3083,7 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->isMethod()) { - JSAutoTempValueRooter root(cx, sprop); + AutoScopePropertyRooter root(cx, sprop); JS_UNLOCK_OBJ(cx, obj2); *vp = sprop->methodValue(); return OBJ_SCOPE(obj2)->methodReadBarrier(cx, sprop, vp); @@ -3841,7 +3841,6 @@ JS_PUBLIC_API(JSIdArray *) JS_Enumerate(JSContext *cx, JSObject *obj) { jsint i, n; - jsval iter_state, num_properties; jsid id; JSIdArray *ida; jsval *vector; @@ -3849,11 +3848,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) CHECK_REQUEST(cx); ida = NULL; - iter_state = JSVAL_NULL; - JSAutoEnumStateRooter tvr(cx, obj, &iter_state); + AutoEnumStateRooter iterState(cx, obj); /* Get the number of properties to enumerate. */ - if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties)) + jsval num_properties; + if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) goto error; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); @@ -3873,11 +3872,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) i = 0; vector = &ida->vector[0]; for (;;) { - if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id)) + if (!obj->enumerate(cx, JSENUMERATE_NEXT, iterState.addr(), &id)) goto error; /* No more jsid's to enumerate ? */ - if (iter_state == JSVAL_NULL) + if (iterState.state() == JSVAL_NULL) break; if (i == ida->length) { @@ -3891,8 +3890,6 @@ JS_Enumerate(JSContext *cx, JSObject *obj) return SetIdArrayLength(cx, ida, i); error: - if (!JSVAL_IS_NULL(iter_state)) - obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); if (ida) JS_DestroyIdArray(cx, ida); return NULL; @@ -3976,7 +3973,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) * Note: we have to make sure that we root obj around the call to * JS_Enumerate to protect against multiple allocations under it. */ - JSAutoTempValueRooter tvr(cx, iterobj); + AutoValueRooter tvr(cx, iterobj); ida = JS_Enumerate(cx, obj); if (!ida) return NULL; @@ -4627,7 +4624,6 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, JS_PUBLIC_API(JSObject *) JS_NewScriptObject(JSContext *cx, JSScript *script) { - JSTempValueRooter tvr; JSObject *obj; CHECK_REQUEST(cx); @@ -4636,16 +4632,19 @@ JS_NewScriptObject(JSContext *cx, JSScript *script) JS_ASSERT(!script->u.object); - JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); - obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); - if (obj) { - obj->setPrivate(script); - script->u.object = obj; + { + AutoScriptRooter root(cx, script); + + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + if (obj) { + obj->setPrivate(script); + script->u.object = obj; #ifdef CHECK_SCRIPT_OWNER - script->owner = NULL; + script->owner = NULL; #endif + } } - JS_POP_TEMP_ROOT(cx, &tvr); + return obj; } @@ -4723,7 +4722,6 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, const char *filename, uintN lineno) { JSFunction *fun; - JSTempValueRooter tvr; JSAtom *funAtom, *argAtom; uintN i; @@ -4741,47 +4739,48 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, if (!fun) goto out2; - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); - for (i = 0; i < nargs; i++) { - argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); - if (!argAtom) { + { + AutoValueRooter tvr(cx, FUN_OBJECT(fun)); + MUST_FLOW_THROUGH("out"); + + for (i = 0; i < nargs; i++) { + argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); + if (!argAtom) { + fun = NULL; + goto out; + } + if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { + fun = NULL; + goto out; + } + } + + if (!JSCompiler::compileFunctionBody(cx, fun, principals, + chars, length, filename, lineno)) { fun = NULL; goto out; } - if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { + + if (obj && funAtom && + !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + NULL, NULL, JSPROP_ENUMERATE)) { fun = NULL; - goto out; } - } - - if (!JSCompiler::compileFunctionBody(cx, fun, principals, - chars, length, filename, lineno)) { - fun = NULL; - goto out; - } - - if (obj && - funAtom && - !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), - NULL, NULL, JSPROP_ENUMERATE)) { - fun = NULL; - } #ifdef JS_SCOPE_DEPTH_METER - if (fun && obj) { - JSObject *pobj = obj; - uintN depth = 1; + if (fun && obj) { + JSObject *pobj = obj; + uintN depth = 1; - while ((pobj = pobj->getParent()) != NULL) - ++depth; - JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); - } + while ((pobj = pobj->getParent()) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } #endif - out: - cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; - JS_POP_TEMP_ROOT(cx, &tvr); + out: + cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; + } out2: LAST_FRAME_CHECKS(cx, fun); @@ -4939,7 +4938,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, { CHECK_REQUEST(cx); - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); JSBool ok = atom && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index c62beef5ec1b..80daa9223a7e 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -838,41 +838,34 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) return false; *vp = STRING_TO_JSVAL(name); - JSTempValueRooter tvr; - JSBool ok; { - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots); #ifdef __GNUC__ message = filename = NULL; #endif - ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) && - (message = js_ValueToSource(cx, localroots[0])); - if (!ok) - goto out; + if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || + !(message = js_ValueToSource(cx, localroots[0]))) { + return false; + } localroots[0] = STRING_TO_JSVAL(message); - ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) && - (filename = js_ValueToSource(cx, localroots[1])); - if (!ok) - goto out; + if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || + !(filename = js_ValueToSource(cx, localroots[1]))) { + return false; + } localroots[1] = STRING_TO_JSVAL(filename); - ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]); - if (!ok) - goto out; + if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2])) + return false; lineno = js_ValueToECMAUint32 (cx, &localroots[2]); - ok = !JSVAL_IS_NULL(localroots[2]); - if (!ok) - goto out; + if (JSVAL_IS_NULL(localroots[2])) + return false; if (lineno != 0) { lineno_as_str = js_ValueToString(cx, localroots[2]); - if (!lineno_as_str) { - ok = JS_FALSE; - goto out; - } + if (!lineno_as_str) + return false; lineno_length = lineno_as_str->length(); } else { lineno_as_str = NULL; @@ -903,10 +896,8 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) } cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); - if (!chars) { - ok = JS_FALSE; - goto out; - } + if (!chars) + return false; *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; js_strncpy(cp, name->chars(), name_length); @@ -943,16 +934,11 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) result = js_NewString(cx, chars, length); if (!result) { cx->free(chars); - ok = JS_FALSE; - goto out; + return false; } *vp = STRING_TO_JSVAL(result); - ok = JS_TRUE; + return true; } - - out: - JS_POP_TEMP_ROOT(cx, &tvr); - return JS_TRUE; } #endif @@ -1003,7 +989,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) return NULL; PodArrayZero(roots); - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); #ifdef __GNUC__ error_proto = NULL; /* quell GCC overwarning */ @@ -1161,9 +1147,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, /* Protect the newly-created strings below from nesting GCs. */ PodArrayZero(tv); - - JSTempValueRooter tvr; - JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv); /* * Try to get an appropriate prototype by looking up the corresponding @@ -1207,7 +1191,6 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, reportp->flags |= JSREPORT_EXCEPTION; out: - JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; } @@ -1229,10 +1212,7 @@ js_ReportUncaughtException(JSContext *cx) return false; PodArrayZero(roots); - JSBool ok = JS_TRUE; - JSTempValueRooter tvr; - JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); - MUST_FLOW_THROUGH("out"); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); /* * Because js_ValueToString below could error and an exception object @@ -1257,49 +1237,36 @@ js_ReportUncaughtException(JSContext *cx) } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); - if (!bytes) { - ok = JS_FALSE; - goto out; - } + if (!bytes) + return false; } if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) { const char *filename; uint32 lineno; - if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) { - ok = JS_FALSE; - goto out; - } + if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) + return false; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); - if (!bytes) { - ok = JS_FALSE; - goto out; - } + if (!bytes) + return false; } - ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); - if (!ok) - goto out; + if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) + return false; str = js_ValueToString(cx, roots[3]); - if (!str) { - ok = JS_FALSE; - goto out; - } + if (!str) + return false; filename = StringToFilename(cx, str); - if (!filename) { - ok = JS_FALSE; - goto out; - } + if (!filename) + return false; - ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); - if (!ok) - goto out; + if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) + return false; lineno = js_ValueToECMAUint32 (cx, &roots[4]); - ok = !JSVAL_IS_NULL(roots[4]); - if (!ok) - goto out; + if (JSVAL_IS_NULL(roots[4])) + return false; reportp = &report; PodZero(&report); @@ -1320,7 +1287,5 @@ js_ReportUncaughtException(JSContext *cx) JS_ClearPendingException(cx); } - out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; + return true; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 8070b563f643..51ef81748883 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -351,7 +351,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio funobj, scopeChain); if (!wfunobj) return NULL; - JSAutoTempValueRooter tvr(cx, wfunobj); + AutoValueRooter tvr(cx, wfunobj); JSFunction *wfun = (JSFunction *) wfunobj; wfunobj->setPrivate(wfun); @@ -599,7 +599,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) if (!JS_ValueToId(cx, idval, &id)) return false; - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); return js_DeleteProperty(cx, obj, id, tvr.addr()) && js_SetProperty(cx, obj, id, vp); } @@ -1584,8 +1584,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) uintN nargs, nvars, nupvars, n; uint32 localsword; /* word for argument and variable counts */ uint32 flagsword; /* word for fun->u.i.nupvars and fun->flags */ - JSTempValueRooter tvr; - JSBool ok; cx = xdr->cx; if (xdr->mode == JSXDR_ENCODE) { @@ -1594,13 +1592,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, JS_GetFunctionName(fun)); - return JS_FALSE; + return false; } if (fun->u.i.wrapper) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, JS_GetFunctionName(fun)); - return JS_FALSE; + return false; } JS_ASSERT((fun->u.i.wrapper & ~1U) == 0); firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom; @@ -1612,7 +1610,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } else { fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); if (!fun) - return JS_FALSE; + return false; FUN_OBJECT(fun)->clearParent(); FUN_OBJECT(fun)->clearProto(); #ifdef __GNUC__ @@ -1620,18 +1618,15 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) #endif } - /* From here on, control flow must flow through label out. */ - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); - ok = JS_TRUE; + AutoValueRooter tvr(cx, FUN_OBJECT(fun)); if (!JS_XDRUint32(xdr, &firstword)) - goto bad; + return false; if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom)) - goto bad; + return false; if (!JS_XDRUint32(xdr, &localsword) || !JS_XDRUint32(xdr, &flagsword)) { - goto bad; + return false; } if (xdr->mode == JSXDR_DECODE) { @@ -1655,6 +1650,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JSAtom *name; JSLocalKind localKind; + bool ok = true; mark = JS_ARENA_MARK(&xdr->cx->tempPool); /* @@ -1673,13 +1669,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) bitmapLength * sizeof *bitmap); if (!bitmap) { js_ReportOutOfScriptQuota(xdr->cx); - ok = JS_FALSE; + ok = false; goto release_mark; } if (xdr->mode == JSXDR_ENCODE) { names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool); if (!names) { - ok = JS_FALSE; + ok = false; goto release_mark; } PodZero(bitmap, bitmapLength); @@ -1734,19 +1730,18 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) goto release_mark; } } - ok = JS_TRUE; release_mark: JS_ARENA_RELEASE(&xdr->cx->tempPool, mark); if (!ok) - goto out; + return false; if (xdr->mode == JSXDR_DECODE) js_FreezeLocalNames(cx, fun); } if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL)) - goto bad; + return false; if (xdr->mode == JSXDR_DECODE) { *objp = FUN_OBJECT(fun); @@ -1758,13 +1753,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } } -out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; - -bad: - ok = JS_FALSE; - goto out; + return true; } #else /* !JS_HAS_XDR */ @@ -2689,26 +2678,26 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) JSStackFrame *fp; uintN error; const char *name, *source; - JSTempValueRooter tvr; for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down) continue; name = source = NULL; - JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr); + + AutoValueRooter tvr(cx); if (flags & JSV2F_ITERATOR) { error = JSMSG_BAD_ITERATOR; name = js_iterator_str; JSString *src = js_ValueToSource(cx, *vp); if (!src) - goto out; - tvr.u.value = STRING_TO_JSVAL(src); + return; + tvr.setString(src); JSString *qsrc = js_QuoteString(cx, src, 0); if (!qsrc) - goto out; - tvr.u.value = STRING_TO_JSVAL(qsrc); + return; + tvr.setString(qsrc); source = js_GetStringBytes(cx, qsrc); if (!source) - goto out; + return; } else if (flags & JSV2F_CONSTRUCT) { error = JSMSG_NOT_CONSTRUCTOR; } else { @@ -2724,9 +2713,6 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) : JSDVG_IGNORE_STACK, *vp, NULL, name, source); - - out: - JS_POP_TEMP_ROOT(cx, &tvr); } /* diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 02044854f460..ffbc5c1e3453 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -994,11 +994,11 @@ js_ValueToNumber(JSContext *cx, jsval *vp) * vp roots obj so we cannot use it as an extra root for * obj->defaultValue result when calling the hook. */ - JSAutoTempValueRooter tvr(cx, v); - if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr())) + AutoValueRooter gcr(cx, v); + if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr())) obj = NULL; else - v = *vp = tvr.value(); + v = *vp = gcr.value(); if (!obj) { *vp = JSVAL_NULL; return 0.0; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 628bcd266fad..04bc452a6438 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1636,7 +1636,7 @@ str_match(JSContext *cx, uintN argc, jsval *vp) if (!g.normalizeRegExp(false, 1, argc, vp)) return false; - JSAutoTempValueRooter array(cx, JSVAL_NULL); + AutoValueRooter array(cx, JSVAL_NULL); if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS)) return false; @@ -3328,7 +3328,7 @@ js_ValueToSource(JSContext *cx, jsval v) } JSAtom *atom = cx->runtime->atomState.toSourceAtom; - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), atom, 0, NULL, tvr.addr())) return NULL; return js_ValueToString(cx, tvr.value()); From 6eaa7e5cd1d5a1df09bf45d64384fbd3188bac32 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 00:02:13 -0700 Subject: [PATCH 159/213] Readd jsarray.cpp changes for bug 548702. array_sort in particular is a rat's-nest of complexity, so this file's changes are being pushed in isolation from all others. In the interest of getting the tree as pristine for morning, I'm pushing this now and letting it cycle while I sleep -- if it turns anything pretty colors, please back out. Otherwise, look for more in the morning... --- js/src/jsarray.cpp | 428 +++++++++++++++++++++------------------------ 1 file changed, 199 insertions(+), 229 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 79ee7ca3a84f..7d0fa07616dc 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -231,7 +231,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) return JS_TRUE; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr())) return JS_FALSE; @@ -405,7 +405,7 @@ EnsureCapacity(JSContext *cx, JSObject *obj, uint32 newcap, static bool ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp) { - JSAutoTempValueRooter dval(cx); + AutoValueRooter dval(cx); if (!js_NewDoubleInRootedValue(cx, index, dval.addr()) || !js_ValueToStringId(cx, dval.value(), idp)) { return JS_FALSE; @@ -450,7 +450,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, return JS_TRUE; } - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); *hole = JS_FALSE; if (!IndexToId(cx, obj, index, hole, idr.addr())) @@ -505,7 +505,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v) return JS_FALSE; } - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE)) return JS_FALSE; @@ -531,7 +531,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index) return JS_TRUE; } - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!IndexToId(cx, obj, index, NULL, idr.addr())) return JS_FALSE; @@ -573,7 +573,7 @@ JSBool js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) { JSErrorReporter older = JS_SetErrorReporter(cx, NULL); - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); JSBool ok = obj->getProperty(cx, id, tvr.addr()); JS_SetErrorReporter(cx, older); @@ -626,8 +626,6 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { jsuint newlen, oldlen, gap, index; jsval junk; - JSTempValueRooter tvr; - JSBool ok; if (!obj->isArray()) { jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); @@ -675,24 +673,19 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return false; /* Protect iter against GC under JSObject::deleteProperty. */ - JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr); + AutoValueRooter tvr(cx, iter); + gap = oldlen - newlen; for (;;) { - ok = (JS_CHECK_OPERATION_LIMIT(cx) && - JS_NextProperty(cx, iter, &id)); - if (!ok) - break; + if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id)) + return false; if (JSVAL_IS_VOID(id)) break; - if (js_IdIsIndex(id, &index) && index - newlen < gap) { - ok = obj->deleteProperty(cx, id, &junk); - if (!ok) - break; + if (js_IdIsIndex(id, &index) && index - newlen < gap && + !obj->deleteProperty(cx, id, &junk)) { + return false; } } - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - return false; } obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen; @@ -1515,7 +1508,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, return true; } - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); /* After this point, all paths exit through the 'out' label. */ MUST_FLOW_THROUGH("out"); @@ -1649,7 +1642,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva #ifdef DEBUG_jwalden { /* Verify that overwriteType and writeType were accurate. */ - JSAutoTempIdRooter idr(cx, JSVAL_ZERO); + AutoIdRooter idr(cx); for (jsuint i = 0; i < count; i++) { JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE); @@ -1715,12 +1708,12 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva JS_ASSERT(start == MAXINDEX); jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL}; - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); if (!js_NewDoubleInRootedValue(cx, MAXINDEX, &tmp[0])) return JS_FALSE; jsdouble *dp = JSVAL_TO_DOUBLE(tmp[0]); JS_ASSERT(*dp == MAXINDEX); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); do { tmp[1] = *vector++; if (!js_ValueToStringId(cx, tmp[0], idr.addr()) || @@ -1766,7 +1759,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector, static JSString* FASTCALL Array_p_join(JSContext* cx, JSObject* obj, JSString *str) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (!array_toString_sub(cx, obj, JS_FALSE, str, tvr.addr())) { SetBuiltinError(cx); return NULL; @@ -1777,7 +1770,7 @@ Array_p_join(JSContext* cx, JSObject* obj, JSString *str) static JSString* FASTCALL Array_p_toString(JSContext* cx, JSObject* obj) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) { SetBuiltinError(cx); return NULL; @@ -1849,7 +1842,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); for (jsuint i = 0, half = len / 2; i < half; i++) { JSBool hole, hole2; if (!JS_CHECK_OPERATION_LIMIT(cx) || @@ -2099,40 +2092,28 @@ JS_STATIC_ASSERT(JSVAL_NULL == 0); static JSBool array_sort(JSContext *cx, uintN argc, jsval *vp) { - jsval *argv, fval, *vec, *mergesort_tmp, v; - JSObject *obj; - CompareArgs ca; + jsval fval; jsuint len, newlen, i, undefs; - JSTempValueRooter tvr; - JSBool hole; - JSBool ok; size_t elemsize; JSString *str; - /* - * Optimize the default compare function case if all of obj's elements - * have values of type string. - */ - JSBool all_strings; - - argv = JS_ARGV(cx, vp); + jsval *argv = JS_ARGV(cx, vp); if (argc > 0) { if (JSVAL_IS_PRIMITIVE(argv[0])) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_SORT_ARG); - return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); + return false; } fval = argv[0]; /* non-default compare function */ } else { fval = JSVAL_NULL; } - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = JS_THIS_OBJECT(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &len)) - return JS_FALSE; + return false; if (len == 0) { *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; + return true; } /* @@ -2142,19 +2123,16 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * malloc'd vector. */ #if JS_BITS_PER_WORD == 32 - if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) { + if (size_t(len) > size_t(-1) / (2 * sizeof(jsval))) { js_ReportAllocationOverflow(cx); - return JS_FALSE; + return false; } #endif - vec = (jsval *) cx->malloc(2 * (size_t) len * sizeof(jsval)); - if (!vec) - return JS_FALSE; /* * Initialize vec as a root. We will clear elements of vec one by - * one while increasing tvr.count when we know that the property at - * the corresponding index exists and its value must be rooted. + * one while increasing the rooted amount of vec when we know that the + * property at the corresponding index exists and its value must be rooted. * * In this way when sorting a huge mostly sparse array we will not * access the tail of vec corresponding to properties that do not @@ -2162,204 +2140,196 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * * After this point control must flow through label out: to exit. */ - JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr); + { + jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval)); + if (!vec) + return false; - /* - * By ECMA 262, 15.4.4.11, a property that does not exist (which we - * call a "hole") is always greater than an existing property with - * value undefined and that is always greater than any other property. - * Thus to sort holes and undefs we simply count them, sort the rest - * of elements, append undefs after them and then make holes after - * undefs. - */ - undefs = 0; - newlen = 0; - all_strings = JS_TRUE; - for (i = 0; i < len; i++) { - ok = JS_CHECK_OPERATION_LIMIT(cx); - if (!ok) - goto out; + struct AutoFreeVector { + AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { } + ~AutoFreeVector() { + cx->free(vec); + } + JSContext * const cx; + jsval *&vec; + } free(cx, vec); - /* Clear vec[newlen] before including it in the rooted set. */ - vec[newlen] = JSVAL_NULL; - tvr.count = newlen + 1; - ok = GetArrayElement(cx, obj, i, &hole, &vec[newlen]); - if (!ok) - goto out; + AutoArrayRooter tvr(cx, 0, vec); - if (hole) - continue; + /* + * By ECMA 262, 15.4.4.11, a property that does not exist (which we + * call a "hole") is always greater than an existing property with + * value undefined and that is always greater than any other property. + * Thus to sort holes and undefs we simply count them, sort the rest + * of elements, append undefs after them and then make holes after + * undefs. + */ + undefs = 0; + newlen = 0; + bool allStrings = true; + for (i = 0; i < len; i++) { + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; - if (JSVAL_IS_VOID(vec[newlen])) { - ++undefs; - continue; + /* Clear vec[newlen] before including it in the rooted set. */ + JSBool hole; + vec[newlen] = JSVAL_NULL; + tvr.changeLength(newlen + 1); + if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen])) + return false; + + if (hole) + continue; + + if (JSVAL_IS_VOID(vec[newlen])) { + ++undefs; + continue; + } + + allStrings = allStrings && JSVAL_IS_STRING(vec[newlen]); + + ++newlen; } - /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */ - all_strings &= JSVAL_IS_STRING(vec[newlen]); + if (newlen == 0) + return true; /* The array has only holes and undefs. */ - ++newlen; - } - - if (newlen == 0) { - /* The array has only holes and undefs. */ - ok = JS_TRUE; - goto out; - } - - /* - * The first newlen elements of vec are copied from the array object - * (above). The remaining newlen positions are used as GC-rooted scratch - * space for mergesort. We must clear the space before including it to - * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize - * initialization using memset. - */ - mergesort_tmp = vec + newlen; - memset(mergesort_tmp, 0, newlen * sizeof(jsval)); - tvr.count = newlen * 2; - - /* Here len == 2 * (newlen + undefs + number_of_holes). */ - if (fval == JSVAL_NULL) { /* - * Sort using the default comparator converting all elements to - * strings. + * The first newlen elements of vec are copied from the array object + * (above). The remaining newlen positions are used as GC-rooted scratch + * space for mergesort. We must clear the space before including it to + * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize + * initialization using memset. */ - if (all_strings) { - elemsize = sizeof(jsval); - } else { + jsval *mergesort_tmp = vec + newlen; + PodZero(mergesort_tmp, newlen); + tvr.changeLength(newlen * 2); + + /* Here len == 2 * (newlen + undefs + number_of_holes). */ + if (fval == JSVAL_NULL) { /* - * To avoid string conversion on each compare we do it only once - * prior to sorting. But we also need the space for the original - * values to recover the sorting result. To reuse - * sort_compare_strings we move the original values to the odd - * indexes in vec, put the string conversion results in the even - * indexes and pass 2 * sizeof(jsval) as an element size to the - * sorting function. In this way sort_compare_strings will only - * see the string values when it casts the compare arguments as - * pointers to jsval. - * - * This requires doubling the temporary storage including the - * scratch space for the merge sort. Since vec already contains - * the rooted scratch space for newlen elements at the tail, we - * can use it to rearrange and convert to strings first and try - * realloc only when we know that we successfully converted all - * the elements. + * Sort using the default comparator converting all elements to + * strings. */ + if (allStrings) { + elemsize = sizeof(jsval); + } else { + /* + * To avoid string conversion on each compare we do it only once + * prior to sorting. But we also need the space for the original + * values to recover the sorting result. To reuse + * sort_compare_strings we move the original values to the odd + * indexes in vec, put the string conversion results in the even + * indexes and pass 2 * sizeof(jsval) as an element size to the + * sorting function. In this way sort_compare_strings will only + * see the string values when it casts the compare arguments as + * pointers to jsval. + * + * This requires doubling the temporary storage including the + * scratch space for the merge sort. Since vec already contains + * the rooted scratch space for newlen elements at the tail, we + * can use it to rearrange and convert to strings first and try + * realloc only when we know that we successfully converted all + * the elements. + */ #if JS_BITS_PER_WORD == 32 - if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) { - js_ReportAllocationOverflow(cx); - ok = JS_FALSE; - goto out; - } + if (size_t(newlen) > size_t(-1) / (4 * sizeof(jsval))) { + js_ReportAllocationOverflow(cx); + return false; + } #endif - /* - * Rearrange and string-convert the elements of the vector from - * the tail here and, after sorting, move the results back - * starting from the start to prevent overwrite the existing - * elements. - */ - i = newlen; - do { - --i; - ok = JS_CHECK_OPERATION_LIMIT(cx); - if (!ok) - goto out; - v = vec[i]; - str = js_ValueToString(cx, v); - if (!str) { - ok = JS_FALSE; - goto out; + /* + * Rearrange and string-convert the elements of the vector from + * the tail here and, after sorting, move the results back + * starting from the start to prevent overwrite the existing + * elements. + */ + i = newlen; + do { + --i; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + jsval v = vec[i]; + str = js_ValueToString(cx, v); + if (!str) + return false; + vec[2 * i] = STRING_TO_JSVAL(str); + vec[2 * i + 1] = v; + } while (i != 0); + + JS_ASSERT(tvr.array == vec); + vec = (jsval *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(jsval)); + if (!vec) { + vec = tvr.array; + return false; } - vec[2 * i] = STRING_TO_JSVAL(str); - vec[2 * i + 1] = v; - } while (i != 0); - - JS_ASSERT(tvr.u.array == vec); - vec = (jsval *) cx->realloc(vec, - 4 * (size_t) newlen * sizeof(jsval)); - if (!vec) { - vec = tvr.u.array; - ok = JS_FALSE; - goto out; + mergesort_tmp = vec + 2 * newlen; + PodZero(mergesort_tmp, newlen * 2); + tvr.changeArray(vec, newlen * 4); + elemsize = 2 * sizeof(jsval); } - tvr.u.array = vec; - mergesort_tmp = vec + 2 * newlen; - PodZero(mergesort_tmp, newlen * 2); - tvr.count = newlen * 4; - elemsize = 2 * sizeof(jsval); - } - ok = js_MergeSort(vec, (size_t) newlen, elemsize, - sort_compare_strings, cx, mergesort_tmp); - if (!ok) - goto out; - if (!all_strings) { - /* - * We want to make the following loop fast and to unroot the - * cached results of toString invocations before the operation - * callback has a chance to run the GC. For this reason we do - * not call JS_CHECK_OPERATION_LIMIT in the loop. - */ - i = 0; - do { - vec[i] = vec[2 * i + 1]; - } while (++i != newlen); - } - } else { - void *mark; + if (!js_MergeSort(vec, size_t(newlen), elemsize, + sort_compare_strings, cx, mergesort_tmp)) { + return false; + } + if (!allStrings) { + /* + * We want to make the following loop fast and to unroot the + * cached results of toString invocations before the operation + * callback has a chance to run the GC. For this reason we do + * not call JS_CHECK_OPERATION_LIMIT in the loop. + */ + i = 0; + do { + vec[i] = vec[2 * i + 1]; + } while (++i != newlen); + } + } else { + void *mark; - LeaveTrace(cx); + LeaveTrace(cx); - ca.context = cx; - ca.fval = fval; - ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); - if (!ca.elemroot) { - ok = JS_FALSE; - goto out; + CompareArgs ca; + ca.context = cx; + ca.fval = fval; + ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); + if (!ca.elemroot) + return false; + bool ok = js_MergeSort(vec, size_t(newlen), sizeof(jsval), + comparator_stack_cast(sort_compare), + &ca, mergesort_tmp); + js_FreeStack(cx, mark); + if (!ok) + return false; + } + + /* + * We no longer need to root the scratch space for the merge sort, so + * unroot it now to make the job of a potential GC under + * InitArrayElements easier. + */ + tvr.changeLength(newlen); + if (!InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues, + SourceVectorAllValues)) { + return false; } - ok = js_MergeSort(vec, (size_t) newlen, sizeof(jsval), - comparator_stack_cast(sort_compare), - &ca, mergesort_tmp); - js_FreeStack(cx, mark); - if (!ok) - goto out; } - /* - * We no longer need to root the scratch space for the merge sort, so - * unroot it now to make the job of a potential GC under InitArrayElements - * easier. - */ - tvr.count = newlen; - ok = InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues, - SourceVectorAllValues); - if (!ok) - goto out; - - out: - JS_POP_TEMP_ROOT(cx, &tvr); - cx->free(vec); - if (!ok) - return JS_FALSE; - /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) { - return JS_FALSE; - } + if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) + return false; } /* Re-create any holes that sorted to the end of the array. */ while (len > newlen) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !DeleteArrayElement(cx, obj, --len)) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len)) return JS_FALSE; - } } *vp = OBJECT_TO_JSVAL(obj); - return JS_TRUE; + return true; } /* @@ -2433,7 +2403,7 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0, static jsval FASTCALL Array_p_push1(JSContext* cx, JSObject* obj, jsval v) { - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); if (obj->isDenseArray() ? array_push1_dense(cx, obj, v, tvr.addr()) : array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) { @@ -2505,7 +2475,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp) static jsval FASTCALL Array_p_pop(JSContext* cx, JSObject* obj) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (obj->isDenseArray() ? array_pop_dense(cx, obj, tvr.addr()) : array_pop_slowly(cx, obj, tvr.addr())) { @@ -2569,7 +2539,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; /* Slide down the array above the first element. */ - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); for (i = 0; i != length; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) || @@ -2614,7 +2584,7 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp) } else { last = length; jsdouble upperIndex = last + argc; - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); do { --last, --upperIndex; if (!JS_CHECK_OPERATION_LIMIT(cx) || @@ -2704,7 +2674,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) argv++; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); /* If there are elements to remove, put them into the return value. */ if (count > 0) { @@ -2843,7 +2813,7 @@ array_concat(JSContext *cx, uintN argc, jsval *vp) length = 0; } - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ for (i = 0; i <= argc; i++) { @@ -2957,7 +2927,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = OBJECT_TO_JSVAL(nobj); - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); for (slot = begin; slot < end; slot++) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, slot, &hole, tvr.addr())) { @@ -3478,7 +3448,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey) JS_ASSERT(obj->getProto()); { - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); if (!InitArrayObject(cx, obj, length, vector, holey)) obj = NULL; } @@ -3597,7 +3567,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector) if (!obj) return NULL; - JSAutoTempValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, obj); if (!EnsureCapacity(cx, obj, capacity, JS_FALSE)) obj = NULL; From b2a62b2daedb86b5434bce981b4f80efe3c52cea Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 26 Mar 2010 18:38:33 -0500 Subject: [PATCH 160/213] Bug 500431 part 5 - Make js::PropertyCache fields private. r=brendan. --- js/src/jsops.cpp | 183 ++++++++++++-------------------- js/src/jspropertycache.h | 49 +++++++-- js/src/jspropertycacheinlines.h | 53 +++++++++ js/src/jsprvtd.h | 2 +- 4 files changed, 164 insertions(+), 123 deletions(-) diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 2bb769ded0ce..b798e658ba5a 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1677,10 +1677,9 @@ BEGIN_CASE(JSOP_SETMETHOD) atom = NULL; if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { PropertyCache *cache = &JS_PROPERTY_CACHE(cx); - uint32 kshape = OBJ_SHAPE(obj); /* - * Open-code PropertyCache::test, specializing for two important + * Probe the property cache, specializing for two important * set-property cases. First: * * function f(a, b, c) { @@ -1698,15 +1697,14 @@ BEGIN_CASE(JSOP_SETMETHOD) * (possibly after the first iteration) always exist in native * object o. */ - entry = &cache->table[PropertyCache::hash(regs.pc, kshape)]; - PCMETER(cache->pctestentry = entry); - PCMETER(cache->tests++); - PCMETER(cache->settests++); - if (entry->kpc == regs.pc && entry->kshape == kshape && - PropertyCache::matchShape(cx, obj, kshape)) { + if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) { /* - * Property cache hit: either predicting a new property to be - * added directly to obj by this set, or on an existing "own" + * Fast property cache hit, only partially confirmed by + * testForSet. We know that the entry applies to regs.pc and + * that obj's shape matches. + * + * The entry predicts either a new property to be added + * directly to obj by this set, or on an existing "own" * property, or on a prototype property that has a setter. */ JS_ASSERT(entry->vword.isSprop()); @@ -1833,17 +1831,15 @@ BEGIN_CASE(JSOP_SETMETHOD) break; } PCMETER(cache->setpcmisses++); - } - - atom = cache->fullTest(cx, regs.pc, &obj, &obj2, entry); - if (atom) { - PCMETER(cache->misses++); - PCMETER(cache->setmisses++); - } else { + atom = NULL; + } else if (!atom) { + /* + * Slower property cache hit, fully confirmed by testForSet (in + * the slow path, via fullTest). + */ ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); sprop = NULL; if (obj == obj2) { - JS_ASSERT(entry->vword.isSprop()); sprop = entry->vword.toSprop(); JS_ASSERT(sprop->writable()); JS_ASSERT(!OBJ_SCOPE(obj2)->sealed()); @@ -3359,6 +3355,7 @@ END_CASE(JSOP_ENDINIT) BEGIN_CASE(JSOP_INITPROP) BEGIN_CASE(JSOP_INITMETHOD) +{ /* Load the property's initial value into rval. */ JS_ASSERT(regs.sp - StackBase(fp) >= 2); rval = FETCH_OPND(-1); @@ -3369,104 +3366,63 @@ BEGIN_CASE(JSOP_INITMETHOD) JS_ASSERT(OBJ_IS_NATIVE(obj)); JS_ASSERT(!OBJ_GET_CLASS(cx, obj)->reserveSlots); JS_ASSERT(!(obj->getClass()->flags & JSCLASS_SHARE_ALL_PROPERTIES)); - do { - JSScope *scope; - uint32 kshape; - PropertyCache *cache; - PropertyCacheEntry *entry; - /* - * We can not assume that the object created by JSOP_NEWINIT is still - * single-threaded as the debugger can access it from other threads. - */ - if (!CX_OWNS_OBJECT_TITLE(cx, obj)) - goto do_initprop_miss; + JSScope *scope = OBJ_SCOPE(obj); + PropertyCacheEntry *entry; - scope = OBJ_SCOPE(obj); - JS_ASSERT(scope->object == obj); - JS_ASSERT(!scope->sealed()); - kshape = scope->shape; - cache = &JS_PROPERTY_CACHE(cx); - entry = &cache->table[PropertyCache::hash(regs.pc, kshape)]; - PCMETER(cache->pctestentry = entry); - PCMETER(cache->tests++); - PCMETER(cache->initests++); - - if (entry->kpc == regs.pc && - entry->kshape == kshape && - entry->vshape() == rt->protoHazardShape) { - JS_ASSERT(entry->vcapTag() == 0); - - PCMETER(cache->pchits++); - PCMETER(cache->inipchits++); - - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - JS_ASSERT(sprop->writable()); - - /* - * If this property has a non-stub setter, it must be __proto__, - * __parent__, or another "shared prototype" built-in. Force a miss - * to save code size here and let the standard code path take care - * of business. - */ - if (!sprop->hasDefaultSetter()) - goto do_initprop_miss; - - /* - * Detect a repeated property name and force a miss to share the - * strict warning code and consolidate all the complexity managed - * by JSScope::addProperty. - */ - if (sprop->parent != scope->lastProperty()) - goto do_initprop_miss; - - /* - * Otherwise this entry must be for a direct property of obj, not a - * proto-property, and there cannot have been any deletions of - * prior properties. - */ - JS_ASSERT(!scope->inDictionaryMode()); - JS_ASSERT_IF(scope->table, !scope->hasProperty(sprop)); - - slot = sprop->slot; - JS_ASSERT(slot == scope->freeslot); - if (slot < STOBJ_NSLOTS(obj)) { - ++scope->freeslot; - } else { - if (!js_AllocSlot(cx, obj, &slot)) - goto error; - JS_ASSERT(slot == sprop->slot); - } - - JS_ASSERT(!scope->lastProperty() || - scope->shape == scope->lastProperty()->shape); - if (scope->table) { - JSScopeProperty *sprop2 = - scope->addProperty(cx, sprop->id, sprop->getter(), sprop->setter(), slot, - sprop->attributes(), sprop->getFlags(), sprop->shortid); - if (!sprop2) { - js_FreeSlot(cx, obj, slot); - goto error; - } - JS_ASSERT(sprop2 == sprop); - } else { - JS_ASSERT(!scope->isSharedEmpty()); - scope->extend(cx, sprop); - } - - /* - * No method change check here because here we are adding a new - * property, not updating an existing slot's value that might - * contain a method of a branded scope. - */ - TRACE_2(SetPropHit, entry, sprop); - LOCKED_OBJ_SET_SLOT(obj, slot, rval); - break; + /* + * Probe the property cache. + * + * We can not assume that the object created by JSOP_NEWINIT is still + * single-threaded as the debugger can access it from other threads. + * So check first. + * + * On a hit, if the cached sprop has a non-default setter, it must be + * __proto__ or __parent__. If sprop->parent != scope->lastProperty(), + * there is a repeated property name. The fast path does not handle these + * two cases. + */ + if (CX_OWNS_OBJECT_TITLE(cx, obj) && + JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, scope, &sprop, &entry) && + sprop->hasDefaultSetter() && + sprop->parent == scope->lastProperty()) + { + /* Fast path. Property cache hit. */ + slot = sprop->slot; + JS_ASSERT(slot == scope->freeslot); + if (slot < STOBJ_NSLOTS(obj)) { + ++scope->freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) + goto error; + JS_ASSERT(slot == sprop->slot); } - do_initprop_miss: - PCMETER(cache->inipcmisses++); + JS_ASSERT(!scope->lastProperty() || + scope->shape == scope->lastProperty()->shape); + if (scope->table) { + JSScopeProperty *sprop2 = + scope->addProperty(cx, sprop->id, sprop->getter(), sprop->setter(), slot, + sprop->attributes(), sprop->getFlags(), sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + goto error; + } + JS_ASSERT(sprop2 == sprop); + } else { + JS_ASSERT(!scope->isSharedEmpty()); + scope->extend(cx, sprop); + } + + /* + * No method change check here because here we are adding a new + * property, not updating an existing slot's value that might + * contain a method of a branded scope. + */ + TRACE_2(SetPropHit, entry, sprop); + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + } else { + PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++); /* Get the immediate property name into id. */ LOAD_ATOM(0); @@ -3488,10 +3444,11 @@ BEGIN_CASE(JSOP_INITMETHOD) defineHow))) { goto error; } - } while (0); + } /* Common tail for property cache hit and miss cases. */ regs.sp--; +} END_CASE(JSOP_INITPROP); BEGIN_CASE(JSOP_INITELEM) diff --git a/js/src/jspropertycache.h b/js/src/jspropertycache.h index 05081a8c42f4..16b3995dbcd1 100644 --- a/js/src/jspropertycache.h +++ b/js/src/jspropertycache.h @@ -147,8 +147,9 @@ struct PropertyCacheEntry #define JS_PROPERTY_CACHE_METERING 1 #endif -struct PropertyCache +class PropertyCache { + private: enum { SIZE_LOG2 = 12, SIZE = JS_BIT(SIZE_LOG2), @@ -158,6 +159,7 @@ struct PropertyCache PropertyCacheEntry table[SIZE]; JSBool empty; #ifdef JS_PROPERTY_CACHE_METERING + public: PropertyCacheEntry *pctestentry; /* entry of the last PC-based test */ uint32 fills; /* number of cache entry fills */ uint32 nofills; /* couldn't fill (e.g. default get) */ @@ -187,6 +189,7 @@ struct PropertyCache uint32 misses; /* cache misses */ uint32 flushes; /* cache flushes */ uint32 pcpurges; /* shadowing purges on proto chain */ + private: # define PCMETER(x) x #else # define PCMETER(x) ((void)0) @@ -205,12 +208,46 @@ struct PropertyCache static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape); + JS_REQUIRES_STACK JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, + JSObject **pobjp, PropertyCacheEntry *entry); + +#ifdef DEBUG + void assertEmpty(); +#else + inline void assertEmpty() {} +#endif + + public: JS_ALWAYS_INLINE JS_REQUIRES_STACK void test(JSContext *cx, jsbytecode *pc, JSObject *&obj, JSObject *&pobj, PropertyCacheEntry *&entry, JSAtom *&atom); - JS_REQUIRES_STACK JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, - JSObject **pobjp, PropertyCacheEntry *entry); + /* + * Test for cached information about a property set on *objp at pc. + * + * On a fast hit, set *entryp to the entry and return true. + * + * On a slow hit, set *entryp to the entry, set *obj2p to the object that + * owns the property (either obj or a prototype), set *atomp to NULL, and + * return false. + * + * On a miss, set *atomp to the name of the property being set and return false. + */ + JS_ALWAYS_INLINE bool testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj, + PropertyCacheEntry **entryp, JSObject **obj2p, + JSAtom **atomp); + + /* + * Test for cached information about creating a new own data property on obj at pc. + * + * On a hit, set *spropp to an sprop from the property tree describing the + * new property as well as all existing properties on obj and return + * true. Otherwise return false. + * + * Hit or miss, *entryp receives a pointer to the property cache entry. + */ + JS_ALWAYS_INLINE bool testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj, JSScope *scope, + JSScopeProperty **spropp, PropertyCacheEntry **entryp); /* * Fill property cache entry for key cx->fp->pc, optimized value word @@ -226,12 +263,6 @@ struct PropertyCache void purge(JSContext *cx); void purgeForScript(JSScript *script); - -#ifdef DEBUG - void assertEmpty(); -#else - inline void assertEmpty() {} -#endif }; } /* namespace js */ diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h index 4f7eb93a3223..6c829a04d443 100644 --- a/js/src/jspropertycacheinlines.h +++ b/js/src/jspropertycacheinlines.h @@ -100,4 +100,57 @@ PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, PCMETER(misses++); } +JS_ALWAYS_INLINE bool +PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj, + PropertyCacheEntry **entryp, JSObject **obj2p, JSAtom **atomp) +{ + uint32 shape = OBJ_SHAPE(obj); + PropertyCacheEntry *entry = &table[hash(pc, shape)]; + *entryp = entry; + PCMETER(pctestentry = entry); + PCMETER(tests++); + PCMETER(settests++); + if (entry->kpc == pc && entry->kshape == shape && matchShape(cx, obj, shape)) + return true; + +#ifdef DEBUG + JSObject *orig = obj; +#endif + JSAtom *atom = fullTest(cx, pc, &obj, obj2p, entry); + if (atom) { + PCMETER(misses++); + PCMETER(setmisses++); + } else { + JS_ASSERT(obj == orig); + } + *atomp = atom; + return false; +} + +JS_ALWAYS_INLINE bool +PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj, JSScope *scope, + JSScopeProperty **spropp, PropertyCacheEntry **entryp) +{ + JS_ASSERT(scope->object == obj); + JS_ASSERT(!scope->sealed()); + uint32 kshape = scope->shape; + PropertyCacheEntry *entry = &table[hash(pc, kshape)]; + *entryp = entry; + PCMETER(pctestentry = entry); + PCMETER(tests++); + PCMETER(initests++); + + if (entry->kpc == pc && + entry->kshape == kshape && + entry->vshape() == rt->protoHazardShape) { + PCMETER(pchits++); + PCMETER(inipchits++); + JS_ASSERT(entry->vcapTag() == 0); + *spropp = entry->vword.toSprop(); + JS_ASSERT((*spropp)->writable()); + return true; + } + return false; +} + #endif /* jspropertycacheinlines_h___ */ diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 4100f7e68a5b..1f9a4af30526 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -174,7 +174,7 @@ class HashSet; class DeflatedStringCache; -struct PropertyCache; +class PropertyCache; struct PropertyCacheEntry; } /* namespace js */ From d1f4fe9a74922fd72a9053e190f8359f7568acb6 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 29 Mar 2010 10:35:16 -0500 Subject: [PATCH 161/213] Bug 554996 - Eliminate native-ops check before testing property cache. Part 1: interpreter. r=gal. --- js/src/jsops.cpp | 506 +++++++++++++++----------------- js/src/jspropertycache.cpp | 3 +- js/src/jspropertycacheinlines.h | 8 +- 3 files changed, 248 insertions(+), 269 deletions(-) diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index b798e658ba5a..699502041561 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -708,16 +708,13 @@ BEGIN_CASE(JSOP_BINDNAME) obj = fp->scopeChain; if (!obj->getParent()) break; - if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - break; - } - } else { - entry = NULL; - LOAD_ATOM(0); + + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + break; } + id = ATOM_TO_JSID(atom); obj = js_FindIdentifierBase(cx, fp->scopeChain, id); if (!obj) @@ -1219,30 +1216,28 @@ BEGIN_CASE(JSOP_NAMEDEC) PropertyCacheEntry *entry; obj = fp->scopeChain; - if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - if (obj == obj2 && entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot); - rval = LOCKED_OBJ_GET_SLOT(obj, slot); - if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { + + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (obj == obj2 && entry->vword.isSlot()) { + slot = entry->vword.toSlot(); + JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj, slot); + if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { + rtmp = rval; + rval += (js_CodeSpec[op].format & JOF_INC) ? 2 : -2; + if (!(js_CodeSpec[op].format & JOF_POST)) rtmp = rval; - rval += (js_CodeSpec[op].format & JOF_INC) ? 2 : -2; - if (!(js_CodeSpec[op].format & JOF_POST)) - rtmp = rval; - LOCKED_OBJ_SET_SLOT(obj, slot, rval); - PUSH_OPND(rtmp); - len = JSOP_INCNAME_LENGTH; - DO_NEXT_OP(len); - } + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + PUSH_OPND(rtmp); + len = JSOP_INCNAME_LENGTH; + DO_NEXT_OP(len); } - LOAD_ATOM(0); } - } else { LOAD_ATOM(0); } + id = ATOM_TO_JSID(atom); if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) goto error; @@ -1483,34 +1478,28 @@ BEGIN_CASE(JSOP_GETXPROP) * from JSOP_NEW) will not be leaked to the calling script. */ aobj = js_GetProtoIfDenseArray(obj); - if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); - if (entry->vword.isObject()) { - rval = entry->vword.toJsval(); - } else if (entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); - rval = LOCKED_OBJ_GET_SLOT(obj2, slot); - } else { - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - NATIVE_GET(cx, obj, obj2, sprop, - fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, - &rval); - } - break; + + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); + if (entry->vword.isObject()) { + rval = entry->vword.toJsval(); + } else if (entry->vword.isSlot()) { + slot = entry->vword.toSlot(); + JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj2, slot); + } else { + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); + NATIVE_GET(cx, obj, obj2, sprop, + fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, + &rval); } - } else { - entry = NULL; - if (i < 0) - atom = rt->atomState.lengthAtom; - else - LOAD_ATOM(i); + break; } + id = ATOM_TO_JSID(atom); - if (entry + if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty) ? !js_GetPropertyHelper(cx, obj, id, fp->imacpc ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER @@ -1579,28 +1568,24 @@ BEGIN_CASE(JSOP_CALLPROP) } aobj = js_GetProtoIfDenseArray(obj); - if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); - if (entry->vword.isObject()) { - rval = entry->vword.toJsval(); - } else if (entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); - rval = LOCKED_OBJ_GET_SLOT(obj2, slot); - } else { - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - NATIVE_GET(cx, obj, obj2, sprop, JSGET_NO_METHOD_BARRIER, &rval); - } - STORE_OPND(-1, rval); - PUSH_OPND(lval); - goto end_callprop; + + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); + if (entry->vword.isObject()) { + rval = entry->vword.toJsval(); + } else if (entry->vword.isSlot()) { + slot = entry->vword.toSlot(); + JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj2, slot); + } else { + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); + NATIVE_GET(cx, obj, obj2, sprop, JSGET_NO_METHOD_BARRIER, &rval); } - } else { - entry = NULL; - LOAD_ATOM(0); + STORE_OPND(-1, rval); + PUSH_OPND(lval); + goto end_callprop; } /* @@ -1611,7 +1596,7 @@ BEGIN_CASE(JSOP_CALLPROP) PUSH(JSVAL_NULL); if (!JSVAL_IS_PRIMITIVE(lval)) { if (!js_GetMethod(cx, obj, id, - entry + JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty) ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER : JSGET_NO_METHOD_BARRIER, &rval)) { @@ -1671,189 +1656,185 @@ BEGIN_CASE(JSOP_SETMETHOD) VALUE_TO_OBJECT(cx, -2, lval, obj); do { - PropertyCacheEntry *entry; - - entry = NULL; + PropertyCache *cache = &JS_PROPERTY_CACHE(cx); + PropertyCacheEntry *entry = NULL; atom = NULL; - if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { - PropertyCache *cache = &JS_PROPERTY_CACHE(cx); + + /* + * Probe the property cache, specializing for two important + * set-property cases. First: + * + * function f(a, b, c) { + * var o = {p:a, q:b, r:c}; + * return o; + * } + * + * or similar real-world cases, which evolve a newborn native + * object predicatably through some bounded number of property + * additions. And second: + * + * o.p = x; + * + * in a frequently executed method or loop body, where p will + * (possibly after the first iteration) always exist in native + * object o. + */ + if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) { + /* + * Fast property cache hit, only partially confirmed by + * testForSet. We know that the entry applies to regs.pc and + * that obj's shape matches. + * + * The entry predicts either a new property to be added + * directly to obj by this set, or on an existing "own" + * property, or on a prototype property that has a setter. + */ + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); + JS_ASSERT(sprop->writable()); + JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0); + + JSScope *scope = OBJ_SCOPE(obj); + JS_ASSERT(!scope->sealed()); /* - * Probe the property cache, specializing for two important - * set-property cases. First: - * - * function f(a, b, c) { - * var o = {p:a, q:b, r:c}; - * return o; - * } - * - * or similar real-world cases, which evolve a newborn native - * object predicatably through some bounded number of property - * additions. And second: - * - * o.p = x; - * - * in a frequently executed method or loop body, where p will - * (possibly after the first iteration) always exist in native - * object o. + * Fastest path: check whether the cached sprop is already + * in scope and call NATIVE_SET and break to get out of the + * do-while(0). But we can call NATIVE_SET only if obj owns + * scope or sprop is shared. */ - if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) { + bool checkForAdd; + if (!sprop->hasSlot()) { + if (entry->vcapTag() == 0 || + ((obj2 = obj->getProto()) && + OBJ_IS_NATIVE(obj2) && + OBJ_SHAPE(obj2) == entry->vshape())) { + goto fast_set_propcache_hit; + } + + /* The cache entry doesn't apply. vshape mismatch. */ + checkForAdd = false; + } else if (!scope->isSharedEmpty()) { + if (sprop == scope->lastProperty() || scope->hasProperty(sprop)) { + fast_set_propcache_hit: + PCMETER(cache->pchits++); + PCMETER(cache->setpchits++); + NATIVE_SET(cx, obj, sprop, entry, &rval); + break; + } + checkForAdd = sprop->hasSlot() && sprop->parent == scope->lastProperty(); + } else { /* - * Fast property cache hit, only partially confirmed by - * testForSet. We know that the entry applies to regs.pc and - * that obj's shape matches. - * - * The entry predicts either a new property to be added - * directly to obj by this set, or on an existing "own" - * property, or on a prototype property that has a setter. + * We check that cx own obj here and will continue to + * own it after js_GetMutableScope returns so we can + * continue to skip JS_UNLOCK_OBJ calls. */ - JS_ASSERT(entry->vword.isSprop()); + JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); + scope = js_GetMutableScope(cx, obj); + JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); + if (!scope) + goto error; + checkForAdd = !sprop->parent; + } + + if (checkForAdd && + entry->vshape() == rt->protoHazardShape && + sprop->hasDefaultSetter() && + (slot = sprop->slot) == scope->freeslot) { + /* + * Fast path: adding a plain old property that was once + * at the frontier of the property tree, whose slot is + * next to claim among the allocated slots in obj, + * where scope->table has not been created yet. + * + * We may want to remove hazard conditions above and + * inline compensation code here, depending on + * real-world workloads. + */ + JS_ASSERT(!(obj->getClass()->flags & + JSCLASS_SHARE_ALL_PROPERTIES)); + + PCMETER(cache->pchits++); + PCMETER(cache->addpchits++); + + /* + * Beware classes such as Function that use the + * reserveSlots hook to allocate a number of reserved + * slots that may vary with obj. + */ + if (slot < STOBJ_NSLOTS(obj) && + !OBJ_GET_CLASS(cx, obj)->reserveSlots) { + ++scope->freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) + goto error; + } + + /* + * If this obj's number of reserved slots differed, or + * if something created a hash table for scope, we must + * pay the price of JSScope::putProperty. + * + * (A reserveSlots hook can cause scopes of the same + * shape to have different freeslot values. This is + * what causes the slot != sprop->slot case. See + * js_GetMutableScope.) + */ + if (slot != sprop->slot || scope->table) { + JSScopeProperty *sprop2 = + scope->putProperty(cx, sprop->id, + sprop->getter(), sprop->setter(), + slot, sprop->attributes(), + sprop->getFlags(), sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + goto error; + } + sprop = sprop2; + } else { + scope->extend(cx, sprop); + } + + /* + * No method change check here because here we are + * adding a new property, not updating an existing + * slot's value that might contain a method of a + * branded scope. + */ + TRACE_2(SetPropHit, entry, sprop); + LOCKED_OBJ_SET_SLOT(obj, slot, rval); + + /* + * Purge the property cache of the id we may have just + * shadowed in obj's scope and proto chains. We do this + * after unlocking obj's scope to avoid lock nesting. + */ + js_PurgeScopeChain(cx, obj, sprop->id); + break; + } + PCMETER(cache->setpcmisses++); + atom = NULL; + } else if (!atom) { + /* + * Slower property cache hit, fully confirmed by testForSet (in + * the slow path, via fullTest). + */ + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + sprop = NULL; + if (obj == obj2) { sprop = entry->vword.toSprop(); JS_ASSERT(sprop->writable()); - JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0); - - JSScope *scope = OBJ_SCOPE(obj); - JS_ASSERT(!scope->sealed()); - - /* - * Fastest path: check whether the cached sprop is already - * in scope and call NATIVE_SET and break to get out of the - * do-while(0). But we can call NATIVE_SET only if obj owns - * scope or sprop is shared. - */ - bool checkForAdd; - if (!sprop->hasSlot()) { - if (entry->vcapTag() == 0 || - ((obj2 = obj->getProto()) && - OBJ_IS_NATIVE(obj2) && - OBJ_SHAPE(obj2) == entry->vshape())) { - goto fast_set_propcache_hit; - } - - /* The cache entry doesn't apply. vshape mismatch. */ - checkForAdd = false; - } else if (!scope->isSharedEmpty()) { - if (sprop == scope->lastProperty() || scope->hasProperty(sprop)) { - fast_set_propcache_hit: - PCMETER(cache->pchits++); - PCMETER(cache->setpchits++); - NATIVE_SET(cx, obj, sprop, entry, &rval); - break; - } - checkForAdd = sprop->hasSlot() && sprop->parent == scope->lastProperty(); - } else { - /* - * We check that cx own obj here and will continue to - * own it after js_GetMutableScope returns so we can - * continue to skip JS_UNLOCK_OBJ calls. - */ - JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); - scope = js_GetMutableScope(cx, obj); - JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); - if (!scope) - goto error; - checkForAdd = !sprop->parent; - } - - if (checkForAdd && - entry->vshape() == rt->protoHazardShape && - sprop->hasDefaultSetter() && - (slot = sprop->slot) == scope->freeslot) { - /* - * Fast path: adding a plain old property that was once - * at the frontier of the property tree, whose slot is - * next to claim among the allocated slots in obj, - * where scope->table has not been created yet. - * - * We may want to remove hazard conditions above and - * inline compensation code here, depending on - * real-world workloads. - */ - JS_ASSERT(!(obj->getClass()->flags & - JSCLASS_SHARE_ALL_PROPERTIES)); - - PCMETER(cache->pchits++); - PCMETER(cache->addpchits++); - - /* - * Beware classes such as Function that use the - * reserveSlots hook to allocate a number of reserved - * slots that may vary with obj. - */ - if (slot < STOBJ_NSLOTS(obj) && - !OBJ_GET_CLASS(cx, obj)->reserveSlots) { - ++scope->freeslot; - } else { - if (!js_AllocSlot(cx, obj, &slot)) - goto error; - } - - /* - * If this obj's number of reserved slots differed, or - * if something created a hash table for scope, we must - * pay the price of JSScope::putProperty. - * - * (A reserveSlots hook can cause scopes of the same - * shape to have different freeslot values. This is - * what causes the slot != sprop->slot case. See - * js_GetMutableScope.) - */ - if (slot != sprop->slot || scope->table) { - JSScopeProperty *sprop2 = - scope->putProperty(cx, sprop->id, - sprop->getter(), sprop->setter(), - slot, sprop->attributes(), - sprop->getFlags(), sprop->shortid); - if (!sprop2) { - js_FreeSlot(cx, obj, slot); - goto error; - } - sprop = sprop2; - } else { - scope->extend(cx, sprop); - } - - /* - * No method change check here because here we are - * adding a new property, not updating an existing - * slot's value that might contain a method of a - * branded scope. - */ - TRACE_2(SetPropHit, entry, sprop); - LOCKED_OBJ_SET_SLOT(obj, slot, rval); - - /* - * Purge the property cache of the id we may have just - * shadowed in obj's scope and proto chains. We do this - * after unlocking obj's scope to avoid lock nesting. - */ - js_PurgeScopeChain(cx, obj, sprop->id); - break; - } - PCMETER(cache->setpcmisses++); - atom = NULL; - } else if (!atom) { - /* - * Slower property cache hit, fully confirmed by testForSet (in - * the slow path, via fullTest). - */ - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - sprop = NULL; - if (obj == obj2) { - sprop = entry->vword.toSprop(); - JS_ASSERT(sprop->writable()); - JS_ASSERT(!OBJ_SCOPE(obj2)->sealed()); - NATIVE_SET(cx, obj, sprop, entry, &rval); - } - if (sprop) - break; + JS_ASSERT(!OBJ_SCOPE(obj2)->sealed()); + NATIVE_SET(cx, obj, sprop, entry, &rval); } + if (sprop) + break; } if (!atom) LOAD_ATOM(0); id = ATOM_TO_JSID(atom); - if (entry) { + if (entry && JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { uintN defineHow = (op == JSOP_SETMETHOD) ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD : JSDNP_CACHE_RESULT; @@ -2287,28 +2268,25 @@ BEGIN_CASE(JSOP_CALLNAME) PropertyCacheEntry *entry; obj = fp->scopeChain; - if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - if (entry->vword.isObject()) { - rval = entry->vword.toJsval(); - goto do_push_rval; - } - if (entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); - rval = LOCKED_OBJ_GET_SLOT(obj2, slot); - goto do_push_rval; - } - - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - goto do_native_get; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (entry->vword.isObject()) { + rval = entry->vword.toJsval(); + goto do_push_rval; } - } else { - LOAD_ATOM(0); + + if (entry->vword.isSlot()) { + slot = entry->vword.toSlot(); + JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot); + rval = LOCKED_OBJ_GET_SLOT(obj2, slot); + goto do_push_rval; + } + + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); + goto do_native_get; } id = ATOM_TO_JSID(atom); diff --git a/js/src/jspropertycache.cpp b/js/src/jspropertycache.cpp index c89d9be2375f..b6e610fc09e6 100644 --- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -334,7 +334,6 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject const JSCodeSpec &cs = js_CodeSpec[op]; obj = *objp; - JS_ASSERT(OBJ_IS_NATIVE(obj)); vcap = entry->vcap; if (entry->kpc != pc) { @@ -360,7 +359,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject return atom; } - if (entry->kshape != OBJ_SHAPE(obj)) { + if (entry->kshape != obj->map->shape) { PCMETER(kshapemisses++); return GetAtomFromBytecode(cx, pc, op, cs); } diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h index 6c829a04d443..b347c1800f5d 100644 --- a/js/src/jspropertycacheinlines.h +++ b/js/src/jspropertycacheinlines.h @@ -73,13 +73,13 @@ PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, JSObject *&pobj, PropertyCacheEntry *&entry, JSAtom *&atom) { JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); - JS_ASSERT(OBJ_IS_NATIVE(obj)); - uint32 kshape = OBJ_SHAPE(obj); + uint32 kshape = obj->map->shape; entry = &table[hash(pc, kshape)]; PCMETER(pctestentry = entry); PCMETER(tests++); JS_ASSERT(&obj != &pobj); + JS_ASSERT(entry->kshape < SHAPE_OVERFLOW_BIT); if (entry->kpc == pc && entry->kshape == kshape) { JSObject *tmp; pobj = obj; @@ -104,12 +104,13 @@ JS_ALWAYS_INLINE bool PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj, PropertyCacheEntry **entryp, JSObject **obj2p, JSAtom **atomp) { - uint32 shape = OBJ_SHAPE(obj); + uint32 shape = obj->map->shape; PropertyCacheEntry *entry = &table[hash(pc, shape)]; *entryp = entry; PCMETER(pctestentry = entry); PCMETER(tests++); PCMETER(settests++); + JS_ASSERT(entry->kshape < SHAPE_OVERFLOW_BIT); if (entry->kpc == pc && entry->kshape == shape && matchShape(cx, obj, shape)) return true; @@ -139,6 +140,7 @@ PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj, JSScope PCMETER(pctestentry = entry); PCMETER(tests++); PCMETER(initests++); + JS_ASSERT(entry->kshape < SHAPE_OVERFLOW_BIT); if (entry->kpc == pc && entry->kshape == kshape && From ef306b8afac4d2ce41360a059ae00cb1930f2f02 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 29 Mar 2010 10:35:38 -0500 Subject: [PATCH 162/213] Bug 554996 - Eliminate native-ops check before testing property cache. Part 2: tracer. r=gal. --- js/src/jstracer.cpp | 64 +++++++-------------------------------------- js/src/jstracer.h | 6 +---- 2 files changed, 11 insertions(+), 59 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 303577f47ce2..eb3fc705c656 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -9032,7 +9032,7 @@ TraceRecorder::dumpGuardedShapes(const char* prefix) JS_REQUIRES_STACK RecordingStatus TraceRecorder::guardShape(LIns* obj_ins, JSObject* obj, uint32 shape, const char* guardName, - LIns* map_ins, VMSideExit* exit) + VMSideExit* exit) { // Test (with add if missing) for a remembered guard for (obj_ins, obj). GuardedShapeTable::AddPtr p = guardedShapeTable.lookupForAdd(obj_ins); @@ -9051,7 +9051,7 @@ TraceRecorder::guardShape(LIns* obj_ins, JSObject* obj, uint32 shape, const char // Finally, emit the shape guard. LIns* shape_ins = - addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape), ACC_OTHER), "shape"); + addName(lir->insLoad(LIR_ld, map(obj_ins), offsetof(JSScope, shape), ACC_OTHER), "shape"); guard(true, addName(lir->ins2i(LIR_eq, shape_ins, shape), guardName), exit); @@ -9110,41 +9110,6 @@ TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, si return true; } -JS_REQUIRES_STACK RecordingStatus -TraceRecorder::guardNativePropertyOp(JSObject* aobj, LIns* map_ins) -{ - /* - * Interpreter calls to PropertyCache::test guard on native object ops - * which is required to use native objects (those whose maps are scopes), - * or even more narrow conditions required because the cache miss case - * will call a particular object-op (js_GetProperty, js_SetProperty). - * - * We parameterize using offsetof and guard on match against the hook at - * the given offset in js_ObjectOps. TraceRecorder::record_JSOP_SETPROP - * guards the js_SetProperty case. - */ - uint32 format = js_CodeSpec[*cx->fp->regs->pc].format; - uint32 mode = JOF_MODE(format); - - // No need to guard native-ness of global object. - JS_ASSERT(OBJ_IS_NATIVE(globalObj)); - if (aobj != globalObj) { - size_t op_offset = offsetof(JSObjectOps, objectMap); - if (mode == JOF_PROP || mode == JOF_VARPROP) { - op_offset = (format & JOF_SET) - ? offsetof(JSObjectOps, setProperty) - : offsetof(JSObjectOps, getProperty); - } else { - JS_ASSERT(mode == JOF_NAME); - } - - LIns* ops_ins; - if (!map_is_native(aobj->map, map_ins, ops_ins, op_offset)) - RETURN_STOP("non-native map"); - } - return RECORD_CONTINUE; -} - JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, PCVal& pcval) { @@ -9162,10 +9127,6 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 obj_ins = stobj_get_proto(obj_ins); } - LIns* map_ins = map(obj_ins); - - CHECK_STATUS_A(guardNativePropertyOp(aobj, map_ins)); - JSAtom* atom; PropertyCacheEntry* entry; JS_PROPERTY_CACHE(cx).test(cx, pc, aobj, obj2, entry, atom); @@ -9242,12 +9203,11 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 JS_ASSERT(cx->requestDepth); #endif - return InjectStatus(guardPropertyCacheHit(obj_ins, map_ins, aobj, obj2, entry, pcval)); + return InjectStatus(guardPropertyCacheHit(obj_ins, aobj, obj2, entry, pcval)); } JS_REQUIRES_STACK RecordingStatus TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, - LIns* map_ins, JSObject* aobj, JSObject* obj2, PropertyCacheEntry* entry, @@ -9272,7 +9232,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, exit); } } else { - CHECK_STATUS(guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", map_ins, exit)); + CHECK_STATUS(guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", exit)); } if (entry->adding()) { @@ -9304,7 +9264,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, } else { obj2_ins = INS_CONSTOBJ(obj2); } - CHECK_STATUS(guardShape(obj2_ins, obj2, vshape, "guard_vshape", map(obj2_ins), exit)); + CHECK_STATUS(guardShape(obj2_ins, obj2, vshape, "guard_vshape", exit)); } pcval = entry->vword; @@ -9594,7 +9554,7 @@ TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins return RECORD_STOP; while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit)) - CHECK_STATUS(guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", map(obj_ins), exit)); + CHECK_STATUS(guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", exit)); return RECORD_CONTINUE; } @@ -11291,10 +11251,8 @@ TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* spr JS_ASSERT_IF(entry->adding(), obj2 == obj); // Guard before anything else. - LIns* map_ins = map(obj_ins); - CHECK_STATUS(guardNativePropertyOp(obj, map_ins)); PCVal pcval; - CHECK_STATUS(guardPropertyCacheHit(obj_ins, map_ins, obj, obj2, entry, pcval)); + CHECK_STATUS(guardPropertyCacheHit(obj_ins, obj, obj2, entry, pcval)); JS_ASSERT(scope->object == obj2); JS_ASSERT(scope->hasProperty(sprop)); JS_ASSERT_IF(obj2 != obj, !sprop->hasSlot()); @@ -12859,11 +12817,9 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, */ VMSideExit* exit = snapshot(BRANCH_EXIT); do { - LIns* map_ins = map(obj_ins); - LIns* ops_ins; - if (map_is_native(obj->map, map_ins, ops_ins)) { - CHECK_STATUS_A(InjectStatus(guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", - map_ins, exit))); + if (OBJ_IS_NATIVE(obj)) { + CHECK_STATUS_A(InjectStatus(guardShape(obj_ins, obj, OBJ_SHAPE(obj), + "guard(shape)", exit))); } else if (!guardDenseArray(obj, obj_ins, exit)) { RETURN_STOP_A("non-native object involved in undefined property access"); } diff --git a/js/src/jstracer.h b/js/src/jstracer.h index dda23bb92b64..256e79a8e37b 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -1195,8 +1195,7 @@ class TraceRecorder JS_REQUIRES_STACK RecordingStatus binary(nanojit::LOpcode op); JS_REQUIRES_STACK RecordingStatus guardShape(nanojit::LIns* obj_ins, JSObject* obj, - uint32 shape, const char* name, - nanojit::LIns* map_ins, VMSideExit* exit); + uint32 shape, const char* name, VMSideExit* exit); #if defined DEBUG_notme && defined XP_UNIX void dumpGuardedShapes(const char* prefix); @@ -1209,10 +1208,7 @@ class TraceRecorder nanojit::LIns*& ops_ins, size_t op_offset = 0); JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, JSObject*& obj2, PCVal& pcval); - JS_REQUIRES_STACK RecordingStatus guardNativePropertyOp(JSObject* aobj, - nanojit::LIns* map_ins); JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins, - nanojit::LIns* map_ins, JSObject* aobj, JSObject* obj2, PropertyCacheEntry* entry, From 2239823240233a39a1839dd2dc0e18483ca8ffa7 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 29 Mar 2010 11:24:42 -0500 Subject: [PATCH 163/213] Bug 541255 - "Assertion failure: obj->isDenseArray(), at ../jsarray.cpp". r=brendan. --- js/src/jsinterp.cpp | 2 +- js/src/jstracer.cpp | 2 +- js/src/tests/js1_8_5/regress/jstests.list | 5 ++++ .../tests/js1_8_5/regress/regress-541255-0.js | 14 +++++++++++ .../tests/js1_8_5/regress/regress-541255-1.js | 23 +++++++++++++++++++ .../tests/js1_8_5/regress/regress-541255-2.js | 11 +++++++++ .../tests/js1_8_5/regress/regress-541255-3.js | 13 +++++++++++ .../tests/js1_8_5/regress/regress-541255-4.js | 11 +++++++++ 8 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-0.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-3.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-4.js diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 704f0ee54848..d1a30d75e9fa 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1588,7 +1588,7 @@ js_GetUpvar(JSContext *cx, uintN level, uintN cookie) uintN slot = UPVAR_FRAME_SLOT(cookie); jsval *vp; - if (!fp->fun) { + if (!fp->fun || (fp->flags & JSFRAME_EVAL)) { vp = fp->slots + fp->script->nfixed; } else if (slot < fp->fun->nargs) { vp = fp->argv; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index eb3fc705c656..5f640cd0c2be 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -12213,7 +12213,7 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v) JSStackFrame* fp = cx->display[level]; const CallInfo* ci; int32 slot; - if (!fp->fun) { + if (!fp->fun || (fp->flags & JSFRAME_EVAL)) { ci = &GetUpvarStackOnTrace_ci; slot = cookieSlot; } else if (cookieSlot < fp->fun->nargs) { diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 28c43b280581..70fdfb08c1b6 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -1,4 +1,9 @@ url-prefix ../../jsreftest.html?test=js1_8_5/regress/ fails script regress-533876.js +script regress-541255-0.js +script regress-541255-1.js +script regress-541255-2.js +script regress-541255-3.js +script regress-541255-4.js script regress-541455.js script regress-546615.js diff --git a/js/src/tests/js1_8_5/regress/regress-541255-0.js b/js/src/tests/js1_8_5/regress/regress-541255-0.js new file mode 100644 index 000000000000..7cee605d6275 --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-541255-0.js @@ -0,0 +1,14 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Gary Kwong + */ +(function(e) { + eval("\ + [(function() {\ + x.k = function(){}\ + })() \ + for (x in [0])]\ + ") +})(); +print(" PASSED!"); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-1.js b/js/src/tests/js1_8_5/regress/regress-541255-1.js new file mode 100644 index 000000000000..1f123abeab06 --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-541255-1.js @@ -0,0 +1,23 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Gary Kwong + */ + +function f(e) { + eval("\ + [((function g(o, bbbbbb) {\ + if (aaaaaa = bbbbbb) {\ + return window.r = []\ + }\ + g(aaaaaa, bbbbbb + 1);\ + #3={}\ + })([], 0)) \ + for (window in this) \ + for each(x in [0, 0])\ + ]\ + ") +} +t = 1; +f(); +print(" PASSED!"); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-2.js b/js/src/tests/js1_8_5/regress/regress-541255-2.js new file mode 100644 index 000000000000..01e85a2e598f --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-541255-2.js @@ -0,0 +1,11 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributors: Gary Kwong and Jason Orendorff + */ + +function f(e) { + eval("[function () { w.r = 0 }() for (w in [0])]") +} +f(0); +print(" PASSED!"); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-3.js b/js/src/tests/js1_8_5/regress/regress-541255-3.js new file mode 100644 index 000000000000..0c3acbc22dbc --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-541255-3.js @@ -0,0 +1,13 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributors: Gary Kwong and Jason Orendorff + */ + +function f(y) { + eval("let (z=2, w=y) { (function () { w.p = 7; })(); }"); +} +var x = {}; +f(x); +assertEq(x.p, 7); +print(" PASSED!"); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-4.js b/js/src/tests/js1_8_5/regress/regress-541255-4.js new file mode 100644 index 000000000000..1617df879ac4 --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-541255-4.js @@ -0,0 +1,11 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributors: Gary Kwong and Jason Orendorff + */ + +function f(e) { + eval("[function () { w.r = 0 }() for (w in [0,1,2,3,4,5,6,7,8,9])]") +} +f(0); +print(" PASSED!"); From e3a19a7cada034349c8bde422d7de87b12216c04 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 11:36:33 -0700 Subject: [PATCH 164/213] Readd jsiter.cpp, jsscript.cpp, jsxml.cpp changes for bug 548702. --- js/src/jsiter.cpp | 56 +++---- js/src/jsscript.cpp | 8 +- js/src/jsxml.cpp | 375 ++++++++++++++++++-------------------------- 3 files changed, 172 insertions(+), 267 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index eaa3c872cd6e..d2882f6c837f 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -215,18 +215,11 @@ Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) static JSBool NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) { - jsval vec[2]; - JSTempValueRooter tvr; - JSObject *aobj; + jsval vec[2] = { ID_TO_VALUE(key), val }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); - vec[0] = ID_TO_VALUE(key); - vec[1] = val; - - JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); - aobj = js_NewArrayObject(cx, 2, vec); + JSObject *aobj = js_NewArrayObject(cx, 2, vec); *rval = OBJECT_TO_JSVAL(aobj); - JS_POP_TEMP_ROOT(cx, &tvr); - return aobj != NULL; } @@ -347,21 +340,19 @@ JS_FRIEND_API(JSBool) js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) { JSObject *obj; - JSTempValueRooter tvr; JSAtom *atom; JSClass *clasp; JSExtendedClass *xclasp; - JSBool ok; JSObject *iterobj; jsval arg; - JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | - JSITER_FOREACH | - JSITER_KEYVALUE))); + JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE))); /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); + AutoValueRooter tvr(cx); + /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(*vp)) { obj = JSVAL_TO_OBJECT(*vp); @@ -374,30 +365,29 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ if ((flags & JSITER_ENUMERATE)) { if (!js_ValueToObject(cx, *vp, &obj)) - return JS_FALSE; + return false; if (!obj) goto default_iter; } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) - return JS_FALSE; + return false; } } - JS_ASSERT(obj); - JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); + tvr.setObject(obj); clasp = OBJ_GET_CLASS(cx, obj); if ((clasp->flags & JSCLASS_IS_EXTENDED) && (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) - goto bad; + return false; *vp = OBJECT_TO_JSVAL(iterobj); } else { atom = cx->runtime->atomState.iteratorAtom; if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp)) - goto bad; + return false; if (JSVAL_IS_VOID(*vp)) { default_iter: /* @@ -410,36 +400,26 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL); if (!iterobj) - goto bad; + return false; /* Store in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); if (!InitNativeIterator(cx, iterobj, obj, flags)) - goto bad; + return false; } else { LeaveTrace(cx); arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); - if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, - vp)) { - goto bad; - } + if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, vp)) + return false; if (JSVAL_IS_PRIMITIVE(*vp)) { - js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN, - JSDVG_SEARCH_STACK, *vp, NULL); - goto bad; + js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN, JSDVG_SEARCH_STACK, *vp, NULL); + return false; } } } - ok = JS_TRUE; - out: - if (obj) - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; - bad: - ok = JS_FALSE; - goto out; + return true; } JS_FRIEND_API(JSBool) JS_FASTCALL diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 51435e5e3cf7..15065a6ca7d4 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -94,7 +94,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, uint32 length, lineno, nslots, magic; uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i; uint32 prologLength, version; - JSTempValueRooter tvr; JSPrincipals *principals; uint32 encodeable; JSBool filenameWasSaved; @@ -212,6 +211,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, if (!JS_XDRUint32(xdr, &nregexps)) return JS_FALSE; + AutoScriptRooter tvr(cx, NULL); + if (xdr->mode == JSXDR_DECODE) { script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, nregexps, ntrynotes); @@ -225,7 +226,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, /* If we know nsrcnotes, we allocated space for notes in script. */ notes = script->notes(); *scriptp = script; - JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); + tvr.setScript(script); } /* @@ -368,13 +369,10 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, } xdr->script = oldscript; - if (xdr->mode == JSXDR_DECODE) - JS_POP_TEMP_ROOT(cx, &tvr); return JS_TRUE; error: if (xdr->mode == JSXDR_DECODE) { - JS_POP_TEMP_ROOT(cx, &tvr); if (script->filename && !filenameWasSaved) { cx->free((void *) script->filename); script->filename = NULL; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 361f7e8ec3ad..141a7f965789 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -70,6 +70,8 @@ #include "jsstaticcheck.h" #include "jsvector.h" +#include "jscntxtinlines.h" + #ifdef DEBUG #include /* for #ifdef DEBUG memset calls */ #endif @@ -3795,12 +3797,10 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *kidobj, *listobj; JSObject *nameqn; jsid funid; - jsval roots[2]; - JSTempValueRooter tvr; xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) - return JS_TRUE; + return true; if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -3817,18 +3817,18 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); if (!kid) { *vp = JSVAL_VOID; - return JS_TRUE; + return true; } kidobj = js_GetXMLObject(cx, kid); if (!kidobj) - return JS_FALSE; + return false; *vp = OBJECT_TO_JSVAL(kidobj); } else { *vp = JSVAL_VOID; } } - return JS_TRUE; + return true; } /* @@ -3836,37 +3836,34 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) */ nameqn = ToXMLName(cx, id, &funid); if (!nameqn) - return JS_FALSE; + return false; if (funid) return GetXMLFunction(cx, obj, funid, vp); - roots[0] = OBJECT_TO_JSVAL(nameqn); - JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr); + jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (listobj) { - roots[1] = OBJECT_TO_JSVAL(listobj); - tvr.count++; + if (!listobj) + return false; - list = (JSXML *) listobj->getPrivate(); - if (!GetNamedProperty(cx, xml, nameqn, list)) { - listobj = NULL; - } else { - /* - * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the - * given list's [[TargetProperty]] to the property that is being - * appended. This means that any use of the internal [[Get]] - * property returns a list which, when used by e.g. [[Insert]] - * duplicates the last element matched by id. See bug 336921. - */ - list->xml_target = xml; - list->xml_targetprop = nameqn; - *vp = OBJECT_TO_JSVAL(listobj); - } - } + roots[1] = OBJECT_TO_JSVAL(listobj); - JS_POP_TEMP_ROOT(cx, &tvr); - return listobj != NULL; + list = (JSXML *) listobj->getPrivate(); + if (!GetNamedProperty(cx, xml, nameqn, list)) + return false; + + /* + * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the + * given list's [[TargetProperty]] to the property that is being + * appended. This means that any use of the internal [[Get]] + * property returns a list which, when used by e.g. [[Insert]] + * duplicates the last element matched by id. See bug 336921. + */ + list->xml_target = xml; + list->xml_targetprop = nameqn; + *vp = OBJECT_TO_JSVAL(listobj); + return true; } static JSXML * @@ -3910,8 +3907,6 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSBool ok, primitiveAssign; enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; - jsval roots[3]; - JSTempValueRooter tvr; JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; JSObject *targetprop, *nameqn, *attrqn; @@ -3940,11 +3935,13 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ok = js_EnterLocalRootScope(cx); if (!ok) return JS_FALSE; + MUST_FLOW_THROUGH("out"); + jsval roots[3]; roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); roots[ID_ROOT] = id; roots[VAL_ROOT] = *vp; - JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -4531,7 +4528,6 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } out: - JS_POP_TEMP_ROOT(cx, &tvr); js_LeaveLocalRootScope(cx); return ok; @@ -4663,38 +4659,34 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) JSObject *pobj; JSProperty *prop; JSXML *xml; - JSTempValueRooter tvr; - JSBool ok; JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass); if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) - return JS_FALSE; + return false; if (prop) { pobj->dropProperty(cx, prop); } else { xml = (JSXML *) obj->getPrivate(); if (HasSimpleContent(xml)) { + AutoObjectRooter tvr(cx); + /* * Search in String.prototype to set found whenever * GetXMLFunction returns existing function. */ - JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); - ok = js_GetClassPrototype(cx, NULL, JSProto_String, - &tvr.u.object); - JS_ASSERT(tvr.u.object); - if (ok) { - ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop); - if (ok && prop) - pobj->dropProperty(cx, prop); - } - JS_POP_TEMP_ROOT(cx, &tvr); - if (!ok) - return JS_FALSE; + if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + return false; + + JS_ASSERT(tvr.object()); + if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop)) + return false; + if (prop) + pobj->dropProperty(cx, prop); } } *found = (prop != NULL); - return JS_TRUE; + return true; } /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ @@ -4961,18 +4953,22 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - cursor = NULL; + *statep = JSVAL_ZERO; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; + *statep = PRIVATE_TO_JSVAL(cursor); } - *statep = PRIVATE_TO_JSVAL(cursor); if (idp) *idp = INT_TO_JSID(length); break; case JSENUMERATE_NEXT: + if (*statep == JSVAL_ZERO) { + *statep = JSVAL_NULL; + break; + } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { *idp = INT_TO_JSID(index); @@ -4982,9 +4978,11 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) - cx->destroy(cursor); + if (*statep != JSVAL_ZERO) { + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) + cx->destroy(cursor); + } *statep = JSVAL_NULL; break; } @@ -5073,7 +5071,7 @@ js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * As our callers have a bad habit of passing a pointer to an unrooted * local value as vp, we use a proper root here. */ - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr()); *vp = tvr.value(); return ok; @@ -5096,20 +5094,22 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - cursor = NULL; + *statep = JSVAL_ZERO; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; + *statep = PRIVATE_TO_JSVAL(cursor); } - *statep = PRIVATE_TO_JSVAL(cursor); - if (idp) - *idp = INT_TO_JSID(length); - if (vp) - *vp = JSVAL_VOID; + JS_ASSERT(!idp); + JS_ASSERT(!vp); break; case JSENUMERATE_NEXT: + if (*statep == JSVAL_ZERO) { + *statep = JSVAL_NULL; + break; + } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) { @@ -5128,10 +5128,12 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) { - destroy: - cx->destroy(cursor); + if (*statep != JSVAL_ZERO) { + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) { + destroy: + cx->destroy(cursor); + } } *statep = JSVAL_NULL; break; @@ -5424,7 +5426,7 @@ xml_attributes(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; name = OBJECT_TO_JSVAL(qn); - JSAutoTempValueRooter tvr(cx, name); + AutoValueRooter tvr(cx, name); return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); } @@ -5830,66 +5832,6 @@ xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } -typedef struct JSTempRootedNSArray { - JSTempValueRooter tvr; - JSXMLArray array; - jsval value; /* extra root for temporaries */ -} JSTempRootedNSArray; - -static void -trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr) -{ - JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr; - - TraceObjectVector(trc, - (JSObject **) tmp->array.vector, - tmp->array.length); - XMLArrayCursorTrace(trc, tmp->array.cursors); - JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value"); -} - -static void -InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) -{ - XMLArrayInit(cx, &tmp->array, 0); - tmp->value = JSVAL_NULL; - JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr); -} - -static void -FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) -{ - JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array); - JS_POP_TEMP_ROOT(cx, &tmp->tvr); - XMLArrayFinish(cx, &tmp->array); -} - -/* - * Populate a new JS array with elements of JSTempRootedNSArray.array and - * place the result into rval. rval must point to a rooted location. - */ -static JSBool -TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval) -{ - JSObject *arrayobj; - uint32 i, n; - JSObject *ns; - - arrayobj = js_NewArrayObject(cx, 0, NULL); - if (!arrayobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(arrayobj); - for (i = 0, n = tmp->array.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&tmp->array, i, JSObject); - if (!ns) - continue; - tmp->value = OBJECT_TO_JSVAL(ns); - if (!arrayobj->setProperty(cx, INT_TO_JSID(i), &tmp->value)) - return JS_FALSE; - } - return JS_TRUE; -} - static JSBool FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) { @@ -5931,19 +5873,48 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) return JS_TRUE; } +class AutoNamespaceArray : public js::AutoNamespaces { + public: + AutoNamespaceArray(JSContext *cx) + : js::AutoNamespaces(cx) + { + XMLArrayInit(cx, &array, 0); + } + + ~AutoNamespaceArray() { + XMLArrayFinish(context, &array); + } + + /* + * Populate a new JS array with elements of array and place the result into + * rval. rval must point to a rooted location. + */ + bool toJSArray(jsval *rval) { + JSObject *arrayobj = js_NewArrayObject(context, 0, NULL); + if (!arrayobj) + return false; + *rval = OBJECT_TO_JSVAL(arrayobj); + + AutoValueRooter tvr(context); + for (uint32 i = 0, n = array.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&array, i, JSObject); + if (!ns) + continue; + *tvr.addr() = OBJECT_TO_JSVAL(ns); + if (!arrayobj->setProperty(context, INT_TO_JSID(i), tvr.addr())) + return false; + } + return true; + } +}; + static JSBool xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) { - JSTempRootedNSArray namespaces; - JSBool ok; - NON_LIST_XML_METHOD_PROLOG; - InitTempNSArray(cx, &namespaces); - ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && - TempNSArrayToJSArray(cx, &namespaces, vp); - FinishTempNSArray(cx, &namespaces); - return ok; + AutoNamespaceArray namespaces(cx); + return FindInScopeNamespaces(cx, xml, &namespaces.array) && namespaces.toJSArray(vp); } static JSBool @@ -6043,15 +6014,13 @@ static JSBool xml_namespace(JSContext *cx, uintN argc, jsval *vp) { JSString *prefix, *nsprefix; - JSTempRootedNSArray inScopeNSes; - JSBool ok; jsuint i, length; JSObject *ns; NON_LIST_XML_METHOD_PROLOG; if (argc == 0 && !JSXML_HAS_NAME(xml)) { *vp = JSVAL_NULL; - return JS_TRUE; + return true; } if (argc == 0) { @@ -6059,22 +6028,18 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } else { prefix = js_ValueToString(cx, vp[2]); if (!prefix) - return JS_FALSE; + return false; vp[2] = STRING_TO_JSVAL(prefix); /* local root */ } - InitTempNSArray(cx, &inScopeNSes); - MUST_FLOW_THROUGH("out"); - ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array); - if (!ok) - goto out; + AutoNamespaceArray inScopeNSes(cx); + if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array)) + return false; if (!prefix) { ns = GetNamespace(cx, xml->name, &inScopeNSes.array); - if (!ns) { - ok = JS_FALSE; - goto out; - } + if (!ns) + return false; } else { ns = NULL; for (i = 0, length = inScopeNSes.array.length; i < length; i++) { @@ -6089,64 +6054,44 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns); - - out: - FinishTempNSArray(cx, &inScopeNSes); - return JS_TRUE; + return true; } static JSBool xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) { - JSBool ok; - JSTempRootedNSArray ancestors, declared; - JSXML *yml; - uint32 i, n; - JSObject *ns; - NON_LIST_XML_METHOD_PROLOG; if (JSXML_HAS_VALUE(xml)) - return JS_TRUE; + return true; - /* From here, control flow must goto out to finish these arrays. */ - ok = JS_TRUE; - InitTempNSArray(cx, &ancestors); - InitTempNSArray(cx, &declared); - yml = xml; + AutoNamespaceArray ancestors(cx); + AutoNamespaceArray declared(cx); + JSXML *yml = xml; while ((yml = yml->parent) != NULL) { JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); - for (i = 0, n = yml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); - if (ns && - !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - ok = XMLARRAY_APPEND(cx, &ancestors.array, ns); - if (!ok) - goto out; + for (uint32 i = 0, n = yml->xml_namespaces.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); + if (ns && !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + if (!XMLARRAY_APPEND(cx, &ancestors.array, ns)) + return false; } } } - for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { - ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + for (uint32 i = 0, n = xml->xml_namespaces.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); if (!ns) continue; if (!IsDeclared(ns)) continue; if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - ok = XMLARRAY_APPEND(cx, &declared.array, ns); - if (!ok) - goto out; + if (!XMLARRAY_APPEND(cx, &declared.array, ns)) + return false; } } - ok = TempNSArrayToJSArray(cx, &declared, vp); - -out: - /* Finishing must be in reverse order of initialization to follow LIFO. */ - FinishTempNSArray(cx, &declared); - FinishTempNSArray(cx, &ancestors); - return ok; + return declared.toJSArray(vp); } static const char js_attribute_str[] = "attribute"; @@ -7179,9 +7124,9 @@ js_TraceXML(JSTracer *trc, JSXML *xml) if (xml->xml_targetprop) JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop"); } else { - TraceObjectVector(trc, - (JSObject **) xml->xml_namespaces.vector, - xml->xml_namespaces.length); + js::TraceObjectVector(trc, + (JSObject **) xml->xml_namespaces.vector, + xml->xml_namespaces.length); XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); if (IS_GC_MARKING_TRACER(trc)) XMLArrayTrim(&xml->xml_namespaces); @@ -7214,17 +7159,12 @@ js_FinalizeXML(JSContext *cx, JSXML *xml) JSObject * js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) { - JSXML *xml; - JSObject *obj; - JSTempValueRooter tvr; - - xml = js_NewXML(cx, xml_class); + JSXML *xml = js_NewXML(cx, xml_class); if (!xml) return NULL; - JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr); - obj = js_GetXMLObject(cx, xml); - JS_POP_TEMP_ROOT(cx, &tvr); - return obj; + + AutoXMLRooter root(cx, xml); + return js_GetXMLObject(cx, xml); } static JSObject * @@ -7741,48 +7681,35 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) static JSBool GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - JSObject *target; - JSXML *xml; - JSTempValueRooter tvr; - JSBool ok; - JS_ASSERT(OBJECT_IS_XML(cx, obj)); - MUST_FLOW_THROUGH("out"); - JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); - /* * See comments before xml_lookupProperty about the need for the proto * chain lookup. */ - target = obj; + JSObject *target = obj; + AutoObjectRooter tvr(cx); for (;;) { - ok = js_GetProperty(cx, target, id, vp); - if (!ok) - goto out; - if (VALUE_IS_FUNCTION(cx, *vp)) { - ok = JS_TRUE; - goto out; - } + if (!js_GetProperty(cx, target, id, vp)) + return false; + if (VALUE_IS_FUNCTION(cx, *vp)) + return true; target = target->getProto(); if (target == NULL) break; - tvr.u.object = target; + tvr.setObject(target); } - xml = (JSXML *) obj->getPrivate(); - if (HasSimpleContent(xml)) { - /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ - ok = js_GetClassPrototype(cx, NULL, JSProto_String, &tvr.u.object); - if (!ok) - goto out; - JS_ASSERT(tvr.u.object); - ok = tvr.u.object->getProperty(cx, id, vp); - } + JSXML *xml = (JSXML *) obj->getPrivate(); + if (!HasSimpleContent(xml)) + return true; - out: - JS_POP_TEMP_ROOT(cx, &tvr); - return ok; + /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ + if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + return false; + + JS_ASSERT(tvr.object()); + return tvr.object()->getProperty(cx, id, vp); } static JSXML * From ecc99e6047910970f92ee39959649f6738d766e9 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 29 Mar 2010 14:57:43 -0500 Subject: [PATCH 165/213] Fix busted tests to use reportCompare. no_r=orange. --HG-- extra : rebase_source : 5d3055655d0c5326d08966c956f2e2d6fcf74e65 --- js/src/tests/js1_8_5/regress/jstests.list | 1 + js/src/tests/js1_8_5/regress/regress-500528.js | 2 +- js/src/tests/js1_8_5/regress/regress-541255-0.js | 2 +- js/src/tests/js1_8_5/regress/regress-541255-1.js | 2 +- js/src/tests/js1_8_5/regress/regress-541255-2.js | 2 +- js/src/tests/js1_8_5/regress/regress-541255-3.js | 2 +- js/src/tests/js1_8_5/regress/regress-541255-4.js | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 70fdfb08c1b6..23101dbe24cc 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -1,4 +1,5 @@ url-prefix ../../jsreftest.html?test=js1_8_5/regress/ +script regress-500528.js fails script regress-533876.js script regress-541255-0.js script regress-541255-1.js diff --git a/js/src/tests/js1_8_5/regress/regress-500528.js b/js/src/tests/js1_8_5/regress/regress-500528.js index a3e1c5b6b30a..bf2908e201a5 100644 --- a/js/src/tests/js1_8_5/regress/regress-500528.js +++ b/js/src/tests/js1_8_5/regress/regress-500528.js @@ -19,4 +19,4 @@ for each (var obj in [c1, c2]) s += obj.x; assertEq(s, 'ab'); -print(" PASSED! Property cache soundness: objects with the same shape but different prototypes."); +reportCompare(0, 0, "Property cache soundness: objects with the same shape but different prototypes."); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-0.js b/js/src/tests/js1_8_5/regress/regress-541255-0.js index 7cee605d6275..6165b6136aa4 100644 --- a/js/src/tests/js1_8_5/regress/regress-541255-0.js +++ b/js/src/tests/js1_8_5/regress/regress-541255-0.js @@ -11,4 +11,4 @@ for (x in [0])]\ ") })(); -print(" PASSED!"); +reportCompare(0, 0, ""); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-1.js b/js/src/tests/js1_8_5/regress/regress-541255-1.js index 1f123abeab06..e7255c67c8bf 100644 --- a/js/src/tests/js1_8_5/regress/regress-541255-1.js +++ b/js/src/tests/js1_8_5/regress/regress-541255-1.js @@ -20,4 +20,4 @@ function f(e) { } t = 1; f(); -print(" PASSED!"); +reportCompare(0, 0, ""); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-2.js b/js/src/tests/js1_8_5/regress/regress-541255-2.js index 01e85a2e598f..dfb65c6d6e96 100644 --- a/js/src/tests/js1_8_5/regress/regress-541255-2.js +++ b/js/src/tests/js1_8_5/regress/regress-541255-2.js @@ -8,4 +8,4 @@ function f(e) { eval("[function () { w.r = 0 }() for (w in [0])]") } f(0); -print(" PASSED!"); +reportCompare(0, 0, ""); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-3.js b/js/src/tests/js1_8_5/regress/regress-541255-3.js index 0c3acbc22dbc..ec1ab7916367 100644 --- a/js/src/tests/js1_8_5/regress/regress-541255-3.js +++ b/js/src/tests/js1_8_5/regress/regress-541255-3.js @@ -10,4 +10,4 @@ function f(y) { var x = {}; f(x); assertEq(x.p, 7); -print(" PASSED!"); +reportCompare(0, 0, ""); diff --git a/js/src/tests/js1_8_5/regress/regress-541255-4.js b/js/src/tests/js1_8_5/regress/regress-541255-4.js index 1617df879ac4..6113a7f275af 100644 --- a/js/src/tests/js1_8_5/regress/regress-541255-4.js +++ b/js/src/tests/js1_8_5/regress/regress-541255-4.js @@ -8,4 +8,4 @@ function f(e) { eval("[function () { w.r = 0 }() for (w in [0,1,2,3,4,5,6,7,8,9])]") } f(0); -print(" PASSED!"); +reportCompare(0, 0, ""); From 43048a9fec4b21959721697f2ea68eebea82ba88 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 12:03:24 -0700 Subject: [PATCH 166/213] Readd substantive jsgc.cpp changes for bug 548702. --HG-- extra : rebase_source : dd4cc7651df4280d1166bf99907f8469e81b006d --- js/src/jsgc.cpp | 51 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 0446ff7a22fa..4ab55fcbfd66 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2270,20 +2270,6 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, return JS_DHASH_NEXT; } -#define TRACE_JSVALS(trc, len, vec, name) \ - JS_BEGIN_MACRO \ - jsval _v, *_vp, *_end; \ - \ - for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \ - _v = *_vp; \ - if (JSVAL_IS_TRACEABLE(_v)) { \ - JS_SET_TRACING_INDEX(trc, name, _vp - (vec)); \ - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(_v), \ - JSVAL_TRACE_KIND(_v)); \ - } \ - } \ - JS_END_MACRO - namespace js { void @@ -2323,7 +2309,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) } else { nslots = fp->script->nfixed; } - TRACE_JSVALS(trc, nslots, fp->slots, "slot"); + TraceValues(trc, nslots, fp->slots, "slot"); } } else { JS_ASSERT(!fp->slots); @@ -2348,7 +2334,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) if (fp->fun->flags & JSFRAME_ROOTED_ARGV) skip = 2 + fp->argc; } - TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); + TraceValues(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); } JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); @@ -2452,7 +2438,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) for (sh = acx->stackHeaders; sh; sh = sh->down) { METER(trc->context->runtime->gcStats.stackseg++); METER(trc->context->runtime->gcStats.segslots += sh->nslots); - TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); + TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); } for (JSTempValueRooter *tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { @@ -2481,7 +2467,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) break; default: JS_ASSERT(tvr->count >= 0); - TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array"); + TraceValues(trc, tvr->count, tvr->u.array, "tvr->u.array"); } } @@ -2497,7 +2483,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) InterpState* state = acx->interpState; while (state) { if (state->nativeVp) - TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); + TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); state = state->prev; } #endif @@ -3449,33 +3435,30 @@ out: * interlock mechanism here. */ if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) { - JSWeakRoots savedWeakRoots; - JSTempValueRooter tvr; + if (!(gckind & GC_KEEP_ATOMS)) { + (void) callback(cx, JSGC_END); - if (gckind & GC_KEEP_ATOMS) { + /* + * On shutdown iterate until JSGC_END callback stops creating + * garbage. + */ + if (gckind == GC_LAST_CONTEXT && rt->gcPoke) + goto restart_at_beginning; + } else { /* * We allow JSGC_END implementation to force a full GC or allocate * new GC things. Thus we must protect the weak roots from garbage * collection and overwrites. */ - savedWeakRoots = cx->weakRoots; - JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr); + AutoSaveWeakRoots save(cx); + JS_KEEP_ATOMS(rt); JS_UNLOCK_GC(rt); - } - (void) callback(cx, JSGC_END); + (void) callback(cx, JSGC_END); - if (gckind & GC_KEEP_ATOMS) { JS_LOCK_GC(rt); JS_UNKEEP_ATOMS(rt); - JS_POP_TEMP_ROOT(cx, &tvr); - } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) { - /* - * On shutdown iterate until JSGC_END callback stops creating - * garbage. - */ - goto restart_at_beginning; } } TIMESTAMP(gcTimer.end); From 893b197054ac2cbe9c87cb8dce9c8da66a2aaa6c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 12:03:43 -0700 Subject: [PATCH 167/213] Readd jsparse.cpp and jsparse.h changes for bug 548702. --- js/src/jsparse.cpp | 20 +++++++------------- js/src/jsparse.h | 10 ++++++---- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index cda95a2dac33..806f1fe7e79c 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -172,7 +172,6 @@ JSCompiler::init(const jschar *base, size_t length, /* Root atoms and objects allocated for the parsed tree. */ JS_KEEP_ATOMS(cx->runtime); - JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot); return true; } @@ -182,8 +181,6 @@ JSCompiler::~JSCompiler() if (principals) JSPRINCIPALS_DROP(cx, principals); - JS_ASSERT(tempRoot.u.compiler == this); - JS_POP_TEMP_ROOT(cx, &tempRoot); JS_UNKEEP_ATOMS(cx->runtime); tokenStream.close(); JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); @@ -288,10 +285,7 @@ JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const void JSCompiler::trace(JSTracer *trc) { - JSObjectBox *objbox; - - JS_ASSERT(tempRoot.u.compiler == this); - objbox = traceListHead; + JSObjectBox *objbox = traceListHead; while (objbox) { JS_CALL_OBJECT_TRACER(trc, objbox->object, "parser.object"); objbox = objbox->traceLink; @@ -8715,7 +8709,6 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; - JSTempValueRooter tvr; JS_ASSERT(pn->pn_arity == PN_LIST); tt = PN_TYPE(pn); @@ -8806,11 +8799,12 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) } if (accum) { - JS_PUSH_TEMP_ROOT_STRING(cx, accum, &tvr); - str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) - ? js_AddAttributePart(cx, i & 1, accum, str) - : js_ConcatStrings(cx, accum, str); - JS_POP_TEMP_ROOT(cx, &tvr); + { + AutoValueRooter tvr(cx, accum); + str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) + ? js_AddAttributePart(cx, i & 1, accum, str) + : js_ConcatStrings(cx, accum, str); + } if (!str) return JS_FALSE; #ifdef DEBUG_brendanXXX diff --git a/js/src/jsparse.h b/js/src/jsparse.h index c9a6a12ac460..fa9b12740915 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -912,8 +912,8 @@ class JSTreeContext; typedef struct BindData BindData; -struct JSCompiler { - JSContext * const context; +struct JSCompiler : private js::AutoGCRooter { + JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; js::TokenStream tokenStream; @@ -925,10 +925,9 @@ struct JSCompiler { uint32 functionCount; /* number of functions in current unit */ JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ JSTreeContext *tc; /* innermost tree context (stack-allocated) */ - JSTempValueRooter tempRoot; /* root to trace traceListHead */ JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) - : context(cx), + : js::AutoGCRooter(cx, COMPILER), context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), callerVarObj(cfp ? cfp->varobj(cx->containingCallStack(cfp)) : NULL), nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL) @@ -940,6 +939,9 @@ struct JSCompiler { ~JSCompiler(); + friend void js::AutoGCRooter::trace(JSTracer *trc); + friend class JSTreeContext; + /* * Initialize a compiler. Parameters are passed on to init tokenStream. * The compiler owns the arena pool "tops-of-stack" space above the current From ff258a8cb065f276daf0e7d51d3dbb047c13a228 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 16:49:45 -0700 Subject: [PATCH 168/213] Oops, forgot a necessary change to go with the jsparse changes in the last push. --- js/src/jscntxtinlines.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 8532e081ff9a..ca28d7682f2f 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -82,11 +82,7 @@ AutoGCRooter::trace(JSTracer *trc) return; case COMPILER: -#if 0 /* JSCompiler is still old-style */ static_cast(this)->trace(trc); -#else - JS_ASSERT(0); -#endif return; case SCRIPT: From 8577d1493c9899dd4770f305928f04463b65a26d Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 12:24:03 -0700 Subject: [PATCH 169/213] Readd jsregexp.{cpp,h} (and to users of the regex-statics save/restore methods) and nsJSEnvironment.{cpp,h} changes for bug 548702. --- dom/base/nsJSEnvironment.cpp | 12 ++++-------- dom/base/nsJSEnvironment.h | 9 ++++++--- js/src/jsregexp.cpp | 11 +++++------ js/src/jsregexp.h | 6 ++++-- js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index d741e3f05280..e48c772fc0f9 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2108,15 +2108,11 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler return NS_OK; } - jsval targetVal = JSVAL_VOID; - JSAutoTempValueRooter tvr(mContext, 1, &targetVal); - JSObject* target = nsnull; nsresult rv = JSObjectFromInterface(aTarget, aScope, &target); NS_ENSURE_SUCCESS(rv, rv); - targetVal = OBJECT_TO_JSVAL(target); - + js::AutoObjectRooter targetVal(mContext, target); jsval rval = JSVAL_VOID; // This one's a lot easier than EvaluateString because we don't have to @@ -2140,7 +2136,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval *argv = nsnull; js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget @@ -2654,7 +2650,7 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg JSAutoRequest ar(mContext); js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, @@ -2689,7 +2685,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter) + js::LazilyConstructed &aRooter) { nsresult rv = NS_OK; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index 785d53c109e3..cec89748f9bb 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -49,8 +49,11 @@ class nsIXPConnectJSObjectHolder; class nsAutoPoolRelease; -class JSAutoTempValueRooter; -namespace js { template class LazilyConstructed; } +namespace js { +class AutoObjectRooter; +class AutoArrayRooter; +template class LazilyConstructed; +} class nsJSContext : public nsIScriptContext, public nsIXPCScriptNotify @@ -215,7 +218,7 @@ protected: PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter); + js::LazilyConstructed &aRooter); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index e5d902d0b1e3..fcbcb4f1dfa5 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5226,11 +5226,11 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr) + AutoValueRooter *tvr) { *statics = cx->regExpStatics; - JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr); - + if (statics->input) + tvr->setString(statics->input); /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). @@ -5241,12 +5241,11 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr) + AutoValueRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ JS_ClearRegExpStatics(cx); cx->regExpStatics = *statics; - JS_POP_TEMP_ROOT(cx, tvr); } void @@ -5839,7 +5838,7 @@ js_NewRegExpObject(JSContext *cx, TokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - JSAutoTempValueRooter tvr(cx, str); + AutoValueRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 63680651e864..73cfee817450 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -65,13 +65,15 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; +namespace js { class AutoValueRooter; } + extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr); + js::AutoValueRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr); + js::AutoValueRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index a0ec10566de1..074cb8e4594e 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -478,7 +478,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NS_STACK_CLASS class SafeCallGuard { public: SafeCallGuard(JSContext *cx, nsIPrincipal *principal) - : cx(cx) { + : cx(cx), tvr(cx) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (ssm) { // Note: We pass null as the target frame pointer because we know that @@ -517,7 +517,7 @@ public: private: JSContext *cx; JSRegExpStatics statics; - JSTempValueRooter tvr; + js::AutoValueRooter tvr; uint32 options; JSStackFrame *fp; }; @@ -957,7 +957,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, From c2dcd0b0c73e33c9fc656a7a435fc9f453547c0c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 19:46:37 -0700 Subject: [PATCH 170/213] Backed out changeset 79fd90e2dd87, n810s all orange -- yay! Something fruitful to investigate! --- dom/base/nsJSEnvironment.cpp | 12 ++++++++---- dom/base/nsJSEnvironment.h | 9 +++------ js/src/jsregexp.cpp | 11 ++++++----- js/src/jsregexp.h | 6 ++---- js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index e48c772fc0f9..d741e3f05280 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2108,11 +2108,15 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler return NS_OK; } + jsval targetVal = JSVAL_VOID; + JSAutoTempValueRooter tvr(mContext, 1, &targetVal); + JSObject* target = nsnull; nsresult rv = JSObjectFromInterface(aTarget, aScope, &target); NS_ENSURE_SUCCESS(rv, rv); - js::AutoObjectRooter targetVal(mContext, target); + targetVal = OBJECT_TO_JSVAL(target); + jsval rval = JSVAL_VOID; // This one's a lot easier than EvaluateString because we don't have to @@ -2136,7 +2140,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval *argv = nsnull; js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget @@ -2650,7 +2654,7 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg JSAutoRequest ar(mContext); js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, @@ -2685,7 +2689,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter) + js::LazilyConstructed &aRooter) { nsresult rv = NS_OK; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index cec89748f9bb..785d53c109e3 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -49,11 +49,8 @@ class nsIXPConnectJSObjectHolder; class nsAutoPoolRelease; -namespace js { -class AutoObjectRooter; -class AutoArrayRooter; -template class LazilyConstructed; -} +class JSAutoTempValueRooter; +namespace js { template class LazilyConstructed; } class nsJSContext : public nsIScriptContext, public nsIXPCScriptNotify @@ -218,7 +215,7 @@ protected: PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter); + js::LazilyConstructed &aRooter); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index fcbcb4f1dfa5..e5d902d0b1e3 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5226,11 +5226,11 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + JSTempValueRooter *tvr) { *statics = cx->regExpStatics; - if (statics->input) - tvr->setString(statics->input); + JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr); + /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). @@ -5241,11 +5241,12 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + JSTempValueRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ JS_ClearRegExpStatics(cx); cx->regExpStatics = *statics; + JS_POP_TEMP_ROOT(cx, tvr); } void @@ -5838,7 +5839,7 @@ js_NewRegExpObject(JSContext *cx, TokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - AutoValueRooter tvr(cx, str); + JSAutoTempValueRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 73cfee817450..63680651e864 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -65,15 +65,13 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; -namespace js { class AutoValueRooter; } - extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + JSTempValueRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + JSTempValueRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 074cb8e4594e..a0ec10566de1 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -478,7 +478,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NS_STACK_CLASS class SafeCallGuard { public: SafeCallGuard(JSContext *cx, nsIPrincipal *principal) - : cx(cx), tvr(cx) { + : cx(cx) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (ssm) { // Note: We pass null as the target frame pointer because we know that @@ -517,7 +517,7 @@ public: private: JSContext *cx; JSRegExpStatics statics; - js::AutoValueRooter tvr; + JSTempValueRooter tvr; uint32 options; JSStackFrame *fp; }; @@ -957,7 +957,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, From 36182c5d481c12dbbfcf500bb837ac30901c4579 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 19:47:40 -0700 Subject: [PATCH 171/213] Readd ctypes, xpconnect, plugin, xpinstall, canvas, and typed array changes from bug 548702. --- content/canvas/src/CustomQS_WebGL.h | 30 ++++++------ js/ctypes/Function.cpp | 2 +- js/src/jstypedarray.cpp | 10 ++-- .../xpconnect/src/XPCChromeObjectWrapper.cpp | 15 +++--- .../xpconnect/src/XPCCrossOriginWrapper.cpp | 6 +-- js/src/xpconnect/src/XPCNativeWrapper.cpp | 2 +- js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp | 8 ++-- js/src/xpconnect/src/XPCWrapper.cpp | 8 ++-- js/src/xpconnect/src/qsgen.py | 2 +- js/src/xpconnect/src/xpcconvert.cpp | 10 ++-- js/src/xpconnect/src/xpcquickstubs.cpp | 4 +- js/src/xpconnect/src/xpcquickstubs.h | 2 +- .../xpconnect/src/xpcwrappednativejsops.cpp | 7 ++- js/src/xpconnect/tests/TestXPC.cpp | 2 +- modules/plugin/base/src/nsJSNPRuntime.cpp | 48 +++++++++---------- modules/plugin/base/src/nsNPAPIPlugin.cpp | 2 +- xpinstall/src/nsXPITriggerInfo.cpp | 2 +- 17 files changed, 79 insertions(+), 81 deletions(-) diff --git a/content/canvas/src/CustomQS_WebGL.h b/content/canvas/src/CustomQS_WebGL.h index 2d479060e59d..abde159d3ffa 100644 --- a/content/canvas/src/CustomQS_WebGL.h +++ b/content/canvas/src/CustomQS_WebGL.h @@ -68,7 +68,7 @@ nsICanvasRenderingContextWebGL_BufferData(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -134,7 +134,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -204,7 +204,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -306,7 +306,7 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -407,7 +407,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -427,7 +427,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -477,7 +477,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -497,7 +497,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -547,7 +547,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -571,7 +571,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -618,7 +618,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - JSAutoTempValueRooter tvr(cx); + js::AutoValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -638,7 +638,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -780,7 +780,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -835,7 +835,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -890,7 +890,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj return JSVAL_VOID; } - JSAutoTempValueRooter obj_tvr(cx); + js::AutoValueRooter obj_tvr(cx); js::TypedArray *wa = 0; diff --git a/js/ctypes/Function.cpp b/js/ctypes/Function.cpp index 601d70593ecb..d73e38e442c7 100644 --- a/js/ctypes/Function.cpp +++ b/js/ctypes/Function.cpp @@ -293,7 +293,7 @@ Function::Create(JSContext* aContext, return NULL; JSObject* fnObj = JS_GetFunctionObject(fn); - JSAutoTempValueRooter fnRoot(aContext, fnObj); + js::AutoObjectRooter fnRoot(aContext, fnObj); // stash a pointer to self, which Function::Call will need at call time if (!JS_SetReservedSlot(aContext, fnObj, SLOT_FUNCTION, PRIVATE_TO_JSVAL(self.get()))) diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index de9c4f60ac0d..7aec65f1461d 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1382,10 +1382,10 @@ js_IsTypedArray(JSObject *obj) JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr()); - JSAutoTempValueRooter rval(cx); + AutoValueRooter rval(cx); if (!ArrayBuffer::class_constructor(cx, cx->globalObject, 1, tvr.addr(), rval.addr())) @@ -1437,7 +1437,7 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - JSAutoTempValueRooter tvr(cx, 2, vals); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); if (!js_NewNumberInRootedValue(cx, jsdouble(nelements), &vals[0])) return NULL; @@ -1454,7 +1454,7 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - JSAutoTempValueRooter tvr(cx, 2, vals); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); vals[0] = OBJECT_TO_JSVAL(arrayArg); @@ -1474,7 +1474,7 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_ASSERT(length < 0 || byteoffset >= 0); jsval vals[4]; - JSAutoTempValueRooter tvr(cx, 4, vals); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); int argc = 1; vals[0] = OBJECT_TO_JSVAL(bufArg); diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp index 70724cadeb6e..918dd1de4145 100644 --- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For JSAutoTempValueRooter. +#include "jscntxt.h" // For js::AutoValueRooter. #include "jsobj.h" #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -283,17 +283,16 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) *vp = OBJECT_TO_JSVAL(wrapperObj); - jsval exposedProps = JSVAL_VOID; - JSAutoTempValueRooter tvr(cx, 1, &exposedProps); + js::AutoValueRooter exposedProps(cx, JSVAL_VOID); - if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) { + if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) || - !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, - JSVAL_ZERO) || - !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) { + !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || + !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, + exposedProps.value())) { return JS_FALSE; } @@ -778,7 +777,7 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoObjectRooter tvr(cx, wrapperIter); // Initialize our COW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 9a9631482783..3e395f9ccbec 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For JSAutoTempValueRooter. +#include "jscntxt.h" // For js::AutoValueRooter. #include "XPCWrapper.h" #include "nsIDOMWindow.h" #include "nsIDOMWindowCollection.h" @@ -830,7 +830,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj) return nsnull; } - JSAutoTempValueRooter tvr(cx, uxpco); + js::AutoValueRooter tvr(cx, uxpco); jsval wrappedObj, parentScope; if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) || @@ -1206,7 +1206,7 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoObjectRooter tvr(cx, wrapperIter); // Initialize our XOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 7bbf51499e32..97b0037a5290 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1144,7 +1144,7 @@ XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoObjectRooter tvr(cx, wrapperIter); // Initialize our native wrapper. XPCWrappedNative *wn = static_cast(JS_GetPrivate(cx, obj)); diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index 406adb39c320..b4c62f09aeac 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For JSAutoTempValueRooter. +#include "jscntxt.h" // For js::AutoValueRooter. #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -137,7 +137,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) } *vp = OBJECT_TO_JSVAL(wrapperObj); - JSAutoTempValueRooter tvr(cx, *vp); + js::AutoValueRooter tvr(cx, *vp); if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { @@ -437,7 +437,7 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - JSAutoTempValueRooter tvr(cx, 1, vp); + js::AutoArrayRooter tvr(cx, 1, vp); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { @@ -649,7 +649,7 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our SOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index b6fc00c21d7d..351b42827aac 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -153,8 +153,8 @@ IteratorNext(JSContext *cx, uintN argc, jsval *vp) } jsval vec[2] = { STRING_TO_JSVAL(str), v }; - JSAutoTempValueRooter tvr(cx, 2, vec); - JSObject *array = JS_NewArrayObject(cx, 2, vec); + js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); + JSObject *array = JS_NewArrayObject(cx, JS_ARRAY_LENGTH(vec), vec); if (!array) { return JS_FALSE; } @@ -192,7 +192,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); + js::AutoObjectRooter tvr(cx, iterObj); // Do this sooner rather than later to avoid complications in // IteratorFinalize. @@ -213,7 +213,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, // call enumerate, and then re-set the prototype. As we do this, we have // to protec the temporary wrapper from garbage collection. - JSAutoTempValueRooter tvr(cx, tempWrapper); + js::AutoValueRooter tvr(cx, tempWrapper); if (!JS_SetPrototype(cx, iterObj, wrapperObj) || !XPCWrapper::Enumerate(cx, iterObj, wrapperObj) || !JS_SetPrototype(cx, iterObj, tempWrapper)) { diff --git a/js/src/xpconnect/src/qsgen.py b/js/src/xpconnect/src/qsgen.py index 7d5f651195da..e00b191394f2 100644 --- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -835,7 +835,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): if isGetter: pthisval = 'vp' elif isSetter: - f.write(" JSAutoTempValueRooter tvr(cx);\n") + f.write(" js::AutoValueRooter tvr(cx);\n") pthisval = 'tvr.addr()' else: pthisval = '&vp[1]' # as above, ok to overwrite vp[1] diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index 03294e4e8a17..f02832feffe7 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1582,23 +1582,23 @@ XPCConvert::ConstructException(nsresult rv, const char* message, /********************************/ -class AutoExceptionRestorer : public JSAutoTempValueRooter +class AutoExceptionRestorer { public: AutoExceptionRestorer(JSContext *cx, jsval v) - : JSAutoTempValueRooter(cx, v), - mVal(v) + : mContext(cx), tvr(cx, v) { JS_ClearPendingException(mContext); } ~AutoExceptionRestorer() { - JS_SetPendingException(mContext, mVal); + JS_SetPendingException(mContext, tvr.value()); } private: - jsval mVal; + JSContext * const mContext; + js::AutoValueRooter tvr; }; // static diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index cc26a2220217..511365ce00d9 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -173,7 +173,7 @@ GeneratePropertyOp(JSContext *cx, JSObject *obj, jsval idval, uintN argc, JSObject *funobj = JS_GetFunctionObject(fun); - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); + js::AutoObjectRooter tvr(cx, funobj); // Unfortunately, we cannot guarantee that JSPropertyOp is aligned. Use a // second object to work around this. @@ -198,7 +198,7 @@ ReifyPropertyOps(JSContext *cx, JSObject *obj, jsval idval, jsid interned_id, { // Generate both getter and setter and stash them in the prototype. jsval roots[2] = { JSVAL_NULL, JSVAL_NULL }; - JSAutoTempValueRooter tvr(cx, 2, roots); + js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); uintN attrs = JSPROP_SHARED; JSObject *getterobj; diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index de2446cd243b..0943aab68a11 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -321,7 +321,7 @@ struct xpc_qsArgValArray memset(array, 0, N * sizeof(jsval)); } - JSAutoTempValueRooter tvr; + js::AutoArrayRooter tvr; jsval array[N]; }; diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index fb7e1192a64f..75964e97386c 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -1517,8 +1517,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) JSStackFrame *fp; nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp); - jsval retval = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter atvr(cx, 1, &retval); + js::AutoValueRooter retval(cx, obj); if(principal && fp) { @@ -1535,7 +1534,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags, - &retval); + retval.addr()); if(NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); @@ -1543,7 +1542,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } } - return JSVAL_TO_OBJECT(retval); + return JSVAL_TO_OBJECT(retval.value()); } JSObjectOps * diff --git a/js/src/xpconnect/tests/TestXPC.cpp b/js/src/xpconnect/tests/TestXPC.cpp index f4955f457715..7d6bfe5b5f65 100644 --- a/js/src/xpconnect/tests/TestXPC.cpp +++ b/js/src/xpconnect/tests/TestXPC.cpp @@ -562,7 +562,7 @@ TestArgFormatter(JSContext* jscontext, JSObject* glob, nsIXPConnect* xpc) // Prepare an array of arguments for JS_ConvertArguments jsval argv[5]; - JSAutoTempValueRooter tvr(jscontext, 5, argv); + js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv); if (!PushArguments(jscontext, 5, argv, "s %ip %iv %is s", diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index 8b61cd6c2ae8..dfb92957dca2 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -673,35 +673,35 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args, } } - JSTempValueRooter tvr; - JS_PUSH_TEMP_ROOT(cx, 0, jsargs, &tvr); - - // Convert args - for (PRUint32 i = 0; i < argCount; ++i) { - jsargs[i] = NPVariantToJSVal(npp, cx, args + i); - ++tvr.count; - } - jsval v; JSBool ok; - if (ctorCall) { - JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); - JSObject *newObj = - ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), - nsnull, global, argCount, jsargs); + { + js::AutoArrayRooter tvr(cx, 0, jsargs); - if (newObj) { - v = OBJECT_TO_JSVAL(newObj); - ok = JS_TRUE; - } else { - ok = JS_FALSE; + // Convert args + for (PRUint32 i = 0; i < argCount; ++i) { + jsargs[i] = NPVariantToJSVal(npp, cx, args + i); + tvr.changeLength(i + 1); } - } else { - ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); - } - JS_POP_TEMP_ROOT(cx, &tvr); + if (ctorCall) { + JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); + JSObject *newObj = + ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), + nsnull, global, argCount, jsargs); + + if (newObj) { + v = OBJECT_TO_JSVAL(newObj); + ok = JS_TRUE; + } else { + ok = JS_FALSE; + } + } else { + ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); + } + + } if (jsargs != jsargs_buf) PR_Free(jsargs); @@ -837,7 +837,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, AutoJSExceptionReporter reporter(cx); jsval v = NPVariantToJSVal(npp, cx, value); - JSAutoTempValueRooter tvr(cx, v); + js::AutoValueRooter tvr(cx, v); if (JSVAL_IS_STRING(id)) { JSString *str = JSVAL_TO_STRING(id); diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index f59f5d189b3e..ab592ed939c3 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -1698,7 +1698,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) // Root obj and the rval (below). jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL }; - JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); + js::AutoArrayRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); jsval *rval = &vec[1]; if (result) { diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index 0ef48ccf9d47..0ec4b2284696 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -247,7 +247,7 @@ XPITriggerEvent::Run() // Build arguments into rooted jsval array jsval args[2] = { JSVAL_NULL, JSVAL_NULL }; - JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(args), args); + js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args); // args[0] is the URL JSString *str = JS_NewUCStringCopyZ(cx, reinterpret_cast(URL.get())); From 1060be6986bc8612391150c2c7e43fa58d393634 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 19:47:40 -0700 Subject: [PATCH 172/213] Readd jsdbgapi.cpp, json.cpp, jsopcode.cpp, and jstracer.cpp changes from bug 548702. --- js/src/jsdbgapi.cpp | 2 +- js/src/jsinterp.cpp | 4 +- js/src/json.cpp | 117 +++++++++++++++++++------------------------- js/src/json.h | 2 +- js/src/jsopcode.cpp | 2 +- js/src/jstracer.cpp | 23 +++++---- 6 files changed, 67 insertions(+), 83 deletions(-) diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 083fd553bedf..7d16d564307a 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1466,7 +1466,7 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, pd->id = ID_TO_VALUE(sprop->id); JSBool wasThrowing = cx->throwing; - JSAutoTempValueRooter lastException(cx, cx->exception); + AutoValueRooter lastException(cx, cx->exception); cx->throwing = JS_FALSE; if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index d1a30d75e9fa..112f748d48c0 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -314,7 +314,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp); if (!innermostNewChild) return NULL; - JSAutoTempValueRooter tvr(cx, innermostNewChild); + AutoValueRooter tvr(cx, innermostNewChild); /* * Clone our way towards outer scopes until we reach the innermost @@ -519,7 +519,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[1]); jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - JSAutoTempValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx, JSVAL_NULL); if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) return false; if (JSVAL_IS_PRIMITIVE(tvr.value())) { diff --git a/js/src/json.cpp b/js/src/json.cpp index de0bfbfe3380..fee0b557ffd1 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -108,10 +108,9 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) { JSString *s = NULL; jsval *argv = vp + 2; - jsval reviver = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &reviver); + AutoValueRooter reviver(cx, JSVAL_NULL); - if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver)) + if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr())) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); @@ -121,7 +120,7 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); - ok &= js_FinishJSONParse(cx, jp, reviver); + ok &= js_FinishJSONParse(cx, jp, reviver.value()); } return ok; @@ -131,18 +130,16 @@ JSBool js_json_stringify(JSContext *cx, uintN argc, jsval *vp) { jsval *argv = vp + 2; - JSObject *replacer = NULL; - jsval space = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, replacer); - JSAutoTempValueRooter tvr2(cx, 1, &space); + AutoValueRooter space(cx, JSVAL_NULL); + AutoObjectRooter replacer(cx); // Must throw an Error if there isn't a first arg - if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, &replacer, &space)) + if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr())) return JS_FALSE; JSCharBuffer cb(cx); - if (!js_Stringify(cx, vp, replacer, space, cb)) + if (!js_Stringify(cx, vp, replacer.object(), space.value(), cb)) return JS_FALSE; // XXX This can never happen to nsJSON.cpp, but the JSON object @@ -260,7 +257,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) return JS_FALSE; jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; - JSAutoTempValueRooter tvr(cx, 3, vec); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); jsval& key = vec[0]; jsval& outputValue = vec[1]; @@ -309,7 +306,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) if (!ks) goto error_break; } - JSAutoTempValueRooter keyStringRoot(cx, ks); + AutoValueRooter keyStringRoot(cx, ks); // Don't include prototype properties, since this operation is // supposed to be implemented as if by ES3.1 Object.keys() @@ -395,21 +392,20 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; - jsval outputValue = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &outputValue); + AutoValueRooter outputValue(cx, JSVAL_NULL); jsid id; jsuint i; for (i = 0; i < length; i++) { id = INT_TO_JSID(i); - if (!obj->getProperty(cx, id, &outputValue)) + if (!obj->getProperty(cx, id, outputValue.addr())) return JS_FALSE; - if (!Str(cx, id, obj, scx, &outputValue)) + if (!Str(cx, id, obj, scx, outputValue.addr())) return JS_FALSE; - if (outputValue == JSVAL_VOID) { + if (outputValue.value() == JSVAL_VOID) { if (!js_AppendLiteral(scx->cb, "null")) return JS_FALSE; } @@ -573,63 +569,54 @@ static JSBool IsNumChar(jschar c) static JSBool HandleData(JSContext *cx, JSONParser *jp, JSONDataType type); static JSBool PopState(JSContext *cx, JSONParser *jp); -static JSBool -DestroyIdArrayOnError(JSContext *cx, JSIdArray *ida) { - JS_DestroyIdArray(cx, ida); - return JS_FALSE; -} - -static JSBool +static bool Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) { - JS_CHECK_RECURSION(cx, return JS_FALSE); + JS_CHECK_RECURSION(cx, return false); if (!holder->getProperty(cx, id, vp)) - return JS_FALSE; + return false; JSObject *obj; if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) { - jsval propValue = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &propValue); + AutoValueRooter propValue(cx, JSVAL_NULL); if(obj->isArray()) { jsuint length = 0; if (!js_GetLengthProperty(cx, obj, &length)) - return JS_FALSE; + return false; for (jsuint i = 0; i < length; i++) { jsid index; if (!js_IndexToId(cx, i, &index)) - return JS_FALSE; + return false; - if (!Walk(cx, index, obj, reviver, &propValue)) - return JS_FALSE; + if (!Walk(cx, index, obj, reviver, propValue.addr())) + return false; - if (!obj->defineProperty(cx, index, propValue, NULL, NULL, JSPROP_ENUMERATE)) - return JS_FALSE; + if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE)) + return false; } } else { - JSIdArray *ida = JS_Enumerate(cx, obj); + AutoIdArray ida(cx, JS_Enumerate(cx, obj)); if (!ida) - return JS_FALSE; + return false; - JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)ida); - - for(jsint i = 0; i < ida->length; i++) { - jsid idName = ida->vector[i]; - if (!Walk(cx, idName, obj, reviver, &propValue)) - return DestroyIdArrayOnError(cx, ida); - if (propValue == JSVAL_VOID) { - if (!js_DeleteProperty(cx, obj, idName, &propValue)) - return DestroyIdArrayOnError(cx, ida); + for (jsint i = 0, len = ida.length(); i < len; i++) { + jsid idName = ida[i]; + if (!Walk(cx, idName, obj, reviver, propValue.addr())) + return false; + if (propValue.value() == JSVAL_VOID) { + if (!js_DeleteProperty(cx, obj, idName, propValue.addr())) + return false; } else { - if (!obj->defineProperty(cx, idName, propValue, NULL, NULL, JSPROP_ENUMERATE)) - return DestroyIdArrayOnError(cx, ida); + if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL, + JSPROP_ENUMERATE)) { + return false; + } } } - - JS_DestroyIdArray(cx, ida); } } @@ -637,31 +624,29 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) jsval value = *vp; JSString *key = js_ValueToString(cx, ID_TO_VALUE(id)); if (!key) - return JS_FALSE; + return false; jsval vec[2] = {STRING_TO_JSVAL(key), value}; jsval reviverResult; if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult)) - return JS_FALSE; + return false; *vp = reviverResult; - - return JS_TRUE; + return true; } -static JSBool +static bool Revive(JSContext *cx, jsval reviver, jsval *vp) { JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL); if (!obj) - return JS_FALSE; + return false; - jsval v = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter tvr(cx, 1, &v); + AutoValueRooter tvr(cx, obj); if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), *vp, NULL, NULL, JSPROP_ENUMERATE)) { - return JS_FALSE; + return false; } return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp); @@ -696,11 +681,11 @@ bad: return NULL; } -JSBool +bool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) { if (!jp) - return JS_TRUE; + return true; JSBool early_ok = JS_TRUE; @@ -721,20 +706,20 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) /* This internal API is infallible, in spite of its JSBool return type. */ js_RemoveRoot(cx->runtime, &jp->objectStack); - JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; + bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; jsval *vp = jp->rootVal; cx->destroy(jp); if (!early_ok) - return JS_FALSE; + return false; if (!ok) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); - return JS_FALSE; + return false; } - if (!JSVAL_IS_PRIMITIVE(reviver) && js_IsCallable(reviver)) + if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable()) ok = Revive(cx, reviver, vp); return ok; @@ -812,7 +797,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) } jsval v = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter tvr(cx, v); + AutoValueRooter tvr(cx, v); // Check if this is the root object if (len == 0) { @@ -885,7 +870,7 @@ CloseArray(JSContext *cx, JSONParser *jp) static JSBool PushPrimitive(JSContext *cx, JSONParser *jp, jsval value) { - JSAutoTempValueRooter tvr(cx, 1, &value); + AutoValueRooter tvr(cx, value); jsuint len; if (!js_GetLengthProperty(cx, jp->objectStack, &len)) diff --git a/js/src/json.h b/js/src/json.h index 84f392419d90..e384863e1604 100644 --- a/js/src/json.h +++ b/js/src/json.h @@ -89,7 +89,7 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal); extern JSBool js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); -extern JSBool +extern bool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver); JS_END_EXTERN_C diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 80ae34738b82..ad06dc64bd4a 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -309,7 +309,7 @@ ToDisassemblySource(JSContext *cx, jsval v) } if (clasp == &js_RegExpClass) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); if (!js_regexp_toString(cx, obj, tvr.addr())) return NULL; return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value())); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 5f640cd0c2be..0207e418dd4e 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8844,13 +8844,12 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) } } { - jsval tmp = JSVAL_NULL; - JSAutoTempValueRooter tvr(cx, 1, &tmp); + AutoValueRooter tvr(cx, JSVAL_NULL); - tmp = l; - lnum = js_ValueToNumber(cx, &tmp); - tmp = r; - rnum = js_ValueToNumber(cx, &tmp); + *tvr.addr() = l; + lnum = js_ValueToNumber(cx, tvr.addr()); + *tvr.addr() = r; + rnum = js_ValueToNumber(cx, tvr.addr()); } cond = EvalCmp(op, lnum, rnum); fp = true; @@ -11204,7 +11203,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, static JSBool FASTCALL MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - JSAutoTempValueRooter tvr(cx, funobj); + AutoValueRooter tvr(cx, funobj); return OBJ_SCOPE(obj)->methodWriteBarrier(cx, sprop, tvr.value()); } @@ -11569,7 +11568,7 @@ GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11914,7 +11913,7 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11929,7 +11928,7 @@ InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval val) { LeaveTraceIfGlobalObject(cx, obj); - JSAutoTempIdRooter idr(cx); + AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(cx); @@ -12756,7 +12755,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) static JSObject* FASTCALL MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - JSAutoTempValueRooter tvr(cx, funobj); + AutoValueRooter tvr(cx, funobj); if (!OBJ_SCOPE(obj)->methodReadBarrier(cx, sprop, tvr.addr())) return NULL; @@ -14886,7 +14885,7 @@ CallIteratorNext(JSContext *cx, uintN argc, jsval *vp) static jsval FASTCALL CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj) { - JSAutoTempValueRooter tvr(cx); + AutoValueRooter tvr(cx); JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr()); if (!ok) { From cf75d4b5c64fc9c7ae39ab4942d0b0c74524494c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 12:24:03 -0700 Subject: [PATCH 173/213] Readd jsregexp.{cpp,h} (and to users of the regex-statics save/restore methods) changes for bug 548702, betting the nsJSEnvironment.{cpp,h} changes were the bad ones causing n810 bustage. --- js/src/jsregexp.cpp | 11 +++++------ js/src/jsregexp.h | 6 ++++-- js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index e5d902d0b1e3..fcbcb4f1dfa5 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5226,11 +5226,11 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr) + AutoValueRooter *tvr) { *statics = cx->regExpStatics; - JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr); - + if (statics->input) + tvr->setString(statics->input); /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). @@ -5241,12 +5241,11 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr) + AutoValueRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ JS_ClearRegExpStatics(cx); cx->regExpStatics = *statics; - JS_POP_TEMP_ROOT(cx, tvr); } void @@ -5839,7 +5838,7 @@ js_NewRegExpObject(JSContext *cx, TokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - JSAutoTempValueRooter tvr(cx, str); + AutoValueRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 63680651e864..73cfee817450 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -65,13 +65,15 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; +namespace js { class AutoValueRooter; } + extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr); + js::AutoValueRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - JSTempValueRooter *tvr); + js::AutoValueRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index a0ec10566de1..074cb8e4594e 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -478,7 +478,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NS_STACK_CLASS class SafeCallGuard { public: SafeCallGuard(JSContext *cx, nsIPrincipal *principal) - : cx(cx) { + : cx(cx), tvr(cx) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (ssm) { // Note: We pass null as the target frame pointer because we know that @@ -517,7 +517,7 @@ public: private: JSContext *cx; JSRegExpStatics statics; - JSTempValueRooter tvr; + js::AutoValueRooter tvr; uint32 options; JSStackFrame *fp; }; @@ -957,7 +957,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, From c0b3caa942112544b6b190ad245336b9d3316e64 Mon Sep 17 00:00:00 2001 From: Brendan Eich Date: Tue, 30 Mar 2010 00:44:28 -0700 Subject: [PATCH 174/213] Fix arguments objects to share a runtime-wide empty scope, instead of each getting a differently shaped own scope at birth (554626, r=igor). --- js/src/jsapi-tests/testLookup.cpp | 4 +- js/src/jsarray.cpp | 17 ++-- js/src/jscntxt.h | 1 + js/src/jsfun.cpp | 127 ++++++++++++++++++------------ js/src/jsfun.h | 99 ++++++++++++++++++----- js/src/jsobj.h | 1 + js/src/jsops.cpp | 62 ++++++++++----- js/src/jsprvtd.h | 8 -- js/src/jsscope.cpp | 48 +++++++++-- js/src/jsstr.cpp | 3 +- js/src/jstracer.cpp | 18 ++--- js/src/jstypedarray.cpp | 2 +- 12 files changed, 267 insertions(+), 123 deletions(-) diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index 4d45f8d791eb..82c6eb1374e8 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -1,5 +1,5 @@ #include "tests.h" -#include "jsfun.h" // for js_IsInternalFunctionObject +#include "jsfun.h" // for js::IsInternalFunctionObject BEGIN_TEST(testLookup_bug522590) { @@ -21,7 +21,7 @@ BEGIN_TEST(testLookup_bug522590) CHECK(JSVAL_IS_OBJECT(r)); JSObject *funobj = JSVAL_TO_OBJECT(r); CHECK(HAS_FUNCTION_CLASS(funobj)); - CHECK(!js_IsInternalFunctionObject(funobj)); + CHECK(!js::IsInternalFunctionObject(funobj)); CHECK(GET_FUNCTION_PRIVATE(cx, funobj) != (JSFunction *) funobj); return true; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7d0fa07616dc..8d9ae59dc3e8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -228,16 +228,21 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) { if (obj->isArray()) { *lengthp = obj->fslots[JSSLOT_ARRAY_LENGTH]; - return JS_TRUE; + return true; + } + + if (obj->isArguments() && !IsOverriddenArgsLength(obj)) { + *lengthp = GetArgsLength(obj); + return true; } AutoValueRooter tvr(cx, JSVAL_NULL); if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr())) - return JS_FALSE; + return false; if (JSVAL_IS_INT(tvr.value())) { *lengthp = jsuint(jsint(JSVAL_TO_INT(tvr.value()))); /* jsuint cast does ToUint32 */ - return JS_TRUE; + return true; } *lengthp = js_ValueToECMAUint32(cx, tvr.addr()); @@ -587,11 +592,9 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) JSBool js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp) { - JSClass *clasp; + JSObject *wrappedObj = js_GetWrappedObject(cx, obj); - clasp = OBJ_GET_CLASS(cx, js_GetWrappedObject(cx, obj)); - *answerp = (clasp == &js_ArgumentsClass || clasp == &js_ArrayClass || - clasp == &js_SlowArrayClass); + *answerp = wrappedObj->isArguments() || wrappedObj->isArray(); if (!*answerp) { *lengthp = 0; return JS_TRUE; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index ae40b2b98650..f013b4ccaf67 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -979,6 +979,7 @@ struct JSRuntime { JSBackgroundThread *deallocatorThread; #endif + JSEmptyScope *emptyArgumentsScope; JSEmptyScope *emptyBlockScope; /* diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 51ef81748883..e11a5f60d726 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -86,7 +86,7 @@ using namespace js; static inline void SetOverriddenArgsLength(JSObject *obj) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); jsval v = obj->fslots[JSSLOT_ARGS_LENGTH]; v = INT_TO_JSVAL(JSVAL_TO_INT(v) | 1); @@ -97,27 +97,17 @@ SetOverriddenArgsLength(JSObject *obj) static inline void InitArgsLengthSlot(JSObject *obj, uint32 argc) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); JS_ASSERT(obj->fslots[JSSLOT_ARGS_LENGTH] == JSVAL_VOID); obj->fslots[JSSLOT_ARGS_LENGTH] = INT_TO_JSVAL(argc << 1); - JS_ASSERT(!js_IsOverriddenArgsLength(obj)); -} - -static inline uint32 -GetArgsLength(JSObject *obj) -{ - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); - - uint32 argc = uint32(JSVAL_TO_INT(obj->fslots[JSSLOT_ARGS_LENGTH])) >> 1; - JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); - return argc; + JS_ASSERT(!IsOverriddenArgsLength(obj)); } static inline void SetArgsPrivateNative(JSObject *argsobj, ArgsPrivateNative *apn) { - JS_ASSERT(STOBJ_GET_CLASS(argsobj) == &js_ArgumentsClass); + JS_ASSERT(argsobj->isArguments()); uintptr_t p = (uintptr_t) apn; argsobj->setPrivate((void*) (p | 2)); } @@ -167,7 +157,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); if (arg < fp->argc) { if (argsobj) { - jsval v = OBJ_GET_SLOT(cx, argsobj, JSSLOT_ARGS_COPY_START+arg); + jsval v = GetArgsSlot(argsobj, arg); if (v == JSVAL_HOLE) return argsobj->getProperty(cx, id, vp); } @@ -190,7 +180,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) } } else if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); - if (argsobj && js_IsOverriddenArgsLength(argsobj)) + if (argsobj && IsOverriddenArgsLength(argsobj)) return argsobj->getProperty(cx, id, vp); *vp = INT_TO_JSVAL(jsint(fp->argc)); } @@ -200,12 +190,25 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) static JSObject * NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) { - JSObject *argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, parent, 0); - if (!argsobj || !js_EnsureReservedSlots(cx, argsobj, argc)) + JSObject *proto; + if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) return NULL; + JSObject *argsobj = js_NewGCObject(cx); + if (!argsobj) + return NULL; + + /* Init immediately to avoid GC seeing a half-init'ed object. */ + argsobj->init(&js_ArgumentsClass, proto, parent, JSVAL_NULL); argsobj->fslots[JSSLOT_ARGS_CALLEE] = OBJECT_TO_JSVAL(callee); InitArgsLengthSlot(argsobj, argc); + + argsobj->map = cx->runtime->emptyArgumentsScope; + cx->runtime->emptyArgumentsScope->hold(); + + /* This must come after argsobj->map has been set. */ + if (!js_EnsureReservedSlots(cx, argsobj, argc)) + return NULL; return argsobj; } @@ -213,13 +216,11 @@ static void PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) { uint32 argc = GetArgsLength(argsobj); - JS_LOCK_OBJ(cx, argsobj); for (uint32 i = 0; i != argc; ++i) { - jsval v = STOBJ_GET_SLOT(argsobj, JSSLOT_ARGS_COPY_START + i); + jsval v = argsobj->dslots[i]; if (v != JSVAL_HOLE) - STOBJ_SET_SLOT(argsobj, JSSLOT_ARGS_COPY_START + i, args[i]); + argsobj->dslots[i] = args[i]; } - JS_UNLOCK_OBJ(cx, argsobj); } JSObject * @@ -303,7 +304,7 @@ JS_DEFINE_CALLINFO_6(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJE JSBool JS_FASTCALL js_PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) { - JS_ASSERT(js_GetArgsPrivateNative(argsobj)); + JS_ASSERT(GetArgsPrivateNative(argsobj)); PutArguments(cx, argsobj, args); argsobj->setPrivate(NULL); return true; @@ -315,12 +316,12 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, JSVALPTR, 0 static JSBool args_delProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); if (JSVAL_IS_INT(idval)) { uintN arg = uintN(JSVAL_TO_INT(idval)); if (arg < GetArgsLength(obj)) - OBJ_SET_SLOT(cx, obj, JSSLOT_ARGS_COPY_START + arg, JSVAL_HOLE); + SetArgsSlot(obj, arg, JSVAL_HOLE); } else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { SetOverriddenArgsLength(obj); } else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) { @@ -514,7 +515,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) uintN arg = uintN(JSVAL_TO_INT(idval)); if (arg < GetArgsLength(obj)) { #ifdef JS_TRACER - ArgsPrivateNative *argp = js_GetArgsPrivateNative(obj); + ArgsPrivateNative *argp = GetArgsPrivateNative(obj); if (argp) { if (NativeToValue(cx, *vp, argp->typemap()[arg], &argp->argv[arg])) return true; @@ -527,13 +528,13 @@ ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) if (fp) { *vp = fp->argv[arg]; } else { - jsval v = OBJ_GET_SLOT(cx, obj, JSSLOT_ARGS_COPY_START + arg); + jsval v = GetArgsSlot(obj, arg); if (v != JSVAL_HOLE) *vp = v; } } } else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { - if (!js_IsOverriddenArgsLength(obj)) + if (!IsOverriddenArgsLength(obj)) *vp = INT_TO_JSVAL(GetArgsLength(obj)); } else { JS_ASSERT(idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)); @@ -608,20 +609,17 @@ static JSBool args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, JSObject **objp) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); *objp = NULL; jsid id = 0; if (JSVAL_IS_INT(idval)) { uint32 arg = uint32(JSVAL_TO_INT(idval)); - if (arg < GetArgsLength(obj) && - OBJ_GET_SLOT(cx, obj, JSSLOT_ARGS_COPY_START + arg) != JSVAL_HOLE) { + if (arg < GetArgsLength(obj) && GetArgsSlot(obj, arg) != JSVAL_HOLE) id = INT_JSVAL_TO_JSID(idval); - } } else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { - if (!js_IsOverriddenArgsLength(obj)) + if (!IsOverriddenArgsLength(obj)) id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - } else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) { if (obj->fslots[JSSLOT_ARGS_CALLEE] != JSVAL_HOLE) id = ATOM_TO_JSID(cx->runtime->atomState.calleeAtom); @@ -642,7 +640,7 @@ args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, static JSBool args_enumerate(JSContext *cx, JSObject *obj) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); /* * Trigger reflection in args_resolve using a series of js_LookupProperty @@ -676,10 +674,12 @@ args_enumerate(JSContext *cx, JSObject *obj) static void args_or_call_trace(JSTracer *trc, JSObject *obj) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass || - STOBJ_GET_CLASS(obj) == &js_CallClass); - if (STOBJ_GET_CLASS(obj) == &js_ArgumentsClass && js_GetArgsPrivateNative(obj)) - return; + if (obj->isArguments()) { + if (GetArgsPrivateNative(obj)) + return; + } else { + JS_ASSERT(obj->getClass() == &js_CallClass); + } JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); if (fp && (fp->flags & JSFRAME_GENERATOR)) { @@ -694,7 +694,7 @@ args_or_call_trace(JSTracer *trc, JSObject *obj) static uint32 args_reserveSlots(JSContext *cx, JSObject *obj) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); return GetArgsLength(obj); } @@ -712,7 +712,7 @@ args_reserveSlots(JSContext *cx, JSObject *obj) JSClass js_ArgumentsClass = { js_Object_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | - JSCLASS_HAS_RESERVED_SLOTS(ARGS_CLASS_FIXED_RESERVED_SLOTS) | + JSCLASS_HAS_RESERVED_SLOTS(ARGS_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), JS_PropertyStub, args_delProperty, JS_PropertyStub, JS_PropertyStub, @@ -1494,7 +1494,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, * script or embedding code and then be mutated. */ if (flags & JSRESOLVE_ASSIGNING) { - JS_ASSERT(!js_IsInternalFunctionObject(obj)); + JS_ASSERT(!IsInternalFunctionObject(obj)); return JS_TRUE; } @@ -1504,7 +1504,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, */ atom = cx->runtime->atomState.classPrototypeAtom; if (id == ATOM_KEY(atom)) { - JS_ASSERT(!js_IsInternalFunctionObject(obj)); + JS_ASSERT(!IsInternalFunctionObject(obj)); /* * Beware of the wacky case of a user function named Object -- trying @@ -1541,7 +1541,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset); if (id == ATOM_KEY(atom)) { - JS_ASSERT(!js_IsInternalFunctionObject(obj)); + JS_ASSERT(!IsInternalFunctionObject(obj)); if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID, @@ -2099,11 +2099,34 @@ js_fun_apply(JSContext *cx, uintN argc, jsval *vp) sp = invokevp; *sp++ = fval; *sp++ = OBJECT_TO_JSVAL(obj); - for (i = 0; i < argc; i++) { - ok = JS_GetElement(cx, aobj, (jsint)i, sp); - if (!ok) - goto out; - sp++; + if (aobj && aobj->isArguments()) { + /* + * Two cases, two loops: note how in the case of an active stack frame + * backing aobj, even though we copy from fp->argv, we still must check + * aobj->dslots[i] for a hole, to handle a delete on the corresponding + * arguments element. See args_delProperty. + */ + JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate(); + if (fp) { + memcpy(sp, fp->argv, argc * sizeof(jsval)); + for (i = 0; i < argc; i++) { + if (aobj->dslots[i] == JSVAL_HOLE) // suppress deleted element + sp[i] = JSVAL_VOID; + } + } else { + memcpy(sp, aobj->dslots, argc * sizeof(jsval)); + for (i = 0; i < argc; i++) { + if (sp[i] == JSVAL_HOLE) + sp[i] = JSVAL_VOID; + } + } + } else { + for (i = 0; i < argc; i++) { + ok = aobj->getProperty(cx, INT_TO_JSID(jsint(i)), sp); + if (!ok) + goto out; + sp++; + } } ok = js_Invoke(cx, argc, invokevp, 0); @@ -2125,8 +2148,8 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) if (JSVAL_IS_PRIMITIVE(vp[2]) || (aobj = JSVAL_TO_OBJECT(vp[2]), - OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass && - OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) { + !aobj->isArray() && + !aobj->isArguments())) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, "__applyConstruct__"); return JS_FALSE; @@ -2145,7 +2168,7 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) *sp++ = vp[1]; *sp++ = JSVAL_NULL; /* this is filled automagically */ for (i = 0; i < length; i++) { - ok = JS_GetElement(cx, aobj, (jsint)i, sp); + ok = aobj->getProperty(cx, INT_TO_JSID(jsint(i)), sp); if (!ok) goto out; sp++; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 37f7d1f825b9..e1c69d321fd1 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -214,7 +214,27 @@ struct JSFunction : public JSObject JS_FN(name, fastcall, nargs, flags) #endif +/* + * NB: the Arguments class is an uninitialized internal class that masquerades + * (according to Object.prototype.toString.call(argsobj)) as "Object". + * + * WARNING (to alert embedders reading this private .h file): arguments objects + * are *not* thread-safe and should not be used concurrently -- they should be + * used by only one thread at a time, preferably by only one thread over their + * lifetime (a JS worker that migrates from one OS thread to another but shares + * nothing is ok). + * + * Yes, this is an incompatible change, which prefigures the impending move to + * single-threaded objects and GC heaps. + */ extern JSClass js_ArgumentsClass; + +inline bool +JSObject::isArguments() const +{ + return getClass() == &js_ArgumentsClass; +} + extern JS_FRIEND_DATA(JSClass) js_CallClass; extern JSClass js_DeclEnvClass; extern const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS; @@ -244,29 +264,33 @@ JSObject::isFunction() const (JS_ASSERT(HAS_FUNCTION_CLASS(funobj)), \ (JSFunction *) (funobj)->getPrivate()) +namespace js { + /* * Return true if this is a compiler-created internal function accessed by * its own object. Such a function object must not be accessible to script * or embedding code. */ inline bool -js_IsInternalFunctionObject(JSObject *funobj) +IsInternalFunctionObject(JSObject *funobj) { JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); JSFunction *fun = (JSFunction *) funobj->getPrivate(); return funobj == fun && (fun->flags & JSFUN_LAMBDA) && !funobj->getParent(); } + +struct ArgsPrivateNative; -namespace js { struct ArgsPrivateNative; } - -inline js::ArgsPrivateNative * -js_GetArgsPrivateNative(JSObject *argsobj) +inline ArgsPrivateNative * +GetArgsPrivateNative(JSObject *argsobj) { - JS_ASSERT(STOBJ_GET_CLASS(argsobj) == &js_ArgumentsClass); + JS_ASSERT(argsobj->isArguments()); uintptr_t p = (uintptr_t) argsobj->getPrivate(); - return (js::ArgsPrivateNative *) (p & 2 ? p & ~2 : NULL); + return (ArgsPrivateNative *) (p & 2 ? p & ~2 : NULL); } +} /* namespace js */ + extern JSObject * js_InitFunctionClass(JSContext *cx, JSObject *obj); @@ -399,17 +423,30 @@ js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->a * whether arguments.length was overwritten. * JSSLOT_ARGS_CALLEE - the arguments.callee value or JSVAL_HOLE if that was * overwritten. - * JSSLOT_ARGS_COPY_START .. - room to store the corresponding arguments after - * the frame exists. The slot's value will be JSVAL_HOLE - * if arguments[i] was deleted or overwritten. + * JSSLOT_ARGS_START - room to store the corresponding arguments after the + * frame exists. The slot's value will be JSVAL_HOLE if + * arguments[i] was deleted or overwritten. + * + * The static assertion checks that hand-optimized code can fetch and store the + * argument value at argsobj->dslots[i] for argument index i. But future-proof + * your code by using {Get,Set}ArgsSlot instead of naked dslots references. */ -const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1; -const uint32 JSSLOT_ARGS_CALLEE = JSSLOT_PRIVATE + 2; -const uint32 JSSLOT_ARGS_COPY_START = JSSLOT_PRIVATE + 3; +const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1; +const uint32 JSSLOT_ARGS_CALLEE = JSSLOT_PRIVATE + 2; +const uint32 JSSLOT_ARGS_START = JSSLOT_PRIVATE + 3; + +JS_STATIC_ASSERT(JSSLOT_ARGS_START == JS_INITIAL_NSLOTS); /* Number of extra fixed slots besides JSSLOT_PRIVATE. */ -const uint32 ARGS_CLASS_FIXED_RESERVED_SLOTS = JSSLOT_ARGS_COPY_START - - JSSLOT_ARGS_LENGTH; +const uint32 ARGS_FIXED_RESERVED_SLOTS = JSSLOT_ARGS_START - JSSLOT_ARGS_LENGTH; + +/* + * Maximum supported value of arguments.length. It bounds the maximum number of + * arguments that can be supplied via the second (so-called |argArray|) param + * to Function.prototype.apply. This value also bounds the number of elements + * parsed in an array initialiser. + */ +const uint32 JS_ARGS_LENGTH_MAX = JS_BIT(24) - 1; /* * JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as int jsval. @@ -419,15 +456,41 @@ const uint32 ARGS_CLASS_FIXED_RESERVED_SLOTS = JSSLOT_ARGS_COPY_START - JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30)); JS_STATIC_ASSERT(jsval((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX); -JS_INLINE bool -js_IsOverriddenArgsLength(JSObject *obj) +namespace js { + +inline jsval +GetArgsSlot(JSObject *argsobj, uint32 arg) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); + return argsobj->dslots[arg]; +} + +inline void +SetArgsSlot(JSObject *argsobj, uint32 arg, jsval v) +{ + argsobj->dslots[arg] = v; +} + +inline bool +IsOverriddenArgsLength(JSObject *obj) +{ + JS_ASSERT(obj->isArguments()); jsval v = obj->fslots[JSSLOT_ARGS_LENGTH]; return (JSVAL_TO_INT(v) & 1) != 0; } +inline uint32 +GetArgsLength(JSObject *obj) +{ + JS_ASSERT(obj->isArguments()); + + uint32 argc = uint32(JSVAL_TO_INT(obj->fslots[JSSLOT_ARGS_LENGTH])) >> 1; + JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); + return argc; +} + +} /* namespace js */ + extern JSBool js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 884389b7063b..f1bb63815ecb 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -436,6 +436,7 @@ struct JSObject { map->ops->dropProperty(cx, this, prop); } + inline bool isArguments() const; inline bool isArray() const; inline bool isDenseArray() const; inline bool isFunction() const; diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 699502041561..84825f207713 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1520,21 +1520,28 @@ BEGIN_CASE(JSOP_LENGTH) if (JSVAL_IS_STRING(lval)) { str = JSVAL_TO_STRING(lval); regs.sp[-1] = INT_TO_JSVAL(str->length()); - } else if (!JSVAL_IS_PRIMITIVE(lval) && - (obj = JSVAL_TO_OBJECT(lval), obj->isArray())) { - jsuint length; + } else if (!JSVAL_IS_PRIMITIVE(lval)) { + obj = JSVAL_TO_OBJECT(lval); + if (obj->isArray()) { + /* + * We know that the array is created with its 'length' private data + * in a fixed slot at JSSLOT_ARRAY_LENGTH. See also JSOP_ARRAYPUSH, + * far below. + */ + jsuint length = obj->fslots[JSSLOT_ARRAY_LENGTH]; - /* - * We know that the array is created with only its 'length' private - * data in a fixed slot at JSSLOT_ARRAY_LENGTH. See also - * JSOP_ARRAYPUSH, far below. - */ - length = obj->fslots[JSSLOT_ARRAY_LENGTH]; - if (length <= JSVAL_INT_MAX) { + if (length <= JSVAL_INT_MAX) + regs.sp[-1] = INT_TO_JSVAL(length); + else if (!js_NewDoubleInRootedValue(cx, (jsdouble) length, ®s.sp[-1])) + goto error; + } else if (obj->isArguments() && !IsOverriddenArgsLength(obj)) { + uint32 length = GetArgsLength(obj); + + JS_ASSERT(INT_FITS_IN_JSVAL(length)); regs.sp[-1] = INT_TO_JSVAL(length); - } else if (!js_NewDoubleInRootedValue(cx, (jsdouble) length, - ®s.sp[-1])) { - goto error; + } else { + i = -2; + goto do_getprop_with_lval; } } else { i = -2; @@ -1867,19 +1874,36 @@ BEGIN_CASE(JSOP_GETELEM) VALUE_TO_OBJECT(cx, -2, lval, obj); if (JSVAL_IS_INT(rval)) { if (obj->isDenseArray()) { - jsuint length; + jsuint idx = jsuint(JSVAL_TO_INT(rval)); - length = js_DenseArrayCapacity(obj); - i = JSVAL_TO_INT(rval); - if ((jsuint)i < length && - i < obj->fslots[JSSLOT_ARRAY_LENGTH]) { - rval = obj->dslots[i]; + if (idx < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) && + idx < js_DenseArrayCapacity(obj)) { + rval = obj->dslots[idx]; if (rval != JSVAL_HOLE) goto end_getelem; /* Reload rval from the stack in the rare hole case. */ rval = FETCH_OPND(-1); } + } else if (obj->isArguments() +#ifdef JS_TRACER + && !GetArgsPrivateNative(obj) +#endif + ) { + uint32 arg = uint32(JSVAL_TO_INT(rval)); + + if (arg < GetArgsLength(obj)) { + JSStackFrame *afp = (JSStackFrame *) obj->getPrivate(); + if (afp) { + rval = afp->argv[arg]; + goto end_getelem; + } + + rval = GetArgsSlot(obj, arg); + if (rval != JSVAL_HOLE) + goto end_getelem; + rval = FETCH_OPND(-1); + } } id = INT_JSVAL_TO_JSID(rval); } else { diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 1f9a4af30526..a54210a6a986 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -390,12 +390,4 @@ typedef void extern JSBool js_CStringsAreUTF8; #endif -/* - * Maximum supported value of Arguments.length. It bounds the maximum number - * of arguments that can be supplied to the function call using - * Function.prototype.apply. This value also gives the maximum number of - * elements in the array initializer. - */ -#define JS_ARGS_LENGTH_MAX (JS_BIT(24) - 1) - #endif /* jsprvtd_h___ */ diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 31ce1330b642..7298d825c961 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -55,8 +55,10 @@ #include "jsatom.h" #include "jscntxt.h" #include "jsdbgapi.h" +#include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */ #include "jslock.h" #include "jsnum.h" +#include "jsobj.h" #include "jsscope.h" #include "jsstr.h" #include "jstracer.h" @@ -279,11 +281,43 @@ JSScope::destroy(JSContext *cx) bool JSScope::initRuntimeState(JSContext *cx) { - cx->runtime->emptyBlockScope = cx->create(cx, &js_ObjectOps, - &js_BlockClass); - JS_ASSERT(cx->runtime->emptyBlockScope->nrefs == 2); - cx->runtime->emptyBlockScope->nrefs = 1; - return !!cx->runtime->emptyBlockScope; + JSRuntime *rt = cx->runtime; + + rt->emptyArgumentsScope = cx->create(cx, &js_ObjectOps, &js_ArgumentsClass); + if (!rt->emptyArgumentsScope) + return false; + JS_ASSERT(rt->emptyArgumentsScope->nrefs == 2); + rt->emptyArgumentsScope->nrefs = 1; + + /* + * NewArguments allocates dslots to have enough room for the argc of the + * particular arguments object being created. + * + * Thus we fake freeslot in the shared empty scope for the many unmutated + * arguments objects so that, until and unless a scope property is defined + * on a particular arguments object, it can share the runtime-wide empty + * scope with other arguments objects, whatever their initial argc values. + * + * This allows assertions that the arg slot being got or set by a fast path + * is less than freeslot to succeed. As the shared emptyArgumentsScope is + * never mutated, it's safe to pretend to have all the slots possible. + * + * Note how the fast paths in jsops.cpp for JSOP_LENGTH and JSOP_GETELEM + * bypass resolution of scope properties for length and element indices on + * arguments objects. This helps ensure that any arguments object needing + * its own mutable scope (with unique shape) is a rare event. + */ + rt->emptyArgumentsScope->freeslot = JS_INITIAL_NSLOTS + JS_ARGS_LENGTH_MAX; + + rt->emptyBlockScope = cx->create(cx, &js_ObjectOps, &js_BlockClass); + if (!rt->emptyBlockScope) { + rt->emptyArgumentsScope->drop(cx); + rt->emptyArgumentsScope = NULL; + return false; + } + JS_ASSERT(rt->emptyBlockScope->nrefs == 2); + rt->emptyBlockScope->nrefs = 1; + return true; } /* static */ @@ -291,6 +325,10 @@ void JSScope::finishRuntimeState(JSContext *cx) { JSRuntime *rt = cx->runtime; + if (rt->emptyArgumentsScope) { + rt->emptyArgumentsScope->drop(cx); + rt->emptyArgumentsScope = NULL; + } if (rt->emptyBlockScope) { rt->emptyBlockScope->drop(cx); rt->emptyBlockScope = NULL; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 04bc452a6438..88284a327eb7 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -63,7 +63,7 @@ #include "jsbool.h" #include "jsbuiltins.h" #include "jscntxt.h" -#include "jsversion.h" +#include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */ #include "jsgc.h" #include "jsinterp.h" #include "jslock.h" @@ -76,6 +76,7 @@ #include "jsstr.h" #include "jsbit.h" #include "jsvector.h" +#include "jsversion.h" #include "jsstrinlines.h" using namespace js; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 0207e418dd4e..5a1a65c23cc2 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -3294,10 +3294,8 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, do for (; n != 0; fp = fp->down) { --n; if (fp->argv) { - if (fp->argsobj && - js_GetArgsPrivateNative(JSVAL_TO_OBJECT(fp->argsobj))) { + if (fp->argsobj && GetArgsPrivateNative(JSVAL_TO_OBJECT(fp->argsobj))) JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(fp); - } JS_ASSERT(JSVAL_IS_OBJECT(fp->argv[-1])); JS_ASSERT(HAS_FUNCTION_CLASS(fp->calleeObject())); @@ -11731,7 +11729,7 @@ TraceRecorder::record_JSOP_GETELEM() return InjectStatus(getPropertyByName(obj_ins, &idx, &lval)); } - if (obj->getClass() == &js_ArgumentsClass) { + if (obj->isArguments()) { unsigned depth; JSStackFrame *afp = guardArguments(obj, obj_ins, &depth); if (afp) { @@ -12395,7 +12393,7 @@ TraceRecorder::guardCallee(jsval& callee) JS_REQUIRES_STACK JSStackFrame * TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp) { - JS_ASSERT(obj->getClass() == &js_ArgumentsClass); + JS_ASSERT(obj->isArguments()); JSStackFrame *afp = frameIfInRange(obj, depthp); if (!afp) @@ -12577,7 +12575,7 @@ TraceRecorder::record_JSOP_APPLY() p2i(stobj_get_fslot(aobj_ins, JSSLOT_ARRAY_LENGTH)), length), BRANCH_EXIT); - } else if (OBJ_GET_CLASS(cx, aobj) == &js_ArgumentsClass) { + } else if (aobj->isArguments()) { unsigned depth; JSStackFrame *afp = guardArguments(aobj, aobj_ins, &depth); if (!afp) @@ -14089,7 +14087,7 @@ TraceRecorder::record_JSOP_ARGSUB() JS_REQUIRES_STACK LIns* TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins) { - // The following implements js_IsOverriddenArgsLength on trace. + // The following implements IsOverriddenArgsLength on trace. // The '2' bit is set if length was overridden. LIns *len_ins = stobj_get_fslot(argsobj_ins, JSSLOT_ARGS_LENGTH); LIns *ovr_ins = lir->ins2(LIR_piand, len_ins, INS_CONSTWORD(2)); @@ -14109,7 +14107,7 @@ TraceRecorder::record_JSOP_ARGCNT() // We also have to check that arguments.length has not been mutated // at record time, because if so we will generate incorrect constant // LIR, which will assert in alu(). - if (cx->fp->argsobj && js_IsOverriddenArgsLength(JSVAL_TO_OBJECT(cx->fp->argsobj))) + if (cx->fp->argsobj && IsOverriddenArgsLength(JSVAL_TO_OBJECT(cx->fp->argsobj))) RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified"); LIns *a_ins = get(&cx->fp->argsobj); if (callDepth == 0) { @@ -14983,7 +14981,7 @@ TraceRecorder::record_JSOP_LENGTH() JSObject* obj = JSVAL_TO_OBJECT(l); LIns* obj_ins = get(&l); - if (obj->getClass() == &js_ArgumentsClass) { + if (obj->isArguments()) { unsigned depth; JSStackFrame *afp = guardArguments(obj, obj_ins, &depth); if (!afp) @@ -14991,7 +14989,7 @@ TraceRecorder::record_JSOP_LENGTH() // We must both check at record time and guard at run time that // arguments.length has not been reassigned, redefined or deleted. - if (js_IsOverriddenArgsLength(obj)) + if (IsOverriddenArgsLength(obj)) RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified"); LIns* slot_ins = guardArgsLengthNotAssigned(obj_ins); diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 7aec65f1461d..fc01d124cb32 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1015,7 +1015,7 @@ class TypedArrayTemplate jsval v; for (uintN i = 0; i < len; ++i) { - if (!JS_GetElement(cx, ar, i, &v)) + if (!ar->getProperty(cx, INT_TO_JSID(i), &v)) return false; *dest++ = nativeFromValue(cx, v); } From 62d96d2c528b4a7062c8639a3967587498514003 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Tue, 30 Mar 2010 11:55:20 -0700 Subject: [PATCH 175/213] b=555721 - typed array checks; r=jorendorff --- js/src/jstypedarray.cpp | 22 +++++++++++++++---- js/src/tests/js1_8_5/extensions/typedarray.js | 3 +++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index fc01d124cb32..e4d740458bed 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -37,6 +37,8 @@ * * ***** END LICENSE BLOCK ***** */ +#define __STDC_LIMIT_MACROS + #include #include "jstypes.h" @@ -918,7 +920,17 @@ class TypedArrayTemplate len = (uint32) lengthInt; } - if (boffset + len*sizeof(NativeType) > abuf->byteLength) { + // Go slowly and check for overflow. + uint32 arrayByteLength = len*sizeof(NativeType); + if (uint32(len) >= INT32_MAX / sizeof(NativeType) || + uint32(boffset) >= INT32_MAX - arrayByteLength) + { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType) + } + + if (arrayByteLength + boffset > abuf->byteLength) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS); return false; // boffset+len is too big for the arraybuffer @@ -927,7 +939,7 @@ class TypedArrayTemplate buffer = abuf; bufferJS = other; byteOffset = boffset; - byteLength = len * sizeof(NativeType); + byteLength = arrayByteLength; length = len; data = abuf->offsetData(boffset); } else { @@ -1095,13 +1107,15 @@ class TypedArrayTemplate bool createBufferWithSizeAndCount(JSContext *cx, uint32 size, uint32 count) { - int32 bytelen = size * count; - if (bytelen / size != count) { + JS_ASSERT(size != 0); + + if (size != 0 && count >= INT32_MAX / size) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET, "size and count"); return false; } + int32 bytelen = size * count; if (!createBufferWithByteLength(cx, bytelen)) return false; diff --git a/js/src/tests/js1_8_5/extensions/typedarray.js b/js/src/tests/js1_8_5/extensions/typedarray.js index 84c52107fdab..0e088c7f96c0 100644 --- a/js/src/tests/js1_8_5/extensions/typedarray.js +++ b/js/src/tests/js1_8_5/extensions/typedarray.js @@ -216,6 +216,9 @@ function test() check(function() !(a[3] == a[3])); check(function() a[4] == 1); + a = new ArrayBuffer(0x10); + checkThrows(function() new Uint32Array(buffer, 4, 0x3FFFFFFF)); + print ("done"); reportCompare(0, TestFailCount, "typed array tests"); From 4808f103018c67067bdb13211f8dcfc85d2cbc2b Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 29 Mar 2010 22:51:52 -0700 Subject: [PATCH 176/213] Readd changes to nsJSEnvironment.{cpp,h}, and adjust js::LazilyConstructed so as to force pointer alignment on the theory that's what was wrong. --HG-- extra : rebase_source : 2215152cf0f03dbb69e49e9adb49979a72294620 --- dom/base/nsJSEnvironment.cpp | 12 ++++-------- dom/base/nsJSEnvironment.h | 8 +++++--- js/src/jstl.h | 30 +++++++++++++++++------------- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index d741e3f05280..e48c772fc0f9 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2108,15 +2108,11 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler return NS_OK; } - jsval targetVal = JSVAL_VOID; - JSAutoTempValueRooter tvr(mContext, 1, &targetVal); - JSObject* target = nsnull; nsresult rv = JSObjectFromInterface(aTarget, aScope, &target); NS_ENSURE_SUCCESS(rv, rv); - targetVal = OBJECT_TO_JSVAL(target); - + js::AutoObjectRooter targetVal(mContext, target); jsval rval = JSVAL_VOID; // This one's a lot easier than EvaluateString because we don't have to @@ -2140,7 +2136,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval *argv = nsnull; js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget @@ -2654,7 +2650,7 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg JSAutoRequest ar(mContext); js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, @@ -2689,7 +2685,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter) + js::LazilyConstructed &aRooter) { nsresult rv = NS_OK; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index 785d53c109e3..b6dc78886051 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -49,8 +49,10 @@ class nsIXPConnectJSObjectHolder; class nsAutoPoolRelease; -class JSAutoTempValueRooter; -namespace js { template class LazilyConstructed; } +namespace js { +class AutoArrayRooter; +template class LazilyConstructed; +} class nsJSContext : public nsIScriptContext, public nsIXPCScriptNotify @@ -215,7 +217,7 @@ protected: PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter); + js::LazilyConstructed &aRooter); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/src/jstl.h b/js/src/jstl.h index ddfe9675c9e3..1a36fe3a2fba 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -259,41 +259,45 @@ class SystemAllocPolicy template class LazilyConstructed { - char bytes[sizeof(T)]; - bool constructed; + union { + void *align; + char bytes[sizeof(T) + 1]; + }; + T &asT() { return *reinterpret_cast(bytes); } + char & constructed() { return bytes[sizeof(T)]; } public: - LazilyConstructed() : constructed(false) {} - ~LazilyConstructed() { if (constructed) asT().~T(); } + LazilyConstructed() { constructed() = false; } + ~LazilyConstructed() { if (constructed()) asT().~T(); } - bool empty() const { return !constructed; } + bool empty() const { return !constructed(); } void construct() { - JS_ASSERT(!constructed); + JS_ASSERT(!constructed()); new(bytes) T(); - constructed = true; + constructed() = true; } template void construct(const T1 &t1) { - JS_ASSERT(!constructed); + JS_ASSERT(!constructed()); new(bytes) T(t1); - constructed = true; + constructed() = true; } template void construct(const T1 &t1, const T2 &t2) { - JS_ASSERT(!constructed); + JS_ASSERT(!constructed()); new(bytes) T(t1, t2); - constructed = true; + constructed() = true; } template void construct(const T1 &t1, const T2 &t2, const T3 &t3) { - JS_ASSERT(!constructed); + JS_ASSERT(!constructed()); new(bytes) T(t1, t2, t3); - constructed = true; + constructed() = true; } }; From ff2fe48d4b3c11e309ecd3dfa89add270d0c7206 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 30 Mar 2010 14:14:47 -0700 Subject: [PATCH 177/213] Realign to 64-bit, since pointers won't be sufficient for that on 32-bit systems. --- js/src/jstl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jstl.h b/js/src/jstl.h index 1a36fe3a2fba..c894767237e7 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -260,7 +260,7 @@ template class LazilyConstructed { union { - void *align; + uint64 align; char bytes[sizeof(T) + 1]; }; From 6090792c57a906c42191aabc16bbe239c1c462db Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 30 Mar 2010 11:14:47 -0700 Subject: [PATCH 178/213] Remove all remnants of JSTempValueRooter. WIN! --- js/src/jscntxt.h | 232 ----------------------------------------------- js/src/jsgc.cpp | 38 -------- js/src/jsprvtd.h | 26 ------ 3 files changed, 296 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index f013b4ccaf67..e9ee1611a9ea 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1165,96 +1165,6 @@ typedef struct JSResolvingEntry { #define JSRESFLAG_WATCH 0x2 /* resolving id from watch */ #define JSRESOLVE_INFER 0xffff /* infer bits from current bytecode */ -/* - * Macros to push/pop JSTempValueRooter instances to context-linked stack of - * temporary GC roots. If you need to protect a result value that flows out of - * a C function across several layers of other functions, use the - * js_LeaveLocalRootScopeWithResult internal API (see further below) instead. - * - * The macros also provide a simple way to get a single rooted pointer via - * JS_PUSH_TEMP_ROOT_(cx, NULL, &tvr). Then &tvr.u. gives the - * necessary pointer. - * - * JSTempValueRooter.count defines the type of the rooted value referenced by - * JSTempValueRooter.u union of type JSTempValueUnion. When count is positive - * or zero, u.array points to a vector of jsvals. Otherwise it must be one of - * the following constants: - */ -#define JSTVU_SINGLE (-1) /* u.value or u. is single jsval - or non-JSString GC-thing pointer */ -#define JSTVU_TRACE (-2) /* u.trace is a hook to trace a custom - * structure */ -#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */ -#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */ -#define JSTVU_COMPILER (-5) /* u.compiler roots JSCompiler* */ -#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */ -#define JSTVU_ENUMERATOR (-7) /* a pointer to JSTempValueRooter points - to an instance of JSAutoEnumStateRooter - with u.object storing the enumeration - object */ - -/* - * Here single JSTVU_SINGLE covers both jsval and pointers to almost (see note - * below) any GC-thing via reinterpreting the thing as JSVAL_OBJECT. This works - * because the GC-thing is aligned on a 0 mod 8 boundary, and object has the 0 - * jsval tag. So any GC-heap-allocated thing pointer may be tagged as if it - * were an object and untagged, if it's then used only as an opaque pointer - * until discriminated by other means than tag bits. This is how, for example, - * js_GetGCThingTraceKind uses its |thing| parameter -- it consults GC-thing - * flags stored separately from the thing to decide the kind of thing. - * - * Note well that JSStrings may be statically allocated (see the intStringTable - * and unitStringTable static arrays), so this hack does not work for arbitrary - * GC-thing pointers. - */ -#define JS_PUSH_TEMP_ROOT_COMMON(cx,x,tvr,cnt,kind) \ - JS_BEGIN_MACRO \ - JS_ASSERT((cx)->tempValueRooters != (tvr)); \ - (tvr)->count = (cnt); \ - (tvr)->u.kind = (x); \ - (tvr)->down = (cx)->tempValueRooters; \ - (cx)->tempValueRooters = (tvr); \ - JS_END_MACRO - -#define JS_POP_TEMP_ROOT(cx,tvr) \ - JS_BEGIN_MACRO \ - JS_ASSERT((cx)->tempValueRooters == (tvr)); \ - (cx)->tempValueRooters = (tvr)->down; \ - JS_END_MACRO - -#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \ - JS_BEGIN_MACRO \ - JS_ASSERT((int)(cnt) >= 0); \ - JS_PUSH_TEMP_ROOT_COMMON(cx, arr, tvr, (ptrdiff_t) (cnt), array); \ - JS_END_MACRO - -#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, val, tvr, JSTVU_SINGLE, value) - -#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, obj, tvr, JSTVU_SINGLE, object) - -#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr) \ - JS_PUSH_SINGLE_TEMP_ROOT(cx, str ? STRING_TO_JSVAL(str) : JSVAL_NULL, tvr) - -#define JS_PUSH_TEMP_ROOT_XML(cx,xml_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, xml_, tvr, JSTVU_SINGLE, xml) - -#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, trace_, tvr, JSTVU_TRACE, trace) - -#define JS_PUSH_TEMP_ROOT_SPROP(cx,sprop_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, sprop_, tvr, JSTVU_SPROP, sprop) - -#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots) - -#define JS_PUSH_TEMP_ROOT_COMPILER(cx,pc,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_COMPILER, compiler) - -#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \ - JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script) - extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ /* @@ -1477,9 +1387,6 @@ struct JSContext /* PDL of stack headers describing stack slots not rooted by argv, etc. */ JSStackHeader *stackHeaders; - /* Stack of thread-stack-allocated temporary GC roots. */ - JSTempValueRooter *tempValueRooters; - /* Stack of thread-stack-allocated GC roots. */ js::AutoGCRooter *autoGCRooters; @@ -2058,145 +1965,6 @@ class AutoXMLRooter : private AutoGCRooter { } /* namespace js */ -/* FIXME(bug 332648): Move this into a public header. */ -class JSAutoTempValueRooter -{ - public: - JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr); - } - explicit JSAutoTempValueRooter(JSContext *cx, jsval v = JSVAL_NULL - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, JSString *str - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT_STRING(mContext, str, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT_OBJECT(mContext, obj, &mTvr); - } - JSAutoTempValueRooter(JSContext *cx, JSScopeProperty *sprop - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_TEMP_ROOT_SPROP(mContext, sprop, &mTvr); - } - - ~JSAutoTempValueRooter() { - JS_POP_TEMP_ROOT(mContext, &mTvr); - } - - jsval value() { return mTvr.u.value; } - jsval *addr() { return &mTvr.u.value; } - - protected: - JSContext *mContext; - - private: - JSTempValueRooter mTvr; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class JSAutoTempIdRooter -{ - public: - explicit JSAutoTempIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_PUSH_SINGLE_TEMP_ROOT(mContext, ID_TO_VALUE(id), &mTvr); - } - - ~JSAutoTempIdRooter() { - JS_POP_TEMP_ROOT(mContext, &mTvr); - } - - jsid id() { return (jsid) mTvr.u.value; } - jsid * addr() { return (jsid *) &mTvr.u.value; } - - private: - JSContext *mContext; - JSTempValueRooter mTvr; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class JSAutoIdArray { - public: - JSAutoIdArray(JSContext *cx, JSIdArray *ida - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : cx(cx), idArray(ida) { - JS_GUARD_OBJECT_NOTIFIER_INIT; - if (ida) - JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr); - } - ~JSAutoIdArray() { - if (idArray) { - JS_POP_TEMP_ROOT(cx, &tvr); - JS_DestroyIdArray(cx, idArray); - } - } - bool operator!() { - return idArray == NULL; - } - jsid operator[](size_t i) const { - JS_ASSERT(idArray); - JS_ASSERT(i < size_t(idArray->length)); - return idArray->vector[i]; - } - size_t length() const { - return idArray->length; - } - private: - JSContext * const cx; - JSIdArray * const idArray; - JSTempValueRooter tvr; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER - - /* No copy or assignment semantics. */ - JSAutoIdArray(JSAutoIdArray &); - void operator=(JSAutoIdArray &); -}; - -/* The auto-root for enumeration object and its state. */ -class JSAutoEnumStateRooter : public JSTempValueRooter -{ - public: - JSAutoEnumStateRooter(JSContext *cx, JSObject *obj, jsval *statep - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx), mStatep(statep) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_ASSERT(obj); - JS_ASSERT(statep); - JS_PUSH_TEMP_ROOT_COMMON(cx, obj, this, JSTVU_ENUMERATOR, object); - } - - ~JSAutoEnumStateRooter() { - JS_POP_TEMP_ROOT(mContext, this); - } - - void mark(JSTracer *trc) { - JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj"); - js_MarkEnumeratorState(trc, u.object, *mStatep); - } - - private: - JSContext *mContext; - jsval *mStatep; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - class JSAutoResolveFlags { public: diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 4ab55fcbfd66..86cbbc5309ff 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -110,14 +110,6 @@ using namespace js; -/* - * Check JSTempValueUnion has the size of jsval and void * so we can - * reinterpret jsval as void* GC-thing pointer and use JSTVU_SINGLE for - * different GC-things. - */ -JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval)); -JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *)); - /* * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and * JSTRACE_STRING. @@ -2441,36 +2433,6 @@ js_TraceContext(JSTracer *trc, JSContext *acx) TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); } - for (JSTempValueRooter *tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { - switch (tvr->count) { - case JSTVU_SINGLE: - JS_SET_TRACING_NAME(trc, "tvr->u.value"); - js_CallValueTracerIfGCThing(trc, tvr->u.value); - break; - case JSTVU_TRACE: - tvr->u.trace(trc, tvr); - break; - case JSTVU_SPROP: - tvr->u.sprop->trace(trc); - break; - case JSTVU_WEAK_ROOTS: - tvr->u.weakRoots->mark(trc); - break; - case JSTVU_COMPILER: - tvr->u.compiler->trace(trc); - break; - case JSTVU_SCRIPT: - js_TraceScript(trc, tvr->u.script); - break; - case JSTVU_ENUMERATOR: - static_cast(tvr)->mark(trc); - break; - default: - JS_ASSERT(tvr->count >= 0); - TraceValues(trc, tvr->count, tvr->u.array, "tvr->u.array"); - } - } - for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) gcr->trace(trc); diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index a54210a6a986..f8a9f9e11875 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -101,7 +101,6 @@ typedef struct JSParseNode JSParseNode; typedef struct JSProperty JSProperty; typedef struct JSSharpObjectMap JSSharpObjectMap; typedef struct JSEmptyScope JSEmptyScope; -typedef struct JSTempValueRooter JSTempValueRooter; typedef struct JSThread JSThread; typedef struct JSThreadData JSThreadData; typedef struct JSTreeContext JSTreeContext; @@ -285,31 +284,6 @@ typedef struct JSDebugHooks { void *debugErrorHookData; } JSDebugHooks; -/* - * Type definitions for temporary GC roots that register with GC local C - * variables. See jscntxt.h for details. - */ -typedef void -(* JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr); - -typedef union JSTempValueUnion { - jsval value; - JSObject *object; - JSXML *xml; - JSTempValueTrace trace; - JSScopeProperty *sprop; - JSWeakRoots *weakRoots; - JSCompiler *compiler; - JSScript *script; - jsval *array; -} JSTempValueUnion; - -struct JSTempValueRooter { - JSTempValueRooter *down; - ptrdiff_t count; - JSTempValueUnion u; -}; - /* JSObjectOps function pointer typedefs. */ /* From a1a894fc1c8c3fa426ae39ac7a3a525a646d4acc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Mar 2010 14:42:48 -0700 Subject: [PATCH 179/213] Bug 555631 - Convert STOBJ_* macros to inline functions. r=gal. --- js/src/jsapi.cpp | 8 +- js/src/jsarray.cpp | 4 +- js/src/jsbuiltins.cpp | 4 +- js/src/jsdbgapi.cpp | 3 +- js/src/jsemit.cpp | 4 +- js/src/jsfun.cpp | 29 ++--- js/src/jsgc.cpp | 2 +- js/src/jsinterp.cpp | 2 +- js/src/jsiter.cpp | 44 +++---- js/src/jsiter.h | 2 +- js/src/jslock.cpp | 12 +- js/src/jsobj.cpp | 54 ++++---- js/src/jsobj.h | 115 +++++++----------- js/src/jsobjinlines.h | 35 ++++++ js/src/jsops.cpp | 10 +- js/src/jsparse.cpp | 4 +- js/src/jsscope.cpp | 10 +- js/src/jsscope.h | 4 +- js/src/jsscript.cpp | 2 +- js/src/jsscriptinlines.h | 2 +- js/src/jstracer.cpp | 44 +++---- js/src/jsxml.cpp | 15 +-- .../xpconnect/src/XPCChromeObjectWrapper.cpp | 8 +- .../xpconnect/src/XPCCrossOriginWrapper.cpp | 30 ++--- js/src/xpconnect/src/XPCNativeWrapper.cpp | 12 +- .../xpconnect/src/XPCSafeJSObjectWrapper.cpp | 6 +- js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp | 16 +-- js/src/xpconnect/src/XPCWrapper.cpp | 2 +- js/src/xpconnect/src/XPCWrapper.h | 4 +- js/src/xpconnect/src/nsXPConnect.cpp | 6 +- js/src/xpconnect/src/xpccomponents.cpp | 2 +- js/src/xpconnect/src/xpcconvert.cpp | 8 +- js/src/xpconnect/src/xpcdebug.cpp | 2 +- js/src/xpconnect/src/xpcprivate.h | 18 +-- js/src/xpconnect/src/xpcquickstubs.cpp | 10 +- js/src/xpconnect/src/xpcwrappedjsclass.cpp | 2 +- js/src/xpconnect/src/xpcwrappednative.cpp | 8 +- .../xpconnect/src/xpcwrappednativejsops.cpp | 4 +- .../xpconnect/src/xpcwrappednativescope.cpp | 4 +- 39 files changed, 281 insertions(+), 270 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9e0e840feb9d..777b9d59b1ea 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1923,7 +1923,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, case JSTRACE_OBJECT: { JSObject *obj = (JSObject *)thing; - JSClass *clasp = STOBJ_GET_CLASS(obj); + JSClass *clasp = obj->getClass(); name = clasp->name; #ifdef HAVE_XPCONNECT @@ -1975,7 +1975,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, case JSTRACE_OBJECT: { JSObject *obj = (JSObject *)thing; - JSClass *clasp = STOBJ_GET_CLASS(obj); + JSClass *clasp = obj->getClass(); if (clasp == &js_FunctionClass) { JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj); if (!fun) { @@ -2817,7 +2817,7 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) /* Walk slots in obj and if any value is a non-null object, seal it. */ nslots = scope->freeslot; for (i = 0; i != nslots; ++i) { - v = STOBJ_GET_SLOT(obj, i); + v = obj->getSlot(i); if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE)) continue; if (JSVAL_IS_PRIMITIVE(v)) @@ -4027,7 +4027,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) *idp = JSVAL_VOID; } else { *idp = ida->vector[--i]; - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i)); + iterobj->setSlot(JSSLOT_ITER_INDEX, INT_TO_JSVAL(i)); } } return JS_TRUE; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 8d9ae59dc3e8..720454d9ca1f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1312,10 +1312,10 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj) uint32 capacity = js_DenseArrayCapacity(obj); if (capacity) { - scope->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS; + scope->freeslot = obj->numSlots() + JS_INITIAL_NSLOTS; obj->dslots[-1] = JS_INITIAL_NSLOTS + capacity; } else { - scope->freeslot = STOBJ_NSLOTS(obj); + scope->freeslot = obj->numSlots(); } /* Create new properties pointing to existing values in dslots */ diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 49d77ce89482..347b098a6051 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -218,8 +218,8 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop) } if (!scope->table) { - if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) { - JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot))); + if (slot < obj->numSlots() && !OBJ_GET_CLASS(cx, obj)->reserveSlots) { + JS_ASSERT(JSVAL_IS_VOID(obj->getSlot(scope->freeslot))); ++scope->freeslot; } else { if (!js_AllocSlot(cx, obj, &slot)) diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 7d16d564307a..4d8b57b18883 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -64,6 +64,7 @@ #include "jsstr.h" #include "jsatominlines.h" +#include "jsobjinlines.h" #include "jsscopeinlines.h" #include "jsautooplen.h" @@ -630,7 +631,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* NB: wp is held, so we can safely dereference it still. */ ok = wp->handler(cx, obj, propid, SPROP_HAS_VALID_SLOT(sprop, scope) - ? OBJ_GET_SLOT(cx, obj, sprop->slot) + ? obj->lockAndGetSlot(cx, sprop->slot) : JSVAL_VOID, vp, wp->closure); if (ok) { diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index a389382aafe7..d4c0b78286d1 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -204,7 +204,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) JS_ASSERT(op == JSOP_ENTERBLOCK); JS_ASSERT(nuses == 0); blockObj = cg->objectList.lastbox->object; - JS_ASSERT(STOBJ_GET_CLASS(blockObj) == &js_BlockClass); + JS_ASSERT(blockObj->getClass() == &js_BlockClass); JS_ASSERT(JSVAL_IS_VOID(blockObj->fslots[JSSLOT_BLOCK_DEPTH])); OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth); @@ -1859,7 +1859,7 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) for (uintN slot = JSSLOT_FREE(&js_BlockClass), limit = slot + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) { - jsval v = STOBJ_GET_SLOT(blockObj, slot); + jsval v = blockObj->getSlot(slot); /* Beware the empty destructuring dummy. */ if (JSVAL_IS_VOID(v)) { diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index e11a5f60d726..1d5a4080f067 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -80,6 +80,7 @@ #endif #include "jsatominlines.h" +#include "jsobjinlines.h" using namespace js; @@ -743,8 +744,8 @@ JSClass js_DeclEnvClass = { static JSBool CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass || - STOBJ_GET_CLASS(obj) == &js_DeclEnvClass); + JS_ASSERT(obj->getClass() == &js_CallClass || + obj->getClass() == &js_DeclEnvClass); jsval v = *vp; @@ -846,7 +847,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp) callobj->setPrivate(fp); JS_ASSERT(fp->argv); JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->calleeObject())); - STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, fp->calleeValue()); + callobj->setSlot(JSSLOT_CALLEE, fp->calleeValue()); fp->callobj = callobj; /* @@ -864,7 +865,7 @@ js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSO JSObject *callobj = NewCallObject(cx, fun, scopeChain); if (!callobj) return NULL; - STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, OBJECT_TO_JSVAL(callee)); + callobj->setSlot(JSSLOT_CALLEE, OBJECT_TO_JSVAL(callee)); return callobj; } @@ -876,8 +877,8 @@ js_GetCallObjectFunction(JSObject *obj) { jsval v; - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass); - v = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE); + JS_ASSERT(obj->getClass() == &js_CallClass); + v = obj->getSlot(JSSLOT_CALLEE); if (JSVAL_IS_VOID(v)) { /* Newborn or prototype object. */ return NULL; @@ -902,7 +903,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp) /* Get the arguments object to snapshot fp's actual argument values. */ if (fp->argsobj) { if (!(fp->flags & JSFRAME_OVERRIDE_ARGS)) - STOBJ_SET_SLOT(callobj, JSSLOT_CALL_ARGUMENTS, fp->argsobj); + callobj->setSlot(JSSLOT_CALL_ARGUMENTS, fp->argsobj); js_PutArgsObject(cx, fp); } @@ -917,7 +918,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp) JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE == 1 + CALL_CLASS_FIXED_RESERVED_SLOTS); if (n != 0) { - JS_ASSERT(STOBJ_NSLOTS(callobj) >= JS_INITIAL_NSLOTS + n); + JS_ASSERT(callobj->numSlots() >= JS_INITIAL_NSLOTS + n); n += JS_INITIAL_NSLOTS; CopyValuesToCallObject(callobj, fun->nargs, fp->argv, fun->u.i.nvars, fp->slots); } @@ -926,7 +927,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp) if (js_IsNamedLambda(fun)) { JSObject *env = callobj->getParent(); - JS_ASSERT(STOBJ_GET_CLASS(env) == &js_DeclEnvClass); + JS_ASSERT(env->getClass() == &js_DeclEnvClass); JS_ASSERT(env->getPrivate() == fp); env->setPrivate(NULL); } @@ -1028,7 +1029,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, jsval *array; if (kind == JSCPK_UPVAR) { - JSObject *callee = JSVAL_TO_OBJECT(STOBJ_GET_SLOT(obj, JSSLOT_CALLEE)); + JSObject *callee = JSVAL_TO_OBJECT(obj->getSlot(JSSLOT_CALLEE)); #ifdef DEBUG JSFunction *callee_fun = (JSFunction *) callee->getPrivate(); @@ -1048,7 +1049,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, if (setter) { if (fp) fp->flags |= JSFRAME_OVERRIDE_ARGS; - STOBJ_SET_SLOT(obj, JSSLOT_CALL_ARGUMENTS, *vp); + obj->setSlot(JSSLOT_CALL_ARGUMENTS, *vp); } else { if (fp && !(fp->flags & JSFRAME_OVERRIDE_ARGS)) { JSObject *argsobj; @@ -1058,7 +1059,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, return false; *vp = OBJECT_TO_JSVAL(argsobj); } else { - *vp = STOBJ_GET_SLOT(obj, JSSLOT_CALL_ARGUMENTS); + *vp = obj->getSlot(JSSLOT_CALL_ARGUMENTS); } } return true; @@ -1177,13 +1178,13 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, JSPropertyOp getter, setter; uintN slot, attrs; - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass); + JS_ASSERT(obj->getClass() == &js_CallClass); JS_ASSERT(!obj->getProto()); if (!JSVAL_IS_STRING(idval)) return JS_TRUE; - callee = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE); + callee = obj->getSlot(JSSLOT_CALLEE); if (JSVAL_IS_VOID(callee)) return JS_TRUE; fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee)); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 86cbbc5309ff..a784ec0810d9 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2508,7 +2508,7 @@ ProcessSetSlotRequest(JSContext *cx, JSSetSlotRequest *ssr) ssr->cycle = true; return; } - pobj = JSVAL_TO_OBJECT(STOBJ_GET_SLOT(pobj, slot)); + pobj = JSVAL_TO_OBJECT(pobj->getSlot(slot)); } pobj = ssr->pobj; diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 112f748d48c0..32fe8f00e750 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -561,7 +561,7 @@ NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags) JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[0])); JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); obj = JSVAL_TO_OBJECT(vp[0]); - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NoSuchMethodClass); + JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass); invokevp[0] = obj->fslots[JSSLOT_FOUND_FUNCTION]; invokevp[1] = vp[1]; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index d2882f6c837f..55688b0ced8e 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -93,10 +93,10 @@ js_CloseNativeIterator(JSContext *cx, JSObject *iterobj) jsval state; JSObject *iterable; - JS_ASSERT(STOBJ_GET_CLASS(iterobj) == &js_IteratorClass); + JS_ASSERT(iterobj->getClass() == &js_IteratorClass); /* Avoid double work if js_CloseNativeIterator was called on obj. */ - state = STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_STATE); + state = iterobj->getSlot(JSSLOT_ITER_STATE); if (JSVAL_IS_NULL(state)) return; @@ -104,7 +104,7 @@ js_CloseNativeIterator(JSContext *cx, JSObject *iterobj) iterable = iterobj->getParent(); if (iterable) { #if JS_HAS_XML_SUPPORT - uintN flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); + uintN flags = JSVAL_TO_INT(iterobj->getSlot(JSSLOT_ITER_FLAGS)); if ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, iterable)) { js_EnumerateXMLValues(cx, iterable, JSENUMERATE_DESTROY, &state, NULL, NULL); @@ -112,7 +112,7 @@ js_CloseNativeIterator(JSContext *cx, JSObject *iterobj) #endif iterable->enumerate(cx, JSENUMERATE_DESTROY, &state, NULL); } - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, JSVAL_NULL); + iterobj->setSlot(JSSLOT_ITER_STATE, JSVAL_NULL); } static void @@ -150,12 +150,12 @@ InitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags) jsval state; JSBool ok; - JS_ASSERT(STOBJ_GET_CLASS(iterobj) == &js_IteratorClass); + JS_ASSERT(iterobj->getClass() == &js_IteratorClass); /* Initialize iterobj in case of enumerate hook failure. */ iterobj->setParent(obj); - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, JSVAL_NULL); - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_FLAGS, INT_TO_JSVAL(flags)); + iterobj->setSlot(JSSLOT_ITER_STATE, JSVAL_NULL); + iterobj->setSlot(JSSLOT_ITER_FLAGS, INT_TO_JSVAL(flags)); if (!js_RegisterCloseableIterator(cx, iterobj)) return JS_FALSE; if (!obj) @@ -171,7 +171,7 @@ InitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags) if (!ok) return JS_FALSE; - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + iterobj->setSlot(JSSLOT_ITER_STATE, state); if (flags & JSITER_ENUMERATE) { /* * The enumerating iterator needs the original object to suppress @@ -236,11 +236,11 @@ IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval) iterable = obj->getParent(); JS_ASSERT(iterable); - state = STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE); + state = obj->getSlot(JSSLOT_ITER_STATE); if (JSVAL_IS_NULL(state)) goto stop; - flags = JSVAL_TO_INT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_FLAGS)); + flags = JSVAL_TO_INT(obj->getSlot(JSSLOT_ITER_FLAGS)); JS_ASSERT(!(flags & JSITER_ENUMERATE)); foreach = (flags & JSITER_FOREACH) != 0; ok = @@ -254,7 +254,7 @@ IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval) if (!ok) return JS_FALSE; - STOBJ_SET_SLOT(obj, JSSLOT_ITER_STATE, state); + obj->setSlot(JSSLOT_ITER_STATE, state); if (JSVAL_IS_NULL(state)) goto stop; @@ -273,7 +273,7 @@ IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval) return JS_TRUE; stop: - JS_ASSERT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE) == JSVAL_NULL); + JS_ASSERT(obj->getSlot(JSSLOT_ITER_STATE) == JSVAL_NULL); *rval = JSVAL_HOLE; return JS_TRUE; } @@ -329,7 +329,7 @@ js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj) { if (OBJ_GET_CLASS(cx, iterobj) != &js_IteratorClass) return 0; - return JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); + return JSVAL_TO_INT(iterobj->getSlot(JSSLOT_ITER_FLAGS)); } /* @@ -465,7 +465,7 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval) obj = iterobj->getParent(); origobj = iterobj->getProto(); - state = STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_STATE); + state = iterobj->getSlot(JSSLOT_ITER_STATE); if (JSVAL_IS_NULL(state)) goto stop; @@ -485,7 +485,7 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval) if (!obj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) return JS_FALSE; } - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + iterobj->setSlot(JSSLOT_ITER_STATE, state); if (JSVAL_IS_NULL(state)) goto stop; } else @@ -495,7 +495,7 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval) if (!obj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) return JS_FALSE; - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + iterobj->setSlot(JSSLOT_ITER_STATE, state); if (JSVAL_IS_NULL(state)) { #if JS_HAS_XML_SUPPORT if (OBJECT_IS_XML(cx, obj)) { @@ -515,7 +515,7 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval) iterobj->setParent(obj); if (!obj->enumerate(cx, JSENUMERATE_INIT, &state, NULL)) return JS_FALSE; - STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_STATE, state); + iterobj->setSlot(JSSLOT_ITER_STATE, state); if (!JSVAL_IS_NULL(state)) goto restart; } @@ -571,7 +571,7 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval) return JS_TRUE; stop: - JS_ASSERT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_STATE) == JSVAL_NULL); + JS_ASSERT(iterobj->getSlot(JSSLOT_ITER_STATE) == JSVAL_NULL); *rval = JSVAL_HOLE; return JS_TRUE; } @@ -583,7 +583,7 @@ js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) /* Fast path for native iterators */ if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass) { - flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS)); + flags = JSVAL_TO_INT(iterobj->getSlot(JSSLOT_ITER_FLAGS)); if (flags & JSITER_ENUMERATE) return CallEnumeratorNext(cx, iterobj, flags, rval); @@ -882,7 +882,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, static JS_REQUIRES_STACK JSBool CloseGenerator(JSContext *cx, JSObject *obj) { - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_GeneratorClass); + JS_ASSERT(obj->getClass() == &js_GeneratorClass); JSGenerator *gen = (JSGenerator *) obj->getPrivate(); if (!gen) { @@ -1010,8 +1010,8 @@ js_InitIteratorClasses(JSContext *cx, JSObject *obj) NULL, iterator_methods, NULL, NULL); if (!proto) return NULL; - STOBJ_SET_SLOT(proto, JSSLOT_ITER_STATE, JSVAL_NULL); - STOBJ_SET_SLOT(proto, JSSLOT_ITER_FLAGS, JSVAL_ZERO); + proto->setSlot(JSSLOT_ITER_STATE, JSVAL_NULL); + proto->setSlot(JSSLOT_ITER_FLAGS, JSVAL_ZERO); #if JS_HAS_GENERATORS /* Initialize the generator internals if configured. */ diff --git a/js/src/jsiter.h b/js/src/jsiter.h index e6814c5ff3ca..41826cebb8a0 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -130,7 +130,7 @@ static inline bool js_ValueIsStopIteration(jsval v) { return !JSVAL_IS_PRIMITIVE(v) && - STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v)) == &js_StopIterationClass; + JSVAL_TO_OBJECT(v)->getClass() == &js_StopIterationClass; } extern JSObject * diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index becfcc9d1106..05f02eb874d6 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -487,7 +487,7 @@ FinishSharingTitle(JSContext *cx, JSTitle *title) uint32 nslots = scope->freeslot; JS_ASSERT(nslots >= JSSLOT_START(obj->getClass())); for (uint32 i = JSSLOT_START(obj->getClass()); i != nslots; ++i) { - jsval v = STOBJ_GET_SLOT(obj, i); + jsval v = obj->getSlot(i); if (JSVAL_IS_STRING(v) && !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) { /* @@ -496,7 +496,7 @@ FinishSharingTitle(JSContext *cx, JSTitle *title) * ignoring errors except out-of-memory, which should have been * reported through JS_ReportOutOfMemory at this point. */ - STOBJ_SET_SLOT(obj, i, JSVAL_VOID); + obj->setSlot(i, JSVAL_VOID); } } } @@ -707,7 +707,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) if (CX_THREAD_IS_RUNNING_GC(cx) || scope->sealed() || (title->ownercx && ClaimTitle(title, cx))) { - return STOBJ_GET_SLOT(obj, slot); + return obj->getSlot(slot); } #ifndef NSPR_LOCK @@ -722,7 +722,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) * lock release followed by fat lock acquisition. */ if (scope == OBJ_SCOPE(obj)) { - v = STOBJ_GET_SLOT(obj, slot); + v = obj->getSlot(slot); if (!NativeCompareAndSwap(&tl->owner, me, 0)) { /* Assert that scope locks never revert to flyweight. */ JS_ASSERT(title->ownercx != cx); @@ -736,12 +736,12 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) js_Dequeue(tl); } else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) { - return STOBJ_GET_SLOT(obj, slot); + return obj->getSlot(slot); } #endif js_LockObj(cx, obj); - v = STOBJ_GET_SLOT(obj, slot); + v = obj->getSlot(slot); /* * Test whether cx took ownership of obj's scope during js_LockObj. diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5de554f0b6ea..8582b8a209d4 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3046,7 +3046,7 @@ js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor) } JSScopeProperty *sprop = scope->lookup(ATOM_TO_JSID(atom)); - jsval pval = sprop ? STOBJ_GET_SLOT(ctor, sprop->slot) : JSVAL_HOLE; + jsval pval = sprop ? ctor->getSlot(sprop->slot) : JSVAL_HOLE; JSObject *proto; if (!JSVAL_IS_PRIMITIVE(pval)) { @@ -3352,7 +3352,7 @@ JSObject * js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp) { JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto)); - JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass); + JS_ASSERT(proto->getClass() == &js_BlockClass); JSObject *clone = js_NewGCObject(cx); if (!clone) @@ -3394,7 +3394,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind) JS_ASSERT(OBJ_SCOPE(obj)->object != obj); /* Block objects should not have reserved slots before they are put. */ - JS_ASSERT(STOBJ_NSLOTS(obj) == JS_INITIAL_NSLOTS); + JS_ASSERT(obj->numSlots() == JS_INITIAL_NSLOTS); /* The block and its locals must be on the current stack for GC safety. */ depth = OBJ_BLOCK_DEPTH(cx, obj); @@ -3447,8 +3447,8 @@ block_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* Values are in reserved slots immediately following DEPTH. */ uint32 slot = JSSLOT_BLOCK_DEPTH + 1 + index; JS_LOCK_OBJ(cx, obj); - JS_ASSERT(slot < STOBJ_NSLOTS(obj)); - *vp = STOBJ_GET_SLOT(obj, slot); + JS_ASSERT(slot < obj->numSlots()); + *vp = obj->getSlot(slot); JS_UNLOCK_OBJ(cx, obj); return true; } @@ -3472,8 +3472,8 @@ block_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* Values are in reserved slots immediately following DEPTH. */ uint32 slot = JSSLOT_BLOCK_DEPTH + 1 + index; JS_LOCK_OBJ(cx, obj); - JS_ASSERT(slot < STOBJ_NSLOTS(obj)); - STOBJ_SET_SLOT(obj, slot, *vp); + JS_ASSERT(slot < obj->numSlots()); + obj->setSlot(slot, *vp); JS_UNLOCK_OBJ(cx, obj); return true; } @@ -3575,7 +3575,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) if (xdr->mode == JSXDR_DECODE) { depth = (uint16)(tmp >> 16); count = (uint16)tmp; - STOBJ_SET_SLOT(obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)); + obj->setSlot(JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)); } /* @@ -3907,8 +3907,8 @@ js_EnsureReservedSlots(JSContext *cx, JSObject *obj, size_t nreserved) JS_ASSERT(OBJ_IS_NATIVE(obj)); JS_ASSERT(!obj->dslots); - uintN nslots = JSSLOT_FREE(STOBJ_GET_CLASS(obj)) + nreserved; - if (nslots > STOBJ_NSLOTS(obj) && !AllocSlots(cx, obj, nslots)) + uintN nslots = JSSLOT_FREE(obj->getClass()) + nreserved; + if (nslots > obj->numSlots() && !AllocSlots(cx, obj, nslots)) return false; JSScope *scope = OBJ_SCOPE(obj); @@ -3916,7 +3916,7 @@ js_EnsureReservedSlots(JSContext *cx, JSObject *obj, size_t nreserved) #ifdef JS_THREADSAFE JS_ASSERT(scope->title.ownercx->thread == cx->thread); #endif - JS_ASSERT(scope->freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj))); + JS_ASSERT(scope->freeslot == JSSLOT_FREE(obj->getClass())); if (scope->freeslot < nslots) scope->freeslot = nslots; } @@ -4167,13 +4167,13 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp) scope->freeslot += clasp->reserveSlots(cx, obj); } - if (scope->freeslot >= STOBJ_NSLOTS(obj) && + if (scope->freeslot >= obj->numSlots() && !js_GrowSlots(cx, obj, scope->freeslot + 1)) { return JS_FALSE; } /* js_ReallocSlots or js_FreeSlot should set the free slots to void. */ - JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot))); + JS_ASSERT(JSVAL_IS_VOID(obj->getSlot(scope->freeslot))); *slotp = scope->freeslot++; return JS_TRUE; } @@ -4300,7 +4300,7 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id) * properties with the same names have been cached or traced. Call objects * may gain such properties via eval introducing new vars; see bug 490364. */ - if (STOBJ_GET_CLASS(obj) == &js_CallClass) { + if (obj->getClass() == &js_CallClass) { while ((obj = obj->getParent()) != NULL) { if (PurgeProtoChain(cx, obj, id)) break; @@ -6567,7 +6567,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj) * that share their scope, scope->freeslot can be an underestimate. */ size_t slots = scope->freeslot; - if (STOBJ_NSLOTS(obj) != slots) + if (obj->numSlots() != slots) js_ShrinkSlots(cx, obj, slots); } @@ -6594,19 +6594,19 @@ js_TraceObject(JSTracer *trc, JSObject *obj) /* * An unmutated object that shares a prototype object's scope. We can't * tell how many slots are in use in obj by looking at its scope, so we - * use STOBJ_NSLOTS(obj). + * use obj->numSlots(). * * NB: In case clasp->mark mutates something, leave this code here -- * don't move it up and unify it with the |if (!traceScope)| section * above. */ - uint32 nslots = STOBJ_NSLOTS(obj); + uint32 nslots = obj->numSlots(); if (!scope->isSharedEmpty() && scope->freeslot < nslots) nslots = scope->freeslot; JS_ASSERT(nslots >= JSSLOT_START(clasp)); for (uint32 i = JSSLOT_START(clasp); i != nslots; ++i) { - jsval v = STOBJ_GET_SLOT(obj, i); + jsval v = obj->getSlot(i); if (JSVAL_IS_TRACEABLE(v)) { JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i); js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); @@ -6632,10 +6632,10 @@ js_Clear(JSContext *cx, JSObject *obj) scope->clear(cx); /* Clear slot values and reset freeslot so we're consistent. */ - i = STOBJ_NSLOTS(obj); + i = obj->numSlots(); n = JSSLOT_FREE(obj->getClass()); while (--i >= n) - STOBJ_SET_SLOT(obj, i, JSVAL_VOID); + obj->setSlot(i, JSVAL_VOID); scope->freeslot = n; } JS_UNLOCK_OBJ(cx, obj); @@ -6676,7 +6676,7 @@ js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) return false; uint32 slot = JSSLOT_START(clasp) + index; - *vp = (slot < STOBJ_NSLOTS(obj)) ? STOBJ_GET_SLOT(obj, slot) : JSVAL_VOID; + *vp = (slot < obj->numSlots()) ? obj->getSlot(slot) : JSVAL_VOID; JS_UNLOCK_OBJ(cx, obj); return true; } @@ -6717,13 +6717,13 @@ js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) * If scope is shared, do not modify scope->freeslot. It is OK for freeslot * to be an underestimate in objects with shared scopes, as they will get * their own scopes before mutating, and elsewhere (e.g. js_TraceObject) we - * use STOBJ_NSLOTS(obj) rather than rely on freeslot. + * use obj->numSlots() rather than rely on freeslot. */ JSScope *scope = OBJ_SCOPE(obj); if (!scope->isSharedEmpty() && slot >= scope->freeslot) scope->freeslot = slot + 1; - STOBJ_SET_SLOT(obj, slot, v); + obj->setSlot(slot, v); GC_POKE(cx, JS_NULL); JS_UNLOCK_SCOPE(cx, scope); return true; @@ -6853,7 +6853,7 @@ dumpValue(jsval val) (void *) fun); } else if (JSVAL_IS_OBJECT(val)) { JSObject *obj = JSVAL_TO_OBJECT(val); - JSClass *cls = STOBJ_GET_CLASS(obj); + JSClass *cls = obj->getClass(); fprintf(stderr, "<%s%s at %p>", cls->name, cls == &js_ObjectClass ? "" : " object", @@ -6924,7 +6924,7 @@ js_DumpObject(JSObject *obj) jsuint reservedEnd; fprintf(stderr, "object %p\n", (void *) obj); - clasp = STOBJ_GET_CLASS(obj); + clasp = obj->getClass(); fprintf(stderr, "class %p %s\n", (void *)clasp, clasp->name); if (obj->isDenseArray()) { @@ -6973,13 +6973,13 @@ js_DumpObject(JSObject *obj) reservedEnd = i + JSCLASS_RESERVED_SLOTS(clasp); slots = (OBJ_IS_NATIVE(obj) && !OBJ_SCOPE(obj)->isSharedEmpty()) ? OBJ_SCOPE(obj)->freeslot - : STOBJ_NSLOTS(obj); + : obj->numSlots(); for (; i < slots; i++) { fprintf(stderr, " %3d ", i); if (i < reservedEnd) fprintf(stderr, "(reserved) "); fprintf(stderr, "= "); - dumpValue(STOBJ_GET_SLOT(obj, i)); + dumpValue(obj->getSlot(i)); fputc('\n', stderr); } fputc('\n', stderr); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index f1bb63815ecb..71a76d160d24 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -284,6 +284,42 @@ struct JSObject { classword |= jsuword(2); } + uint32 numSlots(void) { + return dslots ? (uint32)dslots[-1] : (uint32)JS_INITIAL_NSLOTS; + } + + jsval& getSlotRef(uintN slot) { + return (slot < JS_INITIAL_NSLOTS) + ? fslots[slot] + : (JS_ASSERT(slot < (uint32)dslots[-1]), + dslots[slot - JS_INITIAL_NSLOTS]); + } + + jsval getSlot(uintN slot) const { + return (slot < JS_INITIAL_NSLOTS) + ? fslots[slot] + : (JS_ASSERT(slot < (uint32)dslots[-1]), + dslots[slot - JS_INITIAL_NSLOTS]); + } + + void setSlot(uintN slot, jsval value) { + if (slot < JS_INITIAL_NSLOTS) { + fslots[slot] = value; + } else { + JS_ASSERT(slot < (uint32)dslots[-1]); + dslots[slot - JS_INITIAL_NSLOTS] = value; + } + } + + /* + * These ones are for multi-threaded objects. Use getSlot(), + * getSlotRef(), setSlot() to directly manipulate slots in obj when only + * one thread can access obj, or when accessing read-only slots within + * JS_INITIAL_NSLOTS. + */ + jsval lockAndGetSlot(JSContext *cx, uintN slot); + void lockAndSetSlot(JSContext *cx, uintN slot, jsval value); + JSObject *getProto() const { return JSVAL_TO_OBJECT(fslots[JSSLOT_PROTO]); } @@ -464,77 +500,19 @@ struct JSObject { #define MAX_DSLOTS_LENGTH (JS_MAX(~uint32(0), ~size_t(0)) / sizeof(jsval) - 1) #define MAX_DSLOTS_LENGTH32 (~uint32(0) / sizeof(jsval) - 1) -/* - * STOBJ prefix means Single Threaded Object. Use the following fast macros to - * directly manipulate slots in obj when only one thread can access obj, or - * when accessing read-only slots within JS_INITIAL_NSLOTS. - */ - -#define STOBJ_NSLOTS(obj) \ - ((obj)->dslots ? (uint32)(obj)->dslots[-1] : (uint32)JS_INITIAL_NSLOTS) - -inline jsval& -STOBJ_GET_SLOT(JSObject *obj, uintN slot) -{ - return (slot < JS_INITIAL_NSLOTS) - ? obj->fslots[slot] - : (JS_ASSERT(slot < (uint32)obj->dslots[-1]), - obj->dslots[slot - JS_INITIAL_NSLOTS]); -} - -inline void -STOBJ_SET_SLOT(JSObject *obj, uintN slot, jsval value) -{ - if (slot < JS_INITIAL_NSLOTS) { - obj->fslots[slot] = value; - } else { - JS_ASSERT(slot < (uint32)obj->dslots[-1]); - obj->dslots[slot - JS_INITIAL_NSLOTS] = value; - } -} - -inline JSClass* -STOBJ_GET_CLASS(const JSObject* obj) -{ - return obj->getClass(); -} - #define OBJ_CHECK_SLOT(obj,slot) \ (JS_ASSERT(obj->isNative()), JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot)) #define LOCKED_OBJ_GET_SLOT(obj,slot) \ - (OBJ_CHECK_SLOT(obj, slot), STOBJ_GET_SLOT(obj, slot)) + (OBJ_CHECK_SLOT(obj, slot), obj->getSlot(slot)) #define LOCKED_OBJ_SET_SLOT(obj,slot,value) \ - (OBJ_CHECK_SLOT(obj, slot), STOBJ_SET_SLOT(obj, slot, value)) + (OBJ_CHECK_SLOT(obj, slot), obj->setSlot(slot, value)) #ifdef JS_THREADSAFE -/* Thread-safe functions and wrapper macros for accessing slots in obj. */ -#define OBJ_GET_SLOT(cx,obj,slot) \ - (OBJ_CHECK_SLOT(obj, slot), \ - (OBJ_SCOPE(obj)->title.ownercx == cx) \ - ? LOCKED_OBJ_GET_SLOT(obj, slot) \ - : js_GetSlotThreadSafe(cx, obj, slot)) - -#define OBJ_SET_SLOT(cx,obj,slot,value) \ - JS_BEGIN_MACRO \ - OBJ_CHECK_SLOT(obj, slot); \ - if (OBJ_SCOPE(obj)->title.ownercx == cx) \ - LOCKED_OBJ_SET_SLOT(obj, slot, value); \ - else \ - js_SetSlotThreadSafe(cx, obj, slot, value); \ - JS_END_MACRO - /* - * If thread-safe, define an OBJ_GET_SLOT wrapper that bypasses, for a native - * object, the lock-free "fast path" test of (OBJ_SCOPE(obj)->ownercx == cx), - * to avoid needlessly switching from lock-free to lock-full scope when doing - * GC on a different context from the last one to own the scope. The caller - * in this case is probably a JSClass.mark function, e.g., fun_mark, or maybe - * a finalizer. - * * The GC runs only when all threads except the one on which the GC is active - * are suspended at GC-safe points, so calling STOBJ_GET_SLOT from the GC's + * are suspended at GC-safe points, so calling obj->getSlot() from the GC's * thread is safe when rt->gcRunning is set. See jsgc.c for details. */ #define THREAD_IS_RUNNING_GC(rt, thread) \ @@ -543,18 +521,13 @@ STOBJ_GET_CLASS(const JSObject* obj) #define CX_THREAD_IS_RUNNING_GC(cx) \ THREAD_IS_RUNNING_GC((cx)->runtime, (cx)->thread) -#else /* !JS_THREADSAFE */ - -#define OBJ_GET_SLOT(cx,obj,slot) LOCKED_OBJ_GET_SLOT(obj,slot) -#define OBJ_SET_SLOT(cx,obj,slot,value) LOCKED_OBJ_SET_SLOT(obj,slot,value) - -#endif /* !JS_THREADSAFE */ +#endif /* JS_THREADSAFE */ /* * Class is invariant and comes from the fixed clasp member. Thus no locking * is necessary to read it. Same for the private slot. */ -#define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj) +#define OBJ_GET_CLASS(cx,obj) (obj)->getClass() #ifdef __cplusplus inline void @@ -617,9 +590,9 @@ js_DefineBlockVariable(JSContext *cx, JSObject *obj, jsid id, intN index); #define OBJ_BLOCK_COUNT(cx,obj) \ (OBJ_SCOPE(OBJ_IS_CLONED_BLOCK(obj) ? obj->getProto() : obj)->entryCount) #define OBJ_BLOCK_DEPTH(cx,obj) \ - JSVAL_TO_INT(STOBJ_GET_SLOT(obj, JSSLOT_BLOCK_DEPTH)) + JSVAL_TO_INT(obj->getSlot(JSSLOT_BLOCK_DEPTH)) #define OBJ_SET_BLOCK_DEPTH(cx,obj,depth) \ - STOBJ_SET_SLOT(obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)) + obj->setSlot(JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)) /* * To make sure this slot is well-defined, always call js_NewWithObject to @@ -889,7 +862,7 @@ js_IsCacheableNonGlobalScope(JSObject *obj) extern JS_FRIEND_DATA(JSClass) js_DeclEnvClass; JS_ASSERT(obj->getParent()); - JSClass *clasp = STOBJ_GET_CLASS(obj); + JSClass *clasp = obj->getClass(); bool cacheable = (clasp == &js_CallClass || clasp == &js_BlockClass || clasp == &js_DeclEnvClass); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index b8a21d864a3e..a96923042ae1 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -44,6 +44,41 @@ #include "jsobj.h" #include "jsscope.h" +inline jsval +JSObject::lockAndGetSlot(JSContext *cx, uintN slot) { +#ifdef JS_THREADSAFE + /* + * If thread-safe, define a lockAndGetSlot() that bypasses, for a native + * object, the lock-free "fast path" test of + * (OBJ_SCOPE(obj)->ownercx == cx), to avoid needlessly switching from + * lock-free to lock-full scope when doing GC on a different context + * from the last one to own the scope. The caller in this case is + * probably a JSClass.mark function, e.g., fun_mark, or maybe a + * finalizer. + */ + OBJ_CHECK_SLOT(this, slot); + return (OBJ_SCOPE(this)->title.ownercx == cx) + ? LOCKED_OBJ_GET_SLOT(this, slot) + : js_GetSlotThreadSafe(cx, this, slot); +#else + return LOCKED_OBJ_GET_SLOT(this, slot); +#endif +} + +inline void +JSObject::lockAndSetSlot(JSContext *cx, uintN slot, jsval value) { +#ifdef JS_THREADSAFE + /* Thread-safe way to set a slot. */ + OBJ_CHECK_SLOT(this, slot); + if (OBJ_SCOPE(this)->title.ownercx == cx) + LOCKED_OBJ_SET_SLOT(this, slot, value); + else + js_SetSlotThreadSafe(cx, this, slot, value); +#else + LOCKED_OBJ_SET_SLOT(this, slot, value); +#endif +} + inline void JSObject::initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent, jsval privateSlotValue) diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 84825f207713..d51d298740f2 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1400,7 +1400,7 @@ BEGIN_CASE(JSOP_GVARINC) } slot = JSVAL_TO_INT(lval); JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); - rval = OBJ_GET_SLOT(cx, cx->activeCallStack()->getInitialVarObj(), slot); + rval = cx->activeCallStack()->getInitialVarObj()->lockAndGetSlot(cx, slot); if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { PUSH_OPND(rval + incr2); rval += incr; @@ -1412,7 +1412,7 @@ BEGIN_CASE(JSOP_GVARINC) rval = regs.sp[-1]; --regs.sp; } - OBJ_SET_SLOT(cx, fp->varobj(cx), slot, rval); + fp->varobj(cx)->lockAndSetSlot(cx, slot, rval); len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */ JS_ASSERT(len == js_CodeSpec[op].length); DO_NEXT_OP(len); @@ -1769,7 +1769,7 @@ BEGIN_CASE(JSOP_SETMETHOD) * reserveSlots hook to allocate a number of reserved * slots that may vary with obj. */ - if (slot < STOBJ_NSLOTS(obj) && + if (slot < obj->numSlots() && !OBJ_GET_CLASS(cx, obj)->reserveSlots) { ++scope->freeslot; } else { @@ -2748,7 +2748,7 @@ BEGIN_CASE(JSOP_CALLGVAR) JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); obj = cx->activeCallStack()->getInitialVarObj(); slot = JSVAL_TO_INT(lval); - rval = OBJ_GET_SLOT(cx, obj, slot); + rval = obj->lockAndGetSlot(cx, slot); PUSH_OPND(rval); if (op == JSOP_CALLGVAR) PUSH_OPND(OBJECT_TO_JSVAL(obj)); @@ -3392,7 +3392,7 @@ BEGIN_CASE(JSOP_INITMETHOD) /* Fast path. Property cache hit. */ slot = sprop->slot; JS_ASSERT(slot == scope->freeslot); - if (slot < STOBJ_NSLOTS(obj)) { + if (slot < obj->numSlots()) { ++scope->freeslot; } else { if (!js_AllocSlot(cx, obj, &slot)) diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 806f1fe7e79c..26bcb0a7377c 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -3227,12 +3227,12 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) * slots in jsemit.cpp:EmitEnterBlock. */ uintN slot = JSSLOT_FREE(&js_BlockClass) + n; - if (slot >= STOBJ_NSLOTS(blockObj) && + if (slot >= blockObj->numSlots() && !js_GrowSlots(cx, blockObj, slot + 1)) { return JS_FALSE; } OBJ_SCOPE(blockObj)->freeslot = slot + 1; - STOBJ_SET_SLOT(blockObj, slot, PRIVATE_TO_JSVAL(pn)); + blockObj->setSlot(slot, PRIVATE_TO_JSVAL(pn)); return JS_TRUE; } diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 7298d825c961..0c19fe349d1e 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -106,7 +106,7 @@ js_GetMutableScope(JSContext *cx, JSObject *obj) * Compile-time block objects each have their own scope, created at * birth, and runtime clone of a block objects are never mutated. */ - JS_ASSERT(STOBJ_GET_CLASS(obj) != &js_BlockClass); + JS_ASSERT(obj->getClass() != &js_BlockClass); newscope = JSScope::create(cx, scope->ops, obj->getClass(), obj, scope->shape); if (!newscope) return NULL; @@ -116,8 +116,8 @@ js_GetMutableScope(JSContext *cx, JSObject *obj) JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, newscope)); obj->map = newscope; - JS_ASSERT(newscope->freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj))); - clasp = STOBJ_GET_CLASS(obj); + JS_ASSERT(newscope->freeslot == JSSLOT_FREE(obj->getClass())); + clasp = obj->getClass(); if (clasp->reserveSlots) { /* * FIXME: Here we change OBJ_SCOPE(obj)->freeslot without changing @@ -126,8 +126,8 @@ js_GetMutableScope(JSContext *cx, JSObject *obj) * js_AddProperty. See bug 535416. */ freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj); - if (freeslot > STOBJ_NSLOTS(obj)) - freeslot = STOBJ_NSLOTS(obj); + if (freeslot > obj->numSlots()) + freeslot = obj->numSlots(); if (newscope->freeslot < freeslot) newscope->freeslot = freeslot; } diff --git a/js/src/jsscope.h b/js/src/jsscope.h index e696f4a4d745..3b387530f676 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -984,7 +984,7 @@ JSScopeProperty::get(JSContext* cx, JSObject* obj, JSObject *pobj, jsval* vp) * objects. XPConnect objects don't expect the hook to be called here, * but with objects do. */ - if (STOBJ_GET_CLASS(obj) == &js_WithClass) + if (obj->getClass() == &js_WithClass) obj = obj->map->ops->thisObject(cx, obj); return getterOp()(cx, obj, SPROP_USERID(this), vp); } @@ -1003,7 +1003,7 @@ JSScopeProperty::set(JSContext* cx, JSObject* obj, jsval* vp) return !!js_ReportGetterOnlyAssignment(cx); /* See the comment in JSScopeProperty::get as to why we can check for With. */ - if (STOBJ_GET_CLASS(obj) == &js_WithClass) + if (obj->getClass() == &js_WithClass) obj = obj->map->ops->thisObject(cx, obj); return setterOp()(cx, obj, SPROP_USERID(this), vp); } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 15065a6ca7d4..db7a69a339c7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -312,7 +312,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, JSObject **objp = &script->objects()->vector[i]; uint32 isBlock; if (xdr->mode == JSXDR_ENCODE) { - JSClass *clasp = STOBJ_GET_CLASS(*objp); + JSClass *clasp = (*objp)->getClass(); JS_ASSERT(clasp == &js_FunctionClass || clasp == &js_BlockClass); isBlock = (clasp == &js_BlockClass) ? 1 : 0; diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index fdd3bf51df17..33f6b6347ea6 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -63,7 +63,7 @@ JSScript::getRegExp(size_t index) JSObjectArray *arr = regexps(); JS_ASSERT((uint32) index < arr->length); JSObject *obj = arr->vector[index]; - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_RegExpClass); + JS_ASSERT(obj->getClass() == &js_RegExpClass); return obj; } diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 5a1a65c23cc2..27b4e87089bf 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1793,7 +1793,7 @@ VisitGlobalSlots(Visitor &visitor, JSContext *cx, JSObject *globalObj, { for (unsigned n = 0; n < ngslots; ++n) { unsigned slot = gslots[n]; - visitor.visitGlobalSlot(&STOBJ_GET_SLOT(globalObj, slot), n, slot); + visitor.visitGlobalSlot(&globalObj->getSlotRef(slot), n, slot); } } @@ -2504,7 +2504,7 @@ bool TraceRecorder::isGlobal(jsval* p) const { return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) || - (size_t(p - globalObj->dslots) < (STOBJ_NSLOTS(globalObj) - JS_INITIAL_NSLOTS))); + (size_t(p - globalObj->dslots) < (globalObj->numSlots() - JS_INITIAL_NSLOTS))); } /* @@ -3514,9 +3514,9 @@ JS_REQUIRES_STACK void TraceRecorder::importGlobalSlot(unsigned slot) { JS_ASSERT(slot == uint16(slot)); - JS_ASSERT(STOBJ_NSLOTS(globalObj) <= MAX_GLOBAL_SLOTS); + JS_ASSERT(globalObj->numSlots() <= MAX_GLOBAL_SLOTS); - jsval* vp = &STOBJ_GET_SLOT(globalObj, slot); + jsval* vp = &globalObj->getSlotRef(slot); JS_ASSERT(!known(vp)); /* Add the slot to the list of interned global slots. */ @@ -3548,9 +3548,9 @@ TraceRecorder::lazilyImportGlobalSlot(unsigned slot) * If the global object grows too large, alloca in ExecuteTree might fail, * so abort tracing on global objects with unreasonably many slots. */ - if (STOBJ_NSLOTS(globalObj) > MAX_GLOBAL_SLOTS) + if (globalObj->numSlots() > MAX_GLOBAL_SLOTS) return false; - jsval* vp = &STOBJ_GET_SLOT(globalObj, slot); + jsval* vp = &globalObj->getSlotRef(slot); if (known(vp)) return true; /* we already have it */ importGlobalSlot(slot); @@ -5084,7 +5084,7 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) SlotList& gslots = *tree->globalSlots; for (unsigned i = 0; i < gslots.length(); i++) { unsigned slot = gslots[i]; - jsval* vp = &STOBJ_GET_SLOT(globalObj, slot); + jsval* vp = &globalObj->getSlotRef(slot); tracker.set(vp, NULL); } @@ -5287,7 +5287,7 @@ CheckGlobalObjectShape(JSContext* cx, TraceMonitor* tm, JSObject* globalObj, return false; } - if (STOBJ_NSLOTS(globalObj) > MAX_GLOBAL_SLOTS) { + if (globalObj->numSlots() > MAX_GLOBAL_SLOTS) { if (tm->recorder) AbortRecording(cx, "too many slots in global object"); return false; @@ -6435,7 +6435,7 @@ ScopeChainCheck(JSContext* cx, TreeFragment* f) } /* Make sure the global object is sane. */ - JS_ASSERT(STOBJ_NSLOTS(f->globalObj) <= MAX_GLOBAL_SLOTS); + JS_ASSERT(f->globalObj->numSlots() <= MAX_GLOBAL_SLOTS); JS_ASSERT(f->nGlobalTypes() == f->globalSlots->length()); JS_ASSERT_IF(f->globalSlots->length() != 0, OBJ_SHAPE(f->globalObj) == f->globalShape); @@ -6478,7 +6478,7 @@ ExecuteTree(JSContext* cx, TreeFragment* f, uintN& inlineCallCount, f->maxNativeStackSlots, f->code()); - debug_only_stmt(uint32 globalSlots = STOBJ_NSLOTS(globalObj);) + debug_only_stmt(uint32 globalSlots = globalObj->numSlots();) debug_only_stmt(*(uint64*)&tm->storage->global()[globalSlots] = 0xdeadbeefdeadbeefLL;) /* Execute trace. */ @@ -7855,7 +7855,7 @@ TraceRecorder::scopeChainProp(JSObject* chainHead, jsval*& vp, LIns*& ins, NameR obj2->dropProperty(cx, prop); RETURN_STOP_A("lazy import of global slot failed"); } - vp = &STOBJ_GET_SLOT(obj, sprop->slot); + vp = &obj->getSlotRef(sprop->slot); ins = get(vp); obj2->dropProperty(cx, prop); nr.tracked = true; @@ -8506,7 +8506,7 @@ TraceRecorder::incProp(jsint incr, bool pre) if (slot == SPROP_INVALID_SLOT) RETURN_STOP_A("incProp on invalid slot"); - jsval& v = STOBJ_GET_SLOT(obj, slot); + jsval& v = obj->getSlotRef(slot); CHECK_STATUS_A(inc(v, v_ins, incr, pre)); LIns* dslots_ins = NULL; @@ -11188,7 +11188,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, if (obj == globalObj) { if (!lazilyImportGlobalSlot(slot)) RETURN_STOP("lazy import of global slot failed"); - set(&STOBJ_GET_SLOT(obj, slot), v_ins); + set(&obj->getSlotRef(slot), v_ins); } else { LIns* dslots_ins = NULL; stobj_set_slot(obj_ins, slot, dslots_ins, boxed_ins); @@ -12744,7 +12744,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - vp = &STOBJ_GET_SLOT(obj, slot); + vp = &obj->getSlotRef(slot); ins = get(vp); nr.tracked = true; return ARECORD_CONTINUE; @@ -12895,7 +12895,7 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcva } LIns* dslots_ins = NULL; - LIns* v_ins = unbox_jsval(STOBJ_GET_SLOT(obj, slot), + LIns* v_ins = unbox_jsval(obj->getSlot(slot), stobj_get_slot(obj_ins, slot, dslots_ins), snapshot(BRANCH_EXIT)); @@ -14254,7 +14254,7 @@ TraceRecorder::record_JSOP_GETGVAR() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - stack(0, get(&STOBJ_GET_SLOT(globalObj, slot))); + stack(0, get(&globalObj->getSlotRef(slot))); return ARECORD_CONTINUE; } @@ -14270,7 +14270,7 @@ TraceRecorder::record_JSOP_SETGVAR() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - set(&STOBJ_GET_SLOT(globalObj, slot), stack(-1)); + set(&globalObj->getSlotRef(slot), stack(-1)); return ARECORD_CONTINUE; } @@ -14287,7 +14287,7 @@ TraceRecorder::record_JSOP_INCGVAR() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), 1)); + return InjectStatus(inc(globalObj->getSlotRef(slot), 1)); } JS_REQUIRES_STACK AbortableRecordingStatus @@ -14303,7 +14303,7 @@ TraceRecorder::record_JSOP_DECGVAR() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), -1)); + return InjectStatus(inc(globalObj->getSlotRef(slot), -1)); } JS_REQUIRES_STACK AbortableRecordingStatus @@ -14319,7 +14319,7 @@ TraceRecorder::record_JSOP_GVARINC() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), 1, false)); + return InjectStatus(inc(globalObj->getSlotRef(slot), 1, false)); } JS_REQUIRES_STACK AbortableRecordingStatus @@ -14335,7 +14335,7 @@ TraceRecorder::record_JSOP_GVARDEC() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - return InjectStatus(inc(STOBJ_GET_SLOT(globalObj, slot), -1, false)); + return InjectStatus(inc(globalObj->getSlotRef(slot), -1, false)); } JS_REQUIRES_STACK AbortableRecordingStatus @@ -14826,7 +14826,7 @@ TraceRecorder::record_JSOP_CALLGVAR() if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - jsval& v = STOBJ_GET_SLOT(globalObj, slot); + jsval& v = globalObj->getSlotRef(slot); stack(0, get(&v)); stack(1, INS_NULL()); return ARECORD_CONTINUE; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 141a7f965789..48ec850f5673 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -71,6 +71,7 @@ #include "jsvector.h" #include "jscntxtinlines.h" +#include "jsobjinlines.h" #ifdef DEBUG #include /* for #ifdef DEBUG memset calls */ @@ -155,9 +156,9 @@ GetSlotString(const JSObject *obj, uint32 slot) JS_ASSERT(slot == JSSLOT_PREFIX || slot == JSSLOT_URI || slot == JSSLOT_LOCAL_NAME); - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NamespaceClass.base || - IsQNameClass(STOBJ_GET_CLASS(obj))); - JS_ASSERT_IF(STOBJ_GET_CLASS(obj) == &js_NamespaceClass.base, + JS_ASSERT(obj->getClass() == &js_NamespaceClass.base || + IsQNameClass(obj->getClass())); + JS_ASSERT_IF(obj->getClass() == &js_NamespaceClass.base, slot != JSSLOT_LOCAL_NAME); v = obj->fslots[slot]; @@ -190,7 +191,7 @@ IsDeclared(const JSObject *obj) { jsval v; - JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_NamespaceClass.base); + JS_ASSERT(obj->getClass() == &js_NamespaceClass.base); v = obj->fslots[JSSLOT_DECLARED]; JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE); return v == JSVAL_TRUE; @@ -226,7 +227,7 @@ namespace_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!JSVAL_IS_INT(id)) return JS_TRUE; - if (STOBJ_GET_CLASS(obj) != &js_NamespaceClass.base) + if (obj->getClass() != &js_NamespaceClass.base) return JS_TRUE; switch (JSVAL_TO_INT(id)) { @@ -334,7 +335,7 @@ qname_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!JSVAL_IS_INT(id)) return JS_TRUE; - if (STOBJ_GET_CLASS(obj) != &js_QNameClass.base) + if (obj->getClass() != &js_QNameClass.base) return JS_TRUE; switch (JSVAL_TO_INT(id)) { @@ -7284,7 +7285,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) JS_ASSERT(prop); sprop = (JSScopeProperty *) prop; JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))); - cval = OBJ_GET_SLOT(cx, pobj, sprop->slot); + cval = pobj->lockAndGetSlot(cx, sprop->slot); pobj->dropProperty(cx, prop); JS_ASSERT(VALUE_IS_FUNCTION(cx, cval)); diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp index 918dd1de4145..cabf29cc1e13 100644 --- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp @@ -316,7 +316,7 @@ ThrowException(nsresult rv, JSContext *cx) static inline JSObject * GetWrappedJSObject(JSContext *cx, JSObject *obj) { - JSClass *clasp = STOBJ_GET_CLASS(obj); + JSClass *clasp = obj->getClass(); if (!(clasp->flags & JSCLASS_IS_EXTENDED)) { return obj; } @@ -340,7 +340,7 @@ static inline JSObject * GetWrapper(JSObject *obj) { - while (STOBJ_GET_CLASS(obj) != &COWClass.base) { + while (obj->getClass() != &COWClass.base) { obj = obj->getProto(); if (!obj) { break; @@ -707,7 +707,7 @@ XPC_COW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) return ThrowException(NS_ERROR_FAILURE, cx); } - if (!STOBJ_GET_CLASS(wrappedObj)->convert(cx, wrappedObj, type, vp)) { + if (!wrappedObj->getClass()->convert(cx, wrappedObj, type, vp)) { return JS_FALSE; } @@ -752,7 +752,7 @@ XPC_COW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = me->GetFlatJSObject(); test = other->GetFlatJSObject(); - return ((JSExtendedClass *)STOBJ_GET_CLASS(obj))-> + return ((JSExtendedClass *)obj->getClass())-> equality(cx, obj, OBJECT_TO_JSVAL(test), bp); } diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 3e395f9ccbec..4cbdde35b0c2 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -125,7 +125,7 @@ static inline JSObject * GetWrapper(JSObject *obj) { - while (STOBJ_GET_CLASS(obj) != &XPCCrossOriginWrapper::XOWClass.base) { + while (obj->getClass() != &XPCCrossOriginWrapper::XOWClass.base) { obj = obj->getProto(); if (!obj) { break; @@ -354,7 +354,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) JSObject *wrappedObj; if (JSVAL_IS_PRIMITIVE(*vp) || !(wrappedObj = JSVAL_TO_OBJECT(*vp)) || - STOBJ_GET_CLASS(wrappedObj) == &XOWClass.base) { + wrappedObj->getClass() == &XOWClass.base) { return JS_TRUE; } @@ -368,7 +368,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) // The parent must be the inner global object for its scope. parent = JS_GetGlobalForObject(cx, parent); - JSClass *clasp = STOBJ_GET_CLASS(parent); + JSClass *clasp = parent->getClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { JSExtendedClass *xclasp = reinterpret_cast(clasp); if (xclasp->innerObject) { @@ -384,7 +384,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) #ifdef DEBUG_mrbkap_off printf("Wrapping object at %p (%s) [%p]\n", - (void *)wrappedObj, STOBJ_GET_CLASS(wrappedObj)->name, + (void *)wrappedObj, wrappedObj->getClass()->name, (void *)parentScope); #endif @@ -393,7 +393,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) outerObj = map->Find(wrappedObj); if (outerObj) { - NS_ASSERTION(STOBJ_GET_CLASS(outerObj) == &XOWClass.base, + NS_ASSERTION(outerObj->getClass() == &XOWClass.base, "What crazy object are we getting here?"); #ifdef DEBUG_mrbkap_off printf("But found a wrapper in the map %p!\n", (void *)outerObj); @@ -434,7 +434,7 @@ static JSBool IsValFrame(JSObject *obj, jsval v, XPCWrappedNative *wn) { // Fast path for the common case. - if (STOBJ_GET_CLASS(obj)->name[0] != 'W') { + if (obj->getClass()->name[0] != 'W') { return JS_FALSE; } @@ -530,7 +530,7 @@ WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp) } JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp); - JSClass *clasp = STOBJ_GET_CLASS(wrappedObj); + JSClass *clasp = wrappedObj->getClass(); if (ClassNeedsXOW(clasp->name)) { return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp); } @@ -682,7 +682,7 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); } rv = ssm->CheckPropertyAccess(cx, wrappedObj, - STOBJ_GET_CLASS(wrappedObj)->name, + wrappedObj->getClass()->name, id, isSet ? sSecMgrSetProp : sSecMgrGetProp); if (NS_FAILED(rv)) { @@ -805,7 +805,7 @@ XPC_XOW_Enumerate(JSContext *cx, JSObject *obj) static JSObject * GetUXPCObject(JSContext *cx, JSObject *obj) { - NS_ASSERTION(STOBJ_GET_CLASS(obj) == &XOWClass.base, "wrong object"); + NS_ASSERTION(obj->getClass() == &XOWClass.base, "wrong object"); jsval v; if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &v)) { @@ -895,7 +895,7 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, ? sSecMgrSetProp : sSecMgrGetProp; rv = ssm->CheckPropertyAccess(cx, wrappedObj, - STOBJ_GET_CLASS(wrappedObj)->name, + wrappedObj->getClass()->name, id, action); if (NS_FAILED(rv)) { // The security manager threw an exception for us. @@ -975,7 +975,7 @@ XPC_XOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) return JS_FALSE; } - if (!STOBJ_GET_CLASS(wrappedObj)->convert(cx, wrappedObj, type, vp)) { + if (!wrappedObj->getClass()->convert(cx, wrappedObj, type, vp)) { return JS_FALSE; } @@ -1111,7 +1111,7 @@ XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return JS_FALSE; } - JSClass *clasp = STOBJ_GET_CLASS(iface); + JSClass *clasp = iface->getClass(); *bp = JS_FALSE; if (!clasp->hasInstance) { @@ -1142,7 +1142,7 @@ XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } JSObject *test = JSVAL_TO_OBJECT(v); - if (STOBJ_GET_CLASS(test) == &XOWClass.base) { + if (test->getClass() == &XOWClass.base) { if (!JS_GetReservedSlot(cx, test, sWrappedObjSlot, &v)) { return JS_FALSE; } @@ -1169,7 +1169,7 @@ XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = me->GetFlatJSObject(); test = other->GetFlatJSObject(); - return ((JSExtendedClass *)STOBJ_GET_CLASS(obj))-> + return ((JSExtendedClass *)obj->getClass())-> equality(cx, obj, OBJECT_TO_JSVAL(test), bp); } @@ -1260,7 +1260,7 @@ XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); } rv = ssm->CheckPropertyAccess(cx, wrappedObj, - STOBJ_GET_CLASS(wrappedObj)->name, + wrappedObj->getClass()->name, GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING), nsIXPCSecurityManager::ACCESS_GET_PROPERTY); } diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 97b0037a5290..827621641cbe 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -262,7 +262,7 @@ RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval) // if (HAS_FLAGS(flags, FLAG_DEEP). if (HAS_FLAGS(flags, FLAG_DEEP) && !primitive) { // Unwrap a cross origin wrapper, since we're more restrictive. - if (STOBJ_GET_CLASS(nativeObj) == &XPCCrossOriginWrapper::XOWClass.base) { + if (nativeObj->getClass() == &XPCCrossOriginWrapper::XOWClass.base) { if (!::JS_GetReservedSlot(cx, nativeObj, sWrappedObjSlot, &v)) { return JS_FALSE; @@ -334,10 +334,10 @@ using namespace XPCNativeWrapper; // in the call from XPC_NW_Convert, for example. #define XPC_NW_CALL_HOOK(obj, hook, args) \ - return STOBJ_GET_CLASS(obj)->hook args; + return obj->getClass()->hook args; #define XPC_NW_CAST_HOOK(obj, type, hook, args) \ - return ((type) STOBJ_GET_CLASS(obj)->hook) args; + return ((type) obj->getClass()->hook) args; static JSBool ShouldBypassNativeWrapper(JSContext *cx, JSObject *obj) @@ -381,7 +381,7 @@ ShouldBypassNativeWrapper(JSContext *cx, JSObject *obj) #define XPC_NW_BYPASS_TEST(cx, obj, hook, args) \ XPC_NW_BYPASS_BASE(cx, obj, \ - JSClass *clasp_ = STOBJ_GET_CLASS(obj); \ + JSClass *clasp_ = obj->getClass(); \ return !clasp_->hook || clasp_->hook args; \ ) @@ -445,7 +445,7 @@ EnsureLegalActivity(JSContext *cx, JSObject *obj, (accessType & (sSecMgrSetProp | sSecMgrGetProp)) && (flatObj = wn->GetFlatJSObject())) { rv = ssm->CheckPropertyAccess(cx, flatObj, - STOBJ_GET_CLASS(flatObj)->name, + flatObj->getClass()->name, id, accessType); return NS_SUCCEEDED(rv); } @@ -846,7 +846,7 @@ XPC_NW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSObject *wrapperJSObject = wrappedNative->GetFlatJSObject(); - JSClass *clazz = STOBJ_GET_CLASS(wrapperJSObject); + JSClass *clazz = wrapperJSObject->getClass(); return !clazz->checkAccess || clazz->checkAccess(cx, wrapperJSObject, id, mode, vp); } diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 074cb8e4594e..98e3db884c1e 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -213,7 +213,7 @@ FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj) static inline JSObject * FindSafeObject(JSObject *obj) { - while (STOBJ_GET_CLASS(obj) != &SJOWClass.base) { + while (obj->getClass() != &SJOWClass.base) { obj = obj->getProto(); if (!obj) { @@ -692,7 +692,7 @@ XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, return JS_FALSE; } - JSClass *clazz = STOBJ_GET_CLASS(unsafeObj); + JSClass *clazz = unsafeObj->getClass(); return !clazz->checkAccess || clazz->checkAccess(cx, unsafeObj, id, mode, vp); } @@ -804,7 +804,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, // with XPCSafeJSObjectWrapper, and never let the eval function // object be directly wrapped. - if (STOBJ_GET_CLASS(objToWrap) == &js_ScriptClass || + if (objToWrap->getClass() == &js_ScriptClass || (::JS_ObjectIsFunction(cx, objToWrap) && ::JS_GetFunctionFastNative(cx, ::JS_ValueToFunction(cx, argv[0])) == XPCWrapper::sEvalNative)) { diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index b4c62f09aeac..c2f89cbc418e 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -223,7 +223,7 @@ using namespace SystemOnlyWrapper; static inline JSObject * GetWrappedJSObject(JSContext *cx, JSObject *obj) { - JSClass *clasp = STOBJ_GET_CLASS(obj); + JSClass *clasp = obj->getClass(); if (!(clasp->flags & JSCLASS_IS_EXTENDED)) { return obj; } @@ -241,7 +241,7 @@ static inline JSObject * GetWrapper(JSObject *obj) { - while (STOBJ_GET_CLASS(obj) != &SOWClass.base) { + while (obj->getClass() != &SOWClass.base) { obj = obj->getProto(); if (!obj) { break; @@ -360,7 +360,7 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp) return XPC_SOW_WrapFunction(cx, wrapperObj, obj, vp); } - if (STOBJ_GET_CLASS(obj) == &SOWClass.base) { + if (obj->getClass() == &SOWClass.base) { // We are extra careful about content-polluted wrappers here. I don't know // if it's possible to reach them through objects that we wrap, but figuring // that out is more expensive (and harder) than simply checking and @@ -385,7 +385,7 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp) static JSBool XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - NS_ASSERTION(STOBJ_GET_CLASS(obj) == &SOWClass.base, "Wrong object"); + NS_ASSERTION(obj->getClass() == &SOWClass.base, "Wrong object"); jsval resolving; if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) { @@ -533,7 +533,7 @@ XPC_SOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) return JS_TRUE; } - return STOBJ_GET_CLASS(wrappedObj)->convert(cx, wrappedObj, type, vp); + return wrappedObj->getClass()->convert(cx, wrappedObj, type, vp); } static JSBool @@ -568,7 +568,7 @@ XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return JS_TRUE; } - JSClass *clasp = STOBJ_GET_CLASS(iface); + JSClass *clasp = iface->getClass(); *bp = JS_FALSE; if (!clasp->hasInstance) { @@ -614,7 +614,7 @@ XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) if (lhs) { // Delegate to our wrapped object if we can. - JSClass *clasp = STOBJ_GET_CLASS(lhs); + JSClass *clasp = lhs->getClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { JSExtendedClass *xclasp = (JSExtendedClass *) clasp; // NB: JSExtendedClass.equality is a required field. @@ -623,7 +623,7 @@ XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } // We know rhs is non-null. - JSClass *clasp = STOBJ_GET_CLASS(rhs); + JSClass *clasp = rhs->getClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { JSExtendedClass *xclasp = (JSExtendedClass *) clasp; // NB: JSExtendedClass.equality is a required field. diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index 351b42827aac..8e0391bb6be6 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -59,7 +59,7 @@ const PRUint32 sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY; JSObject * Unwrap(JSContext *cx, JSObject *wrapper) { - JSClass *clasp = STOBJ_GET_CLASS(wrapper); + JSClass *clasp = wrapper->getClass(); if (clasp == &XPCCrossOriginWrapper::XOWClass.base) { return UnwrapXOW(cx, wrapper); } diff --git a/js/src/xpconnect/src/XPCWrapper.h b/js/src/xpconnect/src/XPCWrapper.h index c0002ac4bd5f..d01a800c69c3 100644 --- a/js/src/xpconnect/src/XPCWrapper.h +++ b/js/src/xpconnect/src/XPCWrapper.h @@ -285,7 +285,7 @@ MaybePreserveWrapper(JSContext *cx, XPCWrappedNative *wn, uintN flags) inline JSBool IsSecurityWrapper(JSObject *wrapper) { - JSClass *clasp = STOBJ_GET_CLASS(wrapper); + JSClass *clasp = wrapper->getClass(); return (clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*)clasp)->wrappedObject; } @@ -309,7 +309,7 @@ Unwrap(JSContext *cx, JSObject *wrapper); inline JSObject * UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp, JSObject *wrapper) { - if (STOBJ_GET_CLASS(wrapper) != &xclasp->base) { + if (wrapper->getClass() != &xclasp->base) { return nsnull; } diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index ab219592389d..41c7c695094b 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -1949,7 +1949,7 @@ nsXPConnect::RestoreWrappedNativePrototype(JSContext * aJSContext, if(NS_FAILED(rv)) return UnexpectedFailure(rv); - if(!IS_PROTO_CLASS(STOBJ_GET_CLASS(protoJSObject))) + if(!IS_PROTO_CLASS(protoJSObject->getClass())) return UnexpectedFailure(NS_ERROR_INVALID_ARG); XPCWrappedNativeScope* scope = @@ -2541,7 +2541,7 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext, JSBool sameOrigin; JSBool sameScope = xpc_SameScope(objectscope, xpcscope, &sameOrigin); JSBool forceXOW = - XPCCrossOriginWrapper::ClassNeedsXOW(STOBJ_GET_CLASS(aObject)->name); + XPCCrossOriginWrapper::ClassNeedsXOW(aObject->getClass()->name); // We can do nothing if: // - We're wrapping a system object @@ -2747,7 +2747,7 @@ nsXPConnect::SetSafeJSContext(JSContext * aSafeJSContext) nsIPrincipal* nsXPConnect::GetPrincipal(JSObject* obj, PRBool allowShortCircuit) const { - NS_ASSERTION(IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)), + NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()), "What kind of wrapper is this?"); if(IS_WN_WRAPPER_OBJECT(obj)) diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 2405f50b527a..cc0061748bce 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -3546,7 +3546,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, const char *filename, PRInt32 lineNo, JSVersion jsVersion, PRBool returnStringOnly, jsval *rval) { - if (STOBJ_GET_CLASS(sandbox) != &SandboxClass) + if (sandbox->getClass() != &SandboxClass) return NS_ERROR_INVALID_ARG; nsIScriptObjectPrincipal *sop = diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index f02832feffe7..eee4378062e3 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -153,7 +153,7 @@ XPCConvert::IsMethodReflectable(const XPTMethodDescriptor& info) JSBool XPCConvert::GetISupportsFromJSObject(JSObject* obj, nsISupports** iface) { - JSClass* jsclass = STOBJ_GET_CLASS(obj); + JSClass* jsclass = obj->getClass(); NS_ASSERTION(jsclass, "obj has no class"); if(jsclass && (jsclass->flags & JSCLASS_HAS_PRIVATE) && @@ -474,7 +474,7 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s, #ifdef DEBUG JSObject* jsobj = JSVAL_TO_OBJECT(*d); if(jsobj && !jsobj->getParent()) - NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL, + NS_ASSERTION(jsobj->getClass()->flags & JSCLASS_IS_GLOBAL, "Why did we recreate this wrapper?"); #endif } @@ -1185,7 +1185,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, } } - NS_ASSERTION(!flat || IS_WRAPPER_CLASS(STOBJ_GET_CLASS(flat)), + NS_ASSERTION(!flat || IS_WRAPPER_CLASS(flat->getClass()), "What kind of wrapper is this?"); nsresult rv; @@ -1397,7 +1397,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, } } - const char *name = STOBJ_GET_CLASS(flat)->name; + const char *name = flat->getClass()->name; if(allowNativeWrapper && !(flags & JSFILENAME_SYSTEM) && !JS_IsSystemObject(ccx, flat) && diff --git a/js/src/xpconnect/src/xpcdebug.cpp b/js/src/xpconnect/src/xpcdebug.cpp index fc40f8e41516..6dff5c49cf8c 100644 --- a/js/src/xpconnect/src/xpcdebug.cpp +++ b/js/src/xpconnect/src/xpcdebug.cpp @@ -428,7 +428,7 @@ static void PrintObjectBasics(JSObject* obj) { if(OBJ_IS_NATIVE(obj)) printf("%p 'native' <%s>", - (void *)obj, STOBJ_GET_CLASS(obj)->name); + (void *)obj, obj->getClass()->name); else printf("%p 'host'", (void *)obj); } diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 7097c6b6a1dd..512b34101dca 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -1356,7 +1356,7 @@ xpc_InitWrappedNativeJSOps(); inline JSBool DebugCheckWrapperClass(JSObject* obj) { - NS_ASSERTION(IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)), + NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()), "Forgot to check if this is a wrapper?"); return JS_TRUE; } @@ -1367,21 +1367,21 @@ DebugCheckWrapperClass(JSObject* obj) // also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can // check that slot for a non-void value to distinguish between the two. -// Only use these macros if IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)) is true. +// Only use these macros if IS_WRAPPER_CLASS(obj->getClass()) is true. #define IS_WN_WRAPPER_OBJECT(obj) \ (DebugCheckWrapperClass(obj) && \ - JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, JSSLOT_START(STOBJ_GET_CLASS(obj))))) + JSVAL_IS_VOID(obj->getSlot(JSSLOT_START(obj->getClass())))) #define IS_SLIM_WRAPPER_OBJECT(obj) \ (DebugCheckWrapperClass(obj) && \ - !JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, JSSLOT_START(STOBJ_GET_CLASS(obj))))) + !JSVAL_IS_VOID(obj->getSlot(JSSLOT_START(obj->getClass())))) -// Use these macros if IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)) might be false. -// Avoid calling them if IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)) can only be +// Use these macros if IS_WRAPPER_CLASS(obj->getClass()) might be false. +// Avoid calling them if IS_WRAPPER_CLASS(obj->getClass()) can only be // true, as we'd do a redundant call to IS_WRAPPER_CLASS. #define IS_WN_WRAPPER(obj) \ - (IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)) && IS_WN_WRAPPER_OBJECT(obj)) + (IS_WRAPPER_CLASS(obj->getClass()) && IS_WN_WRAPPER_OBJECT(obj)) #define IS_SLIM_WRAPPER(obj) \ - (IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)) && IS_SLIM_WRAPPER_OBJECT(obj)) + (IS_WRAPPER_CLASS(obj->getClass()) && IS_SLIM_WRAPPER_OBJECT(obj)) // Comes from xpcwrappednativeops.cpp extern void @@ -2238,7 +2238,7 @@ extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj); static inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj) { - jsval v = STOBJ_GET_SLOT(obj, JSSLOT_START(STOBJ_GET_CLASS(obj))); + jsval v = obj->getSlot(JSSLOT_START(obj->getClass())); return static_cast(JSVAL_TO_PRIVATE(v)); } diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index 511365ce00d9..cd614a041247 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -293,7 +293,7 @@ LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, uintN argc, jsval *vp) ? JS_GetStringBytes(JSVAL_TO_STRING(idval)) : nsnull; if(!name || - !IS_PROTO_CLASS(STOBJ_GET_CLASS(desc.obj)) || + !IS_PROTO_CLASS(desc.obj->getClass()) || (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) || !(desc.getter || desc.setter)) { @@ -362,7 +362,7 @@ DefineGetterOrSetter(JSContext *cx, uintN argc, JSBool wantGetter, jsval *vp) if(!obj2 || (attrs & (JSPROP_GETTER | JSPROP_SETTER)) || !(getter || setter) || - !IS_PROTO_CLASS(STOBJ_GET_CLASS(obj2))) + !IS_PROTO_CLASS(obj2->getClass())) return forward(cx, argc, vp); // Reify the getter and setter... @@ -503,8 +503,8 @@ GetMemberInfo(JSObject *obj, // but this code often produces a more specific error message, e.g. *ifaceName = "Unknown"; - NS_ASSERTION(IS_WRAPPER_CLASS(STOBJ_GET_CLASS(obj)) || - STOBJ_GET_CLASS(obj) == &XPC_WN_Tearoff_JSClass, + NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()) || + obj->getClass() == &XPC_WN_Tearoff_JSClass, "obj must be a wrapper"); XPCWrappedNativeProto *proto; if(IS_SLIM_WRAPPER(obj)) @@ -1092,7 +1092,7 @@ xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, nsISupports *p, #ifdef DEBUG JSObject* jsobj = JSVAL_TO_OBJECT(*rval); if(jsobj && !jsobj->getParent()) - NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL, + NS_ASSERTION(jsobj->getClass()->flags & JSCLASS_IS_GLOBAL, "Why did we recreate this wrapper?"); #endif diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 43b75e0aa1b0..2d7e244e9193 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -779,7 +779,7 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self, PRBool isSystem; rv = secMan->IsSystemPrincipal(objPrin, &isSystem); if((NS_FAILED(rv) || !isSystem) && - !IS_WRAPPER_CLASS(STOBJ_GET_CLASS(selfObj))) + !IS_WRAPPER_CLASS(selfObj->getClass())) { // A content object. nsRefPtr checked = diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 12bd98d84692..5a06fc593607 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -1638,7 +1638,7 @@ XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx, JSObject* funObjParent = funobj->getParent(); NS_ASSERTION(funObjParent, "funobj has no parent"); - JSClass* funObjParentClass = STOBJ_GET_CLASS(funObjParent); + JSClass* funObjParentClass = funObjParent->getClass(); if(IS_PROTO_CLASS(funObjParentClass)) { @@ -1669,7 +1669,7 @@ XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx, { // this is on two lines to make the compiler happy given the goto. JSClass* clazz; - clazz = STOBJ_GET_CLASS(cur); + clazz = cur->getClass(); if(IS_WRAPPER_CLASS(clazz)) { @@ -1726,7 +1726,7 @@ return_tearoff: // If we didn't find a wrapper using the given funobj and obj, try // again with obj's outer object, if it's got one. - JSClass *clazz = STOBJ_GET_CLASS(obj); + JSClass *clazz = obj->getClass(); if((clazz->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*)clazz)->outerObject) @@ -1735,7 +1735,7 @@ return_tearoff: // Protect against infinite recursion through XOWs. JSObject *unsafeObj; - clazz = STOBJ_GET_CLASS(outer); + clazz = outer->getClass(); if(clazz == &XPCCrossOriginWrapper::XOWClass.base && (unsafeObj = XPCWrapper::UnwrapXOW(cx, outer))) { diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 75964e97386c..551ede0a388d 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -853,7 +853,7 @@ XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return Throw(rv, cx); if(!*bp && !JSVAL_IS_PRIMITIVE(v) && - STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v)) == &XPCSafeJSObjectWrapper::SJOWClass.base) + JSVAL_TO_OBJECT(v)->getClass() == &XPCSafeJSObjectWrapper::SJOWClass.base) { v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(cx, JSVAL_TO_OBJECT(v))); @@ -1327,7 +1327,7 @@ static JSBool XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp) { - JSClass *clazz = STOBJ_GET_CLASS(obj); + JSClass *clazz = obj->getClass(); if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { // obj must be a prototype object or a wrapper w/o a diff --git a/js/src/xpconnect/src/xpcwrappednativescope.cpp b/js/src/xpconnect/src/xpcwrappednativescope.cpp index ab5761b3b2ae..f6d153cb65a4 100644 --- a/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -240,7 +240,7 @@ XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal) mScriptObjectPrincipal = nsnull; // Now init our script object principal, if the new global has one - const JSClass* jsClass = STOBJ_GET_CLASS(aGlobal); + const JSClass* jsClass = aGlobal->getClass(); if(!(~jsClass->flags & (JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS))) { @@ -719,7 +719,7 @@ XPCWrappedNativeScope* GetScopeOfObject(JSObject* obj) { nsISupports* supports; - JSClass* clazz = STOBJ_GET_CLASS(obj); + JSClass* clazz = obj->getClass(); JSBool isWrapper = IS_WRAPPER_CLASS(clazz); if(isWrapper && IS_SLIM_WRAPPER_OBJECT(obj)) From de52f61320c3b8dee017a44e3d4cb0100147fea2 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Tue, 30 Mar 2010 16:43:42 -0700 Subject: [PATCH 180/213] b=555807; typed array native constructor fix; r=jorendorff --- js/src/jstypedarray.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index e4d740458bed..74ebf1b9155a 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1397,7 +1397,8 @@ JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { AutoValueRooter tvr(cx); - js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr()); + if (!js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr())) + return NULL; AutoValueRooter rval(cx); if (!ArrayBuffer::class_constructor(cx, cx->globalObject, @@ -1484,8 +1485,7 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, { JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg)); - /* if byteoffset is -1, length must be -1 */ - JS_ASSERT(length < 0 || byteoffset >= 0); + JS_ASSERT_IF(byteoffset < 0, length < 0); jsval vals[4]; AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); @@ -1494,17 +1494,19 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, vals[0] = OBJECT_TO_JSVAL(bufArg); if (byteoffset >= 0) { - js_NewNumberInRootedValue(cx, jsdouble(byteoffset), &vals[1]); + if (!js_NewNumberInRootedValue(cx, jsdouble(byteoffset), &vals[argc])) + return NULL; + argc++; } if (length >= 0) { - js_NewNumberInRootedValue(cx, jsdouble(length), &vals[1]); + if (!js_NewNumberInRootedValue(cx, jsdouble(length), &vals[argc])) + return NULL; + argc++; } - js_NewNumberInRootedValue(cx, jsdouble(byteoffset), &vals[0]); - if (!TypedArrayConstruct(cx, atype, argc, &vals[0], &vals[3])) return NULL; From f96ceb99e09aa9b306b995227e7aa54b7b8e6fe2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Mar 2010 18:06:38 -0700 Subject: [PATCH 181/213] Bug 555881 - TM: remove dead fields from TraceMonitor. r=waldo. --- js/src/jscntxt.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index e9ee1611a9ea..d5005755c510 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -414,13 +414,6 @@ struct TraceMonitor { */ JSBool needFlush; - /* - * reservedObjects is a linked list (via fslots[0]) of preallocated JSObjects. - * The JIT uses this to ensure that leaving a trace tree can't fail. - */ - JSBool useReservedObjects; - JSObject *reservedObjects; - /* * Fragment map for the regular expression compiler. */ From 15973b4a9c2e306d83066f9c2db629122919c4df Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Mar 2010 20:19:41 -0700 Subject: [PATCH 182/213] Don't pointlessly set fslots[JSSLOT_ARRAY_COUNT] to a integer jsval when converting a dense array to a slow array. no bug, r=brendan via IRC. --- js/src/jsarray.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 720454d9ca1f..5e834b5d8aeb 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1338,21 +1338,14 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj) } /* - * Render our formerly-reserved count property GC-safe. If length fits in - * a jsval, set our slow/sparse COUNT to the current length as a jsval, so - * we can tell when only named properties have been added to a dense array - * to make it slow-but-not-sparse. - * + * Render our formerly-reserved count property GC-safe. * We do not need to make the length slot GC-safe as this slot is private * where the implementation can store an arbitrary value. */ { JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE); JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE); - uint32 length = uint32(obj->fslots[JSSLOT_ARRAY_LENGTH]); - obj->fslots[JSSLOT_ARRAY_COUNT] = INT_FITS_IN_JSVAL(length) - ? INT_TO_JSVAL(length) - : JSVAL_VOID; + obj->fslots[JSSLOT_ARRAY_COUNT] = JSVAL_VOID; } /* Make sure we preserve any flags borrowing bits in classword. */ From 026c662142a34dfcaf4f64d2d57d52ba474e41e9 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Wed, 31 Mar 2010 08:21:07 -0700 Subject: [PATCH 183/213] Fix merge bustage. --- content/base/src/nsContentUtils.cpp | 6 ++-- js/ctypes/CTypes.cpp | 26 +++++++-------- js/ctypes/Library.cpp | 2 +- js/src/jsstr.cpp | 3 +- js/src/jstracer.cpp | 32 +------------------ .../xpconnect/src/XPCSafeJSObjectWrapper.cpp | 4 +-- js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp | 2 +- js/src/xpconnect/src/XPCWrapper.cpp | 2 +- js/src/xpconnect/src/xpccomponents.cpp | 2 +- js/src/xpconnect/src/xpcquickstubs.cpp | 2 +- 10 files changed, 25 insertions(+), 56 deletions(-) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 9c2bbd9e5e19..282afa86dbbf 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -5407,7 +5407,7 @@ public: jsval source; jsval clone; jsval temp; - JSAutoIdArray ids; + js::AutoIdArray ids; jsuint index; private: @@ -5425,7 +5425,7 @@ private: } CloneStackFrame* prevFrame; - JSAutoTempValueRooter tvrVals; + js::AutoArrayRooter tvrVals; }; class CloneStack @@ -5691,7 +5691,7 @@ nsContentUtils::CreateStructuredClone(JSContext* cx, } jsval output = OBJECT_TO_JSVAL(obj); - JSAutoTempValueRooter tvr(cx, output); + js::AutoValueRooter tvr(cx, output); CloneStack stack(cx); if (!stack.Push(val, OBJECT_TO_JSVAL(obj), diff --git a/js/ctypes/CTypes.cpp b/js/ctypes/CTypes.cpp index 2f61649548d0..91cc9d767bb0 100644 --- a/js/ctypes/CTypes.cpp +++ b/js/ctypes/CTypes.cpp @@ -663,7 +663,7 @@ InitTypeConstructor(JSContext* cx, dataProto = JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent); if (!dataProto) return false; - JSAutoTempValueRooter protoroot(cx, dataProto); + js::AutoValueRooter protoroot(cx, dataProto); // Define functions and properties on the 'dataProto' object that are common // to all CData objects created from this type constructor. (These will @@ -797,25 +797,25 @@ InitTypeClasses(JSContext* cx, JSObject* parent) sPointerInstanceProps, protos[SLOT_POINTERPROTO], protos[SLOT_POINTERDATAPROTO])) return false; - JSAutoTempValueRooter proot(cx, protos[SLOT_POINTERDATAPROTO]); + js::AutoValueRooter proot(cx, protos[SLOT_POINTERDATAPROTO]); if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, sArrayFunction, sArrayProps, sArrayInstanceFunctions, sArrayInstanceProps, protos[SLOT_ARRAYPROTO], protos[SLOT_ARRAYDATAPROTO])) return false; - JSAutoTempValueRooter aroot(cx, protos[SLOT_ARRAYDATAPROTO]); + js::AutoValueRooter aroot(cx, protos[SLOT_ARRAYDATAPROTO]); if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, sStructFunction, sStructProps, sStructInstanceFunctions, NULL, protos[SLOT_STRUCTPROTO], protos[SLOT_STRUCTDATAPROTO])) return false; - JSAutoTempValueRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]); + js::AutoValueRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]); if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, sFunctionFunction, sFunctionProps, NULL, NULL, protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO])) return false; - JSAutoTempValueRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]); + js::AutoValueRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]); protos[SLOT_CDATAPROTO] = CDataProto; @@ -3787,7 +3787,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) js_NewArrayObjectWithCapacity(cx, len, &fieldsVec); if (!fieldsProp) return JS_FALSE; - JSAutoTempValueRooter root(cx, fieldsProp); + js::AutoValueRooter root(cx, fieldsProp); JS_ASSERT(len == 0 || fieldsVec); nsAutoPtr ffiType(new ffi_type); @@ -4366,7 +4366,7 @@ FunctionType::Create(JSContext* cx, uintN argc, jsval* vp) // Pull out the argument types from the array, if any. JS_ASSERT(!argTypes.Length() || arrayObj); - JSAutoTempValueRooter items(cx, argTypes.Length(), argTypes.Elements()); + js::AutoArrayRooter items(cx, argTypes.Length(), argTypes.Elements()); for (jsuint i = 0; i < argTypes.Length(); ++i) { if (!JS_GetElement(cx, arrayObj, i, &argTypes[i])) return JS_FALSE; @@ -4407,7 +4407,7 @@ FunctionType::CreateInternal(JSContext* cx, &ffi_type_pointer, NULL); if (!typeObj) return NULL; - JSAutoTempValueRooter root(cx, typeObj); + js::AutoValueRooter root(cx, typeObj); // Stash the FunctionInfo in a reserved slot. if (!JS_SetReservedSlot(cx, typeObj, SLOT_FNINFO, @@ -4467,7 +4467,7 @@ FunctionType::ConstructData(JSContext* cx, JSObject* closureObj = CClosure::Create(cx, obj, fnObj, thisObj, data); if (!closureObj) return JS_FALSE; - JSAutoTempValueRooter root(cx, closureObj); + js::AutoValueRooter root(cx, closureObj); // Set the closure object as the referent of the new CData object. if (!JS_SetReservedSlot(cx, result, SLOT_REFERENT, @@ -4612,7 +4612,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v js_NewArrayObjectWithCapacity(cx, len, &vec); if (!argTypes) return JS_FALSE; - JSAutoTempValueRooter argsroot(cx, argTypes); + js::AutoValueRooter argsroot(cx, argTypes); JS_ASSERT(len == 0 || vec); for (PRUint32 i = 0; i < len; ++i) @@ -4667,7 +4667,7 @@ CClosure::Create(JSContext* cx, JSObject* result = JS_NewObject(cx, &sCClosureClass, NULL, NULL); if (!result) return NULL; - JSAutoTempValueRooter root(cx, result); + js::AutoValueRooter root(cx, result); // Get the FunctionInfo from the FunctionType. FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); @@ -4813,7 +4813,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) JS_ASSERT(cif == &fninfo->mCIF); // Get a death grip on 'closureObj'. - JSAutoTempValueRooter root(cx, cinfo->closureObj); + js::AutoValueRooter root(cx, cinfo->closureObj); // Set up an array for converted arguments. nsAutoTArray argv; @@ -4825,7 +4825,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) for (PRUint32 i = 0; i < cif->nargs; ++i) argv[i] = JSVAL_VOID; - JSAutoTempValueRooter roots(cx, argv.Length(), argv.Elements()); + js::AutoArrayRooter roots(cx, argv.Length(), argv.Elements()); for (PRUint32 i = 0; i < cif->nargs; ++i) { // Convert each argument, and have any CData objects created depend on // the existing buffers. diff --git a/js/ctypes/Library.cpp b/js/ctypes/Library.cpp index 34731c901f04..4bc3977b79bc 100644 --- a/js/ctypes/Library.cpp +++ b/js/ctypes/Library.cpp @@ -264,7 +264,7 @@ Library::Declare(JSContext* cx, uintN argc, jsval* vp) argv[1], argv[2], &argv[3], argc - 3); if (!typeObj) return JS_FALSE; - JSAutoTempValueRooter root(cx, typeObj); + js::AutoValueRooter root(cx, typeObj); JSObject* fn = CData::Create(cx, typeObj, obj, &func, true); if (!fn) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 9b68ba52479b..bb6284ea7f5f 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1170,8 +1170,7 @@ StringMatch(const jschar *text, jsuint textlen, if (textlen < patlen) return -1; -#if defined(__i386__) || defined(_M_IX86) -#if defined(__i386__) || defined(__i386) +#if defined(__i386__) || defined(_M_IX86) || defined(__i386) /* * Given enough registers, the unrolled loop below is faster than the * following loop. 32-bit x86 does not have enough registers. diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 060d1cf83816..27b4e87089bf 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -12056,37 +12056,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) avmplus::AvmCore::use_cmov()), avmplus::AvmCore::use_cmov()); } else { - switch (tarray->type) { - case js::TypedArray::TYPE_INT8: - case js::TypedArray::TYPE_UINT8: - addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - lir->insStore(LIR_stb, lir->ins1(LIR_f2i, v_ins), addr_ins, 0); - break; - case js::TypedArray::TYPE_INT16: - case js::TypedArray::TYPE_UINT16: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 1)); - lir->insStore(LIR_sts, lir->ins1(LIR_f2i, v_ins), addr_ins, 0); - break; - case js::TypedArray::TYPE_INT32: - case js::TypedArray::TYPE_UINT32: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_sti, lir->ins1(LIR_f2i, v_ins), addr_ins, 0); - break; - case js::TypedArray::TYPE_FLOAT32: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 2)); - lir->insStore(LIR_st32f, v_ins, addr_ins, 0); - break; - case js::TypedArray::TYPE_FLOAT64: - addr_ins = lir->ins2(LIR_piadd, data_ins, lir->ins2i(LIR_pilsh, pidx_ins, 3)); - lir->insStore(LIR_stfi, v_ins, addr_ins, 0); - break; - case js::TypedArray::TYPE_UINT8_CLAMPED: - addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins); - lir->insStore(LIR_stb, lir->insCall(&js_TypedArray_uint8_clamp_double_ci, &v_ins), addr_ins, 0); - break; - default: - JS_NOT_REACHED("Unknown typed array type in tracer"); - } + v_ins = lir->insCall(&js_TypedArray_uint8_clamp_double_ci, &v_ins); } break; case js::TypedArray::TYPE_FLOAT32: diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 7e3293041de5..3926f146e290 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -285,7 +285,7 @@ WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp) // with XPCSafeJSObjectWrapper, and never let the eval function // object be directly wrapped. - if (STOBJ_GET_CLASS(objToWrap) == &js_ScriptClass || + if (objToWrap->getClass() == &js_ScriptClass || (JS_ObjectIsFunction(cx, objToWrap) && JS_GetFunctionFastNative(cx, JS_ValueToFunction(cx, v)) == XPCWrapper::sEvalNative)) { @@ -406,7 +406,7 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval) // parent we pass in here, the construct hook will ensure we get // the right parent for the wrapper. JSObject *safeObj = JSVAL_TO_OBJECT(*rval); - if (STOBJ_GET_CLASS(safeObj) == &SJOWClass.base && + if (safeObj->getClass() == &SJOWClass.base && JS_GetGlobalForObject(cx, obj) != JS_GetGlobalForObject(cx, safeObj)) { // Check to see if the new object we just wrapped is accessible // from the unsafe object we got the new object through. If not, diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index 868dc302ab23..b77c13dbbfa5 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -154,7 +154,7 @@ MakeSOW(JSContext *cx, JSObject *obj) { #ifdef DEBUG { - JSClass *clasp = STOBJ_GET_CLASS(obj); + JSClass *clasp = obj->getClass(); NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass.base && clasp != &XPCCrossOriginWrapper::XOWClass.base && strcmp(clasp->name, "XPCNativeWrapper"), diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index 209f9d233d4b..909cd6efe2b9 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -386,7 +386,7 @@ CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly, return nsnull; } - JSAutoTempValueRooter tvr(cx, iterObj); + js::AutoValueRooter tvr(cx, iterObj); if (!propertyContainer) { if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull)) || !JS_SetReservedSlot(cx, iterObj, 1, JSVAL_ZERO) || diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 17d6b184e1ff..35513279d4bf 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -3221,7 +3221,7 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop) nsnull, nsnull); if (!sandbox) return NS_ERROR_XPC_UNEXPECTED; - JSAutoTempValueRooter tvr(cx, sandbox); + js::AutoValueRooter tvr(cx, sandbox); nsCOMPtr sop(do_QueryInterface(prinOrSop)); diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index 90be0c3e64ae..92ea4a741ef0 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -296,7 +296,7 @@ LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, uintN argc, jsval *vp) !IS_PROTO_CLASS(desc.obj->getClass()) || (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) || !(desc.getter || desc.setter) || - desc.setter == STOBJ_GET_CLASS(desc.obj)->setProperty) + desc.setter == desc.obj->getClass()->setProperty) { JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; From e93fde945d9bb8d1c1155ff6dc11df4ca4c5981c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Mar 2010 15:07:50 -0700 Subject: [PATCH 184/213] Bug 555633 - nanojit: rename opcodes in LIRopcode.tbl. r=edwsmith. --HG-- extra : convert_revision : e09eec330c04cfbf3da745635c67f2fc3fee6c28 --- js/src/lirasm/lirasm.cpp | 5 +- js/src/lirasm/tests/add.in | 8 +- js/src/lirasm/tests/addsub.in | 10 +- js/src/lirasm/tests/call1.in | 24 +- js/src/lirasm/tests/call2.in | 10 +- js/src/lirasm/tests/f2i.in | 12 +- js/src/lirasm/tests/floatingpoint.in | 8 +- js/src/lirasm/tests/fuzz-527178.in | 10 +- js/src/lirasm/tests/loadstore.in | 18 +- js/src/lirasm/tests/mul_xxx.in | 8 +- js/src/lirasm/tests/mul_xxy.in | 10 +- js/src/lirasm/tests/mul_xyy.in | 10 +- js/src/lirasm/tests/mul_xyz.in | 14 +- js/src/lirasm/tests/mulov_xxx.in | 8 +- js/src/lirasm/tests/mulov_xxy.in | 10 +- js/src/lirasm/tests/mulov_xyy.in | 10 +- js/src/lirasm/tests/mulov_xyz.in | 14 +- js/src/lirasm/tests/multfrag1.in | 36 +-- js/src/lirasm/tests/multfrag2.in | 18 +- js/src/lirasm/tests/multfrag3.in | 20 +- js/src/nanojit/LIR.cpp | 24 ++ js/src/nanojit/LIR.h | 247 ++++++++++++++++-- js/src/nanojit/LIRopcode.tbl | 375 +++++++++++++++------------ 23 files changed, 601 insertions(+), 308 deletions(-) diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp index 25bef4e89c11..72720ffa7b5f 100644 --- a/js/src/lirasm/lirasm.cpp +++ b/js/src/lirasm/lirasm.cpp @@ -1975,8 +1975,9 @@ Lirasm::Lirasm(bool verbose) : #include "nanojit/LIRopcode.tbl" #undef OP___ - mOpMap["alloc"] = mOpMap[PTR_SIZE("ialloc", "qalloc")]; - mOpMap["param"] = mOpMap[PTR_SIZE("iparam", "qparam")]; + // XXX: could add more pointer-sized synonyms here + mOpMap["allocp"] = mOpMap[PTR_SIZE("allocl", "allocq")]; + mOpMap["paramp"] = mOpMap[PTR_SIZE("paraml", "paramq")]; } Lirasm::~Lirasm() diff --git a/js/src/lirasm/tests/add.in b/js/src/lirasm/tests/add.in index 48479f9eb710..35bfa38c53fc 100644 --- a/js/src/lirasm/tests/add.in +++ b/js/src/lirasm/tests/add.in @@ -1,4 +1,4 @@ -two = int 2 -three = int 3 -res = add two three -ret res +two = imml 2 +three = imml 3 +res = addl two three +retl res diff --git a/js/src/lirasm/tests/addsub.in b/js/src/lirasm/tests/addsub.in index 2aec24d869dd..9752a2fe4334 100644 --- a/js/src/lirasm/tests/addsub.in +++ b/js/src/lirasm/tests/addsub.in @@ -1,5 +1,5 @@ -two = int 7 -three = int 3 -targ = add two three -res = sub targ three -ret res +two = imml 7 +three = imml 3 +targ = addl two three +res = subl targ three +retl res diff --git a/js/src/lirasm/tests/call1.in b/js/src/lirasm/tests/call1.in index a42e7396e17e..d3e80f06e69b 100644 --- a/js/src/lirasm/tests/call1.in +++ b/js/src/lirasm/tests/call1.in @@ -1,12 +1,12 @@ -ptr = alloc 8 -a = int 65 -sti a ptr 0 -b = int 66 -sti b ptr 1 -c = int 67 -sti c ptr 2 -zero = int 0 -sti zero ptr 3 -ss = icall puts cdecl ptr -nn = ge ss zero -ret nn +ptr = allocp 8 +a = imml 65 +stl a ptr 0 +b = imml 66 +stl b ptr 1 +c = imml 67 +stl c ptr 2 +zero = imml 0 +stl zero ptr 3 +ss = calll puts cdecl ptr +nn = gel ss zero +retl nn diff --git a/js/src/lirasm/tests/call2.in b/js/src/lirasm/tests/call2.in index b1a5834f5c90..39357e0ee023 100644 --- a/js/src/lirasm/tests/call2.in +++ b/js/src/lirasm/tests/call2.in @@ -1,5 +1,5 @@ -pi = float 3.14 -half = float 0.5 -halfpi = fmul pi half -res = fcall sin cdecl halfpi -fret res +pi = immd 3.14 +half = immd 0.5 +halfpi = muld pi half +res = calld sin cdecl halfpi +retd res diff --git a/js/src/lirasm/tests/f2i.in b/js/src/lirasm/tests/f2i.in index 58452caeebed..08aa61c6fa52 100644 --- a/js/src/lirasm/tests/f2i.in +++ b/js/src/lirasm/tests/f2i.in @@ -1,6 +1,6 @@ -a = alloc 8 -d = float 5.0 -stfi d a 0 -x = ldf a 0 -i = f2i x -ret i +a = allocp 8 +d = immd 5.0 +std d a 0 +x = ldd a 0 +i = d2l x +retl i diff --git a/js/src/lirasm/tests/floatingpoint.in b/js/src/lirasm/tests/floatingpoint.in index d625ac18f82f..f2f5b63fd374 100644 --- a/js/src/lirasm/tests/floatingpoint.in +++ b/js/src/lirasm/tests/floatingpoint.in @@ -1,4 +1,4 @@ -pi = float 3.14 -two = float 2.0 -TwoPi = fmul pi two -fret two +pi = immd 3.14 +two = immd 2.0 +TwoPi = muld pi two +retd two diff --git a/js/src/lirasm/tests/fuzz-527178.in b/js/src/lirasm/tests/fuzz-527178.in index 9b210716fff3..f6f2e204d326 100644 --- a/js/src/lirasm/tests/fuzz-527178.in +++ b/js/src/lirasm/tests/fuzz-527178.in @@ -1,5 +1,5 @@ -base = alloc 512 -five = int 5 -sti five base 256 -x = ldzs base 256 -ret x +base = allocp 512 +five = imml 5 +stl five base 256 +x = lduw2ul base 256 +retl x diff --git a/js/src/lirasm/tests/loadstore.in b/js/src/lirasm/tests/loadstore.in index 9266ba3cd85b..a3356c816f79 100644 --- a/js/src/lirasm/tests/loadstore.in +++ b/js/src/lirasm/tests/loadstore.in @@ -1,9 +1,9 @@ -ptr= alloc 8 -five = int 5 -sti five ptr 0 -three= int 3 -sti three ptr 4 -v= ld ptr 0 -u= ld ptr 4 -res= add u v -ret res +ptr = allocp 8 +five = imml 5 +stl five ptr 0 +three = imml 3 +stl three ptr 4 +v = ldl ptr 0 +u = ldl ptr 4 +res = addl u v +retl res diff --git a/js/src/lirasm/tests/mul_xxx.in b/js/src/lirasm/tests/mul_xxx.in index ec6cefea1661..3d20e2c41f8e 100644 --- a/js/src/lirasm/tests/mul_xxx.in +++ b/js/src/lirasm/tests/mul_xxx.in @@ -1,13 +1,13 @@ ; 46340 * 46340 < 2^31, and will not overflow. -big = int 46340 +big = imml 46340 ; Because 'big' isn't used after mul, it _may_ get allocated to the same ; register as 'res'. This is the case with the ARM back-end, and that is where ; this test is important as rX=rX*rX isn't possible on ARMv5 without some ; trickery. -res = mulxov big big ; no overflow, so we don't exit here +res = mulxovl big big ; no overflow, so we don't exit here ; Store 'res' so it isn't dead. -m = alloc 4 -sti res m 0 +m = allocp 4 +stl res m 0 x ; we exit here diff --git a/js/src/lirasm/tests/mul_xxy.in b/js/src/lirasm/tests/mul_xxy.in index c890ef836539..629aaa285fbe 100644 --- a/js/src/lirasm/tests/mul_xxy.in +++ b/js/src/lirasm/tests/mul_xxy.in @@ -1,14 +1,14 @@ ; 1073741823 * 2 = 0x7ffffffe, and will nearly (but not quite) overflow. -big = int 1073741823 -two = int 2 +big = imml 1073741823 +two = imml 2 ; Because 'big' isn't used after mul, it _may_ get allocated to the same ; register as 'res'. This is the case with the ARM back-end, and that is where ; this test is important as rX=rX*rY isn't possible on ARMv5 without some ; trickery. -res = mulxov big two ; no overflow, so we don't exit here +res = mulxovl big two ; no overflow, so we don't exit here ; Store 'res' so it isn't dead. -m = alloc 4 -sti res m 0 +m = allocp 4 +stl res m 0 x ; we exit here diff --git a/js/src/lirasm/tests/mul_xyy.in b/js/src/lirasm/tests/mul_xyy.in index ae6963dfe31c..1011c2c5af88 100644 --- a/js/src/lirasm/tests/mul_xyy.in +++ b/js/src/lirasm/tests/mul_xyy.in @@ -1,11 +1,11 @@ ; 46340 * 46340 < 2^31, and will not overflow. -big = int 46340 +big = imml 46340 -res = mulxov big big ; no overflow, so we don't exit here +res = mulxovl big big ; no overflow, so we don't exit here ; Ensure that 'big' gets its own register and isn't shared with 'res'. ; Also store 'res' so it isn't dead. -m = alloc 8 -sti big m 0 -sti res m 4 +m = allocp 8 +stl big m 0 +stl res m 4 x ; we exit here diff --git a/js/src/lirasm/tests/mul_xyz.in b/js/src/lirasm/tests/mul_xyz.in index 1107035889a0..5ed0d2a4c5a1 100644 --- a/js/src/lirasm/tests/mul_xyz.in +++ b/js/src/lirasm/tests/mul_xyz.in @@ -1,13 +1,13 @@ ; 1073741823 * 2 = 0x7ffffffe, and will nearly (but not quite) overflow. -big = int 1073741823 -two = int 2 +big = imml 1073741823 +two = imml 2 -res = mulxov big two ; no overflow, so we don't exit here +res = mulxovl big two ; no overflow, so we don't exit here ; Ensure that 'big' and 'two' get their own registers and ; aren't shared with 'res'. Also store 'res' so it isn't dead. -m = alloc 12 -sti big m 0 -sti two m 4 -sti res m 8 +m = allocp 12 +stl big m 0 +stl two m 4 +stl res m 8 x ; we exit here diff --git a/js/src/lirasm/tests/mulov_xxx.in b/js/src/lirasm/tests/mulov_xxx.in index 66370f5962b1..d25a8185f74e 100644 --- a/js/src/lirasm/tests/mulov_xxx.in +++ b/js/src/lirasm/tests/mulov_xxx.in @@ -1,14 +1,14 @@ ; 46341 * 46341 >= 2^31, and will overflow. -big = int 46341 +big = imml 46341 ; Because 'big' isn't used after mul, it _may_ get allocated to the same ; register as 'res'. This is the case with the ARM back-end, and that is where ; this test is important as rX=rX*rX isn't possible on ARMv5 without some ; trickery. -res = mulxov big big ; overflow, so we exit here +res = mulxovl big big ; overflow, so we exit here ; Store 'res' so it isn't dead. -m = alloc 4 -sti res m 0 +m = allocp 4 +stl res m 0 x ; we don't exit here diff --git a/js/src/lirasm/tests/mulov_xxy.in b/js/src/lirasm/tests/mulov_xxy.in index b57a5a2ea7e0..ef1c03278749 100644 --- a/js/src/lirasm/tests/mulov_xxy.in +++ b/js/src/lirasm/tests/mulov_xxy.in @@ -1,14 +1,14 @@ ; 1073741824 * 2 >= 2^31, and will overflow. -big = int 1073741824 -two = int 2 +big = imml 1073741824 +two = imml 2 ; Because 'big' isn't used after mul, it _may_ get allocated to the same ; register as 'res'. This is the case with the ARM back-end, and that is where ; this test is important as rX=rX*rY isn't possible on ARMv5 without some ; trickery. -res = mulxov big two ; overflow, so we exit here +res = mulxovl big two ; overflow, so we exit here ; Store 'res' so it isn't dead. -m = alloc 4 -sti res m 0 +m = allocp 4 +stl res m 0 x ; we don't exit here diff --git a/js/src/lirasm/tests/mulov_xyy.in b/js/src/lirasm/tests/mulov_xyy.in index 50fe51d174eb..8379650e1927 100644 --- a/js/src/lirasm/tests/mulov_xyy.in +++ b/js/src/lirasm/tests/mulov_xyy.in @@ -1,11 +1,11 @@ ; 46341 * 46341 >= 2^31, and will overflow. -big = int 46341 +big = imml 46341 -res = mulxov big big ; overflow, so we exit here +res = mulxovl big big ; overflow, so we exit here ; Ensure that 'big' gets its own register and isn't shared with 'res'. ; Also store 'res' so it isn't dead. -m = alloc 8 -sti big m 0 -sti res m 4 +m = allocp 8 +stl big m 0 +stl res m 4 x ; we don't exit here diff --git a/js/src/lirasm/tests/mulov_xyz.in b/js/src/lirasm/tests/mulov_xyz.in index 0975cbae76ac..32a4902aa6aa 100644 --- a/js/src/lirasm/tests/mulov_xyz.in +++ b/js/src/lirasm/tests/mulov_xyz.in @@ -1,13 +1,13 @@ ; 1073741824 * 2 >= 2^31, and will overflow. -big = int 1073741824 -two = int 2 +big = imml 1073741824 +two = imml 2 -res = mulxov big two ; overflow, so we exit here +res = mulxovl big two ; overflow, so we exit here ; Ensure that 'big' and 'two' get their own registers and ; aren't shared with 'res'. Also store 'res' so it isn't dead. -m = alloc 12 -sti big m 0 -sti two m 4 -sti res m 8 +m = allocp 12 +stl big m 0 +stl two m 4 +stl res m 8 x ; we don't exit here diff --git a/js/src/lirasm/tests/multfrag1.in b/js/src/lirasm/tests/multfrag1.in index c2b07e7ace7e..1881bac473ff 100644 --- a/js/src/lirasm/tests/multfrag1.in +++ b/js/src/lirasm/tests/multfrag1.in @@ -1,27 +1,27 @@ .begin a -ptr = alloc 8 -a = int 65 -sti a ptr 0 -b = int 66 -sti b ptr 1 -c = int 67 -sti c ptr 2 -zero = int 0 -sti zero ptr 3 -ss = icall puts cdecl ptr -nn = ge ss zero -ret nn +ptr = allocp 8 +a = imml 65 +stl a ptr 0 +b = imml 66 +stl b ptr 1 +c = imml 67 +stl c ptr 2 +zero = imml 0 +stl zero ptr 3 +ss = calll puts cdecl ptr +nn = gel ss zero +retl nn .end .begin b -rr = icall a fastcall -ret rr +rr = calll a fastcall +retl rr .end .begin main -ans = icall b fastcall -five = int 5 -res = add five ans -ret res +ans = calll b fastcall +five = imml 5 +res = addl five ans +retl res .end diff --git a/js/src/lirasm/tests/multfrag2.in b/js/src/lirasm/tests/multfrag2.in index cf7553e71e44..6a769a964d69 100644 --- a/js/src/lirasm/tests/multfrag2.in +++ b/js/src/lirasm/tests/multfrag2.in @@ -1,14 +1,14 @@ .begin sinpibytwo -pi = float 3.14 -half = float 0.5 -halfpi = fmul pi half -res = fcall sin cdecl halfpi -fret res +pi = immd 3.14 +half = immd 0.5 +halfpi = muld pi half +res = calld sin cdecl halfpi +retd res .end .begin main -aa = fcall sinpibytwo fastcall -bb = float 5.53 -res = fadd aa bb -fret res +aa = calld sinpibytwo fastcall +bb = immd 5.53 +res = addd aa bb +retd res .end diff --git a/js/src/lirasm/tests/multfrag3.in b/js/src/lirasm/tests/multfrag3.in index c9469d6bbb26..8dba76241b21 100644 --- a/js/src/lirasm/tests/multfrag3.in +++ b/js/src/lirasm/tests/multfrag3.in @@ -1,16 +1,16 @@ ; See bug 541232 for why the params are commented out. .begin avg -oneh = int 100 ; should be: p1 = param 0 0 -twoh = int 200 ; should be: p2 = param 1 0 -sum = add oneh twoh ; should be: sum = add p1 p2 -one = int 1 -avg = rsh sum one -ret avg +oneh = imml 100 ; should be: p1 = paramp 0 0 +twoh = imml 200 ; should be: p2 = paramp 1 0 +sum = addl oneh twoh ; should be: sum = addp p1 p2 +one = imml 1 +avg = rshl sum one +retl avg .end .begin main -oneh = int 100 -twoh = int 200 -res = icall avg fastcall twoh oneh -ret res +oneh = imml 100 +twoh = imml 200 +res = calll avg fastcall twoh oneh +retl res .end diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp index c43b0c228a8f..cf029bc41ac8 100644 --- a/js/src/nanojit/LIR.cpp +++ b/js/src/nanojit/LIR.cpp @@ -455,6 +455,30 @@ namespace nanojit } #endif + LOpcode f64cmp_to_i32cmp(LOpcode op) + { + switch (op) { + case LIR_feq: return LIR_eq; + case LIR_flt: return LIR_lt; + case LIR_fgt: return LIR_gt; + case LIR_fle: return LIR_le; + case LIR_fge: return LIR_ge; + default: NanoAssert(0); return LIR_skip; + } + } + + LOpcode f64cmp_to_u32cmp(LOpcode op) + { + switch (op) { + case LIR_feq: return LIR_eq; + case LIR_flt: return LIR_ult; + case LIR_fgt: return LIR_ugt; + case LIR_fle: return LIR_ule; + case LIR_fge: return LIR_uge; + default: NanoAssert(0); return LIR_skip; + } + } + // This is never called, but that's ok because it contains only static // assertions. void LIns::staticSanityCheck() diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 59b25de1fb68..49af54454cfb 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -60,17 +60,226 @@ namespace nanojit # define PTR_SIZE(a,b) a #endif - // pointer op aliases - LIR_ldp = PTR_SIZE(LIR_ld, LIR_ldq), + // Pointer-sized synonyms. + + LIR_paramp = PTR_SIZE(LIR_paraml, LIR_paramq), + + LIR_allocp = PTR_SIZE(LIR_allocl, LIR_allocq), + + LIR_retp = PTR_SIZE(LIR_retl, LIR_retq), + + LIR_livep = PTR_SIZE(LIR_livel, LIR_liveq), + + LIR_ldp = PTR_SIZE(LIR_ldl, LIR_ldq), + + LIR_stp = PTR_SIZE(LIR_stl, LIR_stq), + + LIR_callp = PTR_SIZE(LIR_calll, LIR_callq), + + LIR_eqp = PTR_SIZE(LIR_eql, LIR_eqq), + LIR_ltp = PTR_SIZE(LIR_ltl, LIR_ltq), + LIR_gtp = PTR_SIZE(LIR_gtl, LIR_gtq), + LIR_lep = PTR_SIZE(LIR_lel, LIR_leq), + LIR_gep = PTR_SIZE(LIR_gel, LIR_geq), + LIR_ltup = PTR_SIZE(LIR_ltul, LIR_ltuq), + LIR_gtup = PTR_SIZE(LIR_gtul, LIR_gtuq), + LIR_leup = PTR_SIZE(LIR_leul, LIR_leuq), + LIR_geup = PTR_SIZE(LIR_geul, LIR_geuq), + + LIR_addp = PTR_SIZE(LIR_addl, LIR_addq), + + LIR_andp = PTR_SIZE(LIR_andl, LIR_andq), + LIR_orp = PTR_SIZE(LIR_orl, LIR_orq), + LIR_xorp = PTR_SIZE(LIR_xorl, LIR_xorq), + + LIR_lshp = PTR_SIZE(LIR_lshl, LIR_lshq), + LIR_rshp = PTR_SIZE(LIR_rshl, LIR_rshq), + LIR_rshup = PTR_SIZE(LIR_rshul, LIR_rshuq), + + LIR_cmovp = PTR_SIZE(LIR_cmovl, LIR_cmovq), + + // XXX: temporary synonyms for old opcode names and old pointer-sized + // synonyms, for the Great Opcode Renaming transition period (bug + // 504506). Those in comments have not changed and so don't need a + // temporary synonym. + + // LIR_start + + // LIR_regfence + + // LIR_skip + +#ifndef NANOJIT_64BIT + LIR_iparam = LIR_paraml, +#else + LIR_qparam = LIR_paramq, +#endif + +#ifndef NANOJIT_64BIT + LIR_ialloc = LIR_allocl, +#else + LIR_qalloc = LIR_allocq, +#endif + + LIR_ret = LIR_retl, +#ifdef NANOJIT_64BIT + LIR_qret = LIR_retq, +#endif + LIR_fret = LIR_retd, + + LIR_live = LIR_livel, +#ifdef NANOJIT_64BIT + LIR_qlive = LIR_liveq, +#endif + LIR_flive = LIR_lived, + + // file + // line + + LIR_ldsb = LIR_ldb2l, + LIR_ldss = LIR_ldw2l, + LIR_ldzb = LIR_ldub2ul, + LIR_ldzs = LIR_lduw2ul, + LIR_ld = LIR_ldl, + // LIR_ldq + LIR_ldf = LIR_ldd, + LIR_ld32f = LIR_lds2d, + + // LIR_stb + LIR_sts = LIR_stw, + LIR_sti = LIR_stl, +#ifdef NANOJIT_64BIT + LIR_stqi = LIR_stq, +#endif + LIR_stfi = LIR_std, + LIR_st32f = LIR_std2s, + + LIR_icall = LIR_calll, +#ifdef NANOJIT_64BIT + LIR_qcall = LIR_callq, +#endif + LIR_fcall = LIR_calld, + + // LIR_j + // LIR_jt + // LIR_jf + // LIR_jtbl + + // LIR_label = LIR_label + + // LIR_x + // LIR_xt + // LIR_xf + // LIR_xtbl + // LIR_xbarrier + + LIR_int = LIR_imml, +#ifdef NANOJIT_64BIT + LIR_quad = LIR_immq, +#endif + LIR_float = LIR_immd, + + LIR_eq = LIR_eql, + LIR_lt = LIR_ltl, + LIR_gt = LIR_gtl, + LIR_le = LIR_lel, + LIR_ge = LIR_gel, + LIR_ult = LIR_ltul, + LIR_ugt = LIR_gtul, + LIR_ule = LIR_leul, + LIR_uge = LIR_geul, + +#ifdef NANOJIT_64BIT + LIR_qeq = LIR_eqq, + LIR_qlt = LIR_ltq, + LIR_qgt = LIR_gtq, + LIR_qle = LIR_leq, + LIR_qge = LIR_geq, + LIR_qult = LIR_ltuq, + LIR_qugt = LIR_gtuq, + LIR_qule = LIR_leuq, + LIR_quge = LIR_geuq, +#endif + + LIR_feq = LIR_eqd, + LIR_flt = LIR_ltd, + LIR_fgt = LIR_gtd, + LIR_fle = LIR_led, + LIR_fge = LIR_ged, + + LIR_neg = LIR_negl, + LIR_add = LIR_addl, + LIR_sub = LIR_subl, + LIR_mul = LIR_mull, + LIR_div = LIR_divl, + LIR_mod = LIR_modl, + + LIR_not = LIR_notl, + LIR_and = LIR_andl, + LIR_or = LIR_orl, + LIR_xor = LIR_xorl, + + LIR_lsh = LIR_lshl, + LIR_rsh = LIR_rshl, + LIR_ush = LIR_rshul, + +#ifdef NANOJIT_64BIT + LIR_qiadd = LIR_addq, + + LIR_qiand = LIR_andq, + LIR_qior = LIR_orq, + LIR_qxor = LIR_xorq, + + LIR_qilsh = LIR_lshq, + LIR_qirsh = LIR_rshq, + LIR_qursh = LIR_rshuq, +#endif + + LIR_fneg = LIR_negd, + LIR_fadd = LIR_addd, + LIR_fsub = LIR_subd, + LIR_fmul = LIR_muld, + LIR_fdiv = LIR_divd, + LIR_fmod = LIR_modd, + + LIR_cmov = LIR_cmovl, +#ifdef NANOJIT_64BIT + LIR_qcmov = LIR_cmovq, +#endif + +#ifdef NANOJIT_64BIT + LIR_i2q = LIR_l2q, + LIR_u2q = LIR_ul2uq, + LIR_q2i = LIR_q2l, +#endif + + LIR_i2f = LIR_l2d, + LIR_u2f = LIR_ul2d, + LIR_f2i = LIR_d2l, + + LIR_addxov = LIR_addxovl, + LIR_subxov = LIR_subxovl, + LIR_mulxov = LIR_mulxovl, + +#if NJ_SOFTFLOAT_SUPPORTED + LIR_qlo = LIR_dlo2l, + LIR_qhi = LIR_dhi2l, + LIR_qjoin = LIR_ll2d, + LIR_callh = LIR_hcalll, +#endif + + LIR_param = PTR_SIZE(LIR_iparam, LIR_qparam), + + LIR_alloc = PTR_SIZE(LIR_ialloc, LIR_qalloc), + + LIR_pret = PTR_SIZE(LIR_ret, LIR_qret), + + LIR_plive = PTR_SIZE(LIR_live, LIR_qlive), + LIR_stpi = PTR_SIZE(LIR_sti, LIR_stqi), - LIR_piadd = PTR_SIZE(LIR_add, LIR_qiadd), - LIR_piand = PTR_SIZE(LIR_and, LIR_qiand), - LIR_pilsh = PTR_SIZE(LIR_lsh, LIR_qilsh), - LIR_pirsh = PTR_SIZE(LIR_rsh, LIR_qirsh), - LIR_pursh = PTR_SIZE(LIR_ush, LIR_qursh), - LIR_pcmov = PTR_SIZE(LIR_cmov, LIR_qcmov), - LIR_pior = PTR_SIZE(LIR_or, LIR_qior), - LIR_pxor = PTR_SIZE(LIR_xor, LIR_qxor), + + LIR_pcall = PTR_SIZE(LIR_icall, LIR_qcall), + LIR_peq = PTR_SIZE(LIR_eq, LIR_qeq), LIR_plt = PTR_SIZE(LIR_lt, LIR_qlt), LIR_pgt = PTR_SIZE(LIR_gt, LIR_qgt), @@ -80,11 +289,17 @@ namespace nanojit LIR_pugt = PTR_SIZE(LIR_ugt, LIR_qugt), LIR_pule = PTR_SIZE(LIR_ule, LIR_qule), LIR_puge = PTR_SIZE(LIR_uge, LIR_quge), - LIR_alloc = PTR_SIZE(LIR_ialloc, LIR_qalloc), - LIR_pcall = PTR_SIZE(LIR_icall, LIR_qcall), - LIR_param = PTR_SIZE(LIR_iparam, LIR_qparam), - LIR_plive = PTR_SIZE(LIR_live, LIR_qlive), - LIR_pret = PTR_SIZE(LIR_ret, LIR_qret) + LIR_piadd = PTR_SIZE(LIR_add, LIR_qiadd), + + LIR_piand = PTR_SIZE(LIR_and, LIR_qiand), + LIR_pior = PTR_SIZE(LIR_or, LIR_qior), + LIR_pxor = PTR_SIZE(LIR_xor, LIR_qxor), + + LIR_pilsh = PTR_SIZE(LIR_lsh, LIR_qilsh), + LIR_pirsh = PTR_SIZE(LIR_rsh, LIR_qirsh), + LIR_pursh = PTR_SIZE(LIR_ush, LIR_qursh), + + LIR_pcmov = PTR_SIZE(LIR_cmov, LIR_qcmov) }; // 32-bit integer comparisons must be contiguous, as must 64-bit integer @@ -426,6 +641,8 @@ namespace nanojit #ifdef NANOJIT_64BIT LOpcode i32cmp_to_i64cmp(LOpcode op); #endif + LOpcode f64cmp_to_i32cmp(LOpcode op); + LOpcode f64cmp_to_u32cmp(LOpcode op); // Array holding the 'repKind' field from LIRopcode.tbl. extern const uint8_t repKinds[]; diff --git a/js/src/nanojit/LIRopcode.tbl b/js/src/nanojit/LIRopcode.tbl index 91b715308291..6528e7acf9f8 100644 --- a/js/src/nanojit/LIRopcode.tbl +++ b/js/src/nanojit/LIRopcode.tbl @@ -39,6 +39,9 @@ * ***** END LICENSE BLOCK ***** */ /* + * This file is best viewed with 128 columns: +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 + * * Definitions of LIR opcodes. If you need to allocate an opcode, look * for one defined using OP_UN() and claim it. * @@ -47,8 +50,8 @@ * #define OPxyz(op, number, repKind, retType) ... * * Selected arguments can then be used within the macro expansions. - * - op Bytecode name, token-pasted after "LIR_" to form an LOpcode. - * - number Bytecode number, used as the LOpcode enum value. + * - op Opcode name, token-pasted after "LIR_" to form an LOpcode. + * - number Opcode number, used as the LOpcode enum value. * - repKind Indicates how the instruction is represented in memory; XYZ * corresponds to LInsXYZ and LRK_XYZ. * - retType Type (LTy) of the value returned by the instruction. @@ -56,11 +59,22 @@ * can, -1 if things are more complicated -- in which case * isCseOpcode() shouldn't be called on this opcode. * - * This file is best viewed with 128 columns: -12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 + * Opcodes use type-indicators suffixes that are based on the Intel asm ones: + * - 'b': "byte", ie. 8-bit integer + * - 'w': "word", ie. 16-bit integer [*] + * - 'l': "long", ie. 32-bit integer + * - 'q': "quad", ie. 64-bit integer + * - 'u': "unsigned", is used as a prefix on integer type-indicators when necessary + * - 's': "single", ie. 32-bit floating point value + * - 'd': "double", ie. 64-bit floating point value + * - 'p': "pointer", ie. a long on 32-bit machines, a quad on 64-bit machines * - * Aliases for pointer-sized operations that choose 32-bit or 64-bit instructions - * are given in the LOpcode enum in LIR.h just after including LIRopcodes.tbl. + * [*] This meaning of "word" is used in direct relation to LIR types. But + * you'll probably see it elsewhere (eg. in comments) where it has the + * sense of "pointer-sized" word. + * + * 'p' opcodes are all aliases of long and quad opcodes, they're given in LIR.h + * and chosen according to the platform pointer size. * * Certain opcodes aren't supported on all platforms, so OPxyz must be one of * the following: @@ -95,201 +109,238 @@ # define OP_86(a, b, c, d, e) OP_UN(b) #endif - -// Special operations. +//--------------------------------------------------------------------------- +// Miscellaneous operations +//--------------------------------------------------------------------------- OP___(start, 0, Op0, Void, 0) // start of a fragment -OP___(regfence, 1, Op0, Void, 0) // register fence, no register allocation is allowed across this meta instruction -OP___(skip, 2, Sk, Void, 0) // used to link code chunks -// Impure operations. -OP___(ldsb, 3, Ld, I32, -1) // 8-bit integer load, sign-extend to 32-bit -OP___(ldss, 4, Ld, I32, -1) // 16-bit integer load, sign-extend to 32-bit -OP___(ldzb, 5, Ld, I32, -1) // 8-bit integer load, zero-extend to 32-bit -OP___(ldzs, 6, Ld, I32, -1) // 16-bit integer load, zero-extend to 32-bit -OP_32(iaddp, 7, Op2, I32, 0) // 32-bit integer addition for temporary pointer calculations -OP_32(iparam, 8, P, I32, 0) // load a parameter (32-bit register or stack location) -OP___(stb, 9, Sti, Void, 0) // 8-bit integer store -OP___(ld, 10, Ld, I32, -1) // 32-bit integer load -OP_32(ialloc, 11, I, I32, 0) // allocate some stack space (result is a 32-bit address) -OP___(sti, 12, Sti, Void, 0) // 32-bit integer store -OP___(ret, 13, Op1, Void, 0) // return a 32-bit integer -OP___(live, 14, Op1, Void, 0) // extend live range of a 32-bit integer -OP___(flive, 15, Op1, Void, 0) // extend live range of a 64-bit float -OP___(icall, 16, C, I32, -1) // subroutine call returning a 32-bit value -OP___(sts, 17, Sti, Void, 0) // 16-bit integer store +// A register fence causes no code to be generated, but it affects register +// allocation so that no registers are live when it is reached. +OP___(regfence, 1, Op0, Void, 0) -OP___(x, 18, Op2, Void, 0) // exit always +OP___(skip, 2, Sk, Void, 0) // links code chunks -// Branches. 'jt' and 'jf' must be adjacent so that (op ^ 1) gives the -// opposite one. Static assertions in LIR.h check this requirement. -OP___(j, 19, Op2, Void, 0) // jump always -OP___(jt, 20, Op2, Void, 0) // jump if true -OP___(jf, 21, Op2, Void, 0) // jump if false -OP___(label, 22, Op0, Void, 0) // a jump target (no machine code is emitted for this) -OP___(jtbl, 23, Jtbl, Void, 0) // jump to address in table +OP_32(paraml, 3, P, I32, 0) // load a long parameter (register or stack location) +OP_64(paramq, 4, P, I64, 0) // load a quad parameter (register or stack location) -OP___(int, 24, I, I32, 1) // constant 32-bit integer -OP___(cmov, 25, Op3, I32, 1) // conditional move -// LIR_callh is a hack that's only used on 32-bit platforms that use SoftFloat. -// Its operand is always a LIR_icall, but one that specifies a function that -// returns a 64-bit float. It indicates that the 64-bit float return value is -// being returned via two 32-bit integer registers. The result is always used -// as the second operand of a LIR_qjoin. -OP_SF(callh, 26, Op1, I32, 1) +OP_32(allocl, 5, I, I32, 0) // allocate stack space (result is a long address) +OP_64(allocq, 6, I, I64, 0) // allocate stack space (result is a quad address) -// 64-bit float comparisons. Their order must be preserved so that, except for -// 'feq', (op ^ 1) gives the opposite one (eg. flt ^ 1 == fgt). They must also -// remain contiguous so that opcode range checking works correctly. -// Static assertions in LIR.h check these requirements. -OP___(feq, 27, Op2, I32, 1) // floating-point equality -OP___(flt, 28, Op2, I32, 1) // floating-point less-than -OP___(fgt, 29, Op2, I32, 1) // floating-point greater-than -OP___(fle, 30, Op2, I32, 1) // floating-point less-than-or-equal -OP___(fge, 31, Op2, I32, 1) // floating-point greater-than-or-equal +OP___(retl, 7, Op1, Void, 0) // return a long +OP_64(retq, 8, Op1, Void, 0) // return a quad +OP___(retd, 9, Op1, Void, 0) // return a double +OP___(livel, 10, Op1, Void, 0) // extend live range of a long +OP_64(liveq, 11, Op1, Void, 0) // extend live range of a quad +OP___(lived, 12, Op1, Void, 0) // extend live range of a double + +OP___(file, 13, Op1, Void, 0) // source filename for debug symbols +OP___(line, 14, Op1, Void, 0) // source line number for debug symbols + +OP_UN(15) +OP_UN(16) + +//--------------------------------------------------------------------------- +// Loads and stores +//--------------------------------------------------------------------------- +OP___(ldb2l, 17, Ld, I32, -1) // load byte and sign-extend to a long +OP___(ldw2l, 18, Ld, I32, -1) // load word and sign-extend to a long +OP___(ldub2ul, 19, Ld, I32, -1) // load unsigned byte and zero-extend to an unsigned long +OP___(lduw2ul, 20, Ld, I32, -1) // load unsigned word and zero-extend to an unsigned long +OP___(ldl, 21, Ld, I32, -1) // load long +OP_64(ldq, 22, Ld, I64, -1) // load quad +OP___(ldd, 23, Ld, F64, -1) // load double +OP___(lds2d, 24, Ld, F64, -1) // load single and extend to a double + +OP___(stb, 25, Sti, Void, 0) // store byte +OP___(stw, 26, Sti, Void, 0) // store word +OP___(stl, 27, Sti, Void, 0) // store long +OP_64(stq, 28, Sti, Void, 0) // store quad +OP___(std, 29, Sti, Void, 0) // store double +OP___(std2s, 30, Sti, Void, 0) // store double as a single (losing precision) + +OP_UN(31) OP_UN(32) -OP_UN(33) -OP_UN(34) -OP___(neg, 35, Op1, I32, 1) // 32-bit integer negation -OP___(add, 36, Op2, I32, 1) // 32-bit integer addition -OP___(sub, 37, Op2, I32, 1) // 32-bit integer subtraction -OP___(mul, 38, Op2, I32, 1) // 32-bit integer multiplication -OP_86(div, 39, Op2, I32, 1) // 32-bit integer division -// LIR_mod is a hack. It's only used on i386/X64. The operand is the result -// of a LIR_div because on i386/X64 div and mod results are computed by the -// same instruction. -OP_86(mod, 40, Op1, I32, 1) // 32-bit integer modulus +//--------------------------------------------------------------------------- +// Calls +//--------------------------------------------------------------------------- +OP___(calll, 33, C, I32, -1) // call subroutine that returns a long +OP_64(callq, 34, C, I64, -1) // call subroutine that returns a quad +OP___(calld, 35, C, F64, -1) // call subroutine that returns a double -OP___(and, 41, Op2, I32, 1) // 32-bit bitwise AND -OP___(or, 42, Op2, I32, 1) // 32-bit bitwise OR -OP___(xor, 43, Op2, I32, 1) // 32-bit bitwise XOR -OP___(not, 44, Op1, I32, 1) // 32-bit bitwise NOT -OP___(lsh, 45, Op2, I32, 1) // 32-bit left shift -OP___(rsh, 46, Op2, I32, 1) // 32-bit right shift with sign-extend (>>) -OP___(ush, 47, Op2, I32, 1) // 32-bit unsigned right shift (>>>) +OP_UN(36) -// Conditional guards. 'xt' and 'xf' must be adjacent so that (op ^ 1) gives -// the opposite one. Static assertions in LIR.h check this requirement. -OP___(xt, 48, Op2, Void, 1) // exit if true (0x30 0011 0000) -OP___(xf, 49, Op2, Void, 1) // exit if false (0x31 0011 0001) +//--------------------------------------------------------------------------- +// Branches and labels +//--------------------------------------------------------------------------- +// 'jt' and 'jf' must be adjacent so that (op ^ 1) gives the opposite one. +// Static assertions in LIR.h check this requirement. +OP___(j, 37, Op2, Void, 0) // jump always +OP___(jt, 38, Op2, Void, 0) // jump if true +OP___(jf, 39, Op2, Void, 0) // jump if false +OP___(jtbl, 40, Jtbl, Void, 0) // jump to address in table -OP_SF(qlo, 50, Op1, I32, 1) // get the low 32 bits of a 64-bit value -OP_SF(qhi, 51, Op1, I32, 1) // get the high 32 bits of a 64-bit value +OP___(label, 41, Op0, Void, 0) // a jump target (no machine code is emitted for this) + +OP_UN(42) + +//--------------------------------------------------------------------------- +// Guards +//--------------------------------------------------------------------------- +// 'xt' and 'xf' must be adjacent so that (op ^ 1) gives the opposite one. +// Static assertions in LIR.h check this requirement. +OP___(x, 43, Op2, Void, 0) // exit always +OP___(xt, 44, Op2, Void, 1) // exit if true +OP___(xf, 45, Op2, Void, 1) // exit if false +OP___(xtbl, 46, Op2, Void, 0) // exit via indirect jump +// A LIR_xbarrier cause no code to be generated, but it acts like a never-taken +// guard in that it inhibits certain optimisations, such as dead stack store +// elimination. +OP___(xbarrier, 47, Op2, Void, 0) + +OP_UN(48) + +//--------------------------------------------------------------------------- +// Immediates +//--------------------------------------------------------------------------- +OP___(imml, 49, I, I32, 1) // long immediate +OP_64(immq, 50, N64, I64, 1) // quad immediate +OP___(immd, 51, N64, F64, 1) // double immediate OP_UN(52) -OP_UN(53) -OP___(addxov, 54, Op3, I32, 1) // 32-bit integer addition; exit if overflow occurred, result is valid on either path -OP___(subxov, 55, Op3, I32, 1) // 32-bit integer subtraction; exit if overflow occurred, result is valid on either path -OP___(mulxov, 56, Op3, I32, 1) // 32-bit integer multiplication; exit if overflow occurred, result is valid on either path +//--------------------------------------------------------------------------- +// Comparisons +//--------------------------------------------------------------------------- -// 32-bit integer comparisons. Their order must be preserved so that, except -// for 'eq', (op ^ 1) gives the opposite one (eg. lt ^ 1 == gt). They must -// also remain contiguous so that opcode range checking works correctly. -// Static assertions in LIR.h check these requirements. -OP___(eq, 57, Op2, I32, 1) // integer equality -OP___(lt, 58, Op2, I32, 1) // signed integer less-than (0x38 0011 1000) -OP___(gt, 59, Op2, I32, 1) // signed integer greater-than (0x39 0011 1001) -OP___(le, 60, Op2, I32, 1) // signed integer less-than-or-equal (0x3A 0011 1010) -OP___(ge, 61, Op2, I32, 1) // signed integer greater-than-or-equal (0x3B 0011 1011) -OP___(ult, 62, Op2, I32, 1) // unsigned integer less-than (0x3C 0011 1100) -OP___(ugt, 63, Op2, I32, 1) // unsigned integer greater-than (0x3D 0011 1101) -OP___(ule, 64, Op2, I32, 1) // unsigned integer less-than-or-equal (0x3E 0011 1110) -OP___(uge, 65, Op2, I32, 1) // unsigned integer greater-than-or-equal (0x3F 0011 1111) +// Within each size group, order must be preserved so that, except for eq*, (op +// ^ 1) gives the opposite one (eg. lt ^ 1 == gt). eq* must have odd numbers +// for this to work. They must also remain contiguous so that opcode range +// checking works correctly. Static assertions in LIR.h check these +// requirements. +OP___(eql, 53, Op2, I32, 1) // long equality +OP___(ltl, 54, Op2, I32, 1) // signed long less-than +OP___(gtl, 55, Op2, I32, 1) // signed long greater-than +OP___(lel, 56, Op2, I32, 1) // signed long less-than-or-equal +OP___(gel, 57, Op2, I32, 1) // signed long greater-than-or-equal +OP___(ltul, 58, Op2, I32, 1) // unsigned long less-than +OP___(gtul, 59, Op2, I32, 1) // unsigned long greater-than +OP___(leul, 60, Op2, I32, 1) // unsigned long less-than-or-equal +OP___(geul, 61, Op2, I32, 1) // unsigned long greater-than-or-equal -OP___(file, 66, Op1, Void, 0) // source filename for debug symbols -OP___(line, 67, Op1, Void, 0) // source line number for debug symbols +OP_UN(62) -OP___(xbarrier, 68, Op2, Void, 0) // memory barrier; doesn't exit, but flushes all values to the stack -OP___(xtbl, 69, Op2, Void, 0) // exit via indirect jump +OP_64(eqq, 63, Op2, I32, 1) // long equality +OP_64(ltq, 64, Op2, I32, 1) // signed long less-than +OP_64(gtq, 65, Op2, I32, 1) // signed long greater-than +OP_64(leq, 66, Op2, I32, 1) // signed long less-than-or-equal +OP_64(geq, 67, Op2, I32, 1) // signed long greater-than-or-equal +OP_64(ltuq, 68, Op2, I32, 1) // unsigned long less-than +OP_64(gtuq, 69, Op2, I32, 1) // unsigned long greater-than +OP_64(leuq, 70, Op2, I32, 1) // unsigned long less-than-or-equal +OP_64(geuq, 71, Op2, I32, 1) // unsigned long greater-than-or-equal -OP_64(qlive, 70, Op1, Void, 0) // extend live range of a 64-bit integer +OP_UN(72) -OP_64(qaddp, 71, Op2, I64, 0) // 64-bit integer addition for temp pointer calculations -OP_64(qparam, 72, P, I64, 0) // load a parameter (64bit register or stack location) +OP___(eqd, 73, Op2, I32, 1) // double equality +OP___(ltd, 74, Op2, I32, 1) // double less-than +OP___(gtd, 75, Op2, I32, 1) // double greater-than +OP___(led, 76, Op2, I32, 1) // double less-than-or-equal +OP___(ged, 77, Op2, I32, 1) // double greater-than-or-equal -OP___(ldf, 73, Ld, F64, -1) // 64-bit float load -OP_64(ldq, 74, Ld, I64, -1) // 64-bit integer load +OP_UN(78) -OP_64(qalloc, 75, I, I64, 0) // allocate some stack space (result is a 64-bit address) +//--------------------------------------------------------------------------- +// Arithmetic +//--------------------------------------------------------------------------- +OP___(negl, 79, Op1, I32, 1) // negate long +OP___(addl, 80, Op2, I32, 1) // add long +OP___(subl, 81, Op2, I32, 1) // subtract long +OP___(mull, 82, Op2, I32, 1) // multiply long +OP_86(divl, 83, Op2, I32, 1) // divide long +// LIR_modl is a hack. It's only used on i386/X64. The operand is the result +// of a LIR_divl because on i386/X64 div and mod results are computed by the +// same instruction. +OP_86(modl, 84, Op1, I32, 1) // modulo long -OP_64(stqi, 76, Sti, Void, 0) // 64-bit integer store +OP___(notl, 85, Op1, I32, 1) // bitwise-NOT long +OP___(andl, 86, Op2, I32, 1) // bitwise-AND long +OP___(orl, 87, Op2, I32, 1) // bitwise-OR long +OP___(xorl, 88, Op2, I32, 1) // bitwise-XOR long -OP___(st32f, 77, Sti, Void, 0) // store 64-bit float as a 32-bit float (dropping precision) -OP___(ld32f, 78, Ld, F64, -1) // load 32-bit float and widen to 64-bit float +OP___(lshl, 89, Op2, I32, 1) // left shift long +OP___(rshl, 90, Op2, I32, 1) // right shift long (>>) +OP___(rshul, 91, Op2, I32, 1) // right shift unsigned long (>>>) -OP___(fcall, 79, C, F64, -1) // subroutine call returning 64-bit float value -OP_64(qcall, 80, C, I64, -1) // subroutine call returning 64-bit integer value +OP_64(addq, 92, Op2, I64, 1) // add quad -OP___(stfi, 81, Sti, Void, 0) // 64-bit float store +OP_64(andq, 93, Op2, I64, 1) // bitwise-AND quad +OP_64(orq, 94, Op2, I64, 1) // bitwise-OR quad +OP_64(xorq, 95, Op2, I64, 1) // bitwise-XOR quad -OP___(fret, 82, Op1, Void, 0) // return a 64-bit float -OP_64(qret, 83, Op1, Void, 0) // return a 64-bit integer +OP_64(lshq, 96, Op2, I64, 1) // left shift quad; 2nd operand is a long +OP_64(rshq, 97, Op2, I64, 1) // right shift quad; 2nd operand is a long +OP_64(rshuq, 98, Op2, I64, 1) // right shift unsigned quad; 2nd operand is a long -OP_UN(84) -OP_UN(85) -OP_UN(86) -OP_UN(87) - -OP_64(quad, 88, N64, I64, 1) // 64-bit integer constant value -OP_64(qcmov, 89, Op3, I64, 1) // 64-bit conditional move - -OP_64(i2q, 90, Op1, I64, 1) // sign-extend i32 to i64 -OP_64(u2q, 91, Op1, I64, 1) // zero-extend u32 to u64 -OP___(i2f, 92, Op1, F64, 1) // convert a signed 32-bit integer to a float -OP___(u2f, 93, Op1, F64, 1) // convert an unsigned 32-bit integer to a float -OP___(f2i, 94, Op1, I32, 1) // f2i conversion, no exception raised, platform rounding rules. - -OP_UN(95) -OP_UN(96) -OP_UN(97) -OP_UN(98) - -OP___(fneg, 99, Op1, F64, 1) // floating-point negation -OP___(fadd, 100, Op2, F64, 1) // floating-point addition -OP___(fsub, 101, Op2, F64, 1) // floating-point subtraction -OP___(fmul, 102, Op2, F64, 1) // floating-point multiplication -OP___(fdiv, 103, Op2, F64, 1) // floating-point division -// LIR_fmod is just a place-holder opcode, ie. the back-ends cannot generate +OP___(negd, 99, Op1, F64, 1) // negate double +OP___(addd, 100, Op2, F64, 1) // add double +OP___(subd, 101, Op2, F64, 1) // subtract double +OP___(muld, 102, Op2, F64, 1) // multiply double +OP___(divd, 103, Op2, F64, 1) // divide double +// LIR_modd is just a place-holder opcode, ie. the back-ends cannot generate // code for it. It's used in TraceMonkey briefly but is always demoted to a -// LIR_mod or converted to a function call before Nanojit has to do anything +// LIR_modl or converted to a function call before Nanojit has to do anything // serious with it. -OP___(fmod, 104, Op2, F64, 1) // floating-point modulus +OP___(modd, 104, Op2, F64, 1) // modulo double -OP_64(qiand, 105, Op2, I64, 1) // 64-bit bitwise AND -OP_64(qior, 106, Op2, I64, 1) // 64-bit bitwise OR -OP_64(qxor, 107, Op2, I64, 1) // 64-bit bitwise XOR +OP___(cmovl, 105, Op3, I32, 1) // conditional move long +OP_64(cmovq, 106, Op3, I64, 1) // conditional move quad + +OP_UN(107) OP_UN(108) -OP_64(qilsh, 109, Op2, I64, 1) // 64-bit left shift; 2nd operand is a 32-bit integer -OP_64(qirsh, 110, Op2, I64, 1) // 64-bit signed right shift; 2nd operand is a 32-bit integer -OP_64(qursh, 111, Op2, I64, 1) // 64-bit unsigned right shift; 2nd operand is a 32-bit integer -OP_64(qiadd, 112, Op2, I64, 1) // 64-bit bitwise ADD -OP_UN(113) +//--------------------------------------------------------------------------- +// Conversions +//--------------------------------------------------------------------------- +OP_64(l2q, 109, Op1, I64, 1) // sign-extend long to quad +OP_64(ul2uq, 110, Op1, I64, 1) // zero-extend unsigned long to unsigned quad +OP_64(q2l, 111, Op1, I32, 1) // truncate quad to long (removes the high 32 bits) -OP_SF(qjoin, 114, Op2, F64, 1) // join two 32-bit values (1st arg is low bits, 2nd is high) -OP_64(q2i, 115, Op1, I32, 1) // truncate i64 to i32 +OP___(l2d, 112, Op1, F64, 1) // convert long to double +OP___(ul2d, 113, Op1, F64, 1) // convert unsigned long to double +OP___(d2l, 114, Op1, I32, 1) // convert double to long (no exceptions raised, platform rounding rules) +OP_UN(115) OP_UN(116) -OP_UN(117) -OP___(float, 118, N64, F64, 1) // 64-bit float constant value +//--------------------------------------------------------------------------- +// Overflow arithmetic +//--------------------------------------------------------------------------- +// These all exit if overflow occurred. The results is valid on either path. +OP___(addxovl, 117, Op3, I32, 1) // add long and exit on overflow +OP___(subxovl, 118, Op3, I32, 1) // sub long and exit on overflow +OP___(mulxovl, 119, Op3, I32, 1) // multiply long and exit on overflow -// 64-bit integer comparisons. Their order must be preserved so that, except -// for 'qeq', (op ^ 1) gives the opposite one (eg. qlt ^ 1 == qgt). They must -// also remain contiguous so that opcode range checking works correctly. -// Static assertions in LIR.h check these requirements. -OP_64(qeq, 119, Op2, I32, 1) // integer equality -OP_64(qlt, 120, Op2, I32, 1) // signed integer less-than (0x78 0111 1000) -OP_64(qgt, 121, Op2, I32, 1) // signed integer greater-than (0x79 0111 1001) -OP_64(qle, 122, Op2, I32, 1) // signed integer less-than-or-equal (0x7A 0111 1010) -OP_64(qge, 123, Op2, I32, 1) // signed integer greater-than-or-equal (0x7B 0111 1011) -OP_64(qult, 124, Op2, I32, 1) // unsigned integer less-than (0x7C 0111 1100) -OP_64(qugt, 125, Op2, I32, 1) // unsigned integer greater-than (0x7D 0111 1101) -OP_64(qule, 126, Op2, I32, 1) // unsigned integer less-than-or-equal (0x7E 0111 1110) -OP_64(quge, 127, Op2, I32, 1) // unsigned integer greater-than-or-equal (0x7F 0111 1111) +OP_UN(120) +//--------------------------------------------------------------------------- +// SoftFloat +//--------------------------------------------------------------------------- +OP_SF(dlo2l, 121, Op1, I32, 1) // get the low 32 bits of a double as a long +OP_SF(dhi2l, 122, Op1, I32, 1) // get the high 32 bits of a double as a long +OP_SF(ll2d, 123, Op2, F64, 1) // join two longs (1st arg is low bits, 2nd is high) + +// LIR_hcalll is a hack that's only used on 32-bit platforms that use +// SoftFloat. Its operand is always a LIR_calll, but one that specifies a +// function that returns a double. It indicates that the double result is +// returned via two 32-bit integer registers. The result is always used as the +// second operand of a LIR_ll2d. +OP_SF(hcalll, 124, Op1, I32, 1) + +OP_UN(125) +OP_UN(126) +OP_UN(127) #undef OP_UN #undef OP_32 From 072bedc1129fea91107ff9b8e87e66c0d3febec9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Mar 2010 15:14:28 -0700 Subject: [PATCH 185/213] Fix ARM bustage for bug 555633. r=me. --HG-- extra : convert_revision : be4f098b6cb32f2c2787ef2842402f2b39e0925d --- js/src/nanojit/LIR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index 49af54454cfb..c2c3712e888c 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -211,8 +211,10 @@ namespace nanojit LIR_add = LIR_addl, LIR_sub = LIR_subl, LIR_mul = LIR_mull, +#if defined NANOJIT_IA32 || defined NANOJIT_X64 LIR_div = LIR_divl, LIR_mod = LIR_modl, +#endif LIR_not = LIR_notl, LIR_and = LIR_andl, From 2cb53b9348338f77ac38ece4a0e86d298d146520 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 31 Mar 2010 17:17:20 -0500 Subject: [PATCH 186/213] Bug 556315 part 1 - Remove GCReachableFrame. r=gal. --HG-- extra : rebase_source : 1db26956cf3f73f1213ab222f4c3ee12637265c5 --- js/src/jscntxt.h | 22 ---------------------- js/src/jsdbgapi.cpp | 22 +--------------------- js/src/jsgc.cpp | 4 ---- 3 files changed, 1 insertion(+), 47 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index d40d04313492..a67545adcb9b 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1160,15 +1160,6 @@ typedef struct JSResolvingEntry { extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ -/* - * Wraps a stack frame which has been temporarily popped from its call stack - * and needs to be GC-reachable. See JSContext::{push,pop}GCReachableFrame. - */ -struct JSGCReachableFrame { - JSGCReachableFrame *next; - JSStackFrame *frame; -}; - namespace js { class AutoGCRooter; } @@ -1291,19 +1282,6 @@ struct JSContext void *data; void *data2; - /* Linked list of frames temporarily popped from their chain. */ - JSGCReachableFrame *reachableFrames; - - void pushGCReachableFrame(JSGCReachableFrame &gcrf, JSStackFrame *f) { - gcrf.next = reachableFrames; - gcrf.frame = f; - reachableFrames = &gcrf; - } - - void popGCReachableFrame() { - reachableFrames = reachableFrames->next; - } - private: #ifdef __GNUC__ # pragma GCC visibility push(default) diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 50b6e82512d7..fe0af57ce4c1 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1227,29 +1227,9 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp) JS_PUBLIC_API(JSObject *) JS_GetFrameThis(JSContext *cx, JSStackFrame *fp) { - if (fp->flags & JSFRAME_COMPUTED_THIS) - return JSVAL_TO_OBJECT(fp->thisv); /* JSVAL_COMPUTED_THIS invariant */ - - /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */ - JSStackFrame *afp = js_GetTopStackFrame(cx); - JSGCReachableFrame reachable; - if (afp != fp) { - if (afp) { - cx->fp = fp; - cx->pushGCReachableFrame(reachable, afp); - } - } else { - afp = NULL; - } - - if (fp->argv) + if (!(fp->flags & JSFRAME_COMPUTED_THIS) && fp->argv) fp->thisv = OBJECT_TO_JSVAL(js_ComputeThis(cx, fp->argv)); - if (afp) { - cx->fp = afp; - cx->popGCReachableFrame(); - } - return JSVAL_TO_OBJECT(fp->thisv); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index a784ec0810d9..35b2fa35b9e6 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2412,10 +2412,6 @@ js_TraceContext(JSTracer *trc, JSContext *acx) } } - /* Trace frames that have been temporarily removed but need to be marked. */ - for (JSGCReachableFrame *rf = acx->reachableFrames; rf; rf = rf->next) - TraceFrameChain(trc, rf->frame); - /* Mark other roots-by-definition in acx. */ if (acx->globalObject && !JS_HAS_OPTION(acx, JSOPTION_UNROOTED_GLOBAL)) JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object"); From 54b9b7f300e83bdf84190c348b12ac78ecb7dbd9 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 31 Mar 2010 17:57:03 -0500 Subject: [PATCH 187/213] Bug 556315 part 2 - JSObject::getGlobal() and JSStackFrame::getThisObject(). r=gal. --HG-- extra : rebase_source : 103e73537d3c2f537a914b69a620136451a664ba --- js/src/jsapi.cpp | 4 +--- js/src/jsdbgapi.cpp | 5 +---- js/src/jsinterp.cpp | 2 +- js/src/jsinterp.h | 30 +++++++++++++++--------------- js/src/jsobj.cpp | 11 ++++++++++- js/src/jsobj.h | 2 ++ js/src/jsops.cpp | 2 +- js/src/jstracer.cpp | 30 +++++++++++++++--------------- 8 files changed, 46 insertions(+), 40 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f906ccf99b87..0132104a43b2 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1685,9 +1685,7 @@ JS_GetScopeChain(JSContext *cx) JS_PUBLIC_API(JSObject *) JS_GetGlobalForObject(JSContext *cx, JSObject *obj) { - while (JSObject *parent = obj->getParent()) - obj = parent; - return obj; + return obj->getGlobal(); } JS_PUBLIC_API(jsval) diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index fe0af57ce4c1..b5a28b363805 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1227,10 +1227,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp) JS_PUBLIC_API(JSObject *) JS_GetFrameThis(JSContext *cx, JSStackFrame *fp) { - if (!(fp->flags & JSFRAME_COMPUTED_THIS) && fp->argv) - fp->thisv = OBJECT_TO_JSVAL(js_ComputeThis(cx, fp->argv)); - - return JSVAL_TO_OBJECT(fp->thisv); + return fp->getThisObject(cx); } JS_PUBLIC_API(JSFunction *) diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index fc525ca66b19..6f9c5baf99a4 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -407,7 +407,7 @@ js_ComputeGlobalThis(JSContext *cx, jsval *argv) !JSVAL_TO_OBJECT(argv[-2])->getParent()) { thisp = cx->globalObject; } else { - thisp = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(argv[-2])); + thisp = JSVAL_TO_OBJECT(argv[-2])->getGlobal(); } return CallThisObjectHook(cx, thisp, argv); diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index b4548a8414e2..fa53ca1f5aff 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -167,6 +167,8 @@ struct JSStackFrame { /* Short for: varobj(cx->activeCallStack()). */ JSObject *varobj(JSContext *cx); + + inline JSObject *getThisObject(JSContext *cx); }; #ifdef __cplusplus @@ -274,21 +276,6 @@ extern const uint16 js_PrimitiveTestFlags[]; JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \ js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1])) -#ifdef __cplusplus /* Aargh, libgjs, bug 492720. */ -static JS_INLINE JSObject * -js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp) -{ - if (fp->flags & JSFRAME_COMPUTED_THIS) - return JSVAL_TO_OBJECT(fp->thisv); /* JSVAL_COMPUTED_THIS invariant */ - JSObject* obj = js_ComputeThis(cx, fp->argv); - if (!obj) - return NULL; - fp->thisv = OBJECT_TO_JSVAL(obj); - fp->flags |= JSFRAME_COMPUTED_THIS; - return obj; -} -#endif - /* * 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 @@ -472,4 +459,17 @@ js_MeterSlotOpcode(JSOp op, uint32 slot); JS_END_EXTERN_C +inline JSObject * +JSStackFrame::getThisObject(JSContext *cx) +{ + if (flags & JSFRAME_COMPUTED_THIS) + return JSVAL_TO_OBJECT(thisv); /* JSVAL_COMPUTED_THIS invariant */ + JSObject* obj = js_ComputeThis(cx, argv); + if (!obj) + return NULL; + thisv = OBJECT_TO_JSVAL(obj); + flags |= JSFRAME_COMPUTED_THIS; + return obj; +} + #endif /* jsinterp_h___ */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index a05bb8c38a3f..25eb9543e570 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1352,7 +1352,7 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) * with object to maintain invariants in the engine (see bug 520164). */ if (scopeobj->getParent()) { - JSObject *global = JS_GetGlobalForObject(cx, scopeobj); + JSObject *global = scopeobj->getGlobal(); withGuard.obj = js_NewWithObject(cx, scopeobj, global, 0); if (!withGuard.obj) return JS_FALSE; @@ -6746,6 +6746,15 @@ js_GetWrappedObject(JSContext *cx, JSObject *obj) return obj; } +JSObject * +JSObject::getGlobal() +{ + JSObject *obj = this; + while (JSObject *parent = obj->getParent()) + obj = parent; + return obj; +} + bool JSObject::isCallable() { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index ad28dd995c39..f0e54a5ebca8 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -356,6 +356,8 @@ struct JSObject { JS_CALL_OBJECT_TRACER(trc, parent, "__parent__"); } + JSObject *getGlobal(); + void *getPrivate() const { JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE); jsval v = fslots[JSSLOT_PRIVATE]; diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index d51d298740f2..74568983b96c 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1420,7 +1420,7 @@ BEGIN_CASE(JSOP_GVARINC) #define COMPUTE_THIS(cx, fp, obj) \ JS_BEGIN_MACRO \ - if (!(obj = js_ComputeThisForFrame(cx, fp))) \ + if (!(obj = (fp)->getThisObject(cx))) \ goto error; \ JS_END_MACRO diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 84fbcf922cdf..8d478d44fe94 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1112,7 +1112,7 @@ GlobalSlotHash(JSContext* cx, unsigned slot) fp = fp->down; HashAccum(h, uintptr_t(fp->script), ORACLE_MASK); - HashAccum(h, uintptr_t(OBJ_SHAPE(JS_GetGlobalForObject(cx, fp->scopeChain))), ORACLE_MASK); + HashAccum(h, uintptr_t(OBJ_SHAPE(fp->scopeChain->getGlobal())), ORACLE_MASK); HashAccum(h, uintptr_t(slot), ORACLE_MASK); return int(h); } @@ -1812,7 +1812,7 @@ template static JS_REQUIRES_STACK JS_ALWAYS_INLINE void VisitGlobalSlots(Visitor &visitor, JSContext *cx, SlotList &gslots) { - VisitGlobalSlots(visitor, cx, JS_GetGlobalForObject(cx, cx->fp->scopeChain), + VisitGlobalSlots(visitor, cx, cx->fp->scopeChain->getGlobal(), gslots.length(), gslots.data()); } @@ -1831,7 +1831,7 @@ static JS_REQUIRES_STACK JS_ALWAYS_INLINE void VisitSlots(Visitor& visitor, JSContext* cx, unsigned callDepth, unsigned ngslots, uint16* gslots) { - VisitSlots(visitor, cx, JS_GetGlobalForObject(cx, cx->fp->scopeChain), + VisitSlots(visitor, cx, cx->fp->scopeChain->getGlobal(), callDepth, ngslots, gslots); } @@ -1849,7 +1849,7 @@ static JS_REQUIRES_STACK JS_ALWAYS_INLINE void VisitSlots(Visitor &visitor, JSContext *cx, unsigned callDepth, const SlotList& slots) { - VisitSlots(visitor, cx, JS_GetGlobalForObject(cx, cx->fp->scopeChain), + VisitSlots(visitor, cx, cx->fp->scopeChain->getGlobal(), callDepth, slots.length(), slots.data()); } @@ -2166,7 +2166,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag generatedSpecializedNative(), tempTypeMap(cx) { - JS_ASSERT(globalObj == JS_GetGlobalForObject(cx, cx->fp->scopeChain)); + JS_ASSERT(globalObj == cx->fp->scopeChain->getGlobal()); JS_ASSERT(cx->fp->regs->pc == (jsbytecode*)fragment->ip); fragment->lirbuf = lirbuf; @@ -5908,7 +5908,7 @@ JS_REQUIRES_STACK bool TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) { #ifdef JS_THREADSAFE - if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->title.ownercx != cx) { + if (OBJ_SCOPE(cx->fp->scopeChain->getGlobal())->title.ownercx != cx) { AbortRecording(cx, "Global object not owned by this context"); return false; /* we stay away from shared global objects */ } @@ -5931,7 +5931,7 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall * Make sure the shape of the global object still matches (this might flush * the JIT cache). */ - JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + JSObject* globalObj = cx->fp->scopeChain->getGlobal(); uint32 globalShape = -1; SlotList* globalSlots = NULL; if (!CheckGlobalObjectShape(cx, tm, globalObj, &globalShape, &globalSlots)) { @@ -6399,7 +6399,7 @@ ExecuteTrace(JSContext* cx, Fragment* f, InterpState& state) static JS_REQUIRES_STACK JS_ALWAYS_INLINE bool ScopeChainCheck(JSContext* cx, TreeFragment* f) { - JS_ASSERT(f->globalObj == JS_GetGlobalForObject(cx, cx->fp->scopeChain)); + JS_ASSERT(f->globalObj == cx->fp->scopeChain->getGlobal()); /* * The JIT records and expects to execute with two scope-chain @@ -6896,7 +6896,7 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, RecordReason reason) * Make sure the shape of the global object still matches (this might flush * the JIT cache). */ - JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + JSObject* globalObj = cx->fp->scopeChain->getGlobal(); uint32 globalShape = -1; SlotList* globalSlots = NULL; @@ -9423,7 +9423,7 @@ JS_REQUIRES_STACK RecordingStatus TraceRecorder::getThis(LIns*& this_ins) { /* - * js_ComputeThisForFrame updates cx->fp->argv[-1], so sample it into 'original' first. + * JSStackFrame::getThisObject updates cx->fp->argv[-1], so sample it into 'original' first. */ jsval original = JSVAL_NULL; if (cx->fp->argv) { @@ -9435,9 +9435,9 @@ TraceRecorder::getThis(LIns*& this_ins) } } - JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp); + JSObject* thisObj = cx->fp->getThisObject(cx); if (!thisObj) - RETURN_ERROR("js_ComputeThisForFrame failed"); + RETURN_ERROR("fp->getThisObject failed"); /* In global code, bake in the global object as 'this' object. */ if (!cx->fp->callee()) { @@ -9459,7 +9459,7 @@ TraceRecorder::getThis(LIns*& this_ins) * a null value in argv[-1], this trace will only match if we see null at * runtime as well. Bake in the global object as 'this' object, updating * the tracker as well. We can only detect this condition prior to calling - * js_ComputeThisForFrame, since it updates the interpreter's copy of + * JSStackFrame::getThisObject, since it updates the interpreter's copy of * argv[-1]. */ JSClass* clasp = NULL;; @@ -9811,7 +9811,7 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) * Make sure the shape of the global object still matches (this might * flush the JIT cache). */ - JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); + JSObject* globalObj = cx->fp->scopeChain->getGlobal(); uint32 globalShape = -1; SlotList* globalSlots = NULL; if (!CheckGlobalObjectShape(cx, traceMonitor, globalObj, &globalShape, &globalSlots)) @@ -12425,7 +12425,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, return RECORD_CONTINUE; } - if (JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(fval)) != globalObj) + if (JSVAL_TO_OBJECT(fval)->getGlobal() != globalObj) RETURN_STOP("JSOP_CALL or JSOP_NEW crosses global scopes"); JSStackFrame* fp = cx->fp; From f2295b3d732975bed0d77531ad8dd013f777faa3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Mar 2010 16:40:30 -0700 Subject: [PATCH 188/213] Update nanojit-import-rev stamp. --- js/src/nanojit-import-rev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev index 524890f927f5..6aca08dcf645 100644 --- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1 +1 @@ -b8fea2e57673f9f2d4e864870d73ee294cabd4bd +be4f098b6cb32f2c2787ef2842402f2b39e0925d From fa5f86d068817daaccdec51f885e6b4145060719 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Mar 2010 16:42:18 -0700 Subject: [PATCH 189/213] Bug 555633 - nanojit: rename opcodes in LIRopcode.tbl (TM-specific part). r=jseward. --- js/src/jstracer.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 84fbcf922cdf..704f8007a1de 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1708,13 +1708,11 @@ public: } else if (isFCmpOpcode(v)) { if (isPromoteInt(s0) && isPromoteInt(s1)) { // demote fcmp to cmp - v = LOpcode(v + (LIR_eq - LIR_feq)); + v = f64cmp_to_i32cmp(v); return out->ins2(v, demote(out, s0), demote(out, s1)); } else if (isPromoteUint(s0) && isPromoteUint(s1)) { // uint compare - v = LOpcode(v + (LIR_eq - LIR_feq)); - if (v != LIR_eq) - v = LOpcode(v + (LIR_ult - LIR_lt)); // cmp -> ucmp + v = f64cmp_to_u32cmp(v); return out->ins2(v, demote(out, s0), demote(out, s1)); } } @@ -8860,7 +8858,7 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) */ if (!fp) { JS_ASSERT(isFCmpOpcode(op)); - op = LOpcode(op + (LIR_eq - LIR_feq)); + op = f64cmp_to_i32cmp(op); } x = lir->ins2(op, l_ins, r_ins); From e2e917ef224c6f72e7b34bef67ef2dd230d9ef8f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Mar 2010 22:13:51 -0700 Subject: [PATCH 190/213] Bug 556353 - Remove OBJ_IS_NATIVE, HAS_FUNCTION_CLASS. r=brendan. --- js/src/jsapi-tests/testLookup.cpp | 2 +- js/src/jsapi.cpp | 22 ++++----- js/src/jsarray.cpp | 4 +- js/src/jsarray.h | 4 +- js/src/jsbuiltins.cpp | 4 +- js/src/jsdbgapi.cpp | 12 ++--- js/src/jsfun.cpp | 2 +- js/src/jsfun.h | 8 ++-- js/src/jsgc.cpp | 2 +- js/src/jslock.cpp | 4 +- js/src/jslock.h | 4 +- js/src/jsobj.cpp | 78 +++++++++++++++---------------- js/src/jsobj.h | 9 ++-- js/src/jsobjinlines.h | 8 ++-- js/src/jsops.cpp | 14 +++--- js/src/jsparse.cpp | 2 +- js/src/jspropertycache.cpp | 8 ++-- js/src/jsscope.cpp | 2 +- js/src/jsscriptinlines.h | 2 +- js/src/jstracer.cpp | 32 ++++++------- js/src/jstypedarray.cpp | 2 +- js/src/jsxml.cpp | 4 +- js/src/shell/js.cpp | 4 +- js/src/xpconnect/src/xpcdebug.cpp | 4 +- 24 files changed, 116 insertions(+), 121 deletions(-) diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index 82c6eb1374e8..566b47b5162a 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -20,7 +20,7 @@ BEGIN_TEST(testLookup_bug522590) CHECK(JS_LookupProperty(cx, xobj, "f", r.addr())); CHECK(JSVAL_IS_OBJECT(r)); JSObject *funobj = JSVAL_TO_OBJECT(r); - CHECK(HAS_FUNCTION_CLASS(funobj)); + CHECK(funobj->isFunction()); CHECK(!js::IsInternalFunctionObject(funobj)); CHECK(GET_FUNCTION_PRIVATE(cx, funobj) != (JSFunction *) funobj); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0132104a43b2..3d5ae08dcca4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2770,7 +2770,7 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) if (obj->isDenseArray() && !js_MakeArraySlow(cx, obj)) return JS_FALSE; - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SEAL_OBJECT, OBJ_GET_CLASS(cx, obj)->name); @@ -2851,7 +2851,7 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs, uintN flags, intN tinyid) { - if (flags != 0 && OBJ_IS_NATIVE(obj)) { + if (flags != 0 && obj->isNative()) { JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, flags, tinyid, NULL); @@ -2894,7 +2894,7 @@ DefineUCProperty(JSContext *cx, JSObject *obj, atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); if (!atom) return JS_FALSE; - if (flags != 0 && OBJ_IS_NATIVE(obj)) { + if (flags != 0 && obj->isNative()) { JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); return !!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs, flags, tinyid, @@ -3045,7 +3045,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, js_ReportIsNotDefined(cx, name); return JS_FALSE; } - if (obj2 != obj || !OBJ_IS_NATIVE(obj)) { + if (obj2 != obj || !obj->isNative()) { obj2->dropProperty(cx, prop); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS, alias, name, OBJ_GET_CLASS(cx, obj2)->name); @@ -3077,7 +3077,7 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, } JSBool ok = JS_TRUE; - if (OBJ_IS_NATIVE(obj2)) { + if (obj2->isNative()) { JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->isMethod()) { @@ -3127,7 +3127,7 @@ GetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN flags, ok = obj2->getAttributes(cx, id, prop, &desc->attrs); if (ok) { - if (OBJ_IS_NATIVE(obj2)) { + if (obj2->isNative()) { JSScopeProperty *sprop = (JSScopeProperty *) prop; desc->getter = sprop->getter(); @@ -3257,7 +3257,7 @@ AlreadyHasOwnPropertyHelper(JSContext *cx, JSObject *obj, jsid id, { JSScope *scope; - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { JSObject *obj2; JSProperty *prop; @@ -3381,7 +3381,7 @@ JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop; CHECK_REQUEST(cx); - ok = OBJ_IS_NATIVE(obj) + ok = obj->isNative() ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0 : obj->lookupProperty(cx, id, objp, &prop); if (ok) @@ -3727,7 +3727,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias) js_ReportIsNotDefined(cx, name); return JS_FALSE; } - if (obj2 != obj || !OBJ_IS_NATIVE(obj)) { + if (obj2 != obj || !obj->isNative()) { char numBuf[12]; obj2->dropProperty(cx, prop); JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias); @@ -3959,7 +3959,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) if (!iterobj) return NULL; - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { /* Native case: start with the last property in obj's own scope. */ scope = OBJ_SCOPE(obj); pdata = scope->lastProperty(); @@ -3999,7 +3999,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) if (i < 0) { /* Native case: private data is a property tree node pointer. */ obj = iterobj->getParent(); - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); scope = OBJ_SCOPE(obj); sprop = (JSScopeProperty *) iterobj->getPrivate(); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 8e5adb637928..e8cf567bab17 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -790,7 +790,7 @@ array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) return JS_FALSE; if (prop) { - if (OBJ_IS_NATIVE(obj2)) { + if (obj2->isNative()) { sprop = (JSScopeProperty *) prop; if (!js_NativeGet(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, vp)) return JS_FALSE; @@ -889,7 +889,7 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj) * a native object (possibly a slow array) that has indexed properties, * return true. */ - if (!OBJ_IS_NATIVE(obj)) + if (!obj->isNative()) return JS_TRUE; if (OBJ_SCOPE(obj)->hadIndexedProperties()) return JS_TRUE; diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 685cfe67fc06..0a0f8ab885d3 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -68,8 +68,8 @@ JSObject::isArray() const } /* - * Dense arrays are not native (OBJ_IS_NATIVE(cx, aobj) for a dense array aobj - * results in false, meaning aobj->map does not point to a JSScope). + * Dense arrays are not native -- aobj->isNative() for a dense array aobj + * results in false, meaning aobj->map does not point to a JSScope. * * But Array methods are called via aobj.sort(), e.g., and the interpreter and * the trace recorder must consult the property cache in order to perform well. diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 347b098a6051..4095a12e5fd2 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -328,8 +328,8 @@ JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, A JSObject* FASTCALL js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) { - JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); - JS_ASSERT(HAS_FUNCTION_CLASS(proto)); + JS_ASSERT(funobj->isFunction()); + JS_ASSERT(proto->isFunction()); JS_ASSERT(JS_ON_TRACE(cx)); JSFunction *fun = (JSFunction*) funobj; diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index b5a28b363805..f6ab235ce258 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -631,7 +631,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* NB: wp is held, so we can safely dereference it still. */ ok = wp->handler(cx, obj, propid, SPROP_HAS_VALID_SLOT(sprop, scope) - ? obj->lockAndGetSlot(cx, sprop->slot) + ? obj->getSlotMT(cx, sprop->slot) : JSVAL_VOID, vp, wp->closure); if (ok) { @@ -846,7 +846,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, if (origobj != obj && !obj->checkAccess(cx, propid, JSACC_WATCH, &v, &attrs)) return JS_FALSE; - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, OBJ_GET_CLASS(cx, obj)->name); return JS_FALSE; @@ -874,7 +874,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, uintN attrs, flags; intN shortid; - if (OBJ_IS_NATIVE(pobj)) { + if (pobj->isNative()) { value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)) ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot) : JSVAL_VOID; @@ -1242,7 +1242,7 @@ JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp) if (!fp->fun) return NULL; - JS_ASSERT(HAS_FUNCTION_CLASS(fp->callee())); + JS_ASSERT(fp->callee()->isFunction()); JS_ASSERT(fp->callee()->getPrivate() == fp->fun); return fp->callee(); } @@ -1501,7 +1501,7 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda) JSScopeProperty *sprop; clasp = OBJ_GET_CLASS(cx, obj); - if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { + if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DESCRIBE_PROPS, clasp->name); return JS_FALSE; @@ -1652,7 +1652,7 @@ JS_GetObjectTotalSize(JSContext *cx, JSObject *obj) nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1) * sizeof obj->dslots[0]; } - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { scope = OBJ_SCOPE(obj); if (!scope->isSharedEmpty()) { nbytes += sizeof *scope; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 1d5a4080f067..10ad08e1192c 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2458,7 +2458,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, JSFunction *fun; if (funobj) { - JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); + JS_ASSERT(funobj->isFunction()); funobj->setParent(parent); } else { funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index e1c69d321fd1..55145922de41 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -248,20 +248,18 @@ JSObject::isFunction() const return getClass() == &js_FunctionClass; } -#define HAS_FUNCTION_CLASS(obj) (obj)->isFunction() - /* * NB: jsapi.h and jsobj.h must be included before any call to this macro. */ #define VALUE_IS_FUNCTION(cx, v) \ - (!JSVAL_IS_PRIMITIVE(v) && HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v))) + (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isFunction()) /* * Macro to access the private slot of the function object after the slot is * initialized. */ #define GET_FUNCTION_PRIVATE(cx, funobj) \ - (JS_ASSERT(HAS_FUNCTION_CLASS(funobj)), \ + (JS_ASSERT((funobj)->isFunction()), \ (JSFunction *) (funobj)->getPrivate()) namespace js { @@ -274,7 +272,7 @@ namespace js { inline bool IsInternalFunctionObject(JSObject *funobj) { - JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); + JS_ASSERT(funobj->isFunction()); JSFunction *fun = (JSFunction *) funobj->getPrivate(); return funobj == fun && (fun->flags & JSFUN_LAMBDA) && !funobj->getParent(); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 35b2fa35b9e6..89d5f5c62501 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2550,7 +2550,7 @@ FinalizeObject(JSContext *cx, JSObject *obj, unsigned thingKind) jsdtrace_object_finalize(obj); #endif - if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { + if (JS_LIKELY(obj->isNative())) { JSScope *scope = OBJ_SCOPE(obj); if (scope->isSharedEmpty()) static_cast(scope)->dropFromGC(cx); diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index 05f02eb874d6..2982d7bcedb8 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -1313,7 +1313,7 @@ js_LockObj(JSContext *cx, JSObject *obj) JSScope *scope; JSTitle *title; - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); /* * We must test whether the GC is calling and return without mutating any @@ -1345,7 +1345,7 @@ js_LockObj(JSContext *cx, JSObject *obj) void js_UnlockObj(JSContext *cx, JSObject *obj) { - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); js_UnlockTitle(cx, &OBJ_SCOPE(obj)->title); } diff --git a/js/src/jslock.h b/js/src/jslock.h index 90812617d12d..15f44cc9921f 100644 --- a/js/src/jslock.h +++ b/js/src/jslock.h @@ -149,8 +149,8 @@ struct JSTitle { /* * NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects - * (objects for which OBJ_IS_NATIVE returns true). All uses of these macros in - * the engine are predicated on OBJ_IS_NATIVE or equivalent checks. These uses + * (objects for which obj->isNative() returns true). All uses of these macros in + * the engine are predicated on obj->isNative or equivalent checks. These uses * are for optimizations above the JSObjectOps layer, under which object locks * normally hide. */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 25eb9543e570..ddb12f344c07 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -251,7 +251,7 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj, JS_ASSERT_IF(!checkForCycles, obj != pobj); if (slot == JSSLOT_PROTO) { - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { JS_LOCK_OBJ(cx, obj); bool ok = !!js_GetMutableScope(cx, obj); JS_UNLOCK_OBJ(cx, obj); @@ -265,7 +265,7 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj, * case any entries were filled by looking up through obj. */ JSObject *oldproto = obj; - while (oldproto && OBJ_IS_NATIVE(oldproto)) { + while (oldproto && oldproto->isNative()) { JS_LOCK_OBJ(cx, oldproto); JSScope *scope = OBJ_SCOPE(oldproto); scope->protoShapeChange(cx); @@ -375,7 +375,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) continue; ok = obj2->getAttributes(cx, id, prop, &attrs); if (ok) { - if (OBJ_IS_NATIVE(obj2) && + if (obj2->isNative() && (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { JSScopeProperty *sprop = (JSScopeProperty *) prop; val = JSVAL_VOID; @@ -738,7 +738,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) obj2->dropProperty(cx, prop); goto error; } - if (OBJ_IS_NATIVE(obj2) && + if (obj2->isNative() && (attrs & (JSPROP_GETTER | JSPROP_SETTER))) { JSScopeProperty *sprop = (JSScopeProperty *) prop; if (attrs & JSPROP_GETTER) { @@ -1663,7 +1663,7 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, } if (outer != *objp) { - if (OBJ_IS_NATIVE(*objp) && obj->getClass() == clasp) { + if ((*objp)->isNative() && obj->getClass() == clasp) { /* * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a * delegated property makes that property appear to be direct in @@ -1783,7 +1783,7 @@ js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * to distinguish a shared permanent proto-property from a local one. */ if (pobj != obj && - !(OBJ_IS_NATIVE(pobj) && + !(pobj->isNative() && ((JSScopeProperty *)prop)->isSharedPermanent())) { pobj->dropProperty(cx, prop); *vp = JSVAL_FALSE; @@ -1879,7 +1879,7 @@ obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = JSVAL_VOID; if (prop) { - if (OBJ_IS_NATIVE(pobj)) { + if (pobj->isNative()) { sprop = (JSScopeProperty *) prop; if (sprop->hasGetterValue()) *vp = sprop->getterValue(); @@ -1904,7 +1904,7 @@ obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = JSVAL_VOID; if (prop) { - if (OBJ_IS_NATIVE(pobj)) { + if (pobj->isNative()) { sprop = (JSScopeProperty *) prop; if (sprop->hasSetterValue()) *vp = sprop->setterValue(); @@ -1962,7 +1962,7 @@ js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) jsval roots[] = { JSVAL_VOID, JSVAL_VOID }; AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { JSScopeProperty *sprop = reinterpret_cast(prop); if (attrs & JSPROP_GETTER) roots[0] = sprop->getterValue(); @@ -2558,7 +2558,7 @@ DefineProperty(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, boo if (obj->isArray()) return DefinePropertyArray(cx, obj, desc, throwError, rval); - if (!OBJ_IS_NATIVE(obj)) + if (!obj->isNative()) return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval); return DefinePropertyObject(cx, obj, desc, throwError, rval); @@ -2788,7 +2788,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* o JSClass *clasp = OBJ_GET_CLASS(cx, obj); JSScope *scope = NULL; - if (proto && OBJ_IS_NATIVE(proto)) { + if (proto && proto->isNative()) { JS_LOCK_OBJ(cx, proto); scope = OBJ_SCOPE(proto); if (scope->canProvideEmptyScope(ops, clasp)) { @@ -3028,7 +3028,7 @@ NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject* FASTCALL js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor) { - JS_ASSERT(HAS_FUNCTION_CLASS(ctor)); + JS_ASSERT(ctor->isFunction()); JSAtom *atom = cx->runtime->atomState.classPrototypeAtom; @@ -3902,7 +3902,7 @@ js_ShrinkSlots(JSContext *cx, JSObject *obj, size_t nslots) bool js_EnsureReservedSlots(JSContext *cx, JSObject *obj, size_t nreserved) { - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); JS_ASSERT(!obj->dslots); uintN nslots = JSSLOT_FREE(obj->getClass()) + nreserved; @@ -4062,14 +4062,14 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, id = ATOM_TO_JSID(atom); } - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, &pobj, &prop) < 0) { return JS_FALSE; } v = JSVAL_VOID; if (prop) { - if (OBJ_IS_NATIVE(pobj)) { + if (pobj->isNative()) { sprop = (JSScopeProperty *) prop; if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))) { v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot); @@ -4258,7 +4258,7 @@ PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id) JSScopeProperty *sprop; while (obj) { - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { obj = obj->getProto(); continue; } @@ -4619,7 +4619,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, /* Resolved: juggle locks and lookup id again. */ if (obj2 != obj) { JS_UNLOCK_OBJ(cx, obj); - if (OBJ_IS_NATIVE(obj2)) + if (obj2->isNative()) JS_LOCK_OBJ(cx, obj2); } protoIndex = 0; @@ -4627,7 +4627,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, proto = proto->getProto()) { protoIndex++; } - if (!OBJ_IS_NATIVE(obj2)) { + if (!obj2->isNative()) { /* Whoops, newresolve handed back a foreign obj2. */ JS_ASSERT(obj2 != obj); ok = obj2->lookupProperty(cx, id, objp, propp); @@ -4652,7 +4652,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, JS_ASSERT(!scope->isSharedEmpty()); obj = obj2; } else if (obj2 != obj) { - if (OBJ_IS_NATIVE(obj2)) + if (obj2->isNative()) JS_UNLOCK_OBJ(cx, obj2); JS_LOCK_OBJ(cx, obj); } @@ -4667,7 +4667,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, if (!ok) goto cleanup; JS_LOCK_OBJ(cx, obj); - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); scope = OBJ_SCOPE(obj); if (!scope->isSharedEmpty()) sprop = scope->lookup(id); @@ -4695,7 +4695,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, JS_UNLOCK_OBJ(cx, obj); if (!proto) break; - if (!OBJ_IS_NATIVE(proto)) { + if (!proto->isNative()) { if (!proto->lookupProperty(cx, id, objp, propp)) return -1; return protoIndex + 1; @@ -4753,7 +4753,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, #ifdef DEBUG if (parent) { JSClass *clasp = OBJ_GET_CLASS(cx, obj); - JS_ASSERT(OBJ_IS_NATIVE(pobj)); + JS_ASSERT(pobj->isNative()); JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == clasp); if (clasp == &js_BlockClass) { /* @@ -4847,7 +4847,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id) if (protoIndex < 0) return NULL; if (prop) { - JS_ASSERT(OBJ_IS_NATIVE(pobj)); + JS_ASSERT(pobj->isNative()); JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj)); #ifdef DEBUG PropertyCacheEntry *entry = @@ -4899,7 +4899,7 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, uint32 slot; int32 sample; - JS_ASSERT(OBJ_IS_NATIVE(pobj)); + JS_ASSERT(pobj->isNative()); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj)); scope = OBJ_SCOPE(pobj); @@ -4949,7 +4949,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, uint32 slot; int32 sample; - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj)); scope = OBJ_SCOPE(obj); @@ -5080,7 +5080,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, return JS_TRUE; } - if (!OBJ_IS_NATIVE(obj2)) { + if (!obj2->isNative()) { obj2->dropProperty(cx, prop); return obj2->getProperty(cx, id, vp); } @@ -5194,7 +5194,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (protoIndex < 0) return JS_FALSE; if (prop) { - if (!OBJ_IS_NATIVE(pobj)) { + if (!pobj->isNative()) { pobj->dropProperty(cx, prop); prop = NULL; } @@ -5416,7 +5416,7 @@ js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, *attrsp = 0; return JS_TRUE; } - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { ok = obj->getAttributes(cx, id, prop, attrsp); obj->dropProperty(cx, prop); return ok; @@ -5442,7 +5442,7 @@ js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, return JS_FALSE; if (!prop) return JS_TRUE; - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { ok = obj->setAttributes(cx, id, prop, attrsp); obj->dropProperty(cx, prop); return ok; @@ -5480,7 +5480,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) * each delegating object. */ if (prop) { - if (OBJ_IS_NATIVE(proto)) { + if (proto->isNative()) { sprop = (JSScopeProperty *)prop; if (sprop->isSharedPermanent()) *rval = JSVAL_FALSE; @@ -5920,7 +5920,7 @@ js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, break; } - if (!OBJ_IS_NATIVE(pobj)) { + if (!pobj->isNative()) { pobj->dropProperty(cx, prop); /* Avoid diverging for non-natives that reuse js_CheckAccess. */ @@ -6516,7 +6516,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) JS_ASSERT(slot >= JSSLOT_START(obj->getClass())); JSScopeProperty *sprop; - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { JSScope *scope = OBJ_SCOPE(obj); sprop = scope->lastProperty(); while (sprop && sprop->slot != slot) @@ -6556,7 +6556,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) void js_TraceObject(JSTracer *trc, JSObject *obj) { - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); JSContext *cx = trc->context; JSScope *scope = OBJ_SCOPE(obj); @@ -6663,7 +6663,7 @@ ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp, bool js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) { - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { *vp = JSVAL_VOID; return true; } @@ -6684,7 +6684,7 @@ js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) bool js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) { - if (!OBJ_IS_NATIVE(obj)) + if (!obj->isNative()) return true; JSClass *clasp = OBJ_GET_CLASS(cx, obj); @@ -6852,7 +6852,7 @@ dumpValue(jsval val) } else if (JSVAL_IS_VOID(val)) { fprintf(stderr, "undefined"); } else if (JSVAL_IS_OBJECT(val) && - HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(val))) { + JSVAL_TO_OBJECT(val)->isFunction()) { JSObject *funobj = JSVAL_TO_OBJECT(val); JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); fprintf(stderr, "<%s %s at %p (JSFunction at %p)>", @@ -6949,7 +6949,7 @@ js_DumpObject(JSObject *obj) return; } - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { JSScope *scope = OBJ_SCOPE(obj); if (scope->sealed()) fprintf(stderr, "sealed\n"); @@ -6960,7 +6960,7 @@ js_DumpObject(JSObject *obj) dumpScopeProp(sprop); } } else { - if (!OBJ_IS_NATIVE(obj)) + if (!obj->isNative()) fprintf(stderr, "not native\n"); } @@ -6980,7 +6980,7 @@ js_DumpObject(JSObject *obj) fprintf(stderr, "slots:\n"); reservedEnd = i + JSCLASS_RESERVED_SLOTS(clasp); - slots = (OBJ_IS_NATIVE(obj) && !OBJ_SCOPE(obj)->isSharedEmpty()) + slots = (obj->isNative() && !OBJ_SCOPE(obj)->isSharedEmpty()) ? OBJ_SCOPE(obj)->freeslot : obj->numSlots(); for (; i < slots; i++) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index f0e54a5ebca8..034240b5773e 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -312,13 +312,13 @@ struct JSObject { } /* - * These ones are for multi-threaded objects. Use getSlot(), + * These ones are for multi-threaded ("MT") objects. Use getSlot(), * getSlotRef(), setSlot() to directly manipulate slots in obj when only * one thread can access obj, or when accessing read-only slots within * JS_INITIAL_NSLOTS. */ - jsval lockAndGetSlot(JSContext *cx, uintN slot); - void lockAndSetSlot(JSContext *cx, uintN slot, jsval value); + inline jsval getSlotMT(JSContext *cx, uintN slot); + inline void setSlotMT(JSContext *cx, uintN slot, jsval value); JSObject *getProto() const { return JSVAL_TO_OBJECT(fslots[JSSLOT_PROTO]); @@ -484,9 +484,6 @@ struct JSObject { inline bool unbrand(JSContext *cx); }; -/* Compatibility macro. */ -#define OBJ_IS_NATIVE(obj) ((obj)->isNative()) - #define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \ ? JSSLOT_PRIVATE + 1 \ : JSSLOT_PRIVATE) diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index a96923042ae1..7ba3a71be1c8 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -45,10 +45,10 @@ #include "jsscope.h" inline jsval -JSObject::lockAndGetSlot(JSContext *cx, uintN slot) { +JSObject::getSlotMT(JSContext *cx, uintN slot) { #ifdef JS_THREADSAFE /* - * If thread-safe, define a lockAndGetSlot() that bypasses, for a native + * If thread-safe, define a getSlotMT() that bypasses, for a native * object, the lock-free "fast path" test of * (OBJ_SCOPE(obj)->ownercx == cx), to avoid needlessly switching from * lock-free to lock-full scope when doing GC on a different context @@ -66,7 +66,7 @@ JSObject::lockAndGetSlot(JSContext *cx, uintN slot) { } inline void -JSObject::lockAndSetSlot(JSContext *cx, uintN slot, jsval value) { +JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value) { #ifdef JS_THREADSAFE /* Thread-safe way to set a slot. */ OBJ_CHECK_SLOT(this, slot); @@ -102,7 +102,7 @@ JSObject::freeSlotsArray(JSContext *cx) inline bool JSObject::unbrand(JSContext *cx) { - if (OBJ_IS_NATIVE(this)) { + if (this->isNative()) { JS_LOCK_OBJ(cx, this); JSScope *scope = OBJ_SCOPE(this); if (scope->isSharedEmpty()) { diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 74568983b96c..4ea1dcd45b74 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -1400,7 +1400,7 @@ BEGIN_CASE(JSOP_GVARINC) } slot = JSVAL_TO_INT(lval); JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); - rval = cx->activeCallStack()->getInitialVarObj()->lockAndGetSlot(cx, slot); + rval = cx->activeCallStack()->getInitialVarObj()->getSlotMT(cx, slot); if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { PUSH_OPND(rval + incr2); rval += incr; @@ -1412,7 +1412,7 @@ BEGIN_CASE(JSOP_GVARINC) rval = regs.sp[-1]; --regs.sp; } - fp->varobj(cx)->lockAndSetSlot(cx, slot, rval); + fp->varobj(cx)->setSlotMT(cx, slot, rval); len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */ JS_ASSERT(len == js_CodeSpec[op].length); DO_NEXT_OP(len); @@ -1714,7 +1714,7 @@ BEGIN_CASE(JSOP_SETMETHOD) if (!sprop->hasSlot()) { if (entry->vcapTag() == 0 || ((obj2 = obj->getProto()) && - OBJ_IS_NATIVE(obj2) && + obj2->isNative() && OBJ_SHAPE(obj2) == entry->vshape())) { goto fast_set_propcache_hit; } @@ -2329,7 +2329,7 @@ BEGIN_CASE(JSOP_CALLNAME) } /* Take the slow path if prop was not found in a native object. */ - if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) { + if (!obj->isNative() || !obj2->isNative()) { obj2->dropProperty(cx, prop); if (!obj->getProperty(cx, id, &rval)) goto error; @@ -2748,7 +2748,7 @@ BEGIN_CASE(JSOP_CALLGVAR) JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); obj = cx->activeCallStack()->getInitialVarObj(); slot = JSVAL_TO_INT(lval); - rval = obj->lockAndGetSlot(cx, slot); + rval = obj->getSlotMT(cx, slot); PUSH_OPND(rval); if (op == JSOP_CALLGVAR) PUSH_OPND(OBJECT_TO_JSVAL(obj)); @@ -2841,7 +2841,7 @@ BEGIN_CASE(JSOP_DEFVAR) if (!fp->fun && index < GlobalVarCount(fp) && obj2 == obj && - OBJ_IS_NATIVE(obj)) { + obj->isNative()) { sprop = (JSScopeProperty *) prop; if (!sprop->configurable() && SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) && @@ -3365,7 +3365,7 @@ BEGIN_CASE(JSOP_INITMETHOD) /* Load the object being initialized into lval/obj. */ lval = FETCH_OPND(-2); obj = JSVAL_TO_OBJECT(lval); - JS_ASSERT(OBJ_IS_NATIVE(obj)); + JS_ASSERT(obj->isNative()); JS_ASSERT(!OBJ_GET_CLASS(cx, obj)->reserveSlots); JS_ASSERT(!(obj->getClass()->flags & JSCLASS_SHARE_ALL_PROPERTIES)); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 26bcb0a7377c..09c21da2f90e 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -223,7 +223,7 @@ JSFunctionBox * JSCompiler::newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc) { JS_ASSERT(obj); - JS_ASSERT(HAS_FUNCTION_CLASS(obj)); + JS_ASSERT(obj->isFunction()); /* * We use JSContext.tempPool to allocate parsed objects and place them on diff --git a/js/src/jspropertycache.cpp b/js/src/jspropertycache.cpp index b6e610fc09e6..ec4511839cf0 100644 --- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -108,7 +108,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI * non-native ones on the prototype chain. The non-natives can * mutate in arbitrary way without changing any shapes. */ - if (!tmp || !OBJ_IS_NATIVE(tmp)) { + if (!tmp || !tmp->isNative()) { PCMETER(noprotos++); return JS_NO_PROP_CACHE_FILL; } @@ -240,7 +240,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI * __proto__ assignment we may not find one. */ JSObject *proto = obj->getProto(); - if (!proto || !OBJ_IS_NATIVE(proto)) + if (!proto || !proto->isNative()) return JS_NO_PROP_CACHE_FILL; JSScope *protoscope = OBJ_SCOPE(proto); if (!protoscope->emptyScope || @@ -374,7 +374,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject if (JOF_MODE(cs.format) == JOF_NAME) { while (vcap & (PCVCAP_SCOPEMASK << PCVCAP_PROTOBITS)) { tmp = pobj->getParent(); - if (!tmp || !OBJ_IS_NATIVE(tmp)) + if (!tmp || !tmp->isNative()) break; pobj = tmp; vcap -= PCVCAP_PROTOSIZE; @@ -385,7 +385,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject while (vcap & PCVCAP_PROTOMASK) { tmp = pobj->getProto(); - if (!tmp || !OBJ_IS_NATIVE(tmp)) + if (!tmp || !tmp->isNative()) break; pobj = tmp; --vcap; diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 0c19fe349d1e..482ca4231e72 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -1142,7 +1142,7 @@ JSScope::clear(JSContext *cx) JSEmptyScope *emptyScope; uint32 newShape; if (proto && - OBJ_IS_NATIVE(proto) && + proto->isNative() && (emptyScope = OBJ_SCOPE(proto)->emptyScope) && emptyScope->clasp == clasp) { newShape = emptyScope->shape; diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index 33f6b6347ea6..0ac77a4871ff 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -50,7 +50,7 @@ inline JSFunction * JSScript::getFunction(size_t index) { JSObject *funobj = getObject(index); - JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); + JS_ASSERT(funobj->isFunction()); JS_ASSERT(funobj == (JSObject *) funobj->getPrivate()); JSFunction *fun = (JSFunction *) funobj; JS_ASSERT(FUN_INTERPRETED(fun)); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 4d153e48c80c..f4d29ece6a63 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -1037,7 +1037,7 @@ GetPromotedType(jsval v) if (JSVAL_IS_OBJECT(v)) { if (JSVAL_IS_NULL(v)) return TT_NULL; - if (HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v))) + if (JSVAL_TO_OBJECT(v)->isFunction()) return TT_FUNCTION; return TT_OBJECT; } @@ -1061,7 +1061,7 @@ getCoercedType(jsval v) if (JSVAL_IS_OBJECT(v)) { if (JSVAL_IS_NULL(v)) return TT_NULL; - if (HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v))) + if (JSVAL_TO_OBJECT(v)->isFunction()) return TT_FUNCTION; return TT_OBJECT; } @@ -2566,7 +2566,7 @@ ValueToNative(JSContext* cx, jsval v, TraceType type, double* slot) switch (type) { case TT_OBJECT: JS_ASSERT(tag == JSVAL_OBJECT); - JS_ASSERT(!JSVAL_IS_NULL(v) && !HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v))); + JS_ASSERT(!JSVAL_IS_NULL(v) && !JSVAL_TO_OBJECT(v)->isFunction()); *(JSObject**)slot = JSVAL_TO_OBJECT(v); debug_only_printf(LC_TMTracer, "object<%p:%s> ", (void*)JSVAL_TO_OBJECT(v), @@ -2805,7 +2805,7 @@ NativeToValue(JSContext* cx, jsval& v, TraceType type, double* slot) break; case TT_FUNCTION: { - JS_ASSERT(HAS_FUNCTION_CLASS(*(JSObject**)slot)); + JS_ASSERT((*(JSObject**)slot)->isFunction()); v = OBJECT_TO_JSVAL(*(JSObject**)slot); #ifdef DEBUG JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v)); @@ -3296,7 +3296,7 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, do JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(fp); JS_ASSERT(JSVAL_IS_OBJECT(fp->argv[-1])); - JS_ASSERT(HAS_FUNCTION_CLASS(fp->calleeObject())); + JS_ASSERT(fp->calleeObject()->isFunction()); JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee()) == fp->fun); if (FUN_INTERPRETED(fp->fun) && @@ -3844,7 +3844,7 @@ TraceRecorder::determineSlotType(jsval* vp) } else if (JSVAL_IS_OBJECT(*vp)) { if (JSVAL_IS_NULL(*vp)) m = TT_NULL; - else if (HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(*vp))) + else if (JSVAL_TO_OBJECT(*vp)->isFunction()) m = TT_FUNCTION; else m = TT_OBJECT; @@ -5241,7 +5241,7 @@ TraceRecorder::hasMethod(JSObject* obj, jsid id, bool& found) if (!prop) return status; - if (!OBJ_IS_NATIVE(pobj)) { + if (!pobj->isNative()) { // We can't rely on __iterator__ being present on trace just because // it's there now, if found in a non-native object. status = RECORD_STOP; @@ -6077,7 +6077,7 @@ IsEntryTypeCompatible(jsval* vp, TraceType* m) switch (*m) { case TT_OBJECT: if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) && - !HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(*vp))) { + !JSVAL_TO_OBJECT(*vp)->isFunction()) { return true; } debug_only_printf(LC_TMTracer, "object != tag%u ", tag); @@ -6122,7 +6122,7 @@ IsEntryTypeCompatible(jsval* vp, TraceType* m) default: JS_ASSERT(*m == TT_FUNCTION); if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) && - HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(*vp))) { + JSVAL_TO_OBJECT(*vp)->isFunction()) { return true; } debug_only_printf(LC_TMTracer, "fun != tag%u ", tag); @@ -9161,7 +9161,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 RETURN_ERROR_A("error in js_LookupPropertyWithFlags"); if (prop) { - if (!OBJ_IS_NATIVE(obj2)) { + if (!obj2->isNative()) { obj2->dropProperty(cx, prop); RETURN_STOP_A("property found on non-native object"); } @@ -9394,7 +9394,7 @@ TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit) INS_CONSTWORD(JSVAL_OBJECT)), exit); - guard(HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v)), + guard(JSVAL_TO_OBJECT(v)->isFunction(), lir->ins2(LIR_peq, lir->ins2(LIR_piand, lir->insLoad(LIR_ldp, v_ins, offsetof(JSObject, classword), @@ -10364,7 +10364,7 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins) #ifdef DEBUG /* Double-check that a native proto has a matching emptyScope. */ if (key != JSProto_Array) { - JS_ASSERT(OBJ_IS_NATIVE(proto)); + JS_ASSERT(proto->isNative()); JSEmptyScope *emptyScope = OBJ_SCOPE(proto)->emptyScope; JS_ASSERT(emptyScope); JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(emptyScope->clasp) == key); @@ -12163,7 +12163,7 @@ TraceRecorder::record_JSOP_CALLNAME() if (pcval.isNull() || !pcval.isObject()) RETURN_STOP_A("callee is not an object"); - JS_ASSERT(HAS_FUNCTION_CLASS(pcval.toObject())); + JS_ASSERT(pcval.toObject()->isFunction()); stack(0, INS_CONSTOBJ(pcval.toObject())); stack(1, obj_ins); @@ -12812,7 +12812,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, */ VMSideExit* exit = snapshot(BRANCH_EXIT); do { - if (OBJ_IS_NATIVE(obj)) { + if (obj->isNative()) { CHECK_STATUS_A(InjectStatus(guardShape(obj_ins, obj, OBJ_SHAPE(obj), "guard(shape)", exit))); } else if (!guardDenseArray(obj, obj_ins, exit)) { @@ -14565,7 +14565,7 @@ TraceRecorder::record_JSOP_CALLPROP() if (pcval.isNull()) RETURN_STOP_A("callprop of missing method"); - JS_ASSERT(HAS_FUNCTION_CLASS(pcval.toObject())); + JS_ASSERT(pcval.toObject()->isFunction()); if (JSVAL_IS_PRIMITIVE(l)) { JSFunction* fun = GET_FUNCTION_PRIVATE(cx, pcval.toObject()); @@ -15017,7 +15017,7 @@ TraceRecorder::record_JSOP_LENGTH() stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE), js::TypedArray::lengthOffset(), ACC_READONLY)); } else { - if (!OBJ_IS_NATIVE(obj)) + if (!obj->isNative()) RETURN_STOP_A("can't trace length property access on non-array, non-native object"); return getProp(obj, obj_ins); } diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 70f146f51889..51ffdd1f8df4 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -508,7 +508,7 @@ class TypedArrayTemplate return false; if (prop) { - if (OBJ_IS_NATIVE(obj2)) { + if (obj2->isNative()) { sprop = (JSScopeProperty *) prop; if (!js_NativeGet(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, vp)) return false; diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 48ec850f5673..4bd4107ae892 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -5261,7 +5261,7 @@ out: return ok; } -/* Use NULL for objectMap so XML objects satisfy OBJ_IS_NATIVE tests. */ +/* Use NULL for objectMap so XML objects satisfy obj->isNative() tests. */ JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = { NULL, xml_lookupProperty, xml_defineProperty, @@ -7285,7 +7285,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) JS_ASSERT(prop); sprop = (JSScopeProperty *) prop; JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))); - cval = pobj->lockAndGetSlot(cx, sprop->slot); + cval = pobj->getSlotMT(cx, sprop->slot); pobj->dropProperty(cx, prop); JS_ASSERT(VALUE_IS_FUNCTION(cx, cval)); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8807a80866c6..7ad7237934c2 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1821,7 +1821,7 @@ DisassembleValue(JSContext *cx, jsval v, bool lines, bool recursive) JSObjectArray *objects = script->objects(); for (uintN i = 0; i != objects->length; ++i) { JSObject *obj = objects->vector[i]; - if (HAS_FUNCTION_CLASS(obj)) { + if (obj->isFunction()) { putchar('\n'); if (!DisassembleValue(cx, OBJECT_TO_JSVAL(obj), lines, recursive)) { @@ -3107,7 +3107,7 @@ ShapeOf(JSContext *cx, uintN argc, jsval *vp) *vp = JSVAL_ZERO; return JS_TRUE; } - if (!OBJ_IS_NATIVE(obj)) { + if (!obj->isNative()) { *vp = INT_TO_JSVAL(-1); return JS_TRUE; } diff --git a/js/src/xpconnect/src/xpcdebug.cpp b/js/src/xpconnect/src/xpcdebug.cpp index 6dff5c49cf8c..b35bbf8819e2 100644 --- a/js/src/xpconnect/src/xpcdebug.cpp +++ b/js/src/xpconnect/src/xpcdebug.cpp @@ -426,7 +426,7 @@ static const int tab_width = 2; static void PrintObjectBasics(JSObject* obj) { - if(OBJ_IS_NATIVE(obj)) + if (obj->isNative()) printf("%p 'native' <%s>", (void *)obj, obj->getClass()->name); else @@ -450,7 +450,7 @@ static void PrintObject(JSObject* obj, int depth, ObjectPile* pile) return; } - if(!OBJ_IS_NATIVE(obj)) + if(!obj->isNative()) return; JSObject* parent = obj->getParent(); From a460adbcce37eef5c4068edff68396edec560572 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Thu, 1 Apr 2010 11:01:14 -0500 Subject: [PATCH 191/213] No bug: fix visibility warnings in GCC, no_r=me --- js/src/jscntxt.h | 12 ++++++++++++ js/src/jsobj.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index a67545adcb9b..46e465da2c9d 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -704,9 +704,15 @@ struct JSClassProtoCache { GlobalAndProto entries[JSProto_LIMIT - JSProto_Object]; +#ifdef __GNUC__ +# pragma GCC visibility push(default) +#endif friend JSBool js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop, JSClass *clasp); +#ifdef __GNUC__ +# pragma GCC visibility pop +#endif }; struct JSRuntime { @@ -1617,7 +1623,13 @@ class AutoGCRooter { inline void trace(JSTracer *trc); +#ifdef __GNUC__ +# pragma GCC visibility push(default) +#endif friend void ::js_TraceContext(JSTracer *trc, JSContext *acx); +#ifdef __GNUC__ +# pragma GCC visibility pop +#endif protected: AutoGCRooter * const down; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 034240b5773e..079491149055 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1003,7 +1003,7 @@ js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); */ extern JS_FRIEND_API(JSBool) js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, - JSObject **protop, JSClass *clasp = NULL); + JSObject **protop, JSClass *clasp = NULL); extern JSBool js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, From ecaa6c343f8420a9592221fe1a937aaa3893fd26 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Thu, 1 Apr 2010 13:50:38 -0500 Subject: [PATCH 192/213] Bug 554195 - jsdtoa.cpp should #define MALLOC and FREE. r=jwalden. --- js/src/jsdtoa.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/jsdtoa.cpp b/js/src/jsdtoa.cpp index 1d089f3c79f1..b181142fce8b 100644 --- a/js/src/jsdtoa.cpp +++ b/js/src/jsdtoa.cpp @@ -76,6 +76,8 @@ */ #define NO_GLOBAL_STATE +#define MALLOC js_malloc +#define FREE js_free #include "dtoa.c" /* Mapping of JSDToStrMode -> js_dtoa mode */ From 8b40afd64021c6e3747e0b34488be0421a725f36 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 1 Apr 2010 12:41:01 -0700 Subject: [PATCH 193/213] Remove JSTreeContext/TokenStream warnings (no bug, r=me) --- js/src/jsparse.h | 4 +--- js/src/jsprvtd.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/js/src/jsparse.h b/js/src/jsparse.h index fa9b12740915..ad1d6e4c48bb 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -908,8 +908,6 @@ struct JSFunctionBoxQueue { #define NUM_TEMP_FREELISTS 6U /* 32 to 2048 byte size classes (32 bit) */ -class JSTreeContext; - typedef struct BindData BindData; struct JSCompiler : private js::AutoGCRooter { @@ -940,7 +938,7 @@ struct JSCompiler : private js::AutoGCRooter { ~JSCompiler(); friend void js::AutoGCRooter::trace(JSTracer *trc); - friend class JSTreeContext; + friend struct JSTreeContext; /* * Initialize a compiler. Parameters are passed on to init tokenStream. diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index f8a9f9e11875..f6355713d075 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -144,7 +144,7 @@ class TraceRecorder; struct TraceMonitor; class CallStack; -struct TokenStream; +class TokenStream; struct Token; struct TokenPos; struct TokenPtr; From 6f3eb1c0711be9c66d386fcdbd115752437cbbb0 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Thu, 1 Apr 2010 16:19:45 -0400 Subject: [PATCH 194/213] JSON stringify and parse have the wrong length. bug 554082. r=waldo --- js/src/json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/json.cpp b/js/src/json.cpp index fee0b557ffd1..13d7bbbf13f6 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -1222,8 +1222,8 @@ static JSFunctionSpec json_static_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, json_toSource, 0, 0), #endif - JS_FN("parse", js_json_parse, 1, 0), - JS_FN("stringify", js_json_stringify, 1, 0), + JS_FN("parse", js_json_parse, 2, 0), + JS_FN("stringify", js_json_stringify, 3, 0), JS_FS_END }; From 8b30b0aa4260822303c7cd13f8a0e0ddd0d551d6 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Thu, 1 Apr 2010 16:20:35 -0400 Subject: [PATCH 195/213] Bug 554079: JSON.parse should reject control characters. r=waldo --- js/src/json.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/src/json.cpp b/js/src/json.cpp index 13d7bbbf13f6..509051e814bb 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -1109,6 +1109,11 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len return JS_FALSE; } else if (c == '\\') { *jp->statep = JSON_PARSE_STATE_STRING_ESCAPE; + } else if (c < 31) { + // The JSON lexical grammer does not allow a JSONStringCharacter to be + // any of the Unicode characters U+0000 thru U+001F (control characters). + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); + return JS_FALSE; } else { if (!jp->buffer.append(c)) return JS_FALSE; From 7e0d91db763e1647ff5bd050ab094da42fc12252 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Thu, 1 Apr 2010 16:22:49 -0400 Subject: [PATCH 196/213] Bug 554152: Fix handling of space parameter match final spec. r=waldo --- js/src/json.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/js/src/json.cpp b/js/src/json.cpp index 509051e814bb..40e54cc71848 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -514,19 +514,26 @@ Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp, static JSBool InitializeGap(JSContext *cx, jsval space, JSCharBuffer &cb) { + AutoValueRooter gap(cx, space); + if (!JSVAL_IS_PRIMITIVE(space)) { - JSClass *clasp = OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(space)); - if (clasp == &js_StringClass || clasp == &js_NumberClass) - return js_ValueToCharBuffer(cx, space, cb); + JSObject *obj = JSVAL_TO_OBJECT(space); + JSClass *clasp = OBJ_GET_CLASS(cx, obj); + if (clasp == &js_NumberClass || clasp == &js_StringClass) + *gap.addr() = obj->fslots[JSSLOT_PRIMITIVE_THIS]; } - if (JSVAL_IS_STRING(space)) - return js_ValueToCharBuffer(cx, space, cb); + if (JSVAL_IS_STRING(gap.value())) { + if (!js_ValueToCharBuffer(cx, gap.value(), cb)) + return JS_FALSE; + if (cb.length() > 10) + cb.resize(10); + } - if (JSVAL_IS_NUMBER(space)) { - jsdouble d = JSVAL_IS_INT(space) - ? JSVAL_TO_INT(space) - : js_DoubleToInteger(*JSVAL_TO_DOUBLE(space)); + if (JSVAL_IS_NUMBER(gap.value())) { + jsdouble d = JSVAL_IS_INT(gap.value()) + ? JSVAL_TO_INT(gap.value()) + : js_DoubleToInteger(*JSVAL_TO_DOUBLE(gap.value())); d = JS_MIN(10, d); if (d >= 1 && !cb.appendN(' ', uint32(d))) return JS_FALSE; From e559c398b371b9802147d84e8e763fd9c417291c Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Thu, 1 Apr 2010 16:50:57 -0400 Subject: [PATCH 197/213] Bug 554851: MSVC warning C4345 is lame. r=lw --- js/src/configure.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/configure.in b/js/src/configure.in index 8ad78220d941..616a4144602d 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -447,6 +447,8 @@ case "$target" in # Make sure compilers are valid CFLAGS="$CFLAGS -TC -nologo" CXXFLAGS="$CXXFLAGS -TP -nologo" + # MSVC warning C4345 warns of newly conformant behavior as of VS2003. + CXXFLAGS="$CXXFLAGS -wd4345" AC_LANG_SAVE AC_LANG_C AC_TRY_COMPILE([#include ], From f8296cc3ed1914829ab6dc9ad8932a74f411f435 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Thu, 1 Apr 2010 16:54:03 -0400 Subject: [PATCH 198/213] Bug 554798: msvc warning in json.cpp. r=waldo --- js/src/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/json.cpp b/js/src/json.cpp index 40e54cc71848..a4883610c023 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -120,7 +120,7 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); - ok &= js_FinishJSONParse(cx, jp, reviver.value()); + ok &= !!js_FinishJSONParse(cx, jp, reviver.value()); } return ok; From c53682fd7edb5fd7f049a5f684aae2c350928385 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Thu, 1 Apr 2010 16:54:57 -0400 Subject: [PATCH 199/213] Bug 554850: silence JSBool -> bool conversion warnings in msvc. r=waldo --- js/src/jsarray.cpp | 6 +++--- js/src/jsfun.cpp | 8 ++++---- js/src/jsopcode.cpp | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index e8cf567bab17..d5b1b390641a 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2292,9 +2292,9 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) ca.elemroot = js_AllocStack(cx, 2 + 2, &mark); if (!ca.elemroot) return false; - bool ok = js_MergeSort(vec, size_t(newlen), sizeof(jsval), - comparator_stack_cast(sort_compare), - &ca, mergesort_tmp); + bool ok = !!js_MergeSort(vec, size_t(newlen), sizeof(jsval), + comparator_stack_cast(sort_compare), + &ca, mergesort_tmp); js_FreeStack(cx, mark); if (!ok) return false; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 10ad08e1192c..3d3c1f54ecec 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1695,7 +1695,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } #endif for (i = 0; i != bitmapLength; ++i) { - ok = JS_XDRUint32(xdr, &bitmap[i]); + ok = !!JS_XDRUint32(xdr, &bitmap[i]); if (!ok) goto release_mark; } @@ -1704,7 +1704,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] & JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) { if (xdr->mode == JSXDR_DECODE) { - ok = js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG); + ok = !!js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG); if (!ok) goto release_mark; } else { @@ -1714,7 +1714,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } if (xdr->mode == JSXDR_ENCODE) name = JS_LOCAL_NAME_TO_ATOM(names[i]); - ok = js_XDRStringAtom(xdr, &name); + ok = !!js_XDRStringAtom(xdr, &name); if (!ok) goto release_mark; if (xdr->mode == JSXDR_DECODE) { @@ -1726,7 +1726,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) ? JSLOCAL_CONST : JSLOCAL_VAR) : JSLOCAL_UPVAR; - ok = js_AddLocal(xdr->cx, fun, name, localKind); + ok = !!js_AddLocal(xdr->cx, fun, name, localKind); if (!ok) goto release_mark; } diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index ad06dc64bd4a..5123d272d6f3 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -753,9 +753,9 @@ js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun, INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); JS_InitArenaPool(&jp->pool, name, 256, 1, &cx->scriptStackQuota); jp->indent = indent; - jp->pretty = pretty; - jp->grouped = grouped; - jp->strict = strict; + jp->pretty = !!pretty; + jp->grouped = !!grouped; + jp->strict = !!strict; jp->script = NULL; jp->dvgfence = NULL; jp->pcstack = NULL; From 0fb98b223dcad478d08ab7bfb36454014065e4a5 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Fri, 2 Apr 2010 08:03:11 -0400 Subject: [PATCH 200/213] Disable reftest 508908-1.xul. See bug 556124. --- layout/reftests/bugs/reftest.list | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 15ecf7395c5c..3ae1b44010e6 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1353,7 +1353,8 @@ fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") == 488692-1.html 488692-1-ref.html # needs == 507762-2.html 507762-2-ref.html == 507762-3.html 507762-1-ref.html == 507762-4.html 507762-2-ref.html -== 508908-1.xul 508908-1-ref.xul +# see bug 556124 +fails == 508908-1.xul 508908-1-ref.xul == 508919-1.xhtml 508919-1-ref.xhtml == 509155-1.xhtml 509155-1-ref.xhtml == 512410.html 512410-ref.html From ddd7aaa1d3669b65d8db654796a778e3a57cc6f2 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 12:02:17 -0700 Subject: [PATCH 201/213] Bug 538324 - Move ctypes into js/src. Part 1: Move ctypes into js/src/ctypes. r=sayrer --HG-- rename : js/ctypes/CTypes.cpp => js/src/ctypes/CTypes.cpp rename : js/ctypes/CTypes.h => js/src/ctypes/CTypes.h rename : js/ctypes/Library.cpp => js/src/ctypes/Library.cpp rename : js/ctypes/Library.h => js/src/ctypes/Library.h rename : js/ctypes/ctypes.msg => js/src/ctypes/ctypes.msg rename : js/ctypes/libffi.patch => js/src/ctypes/libffi.patch rename : js/ctypes/libffi/ChangeLog => js/src/ctypes/libffi/ChangeLog rename : js/ctypes/libffi/ChangeLog.libffi => js/src/ctypes/libffi/ChangeLog.libffi rename : js/ctypes/libffi/ChangeLog.libgcj => js/src/ctypes/libffi/ChangeLog.libgcj rename : js/ctypes/libffi/ChangeLog.v1 => js/src/ctypes/libffi/ChangeLog.v1 rename : js/ctypes/libffi/LICENSE => js/src/ctypes/libffi/LICENSE rename : js/ctypes/libffi/Makefile.am => js/src/ctypes/libffi/Makefile.am rename : js/ctypes/libffi/Makefile.in => js/src/ctypes/libffi/Makefile.in rename : js/ctypes/libffi/README => js/src/ctypes/libffi/README rename : js/ctypes/libffi/acinclude.m4 => js/src/ctypes/libffi/acinclude.m4 rename : js/ctypes/libffi/aclocal.m4 => js/src/ctypes/libffi/aclocal.m4 rename : js/ctypes/libffi/compile => js/src/ctypes/libffi/compile rename : js/ctypes/libffi/config.guess => js/src/ctypes/libffi/config.guess rename : js/ctypes/libffi/config.sub => js/src/ctypes/libffi/config.sub rename : js/ctypes/libffi/configure => js/src/ctypes/libffi/configure rename : js/ctypes/libffi/configure.ac => js/src/ctypes/libffi/configure.ac rename : js/ctypes/libffi/configure.host => js/src/ctypes/libffi/configure.host rename : js/ctypes/libffi/depcomp => js/src/ctypes/libffi/depcomp rename : js/ctypes/libffi/doc/libffi.info => js/src/ctypes/libffi/doc/libffi.info rename : js/ctypes/libffi/doc/libffi.texi => js/src/ctypes/libffi/doc/libffi.texi rename : js/ctypes/libffi/doc/stamp-vti => js/src/ctypes/libffi/doc/stamp-vti rename : js/ctypes/libffi/doc/version.texi => js/src/ctypes/libffi/doc/version.texi rename : js/ctypes/libffi/fficonfig.h.in => js/src/ctypes/libffi/fficonfig.h.in rename : js/ctypes/libffi/include/Makefile.am => js/src/ctypes/libffi/include/Makefile.am rename : js/ctypes/libffi/include/Makefile.in => js/src/ctypes/libffi/include/Makefile.in rename : js/ctypes/libffi/include/ffi.h.in => js/src/ctypes/libffi/include/ffi.h.in rename : js/ctypes/libffi/include/ffi_common.h => js/src/ctypes/libffi/include/ffi_common.h rename : js/ctypes/libffi/install-sh => js/src/ctypes/libffi/install-sh rename : js/ctypes/libffi/libffi.pc.in => js/src/ctypes/libffi/libffi.pc.in rename : js/ctypes/libffi/libtool-version => js/src/ctypes/libffi/libtool-version rename : js/ctypes/libffi/ltmain.sh => js/src/ctypes/libffi/ltmain.sh rename : js/ctypes/libffi/m4/libtool.m4 => js/src/ctypes/libffi/m4/libtool.m4 rename : js/ctypes/libffi/m4/ltoptions.m4 => js/src/ctypes/libffi/m4/ltoptions.m4 rename : js/ctypes/libffi/m4/ltsugar.m4 => js/src/ctypes/libffi/m4/ltsugar.m4 rename : js/ctypes/libffi/m4/ltversion.m4 => js/src/ctypes/libffi/m4/ltversion.m4 rename : js/ctypes/libffi/m4/lt~obsolete.m4 => js/src/ctypes/libffi/m4/lt~obsolete.m4 rename : js/ctypes/libffi/man/Makefile.am => js/src/ctypes/libffi/man/Makefile.am rename : js/ctypes/libffi/man/Makefile.in => js/src/ctypes/libffi/man/Makefile.in rename : js/ctypes/libffi/man/ffi.3 => js/src/ctypes/libffi/man/ffi.3 rename : js/ctypes/libffi/man/ffi_call.3 => js/src/ctypes/libffi/man/ffi_call.3 rename : js/ctypes/libffi/man/ffi_prep_cif.3 => js/src/ctypes/libffi/man/ffi_prep_cif.3 rename : js/ctypes/libffi/mdate-sh => js/src/ctypes/libffi/mdate-sh rename : js/ctypes/libffi/missing => js/src/ctypes/libffi/missing rename : js/ctypes/libffi/msvcc.sh => js/src/ctypes/libffi/msvcc.sh rename : js/ctypes/libffi/src/alpha/ffi.c => js/src/ctypes/libffi/src/alpha/ffi.c rename : js/ctypes/libffi/src/alpha/ffitarget.h => js/src/ctypes/libffi/src/alpha/ffitarget.h rename : js/ctypes/libffi/src/alpha/osf.S => js/src/ctypes/libffi/src/alpha/osf.S rename : js/ctypes/libffi/src/arm/ffi.c => js/src/ctypes/libffi/src/arm/ffi.c rename : js/ctypes/libffi/src/arm/ffitarget.h => js/src/ctypes/libffi/src/arm/ffitarget.h rename : js/ctypes/libffi/src/arm/sysv.S => js/src/ctypes/libffi/src/arm/sysv.S rename : js/ctypes/libffi/src/avr32/ffi.c => js/src/ctypes/libffi/src/avr32/ffi.c rename : js/ctypes/libffi/src/avr32/ffitarget.h => js/src/ctypes/libffi/src/avr32/ffitarget.h rename : js/ctypes/libffi/src/avr32/sysv.S => js/src/ctypes/libffi/src/avr32/sysv.S rename : js/ctypes/libffi/src/closures.c => js/src/ctypes/libffi/src/closures.c rename : js/ctypes/libffi/src/cris/ffi.c => js/src/ctypes/libffi/src/cris/ffi.c rename : js/ctypes/libffi/src/cris/ffitarget.h => js/src/ctypes/libffi/src/cris/ffitarget.h rename : js/ctypes/libffi/src/cris/sysv.S => js/src/ctypes/libffi/src/cris/sysv.S rename : js/ctypes/libffi/src/debug.c => js/src/ctypes/libffi/src/debug.c rename : js/ctypes/libffi/src/dlmalloc.c => js/src/ctypes/libffi/src/dlmalloc.c rename : js/ctypes/libffi/src/frv/eabi.S => js/src/ctypes/libffi/src/frv/eabi.S rename : js/ctypes/libffi/src/frv/ffi.c => js/src/ctypes/libffi/src/frv/ffi.c rename : js/ctypes/libffi/src/frv/ffitarget.h => js/src/ctypes/libffi/src/frv/ffitarget.h rename : js/ctypes/libffi/src/ia64/ffi.c => js/src/ctypes/libffi/src/ia64/ffi.c rename : js/ctypes/libffi/src/ia64/ffitarget.h => js/src/ctypes/libffi/src/ia64/ffitarget.h rename : js/ctypes/libffi/src/ia64/ia64_flags.h => js/src/ctypes/libffi/src/ia64/ia64_flags.h rename : js/ctypes/libffi/src/ia64/unix.S => js/src/ctypes/libffi/src/ia64/unix.S rename : js/ctypes/libffi/src/java_raw_api.c => js/src/ctypes/libffi/src/java_raw_api.c rename : js/ctypes/libffi/src/m32r/ffi.c => js/src/ctypes/libffi/src/m32r/ffi.c rename : js/ctypes/libffi/src/m32r/ffitarget.h => js/src/ctypes/libffi/src/m32r/ffitarget.h rename : js/ctypes/libffi/src/m32r/sysv.S => js/src/ctypes/libffi/src/m32r/sysv.S rename : js/ctypes/libffi/src/m68k/ffi.c => js/src/ctypes/libffi/src/m68k/ffi.c rename : js/ctypes/libffi/src/m68k/ffitarget.h => js/src/ctypes/libffi/src/m68k/ffitarget.h rename : js/ctypes/libffi/src/m68k/sysv.S => js/src/ctypes/libffi/src/m68k/sysv.S rename : js/ctypes/libffi/src/mips/ffi.c => js/src/ctypes/libffi/src/mips/ffi.c rename : js/ctypes/libffi/src/mips/ffitarget.h => js/src/ctypes/libffi/src/mips/ffitarget.h rename : js/ctypes/libffi/src/mips/n32.S => js/src/ctypes/libffi/src/mips/n32.S rename : js/ctypes/libffi/src/mips/o32.S => js/src/ctypes/libffi/src/mips/o32.S rename : js/ctypes/libffi/src/moxie/eabi.S => js/src/ctypes/libffi/src/moxie/eabi.S rename : js/ctypes/libffi/src/moxie/ffi.c => js/src/ctypes/libffi/src/moxie/ffi.c rename : js/ctypes/libffi/src/moxie/ffitarget.h => js/src/ctypes/libffi/src/moxie/ffitarget.h rename : js/ctypes/libffi/src/pa/ffi.c => js/src/ctypes/libffi/src/pa/ffi.c rename : js/ctypes/libffi/src/pa/ffitarget.h => js/src/ctypes/libffi/src/pa/ffitarget.h rename : js/ctypes/libffi/src/pa/hpux32.S => js/src/ctypes/libffi/src/pa/hpux32.S rename : js/ctypes/libffi/src/pa/linux.S => js/src/ctypes/libffi/src/pa/linux.S rename : js/ctypes/libffi/src/powerpc/aix.S => js/src/ctypes/libffi/src/powerpc/aix.S rename : js/ctypes/libffi/src/powerpc/aix_closure.S => js/src/ctypes/libffi/src/powerpc/aix_closure.S rename : js/ctypes/libffi/src/powerpc/asm.h => js/src/ctypes/libffi/src/powerpc/asm.h rename : js/ctypes/libffi/src/powerpc/darwin.S => js/src/ctypes/libffi/src/powerpc/darwin.S rename : js/ctypes/libffi/src/powerpc/darwin_closure.S => js/src/ctypes/libffi/src/powerpc/darwin_closure.S rename : js/ctypes/libffi/src/powerpc/ffi.c => js/src/ctypes/libffi/src/powerpc/ffi.c rename : js/ctypes/libffi/src/powerpc/ffi_darwin.c => js/src/ctypes/libffi/src/powerpc/ffi_darwin.c rename : js/ctypes/libffi/src/powerpc/ffitarget.h => js/src/ctypes/libffi/src/powerpc/ffitarget.h rename : js/ctypes/libffi/src/powerpc/linux64.S => js/src/ctypes/libffi/src/powerpc/linux64.S rename : js/ctypes/libffi/src/powerpc/linux64_closure.S => js/src/ctypes/libffi/src/powerpc/linux64_closure.S rename : js/ctypes/libffi/src/powerpc/ppc_closure.S => js/src/ctypes/libffi/src/powerpc/ppc_closure.S rename : js/ctypes/libffi/src/powerpc/sysv.S => js/src/ctypes/libffi/src/powerpc/sysv.S rename : js/ctypes/libffi/src/prep_cif.c => js/src/ctypes/libffi/src/prep_cif.c rename : js/ctypes/libffi/src/raw_api.c => js/src/ctypes/libffi/src/raw_api.c rename : js/ctypes/libffi/src/s390/ffi.c => js/src/ctypes/libffi/src/s390/ffi.c rename : js/ctypes/libffi/src/s390/ffitarget.h => js/src/ctypes/libffi/src/s390/ffitarget.h rename : js/ctypes/libffi/src/s390/sysv.S => js/src/ctypes/libffi/src/s390/sysv.S rename : js/ctypes/libffi/src/sh/ffi.c => js/src/ctypes/libffi/src/sh/ffi.c rename : js/ctypes/libffi/src/sh/ffitarget.h => js/src/ctypes/libffi/src/sh/ffitarget.h rename : js/ctypes/libffi/src/sh/sysv.S => js/src/ctypes/libffi/src/sh/sysv.S rename : js/ctypes/libffi/src/sh64/ffi.c => js/src/ctypes/libffi/src/sh64/ffi.c rename : js/ctypes/libffi/src/sh64/ffitarget.h => js/src/ctypes/libffi/src/sh64/ffitarget.h rename : js/ctypes/libffi/src/sh64/sysv.S => js/src/ctypes/libffi/src/sh64/sysv.S rename : js/ctypes/libffi/src/sparc/ffi.c => js/src/ctypes/libffi/src/sparc/ffi.c rename : js/ctypes/libffi/src/sparc/ffitarget.h => js/src/ctypes/libffi/src/sparc/ffitarget.h rename : js/ctypes/libffi/src/sparc/v8.S => js/src/ctypes/libffi/src/sparc/v8.S rename : js/ctypes/libffi/src/sparc/v9.S => js/src/ctypes/libffi/src/sparc/v9.S rename : js/ctypes/libffi/src/types.c => js/src/ctypes/libffi/src/types.c rename : js/ctypes/libffi/src/x86/darwin.S => js/src/ctypes/libffi/src/x86/darwin.S rename : js/ctypes/libffi/src/x86/darwin64.S => js/src/ctypes/libffi/src/x86/darwin64.S rename : js/ctypes/libffi/src/x86/ffi.c => js/src/ctypes/libffi/src/x86/ffi.c rename : js/ctypes/libffi/src/x86/ffi64.c => js/src/ctypes/libffi/src/x86/ffi64.c rename : js/ctypes/libffi/src/x86/ffitarget.h => js/src/ctypes/libffi/src/x86/ffitarget.h rename : js/ctypes/libffi/src/x86/freebsd.S => js/src/ctypes/libffi/src/x86/freebsd.S rename : js/ctypes/libffi/src/x86/sysv.S => js/src/ctypes/libffi/src/x86/sysv.S rename : js/ctypes/libffi/src/x86/unix64.S => js/src/ctypes/libffi/src/x86/unix64.S rename : js/ctypes/libffi/src/x86/win32.S => js/src/ctypes/libffi/src/x86/win32.S rename : js/ctypes/libffi/src/x86/win64.S => js/src/ctypes/libffi/src/x86/win64.S rename : js/ctypes/libffi/testsuite/Makefile.am => js/src/ctypes/libffi/testsuite/Makefile.am rename : js/ctypes/libffi/testsuite/Makefile.in => js/src/ctypes/libffi/testsuite/Makefile.in rename : js/ctypes/libffi/testsuite/config/default.exp => js/src/ctypes/libffi/testsuite/config/default.exp rename : js/ctypes/libffi/testsuite/lib/libffi-dg.exp => js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp rename : js/ctypes/libffi/testsuite/lib/target-libpath.exp => js/src/ctypes/libffi/testsuite/lib/target-libpath.exp rename : js/ctypes/libffi/testsuite/lib/wrapper.exp => js/src/ctypes/libffi/testsuite/lib/wrapper.exp rename : js/ctypes/libffi/testsuite/libffi.call/call.exp => js/src/ctypes/libffi/testsuite/libffi.call/call.exp rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn0.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn1.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn2.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn3.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn4.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn5.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_fn6.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c rename : js/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c => js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_12byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_16byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_18byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_19byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_20byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_24byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_2byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_4byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_5byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_64byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_6byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_7byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_8byte.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_double.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_float.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_double.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_double_va.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_float.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_pointer.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_schar.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_sint.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_sshort.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_uchar.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_uint.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c rename : js/ctypes/libffi/testsuite/libffi.call/cls_ushort.c => js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c rename : js/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c => js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c rename : js/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c => js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c rename : js/ctypes/libffi/testsuite/libffi.call/ffitest.h => js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h rename : js/ctypes/libffi/testsuite/libffi.call/float.c => js/src/ctypes/libffi/testsuite/libffi.call/float.c rename : js/ctypes/libffi/testsuite/libffi.call/float1.c => js/src/ctypes/libffi/testsuite/libffi.call/float1.c rename : js/ctypes/libffi/testsuite/libffi.call/float2.c => js/src/ctypes/libffi/testsuite/libffi.call/float2.c rename : js/ctypes/libffi/testsuite/libffi.call/float3.c => js/src/ctypes/libffi/testsuite/libffi.call/float3.c rename : js/ctypes/libffi/testsuite/libffi.call/float4.c => js/src/ctypes/libffi/testsuite/libffi.call/float4.c rename : js/ctypes/libffi/testsuite/libffi.call/huge_struct.c => js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c rename : js/ctypes/libffi/testsuite/libffi.call/many.c => js/src/ctypes/libffi/testsuite/libffi.call/many.c rename : js/ctypes/libffi/testsuite/libffi.call/many_win32.c => js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c rename : js/ctypes/libffi/testsuite/libffi.call/negint.c => js/src/ctypes/libffi/testsuite/libffi.call/negint.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct1.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct10.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct2.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct3.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct4.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct5.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct6.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct7.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct8.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c rename : js/ctypes/libffi/testsuite/libffi.call/nested_struct9.c => js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c rename : js/ctypes/libffi/testsuite/libffi.call/problem1.c => js/src/ctypes/libffi/testsuite/libffi.call/problem1.c rename : js/ctypes/libffi/testsuite/libffi.call/promotion.c => js/src/ctypes/libffi/testsuite/libffi.call/promotion.c rename : js/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c => js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c rename : js/ctypes/libffi/testsuite/libffi.call/return_dbl.c => js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c rename : js/ctypes/libffi/testsuite/libffi.call/return_dbl1.c => js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c rename : js/ctypes/libffi/testsuite/libffi.call/return_dbl2.c => js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c rename : js/ctypes/libffi/testsuite/libffi.call/return_fl.c => js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c rename : js/ctypes/libffi/testsuite/libffi.call/return_fl1.c => js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c rename : js/ctypes/libffi/testsuite/libffi.call/return_fl2.c => js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c rename : js/ctypes/libffi/testsuite/libffi.call/return_fl3.c => js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c rename : js/ctypes/libffi/testsuite/libffi.call/return_ldl.c => js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c rename : js/ctypes/libffi/testsuite/libffi.call/return_ll.c => js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c rename : js/ctypes/libffi/testsuite/libffi.call/return_ll1.c => js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c rename : js/ctypes/libffi/testsuite/libffi.call/return_sc.c => js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c rename : js/ctypes/libffi/testsuite/libffi.call/return_sl.c => js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c rename : js/ctypes/libffi/testsuite/libffi.call/return_uc.c => js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c rename : js/ctypes/libffi/testsuite/libffi.call/return_ul.c => js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c rename : js/ctypes/libffi/testsuite/libffi.call/stret_large.c => js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c rename : js/ctypes/libffi/testsuite/libffi.call/stret_large2.c => js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c rename : js/ctypes/libffi/testsuite/libffi.call/stret_medium.c => js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c rename : js/ctypes/libffi/testsuite/libffi.call/stret_medium2.c => js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c rename : js/ctypes/libffi/testsuite/libffi.call/strlen.c => js/src/ctypes/libffi/testsuite/libffi.call/strlen.c rename : js/ctypes/libffi/testsuite/libffi.call/strlen_win32.c => js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c rename : js/ctypes/libffi/testsuite/libffi.call/struct1.c => js/src/ctypes/libffi/testsuite/libffi.call/struct1.c rename : js/ctypes/libffi/testsuite/libffi.call/struct2.c => js/src/ctypes/libffi/testsuite/libffi.call/struct2.c rename : js/ctypes/libffi/testsuite/libffi.call/struct3.c => js/src/ctypes/libffi/testsuite/libffi.call/struct3.c rename : js/ctypes/libffi/testsuite/libffi.call/struct4.c => js/src/ctypes/libffi/testsuite/libffi.call/struct4.c rename : js/ctypes/libffi/testsuite/libffi.call/struct5.c => js/src/ctypes/libffi/testsuite/libffi.call/struct5.c rename : js/ctypes/libffi/testsuite/libffi.call/struct6.c => js/src/ctypes/libffi/testsuite/libffi.call/struct6.c rename : js/ctypes/libffi/testsuite/libffi.call/struct7.c => js/src/ctypes/libffi/testsuite/libffi.call/struct7.c rename : js/ctypes/libffi/testsuite/libffi.call/struct8.c => js/src/ctypes/libffi/testsuite/libffi.call/struct8.c rename : js/ctypes/libffi/testsuite/libffi.call/struct9.c => js/src/ctypes/libffi/testsuite/libffi.call/struct9.c rename : js/ctypes/libffi/testsuite/libffi.call/testclosure.c => js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c rename : js/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h => js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h rename : js/ctypes/libffi/testsuite/libffi.special/special.exp => js/src/ctypes/libffi/testsuite/libffi.special/special.exp rename : js/ctypes/libffi/testsuite/libffi.special/unwindtest.cc => js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc rename : js/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc => js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc rename : js/ctypes/libffi/texinfo.tex => js/src/ctypes/libffi/texinfo.tex rename : js/ctypes/typedefs.h => js/src/ctypes/typedefs.h --- configure.in | 55 ++------------- js/src/Makefile.in | 35 ++++++++++ js/src/Makefile.ref | 11 +++ js/src/config/autoconf.mk.in | 1 + js/src/configure.in | 70 +++++++++++++++++++ js/{ => src}/ctypes/CTypes.cpp | 0 js/{ => src}/ctypes/CTypes.h | 0 js/{ => src}/ctypes/Library.cpp | 0 js/{ => src}/ctypes/Library.h | 0 js/{ => src}/ctypes/ctypes.msg | 0 js/{ => src}/ctypes/libffi.patch | 0 js/{ => src}/ctypes/libffi/ChangeLog | 0 js/{ => src}/ctypes/libffi/ChangeLog.libffi | 0 js/{ => src}/ctypes/libffi/ChangeLog.libgcj | 0 js/{ => src}/ctypes/libffi/ChangeLog.v1 | 0 js/{ => src}/ctypes/libffi/LICENSE | 0 js/{ => src}/ctypes/libffi/Makefile.am | 0 js/{ => src}/ctypes/libffi/Makefile.in | 0 js/{ => src}/ctypes/libffi/README | 0 js/{ => src}/ctypes/libffi/acinclude.m4 | 0 js/{ => src}/ctypes/libffi/aclocal.m4 | 0 js/{ => src}/ctypes/libffi/compile | 0 js/{ => src}/ctypes/libffi/config.guess | 0 js/{ => src}/ctypes/libffi/config.sub | 0 js/{ => src}/ctypes/libffi/configure | 0 js/{ => src}/ctypes/libffi/configure.ac | 0 js/{ => src}/ctypes/libffi/configure.host | 0 js/{ => src}/ctypes/libffi/depcomp | 0 js/{ => src}/ctypes/libffi/doc/libffi.info | 0 js/{ => src}/ctypes/libffi/doc/libffi.texi | 0 js/{ => src}/ctypes/libffi/doc/stamp-vti | 0 js/{ => src}/ctypes/libffi/doc/version.texi | 0 js/{ => src}/ctypes/libffi/fficonfig.h.in | 0 .../ctypes/libffi/include/Makefile.am | 0 .../ctypes/libffi/include/Makefile.in | 0 js/{ => src}/ctypes/libffi/include/ffi.h.in | 0 .../ctypes/libffi/include/ffi_common.h | 0 js/{ => src}/ctypes/libffi/install-sh | 0 js/{ => src}/ctypes/libffi/libffi.pc.in | 0 js/{ => src}/ctypes/libffi/libtool-version | 0 js/{ => src}/ctypes/libffi/ltmain.sh | 0 js/{ => src}/ctypes/libffi/m4/libtool.m4 | 0 js/{ => src}/ctypes/libffi/m4/ltoptions.m4 | 0 js/{ => src}/ctypes/libffi/m4/ltsugar.m4 | 0 js/{ => src}/ctypes/libffi/m4/ltversion.m4 | 0 js/{ => src}/ctypes/libffi/m4/lt~obsolete.m4 | 0 js/{ => src}/ctypes/libffi/man/Makefile.am | 0 js/{ => src}/ctypes/libffi/man/Makefile.in | 0 js/{ => src}/ctypes/libffi/man/ffi.3 | 0 js/{ => src}/ctypes/libffi/man/ffi_call.3 | 0 js/{ => src}/ctypes/libffi/man/ffi_prep_cif.3 | 0 js/{ => src}/ctypes/libffi/mdate-sh | 0 js/{ => src}/ctypes/libffi/missing | 0 js/{ => src}/ctypes/libffi/msvcc.sh | 0 js/{ => src}/ctypes/libffi/src/alpha/ffi.c | 0 .../ctypes/libffi/src/alpha/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/alpha/osf.S | 0 js/{ => src}/ctypes/libffi/src/arm/ffi.c | 0 .../ctypes/libffi/src/arm/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/arm/sysv.S | 0 js/{ => src}/ctypes/libffi/src/avr32/ffi.c | 0 .../ctypes/libffi/src/avr32/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/avr32/sysv.S | 0 js/{ => src}/ctypes/libffi/src/closures.c | 0 js/{ => src}/ctypes/libffi/src/cris/ffi.c | 0 .../ctypes/libffi/src/cris/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/cris/sysv.S | 0 js/{ => src}/ctypes/libffi/src/debug.c | 0 js/{ => src}/ctypes/libffi/src/dlmalloc.c | 0 js/{ => src}/ctypes/libffi/src/frv/eabi.S | 0 js/{ => src}/ctypes/libffi/src/frv/ffi.c | 0 .../ctypes/libffi/src/frv/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/ia64/ffi.c | 0 .../ctypes/libffi/src/ia64/ffitarget.h | 0 .../ctypes/libffi/src/ia64/ia64_flags.h | 0 js/{ => src}/ctypes/libffi/src/ia64/unix.S | 0 js/{ => src}/ctypes/libffi/src/java_raw_api.c | 0 js/{ => src}/ctypes/libffi/src/m32r/ffi.c | 0 .../ctypes/libffi/src/m32r/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/m32r/sysv.S | 0 js/{ => src}/ctypes/libffi/src/m68k/ffi.c | 0 .../ctypes/libffi/src/m68k/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/m68k/sysv.S | 0 js/{ => src}/ctypes/libffi/src/mips/ffi.c | 0 .../ctypes/libffi/src/mips/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/mips/n32.S | 0 js/{ => src}/ctypes/libffi/src/mips/o32.S | 0 js/{ => src}/ctypes/libffi/src/moxie/eabi.S | 0 js/{ => src}/ctypes/libffi/src/moxie/ffi.c | 0 .../ctypes/libffi/src/moxie/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/pa/ffi.c | 0 js/{ => src}/ctypes/libffi/src/pa/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/pa/hpux32.S | 0 js/{ => src}/ctypes/libffi/src/pa/linux.S | 0 js/{ => src}/ctypes/libffi/src/powerpc/aix.S | 0 .../ctypes/libffi/src/powerpc/aix_closure.S | 0 js/{ => src}/ctypes/libffi/src/powerpc/asm.h | 0 .../ctypes/libffi/src/powerpc/darwin.S | 0 .../libffi/src/powerpc/darwin_closure.S | 0 js/{ => src}/ctypes/libffi/src/powerpc/ffi.c | 0 .../ctypes/libffi/src/powerpc/ffi_darwin.c | 0 .../ctypes/libffi/src/powerpc/ffitarget.h | 0 .../ctypes/libffi/src/powerpc/linux64.S | 0 .../libffi/src/powerpc/linux64_closure.S | 0 .../ctypes/libffi/src/powerpc/ppc_closure.S | 0 js/{ => src}/ctypes/libffi/src/powerpc/sysv.S | 0 js/{ => src}/ctypes/libffi/src/prep_cif.c | 0 js/{ => src}/ctypes/libffi/src/raw_api.c | 0 js/{ => src}/ctypes/libffi/src/s390/ffi.c | 0 .../ctypes/libffi/src/s390/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/s390/sysv.S | 0 js/{ => src}/ctypes/libffi/src/sh/ffi.c | 0 js/{ => src}/ctypes/libffi/src/sh/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/sh/sysv.S | 0 js/{ => src}/ctypes/libffi/src/sh64/ffi.c | 0 .../ctypes/libffi/src/sh64/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/sh64/sysv.S | 0 js/{ => src}/ctypes/libffi/src/sparc/ffi.c | 0 .../ctypes/libffi/src/sparc/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/sparc/v8.S | 0 js/{ => src}/ctypes/libffi/src/sparc/v9.S | 0 js/{ => src}/ctypes/libffi/src/types.c | 0 js/{ => src}/ctypes/libffi/src/x86/darwin.S | 0 js/{ => src}/ctypes/libffi/src/x86/darwin64.S | 0 js/{ => src}/ctypes/libffi/src/x86/ffi.c | 0 js/{ => src}/ctypes/libffi/src/x86/ffi64.c | 0 .../ctypes/libffi/src/x86/ffitarget.h | 0 js/{ => src}/ctypes/libffi/src/x86/freebsd.S | 0 js/{ => src}/ctypes/libffi/src/x86/sysv.S | 0 js/{ => src}/ctypes/libffi/src/x86/unix64.S | 0 js/{ => src}/ctypes/libffi/src/x86/win32.S | 0 js/{ => src}/ctypes/libffi/src/x86/win64.S | 0 .../ctypes/libffi/testsuite/Makefile.am | 0 .../ctypes/libffi/testsuite/Makefile.in | 0 .../libffi/testsuite/config/default.exp | 0 .../ctypes/libffi/testsuite/lib/libffi-dg.exp | 0 .../libffi/testsuite/lib/target-libpath.exp | 0 .../ctypes/libffi/testsuite/lib/wrapper.exp | 0 .../libffi/testsuite/libffi.call/call.exp | 0 .../testsuite/libffi.call/closure_fn0.c | 0 .../testsuite/libffi.call/closure_fn1.c | 0 .../testsuite/libffi.call/closure_fn2.c | 0 .../testsuite/libffi.call/closure_fn3.c | 0 .../testsuite/libffi.call/closure_fn4.c | 0 .../testsuite/libffi.call/closure_fn5.c | 0 .../testsuite/libffi.call/closure_fn6.c | 0 .../testsuite/libffi.call/closure_loc_fn0.c | 0 .../testsuite/libffi.call/closure_stdcall.c | 0 .../libffi/testsuite/libffi.call/cls_12byte.c | 0 .../libffi/testsuite/libffi.call/cls_16byte.c | 0 .../libffi/testsuite/libffi.call/cls_18byte.c | 0 .../libffi/testsuite/libffi.call/cls_19byte.c | 0 .../testsuite/libffi.call/cls_1_1byte.c | 0 .../libffi/testsuite/libffi.call/cls_20byte.c | 0 .../testsuite/libffi.call/cls_20byte1.c | 0 .../libffi/testsuite/libffi.call/cls_24byte.c | 0 .../libffi/testsuite/libffi.call/cls_2byte.c | 0 .../testsuite/libffi.call/cls_3_1byte.c | 0 .../libffi/testsuite/libffi.call/cls_3byte1.c | 0 .../libffi/testsuite/libffi.call/cls_3byte2.c | 0 .../testsuite/libffi.call/cls_4_1byte.c | 0 .../libffi/testsuite/libffi.call/cls_4byte.c | 0 .../testsuite/libffi.call/cls_5_1_byte.c | 0 .../libffi/testsuite/libffi.call/cls_5byte.c | 0 .../libffi/testsuite/libffi.call/cls_64byte.c | 0 .../testsuite/libffi.call/cls_6_1_byte.c | 0 .../libffi/testsuite/libffi.call/cls_6byte.c | 0 .../testsuite/libffi.call/cls_7_1_byte.c | 0 .../libffi/testsuite/libffi.call/cls_7byte.c | 0 .../libffi/testsuite/libffi.call/cls_8byte.c | 0 .../libffi/testsuite/libffi.call/cls_9byte1.c | 0 .../libffi/testsuite/libffi.call/cls_9byte2.c | 0 .../testsuite/libffi.call/cls_align_double.c | 0 .../testsuite/libffi.call/cls_align_float.c | 0 .../libffi.call/cls_align_longdouble.c | 0 .../libffi.call/cls_align_longdouble_split.c | 0 .../libffi.call/cls_align_longdouble_split2.c | 0 .../testsuite/libffi.call/cls_align_pointer.c | 0 .../testsuite/libffi.call/cls_align_sint16.c | 0 .../testsuite/libffi.call/cls_align_sint32.c | 0 .../testsuite/libffi.call/cls_align_sint64.c | 0 .../testsuite/libffi.call/cls_align_uint16.c | 0 .../testsuite/libffi.call/cls_align_uint32.c | 0 .../testsuite/libffi.call/cls_align_uint64.c | 0 .../testsuite/libffi.call/cls_dbls_struct.c | 0 .../libffi/testsuite/libffi.call/cls_double.c | 0 .../testsuite/libffi.call/cls_double_va.c | 0 .../libffi/testsuite/libffi.call/cls_float.c | 0 .../testsuite/libffi.call/cls_longdouble.c | 0 .../testsuite/libffi.call/cls_longdouble_va.c | 0 .../testsuite/libffi.call/cls_multi_schar.c | 0 .../testsuite/libffi.call/cls_multi_sshort.c | 0 .../libffi.call/cls_multi_sshortchar.c | 0 .../testsuite/libffi.call/cls_multi_uchar.c | 0 .../testsuite/libffi.call/cls_multi_ushort.c | 0 .../libffi.call/cls_multi_ushortchar.c | 0 .../testsuite/libffi.call/cls_pointer.c | 0 .../testsuite/libffi.call/cls_pointer_stack.c | 0 .../libffi/testsuite/libffi.call/cls_schar.c | 0 .../libffi/testsuite/libffi.call/cls_sint.c | 0 .../libffi/testsuite/libffi.call/cls_sshort.c | 0 .../libffi/testsuite/libffi.call/cls_uchar.c | 0 .../libffi/testsuite/libffi.call/cls_uint.c | 0 .../testsuite/libffi.call/cls_ulonglong.c | 0 .../libffi/testsuite/libffi.call/cls_ushort.c | 0 .../testsuite/libffi.call/err_bad_abi.c | 0 .../testsuite/libffi.call/err_bad_typedef.c | 0 .../libffi/testsuite/libffi.call/ffitest.h | 0 .../libffi/testsuite/libffi.call/float.c | 0 .../libffi/testsuite/libffi.call/float1.c | 0 .../libffi/testsuite/libffi.call/float2.c | 0 .../libffi/testsuite/libffi.call/float3.c | 0 .../libffi/testsuite/libffi.call/float4.c | 0 .../testsuite/libffi.call/huge_struct.c | 0 .../libffi/testsuite/libffi.call/many.c | 0 .../libffi/testsuite/libffi.call/many_win32.c | 0 .../libffi/testsuite/libffi.call/negint.c | 0 .../testsuite/libffi.call/nested_struct.c | 0 .../testsuite/libffi.call/nested_struct1.c | 0 .../testsuite/libffi.call/nested_struct10.c | 0 .../testsuite/libffi.call/nested_struct2.c | 0 .../testsuite/libffi.call/nested_struct3.c | 0 .../testsuite/libffi.call/nested_struct4.c | 0 .../testsuite/libffi.call/nested_struct5.c | 0 .../testsuite/libffi.call/nested_struct6.c | 0 .../testsuite/libffi.call/nested_struct7.c | 0 .../testsuite/libffi.call/nested_struct8.c | 0 .../testsuite/libffi.call/nested_struct9.c | 0 .../libffi/testsuite/libffi.call/problem1.c | 0 .../libffi/testsuite/libffi.call/promotion.c | 0 .../libffi/testsuite/libffi.call/pyobjc-tc.c | 0 .../libffi/testsuite/libffi.call/return_dbl.c | 0 .../testsuite/libffi.call/return_dbl1.c | 0 .../testsuite/libffi.call/return_dbl2.c | 0 .../libffi/testsuite/libffi.call/return_fl.c | 0 .../libffi/testsuite/libffi.call/return_fl1.c | 0 .../libffi/testsuite/libffi.call/return_fl2.c | 0 .../libffi/testsuite/libffi.call/return_fl3.c | 0 .../libffi/testsuite/libffi.call/return_ldl.c | 0 .../libffi/testsuite/libffi.call/return_ll.c | 0 .../libffi/testsuite/libffi.call/return_ll1.c | 0 .../libffi/testsuite/libffi.call/return_sc.c | 0 .../libffi/testsuite/libffi.call/return_sl.c | 0 .../libffi/testsuite/libffi.call/return_uc.c | 0 .../libffi/testsuite/libffi.call/return_ul.c | 0 .../testsuite/libffi.call/stret_large.c | 0 .../testsuite/libffi.call/stret_large2.c | 0 .../testsuite/libffi.call/stret_medium.c | 0 .../testsuite/libffi.call/stret_medium2.c | 0 .../libffi/testsuite/libffi.call/strlen.c | 0 .../testsuite/libffi.call/strlen_win32.c | 0 .../libffi/testsuite/libffi.call/struct1.c | 0 .../libffi/testsuite/libffi.call/struct2.c | 0 .../libffi/testsuite/libffi.call/struct3.c | 0 .../libffi/testsuite/libffi.call/struct4.c | 0 .../libffi/testsuite/libffi.call/struct5.c | 0 .../libffi/testsuite/libffi.call/struct6.c | 0 .../libffi/testsuite/libffi.call/struct7.c | 0 .../libffi/testsuite/libffi.call/struct8.c | 0 .../libffi/testsuite/libffi.call/struct9.c | 0 .../testsuite/libffi.call/testclosure.c | 0 .../testsuite/libffi.special/ffitestcxx.h | 0 .../testsuite/libffi.special/special.exp | 0 .../testsuite/libffi.special/unwindtest.cc | 0 .../libffi.special/unwindtest_ffi_call.cc | 0 js/{ => src}/ctypes/libffi/texinfo.tex | 0 js/{ => src}/ctypes/typedefs.h | 0 js/src/js-config.h.in | 3 + toolkit/toolkit-makefiles.sh | 4 -- toolkit/toolkit-tiers.mk | 7 -- 270 files changed, 124 insertions(+), 62 deletions(-) rename js/{ => src}/ctypes/CTypes.cpp (100%) rename js/{ => src}/ctypes/CTypes.h (100%) rename js/{ => src}/ctypes/Library.cpp (100%) rename js/{ => src}/ctypes/Library.h (100%) rename js/{ => src}/ctypes/ctypes.msg (100%) rename js/{ => src}/ctypes/libffi.patch (100%) rename js/{ => src}/ctypes/libffi/ChangeLog (100%) rename js/{ => src}/ctypes/libffi/ChangeLog.libffi (100%) rename js/{ => src}/ctypes/libffi/ChangeLog.libgcj (100%) rename js/{ => src}/ctypes/libffi/ChangeLog.v1 (100%) rename js/{ => src}/ctypes/libffi/LICENSE (100%) rename js/{ => src}/ctypes/libffi/Makefile.am (100%) rename js/{ => src}/ctypes/libffi/Makefile.in (100%) rename js/{ => src}/ctypes/libffi/README (100%) rename js/{ => src}/ctypes/libffi/acinclude.m4 (100%) rename js/{ => src}/ctypes/libffi/aclocal.m4 (100%) rename js/{ => src}/ctypes/libffi/compile (100%) rename js/{ => src}/ctypes/libffi/config.guess (100%) rename js/{ => src}/ctypes/libffi/config.sub (100%) rename js/{ => src}/ctypes/libffi/configure (100%) rename js/{ => src}/ctypes/libffi/configure.ac (100%) rename js/{ => src}/ctypes/libffi/configure.host (100%) rename js/{ => src}/ctypes/libffi/depcomp (100%) rename js/{ => src}/ctypes/libffi/doc/libffi.info (100%) rename js/{ => src}/ctypes/libffi/doc/libffi.texi (100%) rename js/{ => src}/ctypes/libffi/doc/stamp-vti (100%) rename js/{ => src}/ctypes/libffi/doc/version.texi (100%) rename js/{ => src}/ctypes/libffi/fficonfig.h.in (100%) rename js/{ => src}/ctypes/libffi/include/Makefile.am (100%) rename js/{ => src}/ctypes/libffi/include/Makefile.in (100%) rename js/{ => src}/ctypes/libffi/include/ffi.h.in (100%) rename js/{ => src}/ctypes/libffi/include/ffi_common.h (100%) rename js/{ => src}/ctypes/libffi/install-sh (100%) rename js/{ => src}/ctypes/libffi/libffi.pc.in (100%) rename js/{ => src}/ctypes/libffi/libtool-version (100%) rename js/{ => src}/ctypes/libffi/ltmain.sh (100%) rename js/{ => src}/ctypes/libffi/m4/libtool.m4 (100%) rename js/{ => src}/ctypes/libffi/m4/ltoptions.m4 (100%) rename js/{ => src}/ctypes/libffi/m4/ltsugar.m4 (100%) rename js/{ => src}/ctypes/libffi/m4/ltversion.m4 (100%) rename js/{ => src}/ctypes/libffi/m4/lt~obsolete.m4 (100%) rename js/{ => src}/ctypes/libffi/man/Makefile.am (100%) rename js/{ => src}/ctypes/libffi/man/Makefile.in (100%) rename js/{ => src}/ctypes/libffi/man/ffi.3 (100%) rename js/{ => src}/ctypes/libffi/man/ffi_call.3 (100%) rename js/{ => src}/ctypes/libffi/man/ffi_prep_cif.3 (100%) rename js/{ => src}/ctypes/libffi/mdate-sh (100%) rename js/{ => src}/ctypes/libffi/missing (100%) rename js/{ => src}/ctypes/libffi/msvcc.sh (100%) rename js/{ => src}/ctypes/libffi/src/alpha/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/alpha/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/alpha/osf.S (100%) rename js/{ => src}/ctypes/libffi/src/arm/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/arm/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/arm/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/avr32/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/avr32/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/avr32/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/closures.c (100%) rename js/{ => src}/ctypes/libffi/src/cris/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/cris/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/cris/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/debug.c (100%) rename js/{ => src}/ctypes/libffi/src/dlmalloc.c (100%) rename js/{ => src}/ctypes/libffi/src/frv/eabi.S (100%) rename js/{ => src}/ctypes/libffi/src/frv/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/frv/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/ia64/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/ia64/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/ia64/ia64_flags.h (100%) rename js/{ => src}/ctypes/libffi/src/ia64/unix.S (100%) rename js/{ => src}/ctypes/libffi/src/java_raw_api.c (100%) rename js/{ => src}/ctypes/libffi/src/m32r/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/m32r/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/m32r/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/m68k/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/m68k/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/m68k/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/mips/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/mips/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/mips/n32.S (100%) rename js/{ => src}/ctypes/libffi/src/mips/o32.S (100%) rename js/{ => src}/ctypes/libffi/src/moxie/eabi.S (100%) rename js/{ => src}/ctypes/libffi/src/moxie/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/moxie/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/pa/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/pa/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/pa/hpux32.S (100%) rename js/{ => src}/ctypes/libffi/src/pa/linux.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/aix.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/aix_closure.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/asm.h (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/darwin.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/darwin_closure.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/ffi_darwin.c (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/linux64.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/linux64_closure.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/ppc_closure.S (100%) rename js/{ => src}/ctypes/libffi/src/powerpc/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/prep_cif.c (100%) rename js/{ => src}/ctypes/libffi/src/raw_api.c (100%) rename js/{ => src}/ctypes/libffi/src/s390/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/s390/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/s390/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/sh/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/sh/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/sh/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/sh64/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/sh64/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/sh64/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/sparc/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/sparc/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/sparc/v8.S (100%) rename js/{ => src}/ctypes/libffi/src/sparc/v9.S (100%) rename js/{ => src}/ctypes/libffi/src/types.c (100%) rename js/{ => src}/ctypes/libffi/src/x86/darwin.S (100%) rename js/{ => src}/ctypes/libffi/src/x86/darwin64.S (100%) rename js/{ => src}/ctypes/libffi/src/x86/ffi.c (100%) rename js/{ => src}/ctypes/libffi/src/x86/ffi64.c (100%) rename js/{ => src}/ctypes/libffi/src/x86/ffitarget.h (100%) rename js/{ => src}/ctypes/libffi/src/x86/freebsd.S (100%) rename js/{ => src}/ctypes/libffi/src/x86/sysv.S (100%) rename js/{ => src}/ctypes/libffi/src/x86/unix64.S (100%) rename js/{ => src}/ctypes/libffi/src/x86/win32.S (100%) rename js/{ => src}/ctypes/libffi/src/x86/win64.S (100%) rename js/{ => src}/ctypes/libffi/testsuite/Makefile.am (100%) rename js/{ => src}/ctypes/libffi/testsuite/Makefile.in (100%) rename js/{ => src}/ctypes/libffi/testsuite/config/default.exp (100%) rename js/{ => src}/ctypes/libffi/testsuite/lib/libffi-dg.exp (100%) rename js/{ => src}/ctypes/libffi/testsuite/lib/target-libpath.exp (100%) rename js/{ => src}/ctypes/libffi/testsuite/lib/wrapper.exp (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/call.exp (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn0.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn3.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn4.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn5.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_fn6.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_12byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_16byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_18byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_19byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_20byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_24byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_2byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_4byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_5byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_64byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_6byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_7byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_8byte.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_double.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_float.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_double.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_double_va.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_float.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_pointer.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_schar.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_sint.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_sshort.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_uchar.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_uint.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/cls_ushort.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/ffitest.h (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/float.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/float1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/float2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/float3.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/float4.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/huge_struct.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/many.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/many_win32.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/negint.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct10.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct3.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct4.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct5.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct6.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct7.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct8.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/nested_struct9.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/problem1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/promotion.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_dbl.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_dbl1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_dbl2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_fl.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_fl1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_fl2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_fl3.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_ldl.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_ll.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_ll1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_sc.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_sl.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_uc.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/return_ul.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/stret_large.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/stret_large2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/stret_medium.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/stret_medium2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/strlen.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/strlen_win32.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct1.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct2.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct3.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct4.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct5.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct6.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct7.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct8.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/struct9.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.call/testclosure.c (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.special/special.exp (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.special/unwindtest.cc (100%) rename js/{ => src}/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc (100%) rename js/{ => src}/ctypes/libffi/texinfo.tex (100%) rename js/{ => src}/ctypes/typedefs.h (100%) diff --git a/configure.in b/configure.in index 80633491e2cb..9402da0a6a89 100644 --- a/configure.in +++ b/configure.in @@ -8132,9 +8132,6 @@ if test "$BUILD_CTYPES"; then if test "$OS_ARCH" = "WINCE" -a `echo $OS_TEST | grep -ic arm` = 1; then # Disable ctypes for arm/wince. BUILD_CTYPES= - elif test "$_MSC_VER" && test -z $AS; then - # Disable ctypes if we're on MSVC and MASM is unavailable. - AC_MSG_ERROR([No suitable assembler found. An assembler is required to build js-ctypes. You may --disable-ctypes to avoid this. If you are building with MS Visual Studio 8 Express, you may download the MASM 8.0 package, upgrade to Visual Studio 9 Express, or install the Vista SDK.]) else AC_DEFINE(BUILD_CTYPES) fi @@ -8725,6 +8722,10 @@ fi dist=$MOZ_BUILD_ROOT/dist ac_configure_args="$_SUBDIR_CONFIG_ARGS" ac_configure_args="$ac_configure_args --enable-threadsafe" +if test "$BUILD_CTYPES"; then + # Build js-ctypes on the platforms we can. + ac_configure_args="$ac_configure_args --enable-ctypes" +fi if test -z "$MOZ_NATIVE_NSPR"; then ac_configure_args="$ac_configure_args --with-nspr-cflags='$NSPR_CFLAGS'" ac_configure_args="$ac_configure_args --with-nspr-libs='$NSPR_LIBS'" @@ -8741,54 +8742,6 @@ fi AC_OUTPUT_SUBDIRS(js/src) ac_configure_args="$_SUBDIR_CONFIG_ARGS" -# Build jsctypes on the platforms we can. -if test "$BUILD_CTYPES"; then - # Run the libffi 'configure' script. - ac_configure_args="--disable-shared --enable-static --disable-raw-api" - if test "$MOZ_DEBUG"; then - ac_configure_args="$ac_configure_args --enable-debug" - fi - if test "$DSO_PIC_CFLAGS"; then - ac_configure_args="$ac_configure_args --with-pic" - fi - if test "$CROSS_COMPILE"; then - case "$target" in - *-mingw*) - ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\"" - ;; - *) - ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\" CC=\"$CC\"" - ;; - esac - fi - if test "$_MSC_VER"; then - # Use a wrapper script for cl and ml that looks more like gcc. - # autotools can't quite handle an MSVC build environment yet. - ac_configure_args="$ac_configure_args LD=link CPP=\"cl -nologo -EP\" SHELL=sh.exe" - case "${target_cpu}" in - x86_64) - # Need target since MSYS tools into mozilla-build may be 32bit - ac_configure_args="$ac_configure_args CC=\"$_topsrcdir/js/ctypes/libffi/msvcc.sh -m64\" --build=$build --host=$target" - ;; - *) - ac_configure_args="$ac_configure_args CC=$_topsrcdir/js/ctypes/libffi/msvcc.sh" - ;; - esac - fi - if test "$SOLARIS_SUNPRO_CC"; then - # Always use gcc for libffi on Solaris - ac_configure_args="$ac_configure_args CC=gcc" - fi - - # Use a separate cache file for libffi, since it does things differently - # from our configure. - old_cache_file=$cache_file - cache_file=js/ctypes/libffi/config.cache - AC_OUTPUT_SUBDIRS(js/ctypes/libffi) - cache_file=$old_cache_file - ac_configure_args="$_SUBDIR_CONFIG_ARGS" -fi - fi # COMPILE_ENVIRONMENT && !LIBXUL_SDK_DIR dnl Prevent the regeneration of autoconf.mk forcing rebuilds of the world diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 5c78cc2a21eb..274c8b42f267 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -278,6 +278,27 @@ endif endif # ENABLE_TRACEJIT +ifdef JS_HAS_CTYPES +CPPSRCS += \ + ctypes/CTypes.cpp \ + ctypes/Library.cpp \ + $(NULL) + +LOCAL_INCLUDES = \ + -Ictypes/libffi/include \ + $(NULL) + +ifeq ($(OS_ARCH),OS2) +# libffi builds an aout lib on OS/2; convert it to an OMF lib. +ctypes/libffi/.libs/libffi.$(LIB_SUFFIX): ctypes/libffi/.libs/libffi.a + emxomf $< +endif + +SHARED_LIBRARY_LIBS = \ + ctypes/libffi/.libs/libffi.$(LIB_SUFFIX) \ + $(NULL) +endif # JS_HAS_CTYPES + ifdef HAVE_DTRACE INSTALLED_HEADERS += \ jsdtracef.h \ @@ -347,6 +368,16 @@ endif include $(topsrcdir)/config/rules.mk +ifdef JS_HAS_CTYPES +# Build libffi proper as part of the 'exports' target, so things get built +# in the right order. +export:: + $(call SUBMAKE,,ctypes/libffi) + +clean:: + $(call SUBMAKE,clean,ctypes/libffi) +endif + ifdef MOZ_SYNC_BUILD_FILES # Because the SpiderMonkey can be distributed and built independently # of the Mozilla source tree, it contains its own copies of many of @@ -409,6 +440,10 @@ ifdef JS_THREADSAFE DEFINES += -DJS_THREADSAFE endif +ifdef JS_HAS_CTYPES +DEFINES += -DJS_HAS_CTYPES +endif + ifdef JS_NO_THIN_LOCKS DEFINES += -DJS_USE_ONLY_NSPR_LOCKS endif diff --git a/js/src/Makefile.ref b/js/src/Makefile.ref index 50308a2dc5c2..0e8096805c7c 100644 --- a/js/src/Makefile.ref +++ b/js/src/Makefile.ref @@ -91,6 +91,16 @@ OTHER_LIBS += -L$(DIST)/lib -lnspr$(NSPR_LIBSUFFIX) endif endif +ifdef JS_HAS_CTYPES +DEFINES += -DJS_HAS_CTYPES +INCLUDES += -I$(DIST)/include/nspr +ifdef USE_MSVC +OTHER_LIBS += $(DIST)/lib/libnspr$(NSPR_LIBSUFFIX).lib +else +OTHER_LIBS += -L$(DIST)/lib -lnspr$(NSPR_LIBSUFFIX) +endif +endif + ifdef JS_NO_THIN_LOCKS DEFINES += -DJS_USE_ONLY_NSPR_LOCKS endif @@ -392,6 +402,7 @@ js-config-switch=$(if $(value $($1)),-e 's/\#undef $1/\#define $1/') $(OBJDIR)/js-config.h.stamp: js-config.h.in Makefile.ref sed < $< > $(@:.stamp=.tmp) \ $(call js-config-switch,JS_THREADSAFE) \ + $(call js-config-switch,JS_HAS_CTYPES) \ $(call js-config-switch,JS_GC_ZEAL) \ -e :dummy if ! [ -f $(@:.stamp=) ] || ! cmp $(@:.stamp=.tmp) $(@:.stamp=); then \ diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in index f5cf1e358906..e9fb9ad01858 100644 --- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -92,6 +92,7 @@ MOZ_JPROF = @MOZ_JPROF@ MOZ_SHARK = @MOZ_SHARK@ MOZ_CALLGRIND = @MOZ_CALLGRIND@ MOZ_VTUNE = @MOZ_VTUNE@ +JS_HAS_CTYPES = @JS_HAS_CTYPES@ DEHYDRA_PATH = @DEHYDRA_PATH@ NS_TRACE_MALLOC = @NS_TRACE_MALLOC@ diff --git a/js/src/configure.in b/js/src/configure.in index 616a4144602d..718658a307de 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -4220,6 +4220,22 @@ MOZ_ARG_WITH_STRING(wrap-malloc, [ --with-wrap-malloc=DIR Location of malloc wrapper library], WRAP_MALLOC_LIB=$withval) +dnl ======================================================== +dnl = Build jsctypes if it's enabled +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(ctypes, +[ --enable-ctypes Enable js-ctypes (default=no)], + JS_HAS_CTYPES=1, + JS_HAS_CTYPES= ) +AC_SUBST(JS_HAS_CTYPES) +if test "$JS_HAS_CTYPES"; then + if test "$_MSC_VER" && test -z $AS; then + # Error out if we're on MSVC and MASM is unavailable. + AC_MSG_ERROR([No suitable assembler found. An assembler is required to build js-ctypes. If you are building with MS Visual Studio 8 Express, you may download the MASM 8.0 package, upgrade to Visual Studio 9 Express, or install the Vista SDK.]) + fi + AC_DEFINE(JS_HAS_CTYPES) +fi + dnl ======================================================== dnl = Use TraceVis dnl ======================================================== @@ -5171,6 +5187,8 @@ MAKEFILES=" Makefile shell/Makefile lirasm/Makefile + ctypes/Makefile + ctypes/tests/Makefile jsapi-tests/Makefile tests/Makefile config/Makefile @@ -5221,3 +5239,55 @@ fi # 'js-config' in Makefile.in. AC_MSG_RESULT(invoking make to create js-config script) $MAKE js-config + +# Build jsctypes if it's enabled. +if test "$JS_HAS_CTYPES"; then + # Run the libffi 'configure' script. + ac_configure_args="--disable-shared --enable-static --disable-raw-api" + if test "$MOZ_DEBUG"; then + ac_configure_args="$ac_configure_args --enable-debug" + fi + if test "$DSO_PIC_CFLAGS"; then + ac_configure_args="$ac_configure_args --with-pic" + fi + if test "$CROSS_COMPILE"; then + case "$target" in + *-mingw*) + ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\"" + ;; + *) + ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\" CC=\"$CC\"" + ;; + esac + fi + if test "$_MSC_VER"; then + # Use a wrapper script for cl and ml that looks more like gcc. + # autotools can't quite handle an MSVC build environment yet. + ac_configure_args="$ac_configure_args LD=link CPP=\"cl -nologo -EP\" SHELL=sh.exe" + case "${target_cpu}" in + x86_64) + # Need target since MSYS tools into mozilla-build may be 32bit + ac_configure_args="$ac_configure_args CC=\"$_topsrcdir/ctypes/libffi/msvcc.sh -m64\" --build=$build --host=$target" + ;; + *) + ac_configure_args="$ac_configure_args CC=$_topsrcdir/ctypes/libffi/msvcc.sh" + ;; + esac + fi + if test "$SOLARIS_SUNPRO_CC"; then + # Always use gcc for libffi on Solaris + ac_configure_args="$ac_configure_args CC=gcc" + fi + + # Use a separate cache file for libffi, since it does things differently + # from our configure. + old_cache_file=$cache_file + cache_file=ctypes/libffi/config.cache + old_config_files=$CONFIG_FILES + unset CONFIG_FILES + AC_OUTPUT_SUBDIRS(ctypes/libffi) + cache_file=$old_cache_file + ac_configure_args="$_SUBDIR_CONFIG_ARGS" + CONFIG_FILES=$old_config_files +fi + diff --git a/js/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp similarity index 100% rename from js/ctypes/CTypes.cpp rename to js/src/ctypes/CTypes.cpp diff --git a/js/ctypes/CTypes.h b/js/src/ctypes/CTypes.h similarity index 100% rename from js/ctypes/CTypes.h rename to js/src/ctypes/CTypes.h diff --git a/js/ctypes/Library.cpp b/js/src/ctypes/Library.cpp similarity index 100% rename from js/ctypes/Library.cpp rename to js/src/ctypes/Library.cpp diff --git a/js/ctypes/Library.h b/js/src/ctypes/Library.h similarity index 100% rename from js/ctypes/Library.h rename to js/src/ctypes/Library.h diff --git a/js/ctypes/ctypes.msg b/js/src/ctypes/ctypes.msg similarity index 100% rename from js/ctypes/ctypes.msg rename to js/src/ctypes/ctypes.msg diff --git a/js/ctypes/libffi.patch b/js/src/ctypes/libffi.patch similarity index 100% rename from js/ctypes/libffi.patch rename to js/src/ctypes/libffi.patch diff --git a/js/ctypes/libffi/ChangeLog b/js/src/ctypes/libffi/ChangeLog similarity index 100% rename from js/ctypes/libffi/ChangeLog rename to js/src/ctypes/libffi/ChangeLog diff --git a/js/ctypes/libffi/ChangeLog.libffi b/js/src/ctypes/libffi/ChangeLog.libffi similarity index 100% rename from js/ctypes/libffi/ChangeLog.libffi rename to js/src/ctypes/libffi/ChangeLog.libffi diff --git a/js/ctypes/libffi/ChangeLog.libgcj b/js/src/ctypes/libffi/ChangeLog.libgcj similarity index 100% rename from js/ctypes/libffi/ChangeLog.libgcj rename to js/src/ctypes/libffi/ChangeLog.libgcj diff --git a/js/ctypes/libffi/ChangeLog.v1 b/js/src/ctypes/libffi/ChangeLog.v1 similarity index 100% rename from js/ctypes/libffi/ChangeLog.v1 rename to js/src/ctypes/libffi/ChangeLog.v1 diff --git a/js/ctypes/libffi/LICENSE b/js/src/ctypes/libffi/LICENSE similarity index 100% rename from js/ctypes/libffi/LICENSE rename to js/src/ctypes/libffi/LICENSE diff --git a/js/ctypes/libffi/Makefile.am b/js/src/ctypes/libffi/Makefile.am similarity index 100% rename from js/ctypes/libffi/Makefile.am rename to js/src/ctypes/libffi/Makefile.am diff --git a/js/ctypes/libffi/Makefile.in b/js/src/ctypes/libffi/Makefile.in similarity index 100% rename from js/ctypes/libffi/Makefile.in rename to js/src/ctypes/libffi/Makefile.in diff --git a/js/ctypes/libffi/README b/js/src/ctypes/libffi/README similarity index 100% rename from js/ctypes/libffi/README rename to js/src/ctypes/libffi/README diff --git a/js/ctypes/libffi/acinclude.m4 b/js/src/ctypes/libffi/acinclude.m4 similarity index 100% rename from js/ctypes/libffi/acinclude.m4 rename to js/src/ctypes/libffi/acinclude.m4 diff --git a/js/ctypes/libffi/aclocal.m4 b/js/src/ctypes/libffi/aclocal.m4 similarity index 100% rename from js/ctypes/libffi/aclocal.m4 rename to js/src/ctypes/libffi/aclocal.m4 diff --git a/js/ctypes/libffi/compile b/js/src/ctypes/libffi/compile similarity index 100% rename from js/ctypes/libffi/compile rename to js/src/ctypes/libffi/compile diff --git a/js/ctypes/libffi/config.guess b/js/src/ctypes/libffi/config.guess similarity index 100% rename from js/ctypes/libffi/config.guess rename to js/src/ctypes/libffi/config.guess diff --git a/js/ctypes/libffi/config.sub b/js/src/ctypes/libffi/config.sub similarity index 100% rename from js/ctypes/libffi/config.sub rename to js/src/ctypes/libffi/config.sub diff --git a/js/ctypes/libffi/configure b/js/src/ctypes/libffi/configure similarity index 100% rename from js/ctypes/libffi/configure rename to js/src/ctypes/libffi/configure diff --git a/js/ctypes/libffi/configure.ac b/js/src/ctypes/libffi/configure.ac similarity index 100% rename from js/ctypes/libffi/configure.ac rename to js/src/ctypes/libffi/configure.ac diff --git a/js/ctypes/libffi/configure.host b/js/src/ctypes/libffi/configure.host similarity index 100% rename from js/ctypes/libffi/configure.host rename to js/src/ctypes/libffi/configure.host diff --git a/js/ctypes/libffi/depcomp b/js/src/ctypes/libffi/depcomp similarity index 100% rename from js/ctypes/libffi/depcomp rename to js/src/ctypes/libffi/depcomp diff --git a/js/ctypes/libffi/doc/libffi.info b/js/src/ctypes/libffi/doc/libffi.info similarity index 100% rename from js/ctypes/libffi/doc/libffi.info rename to js/src/ctypes/libffi/doc/libffi.info diff --git a/js/ctypes/libffi/doc/libffi.texi b/js/src/ctypes/libffi/doc/libffi.texi similarity index 100% rename from js/ctypes/libffi/doc/libffi.texi rename to js/src/ctypes/libffi/doc/libffi.texi diff --git a/js/ctypes/libffi/doc/stamp-vti b/js/src/ctypes/libffi/doc/stamp-vti similarity index 100% rename from js/ctypes/libffi/doc/stamp-vti rename to js/src/ctypes/libffi/doc/stamp-vti diff --git a/js/ctypes/libffi/doc/version.texi b/js/src/ctypes/libffi/doc/version.texi similarity index 100% rename from js/ctypes/libffi/doc/version.texi rename to js/src/ctypes/libffi/doc/version.texi diff --git a/js/ctypes/libffi/fficonfig.h.in b/js/src/ctypes/libffi/fficonfig.h.in similarity index 100% rename from js/ctypes/libffi/fficonfig.h.in rename to js/src/ctypes/libffi/fficonfig.h.in diff --git a/js/ctypes/libffi/include/Makefile.am b/js/src/ctypes/libffi/include/Makefile.am similarity index 100% rename from js/ctypes/libffi/include/Makefile.am rename to js/src/ctypes/libffi/include/Makefile.am diff --git a/js/ctypes/libffi/include/Makefile.in b/js/src/ctypes/libffi/include/Makefile.in similarity index 100% rename from js/ctypes/libffi/include/Makefile.in rename to js/src/ctypes/libffi/include/Makefile.in diff --git a/js/ctypes/libffi/include/ffi.h.in b/js/src/ctypes/libffi/include/ffi.h.in similarity index 100% rename from js/ctypes/libffi/include/ffi.h.in rename to js/src/ctypes/libffi/include/ffi.h.in diff --git a/js/ctypes/libffi/include/ffi_common.h b/js/src/ctypes/libffi/include/ffi_common.h similarity index 100% rename from js/ctypes/libffi/include/ffi_common.h rename to js/src/ctypes/libffi/include/ffi_common.h diff --git a/js/ctypes/libffi/install-sh b/js/src/ctypes/libffi/install-sh similarity index 100% rename from js/ctypes/libffi/install-sh rename to js/src/ctypes/libffi/install-sh diff --git a/js/ctypes/libffi/libffi.pc.in b/js/src/ctypes/libffi/libffi.pc.in similarity index 100% rename from js/ctypes/libffi/libffi.pc.in rename to js/src/ctypes/libffi/libffi.pc.in diff --git a/js/ctypes/libffi/libtool-version b/js/src/ctypes/libffi/libtool-version similarity index 100% rename from js/ctypes/libffi/libtool-version rename to js/src/ctypes/libffi/libtool-version diff --git a/js/ctypes/libffi/ltmain.sh b/js/src/ctypes/libffi/ltmain.sh similarity index 100% rename from js/ctypes/libffi/ltmain.sh rename to js/src/ctypes/libffi/ltmain.sh diff --git a/js/ctypes/libffi/m4/libtool.m4 b/js/src/ctypes/libffi/m4/libtool.m4 similarity index 100% rename from js/ctypes/libffi/m4/libtool.m4 rename to js/src/ctypes/libffi/m4/libtool.m4 diff --git a/js/ctypes/libffi/m4/ltoptions.m4 b/js/src/ctypes/libffi/m4/ltoptions.m4 similarity index 100% rename from js/ctypes/libffi/m4/ltoptions.m4 rename to js/src/ctypes/libffi/m4/ltoptions.m4 diff --git a/js/ctypes/libffi/m4/ltsugar.m4 b/js/src/ctypes/libffi/m4/ltsugar.m4 similarity index 100% rename from js/ctypes/libffi/m4/ltsugar.m4 rename to js/src/ctypes/libffi/m4/ltsugar.m4 diff --git a/js/ctypes/libffi/m4/ltversion.m4 b/js/src/ctypes/libffi/m4/ltversion.m4 similarity index 100% rename from js/ctypes/libffi/m4/ltversion.m4 rename to js/src/ctypes/libffi/m4/ltversion.m4 diff --git a/js/ctypes/libffi/m4/lt~obsolete.m4 b/js/src/ctypes/libffi/m4/lt~obsolete.m4 similarity index 100% rename from js/ctypes/libffi/m4/lt~obsolete.m4 rename to js/src/ctypes/libffi/m4/lt~obsolete.m4 diff --git a/js/ctypes/libffi/man/Makefile.am b/js/src/ctypes/libffi/man/Makefile.am similarity index 100% rename from js/ctypes/libffi/man/Makefile.am rename to js/src/ctypes/libffi/man/Makefile.am diff --git a/js/ctypes/libffi/man/Makefile.in b/js/src/ctypes/libffi/man/Makefile.in similarity index 100% rename from js/ctypes/libffi/man/Makefile.in rename to js/src/ctypes/libffi/man/Makefile.in diff --git a/js/ctypes/libffi/man/ffi.3 b/js/src/ctypes/libffi/man/ffi.3 similarity index 100% rename from js/ctypes/libffi/man/ffi.3 rename to js/src/ctypes/libffi/man/ffi.3 diff --git a/js/ctypes/libffi/man/ffi_call.3 b/js/src/ctypes/libffi/man/ffi_call.3 similarity index 100% rename from js/ctypes/libffi/man/ffi_call.3 rename to js/src/ctypes/libffi/man/ffi_call.3 diff --git a/js/ctypes/libffi/man/ffi_prep_cif.3 b/js/src/ctypes/libffi/man/ffi_prep_cif.3 similarity index 100% rename from js/ctypes/libffi/man/ffi_prep_cif.3 rename to js/src/ctypes/libffi/man/ffi_prep_cif.3 diff --git a/js/ctypes/libffi/mdate-sh b/js/src/ctypes/libffi/mdate-sh similarity index 100% rename from js/ctypes/libffi/mdate-sh rename to js/src/ctypes/libffi/mdate-sh diff --git a/js/ctypes/libffi/missing b/js/src/ctypes/libffi/missing similarity index 100% rename from js/ctypes/libffi/missing rename to js/src/ctypes/libffi/missing diff --git a/js/ctypes/libffi/msvcc.sh b/js/src/ctypes/libffi/msvcc.sh similarity index 100% rename from js/ctypes/libffi/msvcc.sh rename to js/src/ctypes/libffi/msvcc.sh diff --git a/js/ctypes/libffi/src/alpha/ffi.c b/js/src/ctypes/libffi/src/alpha/ffi.c similarity index 100% rename from js/ctypes/libffi/src/alpha/ffi.c rename to js/src/ctypes/libffi/src/alpha/ffi.c diff --git a/js/ctypes/libffi/src/alpha/ffitarget.h b/js/src/ctypes/libffi/src/alpha/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/alpha/ffitarget.h rename to js/src/ctypes/libffi/src/alpha/ffitarget.h diff --git a/js/ctypes/libffi/src/alpha/osf.S b/js/src/ctypes/libffi/src/alpha/osf.S similarity index 100% rename from js/ctypes/libffi/src/alpha/osf.S rename to js/src/ctypes/libffi/src/alpha/osf.S diff --git a/js/ctypes/libffi/src/arm/ffi.c b/js/src/ctypes/libffi/src/arm/ffi.c similarity index 100% rename from js/ctypes/libffi/src/arm/ffi.c rename to js/src/ctypes/libffi/src/arm/ffi.c diff --git a/js/ctypes/libffi/src/arm/ffitarget.h b/js/src/ctypes/libffi/src/arm/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/arm/ffitarget.h rename to js/src/ctypes/libffi/src/arm/ffitarget.h diff --git a/js/ctypes/libffi/src/arm/sysv.S b/js/src/ctypes/libffi/src/arm/sysv.S similarity index 100% rename from js/ctypes/libffi/src/arm/sysv.S rename to js/src/ctypes/libffi/src/arm/sysv.S diff --git a/js/ctypes/libffi/src/avr32/ffi.c b/js/src/ctypes/libffi/src/avr32/ffi.c similarity index 100% rename from js/ctypes/libffi/src/avr32/ffi.c rename to js/src/ctypes/libffi/src/avr32/ffi.c diff --git a/js/ctypes/libffi/src/avr32/ffitarget.h b/js/src/ctypes/libffi/src/avr32/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/avr32/ffitarget.h rename to js/src/ctypes/libffi/src/avr32/ffitarget.h diff --git a/js/ctypes/libffi/src/avr32/sysv.S b/js/src/ctypes/libffi/src/avr32/sysv.S similarity index 100% rename from js/ctypes/libffi/src/avr32/sysv.S rename to js/src/ctypes/libffi/src/avr32/sysv.S diff --git a/js/ctypes/libffi/src/closures.c b/js/src/ctypes/libffi/src/closures.c similarity index 100% rename from js/ctypes/libffi/src/closures.c rename to js/src/ctypes/libffi/src/closures.c diff --git a/js/ctypes/libffi/src/cris/ffi.c b/js/src/ctypes/libffi/src/cris/ffi.c similarity index 100% rename from js/ctypes/libffi/src/cris/ffi.c rename to js/src/ctypes/libffi/src/cris/ffi.c diff --git a/js/ctypes/libffi/src/cris/ffitarget.h b/js/src/ctypes/libffi/src/cris/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/cris/ffitarget.h rename to js/src/ctypes/libffi/src/cris/ffitarget.h diff --git a/js/ctypes/libffi/src/cris/sysv.S b/js/src/ctypes/libffi/src/cris/sysv.S similarity index 100% rename from js/ctypes/libffi/src/cris/sysv.S rename to js/src/ctypes/libffi/src/cris/sysv.S diff --git a/js/ctypes/libffi/src/debug.c b/js/src/ctypes/libffi/src/debug.c similarity index 100% rename from js/ctypes/libffi/src/debug.c rename to js/src/ctypes/libffi/src/debug.c diff --git a/js/ctypes/libffi/src/dlmalloc.c b/js/src/ctypes/libffi/src/dlmalloc.c similarity index 100% rename from js/ctypes/libffi/src/dlmalloc.c rename to js/src/ctypes/libffi/src/dlmalloc.c diff --git a/js/ctypes/libffi/src/frv/eabi.S b/js/src/ctypes/libffi/src/frv/eabi.S similarity index 100% rename from js/ctypes/libffi/src/frv/eabi.S rename to js/src/ctypes/libffi/src/frv/eabi.S diff --git a/js/ctypes/libffi/src/frv/ffi.c b/js/src/ctypes/libffi/src/frv/ffi.c similarity index 100% rename from js/ctypes/libffi/src/frv/ffi.c rename to js/src/ctypes/libffi/src/frv/ffi.c diff --git a/js/ctypes/libffi/src/frv/ffitarget.h b/js/src/ctypes/libffi/src/frv/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/frv/ffitarget.h rename to js/src/ctypes/libffi/src/frv/ffitarget.h diff --git a/js/ctypes/libffi/src/ia64/ffi.c b/js/src/ctypes/libffi/src/ia64/ffi.c similarity index 100% rename from js/ctypes/libffi/src/ia64/ffi.c rename to js/src/ctypes/libffi/src/ia64/ffi.c diff --git a/js/ctypes/libffi/src/ia64/ffitarget.h b/js/src/ctypes/libffi/src/ia64/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/ia64/ffitarget.h rename to js/src/ctypes/libffi/src/ia64/ffitarget.h diff --git a/js/ctypes/libffi/src/ia64/ia64_flags.h b/js/src/ctypes/libffi/src/ia64/ia64_flags.h similarity index 100% rename from js/ctypes/libffi/src/ia64/ia64_flags.h rename to js/src/ctypes/libffi/src/ia64/ia64_flags.h diff --git a/js/ctypes/libffi/src/ia64/unix.S b/js/src/ctypes/libffi/src/ia64/unix.S similarity index 100% rename from js/ctypes/libffi/src/ia64/unix.S rename to js/src/ctypes/libffi/src/ia64/unix.S diff --git a/js/ctypes/libffi/src/java_raw_api.c b/js/src/ctypes/libffi/src/java_raw_api.c similarity index 100% rename from js/ctypes/libffi/src/java_raw_api.c rename to js/src/ctypes/libffi/src/java_raw_api.c diff --git a/js/ctypes/libffi/src/m32r/ffi.c b/js/src/ctypes/libffi/src/m32r/ffi.c similarity index 100% rename from js/ctypes/libffi/src/m32r/ffi.c rename to js/src/ctypes/libffi/src/m32r/ffi.c diff --git a/js/ctypes/libffi/src/m32r/ffitarget.h b/js/src/ctypes/libffi/src/m32r/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/m32r/ffitarget.h rename to js/src/ctypes/libffi/src/m32r/ffitarget.h diff --git a/js/ctypes/libffi/src/m32r/sysv.S b/js/src/ctypes/libffi/src/m32r/sysv.S similarity index 100% rename from js/ctypes/libffi/src/m32r/sysv.S rename to js/src/ctypes/libffi/src/m32r/sysv.S diff --git a/js/ctypes/libffi/src/m68k/ffi.c b/js/src/ctypes/libffi/src/m68k/ffi.c similarity index 100% rename from js/ctypes/libffi/src/m68k/ffi.c rename to js/src/ctypes/libffi/src/m68k/ffi.c diff --git a/js/ctypes/libffi/src/m68k/ffitarget.h b/js/src/ctypes/libffi/src/m68k/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/m68k/ffitarget.h rename to js/src/ctypes/libffi/src/m68k/ffitarget.h diff --git a/js/ctypes/libffi/src/m68k/sysv.S b/js/src/ctypes/libffi/src/m68k/sysv.S similarity index 100% rename from js/ctypes/libffi/src/m68k/sysv.S rename to js/src/ctypes/libffi/src/m68k/sysv.S diff --git a/js/ctypes/libffi/src/mips/ffi.c b/js/src/ctypes/libffi/src/mips/ffi.c similarity index 100% rename from js/ctypes/libffi/src/mips/ffi.c rename to js/src/ctypes/libffi/src/mips/ffi.c diff --git a/js/ctypes/libffi/src/mips/ffitarget.h b/js/src/ctypes/libffi/src/mips/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/mips/ffitarget.h rename to js/src/ctypes/libffi/src/mips/ffitarget.h diff --git a/js/ctypes/libffi/src/mips/n32.S b/js/src/ctypes/libffi/src/mips/n32.S similarity index 100% rename from js/ctypes/libffi/src/mips/n32.S rename to js/src/ctypes/libffi/src/mips/n32.S diff --git a/js/ctypes/libffi/src/mips/o32.S b/js/src/ctypes/libffi/src/mips/o32.S similarity index 100% rename from js/ctypes/libffi/src/mips/o32.S rename to js/src/ctypes/libffi/src/mips/o32.S diff --git a/js/ctypes/libffi/src/moxie/eabi.S b/js/src/ctypes/libffi/src/moxie/eabi.S similarity index 100% rename from js/ctypes/libffi/src/moxie/eabi.S rename to js/src/ctypes/libffi/src/moxie/eabi.S diff --git a/js/ctypes/libffi/src/moxie/ffi.c b/js/src/ctypes/libffi/src/moxie/ffi.c similarity index 100% rename from js/ctypes/libffi/src/moxie/ffi.c rename to js/src/ctypes/libffi/src/moxie/ffi.c diff --git a/js/ctypes/libffi/src/moxie/ffitarget.h b/js/src/ctypes/libffi/src/moxie/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/moxie/ffitarget.h rename to js/src/ctypes/libffi/src/moxie/ffitarget.h diff --git a/js/ctypes/libffi/src/pa/ffi.c b/js/src/ctypes/libffi/src/pa/ffi.c similarity index 100% rename from js/ctypes/libffi/src/pa/ffi.c rename to js/src/ctypes/libffi/src/pa/ffi.c diff --git a/js/ctypes/libffi/src/pa/ffitarget.h b/js/src/ctypes/libffi/src/pa/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/pa/ffitarget.h rename to js/src/ctypes/libffi/src/pa/ffitarget.h diff --git a/js/ctypes/libffi/src/pa/hpux32.S b/js/src/ctypes/libffi/src/pa/hpux32.S similarity index 100% rename from js/ctypes/libffi/src/pa/hpux32.S rename to js/src/ctypes/libffi/src/pa/hpux32.S diff --git a/js/ctypes/libffi/src/pa/linux.S b/js/src/ctypes/libffi/src/pa/linux.S similarity index 100% rename from js/ctypes/libffi/src/pa/linux.S rename to js/src/ctypes/libffi/src/pa/linux.S diff --git a/js/ctypes/libffi/src/powerpc/aix.S b/js/src/ctypes/libffi/src/powerpc/aix.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/aix.S rename to js/src/ctypes/libffi/src/powerpc/aix.S diff --git a/js/ctypes/libffi/src/powerpc/aix_closure.S b/js/src/ctypes/libffi/src/powerpc/aix_closure.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/aix_closure.S rename to js/src/ctypes/libffi/src/powerpc/aix_closure.S diff --git a/js/ctypes/libffi/src/powerpc/asm.h b/js/src/ctypes/libffi/src/powerpc/asm.h similarity index 100% rename from js/ctypes/libffi/src/powerpc/asm.h rename to js/src/ctypes/libffi/src/powerpc/asm.h diff --git a/js/ctypes/libffi/src/powerpc/darwin.S b/js/src/ctypes/libffi/src/powerpc/darwin.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/darwin.S rename to js/src/ctypes/libffi/src/powerpc/darwin.S diff --git a/js/ctypes/libffi/src/powerpc/darwin_closure.S b/js/src/ctypes/libffi/src/powerpc/darwin_closure.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/darwin_closure.S rename to js/src/ctypes/libffi/src/powerpc/darwin_closure.S diff --git a/js/ctypes/libffi/src/powerpc/ffi.c b/js/src/ctypes/libffi/src/powerpc/ffi.c similarity index 100% rename from js/ctypes/libffi/src/powerpc/ffi.c rename to js/src/ctypes/libffi/src/powerpc/ffi.c diff --git a/js/ctypes/libffi/src/powerpc/ffi_darwin.c b/js/src/ctypes/libffi/src/powerpc/ffi_darwin.c similarity index 100% rename from js/ctypes/libffi/src/powerpc/ffi_darwin.c rename to js/src/ctypes/libffi/src/powerpc/ffi_darwin.c diff --git a/js/ctypes/libffi/src/powerpc/ffitarget.h b/js/src/ctypes/libffi/src/powerpc/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/powerpc/ffitarget.h rename to js/src/ctypes/libffi/src/powerpc/ffitarget.h diff --git a/js/ctypes/libffi/src/powerpc/linux64.S b/js/src/ctypes/libffi/src/powerpc/linux64.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/linux64.S rename to js/src/ctypes/libffi/src/powerpc/linux64.S diff --git a/js/ctypes/libffi/src/powerpc/linux64_closure.S b/js/src/ctypes/libffi/src/powerpc/linux64_closure.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/linux64_closure.S rename to js/src/ctypes/libffi/src/powerpc/linux64_closure.S diff --git a/js/ctypes/libffi/src/powerpc/ppc_closure.S b/js/src/ctypes/libffi/src/powerpc/ppc_closure.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/ppc_closure.S rename to js/src/ctypes/libffi/src/powerpc/ppc_closure.S diff --git a/js/ctypes/libffi/src/powerpc/sysv.S b/js/src/ctypes/libffi/src/powerpc/sysv.S similarity index 100% rename from js/ctypes/libffi/src/powerpc/sysv.S rename to js/src/ctypes/libffi/src/powerpc/sysv.S diff --git a/js/ctypes/libffi/src/prep_cif.c b/js/src/ctypes/libffi/src/prep_cif.c similarity index 100% rename from js/ctypes/libffi/src/prep_cif.c rename to js/src/ctypes/libffi/src/prep_cif.c diff --git a/js/ctypes/libffi/src/raw_api.c b/js/src/ctypes/libffi/src/raw_api.c similarity index 100% rename from js/ctypes/libffi/src/raw_api.c rename to js/src/ctypes/libffi/src/raw_api.c diff --git a/js/ctypes/libffi/src/s390/ffi.c b/js/src/ctypes/libffi/src/s390/ffi.c similarity index 100% rename from js/ctypes/libffi/src/s390/ffi.c rename to js/src/ctypes/libffi/src/s390/ffi.c diff --git a/js/ctypes/libffi/src/s390/ffitarget.h b/js/src/ctypes/libffi/src/s390/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/s390/ffitarget.h rename to js/src/ctypes/libffi/src/s390/ffitarget.h diff --git a/js/ctypes/libffi/src/s390/sysv.S b/js/src/ctypes/libffi/src/s390/sysv.S similarity index 100% rename from js/ctypes/libffi/src/s390/sysv.S rename to js/src/ctypes/libffi/src/s390/sysv.S diff --git a/js/ctypes/libffi/src/sh/ffi.c b/js/src/ctypes/libffi/src/sh/ffi.c similarity index 100% rename from js/ctypes/libffi/src/sh/ffi.c rename to js/src/ctypes/libffi/src/sh/ffi.c diff --git a/js/ctypes/libffi/src/sh/ffitarget.h b/js/src/ctypes/libffi/src/sh/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/sh/ffitarget.h rename to js/src/ctypes/libffi/src/sh/ffitarget.h diff --git a/js/ctypes/libffi/src/sh/sysv.S b/js/src/ctypes/libffi/src/sh/sysv.S similarity index 100% rename from js/ctypes/libffi/src/sh/sysv.S rename to js/src/ctypes/libffi/src/sh/sysv.S diff --git a/js/ctypes/libffi/src/sh64/ffi.c b/js/src/ctypes/libffi/src/sh64/ffi.c similarity index 100% rename from js/ctypes/libffi/src/sh64/ffi.c rename to js/src/ctypes/libffi/src/sh64/ffi.c diff --git a/js/ctypes/libffi/src/sh64/ffitarget.h b/js/src/ctypes/libffi/src/sh64/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/sh64/ffitarget.h rename to js/src/ctypes/libffi/src/sh64/ffitarget.h diff --git a/js/ctypes/libffi/src/sh64/sysv.S b/js/src/ctypes/libffi/src/sh64/sysv.S similarity index 100% rename from js/ctypes/libffi/src/sh64/sysv.S rename to js/src/ctypes/libffi/src/sh64/sysv.S diff --git a/js/ctypes/libffi/src/sparc/ffi.c b/js/src/ctypes/libffi/src/sparc/ffi.c similarity index 100% rename from js/ctypes/libffi/src/sparc/ffi.c rename to js/src/ctypes/libffi/src/sparc/ffi.c diff --git a/js/ctypes/libffi/src/sparc/ffitarget.h b/js/src/ctypes/libffi/src/sparc/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/sparc/ffitarget.h rename to js/src/ctypes/libffi/src/sparc/ffitarget.h diff --git a/js/ctypes/libffi/src/sparc/v8.S b/js/src/ctypes/libffi/src/sparc/v8.S similarity index 100% rename from js/ctypes/libffi/src/sparc/v8.S rename to js/src/ctypes/libffi/src/sparc/v8.S diff --git a/js/ctypes/libffi/src/sparc/v9.S b/js/src/ctypes/libffi/src/sparc/v9.S similarity index 100% rename from js/ctypes/libffi/src/sparc/v9.S rename to js/src/ctypes/libffi/src/sparc/v9.S diff --git a/js/ctypes/libffi/src/types.c b/js/src/ctypes/libffi/src/types.c similarity index 100% rename from js/ctypes/libffi/src/types.c rename to js/src/ctypes/libffi/src/types.c diff --git a/js/ctypes/libffi/src/x86/darwin.S b/js/src/ctypes/libffi/src/x86/darwin.S similarity index 100% rename from js/ctypes/libffi/src/x86/darwin.S rename to js/src/ctypes/libffi/src/x86/darwin.S diff --git a/js/ctypes/libffi/src/x86/darwin64.S b/js/src/ctypes/libffi/src/x86/darwin64.S similarity index 100% rename from js/ctypes/libffi/src/x86/darwin64.S rename to js/src/ctypes/libffi/src/x86/darwin64.S diff --git a/js/ctypes/libffi/src/x86/ffi.c b/js/src/ctypes/libffi/src/x86/ffi.c similarity index 100% rename from js/ctypes/libffi/src/x86/ffi.c rename to js/src/ctypes/libffi/src/x86/ffi.c diff --git a/js/ctypes/libffi/src/x86/ffi64.c b/js/src/ctypes/libffi/src/x86/ffi64.c similarity index 100% rename from js/ctypes/libffi/src/x86/ffi64.c rename to js/src/ctypes/libffi/src/x86/ffi64.c diff --git a/js/ctypes/libffi/src/x86/ffitarget.h b/js/src/ctypes/libffi/src/x86/ffitarget.h similarity index 100% rename from js/ctypes/libffi/src/x86/ffitarget.h rename to js/src/ctypes/libffi/src/x86/ffitarget.h diff --git a/js/ctypes/libffi/src/x86/freebsd.S b/js/src/ctypes/libffi/src/x86/freebsd.S similarity index 100% rename from js/ctypes/libffi/src/x86/freebsd.S rename to js/src/ctypes/libffi/src/x86/freebsd.S diff --git a/js/ctypes/libffi/src/x86/sysv.S b/js/src/ctypes/libffi/src/x86/sysv.S similarity index 100% rename from js/ctypes/libffi/src/x86/sysv.S rename to js/src/ctypes/libffi/src/x86/sysv.S diff --git a/js/ctypes/libffi/src/x86/unix64.S b/js/src/ctypes/libffi/src/x86/unix64.S similarity index 100% rename from js/ctypes/libffi/src/x86/unix64.S rename to js/src/ctypes/libffi/src/x86/unix64.S diff --git a/js/ctypes/libffi/src/x86/win32.S b/js/src/ctypes/libffi/src/x86/win32.S similarity index 100% rename from js/ctypes/libffi/src/x86/win32.S rename to js/src/ctypes/libffi/src/x86/win32.S diff --git a/js/ctypes/libffi/src/x86/win64.S b/js/src/ctypes/libffi/src/x86/win64.S similarity index 100% rename from js/ctypes/libffi/src/x86/win64.S rename to js/src/ctypes/libffi/src/x86/win64.S diff --git a/js/ctypes/libffi/testsuite/Makefile.am b/js/src/ctypes/libffi/testsuite/Makefile.am similarity index 100% rename from js/ctypes/libffi/testsuite/Makefile.am rename to js/src/ctypes/libffi/testsuite/Makefile.am diff --git a/js/ctypes/libffi/testsuite/Makefile.in b/js/src/ctypes/libffi/testsuite/Makefile.in similarity index 100% rename from js/ctypes/libffi/testsuite/Makefile.in rename to js/src/ctypes/libffi/testsuite/Makefile.in diff --git a/js/ctypes/libffi/testsuite/config/default.exp b/js/src/ctypes/libffi/testsuite/config/default.exp similarity index 100% rename from js/ctypes/libffi/testsuite/config/default.exp rename to js/src/ctypes/libffi/testsuite/config/default.exp diff --git a/js/ctypes/libffi/testsuite/lib/libffi-dg.exp b/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp similarity index 100% rename from js/ctypes/libffi/testsuite/lib/libffi-dg.exp rename to js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp diff --git a/js/ctypes/libffi/testsuite/lib/target-libpath.exp b/js/src/ctypes/libffi/testsuite/lib/target-libpath.exp similarity index 100% rename from js/ctypes/libffi/testsuite/lib/target-libpath.exp rename to js/src/ctypes/libffi/testsuite/lib/target-libpath.exp diff --git a/js/ctypes/libffi/testsuite/lib/wrapper.exp b/js/src/ctypes/libffi/testsuite/lib/wrapper.exp similarity index 100% rename from js/ctypes/libffi/testsuite/lib/wrapper.exp rename to js/src/ctypes/libffi/testsuite/lib/wrapper.exp diff --git a/js/ctypes/libffi/testsuite/libffi.call/call.exp b/js/src/ctypes/libffi/testsuite/libffi.call/call.exp similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/call.exp rename to js/src/ctypes/libffi/testsuite/libffi.call/call.exp diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn0.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn0.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn1.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn2.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn3.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn3.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn4.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn4.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn5.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn5.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_fn6.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_fn6.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c rename to js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_12byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_12byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_16byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_16byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_18byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_18byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_19byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_19byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_20byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_20byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_24byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_24byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_2byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_2byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_4byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_4byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_5byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_5byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_64byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_64byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_6byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_6byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_7byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_7byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_8byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_8byte.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_double.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_double.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_float.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_float.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_double.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_double.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_double_va.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_double_va.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_float.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_float.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_pointer.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_pointer.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_schar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_schar.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_sint.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_sint.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_sshort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_sshort.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_uchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_uchar.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_uint.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_uint.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/cls_ushort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/cls_ushort.c rename to js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c b/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c rename to js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c b/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c rename to js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/ffitest.h b/js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/ffitest.h rename to js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h diff --git a/js/ctypes/libffi/testsuite/libffi.call/float.c b/js/src/ctypes/libffi/testsuite/libffi.call/float.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/float.c rename to js/src/ctypes/libffi/testsuite/libffi.call/float.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/float1.c b/js/src/ctypes/libffi/testsuite/libffi.call/float1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/float1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/float1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/float2.c b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/float2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/float2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/float3.c b/js/src/ctypes/libffi/testsuite/libffi.call/float3.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/float3.c rename to js/src/ctypes/libffi/testsuite/libffi.call/float3.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/float4.c b/js/src/ctypes/libffi/testsuite/libffi.call/float4.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/float4.c rename to js/src/ctypes/libffi/testsuite/libffi.call/float4.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/huge_struct.c b/js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/huge_struct.c rename to js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/many.c b/js/src/ctypes/libffi/testsuite/libffi.call/many.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/many.c rename to js/src/ctypes/libffi/testsuite/libffi.call/many.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/many_win32.c b/js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/many_win32.c rename to js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/negint.c b/js/src/ctypes/libffi/testsuite/libffi.call/negint.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/negint.c rename to js/src/ctypes/libffi/testsuite/libffi.call/negint.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct1.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct10.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct10.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct2.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct3.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct3.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct4.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct4.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct5.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct5.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct6.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct6.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct7.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct7.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct8.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct8.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/nested_struct9.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/nested_struct9.c rename to js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/problem1.c b/js/src/ctypes/libffi/testsuite/libffi.call/problem1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/problem1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/problem1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/promotion.c b/js/src/ctypes/libffi/testsuite/libffi.call/promotion.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/promotion.c rename to js/src/ctypes/libffi/testsuite/libffi.call/promotion.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c b/js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c rename to js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_dbl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_dbl.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_dbl1.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_dbl1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_dbl2.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_dbl2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_fl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_fl.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_fl1.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_fl1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_fl2.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_fl2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_fl3.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_fl3.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_ldl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_ldl.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_ll.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_ll.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_ll1.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_ll1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_sc.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_sc.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_sl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_sl.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_uc.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_uc.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/return_ul.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/return_ul.c rename to js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/stret_large.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/stret_large.c rename to js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/stret_large2.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/stret_large2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/stret_medium.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/stret_medium.c rename to js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/stret_medium2.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/stret_medium2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/strlen.c b/js/src/ctypes/libffi/testsuite/libffi.call/strlen.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/strlen.c rename to js/src/ctypes/libffi/testsuite/libffi.call/strlen.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/strlen_win32.c b/js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/strlen_win32.c rename to js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct1.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct1.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct1.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct1.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct2.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct2.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct2.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct2.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct3.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct3.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct3.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct3.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct4.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct4.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct4.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct4.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct5.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct5.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct5.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct5.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct6.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct6.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct6.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct6.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct7.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct7.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct7.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct7.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct8.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct8.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct8.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct8.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/struct9.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct9.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/struct9.c rename to js/src/ctypes/libffi/testsuite/libffi.call/struct9.c diff --git a/js/ctypes/libffi/testsuite/libffi.call/testclosure.c b/js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.call/testclosure.c rename to js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c diff --git a/js/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h b/js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h rename to js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h diff --git a/js/ctypes/libffi/testsuite/libffi.special/special.exp b/js/src/ctypes/libffi/testsuite/libffi.special/special.exp similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.special/special.exp rename to js/src/ctypes/libffi/testsuite/libffi.special/special.exp diff --git a/js/ctypes/libffi/testsuite/libffi.special/unwindtest.cc b/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.special/unwindtest.cc rename to js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc diff --git a/js/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc b/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc similarity index 100% rename from js/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc rename to js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc diff --git a/js/ctypes/libffi/texinfo.tex b/js/src/ctypes/libffi/texinfo.tex similarity index 100% rename from js/ctypes/libffi/texinfo.tex rename to js/src/ctypes/libffi/texinfo.tex diff --git a/js/ctypes/typedefs.h b/js/src/ctypes/typedefs.h similarity index 100% rename from js/ctypes/typedefs.h rename to js/src/ctypes/typedefs.h diff --git a/js/src/js-config.h.in b/js/src/js-config.h.in index 7555d933f268..a16d154acbc6 100644 --- a/js/src/js-config.h.in +++ b/js/src/js-config.h.in @@ -48,6 +48,9 @@ /* Define to 1 if SpiderMonkey should support multi-threaded clients. */ #undef JS_THREADSAFE +/* Define to 1 if SpiderMonkey should include ctypes support. */ +#undef JS_HAS_CTYPES + /* Define to 1 if SpiderMonkey should support the ability to perform entirely too much GC. */ #undef JS_GC_ZEAL diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 94774b02f90a..eb3bf62f91d6 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -212,10 +212,6 @@ MAKEFILES_jsdebugger=" js/jsd/idl/Makefile " -MAKEFILES_jsctypes=" - js/ctypes/Makefile -" - MAKEFILES_content=" content/Makefile content/base/Makefile diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk index ecc684193abc..22a6f1391f3c 100644 --- a/toolkit/toolkit-tiers.mk +++ b/toolkit/toolkit-tiers.mk @@ -111,16 +111,9 @@ endif tier_platform_dirs += \ js/src/xpconnect \ - js/ctypes \ intl/chardet \ $(NULL) -ifdef BUILD_CTYPES -tier_platform_staticdirs += \ - js/ctypes/libffi \ - $(NULL) -endif - ifdef MOZ_ENABLE_GTK2 ifdef MOZ_X11 tier_platform_dirs += widget/src/gtkxtbin From 59e87a64d6e131262c404e0d45e5064c3d2e22e0 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 12:58:34 -0700 Subject: [PATCH 202/213] Bug 538324 - Move ctypes into js/src. Part 2: Use Vector classes instead of nsTArray/ns*String. r=benjamn --- js/src/ctypes/CTypes.cpp | 506 +++++++++++++++++++------------------- js/src/ctypes/CTypes.h | 174 ++++++++++++- js/src/ctypes/Library.cpp | 2 +- js/src/ctypes/Library.h | 4 +- 4 files changed, 430 insertions(+), 256 deletions(-) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 0c846cec29f9..e31f3176d787 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -36,12 +36,8 @@ * * ***** END LICENSE BLOCK ***** */ -#include "jscntxt.h" #include "CTypes.h" #include "Library.h" -#include "nsAutoPtr.h" -#include "nsUTF8Utils.h" -#include "nsCRTGlue.h" #include "prlog.h" #include "jsdtoa.h" @@ -58,7 +54,7 @@ #include #endif -namespace mozilla { +namespace js { namespace ctypes { /******************************************************************************* @@ -447,20 +443,9 @@ ASSERT_OK(JSBool ok) } JS_ALWAYS_INLINE JSString* -NewUCString(JSContext* cx, const nsString& from) +NewUCString(JSContext* cx, const AutoString& from) { - JS_ASSERT(from.get()); - return JS_NewUCStringCopyN(cx, - reinterpret_cast(from.get()), from.Length()); -} - -JS_ALWAYS_INLINE const nsDependentString -GetString(JSString* str) -{ - JS_ASSERT(str); - const jschar* chars = JS_GetStringChars(str); - size_t length = JS_GetStringLength(str); - return nsDependentString(reinterpret_cast(chars), length); + return JS_NewUCStringCopyN(cx, from.begin(), from.length()); } JS_ALWAYS_INLINE size_t @@ -1312,13 +1297,14 @@ jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result) } template -nsAutoString -IntegerToString(IntegerType i, jsuint radix) +void +IntegerToString(IntegerType i, jsuint radix, AutoString& result) { // The buffer must be big enough for all the bits of IntegerType to fit, // in base-2, including '-'. - PRUnichar buffer[sizeof(IntegerType) * 8 + 1]; - PRUnichar* cp = buffer + sizeof(buffer) / sizeof(PRUnichar); + jschar buffer[sizeof(IntegerType) * 8 + 1]; + jschar* end = buffer + sizeof(buffer) / sizeof(jschar); + jschar* cp = end; // Build the string in reverse. We use multiplication and subtraction // instead of modulus because that's much faster. @@ -1335,7 +1321,7 @@ IntegerToString(IntegerType i, jsuint radix) *--cp = '-'; JS_ASSERT(cp >= buffer); - return nsAutoString(cp, buffer + sizeof(buffer) / sizeof(PRUnichar) - cp); + result.append(cp, end); } template @@ -1768,7 +1754,7 @@ ImplicitConvert(JSContext* cx, // Convert into an intermediate, in case of failure. size_t elementSize = CType::GetSize(cx, baseType); size_t arraySize = elementSize * targetLength; - nsAutoArrayPtr intermediate(new char[arraySize]); + AutoPtr::Array intermediate(new char[arraySize]); if (!intermediate) { JS_ReportAllocationOverflow(cx); return false; @@ -1779,12 +1765,12 @@ ImplicitConvert(JSContext* cx, if (!JS_GetElement(cx, sourceArray, i, item.addr())) return false; - char* data = intermediate + elementSize * i; + char* data = intermediate.get() + elementSize * i; if (!ImplicitConvert(cx, item.value(), baseType, data, false, NULL)) return false; } - memcpy(buffer, intermediate, arraySize); + memcpy(buffer, intermediate.get(), arraySize); } else { // Don't implicitly convert to string. Users can implicitly convert @@ -1795,8 +1781,6 @@ ImplicitConvert(JSContext* cx, } case TYPE_struct: { if (!JSVAL_IS_PRIMITIVE(val) && !sourceData) { - nsTArray* fields = StructType::GetFieldInfo(cx, targetType); - // Enumerate the properties of the object; if they match the struct // specification, convert the fields. JSObject* obj = JSVAL_TO_OBJECT(val); @@ -1807,14 +1791,14 @@ ImplicitConvert(JSContext* cx, // Convert into an intermediate, in case of failure. size_t structSize = CType::GetSize(cx, targetType); - nsAutoArrayPtr intermediate(new char[structSize]); + AutoPtr::Array intermediate(new char[structSize]); if (!intermediate) { JS_ReportAllocationOverflow(cx); return false; } jsid id; - jsuint i = 0; + size_t i = 0; while (1) { if (!JS_NextProperty(cx, iter, &id)) return false; @@ -1843,19 +1827,20 @@ ImplicitConvert(JSContext* cx, return false; // Convert the field via ImplicitConvert(). - char* fieldData = intermediate + field->mOffset; + char* fieldData = intermediate.get() + field->mOffset; if (!ImplicitConvert(cx, prop.value(), field->mType, fieldData, false, NULL)) return false; ++i; } - if (i != fields->Length()) { + Array* fields = StructType::GetFieldInfo(cx, targetType); + if (i != fields->length()) { JS_ReportError(cx, "missing fields"); return false; } - memcpy(buffer, intermediate, structSize); + memcpy(buffer, intermediate.get(), structSize); break; } @@ -1952,16 +1937,17 @@ ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer) // corresponding to 'typeObj'. For instance, the CType constructed from // 'ctypes.int32_t.ptr.array(4).ptr.ptr' will result in the type string // 'int32_t*(**)[4]'. -static nsAutoString +static JSString* BuildTypeName(JSContext* cx, JSObject* typeObj) { + AutoString result; + // Walk the hierarchy of types, outermost to innermost, building up the type // string. This consists of the base type, which goes on the left. // Derived type modifiers (* and []) build from the inside outward, with // pointers on the left and arrays on the right. An excellent description // of the rules for building C type declarations can be found at: // http://unixwiz.net/techtips/reading-cdecl.html - nsAutoString result; JSObject* currentType = typeObj; JSObject* nextType; TypeCode prevGrouping = CType::GetTypeCode(cx, currentType), currentGrouping; @@ -1976,7 +1962,7 @@ BuildTypeName(JSContext* cx, JSObject* typeObj) } // Pointer types go on the left. - result.Insert('*', 0); + PrependString(result, "*"); currentType = nextType; prevGrouping = currentGrouping; @@ -1985,17 +1971,17 @@ BuildTypeName(JSContext* cx, JSObject* typeObj) case TYPE_array: { if (prevGrouping == TYPE_pointer) { // Outer type is pointer, inner type is array. Grouping is required. - result.Insert('(', 0); - result.Append(')'); - } + PrependString(result, "("); + AppendString(result, ")"); + } // Array types go on the right. - result.Append('['); + AppendString(result, "["); size_t length; - if (ArrayType::GetSafeLength(cx, currentType, &length)) { - result.Append(IntegerToString(length, 10)); - } - result.Append(']'); + if (ArrayType::GetSafeLength(cx, currentType, &length)) + IntegerToString(length, 10, result); + + AppendString(result, "]"); currentType = ArrayType::GetBaseType(cx, currentType); prevGrouping = currentGrouping; @@ -2005,28 +1991,28 @@ BuildTypeName(JSContext* cx, JSObject* typeObj) FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, currentType); // Function pointer goes on the left. - result.Insert('*', 0); + PrependString(result, "*"); // Add in the calling convention, if it's not cdecl. if (GetABICode(cx, fninfo->mABI) == ABI_STDCALL) - result.Insert(NS_LITERAL_STRING("__stdcall "), 0); + PrependString(result, "__stdcall "); // Wrap the entire expression so far with parens. - result.Insert('(', 0); - result.Append(')'); + PrependString(result, "("); + AppendString(result, ")"); // Argument list goes on the right. - result.Append('('); - for (PRUint32 i = 0; i < fninfo->mArgTypes.Length(); ++i) { + AppendString(result, "("); + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) { JSString* argName = CType::GetName(cx, fninfo->mArgTypes[i]); - result.Append(GetString(argName)); - if (i != fninfo->mArgTypes.Length() - 1 || + AppendString(result, argName); + if (i != fninfo->mArgTypes.length() - 1 || fninfo->mIsVariadic) - result.Append(NS_LITERAL_STRING(", ")); + AppendString(result, ", "); } if (fninfo->mIsVariadic) - result.Append(NS_LITERAL_STRING("...")); - result.Append(')'); + AppendString(result, "..."); + AppendString(result, ")"); // Set 'currentType' to the return type, and let the loop process it. currentType = fninfo->mReturnType; @@ -2042,8 +2028,8 @@ BuildTypeName(JSContext* cx, JSObject* typeObj) // Stick the base type and derived type parts together. JSString* baseName = CType::GetName(cx, currentType); - result.Insert(GetString(baseName), 0); - return result; + PrependString(result, baseName); + return NewUCString(cx, result); } // Given a CType 'typeObj', generate a string 'result' such that 'eval(result)' @@ -2053,55 +2039,57 @@ BuildTypeName(JSContext* cx, JSObject* typeObj) // (This means the type comparison function CType::TypesEqual will return true // when comparing the input and output of BuildTypeSource, since struct // equality is determined by strict JSObject pointer equality.) -static nsAutoString -BuildTypeSource(JSContext* cx, JSObject* typeObj, bool makeShort) +static void +BuildTypeSource(JSContext* cx, + JSObject* typeObj, + bool makeShort, + AutoString& result) { // Walk the types, building up the toSource() string. - nsAutoString result; switch (CType::GetTypeCode(cx, typeObj)) { case TYPE_void_t: #define DEFINE_TYPE(name, type, ffiType) \ case TYPE_##name: #include "typedefs.h" { - result.Append(NS_LITERAL_STRING("ctypes.")); + AppendString(result, "ctypes."); JSString* nameStr = CType::GetName(cx, typeObj); - result.Append(GetString(nameStr)); + AppendString(result, nameStr); break; } case TYPE_pointer: { JSObject* baseType = PointerType::GetBaseType(cx, typeObj); if (!baseType) { // Opaque pointer type. Use the type's name. - result.Append(NS_LITERAL_STRING("ctypes.PointerType(\"")); + AppendString(result, "ctypes.PointerType(\""); JSString* baseName = CType::GetName(cx, typeObj); - result.Append(GetString(baseName)); - result.Append(NS_LITERAL_STRING("\")")); + AppendString(result, baseName); + AppendString(result, "\")"); break; } // Specialcase ctypes.voidptr_t. if (CType::GetTypeCode(cx, baseType) == TYPE_void_t) { - result.Append(NS_LITERAL_STRING("ctypes.voidptr_t")); + AppendString(result, "ctypes.voidptr_t"); break; } // Recursively build the source string, and append '.ptr'. - result.Append(BuildTypeSource(cx, baseType, makeShort)); - result.Append(NS_LITERAL_STRING(".ptr")); + BuildTypeSource(cx, baseType, makeShort, result); + AppendString(result, ".ptr"); break; } case TYPE_function: { FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); - result.Append(NS_LITERAL_STRING("ctypes.FunctionType(")); + AppendString(result, "ctypes.FunctionType("); switch (GetABICode(cx, fninfo->mABI)) { case ABI_DEFAULT: - result.Append(NS_LITERAL_STRING("ctypes.default_abi, ")); + AppendString(result, "ctypes.default_abi, "); break; case ABI_STDCALL: - result.Append(NS_LITERAL_STRING("ctypes.stdcall_abi, ")); + AppendString(result, "ctypes.stdcall_abi, "); break; case INVALID_ABI: JS_NOT_REACHED("invalid abi"); @@ -2110,22 +2098,22 @@ BuildTypeSource(JSContext* cx, JSObject* typeObj, bool makeShort) // Recursively build the source string describing the function return and // argument types. - result.Append(BuildTypeSource(cx, fninfo->mReturnType, true)); + BuildTypeSource(cx, fninfo->mReturnType, true, result); - if (fninfo->mArgTypes.Length() > 0) { - result.Append(NS_LITERAL_STRING(", [")); - for (PRUint32 i = 0; i < fninfo->mArgTypes.Length(); ++i) { - result.Append(BuildTypeSource(cx, fninfo->mArgTypes[i], true)); - if (i != fninfo->mArgTypes.Length() - 1 || + if (fninfo->mArgTypes.length() > 0) { + AppendString(result, ", ["); + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) { + BuildTypeSource(cx, fninfo->mArgTypes[i], true, result); + if (i != fninfo->mArgTypes.length() - 1 || fninfo->mIsVariadic) - result.Append(NS_LITERAL_STRING(", ")); + AppendString(result, ", "); } if (fninfo->mIsVariadic) - result.Append(NS_LITERAL_STRING("\"...\"")); - result.Append(']'); + AppendString(result, "\"...\""); + AppendString(result, "]"); } - result.Append(')'); + AppendString(result, ")"); break; } case TYPE_array: { @@ -2133,14 +2121,14 @@ BuildTypeSource(JSContext* cx, JSObject* typeObj, bool makeShort) // where n is the array length, or the empty string if the array length // is undefined. JSObject* baseType = ArrayType::GetBaseType(cx, typeObj); - result.Append(BuildTypeSource(cx, baseType, makeShort)); - result.Append(NS_LITERAL_STRING(".array(")); + BuildTypeSource(cx, baseType, makeShort, result); + AppendString(result, ".array("); size_t length; if (ArrayType::GetSafeLength(cx, typeObj, &length)) - result.Append(IntegerToString(length, 10)); + IntegerToString(length, 10, result); - result.Append(')'); + AppendString(result, ")"); break; } case TYPE_struct: { @@ -2149,33 +2137,31 @@ BuildTypeSource(JSContext* cx, JSObject* typeObj, bool makeShort) if (makeShort) { // Shorten the type declaration by assuming that StructType 't' is bound // to an in-scope variable of name 't.name'. - result.Append(GetString(name)); + AppendString(result, name); break; } // Write the full struct declaration. - result.Append(NS_LITERAL_STRING("ctypes.StructType(\"")); - result.Append(GetString(name)); - result.Append(NS_LITERAL_STRING("\", [")); + AppendString(result, "ctypes.StructType(\""); + AppendString(result, name); + AppendString(result, "\", ["); - nsTArray* fields = StructType::GetFieldInfo(cx, typeObj); - for (PRUint32 i = 0; i < fields->Length(); ++i) { - const FieldInfo& field = fields->ElementAt(i); - result.Append(NS_LITERAL_STRING("{ \"")); - result.Append(field.mName); - result.Append(NS_LITERAL_STRING("\": ")); - result.Append(BuildTypeSource(cx, field.mType, true)); - result.Append(NS_LITERAL_STRING(" }")); - if (i != fields->Length() - 1) - result.Append(NS_LITERAL_STRING(", ")); + Array* fields = StructType::GetFieldInfo(cx, typeObj); + for (size_t i = 0; i < fields->length(); ++i) { + FieldInfo* field = fields->begin() + i; + AppendString(result, "{ \""); + AppendString(result, field->mName); + AppendString(result, "\": "); + BuildTypeSource(cx, field->mType, true, result); + AppendString(result, " }"); + if (i != fields->length() - 1) + AppendString(result, ", "); } - result.Append(NS_LITERAL_STRING("])")); + AppendString(result, "])"); break; } } - - return result; } // Given a CData object of CType 'typeObj' with binary value 'data', generate a @@ -2188,63 +2174,69 @@ BuildTypeSource(JSContext* cx, JSObject* typeObj, bool makeShort) // resulting string can ImplicitConvert successfully if passed to another data // constructor. (This is important when called recursively, since fields of // structs and arrays are converted with ImplicitConvert.) -static nsAutoString -BuildDataSource(JSContext* cx, JSObject* typeObj, void* data, bool isImplicit) +static JSBool +BuildDataSource(JSContext* cx, + JSObject* typeObj, + void* data, + bool isImplicit, + AutoString& result) { - nsAutoString result; TypeCode type = CType::GetTypeCode(cx, typeObj); switch (type) { case TYPE_bool: - result.Append(*static_cast(data) ? - NS_LITERAL_STRING("true") : - NS_LITERAL_STRING("false")); + if (*static_cast(data)) + AppendString(result, "true"); + else + AppendString(result, "false"); break; #define DEFINE_INT_TYPE(name, type, ffiType) \ case TYPE_##name: \ /* Serialize as a primitive decimal integer. */ \ - result.Append(IntegerToString(*static_cast(data), 10)); \ + IntegerToString(*static_cast(data), 10, result); \ break; #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType) \ case TYPE_##name: \ /* Serialize as a wrapped decimal integer. */ \ if (IsUnsigned()) \ - result.Append(NS_LITERAL_STRING("ctypes.UInt64(\"")); \ + AppendString(result, "ctypes.UInt64(\""); \ else \ - result.Append(NS_LITERAL_STRING("ctypes.Int64(\"")); \ + AppendString(result, "ctypes.Int64(\""); \ \ - result.Append(IntegerToString(*static_cast(data), 10)); \ - result.Append(NS_LITERAL_STRING("\")")); \ + IntegerToString(*static_cast(data), 10, result); \ + AppendString(result, "\")"); \ break; #define DEFINE_FLOAT_TYPE(name, type, ffiType) \ case TYPE_##name: { \ /* Serialize as a primitive double. */ \ double fp = *static_cast(data); \ char buf[DTOSTR_STANDARD_BUFFER_SIZE]; \ - char* str = JS_dtostr(buf, sizeof(buf), DTOSTR_STANDARD, 0, fp); \ + char* str = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof(buf), \ + DTOSTR_STANDARD, 0, fp); \ JS_ASSERT(str); \ if (!str) \ break; \ \ - result.AppendASCII(str); \ + result.append(str, strlen(str)); \ break; \ } #define DEFINE_CHAR_TYPE(name, type, ffiType) \ case TYPE_##name: \ /* Serialize as an integer. */ \ - result.Append(IntegerToString(*static_cast(data), 10)); \ + IntegerToString(*static_cast(data), 10, result); \ break; #include "typedefs.h" case TYPE_jschar: { - /* Serialize as a 1-character JS string. */ + // Serialize as a 1-character JS string. JSString* str = JS_NewUCStringCopyN(cx, static_cast(data), 1); if (!str) - break; + return false; + // Escape characters, and quote as necessary. JSString* src = JS_ValueToSource(cx, STRING_TO_JSVAL(str)); if (!src) - break; + return false; - result.Append(GetString(src)); + AppendString(result, src); break; } case TYPE_pointer: @@ -2252,18 +2244,18 @@ BuildDataSource(JSContext* cx, JSObject* typeObj, void* data, bool isImplicit) if (isImplicit) { // The result must be able to ImplicitConvert successfully. // Wrap in a type constructor, then serialize for ExplicitConvert. - result.Append(BuildTypeSource(cx, typeObj, true)); - result.Append('('); + BuildTypeSource(cx, typeObj, true, result); + AppendString(result, "("); } // Serialize the pointer value as a wrapped hexadecimal integer. uintptr_t ptr = *static_cast(data); - result.Append(NS_LITERAL_STRING("ctypes.UInt64(\"0x")); - result.Append(IntegerToString(ptr, 16)); - result.Append(NS_LITERAL_STRING("\")")); + AppendString(result, "ctypes.UInt64(\"0x"); + IntegerToString(ptr, 16, result); + AppendString(result, "\")"); if (isImplicit) - result.Append(')'); + AppendString(result, ")"); break; } @@ -2271,17 +2263,19 @@ BuildDataSource(JSContext* cx, JSObject* typeObj, void* data, bool isImplicit) // Serialize each element of the array recursively. Each element must // be able to ImplicitConvert successfully. JSObject* baseType = ArrayType::GetBaseType(cx, typeObj); - result.Append('['); + AppendString(result, "["); size_t length = ArrayType::GetLength(cx, typeObj); size_t elementSize = CType::GetSize(cx, baseType); for (size_t i = 0; i < length; ++i) { char* element = static_cast(data) + elementSize * i; - result.Append(BuildDataSource(cx, baseType, element, true)); + if (!BuildDataSource(cx, baseType, element, true, result)) + return false; + if (i + 1 < length) - result.Append(NS_LITERAL_STRING(", ")); + AppendString(result, ", "); } - result.Append(']'); + AppendString(result, "]"); break; } case TYPE_struct: { @@ -2289,29 +2283,31 @@ BuildDataSource(JSContext* cx, JSObject* typeObj, void* data, bool isImplicit) // The result must be able to ImplicitConvert successfully. // Serialize the data as an object with properties, rather than // a sequence of arguments to the StructType constructor. - result.Append('{'); + AppendString(result, "{"); } // Serialize each field of the struct recursively. Each field must // be able to ImplicitConvert successfully. - nsTArray* fields = StructType::GetFieldInfo(cx, typeObj); - for (size_t i = 0; i < fields->Length(); ++i) { - const FieldInfo& field = fields->ElementAt(i); - char* fieldData = static_cast(data) + field.mOffset; + Array* fields = StructType::GetFieldInfo(cx, typeObj); + for (size_t i = 0; i < fields->length(); ++i) { + FieldInfo* field = fields->begin() + i; + char* fieldData = static_cast(data) + field->mOffset; if (isImplicit) { - result.Append('"'); - result.Append(field.mName); - result.Append(NS_LITERAL_STRING("\": ")); + AppendString(result, "\""); + AppendString(result, field->mName); + AppendString(result, "\": "); } - result.Append(BuildDataSource(cx, field.mType, fieldData, true)); - if (i + 1 != fields->Length()) - result.Append(NS_LITERAL_STRING(", ")); + if (!BuildDataSource(cx, field->mType, fieldData, true, result)) + return false; + + if (i + 1 != fields->length()) + AppendString(result, ", "); } if (isImplicit) - result.Append('}'); + AppendString(result, "}"); break; } @@ -2320,7 +2316,7 @@ BuildDataSource(JSContext* cx, JSObject* typeObj, void* data, bool isImplicit) break; } - return result; + return true; } /******************************************************************************* @@ -2537,8 +2533,10 @@ CType::Finalize(JSContext* cx, JSObject* obj) case TYPE_struct: // Free the FieldInfo array. ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); - if (!JSVAL_IS_VOID(slot)) - delete static_cast*>(JSVAL_TO_PRIVATE(slot)); + if (!JSVAL_IS_VOID(slot)) { + void* info = JSVAL_TO_PRIVATE(slot); + delete static_cast*>(info); + } // Fall through. case TYPE_array: { @@ -2598,7 +2596,7 @@ CType::Trace(JSTracer* trc, JSObject* obj) // Identify our objects to the tracer. JS_CALL_TRACER(trc, fninfo->mABI, JSTRACE_OBJECT, "abi"); JS_CALL_TRACER(trc, fninfo->mReturnType, JSTRACE_OBJECT, "returnType"); - for (PRUint32 i = 0; i < fninfo->mArgTypes.Length(); ++i) + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) JS_CALL_TRACER(trc, fninfo->mArgTypes[i], JSTRACE_OBJECT, "argType"); break; @@ -2668,13 +2666,13 @@ CType::TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2) if (!TypesEqual(cx, f1->mReturnType, f2->mReturnType)) return false; - if (f1->mArgTypes.Length() != f2->mArgTypes.Length()) + if (f1->mArgTypes.length() != f2->mArgTypes.length()) return false; if (f1->mIsVariadic != f2->mIsVariadic) return false; - for (PRUint32 i = 0; i < f1->mArgTypes.Length(); ++i) { + for (size_t i = 0; i < f1->mArgTypes.length(); ++i) { if (!TypesEqual(cx, f1->mArgTypes[i], f2->mArgTypes[i])) return false; } @@ -2923,9 +2921,9 @@ CType::ToString(JSContext* cx, uintN argc, jsval *vp) return JS_FALSE; } - nsAutoString type(NS_LITERAL_STRING("type ")); - JSString* right = GetName(cx, obj); - type.Append(GetString(right)); + AutoString type; + AppendString(type, "type "); + AppendString(type, GetName(cx, obj)); JSString* result = NewUCString(cx, type); if (!result) @@ -2946,7 +2944,8 @@ CType::ToSource(JSContext* cx, uintN argc, jsval *vp) return JS_FALSE; } - nsAutoString source = BuildTypeSource(cx, obj, false); + AutoString source; + BuildTypeSource(cx, obj, false, source); JSString* result = NewUCString(cx, source); if (!result) return JS_FALSE; @@ -3062,8 +3061,7 @@ PointerType::CreateInternal(JSContext* cx, if (baseType) { // Determine the name of the PointerType, since it wasn't supplied. - nsAutoString typeName = BuildTypeName(cx, typeObj); - JSString* nameStr = NewUCString(cx, typeName); + JSString* nameStr = BuildTypeName(cx, typeObj); if (!nameStr || !JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(nameStr))) return NULL; @@ -3358,8 +3356,7 @@ ArrayType::CreateInternal(JSContext* cx, return NULL; // Determine the name of the ArrayType. - nsAutoString typeName = BuildTypeName(cx, typeObj); - JSString* name = NewUCString(cx, typeName); + JSString* name = BuildTypeName(cx, typeObj); if (!name || !JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(name))) return NULL; @@ -3718,11 +3715,12 @@ ExtractStructField(JSContext* cx, jsval val, FieldInfo* field) } JSString* name = JSVAL_TO_STRING(nameVal.value()); - const jschar* nameChars = JS_GetStringChars(name); - size_t namelen = JS_GetStringLength(name); - field->mName.Assign(reinterpret_cast(nameChars), namelen); + field->mName.clear(); + AppendString(field->mName, name); js::AutoValueRooter propVal(cx); + const jschar* nameChars = JS_GetStringChars(name); + size_t namelen = JS_GetStringLength(name); if (!JS_GetUCProperty(cx, obj, nameChars, namelen, propVal.addr())) return false; @@ -3751,7 +3749,7 @@ static JSBool AddFieldToArray(JSContext* cx, JSObject* arrayObj, jsval* element, - const nsString& name, + const String& name, JSObject* typeObj) { JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, arrayObj); @@ -3761,7 +3759,7 @@ AddFieldToArray(JSContext* cx, *element = OBJECT_TO_JSVAL(fieldObj); if (!JS_DefineUCProperty(cx, fieldObj, - reinterpret_cast(name.get()), name.Length(), + name.begin(), name.length(), OBJECT_TO_JSVAL(typeObj), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) return false; @@ -3804,7 +3802,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) js::AutoValueRooter root(cx, fieldsProp); JS_ASSERT(len == 0 || fieldsVec); - nsAutoPtr ffiType(new ffi_type); + AutoPtr ffiType(new ffi_type); if (!ffiType) { JS_ReportOutOfMemory(cx); return JS_FALSE; @@ -3814,15 +3812,16 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) // Create an array of FieldInfo objects to stash on the type object, and an // array of PropertySpecs to reflect the struct fields as properties // on CData objects created from this type. - nsAutoPtr< nsTArray > fields(new nsTArray()); - nsAutoTArray instanceProps; + AutoPtr< Array > fields(new Array); + Array instanceProps; if (!fields || - !fields->SetCapacity(len) || - !instanceProps.SetCapacity(len + 1)) { + !fields->resize(len) || + !instanceProps.resize(len + 1)) { JS_ReportOutOfMemory(cx); return JS_FALSE; } - nsAutoArrayPtr elements; + + AutoPtr::Array elements; // Process the field types and fill in the ffi_type fields. size_t structSize = 0, structAlign = 0; @@ -3839,13 +3838,14 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) if (!JS_GetElement(cx, fieldsObj, i, item.addr())) return JS_FALSE; - FieldInfo* info = fields->AppendElement(); + FieldInfo* info = fields->begin() + i; if (!ExtractStructField(cx, item.value(), info)) return JS_FALSE; // Make sure each field name is unique. - for (PRUint32 j = 0; j < fields->Length() - 1; ++j) { - if (fields->ElementAt(j).mName == info->mName) { + for (size_t j = 0; j < i; ++j) { + FieldInfo* field = fields->begin() + j; + if (StringsEqual(field->mName, info->mName)) { JS_ReportError(cx, "struct fields must have unique names"); return JS_FALSE; } @@ -3857,9 +3857,9 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; // Fill in the PropertySpec for the field. - PropertySpec* instanceProp = instanceProps.AppendElement(); - instanceProp->name = reinterpret_cast(info->mName.get()); - instanceProp->namelen = info->mName.Length(); + PropertySpec* instanceProp = instanceProps.begin() + i; + instanceProp->name = info->mName.begin(); + instanceProp->namelen = info->mName.length(); instanceProp->flags = JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT; instanceProp->getter = StructType::FieldGetter; instanceProp->setter = StructType::FieldSetter; @@ -3907,7 +3907,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) elements[1] = NULL; } - ffiType->elements = elements; + ffiType->elements = elements.get(); #ifdef DEBUG // Perform a sanity check: the result of our struct size and alignment @@ -3916,7 +3916,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) ffi_cif cif; ffiType->size = 0; ffiType->alignment = 0; - ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType, NULL); + ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType.get(), NULL); JS_ASSERT(status == FFI_OK); JS_ASSERT(structSize == ffiType->size); JS_ASSERT(structAlign == ffiType->alignment); @@ -3930,7 +3930,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) #endif // Terminate the PropertySpec array. - instanceProps.AppendElement()->name = NULL; + instanceProps[len].name = NULL; jsval sizeVal; if (!SizeTojsval(cx, structSize, &sizeVal)) @@ -3945,8 +3945,8 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) // Create a new CType object with the common properties and slots. JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_struct, JSVAL_TO_STRING(name), sizeVal, - INT_TO_JSVAL(structAlign), ffiType, - instanceProps.Elements()); + INT_TO_JSVAL(structAlign), ffiType.get(), + instanceProps.begin()); if (!typeObj) return JS_FALSE; ffiType.forget(); @@ -3991,7 +3991,7 @@ StructType::ConstructData(JSContext* cx, return JS_TRUE; char* buffer = static_cast(CData::GetData(cx, result)); - nsTArray* fields = GetFieldInfo(cx, obj); + Array* fields = GetFieldInfo(cx, obj); if (argc == 1) { // There are two possible interpretations of the argument: @@ -4006,7 +4006,7 @@ StructType::ConstructData(JSContext* cx, if (ExplicitConvert(cx, argv[0], obj, buffer)) return JS_TRUE; - if (fields->Length() != 1) + if (fields->length() != 1) return JS_FALSE; // If ExplicitConvert failed, and there is no pending exception, then assume @@ -4023,10 +4023,10 @@ StructType::ConstructData(JSContext* cx, // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'. // ImplicitConvert each field. - if (argc == fields->Length()) { - for (PRUint32 i = 0; i < fields->Length(); ++i) { - FieldInfo& field = fields->ElementAt(i); - if (!ImplicitConvert(cx, argv[i], field.mType, buffer + field.mOffset, + if (argc == fields->length()) { + for (size_t i = 0; i < fields->length(); ++i) { + FieldInfo* field = fields->begin() + i; + if (!ImplicitConvert(cx, argv[i], field->mType, buffer + field->mOffset, false, NULL)) return JS_FALSE; } @@ -4035,11 +4035,11 @@ StructType::ConstructData(JSContext* cx, } JS_ReportError(cx, "constructor takes 0, 1, or %u arguments", - fields->Length()); + fields->length()); return JS_FALSE; } -nsTArray* +Array* StructType::GetFieldInfo(JSContext* cx, JSObject* obj) { JS_ASSERT(CType::IsCType(cx, obj)); @@ -4049,7 +4049,7 @@ StructType::GetFieldInfo(JSContext* cx, JSObject* obj) ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot)); - return static_cast*>(JSVAL_TO_PRIVATE(slot)); + return static_cast*>(JSVAL_TO_PRIVATE(slot)); } FieldInfo* @@ -4058,18 +4058,20 @@ StructType::LookupField(JSContext* cx, JSObject* obj, jsval idval) JS_ASSERT(CType::IsCType(cx, obj)); JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); - nsTArray* fields = GetFieldInfo(cx, obj); + Array* fields = GetFieldInfo(cx, obj); - JSString* nameStr = JSVAL_TO_STRING(idval); - const nsDependentString name(GetString(nameStr)); - - for (PRUint32 i = 0; i < fields->Length(); ++i) { - if (fields->ElementAt(i).mName.Equals(name)) - return &fields->ElementAt(i); + JSString* name = JSVAL_TO_STRING(idval); + for (size_t i = 0; i < fields->length(); ++i) { + FieldInfo* field = fields->begin() + i; + if (StringsEqual(field->mName, name)) + return field; } - JS_ReportError(cx, "%s does not name a field", - NS_LossyConvertUTF16toASCII(name).get()); + const char* bytes = JS_GetStringBytesZ(cx, name); + if (!bytes) + return NULL; + + JS_ReportError(cx, "%s does not name a field", bytes); return NULL; } @@ -4311,9 +4313,9 @@ PrepareCIF(JSContext* cx, ffi_status status = ffi_prep_cif(&fninfo->mCIF, abi, - fninfo->mFFITypes.Length(), + fninfo->mFFITypes.length(), CType::GetFFIType(cx, fninfo->mReturnType), - fninfo->mFFITypes.Elements()); + fninfo->mFFITypes.begin()); switch (status) { case FFI_OK: @@ -4337,7 +4339,7 @@ NewFunctionInfo(JSContext* cx, jsval* argTypes, uintN argLength) { - nsAutoPtr fninfo(new FunctionInfo()); + AutoPtr fninfo(new FunctionInfo()); if (!fninfo) { JS_ReportOutOfMemory(cx); return NULL; @@ -4351,8 +4353,8 @@ NewFunctionInfo(JSContext* cx, return NULL; // prepare the argument types - if (!fninfo->mArgTypes.SetCapacity(argLength) || - !fninfo->mFFITypes.SetCapacity(argLength)) { + if (!fninfo->mArgTypes.reserve(argLength) || + !fninfo->mFFITypes.reserve(argLength)) { JS_ReportOutOfMemory(cx); return NULL; } @@ -4384,15 +4386,15 @@ NewFunctionInfo(JSContext* cx, if (!argType) return NULL; - fninfo->mArgTypes.AppendElement(argType); - fninfo->mFFITypes.AppendElement(CType::GetFFIType(cx, argType)); + fninfo->mArgTypes.append(argType); + fninfo->mFFITypes.append(CType::GetFFIType(cx, argType)); } if (fninfo->mIsVariadic) // wait to PrepareCIF until function is called return fninfo.forget(); - if (!PrepareCIF(cx, fninfo)) + if (!PrepareCIF(cx, fninfo.get())) return NULL; return fninfo.forget(); @@ -4408,7 +4410,7 @@ FunctionType::Create(JSContext* cx, uintN argc, jsval* vp) } jsval* argv = JS_ARGV(cx, vp); - nsAutoTArray argTypes; + Array argTypes; JSObject* arrayObj = NULL; if (argc == 3) { @@ -4423,7 +4425,7 @@ FunctionType::Create(JSContext* cx, uintN argc, jsval* vp) jsuint len; ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len)); - if (!argTypes.SetLength(len)) { + if (!argTypes.resize(len)) { JS_ReportOutOfMemory(cx); return JS_FALSE; } @@ -4433,15 +4435,15 @@ FunctionType::Create(JSContext* cx, uintN argc, jsval* vp) } // Pull out the argument types from the array, if any. - JS_ASSERT(!argTypes.Length() || arrayObj); - js::AutoArrayRooter items(cx, argTypes.Length(), argTypes.Elements()); - for (jsuint i = 0; i < argTypes.Length(); ++i) { + JS_ASSERT(!argTypes.length() || arrayObj); + js::AutoArrayRooter items(cx, argTypes.length(), argTypes.begin()); + for (jsuint i = 0; i < argTypes.length(); ++i) { if (!JS_GetElement(cx, arrayObj, i, &argTypes[i])) return JS_FALSE; } JSObject* result = CreateInternal(cx, argv[0], argv[1], - argTypes.Elements(), argTypes.Length()); + argTypes.begin(), argTypes.length()); if (!result) return JS_FALSE; @@ -4457,7 +4459,7 @@ FunctionType::CreateInternal(JSContext* cx, jsuint arglen) { // Determine and check the types, and prepare the function CIF. - nsAutoPtr fninfo(NewFunctionInfo(cx, abi, rtype, argtypes, arglen)); + AutoPtr fninfo(NewFunctionInfo(cx, abi, rtype, argtypes, arglen)); if (!fninfo) return NULL; @@ -4484,8 +4486,7 @@ FunctionType::CreateInternal(JSContext* cx, fninfo.forget(); // Determine the name of the FunctionType. - nsAutoString typeName = BuildTypeName(cx, typeObj); - JSString* name = NewUCString(cx, typeName); + JSString* name = BuildTypeName(cx, typeObj); if (!name || !JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(name))) return NULL; @@ -4566,17 +4567,15 @@ FunctionType::ConstructData(JSContext* cx, return JS_FALSE; } -typedef nsAutoTArray AutoValueAutoArray; +typedef Array AutoValueAutoArray; static JSBool ConvertArgument(JSContext* cx, jsval arg, JSObject* type, - AutoValueAutoArray* values, + AutoValue* value, AutoValueAutoArray* strings) { - AutoValue* value = values->AppendElement(); - if (!value->SizeToType(cx, type)) { JS_ReportAllocationOverflow(cx); return false; @@ -4589,7 +4588,11 @@ ConvertArgument(JSContext* cx, if (freePointer) { // ImplicitConvert converted a string for us, which we have to free. // Keep track of it. - strings->AppendElement()->mData = *static_cast(value->mData); + if (!strings->growBy(1)) { + JS_ReportOutOfMemory(cx); + return false; + } + *strings[i].mData = *static_cast(value->mData); } return true; @@ -4616,7 +4619,7 @@ FunctionType::Call(JSContext* cx, } FunctionInfo* fninfo = GetFunctionInfo(cx, typeObj); - PRUint32 argcFixed = fninfo->mArgTypes.Length(); + PRUint32 argcFixed = fninfo->mArgTypes.length(); if ((!fninfo->mIsVariadic && argc != argcFixed) || (fninfo->mIsVariadic && argc < argcFixed)) { @@ -4638,14 +4641,20 @@ FunctionType::Call(JSContext* cx, // prepare the values for each argument AutoValueAutoArray values; AutoValueAutoArray strings; + if (!values.resize(fninfo->mArgTypes.length())) { + JS_ReportOutOfMemory(cx); + return false; + } - for (PRUint32 i = 0; i < argcFixed; ++i) - if (!ConvertArgument(cx, argv[i], fninfo->mArgTypes[i], &values, &strings)) + for (jsuint i = 0; i < argcFixed; ++i) + if (!ConvertArgument(cx, argv[i], fninfo->mArgTypes[i], &values[i], &strings)) return false; if (fninfo->mIsVariadic) { - fninfo->mFFITypes.SetLength(argcFixed); - ASSERT_OK(fninfo->mFFITypes.SetCapacity(argc)); + if (!fninfo->mFFITypes.resize(argc)) { + JS_ReportOutOfMemory(cx); + return false; + } JSObject* obj; // Could reuse obj instead of declaring a second JSObject* type; // JSObject*, but readability would suffer. @@ -4663,11 +4672,11 @@ FunctionType::Call(JSContext* cx, !(type = PrepareType(cx, OBJECT_TO_JSVAL(type))) || // Relying on ImplicitConvert only for the limited purpose of // converting one CType to another (e.g., T[] to T*). - !ConvertArgument(cx, argv[i], type, &values, &strings)) { + !ConvertArgument(cx, argv[i], type, &values[i], &strings)) { // These functions report their own errors. return false; } - fninfo->mFFITypes.AppendElement(CType::GetFFIType(cx, type)); + fninfo->mFFITypes[i] = CType::GetFFIType(cx, type); } if (!PrepareCIF(cx, fninfo)) return false; @@ -4688,7 +4697,7 @@ FunctionType::Call(JSContext* cx, jsrefcount rc = JS_SuspendRequest(cx); ffi_call(&fninfo->mCIF, FFI_FN(fn), returnValue.mData, - reinterpret_cast(values.Elements())); + reinterpret_cast(values.begin())); JS_ResumeRequest(cx, rc); @@ -4732,7 +4741,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v return JS_TRUE; FunctionInfo* fninfo = GetFunctionInfo(cx, obj); - PRUint32 len = fninfo->mArgTypes.Length(); + size_t len = fninfo->mArgTypes.length(); // Prepare a new array. jsval* vec; @@ -4743,7 +4752,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v js::AutoValueRooter argsroot(cx, argTypes); JS_ASSERT(len == 0 || vec); - for (PRUint32 i = 0; i < len; ++i) + for (size_t i = 0; i < len; ++i) vec[i] = OBJECT_TO_JSVAL(fninfo->mArgTypes[i]); // Seal and cache it. @@ -4807,7 +4816,7 @@ CClosure::Create(JSContext* cx, FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); JS_ASSERT(!fninfo->mIsVariadic); - nsAutoPtr cinfo(new ClosureInfo()); + AutoPtr cinfo(new ClosureInfo()); if (!cinfo) { JS_ReportOutOfMemory(cx); return NULL; @@ -4861,7 +4870,7 @@ CClosure::Create(JSContext* cx, } ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF, - CClosure::ClosureStub, cinfo, code); + CClosure::ClosureStub, cinfo.get(), code); if (status != FFI_OK) { ffi_closure_free(cinfo->closure); JS_ReportError(cx, "couldn't create closure - libffi error"); @@ -4951,8 +4960,8 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) js::AutoValueRooter root(cx, cinfo->closureObj); // Set up an array for converted arguments. - nsAutoTArray argv; - if (!argv.SetLength(cif->nargs)) { + Array argv; + if (!argv.resize(cif->nargs)) { JS_ReportOutOfMemory(cx); return; } @@ -4960,7 +4969,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) for (PRUint32 i = 0; i < cif->nargs; ++i) argv[i] = JSVAL_VOID; - js::AutoArrayRooter roots(cx, argv.Length(), argv.Elements()); + js::AutoArrayRooter roots(cx, argv.length(), argv.begin()); for (PRUint32 i = 0; i < cif->nargs; ++i) { // Convert each argument, and have any CData objects created depend on // the existing buffers. @@ -4973,7 +4982,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) // will find an appropriate object to use. jsval rval; if (!JS_CallFunctionValue(cx, thisObj, OBJECT_TO_JSVAL(jsfnObj), cif->nargs, - argv.Elements(), &rval)) + argv.begin(), &rval)) return; // Convert the result. Note that we pass 'isArgument = false', such that @@ -5358,10 +5367,13 @@ CData::ToSource(JSContext* cx, uintN argc, jsval *vp) // 't.array([n])' for arrays; // 'n' for structs, where n = t.name, the struct's name. (We assume this is // bound to a variable in the current scope.) - nsAutoString source = BuildTypeSource(cx, typeObj, true); - source.Append('('); - source.Append(BuildDataSource(cx, typeObj, data, false)); - source.Append(')'); + AutoString source; + BuildTypeSource(cx, typeObj, true, source); + AppendString(source, "("); + if (!BuildDataSource(cx, typeObj, data, false, source)) + return JS_FALSE; + + AppendString(source, ")"); JSString* result = NewUCString(cx, source); if (!result) @@ -5447,11 +5459,11 @@ Int64Base::ToString(JSContext* cx, } } - nsAutoString intString; + AutoString intString; if (isUnsigned) { - intString = IntegerToString(GetInt(cx, obj), radix); + IntegerToString(GetInt(cx, obj), radix, intString); } else { - intString = IntegerToString(static_cast(GetInt(cx, obj)), radix); + IntegerToString(static_cast(GetInt(cx, obj)), radix, intString); } JSString *result = NewUCString(cx, intString); @@ -5475,15 +5487,15 @@ Int64Base::ToSource(JSContext* cx, } // Return a decimal string suitable for constructing the number. - nsAutoString source; + AutoString source; if (isUnsigned) { - source.Append(NS_LITERAL_STRING("ctypes.UInt64(\"")); - source.Append(IntegerToString(GetInt(cx, obj), 10)); + AppendString(source, "ctypes.UInt64(\""); + IntegerToString(GetInt(cx, obj), 10, source); } else { - source.Append(NS_LITERAL_STRING("ctypes.Int64(\"")); - source.Append(IntegerToString(static_cast(GetInt(cx, obj)), 10)); + AppendString(source, "ctypes.Int64(\""); + IntegerToString(static_cast(GetInt(cx, obj)), 10, source); } - source.Append(NS_LITERAL_STRING("\")")); + AppendString(source, "\")"); JSString *result = NewUCString(cx, source); if (!result) diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h index 7215b56514cf..d703fc1415af 100644 --- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -39,15 +39,168 @@ #ifndef CTYPES_H #define CTYPES_H +#include "jscntxt.h" #include "jsapi.h" -#include "nsString.h" -#include "nsTArray.h" #include "prlink.h" #include "ffi.h" -namespace mozilla { +namespace js { namespace ctypes { +/******************************************************************************* +** Utility classes +*******************************************************************************/ + +template +class OperatorDelete +{ +public: + static void destroy(T* ptr) { delete ptr; } +}; + +template +class OperatorArrayDelete +{ +public: + static void destroy(T* ptr) { delete[] ptr; } +}; + +// Class that takes ownership of a pointer T*, and calls operator delete or +// operator delete[] upon destruction. +template > +class AutoPtr { +private: + typedef AutoPtr self_type; + +public: + // An AutoPtr variant that calls operator delete[] instead. + typedef AutoPtr > Array; + + AutoPtr() : mPtr(NULL) { } + explicit AutoPtr(T* ptr) : mPtr(ptr) { } + ~AutoPtr() { DeleteTraits::destroy(mPtr); } + + T* operator->() { return mPtr; } + bool operator!() { return mPtr == NULL; } + T& operator[](size_t i) { return *(mPtr + i); } + // Note: we cannot safely provide an 'operator T*()', since this would allow + // the compiler to perform implicit conversion from one AutoPtr to another + // via the constructor AutoPtr(T*). + + T* get() { return mPtr; } + void set(T* other) { JS_ASSERT(mPtr == NULL); mPtr = other; } + T* forget() { T* result = mPtr; mPtr = NULL; return result; } + + self_type& operator=(T* rhs) { mPtr = rhs; return *this; } + +private: + // Do not allow copy construction or assignment from another AutoPtr. + template AutoPtr(AutoPtr&); + template self_type& operator=(AutoPtr& rhs); + + T* mPtr; +}; + +// Container class for Vector, using SystemAllocPolicy. +template +class Array : public Vector +{ +}; + +// String and AutoString classes, based on Vector. +typedef Vector String; +typedef Vector AutoString; + +// Convenience functions to append, insert, and compare Strings. +template +void +AppendString(Vector &v, const char (&array)[ArrayLength]) +{ + // Don't include the trailing '\0'. + size_t alen = ArrayLength - 1; + size_t vlen = v.length(); + if (!v.resize(vlen + alen)) + return; + + for (size_t i = 0; i < alen; ++i) + v[i + vlen] = array[i]; +} + +template +void +AppendString(Vector &v, Vector &w) +{ + v.append(w.begin(), w.length()); +} + +template +void +AppendString(Vector &v, JSString* str) +{ + JS_ASSERT(str); + const jschar* chars = JS_GetStringChars(str); + size_t length = JS_GetStringLength(str); + v.append(chars, length); +} + +template +void +PrependString(Vector &v, const char (&array)[ArrayLength]) +{ + // Don't include the trailing '\0'. + size_t alen = ArrayLength - 1; + size_t vlen = v.length(); + if (!v.resize(vlen + alen)) + return; + + // Move vector data forward. This is safe since we've already resized. + memmove(v.begin() + alen, v.begin(), vlen * sizeof(T)); + + // Copy data to insert. + for (size_t i = 0; i < alen; ++i) + v[i] = array[i]; +} + +template +void +PrependString(Vector &v, JSString* str) +{ + JS_ASSERT(str); + size_t vlen = v.length(); + size_t alen = JS_GetStringLength(str); + if (!v.resize(vlen + alen)) + return; + + // Move vector data forward. This is safe since we've already resized. + memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar)); + + // Copy data to insert. + memcpy(v.begin(), JS_GetStringChars(str), alen * sizeof(jschar)); +} + +template +bool +StringsEqual(Vector &v, Vector &w) +{ + if (v.length() != w.length()) + return false; + + return memcmp(v.begin(), w.begin(), v.length() * sizeof(T)) == 0; +} + +template +bool +StringsEqual(Vector &v, JSString* str) +{ + JS_ASSERT(str); + size_t length = JS_GetStringLength(str); + if (v.length() != length) + return false; + + const jschar* chars = JS_GetStringChars(str); + return memcmp(v.begin(), chars, length * sizeof(jschar)) == 0; +} + /******************************************************************************* ** Function and struct API definitions *******************************************************************************/ @@ -89,7 +242,14 @@ enum TypeCode { struct FieldInfo { - nsString mName; + // We need to provide a copy constructor because of Vector. + FieldInfo() {} + FieldInfo(const FieldInfo& other) + { + JS_NOT_REACHED("shouldn't be copy constructing FieldInfo"); + } + + String mName; JSObject* mType; size_t mOffset; }; @@ -122,12 +282,12 @@ struct FunctionInfo // A fixed array of known parameter types, excluding any variadic // parameters (if mIsVariadic). - nsTArray mArgTypes; + Array mArgTypes; // A variable array of ffi_type*s corresponding to both known parameter // types and dynamic (variadic) parameter types. Longer than mArgTypes // only if mIsVariadic. - nsTArray mFFITypes; + Array mFFITypes; // Flag indicating whether the function behaves like a C function with // ... as the final formal parameter. @@ -275,7 +435,7 @@ namespace ArrayType { } namespace StructType { - nsTArray* GetFieldInfo(JSContext* cx, JSObject* obj); + Array* GetFieldInfo(JSContext* cx, JSObject* obj); FieldInfo* LookupField(JSContext* cx, JSObject* obj, jsval idval); } diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp index 4bc3977b79bc..4b9adaaacb63 100644 --- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -46,7 +46,7 @@ #include "nsILocalFile.h" #include "nsNativeCharsetUtils.h" -namespace mozilla { +namespace js { namespace ctypes { /******************************************************************************* diff --git a/js/src/ctypes/Library.h b/js/src/ctypes/Library.h index 1c97701f17a3..08d6242a3dbf 100644 --- a/js/src/ctypes/Library.h +++ b/js/src/ctypes/Library.h @@ -40,9 +40,11 @@ #ifndef LIBRARY_H #define LIBRARY_H +#include "jsapi.h" + struct PRLibrary; -namespace mozilla { +namespace js { namespace ctypes { enum LibrarySlot { From 929c0d3f4fc115cb65743efc08d84c03fc54cb26 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:05:30 -0700 Subject: [PATCH 203/213] Bug 538324 - Move ctypes into js/src. Part 3: Split out low-level JS 16-bit <--> 8-bit string conversion functions. r=jorendorff --- js/src/jsstr.cpp | 45 +++++++++++++++++++++++++++++++++++---------- js/src/jsstr.h | 28 +++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 4cbf1fdd4f6b..67c64858f67d 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3515,20 +3515,26 @@ js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars) return bytes; } +size_t +js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars) +{ + if (!js_CStringsAreUTF8) + return nchars; + + return js_GetDeflatedUTF8StringLength(cx, chars, nchars); +} + /* * May be called with null cx through js_GetStringBytes, see below. */ size_t -js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars) +js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, size_t nchars) { size_t nbytes; const jschar *end; uintN c, c2; char buffer[10]; - if (!js_CStringsAreUTF8) - return nchars; - nbytes = nchars; for (end = chars + nchars; chars != end; chars++) { c = *chars; @@ -3566,10 +3572,7 @@ JSBool js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp) { - size_t dstlen, i, origDstlen, utf8Len; - jschar c, c2; - uint32 v; - uint8 utf8buf[6]; + size_t dstlen, i; dstlen = *dstlenp; if (!js_CStringsAreUTF8) { @@ -3588,6 +3591,19 @@ js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen, return JS_TRUE; } + return js_DeflateStringToUTF8Buffer(cx, src, srclen, dst, dstlenp); +} + +JSBool +js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *src, size_t srclen, + char *dst, size_t *dstlenp) +{ + size_t dstlen, i, origDstlen, utf8Len; + jschar c, c2; + uint32 v; + uint8 utf8buf[6]; + + dstlen = *dstlenp; origDstlen = dstlen; while (srclen) { c = *src++; @@ -3644,8 +3660,7 @@ JSBool js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp) { - size_t dstlen, i, origDstlen, offset, j, n; - uint32 v; + size_t dstlen, i; if (!js_CStringsAreUTF8) { if (dst) { @@ -3666,6 +3681,16 @@ js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen, return JS_TRUE; } + return js_InflateUTF8StringToBuffer(cx, src, srclen, dst, dstlenp); +} + +JSBool +js_InflateUTF8StringToBuffer(JSContext *cx, const char *src, size_t srclen, + jschar *dst, size_t *dstlenp) +{ + size_t dstlen, origDstlen, offset, j, n; + uint32 v; + dstlen = dst ? *dstlenp : (size_t) -1; origDstlen = dstlen; offset = 0; diff --git a/js/src/jsstr.h b/js/src/jsstr.h index a11c513801d3..392e1c9f4a5a 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -617,29 +617,51 @@ js_DeflateString(JSContext *cx, const jschar *chars, size_t length); * Inflate bytes to JS chars into a buffer. 'chars' must be large enough for * 'length' jschars. The buffer is NOT null-terminated. The destination length * must be be initialized with the buffer size and will contain on return the - * number of copied chars. + * number of copied chars. Conversion behavior depends on js_CStringsAreUTF8. */ extern JSBool js_InflateStringToBuffer(JSContext *cx, const char *bytes, size_t length, jschar *chars, size_t *charsLength); /* - * Get number of bytes in the deflated sequence of characters. + * Same as js_InflateStringToBuffer, but always treats 'bytes' as UTF-8. + */ +extern JSBool +js_InflateUTF8StringToBuffer(JSContext *cx, const char *bytes, size_t length, + jschar *chars, size_t *charsLength); + +/* + * Get number of bytes in the deflated sequence of characters. Behavior depends + * on js_CStringsAreUTF8. */ extern size_t js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t charsLength); +/* + * Same as js_GetDeflatedStringLength, but always treats the result as UTF-8. + */ +extern size_t +js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, + size_t charsLength); + /* * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for * 'length chars. The buffer is NOT null-terminated. The destination length * must to be initialized with the buffer size and will contain on return the - * number of copied bytes. + * number of copied bytes. Conversion behavior depends on js_CStringsAreUTF8. */ extern JSBool js_DeflateStringToBuffer(JSContext *cx, const jschar *chars, size_t charsLength, char *bytes, size_t *length); +/* + * Same as js_DeflateStringToBuffer, but always treats 'bytes' as UTF-8. + */ +extern JSBool +js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars, + size_t charsLength, char *bytes, size_t *length); + /* * Find or create a deflated string cache entry for str that contains its * characters chopped from Unicode code points into bytes. From a40a83771f20e6913cfdfff4ad23960eaf188272 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:06:15 -0700 Subject: [PATCH 204/213] Bug 538324 - Move ctypes into js/src. Part 4: Use js string conversion functions. r=benjamn --- js/src/ctypes/CTypes.cpp | 81 ++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index e31f3176d787..7f53388a888c 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -1373,21 +1373,6 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result) return true; } -static bool -IsUTF16(const jschar* string, size_t length) -{ - PRBool error; - const PRUnichar* buffer = reinterpret_cast(string); - const PRUnichar* end = buffer + length; - while (buffer != end) { - UTF16CharEnumerator::NextChar(&buffer, end, &error); - if (error) - return false; - } - - return true; -} - template static size_t strnlen(const CharType* begin, size_t max) @@ -1643,21 +1628,22 @@ ImplicitConvert(JSContext* cx, case TYPE_signed_char: case TYPE_unsigned_char: { // Convert from UTF-16 to UTF-8. - if (!IsUTF16(sourceChars, sourceLength)) - return TypeError(cx, "UTF-16 string", val); - - NS_ConvertUTF16toUTF8 converted( - reinterpret_cast(sourceChars), sourceLength); + size_t nbytes = + js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); + if (nbytes == (size_t) -1) + return false; char** charBuffer = static_cast(buffer); - *charBuffer = new char[converted.Length() + 1]; + *charBuffer = new char[nbytes + 1]; if (!*charBuffer) { JS_ReportAllocationOverflow(cx); return false; } + ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength, + *charBuffer, &nbytes)); + (*charBuffer)[nbytes] = 0; *freePointer = true; - memcpy(*charBuffer, converted.get(), converted.Length() + 1); break; } case TYPE_jschar: { @@ -1705,20 +1691,22 @@ ImplicitConvert(JSContext* cx, case TYPE_signed_char: case TYPE_unsigned_char: { // Convert from UTF-16 to UTF-8. - if (!IsUTF16(sourceChars, sourceLength)) - return TypeError(cx, "UTF-16 string", val); + size_t nbytes = + js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); + if (nbytes == (size_t) -1) + return false; - NS_ConvertUTF16toUTF8 converted( - reinterpret_cast(sourceChars), sourceLength); - - if (targetLength < converted.Length()) { + if (targetLength < nbytes) { JS_ReportError(cx, "ArrayType has insufficient length"); return false; } - memcpy(buffer, converted.get(), converted.Length()); - if (targetLength > converted.Length()) - static_cast(buffer)[converted.Length()] = 0; + char* charBuffer = static_cast(buffer); + ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength, + charBuffer, &nbytes)); + + if (targetLength > nbytes) + charBuffer[nbytes] = 0; break; } @@ -3423,14 +3411,12 @@ ArrayType::ConstructData(JSContext* cx, case TYPE_char: case TYPE_signed_char: case TYPE_unsigned_char: { - // Convert from UTF-16 to UTF-8 to determine the length. :( - if (!IsUTF16(sourceChars, sourceLength)) - return TypeError(cx, "UTF-16 string", argv[0]); + // Determine the UTF-8 length. + length = js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); + if (length == (size_t) -1) + return false; - NS_ConvertUTF16toUTF8 converted( - reinterpret_cast(sourceChars), sourceLength); - - length = converted.Length() + 1; + ++length; break; } case TYPE_jschar: @@ -5312,13 +5298,20 @@ CData::ReadString(JSContext* cx, uintN argc, jsval *vp) case TYPE_unsigned_char: { char* bytes = static_cast(data); size_t length = strnlen(bytes, maxLength); - nsDependentCSubstring string(bytes, bytes + length); - if (!IsUTF8(string)) { - JS_ReportError(cx, "not a UTF-8 string"); - return JS_FALSE; - } - result = NewUCString(cx, NS_ConvertUTF8toUTF16(string)); + // Determine the length. + size_t dstlen; + if (!js_InflateUTF8StringToBuffer(cx, bytes, length, NULL, &dstlen)) + return JS_FALSE; + + jschar* dst = + static_cast(JS_malloc(cx, (dstlen + 1) * sizeof(jschar))); + if (!dst) + return JS_FALSE; + + ASSERT_OK(js_InflateUTF8StringToBuffer(cx, bytes, length, dst, &dstlen)); + + result = JS_NewUCString(cx, dst, dstlen); break; } case TYPE_int16_t: From 891c9f8bd3395171ebf9df527f9cee5036e27260 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:07:02 -0700 Subject: [PATCH 205/213] Bug 538324 - Move ctypes into js/src. Part 5: Remove nsILocalFile option, and corresponding XPCOM dependency, for ctypes.open(). r=jorendorff --- js/ctypes/tests/unit/test_jsctypes.js.in | 11 +--- js/src/ctypes/Library.cpp | 76 +++++++++--------------- 2 files changed, 30 insertions(+), 57 deletions(-) diff --git a/js/ctypes/tests/unit/test_jsctypes.js.in b/js/ctypes/tests/unit/test_jsctypes.js.in index 19d799ecb94b..5d1ad135eb7d 100644 --- a/js/ctypes/tests/unit/test_jsctypes.js.in +++ b/js/ctypes/tests/unit/test_jsctypes.js.in @@ -75,8 +75,8 @@ function run_test() // Test ctypes.CType and ctypes.CData are set up correctly. run_abstract_class_tests(); - // open the library with an nsILocalFile - let libfile = do_get_file(CTYPES_TEST_LIB); + // open the library + let libfile = do_get_file(CTYPES_TEST_LIB).path; let library = ctypes.open(libfile); // Make sure we can call a function in the library. @@ -193,11 +193,6 @@ function run_test() run_closure_tests(library); run_variadic_tests(library); - // test the string version of ctypes.open() as well - let libpath = libfile.path; - library = ctypes.open(libpath); - run_void_tests(library); - // test library.close let test_void_t = library.declare("test_void_t_cdecl", ctypes.default_abi, ctypes.void_t); library.close(); @@ -207,7 +202,7 @@ function run_test() }, Error); // test that library functions throw when bound to other objects - library = ctypes.open(libpath); + library = ctypes.open(libfile); let obj = {}; obj.declare = library.declare; do_check_throws(function () { run_void_tests(obj); }, Error); diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp index 4b9adaaacb63..e28ea21c3640 100644 --- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -41,10 +41,7 @@ #include "jscntxt.h" #include "Library.h" #include "CTypes.h" -#include "nsServiceManagerUtils.h" -#include "nsIXPConnect.h" -#include "nsILocalFile.h" -#include "nsNativeCharsetUtils.h" +#include "prlink.h" namespace js { namespace ctypes { @@ -98,56 +95,37 @@ Library::Create(JSContext* cx, jsval aPath) if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions)) return NULL; - nsresult rv; - PRLibrary* library; + if (!JSVAL_IS_STRING(aPath)) { + JS_ReportError(cx, "open takes a string argument"); + return NULL; + } - // get the path argument. we accept either an nsILocalFile or a string path. - // determine which we have... - if (JSVAL_IS_STRING(aPath)) { - const PRUnichar* path = reinterpret_cast( - JS_GetStringCharsZ(cx, JSVAL_TO_STRING(aPath))); - if (!path) - return NULL; - - // We don't use nsILocalFile, because it doesn't use the system search - // rules when resolving library path. - PRLibSpec libSpec; + PRLibSpec libSpec; #ifdef XP_WIN - // On Windows, converting to native charset may corrupt path string. - // So, we have to use Unicode path directly. - libSpec.value.pathname_u = path; - libSpec.type = PR_LibSpec_PathnameU; + // On Windows, converting to native charset may corrupt path string. + // So, we have to use Unicode path directly. + const PRUnichar* path = reinterpret_cast( + JS_GetStringCharsZ(cx, JSVAL_TO_STRING(aPath))); + if (!path) + return NULL; + + libSpec.value.pathname_u = path; + libSpec.type = PR_LibSpec_PathnameU; #else - nsCAutoString nativePath; - NS_CopyUnicodeToNative(nsDependentString(path), nativePath); - libSpec.value.pathname = nativePath.get(); - libSpec.type = PR_LibSpec_Pathname; + // Assume the JS string is not UTF-16, but is in the platform's native + // charset. (This basically means ASCII.) It would be nice to have a + // UTF-16 -> native charset implementation available. :( + const char* path = JS_GetStringBytesZ(cx, JSVAL_TO_STRING(aPath)); + if (!path) + return NULL; + + libSpec.value.pathname = path; + libSpec.type = PR_LibSpec_Pathname; #endif - library = PR_LoadLibraryWithFlags(libSpec, 0); - if (!library) { - JS_ReportError(cx, "couldn't open library"); - return NULL; - } - } else if (!JSVAL_IS_PRIMITIVE(aPath)) { - nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID()); - - nsISupports* file = xpc->GetNativeOfWrapper(cx, JSVAL_TO_OBJECT(aPath)); - nsCOMPtr localFile = do_QueryInterface(file); - if (!localFile) { - JS_ReportError(cx, "open takes a string or nsILocalFile argument"); - return NULL; - } - - rv = localFile->Load(&library); - if (NS_FAILED(rv)) { - JS_ReportError(cx, "couldn't open library"); - return NULL; - } - - } else { - // don't convert the argument - JS_ReportError(cx, "open takes a string or nsIFile argument"); + PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, 0); + if (!library) { + JS_ReportError(cx, "couldn't open library"); return NULL; } From 5f94338df4985e525c42428170d5278569991d36 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:07:41 -0700 Subject: [PATCH 206/213] Bug 538324 - Move ctypes into js/src. Part 6: Add ctypes to JSAPI. r=sayrer --- js/src/ctypes/CTypes.cpp | 33 +++++++++++++++++++++++++++++++++ js/src/jsapi.h | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 7f53388a888c..61869bac9ad6 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -428,6 +428,12 @@ static JSFunctionSpec sUInt64Functions[] = { JS_FS_END }; +static JSFunctionSpec sModuleFunctions[] = { + JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS), + JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS), + JS_FS_END +}; + static inline bool FloatIsFinite(jsdouble f) { #ifdef WIN32 return _finite(f); @@ -882,6 +888,33 @@ InitTypeClasses(JSContext* cx, JSObject* parent) return true; } +JS_BEGIN_EXTERN_C + +JS_PUBLIC_API(JSBool) +JS_InitCTypesClass(JSContext* cx, JSObject* global) +{ + // attach ctypes property to global object + JSObject* ctypes = JS_NewObject(cx, NULL, NULL, NULL); + if (!ctypes) + return false; + + if (!JS_DefineProperty(cx, global, "ctypes", OBJECT_TO_JSVAL(ctypes), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return false; + + if (!InitTypeClasses(cx, ctypes)) + return false; + + // attach API functions + if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions)) + return false; + + // Seal the ctypes object, to prevent modification. + return JS_SealObject(cx, ctypes, JS_FALSE); +} + +JS_END_EXTERN_C + /******************************************************************************* ** Type conversion functions *******************************************************************************/ diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 4704bedf22c7..d6a0cc7e563d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -823,6 +823,15 @@ JS_GetScopeChain(JSContext *cx); extern JS_PUBLIC_API(JSObject *) JS_GetGlobalForObject(JSContext *cx, JSObject *obj); +#ifdef JS_HAS_CTYPES +/* + * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes' + * object will be sealed. + */ +extern JS_PUBLIC_API(JSBool) +JS_InitCTypesClass(JSContext *cx, JSObject *global); +#endif + /* * Macros to hide interpreter stack layout details from a JSFastNative using * its jsval *vp parameter. The stack layout underlying invocation can't change From 694be4b6cbd94f07139744922ad5b73b4c161c57 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:16:06 -0700 Subject: [PATCH 207/213] Bug 538324 - Move ctypes into js/src. Part 7: Remove additional NSPR dependencies. r=benjamn --- js/src/ctypes/CTypes.cpp | 147 +++++++++++++++++++-------------------- js/src/ctypes/CTypes.h | 3 - js/src/ctypes/typedefs.h | 16 ++--- 3 files changed, 79 insertions(+), 87 deletions(-) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 61869bac9ad6..22954a0dec90 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -38,7 +38,6 @@ #include "CTypes.h" #include "Library.h" -#include "prlog.h" #include "jsdtoa.h" #include @@ -169,10 +168,10 @@ namespace CData { // Int64Base provides functions common to Int64 and UInt64. namespace Int64Base { - JSObject* Construct(JSContext* cx, JSObject* proto, PRUint64 data, + JSObject* Construct(JSContext* cx, JSObject* proto, JSUint64 data, bool isUnsigned); - PRUint64 GetInt(JSContext* cx, JSObject* obj); + JSUint64 GetInt(JSContext* cx, JSObject* obj); JSBool ToString(JSContext* cx, JSObject* obj, uintN argc, jsval* vp, bool isUnsigned); @@ -716,7 +715,7 @@ AttachProtos(JSContext* cx, JSObject* proto, JSObject** protos) // For a given 'proto' of [[Class]] "CTypeProto", attach each of the 'protos' // to the appropriate CTypeProtoSlot. (SLOT_UINT64PROTO is the last slot // of [[Class]] "CTypeProto".) - for (PRUint32 i = 0; i <= SLOT_UINT64PROTO; ++i) { + for (JSUint32 i = 0; i <= SLOT_UINT64PROTO; ++i) { if (!JS_SetReservedSlot(cx, proto, i, OBJECT_TO_JSVAL(protos[i]))) return false; } @@ -924,16 +923,15 @@ JS_END_EXTERN_C // autoconverts to a primitive JS number; to support ILP64 architectures, it // would need to autoconvert to an Int64 object instead. Therefore we enforce // this invariant here.) -PR_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4); -PR_STATIC_ASSERT(sizeof(char) == 1); -PR_STATIC_ASSERT(sizeof(short) == 2); -PR_STATIC_ASSERT(sizeof(int) == 4); -PR_STATIC_ASSERT(sizeof(unsigned) == 4); -PR_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8); -PR_STATIC_ASSERT(sizeof(long long) == 8); -PR_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t)); -PR_STATIC_ASSERT(sizeof(float) == 4); -PR_STATIC_ASSERT(sizeof(jschar) == sizeof(PRUnichar)); +JS_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4); +JS_STATIC_ASSERT(sizeof(char) == 1); +JS_STATIC_ASSERT(sizeof(short) == 2); +JS_STATIC_ASSERT(sizeof(int) == 4); +JS_STATIC_ASSERT(sizeof(unsigned) == 4); +JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8); +JS_STATIC_ASSERT(sizeof(long long) == 8); +JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t)); +JS_STATIC_ASSERT(sizeof(float) == 4); template static JS_ALWAYS_INLINE IntegerType @@ -946,12 +944,12 @@ Convert(jsdouble d) // MSVC can't perform double to unsigned __int64 conversion when the // double is greater than 2^63 - 1. Help it along a little. template<> -JS_ALWAYS_INLINE PRUint64 -Convert(jsdouble d) +JS_ALWAYS_INLINE JSUint64 +Convert(jsdouble d) { return d > 0x7fffffffffffffffui64 ? - PRUint64(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 : - PRUint64(d); + JSUint64(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 : + JSUint64(d); } #endif @@ -1066,23 +1064,23 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result) } if (Int64::IsInt64(cx, obj)) { - PRInt64 i = Int64Base::GetInt(cx, obj); + JSInt64 i = Int64Base::GetInt(cx, obj); *result = IntegerType(i); // Make sure the integer fits in IntegerType. if (IsUnsigned() && i < 0) return false; - return PRInt64(*result) == i; + return JSInt64(*result) == i; } if (UInt64::IsUInt64(cx, obj)) { - PRUint64 i = Int64Base::GetInt(cx, obj); + JSUint64 i = Int64Base::GetInt(cx, obj); *result = IntegerType(i); // Make sure the integer fits in IntegerType. if (!IsUnsigned() && *result < 0) return false; - return PRUint64(*result) == i; + return JSUint64(*result) == i; } return false; @@ -1202,23 +1200,23 @@ jsvalToBigInteger(JSContext* cx, // Allow conversion from an Int64 or UInt64 object directly. JSObject* obj = JSVAL_TO_OBJECT(val); if (UInt64::IsUInt64(cx, obj)) { - PRUint64 i = Int64Base::GetInt(cx, obj); + JSUint64 i = Int64Base::GetInt(cx, obj); *result = IntegerType(i); // Make sure the integer fits in IntegerType. if (!IsUnsigned() && *result < 0) return false; - return PRUint64(*result) == i; + return JSUint64(*result) == i; } if (Int64::IsInt64(cx, obj)) { - PRInt64 i = Int64Base::GetInt(cx, obj); + JSInt64 i = Int64Base::GetInt(cx, obj); *result = IntegerType(i); // Make sure the integer fits in IntegerType. if (IsUnsigned() && i < 0) return false; - return PRInt64(*result) == i; + return JSInt64(*result) == i; } } return false; @@ -1264,12 +1262,12 @@ jsvalToIntegerExplicit(JSContext* cx, jsval val, IntegerType* result) // Convert Int64 and UInt64 values by C-style cast. JSObject* obj = JSVAL_TO_OBJECT(val); if (Int64::IsInt64(cx, obj)) { - PRInt64 i = Int64Base::GetInt(cx, obj); + JSInt64 i = Int64Base::GetInt(cx, obj); *result = IntegerType(i); return true; } if (UInt64::IsUInt64(cx, obj)) { - PRUint64 i = Int64Base::GetInt(cx, obj); + JSUint64 i = Int64Base::GetInt(cx, obj); *result = IntegerType(i); return true; } @@ -1308,22 +1306,22 @@ jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result) if (!JSVAL_IS_PRIMITIVE(val)) { JSObject* obj = JSVAL_TO_OBJECT(val); if (Int64::IsInt64(cx, obj)) { - PRInt64 i = Int64Base::GetInt(cx, obj); + JSInt64 i = Int64Base::GetInt(cx, obj); intptr_t p = intptr_t(i); // Make sure the integer fits in the alotted precision. - if (PRInt64(p) != i) + if (JSInt64(p) != i) return false; *result = uintptr_t(p); return true; } if (UInt64::IsUInt64(cx, obj)) { - PRUint64 i = Int64Base::GetInt(cx, obj); + JSUint64 i = Int64Base::GetInt(cx, obj); // Make sure the integer fits in the alotted precision. *result = uintptr_t(i); - return PRUint64(*result) == i; + return JSUint64(*result) == i; } } return false; @@ -1462,14 +1460,14 @@ ConvertToJS(JSContext* cx, #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType) \ case TYPE_##name: { \ /* Return an Int64 or UInt64 object - do not convert to a JS number. */ \ - PRUint64 value; \ + JSUint64 value; \ JSObject* proto; \ if (IsUnsigned()) { \ value = *static_cast(data); \ /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */ \ proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO); \ } else { \ - value = PRInt64(*static_cast(data)); \ + value = JSInt64(*static_cast(data)); \ /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */ \ proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO); \ } \ @@ -2233,9 +2231,10 @@ BuildDataSource(JSContext* cx, char buf[DTOSTR_STANDARD_BUFFER_SIZE]; \ char* str = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof(buf), \ DTOSTR_STANDARD, 0, fp); \ - JS_ASSERT(str); \ - if (!str) \ - break; \ + if (!str) { \ + JS_ReportOutOfMemory(cx); \ + return false; \ + } \ \ result.append(str, strlen(str)); \ break; \ @@ -4380,7 +4379,7 @@ NewFunctionInfo(JSContext* cx, fninfo->mIsVariadic = false; - for (PRUint32 i = 0; i < argLength; ++i) { + for (JSUint32 i = 0; i < argLength; ++i) { if (IsEllipsis(argTypes[i])) { fninfo->mIsVariadic = true; if (i < 1) { @@ -4638,7 +4637,7 @@ FunctionType::Call(JSContext* cx, } FunctionInfo* fninfo = GetFunctionInfo(cx, typeObj); - PRUint32 argcFixed = fninfo->mArgTypes.length(); + JSUint32 argcFixed = fninfo->mArgTypes.length(); if ((!fninfo->mIsVariadic && argc != argcFixed) || (fninfo->mIsVariadic && argc < argcFixed)) { @@ -4678,7 +4677,7 @@ FunctionType::Call(JSContext* cx, JSObject* obj; // Could reuse obj instead of declaring a second JSObject* type; // JSObject*, but readability would suffer. - for (PRUint32 i = argcFixed; i < argc; ++i) { + for (JSUint32 i = argcFixed; i < argc; ++i) { if (JSVAL_IS_PRIMITIVE(argv[i]) || !CData::IsCData(cx, obj = JSVAL_TO_OBJECT(argv[i]))) { // Since we know nothing about the CTypes of the ... arguments, @@ -4875,9 +4874,6 @@ CClosure::Create(JSContext* cx, cinfo->typeObj = typeObj; cinfo->thisObj = thisObj; cinfo->jsfnObj = fnObj; -#ifdef DEBUG - cinfo->thread = PR_GetCurrentThread(); -#endif // Create an ffi_closure object and initialize it. void* code; @@ -4963,10 +4959,9 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) JSObject* thisObj = cinfo->thisObj; JSObject* jsfnObj = cinfo->jsfnObj; -#ifdef DEBUG +#ifdef JS_THREADSAFE // Assert that we're on the thread we were created from. - PRThread* thread = PR_GetCurrentThread(); - JS_ASSERT(thread == cinfo->thread); + JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); #endif JSAutoRequest ar(cx); @@ -4985,11 +4980,11 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) return; } - for (PRUint32 i = 0; i < cif->nargs; ++i) + for (JSUint32 i = 0; i < cif->nargs; ++i) argv[i] = JSVAL_VOID; js::AutoArrayRooter roots(cx, argv.length(), argv.begin()); - for (PRUint32 i = 0; i < cif->nargs; ++i) { + for (JSUint32 i = 0; i < cif->nargs; ++i) { // Convert each argument, and have any CData objects created depend on // the existing buffers. if (!ConvertToJS(cx, fninfo->mArgTypes[i], NULL, args[i], false, false, @@ -5416,7 +5411,7 @@ CData::ToSource(JSContext* cx, uintN argc, jsval *vp) JSObject* Int64Base::Construct(JSContext* cx, JSObject* proto, - PRUint64 data, + JSUint64 data, bool isUnsigned) { JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class; @@ -5426,7 +5421,7 @@ Int64Base::Construct(JSContext* cx, js::AutoValueRooter root(cx, result); // attach the Int64's data - PRUint64* buffer = new PRUint64(data); + JSUint64* buffer = new JSUint64(data); if (!buffer) { JS_ReportOutOfMemory(cx); return NULL; @@ -5450,16 +5445,16 @@ Int64Base::Finalize(JSContext* cx, JSObject* obj) if (!JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot) || JSVAL_IS_VOID(slot)) return; - delete static_cast(JSVAL_TO_PRIVATE(slot)); + delete static_cast(JSVAL_TO_PRIVATE(slot)); } -PRUint64 +JSUint64 Int64Base::GetInt(JSContext* cx, JSObject* obj) { JS_ASSERT(Int64::IsInt64(cx, obj) || UInt64::IsUInt64(cx, obj)); jsval slot; ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot)); - return *static_cast(JSVAL_TO_PRIVATE(slot)); + return *static_cast(JSVAL_TO_PRIVATE(slot)); } JSBool @@ -5489,7 +5484,7 @@ Int64Base::ToString(JSContext* cx, if (isUnsigned) { IntegerToString(GetInt(cx, obj), radix, intString); } else { - IntegerToString(static_cast(GetInt(cx, obj)), radix, intString); + IntegerToString(static_cast(GetInt(cx, obj)), radix, intString); } JSString *result = NewUCString(cx, intString); @@ -5519,7 +5514,7 @@ Int64Base::ToSource(JSContext* cx, IntegerToString(GetInt(cx, obj), 10, source); } else { AppendString(source, "ctypes.Int64(\""); - IntegerToString(static_cast(GetInt(cx, obj)), 10, source); + IntegerToString(static_cast(GetInt(cx, obj)), 10, source); } AppendString(source, "\")"); @@ -5544,7 +5539,7 @@ Int64::Construct(JSContext* cx, return JS_FALSE; } - PRInt64 i; + JSInt64 i; if (!jsvalToBigInteger(cx, argv[0], true, &i)) return TypeError(cx, "int64", argv[0]); @@ -5609,8 +5604,8 @@ Int64::Compare(JSContext* cx, uintN argc, jsval* vp) JSObject* obj1 = JSVAL_TO_OBJECT(argv[0]); JSObject* obj2 = JSVAL_TO_OBJECT(argv[1]); - PRInt64 i1 = Int64Base::GetInt(cx, obj1); - PRInt64 i2 = Int64Base::GetInt(cx, obj2); + JSInt64 i1 = Int64Base::GetInt(cx, obj1); + JSInt64 i2 = Int64Base::GetInt(cx, obj2); if (i1 == i2) JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0)); @@ -5622,7 +5617,7 @@ Int64::Compare(JSContext* cx, uintN argc, jsval* vp) return JS_TRUE; } -#define LO_MASK ((PRUint64(1) << 32) - 1) +#define LO_MASK ((JSUint64(1) << 32) - 1) #define INT64_LO(i) ((i) & LO_MASK) #define INT64_HI(i) ((i) >> 32) @@ -5637,8 +5632,8 @@ Int64::Lo(JSContext* cx, uintN argc, jsval* vp) } JSObject* obj = JSVAL_TO_OBJECT(argv[0]); - PRInt64 u = Int64Base::GetInt(cx, obj); - jsdouble d = PRUint32(INT64_LO(u)); + JSInt64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSUint32(INT64_LO(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -5659,8 +5654,8 @@ Int64::Hi(JSContext* cx, uintN argc, jsval* vp) } JSObject* obj = JSVAL_TO_OBJECT(argv[0]); - PRInt64 u = Int64Base::GetInt(cx, obj); - jsdouble d = PRInt32(INT64_HI(u)); + JSInt64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSInt32(INT64_HI(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -5679,14 +5674,14 @@ Int64::Join(JSContext* cx, uintN argc, jsval* vp) } jsval* argv = JS_ARGV(cx, vp); - PRInt32 hi; - PRUint32 lo; + JSInt32 hi; + JSUint32 lo; if (!jsvalToInteger(cx, argv[0], &hi)) return TypeError(cx, "int32", argv[0]); if (!jsvalToInteger(cx, argv[1], &lo)) return TypeError(cx, "uint32", argv[1]); - PRInt64 i = (PRInt64(hi) << 32) + PRInt64(lo); + JSInt64 i = (JSInt64(hi) << 32) + JSInt64(lo); // Get Int64.prototype from the function's reserved slot. JSObject* callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); @@ -5717,7 +5712,7 @@ UInt64::Construct(JSContext* cx, return JS_FALSE; } - PRUint64 u; + JSUint64 u; if (!jsvalToBigInteger(cx, argv[0], true, &u)) return TypeError(cx, "uint64", argv[0]); @@ -5782,8 +5777,8 @@ UInt64::Compare(JSContext* cx, uintN argc, jsval* vp) JSObject* obj1 = JSVAL_TO_OBJECT(argv[0]); JSObject* obj2 = JSVAL_TO_OBJECT(argv[1]); - PRUint64 u1 = Int64Base::GetInt(cx, obj1); - PRUint64 u2 = Int64Base::GetInt(cx, obj2); + JSUint64 u1 = Int64Base::GetInt(cx, obj1); + JSUint64 u2 = Int64Base::GetInt(cx, obj2); if (u1 == u2) JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0)); @@ -5806,8 +5801,8 @@ UInt64::Lo(JSContext* cx, uintN argc, jsval* vp) } JSObject* obj = JSVAL_TO_OBJECT(argv[0]); - PRUint64 u = Int64Base::GetInt(cx, obj); - jsdouble d = PRUint32(INT64_LO(u)); + JSUint64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSUint32(INT64_LO(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -5828,8 +5823,8 @@ UInt64::Hi(JSContext* cx, uintN argc, jsval* vp) } JSObject* obj = JSVAL_TO_OBJECT(argv[0]); - PRUint64 u = Int64Base::GetInt(cx, obj); - jsdouble d = PRUint32(INT64_HI(u)); + JSUint64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSUint32(INT64_HI(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -5848,14 +5843,14 @@ UInt64::Join(JSContext* cx, uintN argc, jsval* vp) } jsval* argv = JS_ARGV(cx, vp); - PRUint32 hi; - PRUint32 lo; + JSUint32 hi; + JSUint32 lo; if (!jsvalToInteger(cx, argv[0], &hi)) return TypeError(cx, "uint32_t", argv[0]); if (!jsvalToInteger(cx, argv[1], &lo)) return TypeError(cx, "uint32_t", argv[1]); - PRUint64 u = (PRUint64(hi) << 32) + PRUint64(lo); + JSUint64 u = (JSUint64(hi) << 32) + JSUint64(lo); // Get UInt64.prototype from the function's reserved slot. JSObject* callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h index d703fc1415af..58ad3d88a2ba 100644 --- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -303,9 +303,6 @@ struct ClosureInfo JSObject* thisObj; // 'this' object to use for the JS function call JSObject* jsfnObj; // JS function ffi_closure* closure; // The C closure itself -#ifdef DEBUG - PRThread* thread; // The thread the closure was created on -#endif }; JSBool InitTypeClasses(JSContext* cx, JSObject* parent); diff --git a/js/src/ctypes/typedefs.h b/js/src/ctypes/typedefs.h index 6f2a06904c6d..7e27b8aa5f43 100644 --- a/js/src/ctypes/typedefs.h +++ b/js/src/ctypes/typedefs.h @@ -102,18 +102,18 @@ // The meat. DEFINE_BOOL_TYPE (bool, bool, CTYPES_FFI_BOOL) -DEFINE_INT_TYPE (int8_t, PRInt8, ffi_type_sint8) -DEFINE_INT_TYPE (int16_t, PRInt16, ffi_type_sint16) -DEFINE_INT_TYPE (int32_t, PRInt32, ffi_type_sint32) -DEFINE_INT_TYPE (uint8_t, PRUint8, ffi_type_uint8) -DEFINE_INT_TYPE (uint16_t, PRUint16, ffi_type_uint16) -DEFINE_INT_TYPE (uint32_t, PRUint32, ffi_type_uint32) +DEFINE_INT_TYPE (int8_t, JSInt8, ffi_type_sint8) +DEFINE_INT_TYPE (int16_t, JSInt16, ffi_type_sint16) +DEFINE_INT_TYPE (int32_t, JSInt32, ffi_type_sint32) +DEFINE_INT_TYPE (uint8_t, JSUint8, ffi_type_uint8) +DEFINE_INT_TYPE (uint16_t, JSUint16, ffi_type_uint16) +DEFINE_INT_TYPE (uint32_t, JSUint32, ffi_type_uint32) DEFINE_INT_TYPE (short, short, ffi_type_sint16) DEFINE_INT_TYPE (unsigned_short, unsigned short, ffi_type_uint16) DEFINE_INT_TYPE (int, int, ffi_type_sint32) DEFINE_INT_TYPE (unsigned_int, unsigned int, ffi_type_uint32) -DEFINE_WRAPPED_INT_TYPE(int64_t, PRInt64, ffi_type_sint64) -DEFINE_WRAPPED_INT_TYPE(uint64_t, PRUint64, ffi_type_uint64) +DEFINE_WRAPPED_INT_TYPE(int64_t, JSInt64, ffi_type_sint64) +DEFINE_WRAPPED_INT_TYPE(uint64_t, JSUint64, ffi_type_uint64) DEFINE_WRAPPED_INT_TYPE(long, long, CTYPES_FFI_LONG) DEFINE_WRAPPED_INT_TYPE(unsigned_long, unsigned long, CTYPES_FFI_ULONG) DEFINE_WRAPPED_INT_TYPE(long_long, long long, ffi_type_sint64) From d4ae70c635069aba7e6ecb4a41cead3d896c5acd Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:16:51 -0700 Subject: [PATCH 208/213] Bug 538324 - Move ctypes into js/src. Part 8: Add ctypes JS module bits to toolkit. r=bsmedberg --HG-- rename : js/ctypes/Makefile.in => toolkit/components/ctypes/Makefile.in rename : js/ctypes/Module.cpp => toolkit/components/ctypes/Module.cpp rename : js/ctypes/Module.h => toolkit/components/ctypes/Module.h rename : js/ctypes/ctypes.jsm => toolkit/components/ctypes/ctypes.jsm rename : js/ctypes/tests/Makefile.in => toolkit/components/ctypes/tests/Makefile.in rename : js/ctypes/tests/jsctypes-test.cpp => toolkit/components/ctypes/tests/jsctypes-test.cpp rename : js/ctypes/tests/jsctypes-test.h => toolkit/components/ctypes/tests/jsctypes-test.h rename : js/ctypes/tests/unit/test_jsctypes.js.in => toolkit/components/ctypes/tests/unit/test_jsctypes.js.in --- toolkit/components/Makefile.in | 6 ++ {js => toolkit/components}/ctypes/Makefile.in | 23 +----- {js => toolkit/components}/ctypes/Module.cpp | 76 ++++++------------- {js => toolkit/components}/ctypes/Module.h | 3 - {js => toolkit/components}/ctypes/ctypes.jsm | 0 .../components}/ctypes/tests/Makefile.in | 6 +- .../ctypes/tests/jsctypes-test.cpp | 4 +- .../components}/ctypes/tests/jsctypes-test.h | 4 +- .../ctypes/tests/unit/test_jsctypes.js.in | 0 toolkit/toolkit-makefiles.sh | 5 ++ 10 files changed, 46 insertions(+), 81 deletions(-) rename {js => toolkit/components}/ctypes/Makefile.in (84%) rename {js => toolkit/components}/ctypes/Module.cpp (72%) rename {js => toolkit/components}/ctypes/Module.h (94%) rename {js => toolkit/components}/ctypes/ctypes.jsm (100%) rename {js => toolkit/components}/ctypes/tests/Makefile.in (97%) rename {js => toolkit/components}/ctypes/tests/jsctypes-test.cpp (99%) rename {js => toolkit/components}/ctypes/tests/jsctypes-test.h (99%) rename {js => toolkit/components}/ctypes/tests/unit/test_jsctypes.js.in (100%) diff --git a/toolkit/components/Makefile.in b/toolkit/components/Makefile.in index ffb46b565ae8..30102d9b90a0 100644 --- a/toolkit/components/Makefile.in +++ b/toolkit/components/Makefile.in @@ -69,6 +69,12 @@ PARALLEL_DIRS += \ viewconfig \ $(NULL) +ifdef BUILD_CTYPES +PARALLEL_DIRS += \ + ctypes \ + $(NULL) +endif + ifneq (,$(filter cocoa, $(MOZ_WIDGET_TOOLKIT))) TOOL_DIRS += alerts else diff --git a/js/ctypes/Makefile.in b/toolkit/components/ctypes/Makefile.in similarity index 84% rename from js/ctypes/Makefile.in rename to toolkit/components/ctypes/Makefile.in index 4b001a0fe297..7ee6c98be471 100644 --- a/js/ctypes/Makefile.in +++ b/toolkit/components/ctypes/Makefile.in @@ -36,7 +36,7 @@ # # ***** END LICENSE BLOCK ***** -DEPTH = ../.. +DEPTH = ../../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @@ -47,38 +47,19 @@ MODULE = jsctypes MODULE_NAME = jsctypes GRE_MODULE = 1 -# package the js module whether ctypes is enabled or not. EXTRA_JS_MODULES = \ ctypes.jsm \ $(NULL) -ifdef BUILD_CTYPES - LIBRARY_NAME = jsctypes LIBXUL_LIBRARY = 1 EXPORT_LIBRARY = 1 IS_COMPONENT = 1 CPPSRCS = \ - Library.cpp \ - CTypes.cpp \ Module.cpp \ $(NULL) -LOCAL_INCLUDES = \ - -Ilibffi/include \ - $(NULL) - -ifeq ($(OS_ARCH),OS2) -# libffi builds an aout lib on OS/2; convert it to an OMF lib. -libffi/.libs/libffi.$(LIB_SUFFIX): libffi/.libs/libffi.a - emxomf $< -endif - -SHARED_LIBRARY_LIBS = \ - libffi/.libs/libffi.$(LIB_SUFFIX) \ - $(NULL) - EXTRA_DSO_LDOPTS += \ $(MOZ_COMPONENT_LIBS) \ $(MOZ_JS_LIBS) \ @@ -88,6 +69,4 @@ ifdef ENABLE_TESTS DIRS += tests endif -endif - include $(topsrcdir)/config/rules.mk diff --git a/js/ctypes/Module.cpp b/toolkit/components/ctypes/Module.cpp similarity index 72% rename from js/ctypes/Module.cpp rename to toolkit/components/ctypes/Module.cpp index c7112400d409..b0f9614154d4 100644 --- a/js/ctypes/Module.cpp +++ b/toolkit/components/ctypes/Module.cpp @@ -38,8 +38,7 @@ * ***** END LICENSE BLOCK ***** */ #include "Module.h" -#include "Library.h" -#include "CTypes.h" +#include "jsapi.h" #include "nsIGenericFactory.h" #include "nsMemory.h" @@ -70,29 +69,6 @@ Module::~Module() #define XPC_MAP_FLAGS nsIXPCScriptable::WANT_CALL #include "xpc_map_end.h" -NS_IMETHODIMP -Module::Call(nsIXPConnectWrappedNative* wrapper, - JSContext* cx, - JSObject* obj, - PRUint32 argc, - jsval* argv, - jsval* vp, - PRBool* _retval) -{ - JSObject* global = JS_GetGlobalObject(cx); - *_retval = Init(cx, global); - return NS_OK; -} - -#define CTYPESFN_FLAGS \ - (JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) - -static JSFunctionSpec sModuleFunctions[] = { - JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS), - JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS), - JS_FS_END -}; - static JSBool SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name) { @@ -109,39 +85,37 @@ SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name) JS_SealObject(cx, prototype, JS_FALSE); } -JSBool -Module::Init(JSContext* cx, JSObject* aGlobal) +static JSBool +InitAndSealCTypesClass(JSContext* cx, JSObject* global) { - // attach ctypes property to global object - JSObject* ctypes = JS_NewObject(cx, NULL, NULL, NULL); - if (!ctypes) + // Init the ctypes object. + if (!JS_InitCTypesClass(cx, global)) return false; - if (!JS_DefineProperty(cx, aGlobal, "ctypes", OBJECT_TO_JSVAL(ctypes), - NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) - return false; - - if (!InitTypeClasses(cx, ctypes)) - return false; - - // attach API functions - if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions)) - return false; - - // Seal the ctypes object, to prevent modification. (This single object - // instance is shared amongst everyone who imports the ctypes module.) - if (!JS_SealObject(cx, ctypes, JS_FALSE)) - return false; - - // Seal up Object, Function, and Array and their prototypes. - if (!SealObjectAndPrototype(cx, aGlobal, "Object") || - !SealObjectAndPrototype(cx, aGlobal, "Function") || - !SealObjectAndPrototype(cx, aGlobal, "Array")) + // Seal up Object, Function, and Array and their prototypes. (This single + // object instance is shared amongst everyone who imports the ctypes module.) + if (!SealObjectAndPrototype(cx, global, "Object") || + !SealObjectAndPrototype(cx, global, "Function") || + !SealObjectAndPrototype(cx, global, "Array")) return false; // Finally, seal the global object, for good measure. (But not recursively; // this breaks things.) - return JS_SealObject(cx, aGlobal, JS_FALSE); + return JS_SealObject(cx, global, JS_FALSE); +} + +NS_IMETHODIMP +Module::Call(nsIXPConnectWrappedNative* wrapper, + JSContext* cx, + JSObject* obj, + PRUint32 argc, + jsval* argv, + jsval* vp, + PRBool* _retval) +{ + JSObject* global = JS_GetGlobalObject(cx); + *_retval = InitAndSealCTypesClass(cx, global); + return NS_OK; } } diff --git a/js/ctypes/Module.h b/toolkit/components/ctypes/Module.h similarity index 94% rename from js/ctypes/Module.h rename to toolkit/components/ctypes/Module.h index 993c2521bc34..bf77dfe36008 100644 --- a/js/ctypes/Module.h +++ b/toolkit/components/ctypes/Module.h @@ -52,9 +52,6 @@ public: Module(); - // Creates the ctypes object and attaches it to the global object. - JSBool Init(JSContext* aContext, JSObject* aGlobal); - private: ~Module(); }; diff --git a/js/ctypes/ctypes.jsm b/toolkit/components/ctypes/ctypes.jsm similarity index 100% rename from js/ctypes/ctypes.jsm rename to toolkit/components/ctypes/ctypes.jsm diff --git a/js/ctypes/tests/Makefile.in b/toolkit/components/ctypes/tests/Makefile.in similarity index 97% rename from js/ctypes/tests/Makefile.in rename to toolkit/components/ctypes/tests/Makefile.in index 69a5162f0699..78eb03f143b0 100644 --- a/js/ctypes/tests/Makefile.in +++ b/toolkit/components/ctypes/tests/Makefile.in @@ -36,7 +36,7 @@ # # ***** END LICENSE BLOCK ***** -DEPTH = ../../.. +DEPTH = ../../../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @@ -51,6 +51,10 @@ NO_DIST_INSTALL = 1 CPPSRCS = jsctypes-test.cpp +LOCAL_INCLUDES = \ + -I$(topsrcdir)/js/src/ctypes \ + $(NULL) + EXTRA_DSO_LDOPTS += \ $(XPCOM_STANDALONE_GLUE_LDOPTS) \ $(MOZALLOC_LIB) \ diff --git a/js/ctypes/tests/jsctypes-test.cpp b/toolkit/components/ctypes/tests/jsctypes-test.cpp similarity index 99% rename from js/ctypes/tests/jsctypes-test.cpp rename to toolkit/components/ctypes/tests/jsctypes-test.cpp index 63d1032b9593..ebde2b228c1c 100644 --- a/js/ctypes/tests/jsctypes-test.cpp +++ b/toolkit/components/ctypes/tests/jsctypes-test.cpp @@ -113,7 +113,7 @@ get_##name##_stats(size_t* align, size_t* size, size_t* nalign, size_t* nsize, \ offsets[2] = offsetof(nested_##name, c); \ } -#include "../typedefs.h" +#include "typedefs.h" #if defined(_WIN32) && !defined(__WIN64) @@ -156,7 +156,7 @@ sum_many_##name##_stdcall( \ return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r;\ } -#include "../typedefs.h" +#include "typedefs.h" void NS_STDCALL test_void_t_stdcall() diff --git a/js/ctypes/tests/jsctypes-test.h b/toolkit/components/ctypes/tests/jsctypes-test.h similarity index 99% rename from js/ctypes/tests/jsctypes-test.h rename to toolkit/components/ctypes/tests/jsctypes-test.h index 1ba322fa1b7a..df86c200c347 100644 --- a/js/ctypes/tests/jsctypes-test.h +++ b/toolkit/components/ctypes/tests/jsctypes-test.h @@ -67,7 +67,7 @@ NS_EXTERN_C size_t* nalign, size_t* nsize, \ size_t offsets[]); -#include "../typedefs.h" +#include "typedefs.h" #if defined(_WIN32) && !defined(__WIN64) EXPORT_STDCALL(void) test_void_t_stdcall(); @@ -87,7 +87,7 @@ NS_EXTERN_C type, type, type, type, type, type, type, type, type, \ type, type, type, type, type, type, type, type, type); -#include "../typedefs.h" +#include "typedefs.h" #endif /* defined(_WIN32) && !defined(__WIN64) */ diff --git a/js/ctypes/tests/unit/test_jsctypes.js.in b/toolkit/components/ctypes/tests/unit/test_jsctypes.js.in similarity index 100% rename from js/ctypes/tests/unit/test_jsctypes.js.in rename to toolkit/components/ctypes/tests/unit/test_jsctypes.js.in diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index eb3bf62f91d6..da8566426edd 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -769,6 +769,11 @@ MAKEFILES_xulapp=" toolkit/xre/Makefile " +MAKEFILES_ctypes=" + toolkit/components/ctypes/Makefile + toolkit/components/ctypes/tests/Makefile +" + MAKEFILES_libpr0n=" modules/libpr0n/Makefile modules/libpr0n/build/Makefile From 7302a0413896e5de24f59757c050837a9e6c7a62 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 13:34:19 -0700 Subject: [PATCH 209/213] Bug 538324 - Move ctypes into js/src. Part 9: Add ctypes to jsshell. r=gal --- js/src/ctypes/CTypes.cpp | 4 ++-- js/src/shell/js.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 22954a0dec90..72f215eed539 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -1725,7 +1725,7 @@ ImplicitConvert(JSContext* cx, size_t nbytes = js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); if (nbytes == (size_t) -1) - return false; + return false; if (targetLength < nbytes) { JS_ReportError(cx, "ArrayType has insufficient length"); @@ -4610,7 +4610,7 @@ ConvertArgument(JSContext* cx, JS_ReportOutOfMemory(cx); return false; } - *strings[i].mData = *static_cast(value->mData); + strings->back().mData = *static_cast(value->mData); } return true; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 7ad7237934c2..90d53ee29881 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4906,6 +4906,10 @@ main(int argc, char **argv, char **envp) #else if (!JS_InitStandardClasses(cx, glob)) return 1; +#endif +#ifdef JS_HAS_CTYPES + if (!JS_InitCTypesClass(cx, glob)) + return 1; #endif if (!JS_DefineFunctions(cx, glob, shell_functions)) return 1; From 28e6b998149fe16c2134c7c7b2ac8e63c25f3543 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Fri, 2 Apr 2010 14:03:27 -0700 Subject: [PATCH 210/213] Typo fix. --- js/src/ctypes/CTypes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 72f215eed539..7e9f8c9cf02e 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -4659,7 +4659,7 @@ FunctionType::Call(JSContext* cx, // prepare the values for each argument AutoValueAutoArray values; AutoValueAutoArray strings; - if (!values.resize(fninfo->mArgTypes.length())) { + if (!values.resize(argc)) { JS_ReportOutOfMemory(cx); return false; } From 00195a52fa0a40d2136fd58e8bce8726b501b69c Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Thu, 1 Apr 2010 09:56:25 -0500 Subject: [PATCH 211/213] Bug 555246 - Wrong answer for 'this' in function code when entry frame was produced by a call across globals. r=brendan. --- js/src/jsops.cpp | 2 +- js/src/tests/js1_8_5/regress/jstests.list | 2 ++ js/src/tests/js1_8_5/regress/regress-555246-0.js | 11 +++++++++++ js/src/tests/js1_8_5/regress/regress-555246-1.js | 11 +++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 js/src/tests/js1_8_5/regress/regress-555246-0.js create mode 100644 js/src/tests/js1_8_5/regress/regress-555246-1.js diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 4ea1dcd45b74..9dedc21dcd3a 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -2751,7 +2751,7 @@ BEGIN_CASE(JSOP_CALLGVAR) rval = obj->getSlotMT(cx, slot); PUSH_OPND(rval); if (op == JSOP_CALLGVAR) - PUSH_OPND(OBJECT_TO_JSVAL(obj)); + PUSH_OPND(JSVAL_NULL); END_CASE(JSOP_GETGVAR) BEGIN_CASE(JSOP_SETGVAR) diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 23101dbe24cc..0f28b6f0c01c 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -8,3 +8,5 @@ script regress-541255-3.js script regress-541255-4.js script regress-541455.js script regress-546615.js +script regress-555246-0.js +fails script regress-555246-1.js diff --git a/js/src/tests/js1_8_5/regress/regress-555246-0.js b/js/src/tests/js1_8_5/regress/regress-555246-0.js new file mode 100644 index 000000000000..86acca0334ea --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-555246-0.js @@ -0,0 +1,11 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Jason Orendorff + */ + +var cx = evalcx(""); +evalcx("function f() { return this; }", cx); +var f = cx.f; +assertEq(f(), cx); +reportCompare(0, 0, ""); diff --git a/js/src/tests/js1_8_5/regress/regress-555246-1.js b/js/src/tests/js1_8_5/regress/regress-555246-1.js new file mode 100644 index 000000000000..6bd0195d833b --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-555246-1.js @@ -0,0 +1,11 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Jason Orendorff + */ + +var cx = evalcx(""); +evalcx("function f() { return this; }", cx); +f = cx.f; +assertEq(f(), cx); +reportCompare(0, 0, ""); From 132aa31ad077c4e98957918a81b8278786ec980c Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Sun, 4 Apr 2010 09:41:11 -0400 Subject: [PATCH 212/213] Fix up the tests from bug 555246 to run when there's no evalcx function available. --- js/src/tests/js1_8_5/regress/regress-555246-0.js | 11 +++++++---- js/src/tests/js1_8_5/regress/regress-555246-1.js | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/js/src/tests/js1_8_5/regress/regress-555246-0.js b/js/src/tests/js1_8_5/regress/regress-555246-0.js index 86acca0334ea..51a46a6d0c0a 100644 --- a/js/src/tests/js1_8_5/regress/regress-555246-0.js +++ b/js/src/tests/js1_8_5/regress/regress-555246-0.js @@ -4,8 +4,11 @@ * Contributor: Jason Orendorff */ -var cx = evalcx(""); -evalcx("function f() { return this; }", cx); -var f = cx.f; -assertEq(f(), cx); +if (typeof evalcx != 'function') { + var cx = evalcx(""); + evalcx("function f() { return this; }", cx); + var f = cx.f; + assertEq(f(), cx); +} + reportCompare(0, 0, ""); diff --git a/js/src/tests/js1_8_5/regress/regress-555246-1.js b/js/src/tests/js1_8_5/regress/regress-555246-1.js index 6bd0195d833b..af3f3e1205c0 100644 --- a/js/src/tests/js1_8_5/regress/regress-555246-1.js +++ b/js/src/tests/js1_8_5/regress/regress-555246-1.js @@ -4,6 +4,7 @@ * Contributor: Jason Orendorff */ +assertEq(typeof evalcx, "function", "") var cx = evalcx(""); evalcx("function f() { return this; }", cx); f = cx.f; From c2d662487edfb8dacb713b8bd8b0d6d11cb976c9 Mon Sep 17 00:00:00 2001 From: Robert Sayre Date: Sun, 4 Apr 2010 11:00:45 -0400 Subject: [PATCH 213/213] Fix thinko in test. --- js/src/tests/js1_8_5/regress/regress-555246-0.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/tests/js1_8_5/regress/regress-555246-0.js b/js/src/tests/js1_8_5/regress/regress-555246-0.js index 51a46a6d0c0a..a79ac62045ca 100644 --- a/js/src/tests/js1_8_5/regress/regress-555246-0.js +++ b/js/src/tests/js1_8_5/regress/regress-555246-0.js @@ -4,7 +4,7 @@ * Contributor: Jason Orendorff */ -if (typeof evalcx != 'function') { +if (typeof evalcx == 'function') { var cx = evalcx(""); evalcx("function f() { return this; }", cx); var f = cx.f;