Bug 906940 - Exactly root the IsAcceptableThis callback; r=jonco,smaug
authorTerrence Cole <terrence@mozilla.com>
Tue, 28 May 2013 11:23:04 -0700
changeset 157433 6eaf9e414a520fe9fd91f6b50d3436e7913e6182
parent 157432 be5a8c4d2d21a55f22d3b091fd29eb0b14d60c49
child 157434 01d3658a980cc0c64f6cdecbc95a7d587bae5efe
push id407
push userlsblakk@mozilla.com
push dateTue, 03 Dec 2013 03:32:50 +0000
treeherdermozilla-release@babf8c9ebc52 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco, smaug
bugs906940
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 906940 - Exactly root the IsAcceptableThis callback; r=jonco,smaug
content/xbl/src/nsXBLProtoImplField.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/builtin/RegExp.cpp
js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsdate.cpp
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsstr.cpp
js/src/jsweakmap.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/content/xbl/src/nsXBLProtoImplField.cpp
+++ b/content/xbl/src/nsXBLProtoImplField.cpp
@@ -100,49 +100,58 @@ nsXBLProtoImplField::AppendFieldText(con
 // that could resolve fields onto themselves.  But given that XBL bindings are
 // associated with elements mutably -- you can add/remove/change -moz-binding
 // whenever you want, alas -- doing so would require all elements to be proxies,
 // which isn't performant now.  So we do this two-step instead.
 static const uint32_t XBLPROTO_SLOT = 0;
 static const uint32_t FIELD_SLOT = 1;
 
 bool
-ValueHasISupportsPrivate(const JS::Value &v)
+ValueHasISupportsPrivate(JS::Handle<JS::Value> v)
 {
   if (!v.isObject()) {
     return false;
   }
 
   const DOMClass* domClass = GetDOMClass(&v.toObject());
   if (domClass) {
     return domClass->mDOMObjectIsISupports;
   }
 
   JSClass* clasp = ::JS_GetClass(&v.toObject());
   const uint32_t HAS_PRIVATE_NSISUPPORTS =
     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
   return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS;
 }
 
+#ifdef DEBUG
+static bool
+ValueHasISupportsPrivate(JSContext* cx, const JS::Value& aVal)
+{
+    JS::Rooted<JS::Value> v(cx, aVal);
+    return ValueHasISupportsPrivate(v);
+}
+#endif
+
 // Define a shadowing property on |this| for the XBL field defined by the
 // contents of the callee's reserved slots.  If the property was defined,
 // *installed will be true, and idp will be set to the property name that was
 // defined.
 static bool
 InstallXBLField(JSContext* cx,
                 JS::Handle<JSObject*> callee, JS::Handle<JSObject*> thisObj,
                 JS::MutableHandle<jsid> idp, bool* installed)
 {
   *installed = false;
 
   // First ensure |this| is a reasonable XBL bound node.
   //
   // FieldAccessorGuard already determined whether |thisObj| was acceptable as
   // |this| in terms of not throwing a TypeError.  Assert this for good measure.
-  MOZ_ASSERT(ValueHasISupportsPrivate(JS::ObjectValue(*thisObj)));
+  MOZ_ASSERT(ValueHasISupportsPrivate(cx, JS::ObjectValue(*thisObj)));
 
   // But there are some cases where we must accept |thisObj| but not install a
   // property on it, or otherwise touch it.  Hence this split of |this|-vetting
   // duties.
   nsISupports* native =
     nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, thisObj);
   if (!native) {
     // Looks like whatever |thisObj| is it's not our nsIContent.  It might well
@@ -217,17 +226,17 @@ InstallXBLField(JSContext* cx,
     xpc::Throw(cx, rv);
   }
   return false;
 }
 
 bool
 FieldGetterImpl(JSContext *cx, JS::CallArgs args)
 {
-  const JS::Value &thisv = args.thisv();
+  JS::Handle<JS::Value> thisv = args.thisv();
   MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
 
   JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
 
   // We should be in the compartment of |this|. If we got here via nativeCall,
   // |this| is not same-compartment with |callee|, and it's possible via
   // asymmetric security semantics that |args.calleev()| is actually a security
   // wrapper. In this case, we know we want to do an unsafe unwrap, and
@@ -258,17 +267,17 @@ FieldGetter(JSContext *cx, unsigned argc
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldGetterImpl>
                                  (cx, args);
 }
 
 bool
 FieldSetterImpl(JSContext *cx, JS::CallArgs args)
 {
-  const JS::Value &thisv = args.thisv();
+  JS::Handle<JS::Value> thisv = args.thisv();
   MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
 
   JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
 
   // We should be in the compartment of |this|. If we got here via nativeCall,
   // |this| is not same-compartment with |callee|, and it's possible via
   // asymmetric security semantics that |args.calleev()| is actually a security
   // wrapper. In this case, we know we want to do an unsafe unwrap, and
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -861,17 +861,17 @@ class MapIteratorObject : public JSObjec
 
     enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
     static const JSFunctionSpec methods[];
     static MapIteratorObject *create(JSContext *cx, HandleObject mapobj, ValueMap *data,
                                      MapObject::IteratorKind kind);
     static void finalize(FreeOp *fop, JSObject *obj);
 
   private:
-    static inline bool is(const Value &v);
+    static inline bool is(HandleValue v);
     inline ValueMap::Range *range();
     inline MapObject::IteratorKind kind() const;
     static bool next_impl(JSContext *cx, CallArgs args);
     static bool next(JSContext *cx, unsigned argc, Value *vp);
 };
 
 } /* anonymous namespace */
 
@@ -951,17 +951,17 @@ MapIteratorObject::create(JSContext *cx,
 
 void
 MapIteratorObject::finalize(FreeOp *fop, JSObject *obj)
 {
     fop->delete_(obj->as<MapIteratorObject>().range());
 }
 
 bool
-MapIteratorObject::is(const Value &v)
+MapIteratorObject::is(HandleValue v)
 {
     return v.isObject() && v.toObject().hasClass(&class_);
 }
 
 bool
 MapIteratorObject::next_impl(JSContext *cx, CallArgs args)
 {
     MapIteratorObject &thisobj = args.thisv().toObject().as<MapIteratorObject>();
@@ -1203,17 +1203,17 @@ MapObject::construct(JSContext *cx, unsi
             return false;
     }
 
     args.rval().setObject(*obj);
     return true;
 }
 
 bool
-MapObject::is(const Value &v)
+MapObject::is(HandleValue v)
 {
     return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().getPrivate();
 }
 
 #define ARG0_KEY(cx, args, key)                                               \
     AutoHashableValueRooter key(cx);                                          \
     if (args.length() > 0 && !key.setValue(cx, args[0]))                      \
         return false
@@ -1428,17 +1428,17 @@ class SetIteratorObject : public JSObjec
 
     enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
     static const JSFunctionSpec methods[];
     static SetIteratorObject *create(JSContext *cx, HandleObject setobj, ValueSet *data,
                                      SetObject::IteratorKind kind);
     static void finalize(FreeOp *fop, JSObject *obj);
 
   private:
-    static inline bool is(const Value &v);
+    static inline bool is(HandleValue v);
     inline ValueSet::Range *range();
     inline SetObject::IteratorKind kind() const;
     static bool next_impl(JSContext *cx, CallArgs args);
     static bool next(JSContext *cx, unsigned argc, Value *vp);
 };
 
 } /* anonymous namespace */
 
