Bug 728423 - Fix warnings in js/src related to JSObject::asString et al (r=luke)
authorJeff Walden <jwalden@mit.edu>
Mon, 20 Feb 2012 13:56:10 -0800
changeset 87253 f07a6060cc5a15f7435d1429dad813baf8992687
parent 87252 ac02ca06e1273e3c0d4e73589fd6655767d3fc26
child 87254 f25d65f080f81dd7256ae593677a858dd628dcda
push id22103
push userbmo@edmorley.co.uk
push dateTue, 21 Feb 2012 12:01:45 +0000
treeherdermozilla-central@4038ffaa5d82 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs728423
milestone13.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 728423 - Fix warnings in js/src related to JSObject::asString et al (r=luke)
js/src/Makefile.in
js/src/builtin/MapObject.cpp
js/src/builtin/RegExp.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsdate.cpp
js/src/jsfun.cpp
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsproxy.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsweakmap.cpp
js/src/jsxml.cpp
js/src/vm/MethodGuard-inl.h
js/src/vm/MethodGuard.cpp
js/src/vm/MethodGuard.h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -148,16 +148,17 @@ CPPSRCS		= \
 		jswrapper.cpp \
 		jsxdrapi.cpp \
 		jsxml.cpp \
 		prmjtime.cpp \
 		sharkctl.cpp \
 		ScopeObject.cpp \
 		Debugger.cpp \
 		GlobalObject.cpp \
+		MethodGuard.cpp \
 		Stack.cpp \
 		String.cpp \
 		BytecodeCompiler.cpp \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -40,16 +40,17 @@
 
 #include "builtin/MapObject.h"
 
 #include "jscntxt.h"
 #include "jsgcmark.h"
 #include "jsobj.h"
 
 #include "vm/GlobalObject.h"
