Bug 924720 - Part 4: Create new macros for easy Proxy JSClass creation. (r=jwalden)
authorEric Faust <efaustbmo@gmail.com>
Wed, 29 Jan 2014 17:20:16 -0800
changeset 165895 ae3ceb166be1b4bd28c60956d09b3107390101bb
parent 165894 1a0f8903f3ceb059163162bc4cd428c8b59889bf
child 165896 aac3d84c27c0846ef1d952a4d43962f8d6f88306
push id39065
push userefaustbmo@gmail.com
push dateThu, 30 Jan 2014 01:20:37 +0000
treeherdermozilla-inbound@f6395f80b24f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs924720
milestone29.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 924720 - Part 4: Create new macros for easy Proxy JSClass creation. (r=jwalden)
js/src/jsfriendapi.h
js/src/jsproxy.cpp
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -222,16 +222,183 @@ struct JSFunctionSpecWithHelp {
     {nullptr, nullptr, 0, 0, nullptr, nullptr}
 
 extern JS_FRIEND_API(bool)
 JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs);
 
 namespace js {
 
 /*
+ * Helper Macros for creating JSClasses that function as proxies.
+ *
+ * NB: The macro invocation must be surrounded by braces, so as to
+ *     allow for potention JSClass extensions.
+ */
+#define PROXY_MAKE_EXT(outerObject, innerObject, iteratorObject,        \
+                       isWrappedNative)                                 \
+    {                                                                   \
+        outerObject,                                                    \
+        innerObject,                                                    \
+        iteratorObject,                                                 \
+        isWrappedNative,                                                \
+        js::proxy_WeakmapKeyDelegate                                    \
+    }
+
+#define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, ext)         \
+    {                                                                                   \
+        name,                                                                           \
+        js::Class::NON_NATIVE |                                                         \
+            JSCLASS_IS_PROXY |                                                          \
+            JSCLASS_IMPLEMENTS_BARRIERS |                                               \
+            JSCLASS_HAS_RESERVED_SLOTS(js::PROXY_MINIMUM_SLOTS + (extraSlots)) |        \
+            flags,                                                                      \
+        JS_PropertyStub,         /* addProperty */                                      \
+        JS_DeletePropertyStub,   /* delProperty */                                      \
+        JS_PropertyStub,         /* getProperty */                                      \
+        JS_StrictPropertyStub,   /* setProperty */                                      \
+        JS_EnumerateStub,                                                               \
+        JS_ResolveStub,                                                                 \
+        js::proxy_Convert,                                                              \
+        js::proxy_Finalize,      /* finalize    */                                      \
+        callOp,                  /* call        */                                      \
+        js::proxy_HasInstance,   /* hasInstance */                                      \
+        constructOp,             /* construct   */                                      \
+        js::proxy_Trace,         /* trace       */                                      \
+        ext,                                                                            \
+        {                                                                               \
+            js::proxy_LookupGeneric,                                                    \
+            js::proxy_LookupProperty,                                                   \
+            js::proxy_LookupElement,                                                    \
+            js::proxy_LookupSpecial,                                                    \
+            js::proxy_DefineGeneric,                                                    \
+            js::proxy_DefineProperty,                                                   \
+            js::proxy_DefineElement,                                                    \
+            js::proxy_DefineSpecial,                                                    \
+            js::proxy_GetGeneric,                                                       \
+            js::proxy_GetProperty,                                                      \
+            js::proxy_GetElement,                                                       \
+            js::proxy_GetSpecial,                                                       \
+            js::proxy_SetGeneric,                                                       \
+            js::proxy_SetProperty,                                                      \
+            js::proxy_SetElement,                                                       \
+            js::proxy_SetSpecial,                                                       \
+            js::proxy_GetGenericAttributes,                                             \
+            js::proxy_SetGenericAttributes,                                             \
+            js::proxy_DeleteProperty,                                                   \
+            js::proxy_DeleteElement,                                                    \
+            js::proxy_DeleteSpecial,                                                    \
+            js::proxy_Watch, js::proxy_Unwatch,                                         \
+            js::proxy_Slice,                                                            \
+            nullptr,             /* enumerate       */                                  \
+            nullptr,             /* thisObject      */                                  \
+        }                                                                               \
+    }
+
+#define PROXY_CLASS_DEF(name, extraSlots, flags, callOp, constructOp)   \
+  PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp,    \
+                       PROXY_MAKE_EXT(                                  \
+                         nullptr, /* outerObject */                     \
+                         nullptr, /* innerObject */                     \
+                         nullptr, /* iteratorObject */                  \
+                         false    /* isWrappedNative */                 \
+                       ))
+
+/*
+ * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions.
+ *
+ * NB: Should not be called directly.
+ */
+
+extern JS_FRIEND_API(bool)
+proxy_LookupGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp,
+                    JS::MutableHandle<Shape*> propp);
+extern JS_FRIEND_API(bool)
+proxy_LookupProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
+                     JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
+extern JS_FRIEND_API(bool)
+proxy_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleObject objp,
+                    JS::MutableHandle<Shape*> propp);
+extern JS_FRIEND_API(bool)
+proxy_LookupSpecial(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
+                    JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
+extern JS_FRIEND_API(bool)
+proxy_DefineGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value,
+                    JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
+extern JS_FRIEND_API(bool)
+proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
+                     JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter,
+                     unsigned attrs);
+extern JS_FRIEND_API(bool)
+proxy_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value,
+                    JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
+extern JS_FRIEND_API(bool)
+proxy_DefineSpecial(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
+                    JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter,
+                    unsigned attrs);
+extern JS_FRIEND_API(bool)
+proxy_GetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
+                 JS::MutableHandleValue vp);
+extern JS_FRIEND_API(bool)
+proxy_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
+                  JS::Handle<PropertyName*> name, JS::MutableHandleValue vp);
+extern JS_FRIEND_API(bool)
+proxy_GetElement(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index,
+                 JS::MutableHandleValue vp);
+extern JS_FRIEND_API(bool)
+proxy_GetSpecial(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
+                 HandleSpecialId sid, JS::MutableHandleValue vp);
+extern JS_FRIEND_API(bool)
+proxy_SetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
+                 JS::MutableHandleValue bp, bool strict);
+extern JS_FRIEND_API(bool)
+proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
+                  JS::MutableHandleValue bp, bool strict);
+extern JS_FRIEND_API(bool)
+proxy_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp,
+                 bool strict);
+extern JS_FRIEND_API(bool)
+proxy_SetSpecial(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
+                 JS::MutableHandleValue vp, bool strict);
+extern JS_FRIEND_API(bool)
+proxy_GetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
+extern JS_FRIEND_API(bool)
+proxy_SetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
+extern JS_FRIEND_API(bool)
+proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
+                     bool *succeeded);
+extern JS_FRIEND_API(bool)
+proxy_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded);
+extern JS_FRIEND_API(bool)
+proxy_DeleteSpecial(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, bool *succeeded);
+
+extern JS_FRIEND_API(void)
+proxy_Trace(JSTracer *trc, JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+proxy_WeakmapKeyDelegate(JSObject *obj);
+extern JS_FRIEND_API(bool)
+proxy_Convert(JSContext *cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp);
+extern JS_FRIEND_API(void)
+proxy_Finalize(FreeOp *fop, JSObject *obj);
+extern JS_FRIEND_API(bool)
+proxy_HasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
+extern JS_FRIEND_API(bool)
+proxy_Call(JSContext *cx, unsigned argc, JS::Value *vp);
+extern JS_FRIEND_API(bool)
+proxy_Construct(JSContext *cx, unsigned argc, JS::Value *vp);
+extern JS_FRIEND_API(JSObject *)
+proxy_innerObject(JSContext *cx, JS::HandleObject obj);
+extern JS_FRIEND_API(bool)
+proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
+extern JS_FRIEND_API(bool)
+proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
+extern JS_FRIEND_API(bool)
+proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
+            JS::HandleObject result);
+
+/*
  * A class of objects that return source code on demand.
  *
  * When code is compiled with CompileOptions::LAZY_SOURCE, SpiderMonkey
  * doesn't retain the source code (and doesn't do lazy bytecode
  * generation). If we ever need the source code, say, in response to a call
  * to Function.prototype.toSource or Debugger.Source.prototype.text, then
  * we call the 'load' member function of the instance of this class that
  * has hopefully been registered with the runtime, passing the code's URL,
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2776,184 +2776,184 @@ Proxy::slice(JSContext *cx, HandleObject
             JS_ASSERT(!cx->isExceptionPending());
             return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
         }
         return false;
     }
     return handler->slice(cx, proxy, begin, end, result);
 }
 
-static JSObject *
-proxy_innerObject(JSContext *cx, HandleObject obj)
+JSObject *
+js::proxy_innerObject(JSContext *cx, HandleObject obj)
 {
     return obj->as<ProxyObject>().private_().toObjectOrNull();
 }
 
-static bool
-proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                    MutableHandleObject objp, MutableHandleShape propp)
+bool
+js::proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                        MutableHandleObject objp, MutableHandleShape propp)
 {
     bool found;
     if (!Proxy::has(cx, obj, id, &found))
         return false;
 
     if (found) {
         MarkNonNativePropertyFound(propp);
         objp.set(obj);
     } else {
         objp.set(nullptr);
         propp.set(nullptr);
     }
     return true;
 }
 
-static bool
-proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                     MutableHandleObject objp, MutableHandleShape propp)
+bool
+js::proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                         MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedId id(cx, NameToId(name));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
-static bool
-proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                    MutableHandleObject objp, MutableHandleShape propp)
+bool
+js::proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                        MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
-static bool
-proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                    MutableHandleObject objp, MutableHandleShape propp)
+bool
+js::proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                        MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedId id(cx, SPECIALID_TO_JSID(sid));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
-static bool
-proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
-                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+bool
+js::proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
+                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     Rooted<PropertyDescriptor> desc(cx);
     desc.object().set(obj);
     desc.value().set(value);
     desc.setAttributes(attrs & (~JSPROP_SHORTID));
     desc.setGetter(getter);
     desc.setSetter(setter);
     desc.setShortId(0);
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
 
-static bool
-proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
-                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+bool
+js::proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
+                         PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
-static bool
-proxy_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
-                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+bool
+js::proxy_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
+                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
-static bool
-proxy_DefineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue value,
-                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+bool
+js::proxy_DefineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue value,
+                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
-static bool
-proxy_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-                 MutableHandleValue vp)
+bool
+js::proxy_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                     MutableHandleValue vp)
 {
     return Proxy::get(cx, obj, receiver, id, vp);
 }
 
-static bool
-proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
-                  MutableHandleValue vp)
+bool
+js::proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
+                      MutableHandleValue vp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
-static bool
-proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
-                 MutableHandleValue vp)
+bool
+js::proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
+                     MutableHandleValue vp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
-static bool
-proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
-                 MutableHandleValue vp)
+bool
+js::proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
+                     MutableHandleValue vp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
-static bool
-proxy_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                 MutableHandleValue vp, bool strict)
+bool
+js::proxy_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                     MutableHandleValue vp, bool strict)
 {
     return Proxy::set(cx, obj, obj, id, strict, vp);
 }
 
-static bool
-proxy_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                  MutableHandleValue vp, bool strict)
+bool
+js::proxy_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                      MutableHandleValue vp, bool strict)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
-static bool
-proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
-                 MutableHandleValue vp, bool strict)
+bool
+js::proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
+                     MutableHandleValue vp, bool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
-static bool
-proxy_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                 MutableHandleValue vp, bool strict)
+bool
+js::proxy_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                     MutableHandleValue vp, bool strict)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
-static bool
-proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
+bool
+js::proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc, 0))
         return false;
     *attrsp = desc.attributes();
     return true;
 }
 
-static bool
-proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
+bool
+js::proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
     Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
     desc.setAttributes(*attrsp & (~JSPROP_SHORTID));
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
@@ -2963,39 +2963,46 @@ proxy_DeleteGeneric(JSContext *cx, Handl
 {
     bool deleted;
     if (!Proxy::delete_(cx, obj, id, &deleted))
         return false;
     *succeeded = deleted;
     return js_SuppressDeletedProperty(cx, obj, id);
 }
 
-static bool
-proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, bool *succeeded)
+bool
+js::proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, bool *succeeded)
 {
     RootedId id(cx, NameToId(name));
     return proxy_DeleteGeneric(cx, obj, id, succeeded);
 }
 
-static bool
-proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded)
+bool
+js::proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return proxy_DeleteGeneric(cx, obj, id, succeeded);
 }
 
-static bool
-proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, bool *succeeded)
+bool
+js::proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, bool *succeeded)
 {
     RootedId id(cx, SPECIALID_TO_JSID(sid));
     return proxy_DeleteGeneric(cx, obj, id, succeeded);
 }
 
+void
+js::proxy_Trace(JSTracer *trc, JSObject *obj)
+{
+    JS_ASSERT(obj->is<ProxyObject>());
+    ProxyObject::trace(trc, obj);
+}
+
 /* static */ void
 ProxyObject::trace(JSTracer *trc, JSObject *obj)
 {
     ProxyObject *proxy = &obj->as<ProxyObject>();
 
 #ifdef DEBUG
     if (!trc->runtime->gcDisableStrictProxyCheckingCount && proxy->is<WrapperObject>()) {
         JSObject *referent = &proxy->private_().toObject();
@@ -3027,198 +3034,110 @@ ProxyObject::trace(JSTracer *trc, JSObje
      * Allow for people to add extra slots to "proxy" classes, without allowing
      * them to set their own trace hook. Trace the extras.
      */
     unsigned numSlots = JSCLASS_RESERVED_SLOTS(proxy->getClass());
     for (unsigned i = PROXY_MINIMUM_SLOTS; i < numSlots; i++)
         MarkSlot(trc, proxy->slotOfClassSpecific(i), "class-specific");
 }
 
-static JSObject *
-proxy_WeakmapKeyDelegate(JSObject *obj)
+JSObject *
+js::proxy_WeakmapKeyDelegate(JSObject *obj)
 {
     JS_ASSERT(obj->is<ProxyObject>());
     return obj->as<ProxyObject>().handler()->weakmapKeyDelegate(obj);
 }
 
-static bool
-proxy_Convert(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp)
+bool
+js::proxy_Convert(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp)
 {
     JS_ASSERT(proxy->is<ProxyObject>());
     return Proxy::defaultValue(cx, proxy, hint, vp);
 }
 
-static void
-proxy_Finalize(FreeOp *fop, JSObject *obj)
+void
+js::proxy_Finalize(FreeOp *fop, JSObject *obj)
 {
     JS_ASSERT(obj->is<ProxyObject>());
     obj->as<ProxyObject>().handler()->finalize(fop, obj);
 }
 
-static bool
-proxy_HasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
+bool
+js::proxy_HasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
 {
     bool b;
     if (!Proxy::hasInstance(cx, proxy, v, &b))
         return false;
     *bp = !!b;
     return true;
 }
 
-static bool
-proxy_Call(JSContext *cx, unsigned argc, Value *vp)
+bool
+js::proxy_Call(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject proxy(cx, &args.callee());
     JS_ASSERT(proxy->is<ProxyObject>());
     return Proxy::call(cx, proxy, args);
 }
 
-static bool
-proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
+bool
+js::proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject proxy(cx, &args.callee());
     JS_ASSERT(proxy->is<ProxyObject>());
     return Proxy::construct(cx, proxy, args);
 }
 
-static bool
-proxy_Watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable)
+bool
+js::proxy_Watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable)
 {
     return Proxy::watch(cx, obj, id, callable);
 }
 
