Bug 939835. Fix up performance regressions from bug 937772. r=h4writer

There are two changes here.

1) When trying to eliminate type barriers, skip over infallible
unboxes, not just barriered ones.

2) When we statically know a value is double or int but dynamically
we've only observed integers, keep allowing TI to barrier and
specialize to integer instead of forcing the value to be treatd as a
double.
This commit is contained in:
Boris Zbarsky 2013-11-20 08:16:19 -05:00
parent ce20f451d3
commit 45c142619f
3 changed files with 44 additions and 26 deletions

View File

@ -1576,7 +1576,7 @@ TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool fi
// Disregard the possible unbox added before the Typebarrier for checking.
MDefinition *input = barrier->input();
if (input->isUnbox() && input->toUnbox()->mode() == MUnbox::TypeBarrier)
if (input->isUnbox() && input->toUnbox()->mode() != MUnbox::Fallible)
input = input->toUnbox()->input();
if (test->getOperand(0) == input && direction == TRUE_BRANCH) {
@ -1626,11 +1626,8 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
const types::TemporaryTypeSet *inputTypes = barrier->input()->resultTypeSet();
// Disregard the possible unbox added before the Typebarrier.
if (barrier->input()->isUnbox() &&
barrier->input()->toUnbox()->mode() == MUnbox::TypeBarrier)
{
if (barrier->input()->isUnbox() && barrier->input()->toUnbox()->mode() != MUnbox::Fallible)
inputTypes = barrier->input()->toUnbox()->input()->resultTypeSet();
}
if (!barrierTypes || !inputTypes)
return true;

View File

@ -5251,21 +5251,10 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit
types::TemporaryTypeSet *types = bytecodeTypes(pc);
bool barrier = true;
MDefinition *replace = call;
if (call->isDOMFunction()) {
JSFunction* target = call->getSingleTarget();
JS_ASSERT(target && target->isNative() && target->jitInfo());
const JSJitInfo *jitinfo = target->jitInfo();
barrier = DOMCallNeedsBarrier(jitinfo, types);
replace = ensureDefiniteType(call, jitinfo->returnType);
if (replace != call) {
current->pop();
current->push(replace);
}
}
if (call->isDOMFunction())
return pushDOMTypeBarrier(call, types, call->getSingleTarget());
return pushTypeBarrier(replace, types, barrier);
return pushTypeBarrier(call, types, true);
}
bool
@ -6147,6 +6136,38 @@ IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed,
return true;
}
bool
IonBuilder::pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func)
{
JS_ASSERT(func && func->isNative() && func->jitInfo());
const JSJitInfo *jitinfo = func->jitInfo();
bool barrier = DOMCallNeedsBarrier(jitinfo, observed);
// Need to be a bit careful: if jitinfo->returnType is JSVAL_TYPE_DOUBLE but
// types->getKnownTypeTag() is JSVAL_TYPE_INT32, then don't unconditionally
// unbox as a double. Instead, go ahead and barrier on having an int type,
// since we know we need a barrier anyway due to the type mismatch. This is
// the only situation in which TI actually has more information about the
// JSValueType than codegen can, short of jitinfo->returnType just being
// JSVAL_TYPE_UNKNOWN.
MDefinition* replace = ins;
if (jitinfo->returnType != JSVAL_TYPE_DOUBLE ||
observed->getKnownTypeTag() != JSVAL_TYPE_INT32) {
JS_ASSERT(jitinfo->returnType == JSVAL_TYPE_UNKNOWN ||
observed->getKnownTypeTag() == JSVAL_TYPE_UNKNOWN ||
jitinfo->returnType == observed->getKnownTypeTag());
replace = ensureDefiniteType(ins, jitinfo->returnType);
if (replace != ins) {
current->pop();
current->push(replace);
}
} else {
JS_ASSERT(barrier);
}
return pushTypeBarrier(replace, observed, barrier);
}
MDefinition *
IonBuilder::ensureDefiniteType(MDefinition *def, JSValueType definiteType)
{
@ -8341,13 +8362,8 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, PropertyName *name,
if (get->isEffectful() && !resumeAfter(get))
return false;
bool barrier = DOMCallNeedsBarrier(jitinfo, types);
MDefinition *replace = ensureDefiniteType(get, jitinfo->returnType);
if (replace != get) {
current->pop();
current->push(replace);
}
if (!pushTypeBarrier(replace, types, barrier))
if (!pushDOMTypeBarrier(get, types, commonGetter))
return false;
*emitted = true;

View File

@ -334,6 +334,11 @@ class IonBuilder : public MIRGenerator
// generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier);
// As pushTypeBarrier, but will compute the needBarrier boolean itself based
// on observed and the JSFunction that we're planning to call. The
// JSFunction must be a DOM method or getter.
bool pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func);
// If definiteType is not known or def already has the right type, just
// returns def. Otherwise, returns an MInstruction that has that definite
// type, infallibly unboxing ins as needed. The new instruction will be