Bug 713867 - Move arrayPrototypeHasIndexedProperty from JM to jsinfer. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 28 Dec 2011 20:44:27 +0100
changeset 84698 c377af7c014dbb9f221b84fd27f9ba3debb34752
parent 84697 855983168b2fcfc98e8b031be84735f1b927ebfe
child 84699 736d90d02bd4bbd61fbd90fe8a1f03f97c735690
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
bugs713867
milestone12.0a1
Bug 713867 - Move arrayPrototypeHasIndexedProperty from JM to jsinfer. r=bhackett
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastBuiltins.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/LoopState.cpp
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2081,16 +2081,39 @@ types::UseNewType(JSContext *cx, JSScrip
         if (id == id_prototype(cx))
             return true;
     }
 
     return false;
 }
 
 bool
+types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
+{
+    if (!cx->typeInferenceEnabled() || !script->hasGlobal())
+        return true;
+
+    JSObject *proto;
+    if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto, NULL))
+        return true;
+
+    while (proto) {
+        TypeObject *type = proto->getType(cx);
+        if (type->unknownProperties())
+            return true;
+        TypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
+        if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
+            return true;
+        proto = proto->getProto();
+    }
+
+    return false;
+}
+
+bool
 TypeCompartment::growPendingArray(JSContext *cx)
 {
     unsigned newCapacity = js::Max(unsigned(100), pendingCapacity * 2);
     PendingWork *newArray = (PendingWork *) OffTheBooks::calloc_(newCapacity * sizeof(PendingWork));
     if (!newArray) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -907,16 +907,23 @@ typedef HashSet<TypeObject *, TypeObject
 extern void
 MarkArgumentsCreated(JSContext *cx, JSScript *script);
 
 /* Whether to use a new type object when calling 'new' at script/pc. */
 bool
 UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
 
 /*
+ * Whether Array.prototype, or an object on its proto chain, has an
+ * indexed property.
+ */
+bool
+ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script);
+
+/*
  * Type information about a callsite. this is separated from the bytecode
  * information itself so we can handle higher order functions not called
  * directly via a bytecode.
  */
 struct TypeCallsite
 {
     JSScript *script;
     jsbytecode *pc;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -7605,39 +7605,16 @@ mjit::Compiler::pushedSingleton(unsigned
 {
     if (!cx->typeInferenceEnabled())
         return NULL;
 
     types::TypeSet *types = analysis->pushedTypes(PC, pushed);
     return types->getSingleton(cx);
 }
 
-bool
-mjit::Compiler::arrayPrototypeHasIndexedProperty()
-{
-    if (!cx->typeInferenceEnabled() || !globalObj)
-        return true;
-
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto, NULL))
-        return true;
-
-    while (proto) {
-        types::TypeObject *type = proto->getType(cx);
-        if (type->unknownProperties())
-            return true;
-        types::TypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
-        if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
-            return true;
-        proto = proto->getProto();
-    }
-
-    return false;
-}
-
 /*
  * Barriers overview.
  *
  * After a property fetch finishes, we may need to do type checks on it to make
  * sure it matches the pushed type set for this bytecode. This can be either
  * because there is a type barrier at the bytecode, or because we cannot rule
  * out an undefined result. For such accesses, we push a register pair, and
  * then use those registers to check the fetched type matches the inferred
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -481,18 +481,16 @@ private:
 
     InvariantCodePatch *getInvariantPatch(unsigned index) {
         return &callSites[index].loopPatch;
     }
     jsbytecode *getInvariantPC(unsigned index) {
         return callSites[index].inlinepc;
     }
 
-    bool arrayPrototypeHasIndexedProperty();
-
     bool activeFrameHasMultipleExits() {
         ActiveFrame *na = a;
         while (na->parent) {
             if (na->exitState)
                 return true;
             na = na->parent;
         }
         return false;
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -876,17 +876,17 @@ mjit::Compiler::inlineNativeFunction(uin
              * in an iterator --- when popping elements we don't account for
              * suppressing deleted properties in active iterators.
              *
              * Constraints propagating properties directly into the result
              * type set are generated by TypeConstraintCall during inference.
              */
             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY |
                                            types::OBJECT_FLAG_ITERATED) &&
-                !arrayPrototypeHasIndexedProperty()) {
+                !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
                 bool packed = !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
                 return compileArrayPopShift(thisValue, packed, native == js::array_pop);
             }
         }
     } else if (argc == 1) {
         FrameEntry *arg = frame.peek(-1);
         types::TypeSet *argTypes = frame.extra(arg).types;
         if (!argTypes)
@@ -926,17 +926,17 @@ mjit::Compiler::inlineNativeFunction(uin
         }
         if (native == js::array_push &&
             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_INT32) {
             /*
              * Constraints propagating properties into the 'this' object are
              * generated by TypeConstraintCall during inference.
              */
             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
-                !arrayPrototypeHasIndexedProperty()) {
+                !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
                 return compileArrayPush(thisValue, arg);
             }
         }
         if (native == js::array_concat && argType == JSVAL_TYPE_OBJECT &&
             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_OBJECT &&
             !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
             !argTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY)) {
             return compileArrayConcat(thisTypes, argTypes, thisValue, arg);
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1516,17 +1516,17 @@ mjit::Compiler::jsop_setelem(bool popGua
     frame.forgetMismatchedObject(obj);
 
     // If the object is definitely a dense array or a typed array we can generate
     // code directly without using an inline cache.
     if (cx->typeInferenceEnabled()) {
         types::TypeSet *types = analysis->poppedTypes(PC, 2);
 
         if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
-            !arrayPrototypeHasIndexedProperty()) {
+            !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
             // Inline dense array path.
             jsop_setelem_dense();
             return true;
         }
 
 #ifdef JS_METHODJIT_TYPED_ARRAY
         if ((value->mightBeType(JSVAL_TYPE_INT32) || value->mightBeType(JSVAL_TYPE_DOUBLE)) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
@@ -2108,17 +2108,17 @@ mjit::Compiler::jsop_getelem(bool isCall
         if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
             // Inline arguments path.
             jsop_getelem_args();
             return true;
         }
 
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
-            !arrayPrototypeHasIndexedProperty()) {
+            !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
             // Inline dense array path.
             bool packed = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
             jsop_getelem_dense(packed);
             return true;
         }
 
 #ifdef JS_METHODJIT_TYPED_ARRAY
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -1710,17 +1710,17 @@ LoopState::definiteArrayAccess(const SSA
     if (objTypes->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT ||
         elemTypes->getKnownTypeTag(cx) != JSVAL_TYPE_INT32) {
         return false;
     }
 
     if (objTypes->hasObjectFlags(cx, OBJECT_FLAG_NON_DENSE_ARRAY))
         return false;
 
-    if (cc.arrayPrototypeHasIndexedProperty())
+    if (ArrayPrototypeHasIndexedProperty(cx, outerScript))
         return false;
 
     uint32_t objSlot;
     int32_t objConstant;
     CrossSSAValue objv(CrossScriptSSA::OUTER_FRAME, obj);
     if (!getEntryValue(objv, &objSlot, &objConstant) || objSlot == UNASSIGNED || objConstant != 0)
         return false;
     if (!loopInvariantEntry(objSlot))