@@ -1517,17 +1517,17 @@ SetIteratorObject::create(JSContext *cx,
 
 void
 SetIteratorObject::finalize(FreeOp *fop, JSObject *obj)
 {
     fop->delete_(obj->as<SetIteratorObject>().range());
 }
 
 bool
-SetIteratorObject::is(const Value &v)
+SetIteratorObject::is(HandleValue v)
 {
     return v.isObject() && v.toObject().is<SetIteratorObject>();
 }
 
 bool
 SetIteratorObject::next_impl(JSContext *cx, CallArgs args)
 {
     SetIteratorObject &thisobj = args.thisv().toObject().as<SetIteratorObject>();
@@ -1678,17 +1678,17 @@ SetObject::construct(JSContext *cx, unsi
             return false;
     }
 
     args.rval().setObject(*obj);
     return true;
 }
 
 bool
-SetObject::is(const Value &v)
+SetObject::is(HandleValue v)
 {
     return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().getPrivate();
 }
 
 ValueSet &
 SetObject::extract(CallReceiver call)
 {
     JS_ASSERT(call.thisv().isObject());
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -94,17 +94,17 @@ class MapObject : public JSObject {
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     ValueMap *getData() { return static_cast<ValueMap *>(getPrivate()); }
     static ValueMap & extract(CallReceiver call);
     static void mark(JSTracer *trc, JSObject *obj);
     static void finalize(FreeOp *fop, JSObject *obj);
     static bool construct(JSContext *cx, unsigned argc, Value *vp);
 
-    static bool is(const Value &v);
+    static bool is(HandleValue v);
 
     static bool iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind);
 
     static bool size_impl(JSContext *cx, CallArgs args);
     static bool size(JSContext *cx, unsigned argc, Value *vp);
     static bool get_impl(JSContext *cx, CallArgs args);
     static bool get(JSContext *cx, unsigned argc, Value *vp);
     static bool has_impl(JSContext *cx, CallArgs args);
@@ -132,17 +132,17 @@ class SetObject : public JSObject {
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     ValueSet *getData() { return static_cast<ValueSet *>(getPrivate()); }
     static ValueSet & extract(CallReceiver call);
     static void mark(JSTracer *trc, JSObject *obj);
     static void finalize(FreeOp *fop, JSObject *obj);
     static bool construct(JSContext *cx, unsigned argc, Value *vp);
 
-    static bool is(const Value &v);
+    static bool is(HandleValue v);
 
     static bool iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind);
 
     static bool size_impl(JSContext *cx, CallArgs args);
     static bool size(JSContext *cx, unsigned argc, Value *vp);
     static bool has_impl(JSContext *cx, CallArgs args);
     static bool has(JSContext *cx, unsigned argc, Value *vp);
     static bool add_impl(JSContext *cx, CallArgs args);
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -300,17 +300,17 @@ CompileRegExpObject(JSContext *cx, RegEx
     if (!reobj)
         return false;
 
     args.rval().setObject(*reobj);
     return true;
 }
 
 JS_ALWAYS_INLINE bool
-IsRegExp(const Value &v)
+IsRegExp(HandleValue v)
 {
     return v.isObject() && v.toObject().is<RegExpObject>();
 }
 
 JS_ALWAYS_INLINE bool
 regexp_compile_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsRegExp(args.thisv()));
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -16,17 +16,17 @@ static JSClass CustomClass = {
   JS_EnumerateStub,
   JS_ResolveStub,
   JS_ConvertStub
 };
 
 static const uint32_t CUSTOM_SLOT = 0;
 
 static bool
-IsCustomClass(const Value &v)
+IsCustomClass(JS::Handle<JS::Value> v)
 {
   return v.isObject() && JS_GetClass(&v.toObject()) == &CustomClass;
 }
 
 static bool
 CustomMethodImpl(JSContext *cx, CallArgs args)
 {
   JS_ASSERT(IsCustomClass(args.thisv()));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -99,17 +99,17 @@ using mozilla::PodCopy;
 using mozilla::PodZero;
 
 using js::frontend::Parser;
 
 bool
 JS::detail::CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                                CallArgs args)
 {
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     JS_ASSERT(!test(thisv));
 
     if (thisv.isObject()) {
         JSObject &thisObj = args.thisv().toObject();
         if (thisObj.is<ProxyObject>())
             return Proxy::nativeCall(cx, test, impl, args);
     }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -639,17 +639,17 @@ class JS_PUBLIC_API(CustomAutoRooter) : 
     /* Supplied by derived class to trace roots. */
     virtual void trace(JSTracer *trc) = 0;
 
   private:
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /* Returns true if |v| is considered an acceptable this-value. */
-typedef bool (*IsAcceptableThis)(const Value &v);
+typedef bool (*IsAcceptableThis)(JS::Handle<JS::Value> v);
 
 /*
  * Implements the guts of a method; guaranteed to be provided an acceptable
  * this-value, as determined by a corresponding IsAcceptableThis method.
  */
 typedef bool (*NativeImpl)(JSContext *cx, CallArgs args);
 
 namespace detail {
@@ -723,27 +723,27 @@ CallMethodIfWrapped(JSContext *cx, IsAcc
  *
  * Note: JS::CallNonGenericMethod will only work correctly if it's called in
  *       tail position in a JSNative.  Do not call it from any other place.
  */
 template<IsAcceptableThis Test, NativeImpl Impl>
 JS_ALWAYS_INLINE bool
 CallNonGenericMethod(JSContext *cx, CallArgs args)
 {
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     if (Test(thisv))
         return Impl(cx, args);
 
     return detail::CallMethodIfWrapped(cx, Test, Impl, args);
 }
 
 JS_ALWAYS_INLINE bool
 CallNonGenericMethod(JSContext *cx, IsAcceptableThis Test, NativeImpl Impl, CallArgs args)
 {
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     if (Test(thisv))
         return Impl(cx, args);
 
     return detail::CallMethodIfWrapped(cx, Test, Impl, args);
 }
 
 }  /* namespace JS */
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -794,17 +794,17 @@ AddLengthProperty(ExclusiveContext *cx, 
 
     return JSObject::addProperty(cx, obj, lengthId, array_length_getter, array_length_setter,
                                  SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0,
                                  /* allowDictionary = */ false);
 }
 
 #if JS_HAS_TOSOURCE
 JS_ALWAYS_INLINE bool
-IsArray(const Value &v)
+IsArray(HandleValue v)
 {
     return v.isObject() && v.toObject().is<ArrayObject>();
 }
 
 JS_ALWAYS_INLINE bool
 array_toSource_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsArray(args.thisv()));
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -33,26 +33,26 @@ Class BooleanObject::class_ = {
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
 JS_ALWAYS_INLINE bool
-IsBoolean(const Value &v)
+IsBoolean(HandleValue v)
 {
     return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>());
 }
 
 #if JS_HAS_TOSOURCE
 JS_ALWAYS_INLINE bool
 bool_toSource_impl(JSContext *cx, CallArgs args)
 {
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     JS_ASSERT(IsBoolean(thisv));
 
     bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox();
 
     StringBuffer sb(cx);
     if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(cx, b, sb) || !sb.append("))"))
         return false;
 
@@ -69,17 +69,17 @@ bool_toSource(JSContext *cx, unsigned ar
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsBoolean, bool_toSource_impl>(cx, args);
 }
 #endif
 
 JS_ALWAYS_INLINE bool
 bool_toString_impl(JSContext *cx, CallArgs args)
 {
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     JS_ASSERT(IsBoolean(thisv));
 
     bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox();
     args.rval().setString(js_BooleanToString(cx, b));
     return true;
 }
 
 bool
@@ -87,17 +87,17 @@ bool_toString(JSContext *cx, unsigned ar
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsBoolean, bool_toString_impl>(cx, args);
 }
 
 JS_ALWAYS_INLINE bool
 bool_valueOf_impl(JSContext *cx, CallArgs args)
 {
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     JS_ASSERT(IsBoolean(thisv));
 
     bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox();
     args.rval().setBoolean(b);
     return true;
 }
 
 bool
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1381,17 +1381,17 @@ DateObject::fillLocalTimeSlots(DateTimeI
 inline double
 DateObject::cachedLocalTime(DateTimeInfo *dtInfo)
 {
     fillLocalTimeSlots(dtInfo);
     return getReservedSlot(LOCAL_TIME_SLOT).toDouble();
 }
 
 JS_ALWAYS_INLINE bool
-IsDate(const Value &v)
+IsDate(HandleValue v)
 {
     return v.isObject() && v.toObject().is<DateObject>();
 }
 
 /*
  * See ECMA 15.9.5.4 thru 15.9.5.23
  */
 /* static */ JS_ALWAYS_INLINE bool
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -758,17 +758,17 @@ js::IteratorConstructor(JSContext *cx, u
 
     if (!ValueToIterator(cx, flags, args[0]))
         return false;
     args.rval().set(args[0]);
     return true;
 }
 
 JS_ALWAYS_INLINE bool
-IsIterator(const Value &v)
+IsIterator(HandleValue v)
 {
     return v.isObject() && v.toObject().hasClass(&PropertyIteratorObject::class_);
 }
 
 JS_ALWAYS_INLINE bool
 iterator_next_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsIterator(args.thisv()));
@@ -871,17 +871,17 @@ ElementIteratorObject::create(JSContext 
     if (iterobj) {
         iterobj->setReservedSlot(TargetSlot, target);
         iterobj->setReservedSlot(IndexSlot, Int32Value(0));
     }
     return iterobj;
 }
 
 static bool
-IsElementIterator(const Value &v)
+IsElementIterator(HandleValue v)
 {
     return v.isObject() && v.toObject().is<ElementIteratorObject>();
 }
 
 bool
 ElementIteratorObject::next(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1628,17 +1628,17 @@ CloseGenerator(JSContext *cx, HandleObje
 
     if (gen->state == JSGEN_CLOSED)
         return true;
 
     return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JS::UndefinedHandleValue);
 }
 
 JS_ALWAYS_INLINE bool
-IsGenerator(const Value &v)
+IsGenerator(HandleValue v)
 {
     return v.isObject() && v.toObject().is<GeneratorObject>();
 }
 
 JS_ALWAYS_INLINE bool
 generator_send_impl(JSContext *cx, CallArgs args)
 {
     // FIXME: Change assertion to IsLegacyGenerator().
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -478,17 +478,17 @@ Number(JSContext *cx, unsigned argc, Val
     JSObject *obj = NumberObject::create(cx, args.rval().toNumber());
     if (!obj)
         return false;
     args.rval().setObject(*obj);
     return true;
 }
 
 JS_ALWAYS_INLINE bool
-IsNumber(const Value &v)
+IsNumber(HandleValue v)
 {
     return v.isNumber() || (v.isObject() && v.toObject().is<NumberObject>());
 }
 
 inline double
 Extract(const Value &v)
 {
     if (v.isNumber())
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -455,17 +455,17 @@ ThisToStringForStringProto(JSContext *cx
     if (!str)
         return NULL;
 
     call.setThis(StringValue(str));
     return str;
 }
 
 JS_ALWAYS_INLINE bool
-IsString(const Value &v)
+IsString(HandleValue v)
 {
     return v.isString() || (v.isObject() && v.toObject().is<StringObject>());
 }
 
 #if JS_HAS_TOSOURCE
 
 /*
  * String.prototype.quote is generic (as are most string methods), unlike
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -121,17 +121,17 @@ GetKeyArg(JSContext *cx, CallArgs &args)
     if (args[0].isPrimitive()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
         return NULL;
     }
     return &args[0].toObject();
 }
 
 JS_ALWAYS_INLINE bool
-IsWeakMap(const Value &v)
+IsWeakMap(HandleValue v)
 {
     return v.isObject() && v.toObject().is<WeakMapObject>();
 }
 
 JS_ALWAYS_INLINE bool
 WeakMap_has_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsWeakMap(args.thisv()));
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -48,27 +48,27 @@ static bool
 ThrowTypeError(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                  JSMSG_THROW_TYPE_ERROR);
     return false;
 }
 
 static bool
-TestProtoGetterThis(const Value &v)
+TestProtoGetterThis(HandleValue v)
 {
     return !v.isNullOrUndefined();
 }
 
 static bool
 ProtoGetterImpl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(TestProtoGetterThis(args.thisv()));
 
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     if (thisv.isPrimitive() && !BoxNonStrictThis(cx, args))
         return false;
 
     unsigned dummy;
     RootedObject obj(cx, &args.thisv().toObject());
     RootedId nid(cx, NameToId(cx->names().proto));
     RootedValue v(cx);
     if (!CheckAccess(cx, obj, nid, JSACC_PROTO, &v, &dummy))
@@ -85,17 +85,17 @@ ProtoGetter(JSContext *cx, unsigned argc
     return CallNonGenericMethod(cx, TestProtoGetterThis, ProtoGetterImpl, args);
 }
 
 namespace js {
 size_t sSetProtoCalled = 0;
 } // namespace js
 
 static bool
-TestProtoSetterThis(const Value &v)
+TestProtoSetterThis(HandleValue v)
 {
     if (v.isNullOrUndefined())
         return false;
 
     /* These will work as if on a boxed primitive; dumb, but whatever. */
     if (!v.isObject())
         return true;
 
@@ -103,17 +103,17 @@ TestProtoSetterThis(const Value &v)
     return !v.toObject().is<ProxyObject>();
 }
 
 static bool
 ProtoSetterImpl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(TestProtoSetterThis(args.thisv()));
 
-    const Value &thisv = args.thisv();
+    HandleValue thisv = args.thisv();
     if (thisv.isPrimitive()) {
         JS_ASSERT(!thisv.isNullOrUndefined());
 
         // Mutating a boxed primitive's [[Prototype]] has no side effects.
         args.rval().setUndefined();
         return true;
     }
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -119,17 +119,17 @@ ToClampedIndex(JSContext *cx, HandleValu
  * ArrayBufferObject
  *
  * This class holds the underlying raw buffer that the TypedArrayObject classes
  * access.  It can be created explicitly and passed to a TypedArrayObject, or
  * can be created implicitly by constructing a TypedArrayObject with a size.
  */
 
 JS_ALWAYS_INLINE bool
-IsArrayBuffer(const Value &v)
+IsArrayBuffer(HandleValue v)
 {
     return v.isObject() && v.toObject().hasClass(&ArrayBufferObject::class_);
 }
 
 JS_ALWAYS_INLINE bool
 ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsArrayBuffer(args.thisv()));
@@ -1436,17 +1436,17 @@ class TypedArrayObjectTemplate : public 
         return &TypedArrayObject::protoClasses[ArrayTypeID()];
     }
 
     static inline Class *fastClass()
     {
         return &TypedArrayObject::classes[ArrayTypeID()];
     }
 
-    static bool is(const Value &v) {
+    static bool is(HandleValue v) {
         return v.isObject() && v.toObject().hasClass(fastClass());
     }
 
     static bool
     obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
                     MutableHandleValue vp)
     {
         RootedObject proto(cx, obj->getProto());
@@ -1890,17 +1890,17 @@ class TypedArrayObjectTemplate : public 
                 }
             }
         }
 
         Rooted<JSObject*> proto(cx, NULL);
         return fromBuffer(cx, dataObj, byteOffset, length, proto);
     }
 
