Bug 714218 - Specialize some get* implementations to do property-type-specific handling, with their getGeneric forwarding to the appropriate specific implementation. r=bhackett
authorJeff Walden <jwalden@mit.edu>
Thu, 15 Sep 2011 11:44:10 -0700
changeset 84942 be81e5f7850fe09d825fa36efb7ff6f3a7867f20
parent 84941 6b0d4b65c4f14dc07e201019861d1dd6e142be1c
child 84943 20550c970bd498ae92d6eff07beb9697faed2001
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs714218
milestone12.0a1
Bug 714218 - Specialize some get* implementations to do property-type-specific handling, with their getGeneric forwarding to the appropriate specific implementation. r=bhackett
js/src/jsarray.cpp
js/src/jsinterp.cpp
js/src/jsobjinlines.h
js/src/jstypedarray.cpp
js/src/jsxml.cpp
js/src/methodjit/StubCalls.cpp
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -771,85 +771,98 @@ js_GetDenseArrayElementValue(JSContext *
         vp->setNumber(obj->getArrayLength());
         return JS_TRUE;
     }
     *vp = obj->getDenseArrayElement(i);
     return JS_TRUE;
 }
 
 static JSBool
-array_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
+array_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp)
 {
-    uint32_t i;
-
-    if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
+    if (name == cx->runtime->atomState.lengthAtom) {
         vp->setNumber(obj->getArrayLength());
-        return JS_TRUE;
+        return true;
     }
 
-    if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) {
+    if (name == cx->runtime->atomState.protoAtom) {
         vp->setObjectOrNull(obj->getProto());
-        return JS_TRUE;
+        return true;
     }
 
     if (!obj->isDenseArray())
-        return js_GetProperty(cx, obj, id, vp);
-
-    if (!js_IdIsIndex(id, &i) || i >= obj->getDenseArrayInitializedLength() ||
-        obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
-        JSObject *proto = obj->getProto();
-        if (!proto) {
-            vp->setUndefined();
-            return JS_TRUE;
-        }
-
-        return proto->getGeneric(cx, receiver, id, vp);
+        return js_GetProperty(cx, obj, receiver, ATOM_TO_JSID(name), vp);
+
+    JSObject *proto = obj->getProto();
+    if (!proto) {
+        vp->setUndefined();
+        return true;
     }
 
-    *vp = obj->getDenseArrayElement(i);
-
-    /* Type information for dense array elements must be correct. */
-    JS_ASSERT_IF(!obj->hasSingletonType(),
-                 js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, *vp));
-
-    return JS_TRUE;
-}
-
-static JSBool
-array_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp)
-{
-    return array_getGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
+    return proto->getProperty(cx, receiver, name, vp);
 }
 
 static JSBool
 array_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
 {
     if (!obj->isDenseArray())
-        return js_GetElement(cx, obj, index, vp);
-
-    if (index < obj->getDenseArrayInitializedLength() &&
-        !obj->getDenseArrayElement(index).isMagic(JS_ARRAY_HOLE))
-    {
+        return js_GetElement(cx, obj, receiver, index, vp);
+
+    if (index < obj->getDenseArrayInitializedLength()) {
         *vp = obj->getDenseArrayElement(index);
-        return true;
+        if (!vp->isMagic(JS_ARRAY_HOLE)) {
+            /* Type information for dense array elements must be correct. */
+            JS_ASSERT_IF(!obj->hasSingletonType(),
+                         js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, *vp));
+
+            return true;
+        }
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         vp->setUndefined();
         return true;
     }
 
     return proto->getElement(cx, receiver, index, vp);
 }
 
 static JSBool
 array_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
 {
-    return array_getGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
+    if (obj->isDenseArray() && !obj->getProto()) {
+        vp->setUndefined();
+        return true;
+    }
+
+    return js_GetProperty(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
+}
+
+static JSBool
+array_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
+{
+    Value idval = IdToValue(id);
+
+    uint32_t index;
+    if (IsDefinitelyIndex(idval, &index))
+        return array_getElement(cx, obj, receiver, index, vp);
+
+    SpecialId sid;
+    if (ValueIsSpecial(obj, &idval, &sid, cx))
+        return array_getSpecial(cx, obj, receiver, sid, vp);
+
+    JSAtom *atom;
+    if (!js_ValueToAtom(cx, idval, &atom))
+        return false;
+
+    if (atom->isIndex(&index))
+        return array_getElement(cx, obj, receiver, index, vp);
+
+    return array_getProperty(cx, obj, receiver, atom->asPropertyName(), vp);
 }
 
 static JSBool
 slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     jsuint index, length;
 
     if (!js_IdIsIndex(id, &index))
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3211,17 +3211,17 @@ BEGIN_CASE(JSOP_GETELEM)
         if (!obj->getElement(cx, index, &rval))
             goto error;
     } else {
         if (script->hasAnalysis())
             script->analysis()->getCode(regs.pc).getStringElement = true;
 
         SpecialId special;
         if (ValueIsSpecial(obj, &rref, &special, cx)) {
-            if (!obj->getSpecial(cx, special, &rval))
+            if (!obj->getSpecial(cx, obj, special, &rval))
                 goto error;
         } else {
             JSAtom *name;
             if (!js_ValueToAtom(cx, rref, &name))
                 goto error;
 
             if (name->isIndex(&index)) {
                 if (!obj->getElement(cx, index, &rval))
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1319,19 +1319,19 @@ JSObject::getElementIfPresent(JSContext 
         return true;
     }
 
     *present = true;
     return getGeneric(cx, receiver, id, vp);
 }
 
 inline JSBool
-JSObject::getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp)
+JSObject::getSpecial(JSContext *cx, JSObject *receiver, js::SpecialId sid, js::Value *vp)
 {
-    return getGeneric(cx, SPECIALID_TO_JSID(sid), vp);
+    return getGeneric(cx, receiver, SPECIALID_TO_JSID(sid), vp);
 }
 
 inline JSBool
 JSObject::getGenericAttributes(JSContext *cx, jsid id, uintN *attrsp)
 {
     js::GenericAttributesOp op = getOps()->getGenericAttributes;
     return (op ? op : js_GetAttributes)(cx, this, id, attrsp);    
 }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -392,17 +392,26 @@ ArrayBuffer::obj_getGeneric(JSContext *c
         return false;
     return js_GetProperty(cx, delegate, receiver, id, vp);
 }
 
 JSBool
 ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
                              Value *vp)
 {
-    return obj_getGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
+    obj = getArrayBuffer(obj);
+    if (name == cx->runtime->atomState.byteLengthAtom) {
+        vp->setInt32(obj->arrayBufferByteLength());
+        return true;
+    }
+
+    JSObject *delegate = DelegateObject(cx, obj);
+    if (!delegate)
+        return false;
+    return js_GetProperty(cx, delegate, receiver, ATOM_TO_JSID(name), vp);
 }
 
 JSBool
 ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
 {
     JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj));
     if (!delegate)
         return false;
