Bug 1255800 - Remove JS_THIS_OBJECT from js. r=jorendorff
authorTom Schuster <evilpies@gmail.com>
Thu, 22 Mar 2018 16:38:30 +0100
changeset 410173 bf1a120681d07e4fa166ac22ed0767176a4e7022
parent 410172 b858515d31112e6b6322495413fa5451e3f944d9
child 410174 16d254b2fe0d46094d86752ec144ba8c2c162046
push id101405
push userevilpies@gmail.com
push dateTue, 27 Mar 2018 14:45:05 +0000
treeherdermozilla-inbound@9a6a2971bce3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1255800
milestone61.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 1255800 - Remove JS_THIS_OBJECT from js. r=jorendorff
js/public/CallArgs.h
js/src/ctypes/CTypes.cpp
js/src/ctypes/CTypes.h
js/src/ctypes/Library.cpp
js/src/jit-test/tests/ctypes/incompatible-abi.js
js/src/jit-test/tests/ctypes/incompatible-array.js
js/src/jit-test/tests/ctypes/incompatible-cdata.js
js/src/jit-test/tests/ctypes/incompatible-ctype.js
js/src/jit-test/tests/ctypes/incompatible-finalizer.js
js/src/jit-test/tests/ctypes/incompatible-int64.js
js/src/jit-test/tests/ctypes/incompatible-pointer.js
js/src/jit-test/tests/ctypes/incompatible-struct.js
js/src/shell/js.cpp
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -340,54 +340,9 @@ CallArgsFromSp(unsigned stackSlots, Valu
                bool ignoresReturnValue = false)
 {
     return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing,
                             ignoresReturnValue);
 }
 
 } // namespace JS
 
-/*
- * Macros to hide interpreter stack layout details from a JSNative using its
- * JS::Value* vp parameter.  DO NOT USE THESE!  Instead use JS::CallArgs and
- * friends, above.  These macros will be removed when we change JSNative to
- * take a const JS::CallArgs&.
- */
-
-/*
- * Return |this| if |this| is an object.  Otherwise, return the global object
- * if |this| is null or undefined, and finally return a boxed version of any
- * other primitive.
- *
- * Note: if this method returns null, an error has occurred and must be
- * propagated or caught.
- */
-MOZ_ALWAYS_INLINE JS::Value
-JS_THIS(JSContext* cx, JS::Value* vp)
-{
-    return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1];
-}
-
-/*
- * A note on JS_THIS_OBJECT: no equivalent method is part of the CallArgs
- * interface, and we're unlikely to add one (functions shouldn't be implicitly
- * exposing the global object to arbitrary callers).  Continue using |vp|
- * directly for this case, but be aware this API will eventually be replaced
- * with a function that operates directly upon |args.thisv()|.
- */
-#define JS_THIS_OBJECT(cx,vp)   (JS_THIS(cx,vp).toObjectOrNull())
-
-/*
- * |this| is passed to functions in ES5 without change.  Functions themselves
- * do any post-processing they desire to box |this|, compute the global object,
- * &c.  This macro retrieves a function's unboxed |this| value.
- *
- * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT,
- * or vice versa.  Either use the provided this value with this macro, or
- * compute the boxed |this| value using those.  JS_THIS_VALUE must not be used
- * if the function is being called as a constructor.
- *
- * But: DO NOT USE THIS!  Instead use JS::CallArgs::thisv(), above.
- *
- */
-#define JS_THIS_VALUE(cx,vp)    ((vp)[1])
-
 #endif /* js_CallArgs_h */
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -272,17 +272,17 @@ namespace PointerType {
   bool ContentsGetter(JSContext* cx, const JS::CallArgs& args);
   bool ContentsSetter(JSContext* cx, const JS::CallArgs& args);
 
   static bool IsNull(JSContext* cx, unsigned argc, Value* vp);
   static bool Increment(JSContext* cx, unsigned argc, Value* vp);
   static bool Decrement(JSContext* cx, unsigned argc, Value* vp);
   // The following is not an instance function, since we don't want to expose arbitrary
   // pointer arithmetic at this moment.
-  static bool OffsetBy(JSContext* cx, const CallArgs& args, int offset);
+  static bool OffsetBy(JSContext* cx, const CallArgs& args, int offset, const char* name);
 } // namespace PointerType
 
 namespace ArrayType {
   bool IsArrayType(HandleValue v);
   bool IsArrayOrArrayType(HandleValue v);
 
   static bool Create(JSContext* cx, unsigned argc, Value* vp);
   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
@@ -1980,16 +1980,27 @@ VariadicArgumentTypeError(JSContext* cx,
   char indexStr[16];
   SprintfLiteral(indexStr, "%u", index + 1);
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_VARG_TYPE_ERROR, indexStr, valStr);
   return false;
 }
 
