Bug 707564 part 4. Teach WebIDL Xrays about the GetOwnProperties methods on WebIDL objects that have NewResolve. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Sat, 03 Aug 2013 23:38:55 -0400
changeset 153604 54e8477f44152ccab35d4f3c00ed9843700be9a4
parent 153603 db968c9c8831693b7d4980339c97419ef4063d4f
child 153605 a630b8d2a4a73b1c283b2cbfb28fca9c48cfd24c
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs707564
milestone25.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 707564 part 4. Teach WebIDL Xrays about the GetOwnProperties methods on WebIDL objects that have NewResolve. r=smaug
dom/bindings/Codegen.py
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
dom/bindings/test/Makefile.in
dom/bindings/test/file_bug707564.html
dom/bindings/test/test_bug707564-chrome.html
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -84,17 +84,17 @@ class CGNativePropertyHooks(CGThing):
     def define(self):
         if self.descriptor.workers:
             return ""
         if self.descriptor.concrete and self.descriptor.proxy:
             resolveOwnProperty = "ResolveOwnProperty"
             enumerateOwnProperties = "EnumerateOwnProperties"
         elif self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             resolveOwnProperty = "ResolveOwnPropertyViaNewresolve"
-            enumerateOwnProperties = "nullptr"
+            enumerateOwnProperties = "EnumerateOwnPropertiesViaGetOwnPropertyNames"
         else:
             resolveOwnProperty = "nullptr"
             enumerateOwnProperties = "nullptr"
         if self.properties.hasNonChromeOnly():
             regular = "&sNativeProperties"
         else:
             regular = "nullptr"
         if self.properties.hasChromeOnly():
