Bug 944080 - Fix IonBuilder handling of missing length property in array type information, r=jandem.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 04 Dec 2013 17:19:54 -0800
changeset 173507 6b5f8c6d9f3ba9e5c3380f9611384ad9b17da840
parent 173506 29e6539961c3a6dae7492d165b12e0e4ad87dba1
child 173508 8b33af450fc6da8f3af2a0c699fed855228bfef6
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs944080
milestone28.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 944080 - Fix IonBuilder handling of missing length property in array type information, r=jandem.
js/src/jit-test/tests/ion/bug944080.js
js/src/jit/IonBuilder.cpp
js/src/jsinfer.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug944080.js
@@ -0,0 +1,17 @@
+
+function intLength (a, l) {
+    var res = 0;
+    for (var i = 0; i < l; i++)
+	res += a.length;
+}
+intLength([0,1,2,3,4,5,6,7,8,9], 10)
+intLength(new Uint8Array(10), 10)
+function test() {
+    var a = "abc".split("");
+    var res = 0;
+    for (var i=0; i<20; i++)
+	res += a.length;
+    return res;
+}
+Object.prototype.length = function(){};
+assertEq(test(), 60);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5981,16 +5981,22 @@ ClassHasEffectlessLookup(const Class *cl
         return true;
     }
     return clasp->isNative() && !clasp->ops.lookupGeneric;
 }
 
 static bool
 ClassHasResolveHook(CompileCompartment *comp, const Class *clasp, PropertyName *name)
 {
+    // While arrays do not have resolve hooks, the types of their |length|
+    // properties are not reflected in type information, so pretend there is a
+    // resolve hook for this property.
+    if (clasp == &ArrayObject::class_)
+        return name = comp->runtime()->names().length;
+
     if (clasp->resolve == JS_ResolveStub)
         return false;
 
     if (clasp->resolve == (JSResolveOp)str_resolve) {
         // str_resolve only resolves integers, not names.
         return false;
     }
 
@@ -6097,16 +6103,19 @@ IonBuilder::testSingletonPropertyTypes(M
         // has the singleton property, the access will not be on a missing property.
         for (unsigned i = 0; i < types->getObjectCount(); i++) {
             types::TypeObjectKey *object = types->getObject(i);
             if (!object)
                 continue;
             if (analysisContext)
                 object->ensureTrackedProperty(analysisContext, NameToId(name));
 
+            const Class *clasp = object->clasp();
+            if (!ClassHasEffectlessLookup(clasp, name) || ClassHasResolveHook(compartment, clasp, name))
+                return false;
             if (object->unknownProperties())
                 return false;
             types::HeapTypeSetKey property = object->property(NameToId(name));
             if (property.isOwnProperty(constraints()))
                 return false;
 
             if (JSObject *proto = object->proto().toObjectOrNull()) {
                 // Test this type.
@@ -7996,16 +8005,20 @@ IonBuilder::annotateGetPropertyCache(MDe
     for (unsigned int i = 0; i < objCount; i++) {
         types::TypeObject *baseTypeObj = objTypes->getTypeObject(i);
         if (!baseTypeObj)
             continue;
         types::TypeObjectKey *typeObj = types::TypeObjectKey::get(baseTypeObj);
         if (typeObj->unknownProperties() || !typeObj->proto().isObject())
             continue;
 
+        const Class *clasp = typeObj->clasp();
+        if (!ClassHasEffectlessLookup(clasp, name) || ClassHasResolveHook(compartment, clasp, name))
+            continue;
+
         types::HeapTypeSetKey ownTypes = typeObj->property(NameToId(name));
         if (ownTypes.isOwnProperty(constraints()))
             continue;
 
         JSObject *singleton = testSingletonProperty(typeObj->proto().toObject(), name);
         if (!singleton || !singleton->is<JSFunction>())
             continue;
 
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -947,16 +947,19 @@ struct TypeObject : gc::BarrieredCell<Ty
      *    There is an exception for properties of global JS objects which
      *    are undefined at the point where the property was (lazily) generated.
      *    In such cases the property type set will remain empty, and the
      *    'undefined' type will only be added after a subsequent assignment or
      *    deletion. After these properties have been assigned a defined value,
      *    the only way they can become undefined again is after such an assign
      *    or deletion.
      *
+     *    There is another exception for array lengths, which are special cased
+     *    by the compiler and VM and are not reflected in property types.
+     *
      * We establish these by using write barriers on calls to setProperty and
      * defineProperty which are on native properties, and on any jitcode which
      * might update the property with a new type.
      */
     Property **propertySet;
 
     /* If this is an interpreted function, the function object. */
     HeapPtrFunction interpretedFunction;