+MOZ_MUST_USE JSObject*
+GetThisObject(JSContext* cx, const CallArgs& args, const char* msg)
+{
+  if (!args.thisv().isObject()) {
+    IncompatibleThisProto(cx, msg, args.thisv());
+    return nullptr;
+  }
+
+  return &args.thisv().toObject();
+}
+
 static JSObject*
 InitCTypeClass(JSContext* cx, HandleObject ctypesObj)
 {
   JSFunction* fun = JS_DefineFunction(cx, ctypesObj, "CType", ConstructAbstract, 0,
                                       CTYPESCTOR_FLAGS);
   if (!fun)
     return nullptr;
 
@@ -4926,17 +4937,17 @@ CType::PtrGetter(JSContext* cx, const JS
   args.rval().setObject(*pointerType);
   return true;
 }
 
 bool
 CType::CreateArray(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject baseType(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject baseType(cx, GetThisObject(cx, args, "CType.prototype.array"));
   if (!baseType)
     return false;
   if (!CType::IsCType(baseType)) {
     return IncompatibleThisProto(cx, "CType.prototype.array", args.thisv());
   }
 
   // Construct and return a new ArrayType object.
   if (args.length() > 1) {
@@ -4957,17 +4968,17 @@ CType::CreateArray(JSContext* cx, unsign
   args.rval().setObject(*result);
   return true;
 }
 
 bool
 CType::ToString(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "CType.prototype.toString"));
   if (!obj)
     return false;
   if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj)) {
     return IncompatibleThisProto(cx, "CType.prototype.toString",
                                  InformalValueTypeName(args.thisv()));
   }
 
   // Create the appropriate string depending on whether we're sCTypeClass or
@@ -4988,17 +4999,17 @@ CType::ToString(JSContext* cx, unsigned 
   args.rval().setString(result);
   return true;
 }
 
 bool
 CType::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  JSObject* obj = JS_THIS_OBJECT(cx, vp);
+  JSObject* obj = GetThisObject(cx, args, "CType.prototype.toSource");
   if (!obj)
     return false;
   if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj)) {
     return IncompatibleThisProto(cx, "CType.prototype.toSource",
                                  InformalValueTypeName(args.thisv()));
   }
 
   // Create the appropriate string depending on whether we're sCTypeClass or
@@ -5076,17 +5087,17 @@ ABI::IsABI(JSObject* obj)
 bool
 ABI::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 0) {
     return ArgumentLengthError(cx, "ABI.prototype.toSource", "no", "s");
   }
 
-  JSObject* obj = JS_THIS_OBJECT(cx, vp);
+  JSObject* obj = GetThisObject(cx, args, "ABI.prototype.toSource");
   if (!obj)
     return false;
   if (!ABI::IsABI(obj)) {
     return IncompatibleThisProto(cx, "ABI.prototype.toSource",
                                  InformalValueTypeName(args.thisv()));
   }
 
   JSString* result;
@@ -5295,17 +5306,17 @@ PointerType::TargetTypeGetter(JSContext*
   MOZ_ASSERT(args.rval().isObject());
   return true;
 }
 
 bool
 PointerType::IsNull(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "PointerType.prototype.isNull"));
   if (!obj)
     return false;
   if (!CData::IsCDataMaybeUnwrap(&obj)) {
     return IncompatibleThisProto(cx, "PointerType.prototype.isNull",
                                  args.thisv());
   }
 
   // Get pointer type and base type.