+#include "vm/MethodGuard.h"
 #include "vm/Stack.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
 static JSObject *
 InitClass(JSContext *cx, GlobalObject *global, Class *clasp, JSProtoKey key, Native construct,
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -37,16 +37,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "jscntxt.h"
 
 #include "builtin/RegExp.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 class RegExpMatchBuilder
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -87,16 +87,17 @@
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Util.h"
 #include "yarr/BumpPointerAllocator.h"
+#include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/RegExpObject-inl.h"
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -122,16 +122,17 @@
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jswrapper.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/StubCalls.h"
 #include "methodjit/StubCalls-inl.h"
 
 #include "vm/ArgumentsObject.h"
+#include "vm/MethodGuard.h"
 
 #include "ds/Sort.h"
 
 #include "jsarrayinlines.h"
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -48,23 +48,25 @@
 #include "jscntxt.h"
 #include "jsinfer.h"
 #include "jsversion.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstr.h"
 
-#include "vm/BooleanObject-inl.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "vm/BooleanObject-inl.h"
+#include "vm/MethodGuard-inl.h"
+
 using namespace js;
 using namespace js::types;
 
 Class js::BooleanClass = {
     "Boolean",
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),    JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -74,16 +74,17 @@
 #include "jslibmath.h"
 
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::types;
 
 /*
  * The JS 'Date' object is patterned after the Java 'Date' object.
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -66,18 +66,19 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsexn.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TokenStream.h"
+#include "vm/Debugger.h"
+#include "vm/MethodGuard.h"
 #include "vm/ScopeObject.h"
-#include "vm/Debugger.h"
 
 #if JS_HAS_GENERATORS
 # include "jsiter.h"
 #endif
 
 #if JS_HAS_XDR
 # include "jsxdrapi.h"
 #endif
@@ -86,18 +87,18 @@
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
+#include "vm/ArgumentsObject-inl.h"
 #include "vm/ScopeObject-inl.h"
-#include "vm/ArgumentsObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 JSBool
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -71,16 +71,17 @@
 
 #include "ds/Sort.h"
 #include "frontend/TokenStream.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
 static void iterator_finalize(JSContext *cx, JSObject *obj);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -67,23 +67,25 @@
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsprf.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jslibmath.h"
 
 #include "vm/GlobalObject.h"
+#include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsnuminlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 /*
  * If we're accumulating a decimal number and the number is >= 2^53, then the
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -85,19 +85,17 @@
 
 #include "jsarrayinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsstrinlines.h"
 
-#include "vm/BooleanObject-inl.h"
-#include "vm/NumberObject-inl.h"
-#include "vm/StringObject-inl.h"
+#include "vm/MethodGuard-inl.h"
 
 #if JS_HAS_GENERATORS
 #include "jsiter.h"
 #endif
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
@@ -6356,59 +6354,16 @@ js_ReportGetterOnlyAssignment(JSContext 
 
 JS_FRIEND_API(JSBool)
 js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_GETTER_ONLY);
     return JS_FALSE;
 }
 
-void
-js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
-{
-    Value &thisv = call.thisv();
-
-#ifdef DEBUG
-    if (thisv.isObject()) {
-        JS_ASSERT(thisv.toObject().getClass() != clasp ||
-                  !thisv.toObject().getProto() ||
-                  thisv.toObject().getProto()->getClass() != clasp);
-    } else if (thisv.isString()) {
-        JS_ASSERT(clasp != &StringClass);
-    } else if (thisv.isNumber()) {
-        JS_ASSERT(clasp != &NumberClass);
-    } else if (thisv.isBoolean()) {
-        JS_ASSERT(clasp != &BooleanClass);
-    } else {
-        JS_ASSERT(thisv.isUndefined() || thisv.isNull());
-    }
-#endif
-
-    if (JSFunction *fun = js_ValueToFunction(cx, &call.calleev(), 0)) {
-        JSAutoByteString funNameBytes;
-        if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
-                                 clasp->name, funName, InformalValueTypeName(thisv));
-        }
-    }
-}
-
-bool
-js::HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp)
-{
-    if (args.thisv().isObject()) {
-        JSObject &thisObj = args.thisv().toObject();
-        if (thisObj.isProxy())
-            return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
-    }
-
-    ReportIncompatibleMethod(cx, args, clasp);
-    return false;
-}
-
 #ifdef DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -2025,76 +2025,11 @@ extern JSPrincipals *
 PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx);
 
 extern JSObject *
 NonNullObject(JSContext *cx, const Value &v);
 
 extern const char *
 InformalValueTypeName(const Value &v);
 
-/*
- * Report an error if call.thisv is not compatible with the specified class.
- *
- * NB: most callers should be calling or NonGenericMethodGuard,
- * HandleNonGenericMethodClassMismatch, or BoxedPrimitiveMethodGuard (so that
- * transparent proxies are handled correctly). Thus, any caller of this
- * function better have a good explanation for why proxies are being handled
- * correctly (e.g., by IsCallable) or are not an issue (E4X).
- */
-extern void
-ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
-
-/*
- * A non-generic method is specified to report an error if args.thisv is not an
- * object with a specific [[Class]] internal property (ES5 8.6.2).
- * NonGenericMethodGuard performs this checking. Canonical usage is:
- *
- *   CallArgs args = ...
- *   bool ok;
- *   JSObject *thisObj = NonGenericMethodGuard(cx, args, clasp, &ok);
- *   if (!thisObj)
- *     return ok;
- *
- * Specifically: if obj is a proxy, NonGenericMethodGuard will call the
- * object's ProxyHandler's nativeCall hook (which may recursively call
- * args.callee in args.thisv's compartment). Thus, there are three possible
- * post-conditions:
- *
- *   1. thisv is an object of the given clasp: the caller may proceed;
- *
- *   2. there was an error: the caller must return 'false';
- *
- *   3. thisv wrapped an object of the given clasp and the native was reentered
- *      and completed succesfully: the caller must return 'true'.
- *
- * Case 1 is indicated by a non-NULL return value; case 2 by a NULL return
- * value with *ok == false; and case 3 by a NULL return value with *ok == true.
- *
- * NB: since this guard may reenter the native, the guard must be placed before
- * any effectful operations are performed.
- */
-inline JSObject *
-NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok);
-
-/*
- * NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than
- * one class is acceptable (viz., isDenseArray() || isSlowArray()), the caller
- * may test the class and delegate to HandleNonGenericMethodClassMismatch to
- * handle the proxy case and error reporting. The 'clasp' argument is only used
- * for error reporting (clasp->name).
- */
-extern bool
-HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp);
-
-/*
- * Implement the extraction of a primitive from a value as needed for the
- * toString, valueOf, and a few other methods of the boxed primitives classes
- * Boolean, Number, and String (e.g., ES5 15.6.4.2). If 'true' is returned, the
- * extracted primitive is stored in |*v|. If 'false' is returned, the caller
- * must immediately 'return *ok'. For details, see NonGenericMethodGuard.
- */
-template <typename T>
-inline bool
-BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok);
-
 }  /* namespace js */
 
 #endif /* jsobj_h___ */
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1910,84 +1910,16 @@ PropDesc::checkSetter(JSContext *cx)
     if (hasSet && !js_IsCallable(set) && !set.isUndefined()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD,
                              js_setter_str);
         return false;
     }
     return true;
 }
 