-static bool
-proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id)
+bool
+js::proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id)
 {
     return Proxy::unwatch(cx, obj, id);
 }
 
-static bool
-proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
-            HandleObject result)
+bool
+js::proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
+                HandleObject result)
 {
     return Proxy::slice(cx, proxy, begin, end, result);
 }
 
-#define PROXY_CLASS_EXT                             \
-    {                                               \
-        nullptr,             /* outerObject */      \
-        nullptr,             /* innerObject */      \
-        nullptr,             /* iteratorObject */   \
-        false,               /* isWrappedNative */  \
-        proxy_WeakmapKeyDelegate                    \
-    }
-
-#define PROXY_CLASS(callOp, constructOp) {          \
-    "Proxy",                                        \
-    Class::NON_NATIVE |                             \
-           JSCLASS_IS_PROXY |                       \
-           JSCLASS_IMPLEMENTS_BARRIERS |            \
-           JSCLASS_HAS_RESERVED_SLOTS(4) |          \
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),        \
-    JS_PropertyStub,         /* addProperty */      \
-    JS_DeletePropertyStub,   /* delProperty */      \
-    JS_PropertyStub,         /* getProperty */      \
-    JS_StrictPropertyStub,   /* setProperty */      \
-    JS_EnumerateStub,                               \
-    JS_ResolveStub,                                 \
-    proxy_Convert,                                  \
-    proxy_Finalize,          /* finalize    */      \
-    callOp,                  /* call        */      \
-    proxy_HasInstance,       /* hasInstance */      \
-    constructOp,             /* construct   */      \
-    ProxyObject::trace,      /* trace       */      \
-    PROXY_CLASS_EXT,                                \
-    {                                               \
-        proxy_LookupGeneric,                        \
-        proxy_LookupProperty,                       \
-        proxy_LookupElement,                        \
-        proxy_LookupSpecial,                        \
-        proxy_DefineGeneric,                        \
-        proxy_DefineProperty,                       \
-        proxy_DefineElement,                        \
-        proxy_DefineSpecial,                        \
-        proxy_GetGeneric,                           \
-        proxy_GetProperty,                          \
-        proxy_GetElement,                           \
-        proxy_GetSpecial,                           \
-        proxy_SetGeneric,                           \
-        proxy_SetProperty,                          \
-        proxy_SetElement,                           \
-        proxy_SetSpecial,                           \
-        proxy_GetGenericAttributes,                 \
-        proxy_SetGenericAttributes,                 \
-        proxy_DeleteProperty,                       \
-        proxy_DeleteElement,                        \
-        proxy_DeleteSpecial,                        \
-        proxy_Watch, proxy_Unwatch,                 \
-        proxy_Slice,                                \
-        nullptr,             /* enumerate       */  \
-        nullptr,             /* thisObject      */  \
-    }                                               \
-}
+#define PROXY_CLASS(callOp, constructOp)                        \
+    PROXY_CLASS_DEF("Proxy",                                    \
+                    0, /* additional slots */                   \
+                    JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),    \
+                    callOp,                                     \
+                    constructOp)
 
 const Class js::ProxyObject::uncallableClass_ = PROXY_CLASS(nullptr, nullptr);
 const Class js::ProxyObject::callableClass_ = PROXY_CLASS(proxy_Call, proxy_Construct);
 
 const Class* const js::CallableProxyClassPtr = &ProxyObject::callableClass_;
 const Class* const js::UncallableProxyClassPtr = &ProxyObject::uncallableClass_;
 