@@ -5316,39 +5327,27 @@ PointerType::IsNull(JSContext* cx, unsig
   }
 
   void* data = *static_cast<void**>(CData::GetData(obj));
   args.rval().setBoolean(data == nullptr);
   return true;
 }
 
 bool
-PointerType::OffsetBy(JSContext* cx, const CallArgs& args, int offset)
-{
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, args.base()));
+PointerType::OffsetBy(JSContext* cx, const CallArgs& args, int offset, const char* name)
+{
+  RootedObject obj(cx, GetThisObject(cx, args, name));
   if (!obj)
     return false;
-  if (!CData::IsCDataMaybeUnwrap(&obj)) {
-    if (offset == 1) {
-      return IncompatibleThisProto(cx, "PointerType.prototype.increment",
-                                   args.thisv());
-    }
-    return IncompatibleThisProto(cx, "PointerType.prototype.decrement",
-                                 args.thisv());
-  }
+  if (!CData::IsCDataMaybeUnwrap(&obj))
+    return IncompatibleThisProto(cx, name, args.thisv());
 
   RootedObject typeObj(cx, CData::GetCType(obj));
-  if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
-    if (offset == 1) {
-      return IncompatibleThisType(cx, "PointerType.prototype.increment",
-                                  "non-PointerType CData", args.thisv());
-    }
-    return IncompatibleThisType(cx, "PointerType.prototype.decrement",
-                                "non-PointerType CData", args.thisv());
-  }
+  if (CType::GetTypeCode(typeObj) != TYPE_pointer)
+    return IncompatibleThisType(cx, name, "non-PointerType CData", args.thisv());
 
   RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
   if (!CType::IsSizeDefined(baseType)) {
     return UndefinedSizePointerError(cx, "modify", obj);
   }
 
   size_t elementSize = CType::GetSize(baseType);
   char* data = static_cast<char*>(*static_cast<void**>(CData::GetData(obj)));