-namespace detail {
-
-template<typename T> class PrimitiveBehavior { };
-
-template<>
-class PrimitiveBehavior<JSString *> {
-  public:
-    static inline bool isType(const Value &v) { return v.isString(); }
-    static inline JSString *extract(const Value &v) { return v.toString(); }
-    static inline JSString *extract(JSObject &obj) { return obj.asString().unbox(); }
-    static inline Class *getClass() { return &StringClass; }
-};
-
-template<>
-class PrimitiveBehavior<bool> {
-  public:
-    static inline bool isType(const Value &v) { return v.isBoolean(); }
-    static inline bool extract(const Value &v) { return v.toBoolean(); }
-    static inline bool extract(JSObject &obj) { return obj.asBoolean().unbox(); }
-    static inline Class *getClass() { return &BooleanClass; }
-};
-
-template<>
-class PrimitiveBehavior<double> {
-  public:
-    static inline bool isType(const Value &v) { return v.isNumber(); }
-    static inline double extract(const Value &v) { return v.toNumber(); }
-    static inline double extract(JSObject &obj) { return obj.asNumber().unbox(); }
-    static inline Class *getClass() { return &NumberClass; }
-};
-
-} /* namespace detail */
-
-inline JSObject *
-NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
-{
-    const Value &thisv = args.thisv();
-    if (thisv.isObject()) {
-        JSObject &obj = thisv.toObject();
-        if (obj.getClass() == clasp) {
-            *ok = true;  /* quell gcc overwarning */
-            return &obj;
-        }
-    }
-
-    *ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
-    return NULL;
-}
-
-template <typename T>
-inline bool
-BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok)
-{
-    typedef detail::PrimitiveBehavior<T> Behavior;
-
-    const Value &thisv = args.thisv();
-    if (Behavior::isType(thisv)) {
-        *v = Behavior::extract(thisv);
-        return true;
-    }
-
-    if (!NonGenericMethodGuard(cx, args, native, Behavior::getClass(), ok))
-        return false;
-
-    *v = Behavior::extract(thisv.toObject());
-    return true;
-}
-
 inline bool
 ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx)
 {
     if (JS_UNLIKELY(obj.isProxy()))
         return Proxy::objectClassIs(&obj, classValue, cx);
 
     switch (classValue) {
       case ESClass_Array: return obj.isArray();
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -45,16 +45,18 @@
 #include "jsgc.h"
 #include "jsgcmark.h"
 #include "jsprvtd.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 
+#include "vm/MethodGuard.h"
+
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 static inline HeapValue &
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -76,16 +76,17 @@
 #include "builtin/RegExp.h"
 #include "vm/GlobalObject.h"
 #include "vm/RegExpObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsautooplen.h"        // generated headers last
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -62,16 +62,18 @@
 
 #include "vm/GlobalObject.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
+#include "vm/MethodGuard-inl.h"
+
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 /*
  * Allocate array buffers with the maximum number of fixed slots marked as
  * reserved, so that the fixed slots may be used for the buffer's contents.
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -49,16 +49,18 @@
 #include "jsgcmark.h"
 #include "jsweakmap.h"
 
 #include "vm/GlobalObject.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/MethodGuard-inl.h"
+
 using namespace js;
 
 namespace js {
 
 bool
 WeakMapBase::markAllIteratively(JSTracer *tracer)
 {
     bool markedAny = false;
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -65,16 +65,17 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsxml.h"
 
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "vm/GlobalObject.h"
+#include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
new file mode 100644
--- /dev/null
+++ b/js/src/vm/MethodGuard-inl.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey method-guard code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MethodGuard_inl_h___
+#define MethodGuard_inl_h___
+
+#include "jsobj.h"
+
+#include "MethodGuard.h"
+
+#include "jsobjinlines.h"
+
+#include "BooleanObject-inl.h"
+#include "NumberObject-inl.h"
+#include "StringObject-inl.h"
+
+namespace js {
+
+namespace detail {
+
+template<typename T> class PrimitiveBehavior { };
+
+template<>
+class PrimitiveBehavior<bool> {
+  public:
+    static inline bool isType(const Value &v) { return v.isBoolean(); }
+    static inline bool extract(const Value &v) { return v.toBoolean(); }
+    static inline bool extract(JSObject &obj) { return obj.asBoolean().unbox(); }
+    static inline Class *getClass() { return &BooleanClass; }
+};
+
+template<>
+class PrimitiveBehavior<double> {
+  public:
+    static inline bool isType(const Value &v) { return v.isNumber(); }
+    static inline double extract(const Value &v) { return v.toNumber(); }
+    static inline double extract(JSObject &obj) { return obj.asNumber().unbox(); }
+    static inline Class *getClass() { return &NumberClass; }
+};
+
+template<>
+class PrimitiveBehavior<JSString *> {
+  public:
+    static inline bool isType(const Value &v) { return v.isString(); }
+    static inline JSString *extract(const Value &v) { return v.toString(); }
+    static inline JSString *extract(JSObject &obj) { return obj.asString().unbox(); }
+    static inline Class *getClass() { return &StringClass; }
+};
+
+} /* namespace detail */
+
+inline JSObject *
+NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
+{
+    const Value &thisv = args.thisv();
+    if (thisv.isObject()) {
+        JSObject &obj = thisv.toObject();
+        if (obj.getClass() == clasp) {
+            *ok = true;  /* quell gcc overwarning */
+            return &obj;
+        }
+    }
+
+    *ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
+    return NULL;
+}
+
+template <typename T>
+inline bool
+BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok)
+{
+    typedef detail::PrimitiveBehavior<T> Behavior;
+
+    const Value &thisv = args.thisv();
+    if (Behavior::isType(thisv)) {
+        *v = Behavior::extract(thisv);
+        return true;
+    }
+
+    if (!NonGenericMethodGuard(cx, args, native, Behavior::getClass(), ok))
+        return false;
+
+    *v = Behavior::extract(thisv.toObject());
+    return true;
+}
+
+} /* namespace js */
+
+#endif /* MethodGuard_inl_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/vm/MethodGuard.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey method-guard code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jsproxy.h"
+
+#include "MethodGuard.h"
+#include "Stack.h"
+
+#include "jsfuninlines.h"
+#include "jsobjinlines.h"
+
+using namespace js;
+
+void
+js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
+{
+    Value &thisv = call.thisv();
+
+#ifdef DEBUG
+    if (thisv.isObject()) {
+        JS_ASSERT(thisv.toObject().getClass() != clasp ||
+                  !thisv.toObject().getProto() ||
+                  thisv.toObject().getProto()->getClass() != clasp);
+    } else if (thisv.isString()) {
+        JS_ASSERT(clasp != &StringClass);
+    } else if (thisv.isNumber()) {
+        JS_ASSERT(clasp != &NumberClass);
+    } else if (thisv.isBoolean()) {
+        JS_ASSERT(clasp != &BooleanClass);
+    } else {
+        JS_ASSERT(thisv.isUndefined() || thisv.isNull());
+    }
+#endif
+
+    if (JSFunction *fun = js_ValueToFunction(cx, &call.calleev(), 0)) {
+        JSAutoByteString funNameBytes;
+        if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
+                                 clasp->name, funName, InformalValueTypeName(thisv));
+        }
+    }
+}
+
+bool
+js::HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp)
+{
+    if (args.thisv().isObject()) {
+        JSObject &thisObj = args.thisv().toObject();
+        if (thisObj.isProxy())
+            return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
+    }
+
+    ReportIncompatibleMethod(cx, args, clasp);
+    return false;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/vm/MethodGuard.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey method-guard code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Method prologue type-checking and unwrapping of the this parameter. */
+
+#ifndef MethodGuard_h___
+#define MethodGuard_h___
+
+#include "jsobj.h"
+
+namespace js {
+
+/*
+ * Report an error if call.thisv is not compatible with the specified class.
+ *
+ * NB: most callers should be calling or NonGenericMethodGuard,
+ * HandleNonGenericMethodClassMismatch, or BoxedPrimitiveMethodGuard (so that
+ * transparent proxies are handled correctly). Thus, any caller of this
+ * function better have a good explanation for why proxies are being handled
+ * correctly (e.g., by IsCallable) or are not an issue (E4X).
+ */
+extern void
+ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
+
+/*
+ * A non-generic method is specified to report an error if args.thisv is not an
+ * object with a specific [[Class]] internal property (ES5 8.6.2).
+ * NonGenericMethodGuard performs this checking. Canonical usage is:
+ *
+ *   CallArgs args = ...
+ *   bool ok;
+ *   JSObject *thisObj = NonGenericMethodGuard(cx, args, clasp, &ok);
+ *   if (!thisObj)
+ *     return ok;
+ *
+ * Specifically: if obj is a proxy, NonGenericMethodGuard will call the
+ * object's ProxyHandler's nativeCall hook (which may recursively call
+ * args.callee in args.thisv's compartment). Thus, there are three possible
+ * post-conditions:
+ *
+ *   1. thisv is an object of the given clasp: the caller may proceed;
+ *
+ *   2. there was an error: the caller must return 'false';
+ *
+ *   3. thisv wrapped an object of the given clasp and the native was reentered
+ *      and completed succesfully: the caller must return 'true'.
+ *
+ * Case 1 is indicated by a non-NULL return value; case 2 by a NULL return
+ * value with *ok == false; and case 3 by a NULL return value with *ok == true.
+ *
+ * NB: since this guard may reenter the native, the guard must be placed before
+ * any effectful operations are performed.
+ */
+inline JSObject *
+NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok);
+
+/*
+ * NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than
+ * one class is acceptable (viz., isDenseArray() || isSlowArray()), the caller
+ * may test the class and delegate to HandleNonGenericMethodClassMismatch to
+ * handle the proxy case and error reporting. The 'clasp' argument is only used
+ * for error reporting (clasp->name).
+ */
+extern bool
+HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp);
+
+/*
+ * Implement the extraction of a primitive from a value as needed for the
+ * toString, valueOf, and a few other methods of the boxed primitives classes
+ * Boolean, Number, and String (e.g., ES5 15.6.4.2). If 'true' is returned, the
+ * extracted primitive is stored in |*v|. If 'false' is returned, the caller
+ * must immediately 'return *ok'. For details, see NonGenericMethodGuard.
+ */
+template <typename T>
+inline bool
+BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok);
+
+} /* namespace js */
+
+#endif /* MethodGuard_h___ */