-const Class js::OuterWindowProxyObject::class_ = {
-    "Proxy",
-    Class::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    proxy_Convert,
-    proxy_Finalize,          /* finalize    */
-    nullptr,                 /* call        */
-    proxy_HasInstance,       /* hasInstance */
-    nullptr,                 /* construct   */
-    ProxyObject::trace,      /* trace       */
-    {
-        nullptr,             /* outerObject */
-        proxy_innerObject,
-        nullptr,             /* iteratorObject */
-        false,               /* isWrappedNative */
-        proxy_WeakmapKeyDelegate
-    },
-    {
-        proxy_LookupGeneric,
-        proxy_LookupProperty,
-        proxy_LookupElement,
-        proxy_LookupSpecial,
-        proxy_DefineGeneric,
-        proxy_DefineProperty,
-        proxy_DefineElement,
-        proxy_DefineSpecial,
-        proxy_GetGeneric,
-        proxy_GetProperty,
-        proxy_GetElement,
-        proxy_GetSpecial,
-        proxy_SetGeneric,
-        proxy_SetProperty,
-        proxy_SetElement,
-        proxy_SetSpecial,
-        proxy_GetGenericAttributes,
-        proxy_SetGenericAttributes,
-        proxy_DeleteProperty,
-        proxy_DeleteElement,
-        proxy_DeleteSpecial,
-        proxy_Watch, proxy_Unwatch,
-        proxy_Slice,
-        nullptr,             /* enumerate       */
-        nullptr,             /* thisObject      */
-    }
-};
+const Class js::OuterWindowProxyObject::class_ =
+    PROXY_CLASS_WITH_EXT(
+        "Proxy",
+        0, /* additional slots */
+        0, /* JSClass flags */
+        nullptr, /* call */
+        nullptr, /* construct */
+        PROXY_MAKE_EXT(
+            nullptr, /* outerObject */
+            proxy_innerObject,
+            nullptr, /* IteratorObject */
+            false /* isWrappedNative */
+        ));
 
 const Class* const js::OuterWindowProxyClassPtr = &OuterWindowProxyObject::class_;
 
 JS_FRIEND_API(JSObject *)
 js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv, JSObject *proto_,
                    JSObject *parent_, const ProxyOptions &options)
 {
     return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), parent_,