@@ -5362,24 +5361,24 @@ PointerType::OffsetBy(JSContext* cx, con
   args.rval().setObject(*result);
   return true;
 }
 
 bool
 PointerType::Increment(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  return OffsetBy(cx, args, 1);
+  return OffsetBy(cx, args, 1, "PointerType.prototype.increment");
 }
 
 bool
 PointerType::Decrement(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  return OffsetBy(cx, args, -1);
+  return OffsetBy(cx, args, -1, "PointerType.prototype.decrement");
 }
 
 bool
 PointerType::ContentsGetter(JSContext* cx, const JS::CallArgs& args)
 {
   RootedObject obj(cx, &args.thisv().toObject());
   RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
   if (!CType::IsSizeDefined(baseType)) {
@@ -5854,17 +5853,17 @@ ArrayType::Setter(JSContext* cx, HandleO
     return false;
   return result.succeed();
 }
 
 bool
 ArrayType::AddressOfElement(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "ArrayType.prototype.addressOfElement"));
   if (!obj)
     return false;
   if (!CData::IsCDataMaybeUnwrap(&obj)) {
     return IncompatibleThisProto(cx, "ArrayType.prototype.addressOfElement",
                                  args.thisv());
   }
 
   RootedObject typeObj(cx, CData::GetCType(obj));
@@ -6257,17 +6256,17 @@ StructType::BuildFFIType(JSContext* cx, 
 
   return Move(ffiType);
 }
 
 bool
 StructType::Define(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "StructType.prototype.define"));
   if (!obj)
     return false;
   if (!CType::IsCType(obj)) {
     return IncompatibleThisProto(cx, "StructType.prototype.define",
                                  args.thisv());
   }
   if (CType::GetTypeCode(obj) != TYPE_struct) {
     return IncompatibleThisType(cx, "StructType.prototype.define",
@@ -6549,20 +6548,21 @@ StructType::FieldSetter(JSContext* cx, u
   return ImplicitConvert(cx, args.get(0), field->mType, data, ConversionType::Setter, nullptr,
                          nullptr, 0, typeObj, field->mIndex);
 }
 
 bool
 StructType::AddressOfField(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "StructType.prototype.addressOfField"));
   if (!obj)
     return false;
- if (!CData::IsCDataMaybeUnwrap(&obj)) {
+
+  if (!CData::IsCDataMaybeUnwrap(&obj)) {
     return IncompatibleThisProto(cx, "StructType.prototype.addressOfField",
                                  args.thisv());
   }
 
   JSObject* typeObj = CData::GetCType(obj);
   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
     return IncompatibleThisType(cx, "StructType.prototype.addressOfField",
                                 "non-StructType CData", args.thisv());
@@ -7803,17 +7803,17 @@ CData::ValueSetter(JSContext* cx, const 
 bool
 CData::Address(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 0) {
     return ArgumentLengthError(cx, "CData.prototype.address", "no", "s");
   }
 
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "CData.prototype.address"));
   if (!obj)
     return false;
   if (!IsCDataMaybeUnwrap(&obj)) {
     return IncompatibleThisProto(cx, "CData.prototype.address", args.thisv());
   }
 
   RootedObject typeObj(cx, CData::GetCType(obj));
   RootedObject pointerType(cx, PointerType::CreateInternal(cx, typeObj));
@@ -7911,17 +7911,17 @@ static bool
 ReadStringCommon(JSContext* cx, InflateUTF8Method inflateUTF8, unsigned argc,
                  Value* vp, const char* funName)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 0) {
     return ArgumentLengthError(cx, funName, "no", "s");
   }
 
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, funName));
   if (!obj) {
     return IncompatibleThisProto(cx, funName, args.thisv());
   }
   if (!CData::IsCDataMaybeUnwrap(&obj)) {
       if (!CDataFinalizer::IsCDataFinalizer(obj)) {
           return IncompatibleThisProto(cx, funName, args.thisv());
       }
 
@@ -8060,17 +8060,17 @@ CData::GetSourceString(JSContext* cx, Ha
 bool
 CData::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 0) {
     return ArgumentLengthError(cx, "CData.prototype.toSource", "no", "s");
   }
 
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "CData.prototype.toSource"));
   if (!obj)
     return false;
   if (!CData::IsCDataMaybeUnwrap(&obj) && !CData::IsCDataProto(obj)) {
     return IncompatibleThisProto(cx, "CData.prototype.toSource",
                                  InformalValueTypeName(args.thisv()));
   }
 
   JSString* result;
@@ -8105,17 +8105,17 @@ CData::LastErrorGetter(JSContext* cx, co
   return true;
 }
 #endif // defined(XP_WIN)
 
 bool
 CDataFinalizer::Methods::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject objThis(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject objThis(cx, GetThisObject(cx, args, "CDataFinalizer.prototype.toSource"));
   if (!objThis)
     return false;
   if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.toSource",
                                  InformalValueTypeName(args.thisv()));
   }
 
   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
@@ -8164,17 +8164,17 @@ CDataFinalizer::Methods::ToSource(JSCont
   args.rval().setString(strMessage);
   return true;
 }
 
 bool
 CDataFinalizer::Methods::ToString(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  JSObject* objThis = JS_THIS_OBJECT(cx, vp);
+  JSObject* objThis = GetThisObject(cx, args, "CDataFinalizer.prototype.toString");
   if (!objThis)
     return false;
   if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.toString",
                                  InformalValueTypeName(args.thisv()));
   }
 
   JSString* strMessage;
@@ -8484,17 +8484,17 @@ bool
 CDataFinalizer::Methods::Forget(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 0) {
     return ArgumentLengthError(cx, "CDataFinalizer.prototype.forget", "no",
                                "s");
   }
 
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "CDataFinalizer.prototype.forget"));
   if (!obj)
     return false;
   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.forget",
                                  args.thisv());
   }
 
   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
@@ -8531,17 +8531,17 @@ bool
 CDataFinalizer::Methods::Dispose(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   if (args.length() != 0) {
     return ArgumentLengthError(cx, "CDataFinalizer.prototype.dispose", "no",
                                "s");
   }
 
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "CDataFinalizer.prototype.dispose"));
   if (!obj)
     return false;
   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.dispose",
                                  args.thisv());
   }
 
   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
