Bug 1073861 - IonMonkey: Don't update types during type policy, r=jandem

This commit is contained in:
Hannes Verschore 2014-10-02 17:11:28 +02:00
parent d2772198b4
commit 1a57f38c68
3 changed files with 146 additions and 49 deletions

View File

@ -0,0 +1,69 @@
function a(a, b, c, g) {
for (;;) {
if (0 > c) return a;
a: {
for (;;) {
var k = a.forward[c];
if (t(k))
if (k.key < b) a = k;
else break a;
else break a
}
a = void 0
}
null !=
g && (g[c] = a);
c -= 1
}
}
function t(a) {
return null != a && !1 !== a
}
var d = {forward: [{},null,{}]}
for (var i=0; i < 1000; i++) {
a(d, 0, 1, null);
a(d, 0, 0, null);
}
function test(a) {
var t = a[0]
if (t) {
return t.test;
}
}
function test2(a) {
var t = a[0]
if (t) {
if (t) {
return t.test;
}
}
}
function test3(a) {
var t = a[0]
if (t !== null) {
if (t !== undefined) {
return t.test;
}
}
}
var a = [{test:1}]
var b = [undefined]
assertEq(test(b), undefined)
assertEq(test(a), 1)
assertEq(test(a), 1)
assertEq(test2(b), undefined)
assertEq(test2(a), 1)
assertEq(test2(a), 1)
assertEq(test3(b), undefined)
assertEq(test3(a), 1)
assertEq(test3(a), 1)

View File

