Bug 826148 - Part 2: TI changes (r=bhackett)
authorShu-yu Guo <shu@rfrn.org>
Thu, 10 Jan 2013 13:04:04 -0800
changeset 118628 c8b493e0551523f3ccea38bad7264910f24af7bf
parent 118627 9929e066c93750e13502e8b1bd56a6b27d056cb0
child 118629 a5e3c3dd6ab2ee7a210438db06fd7b13944a2bcc
push idunknown
push userunknown
push dateunknown
reviewersbhackett
bugs826148
milestone21.0a1
Bug 826148 - Part 2: TI changes (r=bhackett)
js/src/jsinfer.cpp
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -684,16 +684,17 @@ class TypeConstraintCall : public TypeCo
 
     TypeConstraintCall(TypeCallsite *callsite)
         : callsite(callsite)
     {}
 
     const char *kind() { return "call"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
+    bool newCallee(JSContext *cx, HandleFunction callee, HandleScript script);
 };
 
 void
 StackTypeSet::addCall(JSContext *cx, TypeCallsite *site)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintCall>(site));
 }
 
@@ -767,16 +768,17 @@ class TypeConstraintPropagateThis : publ
 
     TypeConstraintPropagateThis(UnrootedScript script, jsbytecode *callpc, Type type, StackTypeSet *types)
         : script_(script), callpc(callpc), type(type), types(types)
     {}
 
     const char *kind() { return "propagatethis"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
+    bool newCallee(JSContext *cx, HandleFunction callee);
 };
 
 void
 StackTypeSet::addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
                                Type type, StackTypeSet *types)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, pc, type, types));
 }
@@ -1251,16 +1253,33 @@ TypeConstraintSetElement::newType(JSCont
     RootedScript script(cx, script_);
     if (type.isUnknown() ||
         type.isPrimitive(JSVAL_TYPE_INT32) ||
         type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
         objectTypes->addSetProperty(cx, script, pc, valueTypes, JSID_VOID);
     }
 }
 
+static inline RawFunction
+CloneCallee(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc)
+{
+    /*
+     * Clone called functions at appropriate callsites to match interpreter
+     * behavior.
+     */
+    RawFunction callee = CloneFunctionAtCallsite(cx, fun, script, pc);
+    if (!callee)
+        return NULL;
+
+    InferSpew(ISpewOps, "callsiteCloneType: #%u:%05u: %s",
+              script->id(), pc - script->code, TypeString(Type::ObjectType(callee)));
+
+    return callee;
+}
+
 void
 TypeConstraintCall::newType(JSContext *cx, TypeSet *source, Type type)
 {
     AssertCanGC();
     RootedScript script(cx, callsite->script);
     jsbytecode *pc = callsite->pc;
 
     JS_ASSERT_IF(script->hasAnalysis(),
@@ -1343,29 +1362,48 @@ TypeConstraintCall::newType(JSContext *c
         callee = type.typeObject()->interpretedFunction;
         if (!callee)
             return;
     } else {
         /* Calls on non-objects are dynamically monitored. */
         return;
     }
 
-    RootedScript calleeScript(cx, JSFunction::getOrCreateScript(cx, callee));
-    if (!calleeScript)
+    if (callee->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, callee))
         return;
+
+    /*
+     * As callsite cloning is a hint, we must propagate to both the original
+     * and the clone.
+     */
+    if (callee->isCloneAtCallsite()) {
+        RootedFunction clone(cx, CloneCallee(cx, callee, script, pc));
+        if (!clone)
+            return;
+        if (!newCallee(cx, clone, script))
+            return;
+    }
+
+    newCallee(cx, callee, script);
+}
+
+bool
+TypeConstraintCall::newCallee(JSContext *cx, HandleFunction callee, HandleScript script)
+{
+    RootedScript calleeScript(cx, callee->nonLazyScript());
     if (!calleeScript->ensureHasTypes(cx))
-        return;
+        return false;
 
     unsigned nargs = callee->nargs;
 
     /* Add bindings for the arguments of the call. */
     for (unsigned i = 0; i < callsite->argumentCount && i < nargs; i++) {
         StackTypeSet *argTypes = callsite->argumentTypes[i];
         StackTypeSet *types = TypeScript::ArgTypes(calleeScript, i);
-        argTypes->addSubsetBarrier(cx, script, pc, types);
+        argTypes->addSubsetBarrier(cx, script, callsite->pc, types);
     }
 
     /* Add void type for any formals in the callee not supplied at the call site. */
     for (unsigned i = callsite->argumentCount; i < nargs; i++) {
         TypeSet *types = TypeScript::ArgTypes(calleeScript, i);
         types->addType(cx, Type::UndefinedType());
     }
 
@@ -1387,31 +1425,33 @@ TypeConstraintCall::newType(JSContext *c
          * binding for the receiver object, as this is done with PropagateThis
          * constraints added by the original JSOP_CALL* op. The type sets we
          * manipulate here have lost any correlations between particular types
          * in the 'this' and 'callee' sets, which we want to maintain for
          * polymorphic JSOP_CALLPROP invocations.
          */
         returnTypes->addSubset(cx, callsite->returnTypes);
     }
+
+    return true;
 }
 
 void
 TypeConstraintPropagateThis::newType(JSContext *cx, TypeSet *source, Type type)
 {
     AssertCanGC();
 
+    RootedScript script(cx, script_);
     if (type.isUnknown() || type.isAnyObject()) {
         /*
          * The callee is unknown, make sure the call is monitored so we pick up
          * possible this/callee correlations. This only comes into play for
          * CALLPROP, for other calls we are past the type barrier and a
          * TypeConstraintCall will also monitor the call.
          */
-        RootedScript script(cx, script_);
         cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
         return;
     }
 
     /* Ignore calls to natives, these will be handled by TypeConstraintCall. */
     RootedFunction callee(cx);
 
     if (type.isSingleObject()) {
@@ -1424,24 +1464,47 @@ TypeConstraintPropagateThis::newType(JSC
         if (!object->interpretedFunction)
             return;
         callee = object->interpretedFunction;
     } else {
         /* Ignore calls to primitives, these will go through a stub. */
         return;
     }
 
-    if (!(JSFunction::getOrCreateScript(cx, callee) && callee->nonLazyScript()->ensureHasTypes(cx)))
+    if (callee->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, callee))
         return;
 
+    /*
+     * As callsite cloning is a hint, we must propagate to both the original
+     * and the clone.
+     */
+    if (callee->isCloneAtCallsite()) {
+        RootedFunction clone(cx, CloneCallee(cx, callee, script, callpc));
+        if (!clone)
+            return;
+        if (!newCallee(cx, clone))
+            return;
+    }
+
+    newCallee(cx, callee);
+}
+
+bool
+TypeConstraintPropagateThis::newCallee(JSContext *cx, HandleFunction callee)
+{
+    if (!callee->nonLazyScript()->ensureHasTypes(cx))
+        return false;
+
     TypeSet *thisTypes = TypeScript::ThisTypes(callee->nonLazyScript());
     if (this->types)
         this->types->addSubset(cx, thisTypes);
     else
         thisTypes->addType(cx, this->type);
+
+    return true;
 }
 
 void
 TypeConstraintArith::newType(JSContext *cx, TypeSet *source, Type type)
 {
     /*
      * We only model a subset of the arithmetic behavior that is actually
      * possible. The following need to be watched for at runtime: