Bug 869040. Fix ion IC for non-overridebuiltins named gets on ListBase proxies to not cache lack of a property when it's just missing on the prototype. r=djvj
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 08 May 2013 15:50:58 -0400
changeset 138062 b61e721b78af92e7900112d59b8cb7490139cc8e
parent 138061 b1041ccc5475c07c1f5aaa65272ace5609dfe58c
child 138063 1c8df5e637a21782acfec5fc13d333b3eb489780
push id3752
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 17:21:10 +0000
treeherdermozilla-aurora@1580544aef0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs869040
milestone23.0a1
Bug 869040. Fix ion IC for non-overridebuiltins named gets on ListBase proxies to not cache lack of a property when it's just missing on the prototype. r=djvj
content/html/content/test/Makefile.in
content/html/content/test/test_bug869040.html
js/src/ion/IonCaches.cpp
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -368,16 +368,17 @@ MOCHITEST_FILES = \
 		test_mozLoadFrom.html \
 		test_style_attributes_reflection.html \
 		test_bug629801.html \
 		test_bug839371.html \
 		test_element_prototype.html \
 		test_formData.html \
 		test_audio_wakelock.html \
 		wakelock.ogg \
+		test_bug869040.html \
 		$(NULL)
 
 MOCHITEST_BROWSER_FILES = \
 		browser_bug649778.js \
 		file_bug649778.html \
 		file_bug649778.html^headers^ \
 		$(NULL)
 
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug869040.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=869040
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 869040</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=869040">Mozilla Bug 869040</a>
+<p id="display"></p>
+<div id="content" style="display: none" data-foo="present1" data-bar="present2">
+
+</div>
+<pre id="test">
+</pre>
+  <script type="application/javascript">
+
+  /** Test for Bug 869040 **/
+    var foo = "default1";
+    var dataset = $("content").dataset;
+    for (var i = 0; i < 100000; ++i)
+      foo = dataset.foo;
+
+    var bar = "default2";
+    for (var j = 0; j < 100; ++j)
+      bar = dataset.bar;
+
+    is(foo, "present1", "Our IC should work");
+    is(bar, "present2", "Our non-IC case should work");
+  </script>
+</body>
+</html>
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -1188,33 +1188,38 @@ static bool
 IsIdempotentAndMaybeHasHooks(IonCache &cache, JSObject *obj)
 {
     // If the cache is idempotent, watch out for resolve hooks or non-native
     // objects on the proto chain. We check this before calling lookupProperty,
     // to make sure no effectful lookup hooks or resolve hooks are called.
     return cache.idempotent() && !obj->hasIdempotentProtoChain();
 }
 
+/*
+ * The receiver is the object the get is actually happening on, and what should
+ * be used for missing-property checks.  The checkObj is the object that we want
+ * to do the get on if the property is present on it.
+ */
 static bool
-DetermineGetPropKind(JSContext *cx, IonCache &cache,
+DetermineGetPropKind(JSContext *cx, IonCache &cache, JSObject *receiver,
                      JSObject *checkObj, JSObject *holder, HandleShape shape,
                      TypedOrValueRegister output, bool allowGetters,
                      bool *readSlot, bool *callGetter)
 {
     // Check what kind of cache stub we can emit: either a slot read,
     // or a getter call.
     *readSlot = false;
     *callGetter = false;
 
     RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
 
     if (IsCacheableGetPropReadSlot(checkObj, holder, shape) ||
-        IsCacheableNoProperty(checkObj, holder, shape, pc, output))
+        IsCacheableNoProperty(receiver, holder, shape, pc, output))
     {
         // With Proxies, we cannot garantee any property access as the proxy can
         // mask any property from the prototype chain.
         JS_ASSERT(!checkObj->isProxy());
         *readSlot = true;
     } else if (IsCacheableGetPropCallNative(checkObj, holder, shape) ||
                IsCacheableGetPropCallPropertyOp(checkObj, holder, shape))
     {
@@ -1283,17 +1288,17 @@ TryAttachNativeGetPropStub(JSContext *cx
 
     RootedShape shape(cx);
     RootedObject holder(cx);
     if (!JSObject::lookupProperty(cx, checkObj, name, &holder, &shape))
         return false;
 
     bool readSlot;
     bool callGetter;
-    if (!DetermineGetPropKind(cx, cache, checkObj, holder, shape, cache.output(),
+    if (!DetermineGetPropKind(cx, cache, obj, checkObj, holder, shape, cache.output(),
                               cache.allowGetters(), &readSlot, &callGetter))
     {
         return true;
     }
 
     if (IsIdempotentAndHasSingletonHolder(cache, holder, shape))
         return true;
 
@@ -1463,17 +1468,17 @@ ParallelGetPropertyIC::canAttachReadSlot
 
     if (!js::LookupPropertyPure(obj, NameToId(name()), holder.address(), shape.address()))
         return false;
 
     // In parallel execution we can't cache getters due to possible
     // side-effects, so only check if we can cache slot reads.
     bool readSlot;
     bool callGetter;
-    if (!DetermineGetPropKind(cx, *this, obj, holder, shape, output(), false,
+    if (!DetermineGetPropKind(cx, *this, obj, obj, holder, shape, output(), false,
                               &readSlot, &callGetter) || !readSlot)
     {
         return false;
     }
 
     if (IsIdempotentAndHasSingletonHolder(*this, holder, shape))
         return false;