mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
ce20f451d3
commit
45c142619f
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user