Bug 921454 - Refactor proxy creation to use an options object. r=jonco
authorBobby Holley <bobbyholley@gmail.com>
Fri, 04 Oct 2013 13:29:35 +0200
changeset 149900 6a194198c85da6772c32865cef1d507d75f44d1c
parent 149899 c03caed5328f009f93ee638c8d526b75102f2915
child 149901 7ea98711b26ce2b47b24df60cfa0b9519bfe0afa
push id25405
push userphilringnalda@gmail.com
push dateSat, 05 Oct 2013 05:04:31 +0000
treeherdermozilla-central@bd7bb523c5dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs921454
milestone27.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 921454 - Refactor proxy creation to use an options object. r=jonco
dom/base/WindowNamedPropertiesHandler.cpp
js/ipc/JavaScriptParent.cpp
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jswrapper.cpp
js/src/vm/ProxyObject.cpp
js/src/vm/ProxyObject.h
js/src/vm/ScopeObject.cpp
js/xpconnect/src/Sandbox.cpp
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -206,21 +206,22 @@ WindowNamedPropertiesHandler::Install(JS
   if (!::JS_GetPrototype(aCx, aProto, &protoProto)) {
     return;
   }
 
   // Note: since the scope polluter proxy lives on the window's prototype
   // chain, it needs a singleton type to avoid polluting type information
   // for properties on the window.
   JS::Rooted<JSObject*> gsp(aCx);
+  js::ProxyOptions options;
+  options.setSingleton(true);
   gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
                            JS::NullHandleValue, protoProto,
                            js::GetGlobalForObjectCrossCompartment(aProto),
-                           js::ProxyNotCallable,
-                           /* singleton = */ true);
+                           options);
   if (!gsp) {
     return;
   }
 
   // And then set the prototype of the interface prototype object to be the
   // global scope polluter.
   ::JS_SplicePrototype(aCx, aProto, gsp);
 }
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -567,22 +567,24 @@ JavaScriptParent::unwrap(JSContext *cx, 
         return nullptr;
     }
 
     bool callable = !!(objId & OBJECT_IS_CALLABLE);
 
     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
 
     RootedValue v(cx, UndefinedValue());
+    ProxyOptions options;
+    options.setCallable(callable);
     obj = NewProxyObject(cx,
                          &CPOWProxyHandler::singleton,
                          v,
                          nullptr,
                          global,
-                         callable ? ProxyIsCallable : ProxyNotCallable);
+                         options);
     if (!obj)
         return nullptr;
 
     if (!objects_.add(objId, obj))
         return nullptr;
 
     // Incref once we know the decref will be called.
     incref();
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -3138,20 +3138,20 @@ const Class js::OuterWindowProxyObject::
         NULL,                /* thisObject      */
     }
 };
 
 const Class* const js::OuterWindowProxyClassPtr = &OuterWindowProxyObject::class_;
 
 JS_FRIEND_API(JSObject *)
 js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv, JSObject *proto_,
-                   JSObject *parent_, ProxyCallable callable, bool singleton)
+                   JSObject *parent_, const ProxyOptions &options)
 {
     return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), parent_,
-                            callable, singleton);
+                            options);
 }
 
 void
 ProxyObject::renew(JSContext *cx, BaseProxyHandler *handler, Value priv)
 {
     JS_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this));
     JS_ASSERT(getParent() == cx->global());
     JS_ASSERT(getClass() == &uncallableClass_);
@@ -3181,21 +3181,22 @@ proxy(JSContext *cx, unsigned argc, jsva
         return false;
     RootedObject handler(cx, NonNullObject(cx, args[1]));
     if (!handler)
         return false;
     RootedObject proto(cx);
     if (!JSObject::getProto(cx, target, &proto))
         return false;
     RootedValue priv(cx, ObjectValue(*target));
+    ProxyOptions options;
+    options.setCallable(target->isCallable());
     ProxyObject *proxy =
         ProxyObject::New(cx, &ScriptedDirectProxyHandler::singleton,
                          priv, TaggedProto(proto), cx->global(),
-                         target->isCallable() ? ProxyIsCallable
-                                              : ProxyNotCallable);
+                         options);
     if (!proxy)
         return false;
     proxy->setExtra(0, ObjectOrNullValue(handler));
     vp->setObject(*proxy);
     return true;
 }
 
 static bool
