[INFER] Remove guessing mechanism for unpacked arrays.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 22 Dec 2010 17:02:24 -0800
changeset 74687 b1a613d3b6e3c607fa20b46d87ab3b6fe02a7d51
parent 74686 6ae854b6490f5c99555f1d9d811844b8949da8fe
child 74688 6b5c2cb89388d73a1ac320a32b92ae410d5feb9b
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone2.0b8pre
[INFER] Remove guessing mechanism for unpacked arrays.
js/src/jsanalyze.h
js/src/jsarray.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -376,43 +376,32 @@ class Script
         bool isForEach;
 
         /* Scope for any name binding pushed on this stack node, per SearchScope. */
         Script *scope;
 
         /* Any value pushed by a JSOP_DOUBLE. */
         bool hasDouble;
         double doubleValue;
-
-        /* Whether this is or could be the constant zero. */
-        bool isZero;
-
-        /* Whether this is another constant. */
-        bool isConstant;
     };
 
     struct AnalyzeState {
         AnalyzeStateStack *stack;
 
         /* Current stack depth. */
         unsigned stackDepth;
 
         /* Last opcode was JSOP_GETTER or JSOP_SETTER. */
         bool hasGetSet;
 
         /* Last opcode was JSOP_HOLE. */
         bool hasHole;
 
-        /* Locals thought to be zero/constants. */
-        bool zeroLocals[4];
-        uint32 constLocals[4];
-        unsigned numConstLocals;
-
         AnalyzeState()
-            : stack(NULL), stackDepth(0), hasGetSet(false), hasHole(false), numConstLocals(0)
+            : stack(NULL), stackDepth(0), hasGetSet(false), hasHole(false)
         {}
 
         bool init(JSContext *cx, JSScript *script)
         {
             if (script->nslots) {
                 stack = (AnalyzeStateStack *)
                     cx->calloc(script->nslots * sizeof(AnalyzeStateStack));
                 return (stack != NULL);
@@ -429,42 +418,16 @@ class Script
             JS_ASSERT(i < stackDepth);
             return stack[stackDepth - 1 - i];
         }
 
         const AnalyzeStateStack &popped(unsigned i) const {
             JS_ASSERT(i < stackDepth);
             return stack[stackDepth - 1 - i];
         }
-
-        void addConstLocal(uint32 local, bool zero) {
-            if (numConstLocals == JS_ARRAY_LENGTH(constLocals))
-                return;
-            if (maybeLocalConst(local, false))
-                return;
-            zeroLocals[numConstLocals] = zero;
-            constLocals[numConstLocals++] = local;
-        }
-
-        bool maybeLocalConst(uint32 local, bool zero) {
-            for (unsigned i = 0; i < numConstLocals; i++) {
-                if (constLocals[i] == local)
-                    return !zero || zeroLocals[i];
-            }
-            return false;
-        }
-
-        void clearLocal(uint32 local) {
-            for (unsigned i = 0; i < numConstLocals; i++) {
-                if (constLocals[i] == local) {
-                    constLocals[i] = constLocals[--numConstLocals];
-                    return;
-                }
-            }
-        }
     };
 
     /* Analyzes a bytecode, generating type constraints describing its behavior. */
     void analyzeTypes(JSContext *cx, Bytecode *code, AnalyzeState &state);
 
     /* Get the default 'new' object for a given standard class, per the script's global. */
     inline js::types::TypeObject *getTypeNewObject(JSContext *cx, JSProtoKey key);
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3394,17 +3394,16 @@ static void array_TypeNew(JSContext *cx,
     TypeSet *indexTypes = object->getProperty(cx, JSID_VOID, true);
 
     // ignore the case where the call is passed a single argument. this is
     // expected to be the array length, but if it isn't we will catch it
     // in the Array native itself.
     if (site->argumentCount > 1) {
         for (size_t ind = 0; ind < site->argumentCount; ind++)
             site->argumentTypes[ind]->addSubset(cx, site->pool(), indexTypes);
-        object->possiblePackedArray = true;
     }
 #endif
 }
 
 JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, array_TypeNew,
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1015,31 +1015,16 @@ TypeConstraintGenerator::newType(JSConte
         target->addType(cx, TYPE_UNKNOWN);
     if (object->proto) {
         Class *clasp = object->proto->getClass();
         if (clasp == &js_IteratorClass || clasp == &js_GeneratorClass)
             target->addType(cx, TYPE_UNKNOWN);
     }
 }
 
-/* Constraint marking incoming arrays as possibly packed. */
-class TypeConstraintPossiblyPacked : public TypeConstraint
-{
-public:
-    TypeConstraintPossiblyPacked() : TypeConstraint("possiblyPacked") {}
-
-    void newType(JSContext *cx, TypeSet *source, jstype type)
-    {
-        if (type != TYPE_UNKNOWN && TypeIsObject(type)) {
-            TypeObject *object = (TypeObject *) type;
-            object->possiblePackedArray = true;
-        }
-    }
-};
-
 /////////////////////////////////////////////////////////////////////
 // Freeze constraints
 /////////////////////////////////////////////////////////////////////
 
 /*
  * Constraint which triggers recompilation of a script if a possible new JSValueType
  * tag is realized for a type set.
  */
@@ -1112,28 +1097,16 @@ TypeSet::getKnownTypeTag(JSContext *cx, 
 
     return type;
 }
 
 /* Compute the meet of kind with the kind of object, per the ObjectKind lattice. */
 static inline ObjectKind
 CombineObjectKind(TypeObject *object, ObjectKind kind)
 {
-    /*
-     * Our initial guess is that all arrays are packed, but if the array is
-     * created through [], Array() or Array(N) and we don't see later code
-     * which looks to be filling it in starting at zero, consider it not packed.
-     * All requests for the kind of an object go through here, so there are
-     * no FreezeObjectKind constraints to update if we unset isPackedArray here.
-     */
-    if (object->isPackedArray && !object->possiblePackedArray) {
-        InferSpew(ISpewDynamic, "Possible unpacked array: %s", object->name());
-        object->isPackedArray = false;
-    }
-
     ObjectKind nkind;
     if (object->isFunction)
         nkind = object->asFunction()->script ? OBJECT_SCRIPTED_FUNCTION : OBJECT_NATIVE_FUNCTION;
     else if (object->isPackedArray)
         nkind = OBJECT_PACKED_ARRAY;
     else if (object->isDenseArray)
         nkind = OBJECT_DENSE_ARRAY;
     else
@@ -2178,16 +2151,20 @@ class TypeConstraintToString : public Ty
 static inline void
 CheckNextTest(JSContext *cx, Bytecode *code, jsbytecode *pc)
 {
     jsbytecode *next = pc + GetBytecodeLength(pc);
     switch ((JSOp)*next) {
       case JSOP_IFEQ:
       case JSOP_IFNE:
       case JSOP_NOT:
+      case JSOP_OR:
+      case JSOP_ORX:
+      case JSOP_AND:
+      case JSOP_ANDX:
       case JSOP_TYPEOF:
       case JSOP_TYPEOFEXPR:
         code->pushed(0)->addType(cx, TYPE_UNDEFINED);
         break;
       default:
         break;
     }
 }
@@ -2588,20 +2565,16 @@ Script::analyzeTypes(JSContext *cx, Byte
 
         if (op != JSOP_SETLOCALPOP) {
             MergePushed(cx, *pool, code, 0, types);
             if (op == JSOP_CALLLOCAL)
                 code->setFixed(cx, 1, TYPE_UNDEFINED);
         }
 
         if (op == JSOP_SETLOCAL || op == JSOP_SETLOCALPOP) {
-            state.clearLocal(local);
-            if (state.popped(0).isConstant)
-                state.addConstLocal(local, state.popped(0).isZero);
-
             code->popped(0)->addSubset(cx, this->pool, types);
         } else {
             /*
              * Add void type if the variable might be undefined.  TODO: monitor for
              * undefined read instead?  localDefined returns false for
              * variables which could have a legitimate use-before-def, for let
              * variables and variables exceeding the LOCAL_LIMIT threshold.
              */
@@ -2614,18 +2587,16 @@ Script::analyzeTypes(JSContext *cx, Byte
 
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC: {
         uint32 local = GET_SLOTNO(pc);
         jsid id = getLocalId(local, code);
 
-        state.clearLocal(local);
-
         TypeSet *types = evalParent()->getVariable(cx, id);
         types->addArith(cx, evalParent()->pool, code, types);
         MergePushed(cx, evalParent()->pool, code, 0, types);
 
         if (code->hasIncDecOverflow)
             types->addType(cx, TYPE_DOUBLE);
         break;
       }
@@ -2716,28 +2687,16 @@ Script::analyzeTypes(JSContext *cx, Byte
 
         CheckNextTest(cx, code, pc);
 
         if (op == JSOP_CALLELEM)
             code->popped(1)->addFilterPrimitives(cx, pool, code->pushed(1), true);
         break;
 
       case JSOP_SETELEM:
-        if (state.popped(1).isZero) {
-            /*
-             * Initializing the array with what looks like it could be zero.
-             * This is sensitive to the order in which bytecodes are emitted
-             * for common loop forms: '(for i = 0;; i++) a[i] = ...' and
-             * 'i = 0; while () { a[i] = ...; i++ }. In the bytecode the increment
-             * will appear after the initialization, and we are looking for arrays
-             * initialized between the two statements.
-             */
-            code->popped(2)->add(cx, ArenaNew<TypeConstraintPossiblyPacked>(pool));
-        }
-
         code->popped(1)->addSetElem(cx, code, code->popped(2), code->popped(0));
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
 
       case JSOP_INCELEM:
       case JSOP_DECELEM:
       case JSOP_ELEMINC:
       case JSOP_ELEMDEC:
@@ -2844,24 +2803,20 @@ Script::analyzeTypes(JSContext *cx, Byte
         break;
       }
 
       case JSOP_NEWINIT:
       case JSOP_NEWARRAY:
       case JSOP_NEWOBJECT:
         if (script->compileAndGo) {
             TypeObject *object;
-            if (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array)) {
+            if (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array))
                 object = code->initArray;
-                jsbytecode *next = pc + GetBytecodeLength(pc);
-                if (JSOp(*next) != JSOP_ENDINIT)
-                    object->possiblePackedArray = true;
-            } else {
+            else
                 object = code->initObject;
-            }
             code->pushed(0)->addType(cx, (jstype) object);
         } else {
             code->setFixed(cx, 0, TYPE_UNKNOWN);
         }
         break;
 
       case JSOP_ENDINIT:
         break;
@@ -3196,35 +3151,16 @@ Script::analyzeTypes(JSContext *cx, Byte
 
       case JSOP_DOUBLE: {
         AnalyzeStateStack &stack = state.popped(0);
         stack.hasDouble = true;
         stack.doubleValue = GetScriptConst(cx, script, pc).toDouble();
         break;
       }
 
-      case JSOP_ZERO:
-        state.popped(0).isZero = true;
-        /* FALLTHROUGH */
-      case JSOP_ONE:
-      case JSOP_INT8:
-      case JSOP_INT32:
-      case JSOP_UINT16:
-      case JSOP_UINT24:
-        state.popped(0).isConstant = true;
-        break;
-
-      case JSOP_GETLOCAL:
-        if (state.maybeLocalConst(GET_SLOTNO(pc), false)) {
-            state.popped(0).isConstant = true;
-            if (state.maybeLocalConst(GET_SLOTNO(pc), true))
-                state.popped(0).isZero = true;
-        }
-        break;
-
       default:;
     }
 }
 
 void
 Script::nukeUpvarTypes(JSContext *cx)
 {
     JS_ASSERT(parent && !getScript()->compileAndGo);
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -455,23 +455,16 @@ struct TypeObject
     bool unknownProperties;
 
     /* Whether all objects this represents are dense arrays. */
     bool isDenseArray;
 
     /* Whether all objects this represents are packed arrays (implies isDenseArray). */
     bool isPackedArray;
 
-    /*
-     * Whether this object is thought to be a possible packed array: either it came
-     * from a [a,b,c] initializer, an Array(a,b,c) call, or is another array for
-     * which we've seen what looks like initialization code. This is purely heuristic.
-     */
-    bool possiblePackedArray;
-
     TypeObject() {}
 
     /* Make an object with the specified name. */
     inline TypeObject(JSArenaPool *pool, jsid id, JSObject *proto);
 
     /* Coerce this object to a function. */
     TypeFunction* asFunction()
     {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1222,17 +1222,17 @@ TypeObject::name()
     return NULL;
 #endif
 }
 
 inline TypeObject::TypeObject(JSArenaPool *pool, jsid name, JSObject *proto)
     : proto(proto), emptyShapes(NULL), isFunction(false), marked(false),
       propertySet(NULL), propertyCount(0),
       instanceList(NULL), instanceNext(NULL), pool(pool), next(NULL), unknownProperties(false),
-      isDenseArray(false), isPackedArray(false), possiblePackedArray(false)
+      isDenseArray(false), isPackedArray(false)
 {
 #ifdef DEBUG
     this->name_ = name;
 #endif
 
 #ifdef JS_TYPE_INFERENCE
     InferSpew(ISpewOps, "newObject: %s", this->name());
 #endif