Bug 894881 - Fix JIT fast paths to work with typed array properties. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 19 Nov 2013 19:21:11 +0100
changeset 170996 5ef1eb4f5d571a48be56989387f9c7bacad11ac6
parent 170995 644408afbf21fe1f06cfa6693d5688ad15c8b337
child 170997 c534f99dacf61b02a4607865995e6cfff14e1a97
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)
reviewersbhackett
bugs894881
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 894881 - Fix JIT fast paths to work with typed array properties. r=bhackett
js/src/jit/BaselineIC.cpp
js/src/jit/IonBuilder.cpp
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3264,37 +3264,41 @@ EffectlesslyLookupProperty(JSContext *cx
         if (*shadowsResult == Shadows) {
             holder.set(obj);
             return true;
         }
 
         *domProxyHasGeneration = (*shadowsResult == DoesntShadowUnique);
 
         checkObj = GetDOMProxyProto(obj);
-    }
-
-    if (!isDOMProxy && !obj->isNative())
+    } else if (obj->is<TypedArrayObject>() && obj->getProto()) {
+        // Typed array objects are non-native, but don't have any named
+        // properties. Just forward the lookup to the prototype, to allow
+        // inlining common getters like byteOffset.
+        checkObj = obj->getProto();
+    } else if (!obj->isNative()) {
         return true;
+    }
 
     if (checkObj->hasIdempotentProtoChain()) {
         if (!JSObject::lookupProperty(cx, checkObj, name, holder, shape))
             return false;
     } else if (checkObj->isNative()) {
         shape.set(checkObj->nativeLookup(cx, NameToId(name)));
         if (shape)
             holder.set(checkObj);
     }
     return true;
 }
 
 static bool
 IsCacheableProtoChain(JSObject *obj, JSObject *holder, bool isDOMProxy=false)
 {
     JS_ASSERT_IF(isDOMProxy, IsCacheableDOMProxy(obj));
-    JS_ASSERT_IF(!isDOMProxy, obj->isNative());
+    JS_ASSERT_IF(!isDOMProxy, obj->isNative() || obj->is<TypedArrayObject>());
 
     // Don't handle objects which require a prototype guard. This should
     // be uncommon so handling it is likely not worth the complexity.
     if (obj->hasUncacheableProto())
         return false;
 
     JSObject *cur = obj;
     while (cur != holder) {
@@ -5969,17 +5973,17 @@ TryAttachNativeGetPropStub(JSContext *cx
     RootedShape shape(cx);
     RootedObject holder(cx);
     if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isDOMProxy,
                                     &domProxyShadowsResult, &domProxyHasGeneration))
     {
         return false;
     }
 
-    if (!isDOMProxy && !obj->isNative())
+    if (!isDOMProxy && !obj->isNative() && !obj->is<TypedArrayObject>())
         return true;
 
     bool isCallProp = (JSOp(*pc) == JSOP_CALLPROP);
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
     if (!isDOMProxy && IsCacheableGetPropReadSlot(obj, holder, shape)) {
         bool isFixedSlot;
         uint32_t offset;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5929,18 +5929,24 @@ IonBuilder::maybeInsertResume()
 
     MNop *ins = MNop::New(alloc());
     current->add(ins);
 
     return resumeAfter(ins);
 }
 
 static bool
-ClassHasEffectlessLookup(const Class *clasp)
-{
+ClassHasEffectlessLookup(const Class *clasp, PropertyName *name)
+{
+    if (IsTypedArrayClass(clasp)) {
+        // Typed arrays have a lookupGeneric hook, but it only handles
+        // integers, not names.
+        JS_ASSERT(name);
+        return true;
+    }
     return clasp->isNative() && !clasp->ops.lookupGeneric;
 }
 
 static bool
 ClassHasResolveHook(CompileCompartment *comp, const Class *clasp, PropertyName *name)
 {
     if (clasp->resolve == JS_ResolveStub)
         return false;
@@ -5969,17 +5975,17 @@ IonBuilder::testSingletonProperty(JSObje
     // If the access definitely goes through obj, either directly or on the
     // prototype chain, and the object has singleton type, then the type
     // information for that property reflects the value that will definitely be
     // read on accesses to the object. If the property is later deleted or
     // reconfigured as a getter/setter then the type information for the
     // property will change and trigger invalidation.
 
     while (obj) {
-        if (!ClassHasEffectlessLookup(obj->getClass()))
+        if (!ClassHasEffectlessLookup(obj->getClass(), name))
             return nullptr;
 
         types::TypeObjectKey *objType = types::TypeObjectKey::get(obj);
         if (analysisContext)
             objType->ensureTrackedProperty(analysisContext, NameToId(name));
 
         if (objType->unknownProperties())
             return nullptr;
@@ -7780,22 +7786,23 @@ IonBuilder::objectsHaveCommonPrototype(t
         if (!type)
             continue;
 
         while (type) {
             if (type->unknownProperties())
                 return false;
 
             const Class *clasp = type->clasp();
-            if (!ClassHasEffectlessLookup(clasp) || ClassHasResolveHook(compartment, clasp, name))
+            if (!ClassHasEffectlessLookup(clasp, name) || ClassHasResolveHook(compartment, clasp, name))
                 return false;
 
             // Look for a getter/setter on the class itself which may need
-            // to be called.
-            if (isGetter && clasp->ops.getGeneric)
+            // to be called. Ignore the getGeneric hook for typed arrays, it
+            // only handles integers and forwards names to the prototype.
+            if (isGetter && clasp->ops.getGeneric && !IsTypedArrayClass(clasp))
                 return false;
             if (!isGetter && clasp->ops.setGeneric)
                 return false;
 
             // Test for isOwnProperty() without freezing. If we end up
             // optimizing, freezePropertiesForCommonPropFunc will freeze the
             // property type sets later on.
             types::HeapTypeSetKey property = type->property(NameToId(name));