Bug 601709 - Remove the misnomer InstanceOf variant methods by replacing their uses with clearer if-not-class-then-report code. r=jwalden
authorTom Schuster <evilpies@gmail.com>
Mon, 11 Apr 2011 01:38:27 -0700
changeset 67943 43cef42964d755dd1abbddcb92c61fa6cc56fc1b
parent 67942 474e167e344acdc57eba2289233f1b95f4962756
child 67944 19df46c13176aaa46e87fab09164075818f64acf
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs601709
milestone2.2a1pre
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 601709 - Remove the misnomer InstanceOf variant methods by replacing their uses with clearer if-not-class-then-report code. r=jwalden
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsdate.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsregexp.cpp
js/src/jstypedarray.cpp
js/src/jsxml.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -131,20 +131,20 @@ class AutoVersionAPI
 
   public:
     explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
       : cx(cx),
         oldDefaultVersion(cx->getDefaultVersion()),
         oldHasVersionOverride(cx->isVersionOverridden()),
         oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
 #ifdef DEBUG
-        , oldCompileOptions(cx->getCompileOptions()) 
+        , oldCompileOptions(cx->getCompileOptions())
 #endif
     {
-        /* 
+        /*
          * Note: ANONFUNFIX in newVersion is ignored for backwards
          * compatibility, must be set via JS_SetOptions. (Because of this, we
          * inherit the current ANONFUNFIX setting from the options.
          */
         VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->getCompileOptions()));
         this->newVersion = newVersion;
         cx->clearVersionOverride();
         cx->setDefaultVersion(newVersion);
@@ -1228,17 +1228,17 @@ JS_EnterCrossCompartmentCallScript(JSCon
     CHECK_REQUEST(cx);
 
     JS_ASSERT(target);
     JSObject *scriptObject = target->u.object;
     if (!scriptObject) {
         SwitchToCompartment sc(cx, target->compartment);
         scriptObject = JS_NewGlobalObject(cx, &dummy_class);
         if (!scriptObject)
-            return NULL;        
+            return NULL;
     }
     return JS_EnterCrossCompartmentCall(cx, scriptObject);
 }
 
 JS_PUBLIC_API(void)
 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
 {
     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
@@ -1271,17 +1271,17 @@ bool
 AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
 {
     JS_ASSERT(!call);
     if (cx->compartment == target->compartment) {
         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
         return true;
     }
     call = JS_EnterCrossCompartmentCallScript(cx, target);
-    return call != NULL;    
+    return call != NULL;
 }
 
 } /* namespace JS */
 
 JS_PUBLIC_API(void *)
 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
 {
     CHECK_REQUEST(cx);
@@ -2928,17 +2928,22 @@ JS_GetClass(JSObject *obj)
 }
 #endif
 
 JS_PUBLIC_API(JSBool)
 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
+    if (obj->getJSClass() != clasp) {
+        if (argv)
+            ReportIncompatibleMethod(cx, Valueify(argv - 2), Valueify(clasp));
+        return false;
+    }
+    return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
 {
     assertSameCompartment(cx, obj, v);
     return HasInstance(cx, obj, Valueify(&v), bp);
 }
@@ -2954,17 +2959,17 @@ JS_SetPrivate(JSContext *cx, JSObject *o
 {
     obj->setPrivate(data);
     return true;
 }
 
 JS_PUBLIC_API(void *)
 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
 {
-    if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
+    if (JS_InstanceOf(cx, obj, clasp, argv))
         return NULL;
     return obj->getPrivate();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetPrototype(JSContext *cx, JSObject *obj)
 {
     JSObject *proto;
@@ -4707,17 +4712,17 @@ CompileFileHelper(JSContext *cx, JSObjec
                                      cx->findVersion());
     cx->free_(buf);
     if (!script)
         return NULL;
 
     JSObject *scriptObj = js_NewScriptObject(cx, script);
     if (!scriptObj)
         js_DestroyScript(cx, script);
-    
+
     return scriptObj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
@@ -4736,17 +4741,17 @@ JS_CompileFile(JSContext *cx, JSObject *
                 break;
             }
         }
 
         scriptObj = CompileFileHelper(cx, obj, NULL, filename, fp);
         if (fp != stdin)
             fclose(fp);
     } while (false);
-    
+
     LAST_FRAME_CHECKS(cx, scriptObj);
     return scriptObj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename,
                                   FILE *file, JSPrincipals *principals)
 {
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -167,17 +167,17 @@ js_StringIsIndex(JSLinearString *str, js
         {
             *indexp = index;
             return true;
         }
     }
     return false;
 }
 
-static bool 
+static bool
 ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
 {
     if (vp->isInt32()) {
         int32_t i = vp->toInt32();
         if (i < 0)
             goto error;
 
         *plength = (jsuint)(i);
@@ -298,25 +298,25 @@ JSObject::willBeSparseDenseArray(uintN r
     JS_ASSERT(isDenseArray());
     JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
 
     uintN cap = numSlots();
     JS_ASSERT(requiredCapacity >= cap);
 
     if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
         return true;
-    
+
     uintN minimalDenseCount = requiredCapacity / 4;
     if (newElementsHint >= minimalDenseCount)
         return false;
     minimalDenseCount -= newElementsHint;
 
     if (minimalDenseCount > cap)
         return true;
-    
+
     Value *elems = getDenseArrayElements();
     for (uintN i = 0; i < cap; i++) {
         if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount)
             return false;
     }
     return true;
 }
 
@@ -480,17 +480,17 @@ SetArrayElement(JSContext *cx, JSObject 
     return obj->setProperty(cx, idr.id(), &tmp, true);
 }
 
 #ifdef JS_TRACER
 JSBool JS_FASTCALL
 js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
 {
 #ifdef DEBUG
-    Class *origObjClasp = obj->clasp; 
+    Class *origObjClasp = obj->clasp;
 #endif
     jsuint u = jsuint(i);
     JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK);
 
     /* Partially check the CallInfo's storeAccSet is correct. */
     JS_ASSERT(obj->clasp == origObjClasp);
     return ret;
 }
