Bug 965830 - Make AutoValueArray into a fixed-size inline array that roots its contents r=terrence

This commit is contained in:
Jon Coppeard 2014-02-11 10:59:15 +00:00
parent bc51fc58c5
commit a7102e885e
10 changed files with 172 additions and 129 deletions

View File

@ -971,10 +971,11 @@ MapIteratorObject::next_impl(JSContext *cx, CallArgs args)
break;
case MapObject::Entries: {
Value pair[2] = { range->front().key.get(), range->front().value };
AutoValueArray root(cx, pair, ArrayLength(pair));
JS::AutoValueArray<2> pair(cx);
pair[0].set(range->front().key.get());
pair[1].set(range->front().value);
JSObject *pairobj = NewDenseCopiedArray(cx, ArrayLength(pair), pair);
JSObject *pairobj = NewDenseCopiedArray(cx, pair.length(), pair.begin());
if (!pairobj)
return false;
value.setObject(*pairobj);
@ -1561,10 +1562,11 @@ SetIteratorObject::next_impl(JSContext *cx, CallArgs args)
break;
case SetObject::Entries: {
Value pair[2] = { range->front().get(), range->front().get() };
AutoValueArray root(cx, pair, 2);
JS::AutoValueArray<2> pair(cx);
pair[0].set(range->front().get());
pair[1].set(range->front().get());
JSObject *pairObj = NewDenseCopiedArray(cx, 2, pair);
JSObject *pairObj = NewDenseCopiedArray(cx, 2, pair.begin());
if (!pairObj)
return false;
value.setObject(*pairObj);

View File

@ -466,8 +466,12 @@ AutoGCRooter::trace(JSTracer *trc)
}
case VALARRAY: {
AutoValueArray *array = static_cast<AutoValueArray *>(this);
MarkValueRootRange(trc, array->length(), array->start(), "js::AutoValueArray");
/*
* We don't know the template size parameter, but we can safely treat it
* as an AutoValueArray<1> because the length is stored separately.
*/
AutoValueArray<1> *array = static_cast<AutoValueArray<1> *>(this);
MarkValueRootRange(trc, array->length(), array->begin(), "js::AutoValueArray");
return;
}

View File

@ -1602,13 +1602,14 @@ DoCallNativeGetter(JSContext *cx, HandleFunction callee, HandleObject obj,
JS_ASSERT(callee->isNative());
JSNative natfun = callee->native();
Value vp[2] = { ObjectValue(*callee.get()), ObjectValue(*obj.get()) };
AutoValueArray rootVp(cx, vp, 2);
JS::AutoValueArray<2> vp(cx);
vp[0].setObject(*callee.get());
vp[1].setObject(*obj.get());
if (!natfun(cx, 0, rootVp.start()))
if (!natfun(cx, 0, vp.begin()))
return false;
result.set(rootVp[0]);
result.set(vp[0]);
return true;
}
@ -7675,10 +7676,12 @@ DoCallNativeSetter(JSContext *cx, HandleFunction callee, HandleObject obj, Handl
JS_ASSERT(callee->isNative());
JSNative natfun = callee->native();
Value vp[3] = { ObjectValue(*callee.get()), ObjectValue(*obj.get()), val };
AutoValueArray rootVp(cx, vp, 3);
JS::AutoValueArray<3> vp(cx);
vp[0].setObject(*callee.get());
vp[1].setObject(*obj.get());
vp[2].set(val);
return natfun(cx, 1, vp);
return natfun(cx, 1, vp.begin());
}
typedef bool (*DoCallNativeSetterFn)(JSContext *, HandleFunction, HandleObject, HandleValue);

View File

@ -369,14 +369,15 @@ ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
AutoDetectInvalidation adi(cx, rval.address());
Value argv[] = { UndefinedValue(), ObjectValue(*obj) };
AutoValueArray ava(cx, argv, 2);
if (!js::array_pop(cx, 0, ava.start()))
JS::AutoValueArray<2> argv(cx);
argv[0].setUndefined();
argv[1].setObject(*obj);
if (!js::array_pop(cx, 0, argv.begin()))
return false;
// If the result is |undefined|, the array was probably empty and we
// have to monitor the return value.
rval.set(ava[0]);
rval.set(argv[0]);
if (rval.isUndefined())
types::TypeScript::Monitor(cx, rval);
return true;
@ -387,12 +388,14 @@ ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length)
{
JS_ASSERT(obj->is<ArrayObject>());
Value argv[] = { UndefinedValue(), ObjectValue(*obj), v };
AutoValueArray ava(cx, argv, 3);
if (!js::array_push(cx, 1, ava.start()))
JS::AutoValueArray<3> argv(cx);
argv[0].setUndefined();
argv[1].setObject(*obj);
argv[2].set(v);
if (!js::array_push(cx, 1, argv.begin()))
return false;
*length = ava[0].toInt32();
*length = argv[0].toInt32();
return true;
}
@ -403,14 +406,15 @@ ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
AutoDetectInvalidation adi(cx, rval.address());
Value argv[] = { UndefinedValue(), ObjectValue(*obj) };
AutoValueArray ava(cx, argv, 2);
if (!js::array_shift(cx, 0, ava.start()))
JS::AutoValueArray<2> argv(cx);
argv[0].setUndefined();
argv[1].setObject(*obj);
if (!js::array_shift(cx, 0, argv.begin()))
return false;
// If the result is |undefined|, the array was probably empty and we
// have to monitor the return value.
rval.set(ava[0]);
rval.set(argv[0]);
if (rval.isUndefined())
types::TypeScript::Monitor(cx, rval);
return true;
@ -430,11 +434,13 @@ ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObje
return arrRes;
}
Value argv[] = { UndefinedValue(), ObjectValue(*arr1), ObjectValue(*arr2) };
AutoValueArray ava(cx, argv, 3);
if (!js::array_concat(cx, 1, ava.start()))
JS::AutoValueArray<3> argv(cx);
argv[0].setUndefined();
argv[1].setObject(*arr1);
argv[2].setObject(*arr2);
if (!js::array_concat(cx, 1, argv.begin()))
return nullptr;
return &ava[0].toObject();
return &argv[0].toObject();
}
bool

