Bug 824473: IonMonkey: Remove use of monitoredTypesReturn to decide when inlining calls, r=dvander

This commit is contained in:
Hannes Verschore 2013-01-27 22:51:32 +01:00
parent 6049650a20
commit 8b45633296
5 changed files with 82 additions and 25 deletions

View File

@ -212,7 +212,8 @@ IonBuilder::canInlineTarget(JSFunction *target)
builder = builder->callerBuilder_;
}
bool canInline = oracle->canEnterInlinedFunction(target);
RootedScript callerScript(cx, script());
bool canInline = oracle->canEnterInlinedFunction(callerScript, pc, target);
if (!canInline) {
IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d", script()->lineno);

View File

@ -542,28 +542,44 @@ TypeInferenceOracle::canInlineCall(HandleScript caller, jsbytecode *pc)
JS_ASSERT(types::IsInlinableCall(pc));
Bytecode *code = caller->analysis()->maybeCode(pc);
if (code->monitoredTypes || code->monitoredTypesReturn || caller->analysis()->typeBarriers(cx, pc))
if (code->monitoredTypes)
return false;
// Gets removed in Bug 796114
if (caller->analysis()->typeBarriers(cx, pc))
return false;
return true;
}
bool
TypeInferenceOracle::canEnterInlinedFunction(JSFunction *target)
TypeInferenceOracle::canEnterInlinedFunction(HandleScript caller, jsbytecode *pc, JSFunction *target)
{
AssertCanGC();
RootedScript script(cx, target->nonLazyScript());
if (!script->hasAnalysis() || !script->analysis()->ranInference())
RootedScript targetScript(cx, target->nonLazyScript());
if (!targetScript->hasAnalysis() || !targetScript->analysis()->ranInference())
return false;
if (!script->analysis()->ionInlineable())
if (!targetScript->analysis()->ionInlineable())
return false;
if (script->analysis()->usesScopeChain())
if (targetScript->analysis()->usesScopeChain())
return false;
if (target->getType(cx)->unknownProperties())
return false;
JSOp op = JSOp(*pc);
TypeSet *returnTypes = TypeScript::ReturnTypes(targetScript);
TypeSet *callReturn = getCallReturn(caller, pc);
if (op == JSOP_NEW) {
if (!returnTypes->isSubsetIgnorePrimitives(callReturn))
return false;
} else {
if (!returnTypes->isSubset(callReturn))
return false;
}
// TI calls ObjectStateChange to trigger invalidation of the caller.
HeapTypeSet::WatchObjectStateChange(cx, target->getType(cx));
return true;

View File

@ -146,7 +146,7 @@ class TypeOracle
virtual bool canInlineCall(HandleScript caller, jsbytecode *pc) {
return false;
}
virtual bool canEnterInlinedFunction(JSFunction *callee) {
virtual bool canEnterInlinedFunction(HandleScript caller, jsbytecode *pc, JSFunction *callee) {
return false;
}
@ -251,7 +251,7 @@ class TypeInferenceOracle : public TypeOracle
MIRType elementWrite(UnrootedScript script, jsbytecode *pc);
bool canInlineCalls();
bool canInlineCall(HandleScript caller, jsbytecode *pc);
bool canEnterInlinedFunction(JSFunction *callee);
bool canEnterInlinedFunction(HandleScript caller, jsbytecode *pc, JSFunction *callee);
types::StackTypeSet *aliasedVarBarrier(UnrootedScript script, jsbytecode *pc, types::StackTypeSet **barrier);
LazyArgumentsType isArgumentObject(types::StackTypeSet *obj);

View File

@ -323,6 +323,49 @@ types::TypeFailure(JSContext *cx, const char *fmt, ...)
// TypeSet
/////////////////////////////////////////////////////////////////////
bool
TypeSet::isSubset(TypeSet *other)
{
if ((baseFlags() & other->baseFlags()) != baseFlags())
return false;
if (unknownObject()) {
JS_ASSERT(other->unknownObject());
} else {
for (unsigned i = 0; i < getObjectCount(); i++) {
TypeObjectKey *obj = getObject(i);
if (!obj)
continue;
if (!other->hasType(Type::ObjectType(obj)))
return false;
}
}
return true;
}
bool
TypeSet::isSubsetIgnorePrimitives(TypeSet *other)
{
TypeFlags otherFlags = other->baseFlags() | TYPE_FLAG_PRIMITIVE;
if ((baseFlags() & otherFlags) != baseFlags())
return false;
if (unknownObject()) {
JS_ASSERT(other->unknownObject());
} else {
for (unsigned i = 0; i < getObjectCount(); i++) {
TypeObjectKey *obj = getObject(i);
if (!obj)
continue;
if (!other->hasType(Type::ObjectType(obj)))
return false;
}
}
return true;
}
inline void
TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
{
@ -1958,21 +2001,9 @@ HeapTypeSet::knownSubset(JSContext *cx, TypeSet *other)
{
JS_ASSERT(!other->constraintsPurged());
if ((baseFlags() & other->baseFlags()) != baseFlags())
if (!isSubset(other))
return false;
if (unknownObject()) {
JS_ASSERT(other->unknownObject());
} else {
for (unsigned i = 0; i < getObjectCount(); i++) {
TypeObjectKey *obj = getObject(i);
if (!obj)
continue;
if (!other->hasType(Type::ObjectType(obj)))
return false;
}
}
addFreeze(cx);
return true;

View File

@ -286,6 +286,10 @@ enum {
TYPE_FLAG_LAZYARGS = 0x40,
TYPE_FLAG_ANYOBJECT = 0x80,
/* Mask containing all primitives */
TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING,
/* Mask/shift for the number of objects in objectSet */
TYPE_FLAG_OBJECT_COUNT_MASK = 0xff00,
TYPE_FLAG_OBJECT_COUNT_SHIFT = 8,
@ -507,6 +511,13 @@ class TypeSet
bool purged() { return !!(flags & TYPE_FLAG_PURGED); }
void setPurged() { flags |= TYPE_FLAG_PURGED | TYPE_FLAG_CONSTRAINTS_PURGED; }
/*
* Get whether this type set is known to be a subset of other.
* This variant doesn't freeze constraints. That variant is called knownSubset
*/
bool isSubset(TypeSet *other);
bool isSubsetIgnorePrimitives(TypeSet *other);
inline StackTypeSet *toStackTypeSet();
inline HeapTypeSet *toHeapTypeSet();
@ -620,9 +631,7 @@ class StackTypeSet : public TypeSet
bool knownNonStringPrimitive();
bool knownPrimitiveOrObject() {
TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_DOUBLE |
TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN | TYPE_FLAG_STRING |
TYPE_FLAG_ANYOBJECT;
TypeFlags flags = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_ANYOBJECT;
if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
return false;