mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1073861 - IonMonkey: Don't update types during type policy, r=jandem
This commit is contained in:
parent
d2772198b4
commit
1a57f38c68
69
js/src/jit-test/tests/ion/bug1073861.js
Normal file
69
js/src/jit-test/tests/ion/bug1073861.js
Normal 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)
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user