@@ -8814,17 +8814,17 @@ Int64::IsInt64(JSObject* obj)
 {
   return JS_GetClass(obj) == &sInt64Class;
 }
 
 bool
 Int64::ToString(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "Int64.prototype.toString"));
   if (!obj)
     return false;
   if (!Int64::IsInt64(obj)) {
     if (!CData::IsCDataMaybeUnwrap(&obj)) {
       return IncompatibleThisProto(cx, "Int64.prototype.toString",
                                    InformalValueTypeName(args.thisv()));
     }
     return IncompatibleThisType(cx, "Int64.prototype.toString",
@@ -8833,17 +8833,17 @@ Int64::ToString(JSContext* cx, unsigned 
 
   return Int64Base::ToString(cx, obj, args, false);
 }
 
 bool
 Int64::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "Int64.prototype.toSource"));
   if (!obj)
     return false;
   if (!Int64::IsInt64(obj)) {
     if (!CData::IsCDataMaybeUnwrap(&obj)) {
       return IncompatibleThisProto(cx, "Int64.prototype.toSource",
                                    InformalValueTypeName(args.thisv()));
     }
     return IncompatibleThisType(cx, "Int64.prototype.toSource",
@@ -8998,17 +8998,17 @@ UInt64::IsUInt64(JSObject* obj)
 {
   return JS_GetClass(obj) == &sUInt64Class;
 }
 
 bool
 UInt64::ToString(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "UInt64.prototype.toString"));
   if (!obj)
     return false;
   if (!UInt64::IsUInt64(obj)) {
     if (!CData::IsCDataMaybeUnwrap(&obj)) {
       return IncompatibleThisProto(cx, "UInt64.prototype.toString",
                                    InformalValueTypeName(args.thisv()));
     }
     return IncompatibleThisType(cx, "UInt64.prototype.toString",
@@ -9017,17 +9017,17 @@ UInt64::ToString(JSContext* cx, unsigned
 
   return Int64Base::ToString(cx, obj, args, true);
 }
 
 bool
 UInt64::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+  RootedObject obj(cx, GetThisObject(cx, args, "UInt64.prototype.toSource"));
   if (!obj)
     return false;
   if (!UInt64::IsUInt64(obj)) {
     if (!CData::IsCDataMaybeUnwrap(&obj)) {
       return IncompatibleThisProto(cx, "UInt64.prototype.toSource",
                                    InformalValueTypeName(args.thisv()));
     }
     return IncompatibleThisType(cx, "UInt64.prototype.toSource",
--- a/js/src/ctypes/CTypes.h
+++ b/js/src/ctypes/CTypes.h
@@ -176,16 +176,18 @@ extern size_t
 GetDeflatedUTF8StringLength(JSContext* maybecx, const CharT* chars,
                             size_t charsLength);
 
 template <typename CharT>
 MOZ_MUST_USE bool
 DeflateStringToUTF8Buffer(JSContext* maybecx, const CharT* src, size_t srclen,
                           char* dst, size_t* dstlenp);
 
+MOZ_MUST_USE JSObject*
+GetThisObject(JSContext* cx, const CallArgs& args, const char* msg);
 
 /*******************************************************************************
 ** Function and struct API definitions
 *******************************************************************************/
 
 MOZ_ALWAYS_INLINE void
 ASSERT_OK(bool ok)
 {
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -208,19 +208,20 @@ Library::Finalize(JSFreeOp* fop, JSObjec
 {
   UnloadLibrary(obj);
 }
 
 bool
 Library::Open(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp);
+  JSObject* ctypesObj = GetThisObject(cx, args, "ctypes.open");
   if (!ctypesObj)
     return false;
+
   if (!IsCTypesGlobal(ctypesObj)) {
     JS_ReportErrorASCII(cx, "not a ctypes object");
     return false;
   }
 
   if (args.length() != 1 || args[0].isUndefined()) {
     JS_ReportErrorASCII(cx, "open requires a single argument");
     return false;
@@ -234,20 +235,21 @@ Library::Open(JSContext* cx, unsigned ar
   return true;
 }
 
 bool
 Library::Close(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
 
-  RootedObject obj(cx);
-  if (args.thisv().isObject())
-    obj = &args.thisv().toObject();
-  if (!obj || !IsLibrary(obj)) {
+  RootedObject obj(cx, GetThisObject(cx, args, "ctypes.close"));
+  if (!obj)
+    return false;
+
+  if (!IsLibrary(obj)) {
     JS_ReportErrorASCII(cx, "not a library");
     return false;
   }
 
   if (args.length() != 0) {
     JS_ReportErrorASCII(cx, "close doesn't take any arguments");
     return false;
   }
@@ -259,19 +261,21 @@ Library::Close(JSContext* cx, unsigned a
   args.rval().setUndefined();
   return true;
 }
 
 bool
 Library::Declare(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
-  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
+
+  RootedObject obj(cx, GetThisObject(cx, args, "ctypes.declare"));
   if (!obj)
     return false;
+
   if (!IsLibrary(obj)) {
     JS_ReportErrorASCII(cx, "not a library");
     return false;
   }
 
   PRLibrary* library = GetLibrary(obj);
   if (!library) {
     JS_ReportErrorASCII(cx, "library not open");
--- a/js/src/jit-test/tests/ctypes/incompatible-abi.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-abi.js
@@ -1,9 +1,9 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.default_abi.toSource.call(1); },
-                         "ABI.prototype.toSource called on incompatible Number");
+                         "ABI.prototype.toSource called on incompatible object, got the number 1");
 }
 
 if (typeof ctypes === "object")
   test();
--- a/js/src/jit-test/tests/ctypes/incompatible-array.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-array.js
@@ -1,13 +1,13 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.int32_t.array.call(1); },
-                         "CType.prototype.array called on incompatible object, got the object (new Number(1))");
+                         "CType.prototype.array called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t.array(10)().addressOfElement.call(1); },
-                         "ArrayType.prototype.addressOfElement called on incompatible object, got the object (new Number(1))");
+                         "ArrayType.prototype.addressOfElement called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t.array(10)().addressOfElement.call(ctypes.int32_t(0)); },
                          "ArrayType.prototype.addressOfElement called on non-ArrayType CData, got ctypes.int32_t(0)");
 }
 
 if (typeof ctypes === "object")
   test();
--- a/js/src/jit-test/tests/ctypes/incompatible-cdata.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-cdata.js
@@ -1,20 +1,20 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.int32_t(0).address.call(1); },
-                         "CData.prototype.address called on incompatible object, got the object (new Number(1))");
+                         "CData.prototype.address called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.char.array(10)("abc").readString.call(1); },
-                         "CData.prototype.readString called on incompatible object, got the object (new Number(1))");
+                         "CData.prototype.readString called on incompatible object, got the number 1");
 
   assertTypeErrorMessage(() => { ctypes.char.array(10)("abc").readStringReplaceMalformed.call(1); },
-                         "CData.prototype.readStringReplaceMalformed called on incompatible object, got the object (new Number(1))");
+                         "CData.prototype.readStringReplaceMalformed called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t(0).toSource.call(1); },
-                         "CData.prototype.toSource called on incompatible Number");
+                         "CData.prototype.toSource called on incompatible object, got the number 1");
 
   let p = Object.getPrototypeOf(ctypes.int32_t());
   let o = {};
   Object.setPrototypeOf(o, p);
   assertTypeErrorMessage(() => { o.readString(); },
                          "CData.prototype.readString called on incompatible object, got <<error converting value to string>>");
   assertTypeErrorMessage(() => { o.readStringReplaceMalformed(); },
                          "CData.prototype.readStringReplaceMalformed called on incompatible object, got <<error converting value to string>>");