-    static bool IsThisClass(const Value &v) {
+    static bool IsThisClass(HandleValue v) {
         return v.isObject() && v.toObject().hasClass(fastClass());
     }
 
     template<Value ValueGetter(TypedArrayObject *tarr)>
     static bool
     GetterImpl(JSContext *cx, CallArgs args)
     {
         JS_ASSERT(IsThisClass(args.thisv()));
@@ -3979,17 +3979,17 @@ js_InitTypedArrayClasses(JSContext *cx, 
     {
         return NULL;
     }
 
     return InitArrayBufferClass(cx);
 }
 
 bool
-js::IsTypedArrayConstructor(const Value &v, uint32_t type)
+js::IsTypedArrayConstructor(HandleValue v, uint32_t type)
 {
     switch (type) {
       case TypedArrayObject::TYPE_INT8:
         return IsNativeFunction(v, Int8ArrayObject::class_constructor);
       case TypedArrayObject::TYPE_UINT8:
         return IsNativeFunction(v, Uint8ArrayObject::class_constructor);
       case TypedArrayObject::TYPE_INT16:
         return IsNativeFunction(v, Int16ArrayObject::class_constructor);
@@ -4005,17 +4005,17 @@ js::IsTypedArrayConstructor(const Value 
         return IsNativeFunction(v, Float64ArrayObject::class_constructor);
       case TypedArrayObject::TYPE_UINT8_CLAMPED:
         return IsNativeFunction(v, Uint8ClampedArrayObject::class_constructor);
     }
     MOZ_ASSUME_UNREACHABLE("unexpected typed array type");
 }
 
 bool
-js::IsTypedArrayBuffer(const Value &v)
+js::IsTypedArrayBuffer(HandleValue v)
 {
     return v.isObject() && v.toObject().is<ArrayBufferObject>();
 }
 
 /* JS Friend API */
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferObject(JSObject *obj)
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -410,20 +410,20 @@ IsTypedArrayClass(const Class *clasp)
 inline bool
 IsTypedArrayProtoClass(const Class *clasp)
 {
     return &TypedArrayObject::protoClasses[0] <= clasp &&
            clasp < &TypedArrayObject::protoClasses[TypedArrayObject::TYPE_MAX];
 }
 
 bool
-IsTypedArrayConstructor(const Value &v, uint32_t type);
+IsTypedArrayConstructor(HandleValue v, uint32_t type);
 
 bool
-IsTypedArrayBuffer(const Value &v);
+IsTypedArrayBuffer(HandleValue v);
 
 static inline unsigned
 TypedArrayShift(ArrayBufferView::ViewType viewType)
 {
     switch (viewType) {
       case ArrayBufferView::TYPE_INT8:
       case ArrayBufferView::TYPE_UINT8:
       case ArrayBufferView::TYPE_UINT8_CLAMPED:
@@ -445,17 +445,17 @@ TypedArrayShift(ArrayBufferView::ViewTyp
 class DataViewObject : public ArrayBufferViewObject
 {
     static const size_t RESERVED_SLOTS = ArrayBufferViewObject::NUM_SLOTS;
     static const size_t DATA_SLOT      = 7; // private slot, based on alloc kind
 
   private:
     static Class protoClass;
 
-    static bool is(const Value &v) {
+    static bool is(HandleValue v) {
         return v.isObject() && v.toObject().hasClass(&class_);
     }
 
     template<Value ValueGetter(DataViewObject *view)>
     static bool
     getterImpl(JSContext *cx, CallArgs args);
 
     template<Value ValueGetter(DataViewObject *view)>