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:
Jeff Walden 2010-03-26 18:01:54 -07:00
parent 106fbd8085
commit 95422c65a3
50 changed files with 1388 additions and 1383 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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())))

View File

@ -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),

View File

@ -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;

View File

@ -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;
}

View File

@ -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___ */

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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);
}
/*

View File

@ -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;
}
}
}

View File

@ -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___ */

View File

@ -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())) {

View File

@ -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

View File

@ -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;

View File

@ -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) &&

View File

@ -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();

View File

@ -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___ */

View File

@ -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))

View File

@ -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

View File

@ -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()));

View File

@ -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

View File

@ -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

View File

@ -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. */
/*

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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());

View File

@ -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) {

View File

@ -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);

View File

@ -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.
*

View File

@ -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()). */

View File

@ -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 *

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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,

View File

@ -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);

View File

@ -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)) {

View File

@ -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]

View File

@ -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

View File

@ -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;

View File

@ -321,7 +321,7 @@ struct xpc_qsArgValArray
memset(array, 0, N * sizeof(jsval));
}
js::AutoArrayRooter tvr;
JSAutoTempValueRooter tvr;
jsval array[N];
};

View File

@ -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 *

View File

@ -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",

View File

@ -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);

View File

@ -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) {

View File

@ -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());