@@ -6930,16 +6930,43 @@ class CGEnumerateOwnProperties(CGAbstrac
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractStaticMethod.__init__(self, descriptor,
                                         "EnumerateOwnProperties", "bool", args)
     def definition_body(self):
         return """  return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
 """
 
+class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
+    """
+    An implementation of Xray EnumerateOwnProperties stuff for things
+    that have a newresolve hook.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'),
+                Argument('JS::Handle<JSObject*>', 'wrapper'),
+                Argument('JS::Handle<JSObject*>', 'obj'),
+                Argument('JS::AutoIdVector&', 'props')]
+        CGAbstractBindingMethod.__init__(self, descriptor,
+                                         "EnumerateOwnPropertiesViaGetOwnPropertyNames",
+                                         args, getThisObj="",
+                                         callArgs="", returnType="bool")
+    def generate_code(self):
+        return CGIndenter(CGGeneric(
+                "nsAutoTArray<nsString, 8> names;\n"
+                "ErrorResult rv;\n"
+                "self->GetOwnPropertyNames(cx, names, rv);\n"
+                "rv.WouldReportJSException();\n"
+                "if (rv.Failed()) {\n"
+                '  return ThrowMethodFailedWithDetails<true>(cx, rv, "%s", "enumerate");\n'
+                "}\n"
+                '// OK to pass null as "proxy" because it\'s ignored if\n'
+                "// shadowPrototypeProperties is true\n"
+                "return DOMProxyHandler::AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, nullptr, props);"))
+
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
         CGClass.__init__(self, 'PrototypeTraits', indent=indent,
@@ -7498,17 +7525,17 @@ for (int32_t i = 0; i < int32_t(length);
         if self.descriptor.supportsNamedProperties():
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 shadow = "!isXray"
             else:
                 shadow = "false"
             addNames = """
 nsTArray<nsString> names;
 UnwrapProxy(proxy)->GetSupportedNames(names);
-if (!AppendNamedPropertyIds(cx, proxy, names, %s, props)) {
+if (!AppendNamedPropertyIds(cx, proxy, names, %s, this, props)) {
   return false;
 }
 """ % shadow
         else:
             addNames = ""
 
         if UseHolderForUnforgeable(self.descriptor):
             addUnforgeable = (
@@ -7892,16 +7919,17 @@ class CGDescriptor(CGThing):
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if not descriptor.workers and descriptor.concrete and descriptor.proxy:
             cgThings.append(CGResolveOwnProperty(descriptor))
             cgThings.append(CGEnumerateOwnProperties(descriptor))
         elif descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             cgThings.append(CGResolveOwnPropertyViaNewresolve(descriptor))
+            cgThings.append(CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor))
 
         # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
         # done, set up our NativePropertyHooks.
         cgThings.append(CGNativePropertyHooks(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGClassConstructor(descriptor,
                                                descriptor.interface.ctor()))
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -261,36 +261,38 @@ DOMProxyHandler::has(JSContext* cx, JS::
   JSBool protoHasProp;
   bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
   if (ok) {
     *bp = protoHasProp;
   }
   return ok;
 }
 
+/* static */
 bool
 DOMProxyHandler::AppendNamedPropertyIds(JSContext* cx,
                                         JS::Handle<JSObject*> proxy,
                                         nsTArray<nsString>& names,
                                         bool shadowPrototypeProperties,
+                                        DOMProxyHandler* handler,
                                         JS::AutoIdVector& props)
 {
   for (uint32_t i = 0; i < names.Length(); ++i) {
     JS::Rooted<JS::Value> v(cx);
     if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
       return false;
     }
 
     JS::Rooted<jsid> id(cx);
     if (!JS_ValueToId(cx, v, id.address())) {
       return false;
     }
 
     if (shadowPrototypeProperties ||
-        !HasPropertyOnPrototype(cx, proxy, this, id)) {
+        !HasPropertyOnPrototype(cx, proxy, handler, id)) {
       if (!props.append(id)) {
         return false;
       }
     }
   }
 
   return true;
 }
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -72,24 +72,25 @@ public:
   }
   /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
   static JSObject* GetAndClearExpandoObject(JSObject* obj);
   static JSObject* EnsureExpandoObject(JSContext* cx,
                                        JS::Handle<JSObject*> obj);
 
   const DOMClass& mClass;
 
-protected:
   // Append the property names in "names" to "props". If
   // shadowPrototypeProperties is false then skip properties that are also
-  // present on our proto chain.
-  bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
-                              nsTArray<nsString>& names,
-                              bool shadowPrototypeProperties,
-                              JS::AutoIdVector& props);
+  // present on our proto chain.  If shadowPrototypeProperties is true,
+  // then the "proxy" and "handler" arguments are ignored.
+  static bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                     nsTArray<nsString>& names,
+                                     bool shadowPrototypeProperties,
+                                     DOMProxyHandler* handler,
+                                     JS::AutoIdVector& props);
 };
 
 extern jsid s_length_id;
 
 int32_t IdToInt32(JSContext* cx, JS::Handle<jsid> id);
 
 // XXXbz this should really return uint32_t, with the maximum value
 // meaning "not an index"...
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -58,16 +58,17 @@ MOCHITEST_FILES := \
   test_lookupGetter.html \
   test_InstanceOf.html \
   file_InstanceOf.html \
   test_traceProtos.html \
   test_forOf.html \
   forOf_iframe.html \
   test_sequence_wrapping.html \
   file_bug775543.html \
+  file_bug707564.html \
   test_bug788369.html \
   test_bug742191.html \
   test_namedNoIndexed.html \
   test_bug759621.html \
   test_queryInterface.html \
   test_exceptionThrowing.html \
   test_bug852846.html \
   test_bug862092.html \
@@ -75,16 +76,17 @@ MOCHITEST_FILES := \
   test_lenientThis.html \
   test_ByteString.html \
   test_exception_messages.html \
   test_bug707564.html \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
   test_bug775543.html \
+  test_bug707564-chrome.html \
   $(NULL)
 
 ifdef GNU_CC
 CXXFLAGS += -Wno-uninitialized
 endif
 
 # Include rules.mk before any of our targets so our first target is coming from
 # rules.mk and running make with no target in this dir does the right thing.
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/file_bug707564.html
@@ -0,0 +1,5 @@
+<body>
+<script>
+  navigator.foopy = 5;
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_bug707564-chrome.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=707564
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 707564</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id="t1" src="http://example.org/tests/dom/bindings/test/file_bug707564.html"></iframe>
+<iframe id="t2" src="http://example.org/tests/dom/bindings/test/file_bug707564.html"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 775543 **/
+function test()
+{
+  var nav = document.getElementById("t1").contentWindow.navigator;
+  ise(nav.foopy, undefined, "We should have an Xray now");
+  is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object");
+  var props = Object.getOwnPropertyNames(nav);
+  isnot(props.indexOf("mozApps"), -1,
+        "Should enumerate a mozApps property on navigator xray");
+
+  var nav = document.getElementById("t2").contentWindow.navigator;
+  ise(nav.foopy, undefined, "We should have an Xray now again");
+  is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object again");
+  var found = false;
+  for (var name in nav) {
+    if (name == "mozApps") {
+      found = true;
+    }
+  }
+  ok(found, "Should enumerate a mozApps property on navigator xray via for...in");
+
+  SimpleTest.finish();
+}
+
+addLoadEvent(test);
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>