--- a/js/src/jit-test/tests/ctypes/incompatible-ctype.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-ctype.js
@@ -1,11 +1,11 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.int32_t.toString.call(1); },
-                         "CType.prototype.toString called on incompatible Number");
+                         "CType.prototype.toString called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t.toSource.call(1); },
-                         "CType.prototype.toSource called on incompatible Number");
+                         "CType.prototype.toSource called on incompatible object, got the number 1");
 }
 
 if (typeof ctypes === "object")
   test();
--- a/js/src/jit-test/tests/ctypes/incompatible-finalizer.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-finalizer.js
@@ -1,20 +1,20 @@
 load(libdir + 'asserts.js');
 
 function test() {
   let fin = ctypes.CDataFinalizer(ctypes.int32_t(0), ctypes.FunctionType(ctypes.default_abi, ctypes.int32_t, [ctypes.int32_t]).ptr(x => x));
   assertTypeErrorMessage(() => { fin.toSource.call(1); },
-                         "CDataFinalizer.prototype.toSource called on incompatible Number");
+                         "CDataFinalizer.prototype.toSource called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { fin.toString.call(1); },
-                         "CDataFinalizer.prototype.toString called on incompatible Number");
+                         "CDataFinalizer.prototype.toString called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { fin.forget.call(1); },
-                         "CDataFinalizer.prototype.forget called on incompatible object, got the object (new Number(1))");
+                         "CDataFinalizer.prototype.forget called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { fin.dispose.call(1); },
-                         "CDataFinalizer.prototype.dispose called on incompatible object, got the object (new Number(1))");
+                         "CDataFinalizer.prototype.dispose called on incompatible object, got the number 1");
   fin.forget();
 
   assertTypeErrorMessage(() => { fin.readString(); },
                          "CDataFinalizer.prototype.readString called on empty CDataFinalizer");
   assertTypeErrorMessage(() => { fin.dispose(); },
                          "CDataFinalizer.prototype.dispose called on empty CDataFinalizer");
   assertTypeErrorMessage(() => { fin.forget(); },
                          "CDataFinalizer.prototype.forget called on empty CDataFinalizer");
