Propagate callee 'this' types more often, bug 788822. r=jandem
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 23 Oct 2012 09:05:27 -0700
changeset 111293 ca391c7bceb811856bf3014049775722084033e9
parent 111292 f39a603626882c606a248ab97cffa0b51000e245
child 111294 9a5191dfae8d0f5577b248ca79fbdd46e49473f8
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersjandem
bugs788822
milestone19.0a1
Propagate callee 'this' types more often, bug 788822. r=jandem
js/src/jsinfer.cpp
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -743,22 +743,17 @@ class TypeConstraintPropagateThis : publ
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
 StackTypeSet::addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
                                Type type, StackTypeSet *types)
 {
-    /* Don't add constraints when the call will be 'new' (see addCallProperty). */
-    jsbytecode *callpc = script->analysis()->getCallPC(pc);
-    if (JSOp(*callpc) == JSOP_NEW)
-        return;
-
-    add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, callpc, type, types));
+    add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, pc, type, types));
 }
 
 /* Subset constraint which filters out primitive types. */
 class TypeConstraintFilterPrimitive : public TypeConstraint
 {
   public:
     TypeSet *target;
 
@@ -1202,17 +1197,16 @@ TypeConstraintCallProp<access>::newType(
         if (object->unknownProperties()) {
             cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
         } else {
             TypeSet *types = object->getProperty(cx, id, false);
             if (!types)
                 return;
             if (!types->hasPropagatedProperty())
                 object->getFromPrototypes(cx, id, types);
-            /* Bypass addPropagateThis, we already have the callpc. */
             if (access == PROPERTY_READ) {
                 types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(
                                 script_, callpc, type, (StackTypeSet *) NULL));
             } else {
                 TypeConstraintPropagateThis constraint(script, callpc, type, NULL);
                 types->addTypesToConstraint(cx, &constraint);
             }
         }
@@ -3574,26 +3568,16 @@ GetInitializerType(JSContext *cx, Handle
     JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
 
     if (UseNewTypeForInitializer(cx, script, pc, key))
         return NULL;
 
     return TypeScript::InitObject(cx, script, pc, key);
 }
 
-static inline Type
-GetCalleeThisType(jsbytecode *pc)
-{
-    pc += GetBytecodeLength(pc);
-    if (*pc == JSOP_UNDEFINED)
-        return Type::UndefinedType();
-    JS_ASSERT(*pc == JSOP_IMPLICITTHIS);
-    return Type::UnknownType();
-}
-
 /* Analyze type information for a single bytecode. */
 bool
 ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state)
 {
     RootedScript script(cx, script_);
 
     jsbytecode *pc = script_->code + offset;
     JSOp op = (JSOp)*pc;
@@ -3818,31 +3802,26 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
         TypeObject *global = script_->global().getType(cx);
 
         /* Handle as a property access. */
         if (state.hasPropertyReadTypes)
             PropertyAccess<PROPERTY_READ_EXISTING>(cx, script, pc, global, seen, id);
         else
             PropertyAccess<PROPERTY_READ>(cx, script, pc, global, seen, id);
-
-        if (op == JSOP_CALLGNAME)
-            pushed[0].addPropagateThis(cx, script, pc, GetCalleeThisType(pc));
         break;
       }
 
       case JSOP_NAME:
       case JSOP_INTRINSICNAME:
       case JSOP_CALLNAME:
       case JSOP_CALLINTRINSIC: {
         StackTypeSet *seen = bytecodeTypes(pc);
         addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLNAME || op == JSOP_CALLINTRINSIC)
-            pushed[0].addPropagateThis(cx, script, pc, GetCalleeThisType(pc));
         break;
       }
 
       case JSOP_BINDGNAME:
       case JSOP_BINDNAME:
         break;
 
       case JSOP_SETGNAME: {
@@ -3880,18 +3859,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
             poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         } else if (slot < TotalSlots(script_)) {
             StackTypeSet *types = TypeScript::SlotTypes(script_, slot);
             types->addSubset(cx, &pushed[0]);
         } else {
             /* Local 'let' variable. Punt on types for these, for now. */
             pushed[0].addType(cx, Type::UnknownType());
         }
-        if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
         break;
       }
 
       case JSOP_SETARG:
       case JSOP_SETLOCAL: {
         uint32_t slot = GetBytecodeSlot(script_, pc);
         if (!trackSlot(slot) && slot < TotalSlots(script_)) {
             TypeSet *types = TypeScript::SlotTypes(script_, slot);
@@ -3912,18 +3889,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         /*
          * Every aliased variable will contain 'undefined' in addition to the
          * type of whatever value is written to it. Thus, a dynamic barrier is
          * necessary. Since we don't expect the to observe more than 1 type,
          * there is little benefit to maintaining a TypeSet for the aliased
          * variable. Instead, we monitor/barrier all reads unconditionally.
          */
         bytecodeTypes(pc)->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLALIASEDVAR)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
         break;
 
       case JSOP_SETALIASEDVAR:
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_INCARG:
       case JSOP_DECARG:
@@ -4030,18 +4005,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         if (state.hasPropertyReadTypes) {
             TypeConstraintGetPropertyExisting getProp(script_, pc, seen, JSID_VOID);
             input->addTypesToConstraint(cx, &getProp);
         } else {
             input->addGetProperty(cx, script, pc, seen, JSID_VOID);
         }
 
         seen->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLELEM)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType(), poppedTypes(pc, 1));
         break;
       }
 
       case JSOP_SETELEM:
         poppedTypes(pc, 1)->addSetElement(cx, script, pc, poppedTypes(pc, 2), poppedTypes(pc, 0));
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
@@ -4128,17 +4101,34 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         /*
          * Mark FUNCALL and FUNAPPLY sites as monitored. The method JIT may
          * lower these into normal calls, and we need to make sure the
          * callee's argument types are checked on entry.
          */
         if (op == JSOP_FUNCALL || op == JSOP_FUNAPPLY)
             cx->compartment->types.monitorBytecode(cx, script, pc - script_->code);
 
-        poppedTypes(pc, argCount + 1)->addCall(cx, callsite);
+        StackTypeSet *calleeTypes = poppedTypes(pc, argCount + 1);
+
+        /*
+         * Propagate possible 'this' types to the callee except when the call
+         * came through JSOP_CALLPROP (which uses TypeConstraintCallProperty)
+         * or for JSOP_NEW (where the callee will construct the 'this' object).
+         */
+        SSAValue calleeValue = poppedValue(pc, argCount + 1);
+        if (*pc != JSOP_NEW &&
+            (calleeValue.kind() != SSAValue::PUSHED ||
+             script->code[calleeValue.pushedOffset()] != JSOP_CALLPROP))
+        {
+            HandleScript script_ = script;
+            calleeTypes->add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>
+                                   (script_, pc, Type::UndefinedType(), callsite->thisTypes));
+        }
+
+        calleeTypes->addCall(cx, callsite);
         break;
       }
 
       case JSOP_NEWINIT:
       case JSOP_NEWARRAY:
       case JSOP_NEWOBJECT: {
         StackTypeSet *types = script_->analysis()->bytecodeTypes(pc);
         types->addSubset(cx, &pushed[0]);