@ -3144,7 +3144,7 @@ IonBuilder::replaceTypeSet(MDefinition *subject, types::TemporaryTypeSet *type,
if (type->unknown())
return true;
MFilterTypeSet *replace = nullptr;
MInstruction *replace = nullptr;
MDefinition *ins;
for (uint32_t i = 0; i < current->stackDepth(); i++) {
@ -3161,27 +3161,32 @@ IonBuilder::replaceTypeSet(MDefinition *subject, types::TemporaryTypeSet *type,
ins->toFilterTypeSet()->setResultType(intersect->getKnownMIRType());
ins->toFilterTypeSet()->setResultTypeSet(intersect);
if (ins->type() == MIRType_Undefined)
current->setSlot(i, constant(UndefinedValue()));
if (ins->type() == MIRType_Null)
current->setSlot(i, constant(NullValue()));
continue;
}
if (ins == subject) {
if (!replace) {
replace = MFilterTypeSet::New(alloc(), subject, type);
if (!replace)
return false;
if (replace == subject)
break;
current->add(replace);
if (replace != subject) {
// Make sure we don't hoist it above the MTest, we can use the
// 'dependency' of an MInstruction. This is normally used by
// Alias Analysis, but won't get overwritten, since this
// instruction doesn't have an AliasSet.
replace->setDependency(test);
}
// Make sure we don't hoist it above the MTest, we can use the
// 'dependency' of an MInstruction. This is normally used by
// Alias Analysis, but won't get overwritten, since this
// instruction doesn't have an AliasSet.
replace->setDependency(test);
if (replace->type() == MIRType_Undefined)
replace = constant(UndefinedValue());
if (replace->type() == MIRType_Null)
replace = constant(NullValue());
}
current->setSlot(i, replace);
}
@ -3312,7 +3317,7 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test)
if (!ins)
return true;
switch(ins->op()) {
switch (ins->op()) {
case MDefinition::Op_Not:
return improveTypesAtTest(ins->toNot()->getOperand(0), !trueBranch, test);
case MDefinition::Op_IsObject: {
@ -4245,7 +4250,12 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
return oom();
MTypeBarrier *barrier = MTypeBarrier::New(alloc(), callInfo.thisArg(), clonedTypes);
current->add(barrier);
callInfo.setThis(barrier);
if (barrier->type() == MIRType_Undefined)
callInfo.setThis(constant(UndefinedValue()));
else if (barrier->type() == MIRType_Null)
callInfo.setThis(constant(NullValue()));
else
callInfo.setThis(barrier);
}
}

View File

@ -259,34 +259,35 @@ TypeBarrierPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
return true;
}
// Input is a value. Unbox the input to the requested type.
if (inputType == MIRType_Value) {
MOZ_ASSERT(outputType != MIRType_Value);
// Box input if needed.
if (inputType != MIRType_Value) {
MOZ_ASSERT(ins->alwaysBails());
ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
}
// We can't unbox a value to null/undefined/lazyargs. So keep output
// also a value.
if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
MOZ_ASSERT(!ins->hasDefUses());
ins->setResultType(MIRType_Value);
return true;
}
MUnbox *unbox = MUnbox::New(alloc, ins->getOperand(0), outputType, MUnbox::TypeBarrier);
ins->block()->insertBefore(ins, unbox);
// The TypeBarrier is equivalent to removing branches with unexpected
// types. The unexpected types would have changed Range Analysis
// predictions. As such, we need to prevent destructive optimizations.
ins->block()->flagOperandsOfPrunedBranches(unbox);
ins->replaceOperand(0, unbox);
// We can't unbox a value to null/undefined/lazyargs. So keep output
// also a value.
// Note: Using setResultType shouldn't be done in TypePolicies,
// Here it is fine, since the type barrier has no uses.
if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
MOZ_ASSERT(!ins->hasDefUses());
ins->setResultType(MIRType_Value);
return true;
}
// In the remaining cases we will alway bail. OutputType doesn't matter.
// Take inputType so we can use redefine during lowering.
MOZ_ASSERT(ins->alwaysBails());
ins->setResultType(inputType);
// Unbox / propagate the right type.
MUnbox::Mode mode = MUnbox::TypeBarrier;
MInstruction *replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(0, replace);
if (!replace->typePolicy()->adjustInputs(alloc, replace))
return false;
// The TypeBarrier is equivalent to removing branches with unexpected
// types. The unexpected types would have changed Range Analysis
// predictions. As such, we need to prevent destructive optimizations.
ins->block()->flagOperandsOfPrunedBranches(replace);
return true;
}
@ -851,29 +852,46 @@ bool
FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MOZ_ASSERT(ins->numOperands() == 1);
MIRType inputType = ins->getOperand(0)->type();
MIRType outputType = ins->type();
// Do nothing if already same type.
if (ins->type() == ins->getOperand(0)->type())
// Input and output type are already in accordance.
if (inputType == outputType)
return true;
// Box input if ouput type is MIRType_Value
if (ins->type() == MIRType_Value) {
// Output is a value, box the input.
if (outputType == MIRType_Value) {
MOZ_ASSERT(inputType != MIRType_Value);
ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
return true;
}
// For simplicity just mark output type as MIRType_Value if input type
// is MIRType_Value. It should be possible to unbox, but we need to
// add extra code for Undefined/Null.
if (ins->getOperand(0)->type() == MIRType_Value) {
// The outputType should always be a subset of the inputType.
// So if types don't equal, the input type is definitely a MIRType_Value.
if (inputType != MIRType_Value)
MOZ_CRASH("Types should be in accordance.");
// We can't unbox a value to null/undefined/lazyargs. So keep output
// also a value.
// Note: Using setResultType shouldn't be done in TypePolicies,
// Here it is fine, since the type barrier has no uses.
if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
MOZ_ASSERT(!ins->hasDefUses());
ins->setResultType(MIRType_Value);
return true;
}
// In all other cases we will definitely bail, since types don't
// correspond. Just box and mark output as MIRType_Value.
ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
ins->setResultType(MIRType_Value);
// Unbox / propagate the right type.
MUnbox::Mode mode = MUnbox::Infallible;
MInstruction *replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(0, replace);
if (!replace->typePolicy()->adjustInputs(alloc, replace))
return false;
// Carry over the dependency the MFilterTypeSet had.
replace->setDependency(ins->dependency());
return true;
}