--- a/js/src/jit-test/tests/ctypes/incompatible-int64.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-int64.js
@@ -1,24 +1,24 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.Int64(0).toString.call(1); },
-                         "Int64.prototype.toString called on incompatible Number");
+                         "Int64.prototype.toString called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.Int64(0).toString.call(ctypes.int32_t(0)); },
                          "Int64.prototype.toString called on non-Int64 CData");
   assertTypeErrorMessage(() => { ctypes.Int64(0).toSource.call(1); },
-                         "Int64.prototype.toSource called on incompatible Number");
+                         "Int64.prototype.toSource called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.Int64(0).toSource.call(ctypes.int32_t(0)); },
                          "Int64.prototype.toSource called on non-Int64 CData");
 
   assertTypeErrorMessage(() => { ctypes.UInt64(0).toString.call(1); },
-                         "UInt64.prototype.toString called on incompatible Number");
+                         "UInt64.prototype.toString called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.UInt64(0).toString.call(ctypes.int32_t(0)); },
                          "UInt64.prototype.toString called on non-UInt64 CData");
   assertTypeErrorMessage(() => { ctypes.UInt64(0).toSource.call(1); },
-                         "UInt64.prototype.toSource called on incompatible Number");
+                         "UInt64.prototype.toSource called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.UInt64(0).toSource.call(ctypes.int32_t(0)); },
                          "UInt64.prototype.toSource called on non-UInt64 CData");
 }
 
 if (typeof ctypes === "object")
   test();
--- a/js/src/jit-test/tests/ctypes/incompatible-pointer.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-pointer.js
@@ -1,19 +1,19 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.int32_t.ptr(0).isNull.call(1); },
-                         "PointerType.prototype.isNull called on incompatible object, got the object (new Number(1))");
+                         "PointerType.prototype.isNull called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t.ptr(0).isNull.call({}); },
                          "PointerType.prototype.isNull called on incompatible object, got the object ({})");
   assertTypeErrorMessage(() => { ctypes.int32_t.ptr(0).increment.call(1); },
-                         "PointerType.prototype.increment called on incompatible object, got the object (new Number(1))");
+                         "PointerType.prototype.increment called on incompatible object,  got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t.ptr(0).increment.call(ctypes.int32_t(0)); },
                          "PointerType.prototype.increment called on non-PointerType CData, got ctypes.int32_t(0)");
   assertTypeErrorMessage(() => { ctypes.int32_t.ptr(0).decrement.call(1); },
-                         "PointerType.prototype.decrement called on incompatible object, got the object (new Number(1))");
+                         "PointerType.prototype.decrement called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.int32_t.ptr(0).decrement.call(ctypes.int32_t(0)); },
                          "PointerType.prototype.decrement called on non-PointerType CData, got ctypes.int32_t(0)");
 }
 
 if (typeof ctypes === "object")
   test();
