mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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! :-\
This commit is contained in:
parent
106fbd8085
commit
95422c65a3
@ -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;
|
||||
|
||||
|
@ -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<nsAutoPoolRelease> poolRelease;
|
||||
js::LazilyConstructed<js::AutoArrayRooter> tvr;
|
||||
js::LazilyConstructed<JSAutoTempValueRooter> 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<nsAutoPoolRelease> poolRelease;
|
||||
js::LazilyConstructed<js::AutoArrayRooter> tvr;
|
||||
js::LazilyConstructed<JSAutoTempValueRooter> tvr;
|
||||
|
||||
nsresult rv;
|
||||
rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
|
||||
@ -2689,7 +2690,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
|
||||
PRUint32 *aArgc,
|
||||
jsval **aArgv,
|
||||
js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
|
||||
js::LazilyConstructed<js::AutoArrayRooter> &aRooter)
|
||||
js::LazilyConstructed<JSAutoTempValueRooter> &aRooter)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -49,11 +49,8 @@
|
||||
|
||||
class nsIXPConnectJSObjectHolder;
|
||||
class nsAutoPoolRelease;
|
||||
namespace js {
|
||||
class AutoValueRooter;
|
||||
class AutoArrayRooter;
|
||||
template <class> class LazilyConstructed;
|
||||
}
|
||||
class JSAutoTempValueRooter;
|
||||
namespace js { template <class> class LazilyConstructed; }
|
||||
|
||||
class nsJSContext : public nsIScriptContext,
|
||||
public nsIXPCScriptNotify
|
||||
@ -218,7 +215,7 @@ protected:
|
||||
PRUint32 *aArgc,
|
||||
jsval **aArgv,
|
||||
js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
|
||||
js::LazilyConstructed<js::AutoArrayRooter> &aRooter);
|
||||
js::LazilyConstructed<JSAutoTempValueRooter> &aRooter);
|
||||
|
||||
nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
|
||||
|
||||
|
@ -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())))
|
||||
|
111
js/src/jsapi.cpp
111
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),
|
||||
|
@ -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;
|
||||
|
||||
|
460
js/src/jscntxt.h
460
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_<KIND>(cx, NULL, &tvr). Then &tvr.u.<kind> 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.<gcthing> 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;
|
||||
}
|
||||
|
@ -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 <jwalden+code@mit.edu> (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<AutoValueRooter *>(this)->val);
|
||||
return;
|
||||
|
||||
case SPROP:
|
||||
static_cast<AutoScopePropertyRooter *>(this)->sprop->trace(trc);
|
||||
return;
|
||||
|
||||
case WEAKROOTS:
|
||||
static_cast<AutoSaveWeakRoots *>(this)->savedRoots.mark(trc);
|
||||
return;
|
||||
|
||||
case COMPILER:
|
||||
static_cast<JSCompiler *>(this)->trace(trc);
|
||||
return;
|
||||
|
||||
case SCRIPT:
|
||||
if (JSScript *script = static_cast<AutoScriptRooter *>(this)->script)
|
||||
js_TraceScript(trc, script);
|
||||
return;
|
||||
|
||||
case ENUMERATOR:
|
||||
static_cast<AutoEnumStateRooter *>(this)->trace(trc);
|
||||
return;
|
||||
|
||||
case IDARRAY: {
|
||||
JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
|
||||
TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
|
||||
return;
|
||||
}
|
||||
|
||||
case DESCRIPTORS: {
|
||||
PropertyDescriptorArray &descriptors =
|
||||
static_cast<AutoDescriptorArray *>(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<AutoNamespaces *>(this)->array;
|
||||
TraceObjectVector(trc, reinterpret_cast<JSObject **>(array.vector), array.length);
|
||||
array.cursors->trace(trc);
|
||||
return;
|
||||
}
|
||||
|
||||
case XML:
|
||||
js_TraceXML(trc, static_cast<AutoXMLRooter *>(this)->xml);
|
||||
return;
|
||||
|
||||
case OBJECT:
|
||||
if (JSObject *obj = static_cast<AutoObjectRooter *>(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<AutoIdRooter *>(this)->idval);
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ASSERT(tag >= 0);
|
||||
TraceValues(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "js::AutoArrayRooter.array");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* jscntxtinlines_h___ */
|
@ -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)) {
|
||||
|
265
js/src/jsexn.cpp
265
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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
103
js/src/jsgc.cpp
103
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<JSAutoEnumStateRooter *>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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___ */
|
||||
|
@ -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())) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
122
js/src/jsobj.cpp
122
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<JSScopeProperty *>(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<PropertyDescriptor, 1> 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<AutoDescriptorArray *>(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) &&
|
||||
|
@ -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();
|
||||
|
@ -83,34 +83,4 @@ JSObject::unbrand(JSContext *cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
typedef Vector<PropertyDescriptor, 1> 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___ */
|
||||
|
119
js/src/json.cpp
119
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))
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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()). */
|
||||
|
444
js/src/jsxml.cpp
444
js/src/jsxml.cpp
@ -70,14 +70,10 @@
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <string.h> /* 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<JSXMLArrayCursor>(&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<JSXMLArrayCursor>(&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 *
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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<XPCWrappedNative *>(JS_GetPrivate(cx, obj));
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -321,7 +321,7 @@ struct xpc_qsArgValArray
|
||||
memset(array, 0, N * sizeof(jsval));
|
||||
}
|
||||
|
||||
js::AutoArrayRooter tvr;
|
||||
JSAutoTempValueRooter tvr;
|
||||
jsval array[N];
|
||||
};
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user