@@ -1007,69 +1016,90 @@ class TypedArrayTemplate
 
     static void
     obj_trace(JSTracer *trc, JSObject *obj)
     {
         MarkValue(trc, obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
     }
 
     static JSBool
-    obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
+    obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
+                    Value *vp)
     {
         JSObject *tarray = getTypedArray(obj);
 
-        if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
+        if (name == cx->runtime->atomState.lengthAtom) {
             vp->setNumber(getLength(tarray));
             return true;
         }
 
-        jsuint index;
-        if (isArrayIndex(cx, tarray, id, &index)) {
-            // this inline function is specialized for each type
-            copyIndexToValue(cx, tarray, index, vp);
-            return true;
-        }
-
         JSObject *proto = obj->getProto();
         if (!proto) {
             vp->setUndefined();
             return true;
         }
 
-        return proto->getGeneric(cx, receiver, id, vp);
-    }
-
-    static JSBool
-    obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
-                    Value *vp)
-    {
-        return obj_getGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
+        return proto->getProperty(cx, receiver, name, vp);
     }
 
     static JSBool
     obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
     {
         JSObject *tarray = getTypedArray(obj);
 
         if (index < getLength(tarray)) {
-            // this inline function is specialized for each type
             copyIndexToValue(cx, tarray, index, vp);
             return true;
         }
 
         JSObject *proto = obj->getProto();
         if (!proto) {
             vp->setUndefined();
             return true;
         }
 
         return proto->getElement(cx, receiver, index, vp);
     }
 
     static JSBool
+    obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
+    {
+        JSObject *proto = obj->getProto();
+        if (!proto) {
+            vp->setUndefined();
+            return true;
+        }
+
+        return proto->getSpecial(cx, receiver, sid, vp);
+    }
+
+    static JSBool
+    obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
+    {
+        Value idval = IdToValue(id);
+
+        uint32_t index;
+        if (IsDefinitelyIndex(idval, &index))
+            return obj_getElement(cx, obj, receiver, index, vp);
+
+        SpecialId sid;
+        if (ValueIsSpecial(obj, &idval, &sid, cx))
+            return obj_getSpecial(cx, obj, receiver, sid, vp);
+
+        JSAtom *atom;
+        if (!js_ValueToAtom(cx, idval, &atom))
+            return false;
+
+        if (atom->isIndex(&index))
+            return obj_getElement(cx, obj, receiver, index, vp);
+
+        return obj_getProperty(cx, obj, receiver, atom->asPropertyName(), vp);
+    }
+
+    static JSBool
     obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp, bool *present)
     {
         // Fast-path the common case of index < length
         JSObject *tarray = getTypedArray(obj);
 
         if (index < getLength(tarray)) {
             // this inline function is specialized for each type
             copyIndexToValue(cx, tarray, index, vp);
@@ -1081,22 +1111,16 @@ class TypedArrayTemplate
         if (!proto) {
             vp->setUndefined();
             return true;
         }
 
         return proto->getElementIfPresent(cx, receiver, index, vp, present);
     }
 
-    static JSBool
-    obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
-    {
-        return obj_getGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
-    }
-
     static bool
     setElementTail(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp, JSBool strict)
     {
         JS_ASSERT(tarray);
         JS_ASSERT(index < getLength(tarray));
 
         if (vp->isInt32()) {
             setIndex(tarray, index, NativeType(vp->toInt32()));
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -7581,17 +7581,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
     JSObject *scopeChain = GetCurrentScopeChain(cx);
     if (!scopeChain)
         return false;
 
     obj = NULL;
     for (tmp = scopeChain; tmp; tmp = tmp->enclosingScope()) {
         if (tmp->isBlock() || tmp->isWith())
             continue;
-        if (!tmp->getSpecial(cx, SpecialId::defaultXMLNamespace(), &v))
+        if (!tmp->getSpecial(cx, tmp, SpecialId::defaultXMLNamespace(), &v))
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -399,17 +399,17 @@ stubs::GetElem(VMFrame &f)
                 return;
         }
 
         if (!obj->getElement(cx, index, &rval))
             THROW();
     } else {
         SpecialId special;
         if (ValueIsSpecial(obj, &rref, &special, cx)) {
-            if (!obj->getSpecial(cx, special, &rval))
+            if (!obj->getSpecial(cx, obj, special, &rval))
                 THROW();
         } else {
             JSAtom *name;
             if (!js_ValueToAtom(cx, rref, &name))
                 THROW();
 
             if (name->isIndex(&index)) {
                 if (!obj->getElement(cx, index, &rval))