--- a/js/src/jit-test/tests/ctypes/incompatible-struct.js
+++ b/js/src/jit-test/tests/ctypes/incompatible-struct.js
@@ -1,13 +1,13 @@
 load(libdir + 'asserts.js');
 
 function test() {
   assertTypeErrorMessage(() => { ctypes.StructType("a").define.call(1); },
-                         "StructType.prototype.define called on incompatible object, got the object (new Number(1))");
+                         "StructType.prototype.define called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.StructType("a").define.call(ctypes.int32_t); },
                          "StructType.prototype.define called on non-StructType, got ctypes.int32_t");
 
   let p = Object.getPrototypeOf(ctypes.StructType("a", [ { "x": ctypes.int32_t, } ])());
   let o = {};
   Object.setPrototypeOf(o, p);
   assertTypeErrorMessage(() => { let a = o.x; },
                          "StructType property getter called on incompatible object, got <<error converting value to string>>");
@@ -17,15 +17,15 @@ function test() {
   o = ctypes.int32_t(0);
   Object.setPrototypeOf(o, p);
   assertTypeErrorMessage(() => { let a = o.x; },
                          "StructType property getter called on non-StructType CData, got ctypes.int32_t(0)");
   assertTypeErrorMessage(() => { o.x = 1; },
                          "StructType property setter called on non-StructType CData, got ctypes.int32_t(0)");
 
   assertTypeErrorMessage(() => { ctypes.StructType("a", [])().addressOfField.call(1); },
-                         "StructType.prototype.addressOfField called on incompatible object, got the object (new Number(1))");
+                         "StructType.prototype.addressOfField called on incompatible object, got the number 1");
   assertTypeErrorMessage(() => { ctypes.StructType("a", [])().addressOfField.call(ctypes.int32_t(0)); },
                          "StructType.prototype.addressOfField called on non-StructType CData, got ctypes.int32_t(0)");
 }
 
 if (typeof ctypes === "object")
   test();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7977,20 +7977,23 @@ static const JSClass* GetDomClass() {
     return &dom_class;
 }
 #endif
 
 static bool
 dom_genericGetter(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
-    if (!obj)
-        return false;
-
+
+    if (!args.thisv().isObject()) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    RootedObject obj(cx, &args.thisv().toObject());
     if (JS_GetClass(obj) != &dom_class) {
         args.rval().set(UndefinedValue());
         return true;
     }
 
     JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
 
     const JSJitInfo* info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
@@ -7998,22 +8001,24 @@ dom_genericGetter(JSContext* cx, unsigne
     JSJitGetterOp getter = info->getter;
     return getter(cx, obj, val.toPrivate(), JSJitGetterCallArgs(args));
 }
 
 static bool
 dom_genericSetter(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
-    if (!obj)
-        return false;
-
     MOZ_ASSERT(args.length() == 1);
 
+    if (!args.thisv().isObject()) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    RootedObject obj(cx, &args.thisv().toObject());
     if (JS_GetClass(obj) != &dom_class) {
         args.rval().set(UndefinedValue());
         return true;
     }
 
     JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
 
     const JSJitInfo* info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
@@ -8024,20 +8029,23 @@ dom_genericSetter(JSContext* cx, unsigne
     args.rval().set(UndefinedValue());
     return true;
 }
 
 static bool
 dom_genericMethod(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
-    if (!obj)
-        return false;
-
+
+    if (!args.thisv().isObject()) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    RootedObject obj(cx, &args.thisv().toObject());
     if (JS_GetClass(obj) != &dom_class) {
         args.rval().set(UndefinedValue());
         return true;
     }
 
     JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
 
     const JSJitInfo* info = FUNCTION_VALUE_TO_JITINFO(args.calleev());