@@ -1115,18 +1115,20 @@ BufferToString(JSContext *cx, StringBuff
 static JSBool
 array_toSource(JSContext *cx, uintN argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
-    if (!obj->isSlowArray() && !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))
+    if (!obj->isArray()) {
+        ReportIncompatibleMethod(cx, vp, &js_ArrayClass);
         return false;
+    }
 
     /* Find joins or cycles in the reachable object graph. */
     jschar *sharpchars;
     JSHashEntry *he = js_EnterSharpObject(cx, obj, NULL, &sharpchars);
     if (!he)
         return false;
     bool initiallySharp = IS_SHARP(he);
 
@@ -1478,17 +1480,17 @@ array_reverse(JSContext *cx, uintN argc,
         return false;
     vp->setObject(*obj);
 
     do {
         if (!obj->isDenseArray())
             break;
         if (js_PrototypeHasIndexedProperties(cx, obj))
             break;
-        
+
         /* An empty array or an array with no elements is already reversed. */
         if (len == 0 || obj->getDenseArrayCapacity() == 0)
             return true;
 
         /*
          * It's actually surprisingly complicated to reverse an array due to the
          * orthogonality of array length and array capacity while handling
          * leading and trailing holes correctly.  Reversing seems less likely to
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -190,17 +190,17 @@ TimeWithinDay(jsdouble t)
 
 static inline bool
 IsLeapYear(jsint year)
 {
     return year % 4 == 0 && (year % 100 || (year % 400 == 0));
 }
 
 static inline jsint
-DaysInYear(jsint year) 
+DaysInYear(jsint year)
 {
     return IsLeapYear(year) ? 366 : 365;
 }
 
 static inline jsint
 DaysInFebruary(jsint year)
 {
     return IsLeapYear(year) ? 29 : 28;
@@ -627,78 +627,78 @@ date_UTC(JSContext *cx, uintN argc, Valu
     msec_time = TIMECLIP(msec_time);
 
     vp->setNumber(msec_time);
     return JS_TRUE;
 }
 
 /*
  * Read and convert decimal digits from s[*i] into *result
- * while *i < limit. 
- * 
+ * while *i < limit.
+ *
  * Succeed if any digits are converted. Advance *i only
  * as digits are consumed.
  */
 static JSBool
 digits(size_t *result, const jschar *s, size_t *i, size_t limit)
 {
     size_t init = *i;
     *result = 0;
-    while (*i < limit && 
+    while (*i < limit &&
            ('0' <= s[*i] && s[*i] <= '9')) {
         *result *= 10;
         *result += (s[*i] - '0');
         ++(*i);
     }
     return (*i != init);
 }
 
-/* 
+/*
  * Read and convert decimal digits to the right of a decimal point,
  * representing a fractional integer, from s[*i] into *result
- * while *i < limit. 
- * 
+ * while *i < limit.
+ *
  * Succeed if any digits are converted. Advance *i only
  * as digits are consumed.
  */
 static JSBool
 fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit)
 {
     jsdouble factor = 0.1;
     size_t init = *i;
     *result = 0.0;
-    while (*i < limit && 
+    while (*i < limit &&
            ('0' <= s[*i] && s[*i] <= '9')) {
         *result += (s[*i] - '0') * factor;
         factor *= 0.1;
         ++(*i);
     }
     return (*i != init);
 }
 
-/* 
- * Read and convert exactly n decimal digits from s[*i] 
- * to s[min(*i+n,limit)] into *result. 
+/*
+ * Read and convert exactly n decimal digits from s[*i]
+ * to s[min(*i+n,limit)] into *result.
  *
  * Succeed if exactly n digits are converted. Advance *i only
  * on success.
  */
 static JSBool
 ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
 {
     size_t init = *i;
 
     if (digits(result, s, i, JS_MIN(limit, init+n)))
         return ((*i - init) == n);
-    
+
     *i = init;
     return JS_FALSE;
 }
 
-/* 
+/*
  * Parse a string in one of the date-time formats given by the W3C
  * "NOTE-datetime" specification. These formats make up a restricted
  * profile of the ISO 8601 format. Quoted here:
  *
  *   The formats are as follows. Exactly the components shown here
  *   must be present, with exactly this punctuation. Note that the "T"
  *   appears literally in the string, to indicate the beginning of the
  *   time element, as specified in ISO 8601.
@@ -709,33 +709,33 @@ ndigits(size_t n, size_t *result, const 
  *   The specification is silent on the meaning when fields are
  *   ommitted so the interpretations are a guess, but hopefully a
  *   reasonable one. We default the month to January, the day to the
  *   1st, and hours minutes and seconds all to 0. If the date is
  *   missing entirely then we assume 1970-01-01 so that the time can
  *   be aded to a date later. If the time is missing then we assume
  *   00:00 UTC.  If the time is present but the time zone field is
  *   missing then we use local time.
- * 
+ *
  * Date part:
  *
  *  Year:
  *     YYYY (eg 1997)
  *
  *  Year and month:
  *     YYYY-MM (eg 1997-07)
  *
  *  Complete date:
  *     YYYY-MM-DD (eg 1997-07-16)
  *
  * Time part:
  *
  *  Hours and minutes:
  *     Thh:mmTZD (eg T19:20+01:00)
- * 
+ *
  *  Hours, minutes and seconds:
  *     Thh:mm:ssTZD (eg T19:20:30+01:00)
  *
  *  Hours, minutes, seconds and a decimal fraction of a second:
  *     Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
  *
  * where:
  *
@@ -770,32 +770,32 @@ date_parseISOString(JSLinearString *str,
     size_t tzHour = 0;
     size_t tzMin = 0;
 
 #define PEEK(ch) (i < limit && s[i] == ch)
 
 #define NEED(ch)                                                     \
     JS_BEGIN_MACRO                                                   \
         if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
-    JS_END_MACRO 
+    JS_END_MACRO
 
 #define DONE_DATE_UNLESS(ch)                                            \
     JS_BEGIN_MACRO                                                      \
         if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
-    JS_END_MACRO 
+    JS_END_MACRO
 
 #define DONE_UNLESS(ch)                                            \
     JS_BEGIN_MACRO                                                 \
         if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
-    JS_END_MACRO 
+    JS_END_MACRO
 
 #define NEED_NDIGITS(n, field)                                      \
     JS_BEGIN_MACRO                                                  \
         if (!ndigits(n, &field, s, &i, limit)) { goto syntax; }     \
-    JS_END_MACRO 
+    JS_END_MACRO
 
     s = str->chars();
     limit = str->length();
 
     if (PEEK('+') || PEEK('-')) {
         if (PEEK('-'))
             dateMul = -1;
         ++i;
@@ -836,37 +836,37 @@ date_parseISOString(JSLinearString *str,
     } else {
         isLocalTime = JS_TRUE;
     }
 
  done:
     if (year > 275943 // ceil(1e8/365) + 1970
         || (month == 0 || month > 12)
         || (day == 0 || day > size_t(DaysInMonth(year,month)))
-        || hour > 24 
+        || hour > 24
         || ((hour == 24) && (min > 0 || sec > 0))
-        || min > 59 
+        || min > 59
         || sec > 59
         || tzHour > 23
-        || tzMin > 59) 
+        || tzMin > 59)
         goto syntax;
 
     if (i != limit)
         goto syntax;
 
     month -= 1; /* convert month to 0-based */
 
     msec = date_msecFromDate(dateMul * (jsdouble)year, month, day,
                              hour, min, sec,
                              frac * 1000.0);;
 
     if (isLocalTime) {
         msec = UTC(msec, cx);
     } else {
-        msec -= ((tzMul) * ((tzHour * msPerHour) 
+        msec -= ((tzMul) * ((tzHour * msPerHour)
                             + (tzMin * msPerMinute)));
     }
 
     if (msec < -8.64e15 || msec > 8.64e15)
         goto syntax;
 
     *result = msec;
 
@@ -1206,20 +1206,23 @@ date_now_tn(JSContext*)
 
 /*
  * Get UTC time from the date object. Returns false if the object is not
  * Date type.
  */
 static JSBool
 GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
 {
-    if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
-        return JS_FALSE;
+    if (!obj->isDate()) {
+        if (vp)
+            ReportIncompatibleMethod(cx, vp, &js_DateClass);
+        return false;
+    }
     *dp = obj->getDateUTCTime().toNumber();
-    return JS_TRUE;
+    return true;
 }
 
 /*
  * Set UTC time to a given time and invalidate cached local time.
  */
 static JSBool
 SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
 {
@@ -1383,18 +1386,23 @@ FillLocalTimes(JSContext *cx, JSObject *
 
     return true;
 }
 
 /* Cache the local times in obj, if necessary. */
 static inline JSBool
 GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
 {
-    if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
+    if (!obj)
         return false;
+    if (!obj->isDate()) {
+        if (vp)
+            ReportIncompatibleMethod(cx, vp, &js_DateClass);
+        return false;
+    }
 
     /* If the local time is undefined, we need to fill in the cached values. */
     if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
         if (!FillLocalTimes(cx, obj))
             return false;
     }
 
     if (time)
@@ -1674,18 +1682,20 @@ date_getTimezoneOffset(JSContext *cx, ui
 
 static JSBool
 date_setTime(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
-    if (!InstanceOf(cx, obj, &js_DateClass, vp + 2))
+    if (!obj->isDate()) {
+        ReportIncompatibleMethod(cx, vp, &js_DateClass);
         return false;
+    }
 
     if (argc == 0) {
         SetDateToNaN(cx, obj, vp);
         return true;
     }
 
     jsdouble result;
     if (!ValueToNumber(cx, vp[2], &result))
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -508,17 +508,17 @@ WrapEscapingClosure(JSContext *cx, JSSta
     return wfunobj;
 }
 
 static JSBool
 ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     LeaveTrace(cx);
 
-    if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
+    if (!obj->isNormalArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
@@ -561,17 +561,18 @@ ArgSetter(JSContext *cx, JSObject *obj, 
 #ifdef JS_TRACER
     // To be able to set a property here on trace, we would have to make
     // sure any updates also get written back to the trace native stack.
     // For simplicity, we just leave trace, since this is presumably not
     // a common operation.
     LeaveTrace(cx);
 #endif
 
-    if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
+
+    if (!obj->isNormalArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < obj->getArgsInitialLength()) {
             JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
             if (fp) {
                 JSScript *script = fp->functionScript();
@@ -657,17 +658,17 @@ args_enumerate(JSContext *cx, JSObject *
     return true;
 }
 
 static JSBool
 StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     LeaveTrace(cx);
 
-    if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
+    if (!obj->isStrictArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
@@ -683,17 +684,17 @@ StrictArgGetter(JSContext *cx, JSObject 
     }
     return true;
 }
 
 static JSBool
 
 StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
-    if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
+    if (!obj->isStrictArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < obj->getArgsInitialLength()) {
             obj->setArgsElement(arg, *vp);
             return true;
         }
@@ -1565,25 +1566,25 @@ fun_getProperty(JSContext *cx, JSObject 
      * and name.  If we didn't return early for slot != FUN_LENGTH, we would
      * clobber *vp with the native property value, instead of letting script
      * override that value in delegating objects.
      *
      * Note how that clobbering is what simulates JSPROP_READONLY for all of
      * the non-standard properties when the directly addressed object (obj)
      * is a function object (i.e., when this loop does not iterate).
      */
-    JSFunction *fun;
-    while (!(fun = (JSFunction *)
-                   GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
+
+    while (!obj->isFunction()) {
         if (slot != FUN_LENGTH)
             return true;
         obj = obj->getProto();
         if (!obj)
             return true;
     }
+    JSFunction *fun = obj->getFunctionPrivate();
 
     /* Find fun's top-most activation record. */
     JSStackFrame *fp;
     for (fp = js_GetTopStackFrame(cx);
          fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
          fp = fp->prev()) {
         continue;
     }
@@ -2112,25 +2113,17 @@ fun_toSource(JSContext *cx, uintN argc, 
 
 JSBool
 js_fun_call(JSContext *cx, uintN argc, Value *vp)
 {
     LeaveTrace(cx);
     Value fval = vp[1];
 
     if (!js_IsCallable(fval)) {
-        if (JSString *str = js_ValueToString(cx, fval)) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_INCOMPATIBLE_PROTO,
-                                     js_Function_str, js_call_str,
-                                     bytes.ptr());
-            }
-        }
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     Value *argv = vp + 2;
     Value thisv;
     if (argc == 0) {
         thisv.setUndefined();
     } else {
@@ -2157,25 +2150,17 @@ js_fun_call(JSContext *cx, uintN argc, V
 
 /* ES5 15.3.4.3 */
 JSBool
 js_fun_apply(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value fval = vp[1];
     if (!js_IsCallable(fval)) {
-        if (JSString *str = js_ValueToString(cx, fval)) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_INCOMPATIBLE_PROTO,
-                                     js_Function_str, js_apply_str,
-                                     bytes.ptr());
-            }
-        }
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     /* Step 2. */
     if (argc < 2 || vp[3].isNullOrUndefined())
         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
 
     /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
@@ -2364,24 +2349,17 @@ fun_isGenerator(JSContext *cx, uintN arg
 static JSBool
 fun_bind(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value &thisv = vp[1];
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
-        if (JSString *str = js_ValueToString(cx, thisv)) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_INCOMPATIBLE_PROTO,
-                                     js_Function_str, "bind", bytes.ptr());
-            }
-        }
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     JSObject *target = &thisv.toObject();
 
     /* Step 3. */
     Value *args = NULL;
     uintN argslen = 0;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1022,17 +1022,17 @@ CheckRedeclaration(JSContext *cx, JSObje
             return false;
     }
 
     /* We allow redeclaring some non-readonly properties. */
     if (((oldAttrs | attrs) & JSPROP_READONLY) == 0) {
         /* Allow redeclaration of variables and functions. */
         if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
             return true;
-        
+
         /*
          * Allow adding a getter only if a property already has a setter
          * but no getter and similarly for adding a setter. That is, we
          * allow only the following transitions:
          *
          *   no-property --> getter --> getter + setter
          *   no-property --> setter --> getter + setter
          */
@@ -1095,23 +1095,23 @@ LooselyEqual(JSContext *cx, const Value 
 #endif
 
     if (SameType(lval, rval)) {
         if (lval.isString()) {
             JSString *l = lval.toString();
             JSString *r = rval.toString();
             return EqualStrings(cx, l, r, result);
         }
-        
+
         if (lval.isDouble()) {
             double l = lval.toDouble(), r = rval.toDouble();
             *result = JSDOUBLE_COMPARE(l, ==, r, false);
             return true;
         }
-        
+
         if (lval.isObject()) {
             JSObject *l = &lval.toObject();
             JSObject *r = &rval.toObject();
             l->assertSpecialEqualitySynced();
 
             if (EqualityOp eq = l->getClass()->ext.equality) {
                 return eq(cx, l, &rval, result);
             }
@@ -1123,17 +1123,17 @@ LooselyEqual(JSContext *cx, const Value 
         *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
         return true;
     }
 
     if (lval.isNullOrUndefined()) {
         *result = rval.isNullOrUndefined();
         return true;
     }
-    
+
     if (rval.isNullOrUndefined()) {
         *result = false;
         return true;
     }
 
     Value lvalue = lval;
     Value rvalue = rval;
 
@@ -1241,34 +1241,16 @@ TypeOfValue(JSContext *cx, const Value &
     if (v.isUndefined())
         return JSTYPE_VOID;
     if (v.isObject())
         return v.toObject().typeOf(cx);
     JS_ASSERT(v.isBoolean());
     return JSTYPE_BOOLEAN;
 }
 
-bool
-InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
-{
-    JS_ASSERT(!obj || obj->getClass() != clasp);
-    if (argv) {
-        JSFunction *fun = js_ValueToFunction(cx, &argv[-2], 0);
-        if (fun) {
-            JSAutoByteString funNameBytes;
-            if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
-                                     clasp->name, funName,
-                                     obj ? obj->getClass()->name : js_null_str);
-            }
-        }
-    }
-    return false;
-}
-
 JS_REQUIRES_STACK bool
 InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
 {
     JS_ASSERT(!js_FunctionClass.construct);
     CallArgs args = argsRef;
 
     JSObject *callee;
     if (args.callee().isPrimitive() || !(callee = &args.callee().toObject())->getParent()) {
@@ -2365,17 +2347,17 @@ Interpret(JSContext *cx, JSStackFrame *e
 
 #define LOAD_FUNCTION(PCOFF)                                                  \
     (fun = script->getFunction(GET_FULL_INDEX(PCOFF)))
 
 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
     (dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
 
     bool useMethodJIT = false;
-    
+
 #ifdef JS_METHODJIT
 
 #define RESET_USE_METHODJIT()                                                 \
     JS_BEGIN_MACRO                                                            \
         useMethodJIT = cx->methodJitEnabled &&                                \
             interpMode == JSINTERP_NORMAL &&                                  \
             script->getJITStatus(regs.fp->isConstructing()) != JITScript_Invalid; \
     JS_END_MACRO
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -1082,36 +1082,19 @@ LooselyEqual(JSContext *cx, const Value 
 
 /* === except that NaN is the same as NaN and -0 is not the same as +0. */
 extern bool
 SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
 
 extern JSType
 TypeOfValue(JSContext *cx, const Value &v);
 
-inline bool
-InstanceOf(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
-{
-    if (obj && obj->getClass() == clasp)
-        return true;
-    extern bool InstanceOfSlow(JSContext *, JSObject *, Class *, Value *);
-    return InstanceOfSlow(cx, obj, clasp, argv);
-}
-
 extern JSBool
 HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp);
 
-inline void *
-GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
-{
-    if (!InstanceOf(cx, obj, clasp, argv))
-        return NULL;
-    return obj->getPrivate();
-}
-
 extern bool
 ValueToId(JSContext *cx, const Value &v, jsid *idp);
 
 /*
  * @param closureLevel      The static level of the closure that the cookie
  *                          pertains to.
  * @param cookie            Level amount is a "skip" (delta) value from the
  *                          closure level.
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -588,19 +588,19 @@ GetIterator(JSContext *cx, JSObject *obj
              * objects here, as they are not inserted into the cache and
              * will result in a miss.
              */
             JSObject *last = cx->compartment->nativeIterCache.last;
             JSObject *proto = obj->getProto();
             if (last) {
                 NativeIterator *lastni = last->getNativeIterator();
                 if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
-                    obj->isNative() && 
+                    obj->isNative() &&
                     obj->shape() == lastni->shapes_array[0] &&
-                    proto && proto->isNative() && 
+                    proto && proto->isNative() &&
                     proto->shape() == lastni->shapes_array[1] &&
                     !proto->getProto()) {
                     vp->setObject(*last);
                     UpdateNativeIterator(lastni, obj);
                     RegisterEnumerator(cx, last, lastni);
                     return true;
                 }
             }
@@ -708,18 +708,22 @@ js_ThrowStopIteration(JSContext *cx)
         cx->setPendingException(v);
     return JS_FALSE;
 }
 
 static JSBool
 iterator_next(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
-    if (!obj || !InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
+    if (!obj)
         return false;
+    if (obj->getClass() != &js_IteratorClass) {
+        ReportIncompatibleMethod(cx, vp, &js_IteratorClass);
+        return false;
+    }
 
     if (!js_IteratorMore(cx, obj, vp))
         return false;
     if (!vp->toBoolean()) {
         js_ThrowStopIteration(cx);
         return false;
     }
     return js_IteratorNext(cx, obj, vp);
@@ -809,17 +813,17 @@ js_CloseIterator(JSContext *cx, JSObject
         return CloseGenerator(cx, obj);
     }
 #endif
     return JS_TRUE;
 }
 
 /*
  * Suppress enumeration of deleted properties. This function must be called
- * when a property is deleted and there might be active enumerators. 
+ * when a property is deleted and there might be active enumerators.
  *
  * We maintain a list of active non-escaping for-in enumerators. To suppress
  * a property, we check whether each active enumerator contains the (obj, id)
  * pair and has not yet enumerated |id|. If so, and |id| is the next property,
  * we simply advance the cursor. Otherwise, we delete |id| from the list.
  *
  * We do not suppress enumeration of a property deleted along an object's
  * prototype chain. Only direct deletions on the object are handled.
@@ -914,17 +918,17 @@ js_SuppressDeletedProperty(JSContext *cx
     return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
 }
 
 class IndexRangePredicate {
     jsint begin, end;
 public:
     IndexRangePredicate(jsint begin, jsint end) : begin(begin), end(end) {}
 
-    bool operator()(jsid id) { 
+    bool operator()(jsid id) {
         return JSID_IS_INT(id) && begin <= JSID_TO_INT(id) && JSID_TO_INT(id) < end;
     }
     bool matchesAtMostOne() { return false; }
 };
 
 bool
 js_SuppressDeletedIndexProperties(JSContext *cx, JSObject *obj, jsint begin, jsint end)
 {
@@ -1351,18 +1355,22 @@ CloseGenerator(JSContext *cx, JSObject *
  * Common subroutine of generator_(next|send|throw|close) methods.
  */
 static JSBool
 generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
 {
     LeaveTrace(cx);
 
     JSObject *obj = ToObject(cx, &vp[1]);
-    if (!obj || !InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
+    if (!obj)
         return JS_FALSE;
+    if (obj->getClass() != &js_GeneratorClass) {
+        ReportIncompatibleMethod(cx, vp, &js_GeneratorClass);
+        return JS_FALSE;
+    }
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         goto closed_generator;
     }
 
     if (gen->state == JSGEN_NEWBORN) {
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -87,17 +87,17 @@ resc_trace(JSTracer *trc, JSObject *obj)
 {
     void *pdata = obj->getPrivate();
     JS_ASSERT(pdata);
     RegExpStatics *res = static_cast<RegExpStatics *>(pdata);
     res->mark(trc);
 }
 
 Class js::regexp_statics_class = {
-    "RegExpStatics", 
+    "RegExpStatics",
     JSCLASS_HAS_PRIVATE,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
@@ -141,17 +141,17 @@ js_CloneRegExpObject(JSContext *cx, JSOb
     JS_ASSERT(obj->getClass() == &js_RegExpClass);
     JS_ASSERT(proto);
     JS_ASSERT(proto->getClass() == &js_RegExpClass);
 
     JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent());
     if (!clone)
         return NULL;
 
-    /* 
+    /*
      * This clone functionality does not duplicate the JITted code blob, which is necessary for
      * cross-compartment cloning functionality.
      */
     assertSameCompartment(cx, obj, clone);
 
     RegExpStatics *res = cx->regExpStatics();
     RegExp *re = RegExp::extractFrom(obj);
     {
@@ -493,18 +493,20 @@ js::Class js_RegExpClass = {
 
 /*
  * RegExp instance methods.
  */
 
 JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
 {
-    if (!InstanceOf(cx, obj, &js_RegExpClass, vp + 2))
+    if (!obj->isRegExp()) {
+        ReportIncompatibleMethod(cx, vp, &js_RegExpClass);
         return false;
+    }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re) {
         *vp = StringValue(cx->runtime->emptyString);
         return true;
     }
 
     JSLinearString *src = re->getSource();
@@ -624,17 +626,17 @@ ExecuteRegExp(JSContext *cx, ExecType ex
         }
         return false;
     }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
         return true;
 
-    /* 
+    /*
      * Code execution under this call could swap out the guts of |obj|, so we
      * have to take a defensive refcount here.
      */
     AutoRefCount<RegExp> arc(cx, NeedsIncRef<RegExp>(re));
     RegExpStatics *res = cx->regExpStatics();
 
     /* Step 2. */
     JSString *input;
@@ -766,17 +768,17 @@ CompileRegExpAndSwap(JSContext *cx, JSOb
     JSString *sourceStr;
     if (sourceValue.isUndefined()) {
         sourceStr = cx->runtime->emptyString;
     } else {
         /* Coerce to string and compile. */
         sourceStr = js_ValueToString(cx, sourceValue);
         if (!sourceStr)
             return false;
-    }  
+    }
 
     uintN flags = 0;
     if (argc > 1 && !argv[1].isUndefined()) {
         JSString *flagStr = js_ValueToString(cx, argv[1]);
         if (!flagStr)
             return false;
         argv[1].setString(flagStr);
         if (!RegExp::parseFlags(cx, flagStr, &flags))
@@ -789,18 +791,22 @@ CompileRegExpAndSwap(JSContext *cx, JSOb
 
     return SwapRegExpInternals(cx, obj, rval, escapedSourceStr, flags);
 }
 
 static JSBool
 regexp_compile(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
-    if (!obj || !InstanceOf(cx, obj, &js_RegExpClass, JS_ARGV(cx, vp)))
+    if (!obj)
         return false;
+    if (!obj->isRegExp()) {
+        ReportIncompatibleMethod(cx, vp, &js_RegExpClass);
+        return false;
+    }
 
     return CompileRegExpAndSwap(cx, obj, argc, JS_ARGV(cx, vp), &JS_RVAL(cx, vp));
 }
 
 static JSBool
 regexp_construct(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = JS_ARGV(cx, vp);
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -432,26 +432,26 @@ struct uint8_clamped {
         val = (x >= 0)
               ? ((x < 255)
                  ? uint8(x)
                  : 255)
               : 0;
         return *this;
     }
 
-    inline uint8_clamped& operator= (int32 x) { 
+    inline uint8_clamped& operator= (int32 x) {
         val = (x >= 0)
               ? ((x < 255)
                  ? uint8(x)
                  : 255)
               : 0;
         return *this;
     }
 
-    inline uint8_clamped& operator= (const jsdouble x) { 
+    inline uint8_clamped& operator= (const jsdouble x) {
         val = uint8(js_TypedArray_uint8_clamp_double(x));
         return *this;
     }
 
     inline operator uint8() const {
         return val;
     }
 };
@@ -838,24 +838,19 @@ class TypedArrayTemplate
     /* subarray(start[, end]) */
     static JSBool
     fun_subarray(JSContext *cx, uintN argc, Value *vp)
     {
         JSObject *obj = ToObject(cx, &vp[1]);
         if (!obj)
             return false;
 
-        if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2))
-            return false;
-
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this subarray() to the wrong class
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_INCOMPATIBLE_METHOD,
-                                 fastClass()->name, "subarray", obj->getClass()->name);
+            ReportIncompatibleMethod(cx, vp, fastClass());
             return false;
         }
 
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         if (!tarray)
             return true;
 
         // these are the default values
@@ -900,24 +895,19 @@ class TypedArrayTemplate
     /* set(array[, offset]) */
     static JSBool
     fun_set(JSContext *cx, uintN argc, Value *vp)
     {
         JSObject *obj = ToObject(cx, &vp[1]);
         if (!obj)
             return false;
 
-        if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2))
-            return false;
-
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this set() to the wrong class
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_INCOMPATIBLE_METHOD,
-                                 fastClass()->name, "set", obj->getClass()->name);
+            ReportIncompatibleMethod(cx, vp, fastClass());
             return false;
         }
 
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         if (!tarray)
             return true;
 
         // these are the default values
@@ -1135,17 +1125,17 @@ class TypedArrayTemplate
             return NativeType(dval);
         }
 
         if (ArrayTypeIsFloatingPoint())
             return NativeType(js_NaN);
 
         return NativeType(int32(0));
     }
-    
+
     static bool
     copyFrom(JSContext *cx, JSObject *thisTypedArrayObj,
              JSObject *ar, jsuint len, jsuint offset = 0)
     {
         ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
         JS_ASSERT(thisTypedArray);
 
         JS_ASSERT(offset <= thisTypedArray->length);
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -259,18 +259,20 @@ static JSPropertySpec namespace_props[] 
 };
 
 static JSBool
 namespace_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return JS_FALSE;
-    if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), Jsvalify(vp + 2)))
+    if (!obj->isNamespace()) {
+        ReportIncompatibleMethod(cx, vp, &js_NamespaceClass);
         return JS_FALSE;
+    }
     *vp = Valueify(obj->getNameURIVal());
     return JS_TRUE;
 }
 
 static JSFunctionSpec namespace_methods[] = {
     JS_FN(js_toString_str,  namespace_toString,        0,0),
     JS_FS_END
 };
@@ -451,18 +453,20 @@ ConvertQNameToString(JSContext *cx, JSOb
 
 static JSBool
 qname_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
-    if (!InstanceOf(cx, obj, &js_QNameClass, vp + 2))
+    if (!obj->isQName()) {
+        ReportIncompatibleMethod(cx, vp, &js_QNameClass);
         return false;
+    }
 
     JSString *str = ConvertQNameToString(cx, obj);
     if (!str)
         return false;
 
     vp->setString(str);
     return true;
 }
@@ -1427,17 +1431,17 @@ ParseNodeToXML(Parser *parser, JSParseNo
             if (pn2->pn_type != TOK_XMLNAME || pn2->pn_arity != PN_NULLARY)
                 goto syntax;
 
             /* Enforce "Well-formedness constraint: Unique Att Spec". */
             for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) {
                 if (pn3->pn_atom == pn2->pn_atom) {
                     Value v = StringValue(pn2->pn_atom);
                     JSAutoByteString bytes;
-                    if (js_ValueToPrintable(cx, v, &bytes)) { 
+                    if (js_ValueToPrintable(cx, v, &bytes)) {
                         ReportCompileErrorNumber(cx, &parser->tokenStream, pn2,
                                                  JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR,
                                                  bytes.ptr());
                     }
                     goto fail;
                 }
             }
 
@@ -1568,17 +1572,17 @@ ParseNodeToXML(Parser *parser, JSParseNo
         if (pn->pn_type == TOK_XMLCOMMENT) {
             if (flags & XSF_IGNORE_COMMENTS)
                 goto skip_child;
             xml_class = JSXML_CLASS_COMMENT;
         } else if (pn->pn_type == TOK_XMLPI) {
             if (IS_XML(str)) {
                 Value v = StringValue(str);
                 JSAutoByteString bytes;
-                if (js_ValueToPrintable(cx, v, &bytes)) { 
+                if (js_ValueToPrintable(cx, v, &bytes)) {
                     ReportCompileErrorNumber(cx, &parser->tokenStream, pn,
                                              JSREPORT_ERROR, JSMSG_RESERVED_ID, bytes.ptr());
                 }
                 goto fail;
             }
 
             if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS)
                 goto skip_child;
@@ -3725,17 +3729,19 @@ static JSBool
 GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     JSXML *xml, *list, *kid;
     uint32 index;
     JSObject *kidobj, *listobj;
     JSObject *nameqn;
     jsid funid;
 
-    xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
+    if (!obj->isXML())
+        return true;
+    xml = (JSXML *) obj->getPrivate();
     if (!xml)
         return true;
 
     if (js_IdIsIndex(id, &index)) {
         if (!JSXML_HAS_KIDS(xml)) {
             *vp = (index == 0) ? OBJECT_TO_JSVAL(obj) : JSVAL_VOID;
         } else {
             /*
@@ -3842,17 +3848,19 @@ PutProperty(JSContext *cx, JSObject *obj
     JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match;
     JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj;
     JSObject *targetprop, *nameqn, *attrqn;
     uint32 index, i, j, k, n, q, matchIndex;
     jsval attrval, nsval;
     jsid funid;
     JSObject *ns;
 
-    xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
+    if (!obj->isXML())
+        return JS_TRUE;
+    xml = (JSXML *) obj->getPrivate();
     if (!xml)
         return JS_TRUE;
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
     if (!xml)
         return JS_FALSE;
 
     /* Precompute vxml for 9.2.1.2 2(c)(vii)(2-3) and 2(d) and 9.1.1.2 1. */
@@ -4994,17 +5002,17 @@ again:
 }
 
 /*
  * 11.2.2.1 Step 3(d) onward.
  */
 JSBool
 js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL));
+    JS_ASSERT(obj->isXML());
 
     if (JSID_IS_OBJECT(id)) {
         jsid funid;
 
         if (!js_IsFunctionQName(cx, JSID_TO_OBJECT(id), &funid))
             return JS_FALSE;
         if (!JSID_IS_VOID(funid))
             id = funid;
@@ -5034,17 +5042,17 @@ js_TestXMLEquality(JSContext *cx, const 
     if (v1.isObject() && v1.toObject().isXML()) {
         obj = &v1.toObject();
         v = Jsvalify(v2);
     } else {
         v = Jsvalify(v1);
         obj = &v2.toObject();
     }
 
-    JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL));
+    JS_ASSERT(obj->isXML());
 
     xml = (JSXML *) obj->getPrivate();
     vxml = NULL;
     if (!JSVAL_IS_PRIMITIVE(v)) {
         vobj = JSVAL_TO_OBJECT(v);
         if (vobj->isXML())
             vxml = (JSXML *) vobj->getPrivate();
     }
@@ -5106,17 +5114,17 @@ js_TestXMLEquality(JSContext *cx, const 
 
 JSBool
 js_ConcatenateXML(JSContext *cx, JSObject *obj, JSObject *robj, Value *vp)
 {
     JSBool ok;
     JSObject *listobj;
     JSXML *list, *lxml, *rxml;
 
-    JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL));
+    JS_ASSERT(obj->isXML());
     ok = js_EnterLocalRootScope(cx);
     if (!ok)
         return JS_FALSE;
 
     listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
     if (!listobj) {
         ok = JS_FALSE;
         goto out;
@@ -5183,17 +5191,21 @@ StartNonListXMLMethod(JSContext *cx, jsv
     JSFunction *fun;
     char numBuf[12];
 
     JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp));
 
     *objp = ToObject(cx, Valueify(&vp[1]));
     if (!*objp)
         return NULL;
-    xml = (JSXML *) GetInstancePrivate(cx, *objp, &js_XMLClass, Valueify(vp + 2));
+    if (!(*objp)->isXML()) {
+        ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass);
+        return NULL;
+    }
+    xml = (JSXML *) (*objp)->getPrivate();
     if (!xml || xml->xml_class != JSXML_CLASS_LIST)
         return xml;
 
     if (xml->xml_kids.length == 1) {
         xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
         if (xml) {
             *objp = js_GetXMLObject(cx, xml);
             if (!*objp)
@@ -5213,17 +5225,21 @@ StartNonListXMLMethod(JSContext *cx, jsv
     return NULL;
 }
 
 /* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */
 #define XML_METHOD_PROLOG                                                     \
     JSObject *obj = ToObject(cx, Valueify(&vp[1]));                           \
     if (!obj)                                                                 \
         return JS_FALSE;                                                      \
-    JSXML *xml = (JSXML *)GetInstancePrivate(cx, obj, &js_XMLClass, Valueify(vp+2)); \
+    if (!obj->isXML()) {                                                      \
+        ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass);             \
+        return JS_FALSE;                                                      \
+    }                                                                         \
+    JSXML *xml = (JSXML *)obj->getPrivate();                                  \
     if (!xml)                                                                 \
         return JS_FALSE
 
 #define NON_LIST_XML_METHOD_PROLOG                                            \
     JSObject *obj;                                                            \
     JSXML *xml = StartNonListXMLMethod(cx, vp, &obj);                         \
     if (!xml)                                                                 \
         return JS_FALSE;                                                      \
@@ -5696,18 +5712,20 @@ static JSBool
 xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval name;
     JSBool found;
 
     JSObject *obj = ToObject(cx, Valueify(&vp[1]));
     if (!obj)
         return JS_FALSE;
-    if (!InstanceOf(cx, obj, &js_XMLClass, Valueify(vp + 2)))
+    if (!obj->isXML()) {
+        ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass);
         return JS_FALSE;
+    }
 
     name = argc != 0 ? vp[2] : JSVAL_VOID;
     if (!HasProperty(cx, obj, name, &found))
         return JS_FALSE;
     if (found) {
         *vp = JSVAL_TRUE;
         return JS_TRUE;
     }
@@ -7501,25 +7519,22 @@ GetXMLFunction(JSContext *cx, JSObject *
 
     JS_ASSERT(tvr.object());
     return tvr.object()->getProperty(cx, id, Valueify(vp));
 }
 
 static JSXML *
 GetPrivate(JSContext *cx, JSObject *obj, const char *method)
 {
-    JSXML *xml;
-
-    xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
-    if (!xml) {
+    if (!obj->isXML()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_METHOD,
                              js_XML_str, method, obj->getClass()->name);
     }
-    return xml;
+    return (JSXML *)obj->getPrivate();
 }
 
 JSBool
 js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     JSXML *xml, *list;
 
     xml = GetPrivate(cx, obj, "descendants internal method");