@@ -3264,19 +3265,21 @@ proxy_createFunction(JSContext *cx, unsi
     RootedObject ccHolder(cx, JS_NewObjectWithGivenProto(cx, Jsvalify(&CallConstructHolder),
                                                          NULL, cx->global()));
     if (!ccHolder)
         return false;
     ccHolder->setReservedSlot(0, ObjectValue(*call));
     ccHolder->setReservedSlot(1, ObjectValue(*construct));
 
     RootedValue priv(cx, ObjectValue(*handler));
+    ProxyOptions options;
+    options.setCallable(true);
     JSObject *proxy =
         ProxyObject::New(cx, &ScriptedIndirectProxyHandler::singleton,
-                         priv, TaggedProto(proto), parent, ProxyIsCallable);
+                         priv, TaggedProto(proto), parent, options);
     if (!proxy)
         return false;
     proxy->as<ProxyObject>().setExtra(0, ObjectValue(*ccHolder));
 
     vp->setObject(*proxy);
     return true;
 }
 
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -345,25 +345,42 @@ SetProxyHandler(JSObject *obj, BaseProxy
 inline void
 SetProxyExtra(JSObject *obj, size_t n, const Value &extra)
 {
     JS_ASSERT(IsProxy(obj));
     JS_ASSERT(n <= 1);
     SetReservedSlot(obj, PROXY_EXTRA_SLOT + n, extra);
 }
 
-enum ProxyCallable {
-    ProxyNotCallable = false,
-    ProxyIsCallable = true
+class MOZ_STACK_CLASS ProxyOptions {
+  public:
+    ProxyOptions() : callable_(false),
+                     singleton_(false)
+    {}
+
+    bool callable() const { return callable_; }
+    ProxyOptions &setCallable(bool flag) {
+        callable_ = flag;
+        return *this;
+    }
+
+    bool singleton() const { return singleton_; }
+    ProxyOptions &setSingleton(bool flag) {
+        singleton_ = flag;
+        return *this;
+    }
+
+  private:
+    bool callable_;
+    bool singleton_;
 };
 
 JS_FRIEND_API(JSObject *)
 NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv,
-               JSObject *proto, JSObject *parent,
-               ProxyCallable callable = ProxyNotCallable, bool singleton = false);
+               JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions());
 
 JSObject *
 RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
 
 class JS_FRIEND_API(AutoEnterPolicy)
 {
   public:
     typedef BaseProxyHandler::Action Action;
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -42,18 +42,19 @@ Wrapper::defaultValue(JSContext *cx, Han
 JSObject *
 Wrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, Wrapper *handler)
 {
     JS_ASSERT(parent);
 
     AutoMarkInDeadZone amd(cx->zone());
 
     RootedValue priv(cx, ObjectValue(*obj));
-    return NewProxyObject(cx, handler, priv, proto, parent,
-                          obj->isCallable() ? ProxyIsCallable : ProxyNotCallable);
+    ProxyOptions options;
+    options.setCallable(obj->isCallable());
+    return NewProxyObject(cx, handler, priv, proto, parent, options);
 }
 
 JSObject *
 Wrapper::Renew(JSContext *cx, JSObject *existing, JSObject *obj, Wrapper *handler)
 {
     JS_ASSERT(!obj->isCallable());
     existing->as<ProxyObject>().renew(cx, handler, ObjectValue(*obj));
     return existing;
@@ -834,17 +835,17 @@ DeadObjectProxy::getPrototypeOf(JSContex
 
 DeadObjectProxy DeadObjectProxy::singleton;
 const char DeadObjectProxy::sDeadObjectFamily = 0;
 
 JSObject *
 js::NewDeadProxyObject(JSContext *cx, JSObject *parent)
 {
     return NewProxyObject(cx, &DeadObjectProxy::singleton, JS::NullHandleValue,
-                          NULL, parent, ProxyNotCallable);
+                          NULL, parent);
 }
 
 bool
 js::IsDeadProxyObject(JSObject *obj)
 {
     return obj->is<ProxyObject>() &&
            obj->as<ProxyObject>().handler() == &DeadObjectProxy::singleton;
 }
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -10,43 +10,43 @@
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 
 /* static */ ProxyObject *
 ProxyObject::New(JSContext *cx, BaseProxyHandler *handler, HandleValue priv, TaggedProto proto_,
-                 JSObject *parent_, ProxyCallable callable, bool singleton)
+                 JSObject *parent_, const ProxyOptions &options)
 {
     Rooted<TaggedProto> proto(cx, proto_);
     RootedObject parent(cx, parent_);
 
     JS_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
     JS_ASSERT_IF(parent, cx->compartment() == parent->compartment());
     const Class *clasp;
     if (handler->isOuterWindow())
         clasp = &OuterWindowProxyObject::class_;
     else
-        clasp = callable ? &ProxyObject::callableClass_
-                         : &ProxyObject::uncallableClass_;
+        clasp = options.callable() ? &ProxyObject::callableClass_
+                                   : &ProxyObject::uncallableClass_;
 
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
      * their prototype changes later.
      */
-    if (proto.isObject() && !singleton) {
+    if (proto.isObject() && !options.singleton()) {
         RootedObject protoObj(cx, proto.toObject());
         if (!JSObject::setNewTypeUnknown(cx, clasp, protoObj))
             return NULL;
     }
 
     NewObjectKind newKind =
-        (clasp == &OuterWindowProxyObject::class_ || singleton) ? SingletonObject : GenericObject;
+        (clasp == &OuterWindowProxyObject::class_ || options.singleton()) ? SingletonObject : GenericObject;
     gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
     if (handler->finalizeInBackground(priv))
         allocKind = GetBackgroundAllocKind(allocKind);
     RootedObject obj(cx, NewObjectWithGivenProto(cx, clasp, proto, parent, allocKind, newKind));
     if (!obj)
         return NULL;
 
     Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
--- a/js/src/vm/ProxyObject.h
+++ b/js/src/vm/ProxyObject.h
@@ -19,17 +19,18 @@ class ProxyObject : public JSObject
     // These are just local renamings of the slot constants that are part of
     // the API in jsproxy.h.
     static const uint32_t PRIVATE_SLOT = PROXY_PRIVATE_SLOT;
     static const uint32_t HANDLER_SLOT = PROXY_HANDLER_SLOT;
     static const uint32_t EXTRA_SLOT   = PROXY_EXTRA_SLOT;
 
   public:
     static ProxyObject *New(JSContext *cx, BaseProxyHandler *handler, HandleValue priv,
-                            TaggedProto proto_, JSObject *parent_, ProxyCallable callable, bool singleton = false);
+                            TaggedProto proto_, JSObject *parent_,
+                            const ProxyOptions &options);
 
     const Value &private_() {
         return GetReservedSlot(this, PRIVATE_SLOT);
     }
 
     void initCrossCompartmentPrivate(HandleValue priv);
 
     HeapSlot *slotOfPrivate() {
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1503,17 +1503,17 @@ int DebugScopeProxy::family = 0;
 DebugScopeProxy DebugScopeProxy::singleton;
 
 /* static */ DebugScopeObject *
 DebugScopeObject::create(JSContext *cx, ScopeObject &scope, HandleObject enclosing)
 {
     JS_ASSERT(scope.compartment() == cx->compartment());
     RootedValue priv(cx, ObjectValue(scope));
     JSObject *obj = NewProxyObject(cx, &DebugScopeProxy::singleton, priv,
-                                   nullptr /* proto */, &scope.global(), ProxyNotCallable);
+                                   nullptr /* proto */, &scope.global());
     if (!obj)
         return nullptr;
 
     JS_ASSERT(!enclosing->is<ScopeObject>());
 
     DebugScopeObject *debugScope = &obj->as<DebugScopeObject>();
     debugScope->setExtra(ENCLOSING_EXTRA, ObjectValue(*enclosing));
     debugScope->setExtra(SNAPSHOT_EXTRA, NullValue());
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -714,19 +714,21 @@ WrapCallable(JSContext *cx, JSObject *ca
     // Our proxy is wrapping the callable.  So we need to use the
     // callable as the private.  We use the given sandboxProtoProxy as
     // the parent, and our call() hook depends on that.
     MOZ_ASSERT(js::IsProxy(sandboxProtoProxy) &&
                js::GetProxyHandler(sandboxProtoProxy) ==
                  &xpc::sandboxProxyHandler);
 
     RootedValue priv(cx, ObjectValue(*callable));
+    js::ProxyOptions options;
+    options.setCallable(true);
     return js::NewProxyObject(cx, &xpc::sandboxCallableProxyHandler,
                               priv, nullptr,
-                              sandboxProtoProxy, js::ProxyIsCallable);
+                              sandboxProtoProxy, options);
 }
 
 template<typename Op>
 bool BindPropertyOp(JSContext *cx, Op &op, JSPropertyDescriptor *desc, HandleId id,
                     unsigned attrFlag, HandleObject sandboxProtoProxy)
 {
     if (!op) {
         return true;