View File

@ -85,13 +85,12 @@ ExhaustiveTest(const char funcode[])
EVAL(CALL_CODES[ArgCount], v.address());
Rooted<ArgumentsObject*> argsobj(cx, &JSVAL_TO_OBJECT(v)->as<ArgumentsObject>());
Value elems_[MAX_ELEMS];
AutoValueArray elems(cx, elems_, MAX_ELEMS);
JS::AutoValueArray<MAX_ELEMS> elems(cx);
for (size_t i = 0; i <= ArgCount; i++) {
for (size_t j = 0; j <= ArgCount - i; j++) {
ClearElements(elems);
CHECK(argsobj->maybeGetElements(i, j, elems.start()));
CHECK(argsobj->maybeGetElements(i, j, elems.begin()));
for (size_t k = 0; k < j; k++)
CHECK_SAME(elems[k], INT_TO_JSVAL(i + k));
for (size_t k = j; k < MAX_ELEMS - 1; k++)
@ -103,8 +102,9 @@ ExhaustiveTest(const char funcode[])
return true;
}
template <size_t N>
static void
ClearElements(AutoValueArray &elems)
ClearElements(JS::AutoValueArray<N> &elems)
{
for (size_t i = 0; i < elems.length() - 1; i++)
elems[i].setNull();

View File

@ -136,6 +136,7 @@ class JS_PUBLIC_API(AutoGCRooter) {
void operator=(AutoGCRooter &ida) MOZ_DELETE;
};
/* AutoArrayRooter roots an external array of Values. */
class AutoArrayRooter : private AutoGCRooter
{
public:
@ -191,6 +192,40 @@ class AutoArrayRooter : private AutoGCRooter
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* AutoValueArray roots an internal fixed-size array of Values. */
template <size_t N>
class AutoValueArray : public AutoGCRooter
{
const size_t length_;
Value elements_[N];
js::SkipRoot skip_;
public:
AutoValueArray(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VALARRAY), length_(N), skip_(cx, elements_, N)
{
/* Always initialize in case we GC before assignment. */
mozilla::PodArrayZero(elements_);
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
unsigned length() const { return length_; }
const Value *begin() const { return elements_; }
Value *begin() { return elements_; }
HandleValue operator[](unsigned i) const {
JS_ASSERT(i < N);
return HandleValue::fromMarkedLocation(&elements_[i]);
}
MutableHandleValue operator[](unsigned i) {
JS_ASSERT(i < N);
return MutableHandleValue::fromMarkedLocation(&elements_[i]);
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
template<class T>
class AutoVectorRooter : protected AutoGCRooter
{

View File

@ -891,43 +891,6 @@ class AutoShapeVector : public AutoVectorRooter<Shape *>
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoValueArray : public AutoGCRooter
{
Value *start_;
unsigned length_;
SkipRoot skip;
public:
AutoValueArray(JSContext *cx, Value *start, unsigned length
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VALARRAY), start_(start), length_(length), skip(cx, start, length)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
Value *start() { return start_; }
unsigned length() const { return length_; }
MutableHandleValue handleAt(unsigned i) {
JS_ASSERT(i < length_);
return MutableHandleValue::fromMarkedLocation(&start_[i]);
}
HandleValue handleAt(unsigned i) const {
JS_ASSERT(i < length_);
return HandleValue::fromMarkedLocation(&start_[i]);
}
MutableHandleValue operator[](unsigned i) {
JS_ASSERT(i < length_);
return MutableHandleValue::fromMarkedLocation(&start_[i]);
}
HandleValue operator[](unsigned i) const {
JS_ASSERT(i < length_);
return HandleValue::fromMarkedLocation(&start_[i]);
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoObjectObjectHashMap : public AutoHashMapRooter<JSObject *, JSObject *>
{
public:

View File

@ -683,9 +683,10 @@ Trap2(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, Value
if (!str)
return false;
rval.setString(str);
Value argv[2] = { rval.get(), v };
AutoValueArray ava(cx, argv, 2);
return Trap(cx, handler, fval, 2, argv, rval);
JS::AutoValueArray<2> argv(cx);
argv[0].set(rval);
argv[1].set(v);
return Trap(cx, handler, fval, 2, argv.begin(), rval);
}
static bool
@ -969,14 +970,15 @@ ScriptedIndirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObjec
if (!str)
return false;
RootedValue value(cx, StringValue(str));
Value argv[] = { ObjectOrNullValue(receiver), value };
AutoValueArray ava(cx, argv, 2);
JS::AutoValueArray<2> argv(cx);
argv[0].setObjectOrNull(receiver);
argv[1].set(value);
RootedValue fval(cx);
if (!GetDerivedTrap(cx, handler, cx->names().get, &fval))
return false;
if (!js_IsCallable(fval))
return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
return Trap(cx, handler, fval, 2, ava.start(), vp);
return Trap(cx, handler, fval, 2, argv.begin(), vp);
}
bool
@ -989,14 +991,16 @@ ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObjec
if (!str)
return false;
RootedValue value(cx, StringValue(str));
Value argv[] = { ObjectOrNullValue(receiver), value, vp.get() };
AutoValueArray ava(cx, argv, 3);
JS::AutoValueArray<3> argv(cx);
argv[0].setObjectOrNull(receiver);
argv[1].set(value);
argv[2].set(vp);
RootedValue fval(cx);
if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
return false;
if (!js_IsCallable(fval))
return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
return Trap(cx, handler, fval, 3, ava.start(), &value);
return Trap(cx, handler, fval, 3, argv.begin(), &value);
}
bool

View File

@ -30,6 +30,7 @@
using namespace js;
using namespace js::frontend;
using JS::AutoValueArray;
using mozilla::ArrayLength;
using mozilla::DebugOnly;
@ -148,22 +149,21 @@ GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, HandleValue def
*/
class NodeBuilder
{
typedef AutoValueArray<AST_LIMIT> CallbackArray;
JSContext *cx;
TokenStream *tokenStream;
bool saveLoc; /* save source location information? */
char const *src; /* source filename or null */
RootedValue srcval; /* source filename JS value or null */
Value callbacks_[AST_LIMIT]; /* user-specified callbacks */
AutoValueArray callbacks; /* for rooting |callbacks| */
CallbackArray callbacks; /* user-specified callbacks */
RootedValue userv; /* user-specified builder object or null */
public:
NodeBuilder(JSContext *c, bool l, char const *s)
: cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c),
callbacks(c, callbacks_, AST_LIMIT), userv(c)
{
MakeRangeGCSafe(callbacks.start(), callbacks.length());
}
: cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c), callbacks(cx),
userv(c)
{}
bool init(HandleObject userobj = js::NullPtr()) {
if (src) {
@ -221,14 +221,14 @@ class NodeBuilder
RootedValue loc(cx);
if (!newNodeLoc(pos, &loc))
return false;
Value argv[] = { loc };
AutoValueArray ava(cx, argv, 1);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<1> argv(cx);
argv[1].set(loc);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
Value argv[] = { NullValue() }; /* no zero-length arrays allowed! */
AutoValueArray ava(cx, argv, 1);
return Invoke(cx, userv, fun, 0, argv, dst);
AutoValueArray<1> argv(cx);
argv[1].setNull(); /* no zero-length arrays allowed! */
return Invoke(cx, userv, fun, 0, argv.begin(), dst);
}
bool callback(HandleValue fun, HandleValue v1, TokenPos *pos, MutableHandleValue dst) {
@ -236,14 +236,15 @@ class NodeBuilder
RootedValue loc(cx);
if (!newNodeLoc(pos, &loc))
return false;
Value argv[] = { v1, loc };
AutoValueArray ava(cx, argv, 2);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<2> argv(cx);
argv[0].set(v1);
argv[1].set(loc);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
Value argv[] = { v1 };
AutoValueArray ava(cx, argv, 1);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<1> argv(cx);
argv[1].set(v1);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, TokenPos *pos,
@ -252,14 +253,17 @@ class NodeBuilder
RootedValue loc(cx);
if (!newNodeLoc(pos, &loc))
return false;
Value argv[] = { v1, v2, loc };
AutoValueArray ava(cx, argv, 3);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<3> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(loc);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
Value argv[] = { v1, v2 };
AutoValueArray ava(cx, argv, 2);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<2> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, TokenPos *pos,
@ -268,14 +272,19 @@ class NodeBuilder
RootedValue loc(cx);
if (!newNodeLoc(pos, &loc))
return false;
Value argv[] = { v1, v2, v3, loc };
AutoValueArray ava(cx, argv, 4);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<4> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(v3);
argv[3].set(loc);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
Value argv[] = { v1, v2, v3 };
AutoValueArray ava(cx, argv, 3);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<3> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(v3);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
@ -284,14 +293,21 @@ class NodeBuilder
RootedValue loc(cx);
if (!newNodeLoc(pos, &loc))
return false;
Value argv[] = { v1, v2, v3, v4, loc };
AutoValueArray ava(cx, argv, 5);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<5> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(v3);
argv[3].set(v4);
argv[4].set(loc);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
Value argv[] = { v1, v2, v3, v4 };
AutoValueArray ava(cx, argv, 4);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<4> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(v3);
argv[3].set(v4);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
@ -300,14 +316,23 @@ class NodeBuilder
RootedValue loc(cx);
if (!newNodeLoc(pos, &loc))
return false;
Value argv[] = { v1, v2, v3, v4, v5, loc };
AutoValueArray ava(cx, argv, 6);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<6> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(v3);
argv[3].set(v4);
argv[4].set(v5);
argv[5].set(loc);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
Value argv[] = { v1, v2, v3, v4, v5 };
AutoValueArray ava(cx, argv, 5);
return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
AutoValueArray<5> argv(cx);
argv[0].set(v1);
argv[1].set(v2);
argv[2].set(v3);
argv[3].set(v4);
argv[4].set(v5);
return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
}
// WARNING: Returning a Handle is non-standard, but it works in this case

View File

@ -997,15 +997,16 @@ Debugger::fireExceptionUnwind(JSContext *cx, MutableHandleValue vp)
Maybe<AutoCompartment> ac;
ac.construct(cx, object);
Value argvData[] = { JSVAL_VOID, exc };
AutoValueArray argv(cx, argvData, 2);
ScriptFrameIter iter(cx);
JS::AutoValueArray<2> argv(cx);
argv[0].setUndefined();
argv[1].set(exc);
if (!getScriptFrame(cx, iter, argv.handleAt(0)) || !wrapDebuggeeValue(cx, argv.handleAt(1)))
ScriptFrameIter iter(cx);
if (!getScriptFrame(cx, iter, argv[0]) || !wrapDebuggeeValue(cx, argv[1]))
return handleUncaughtException(ac, false);
RootedValue rv(cx);
bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 2, argv.start(), &rv);
bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 2, argv.begin(), &rv);
JSTrapStatus st = parseResumptionValue(ac, ok, rv, vp);
if (st == JSTRAP_CONTINUE)
cx->setPendingException(exc);