mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1004169. Make sure MTest always uses TI information for deciding whether its operand might emulate undefined. r=jandem
This commit is contained in:
parent
d7004c64a6
commit
0697387fc7
@ -683,10 +683,11 @@ bool
|
||||
CodeGenerator::visitTestVAndBranch(LTestVAndBranch *lir)
|
||||
{
|
||||
OutOfLineTestObject *ool = nullptr;
|
||||
// XXXbz operandMightEmulateUndefined lies a lot. See bug 1004169. In
|
||||
// practice, we don't need the OutOfLineTestObject if the input to our test
|
||||
// is not an object.
|
||||
MDefinition* input = lir->mir()->input();
|
||||
// Unfortunately, it's possible that someone (e.g. phi elimination) switched
|
||||
// out our input after we did cacheOperandMightEmulateUndefined. So we
|
||||
// might think it can emulate undefined _and_ know that it can't be an
|
||||
// object.
|
||||
if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType_Object)) {
|
||||
ool = new(alloc()) OutOfLineTestObject();
|
||||
if (!addOutOfLineCode(ool))
|
||||
|
@ -2168,7 +2168,7 @@ IonBuilder::processDoWhileCondEnd(CFGState &state)
|
||||
}
|
||||
|
||||
// Create the test instruction and end the current block.
|
||||
MTest *test = MTest::New(alloc(), vins, state.loop.entry, successor);
|
||||
MTest *test = newTest(vins, state.loop.entry, successor);
|
||||
current->end(test);
|
||||
return finishLoop(state, successor);
|
||||
}
|
||||
@ -2189,9 +2189,9 @@ IonBuilder::processWhileCondEnd(CFGState &state)
|
||||
|
||||
MTest *test;
|
||||
if (JSOp(*pc) == JSOP_IFNE)
|
||||
test = MTest::New(alloc(), ins, body, state.loop.successor);
|
||||
test = newTest(ins, body, state.loop.successor);
|
||||
else
|
||||
test = MTest::New(alloc(), ins, state.loop.successor, body);
|
||||
test = newTest(ins, state.loop.successor, body);
|
||||
current->end(test);
|
||||
|
||||
state.state = CFGState::WHILE_LOOP_BODY;
|
||||
@ -2229,7 +2229,7 @@ IonBuilder::processForCondEnd(CFGState &state)
|
||||
if (!body || !state.loop.successor)
|
||||
return ControlStatus_Error;
|
||||
|
||||
MTest *test = MTest::New(alloc(), ins, body, state.loop.successor);
|
||||
MTest *test = newTest(ins, body, state.loop.successor);
|
||||
current->end(test);
|
||||
|
||||
state.state = CFGState::FOR_LOOP_BODY;
|
||||
@ -3352,7 +3352,7 @@ IonBuilder::processCondSwitchCase(CFGState &state)
|
||||
cmpResult->infer(inspector, pc);
|
||||
JS_ASSERT(!cmpResult->isEffectful());
|
||||
current->add(cmpResult);
|
||||
current->end(MTest::New(alloc(), cmpResult, bodyBlock, caseBlock));
|
||||
current->end(newTest(cmpResult, bodyBlock, caseBlock));
|
||||
|
||||
// Add last case as predecessor of the body if the body is aliasing
|
||||
// the previous case body.
|
||||
@ -3463,9 +3463,8 @@ IonBuilder::jsop_andor(JSOp op)
|
||||
return false;
|
||||
|
||||
MTest *test = (op == JSOP_AND)
|
||||
? MTest::New(alloc(), lhs, evalRhs, join)
|
||||
: MTest::New(alloc(), lhs, join, evalRhs);
|
||||
test->infer();
|
||||
? newTest(lhs, evalRhs, join)
|
||||
: newTest(lhs, join, evalRhs);
|
||||
current->end(test);
|
||||
|
||||
if (!cfgStack_.append(CFGState::AndOr(joinStart, join)))
|
||||
@ -3516,7 +3515,7 @@ IonBuilder::jsop_ifeq(JSOp op)
|
||||
if (!ifTrue || !ifFalse)
|
||||
return false;
|
||||
|
||||
MTest *test = MTest::New(alloc(), ins, ifTrue, ifFalse);
|
||||
MTest *test = newTest(ins, ifTrue, ifFalse);
|
||||
current->end(test);
|
||||
|
||||
// The bytecode for if/ternary gets emitted either like this:
|
||||
@ -3645,7 +3644,7 @@ IonBuilder::jsop_try()
|
||||
// Add MTest(true, tryBlock, successorBlock).
|
||||
MConstant *true_ = MConstant::New(alloc(), BooleanValue(true));
|
||||
current->add(true_);
|
||||
current->end(MTest::New(alloc(), true_, tryBlock, successor));
|
||||
current->end(newTest(true_, tryBlock, successor));
|
||||
} else {
|
||||
successor = nullptr;
|
||||
current->end(MGoto::New(alloc(), tryBlock));
|
||||
@ -6005,6 +6004,14 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
|
||||
return block;
|
||||
}
|
||||
|
||||
MTest *
|
||||
IonBuilder::newTest(MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse)
|
||||
{
|
||||
MTest *test = MTest::New(alloc(), ins, ifTrue, ifFalse);
|
||||
test->cacheOperandMightEmulateUndefined();
|
||||
return test;
|
||||
}
|
||||
|
||||
// A resume point is a mapping of stack slots to MDefinitions. It is used to
|
||||
// capture the environment such that if a guard fails, and IonMonkey needs
|
||||
// to exit back to the interpreter, the interpreter state can be
|
||||
@ -8284,7 +8291,7 @@ IonBuilder::jsop_not()
|
||||
MNot *ins = MNot::New(alloc(), value);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
ins->infer();
|
||||
ins->cacheOperandMightEmulateUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9772,7 +9779,7 @@ IonBuilder::jsop_typeof()
|
||||
MDefinition *input = current->pop();
|
||||
MTypeOf *ins = MTypeOf::New(alloc(), input, input->type());
|
||||
|
||||
ins->infer();
|
||||
ins->cacheInputMaybeCallableOrEmulatesUndefined();
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
@ -289,6 +289,14 @@ class IonBuilder : public MIRGenerator
|
||||
return newBlockAfter(at, nullptr, pc);
|
||||
}
|
||||
|
||||
// We want to make sure that our MTest instructions all check whether the
|
||||
// thing being tested might emulate undefined. So we funnel their creation
|
||||
// through this method, to make sure that happens. We don't want to just do
|
||||
// the check in MTest::New, because that can run on background compilation
|
||||
// threads, and we're not sure it's safe to touch that part of the typeset
|
||||
// from a background thread.
|
||||
MTest *newTest(MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
|
||||
|
||||
// Given a list of pending breaks, creates a new block and inserts a Goto
|
||||
// linking each break to the new block.
|
||||
MBasicBlock *createBreakCatchBlock(DeferredEdge *edge, jsbytecode *pc);
|
||||
|
@ -1637,10 +1637,10 @@ IonBuilder::inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Clas
|
||||
current->add(either);
|
||||
// Convert to bool with the '!!' idiom
|
||||
MNot *resultInverted = MNot::New(alloc(), either);
|
||||
resultInverted->infer();
|
||||
resultInverted->cacheOperandMightEmulateUndefined();
|
||||
current->add(resultInverted);
|
||||
MNot *result = MNot::New(alloc(), resultInverted);
|
||||
result->infer();
|
||||
result->cacheOperandMightEmulateUndefined();
|
||||
current->add(result);
|
||||
current->push(result);
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBl
|
||||
}
|
||||
|
||||
void
|
||||
MTest::infer()
|
||||
MTest::cacheOperandMightEmulateUndefined()
|
||||
{
|
||||
JS_ASSERT(operandMightEmulateUndefined());
|
||||
|
||||
@ -2174,7 +2174,7 @@ MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers)
|
||||
}
|
||||
|
||||
void
|
||||
MTypeOf::infer()
|
||||
MTypeOf::cacheInputMaybeCallableOrEmulatesUndefined()
|
||||
{
|
||||
JS_ASSERT(inputMaybeCallableOrEmulatesUndefined());
|
||||
|
||||
@ -2669,7 +2669,7 @@ MCompare::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *f
|
||||
}
|
||||
|
||||
void
|
||||
MNot::infer()
|
||||
MNot::cacheOperandMightEmulateUndefined()
|
||||
{
|
||||
JS_ASSERT(operandMightEmulateUndefined());
|
||||
|
||||
|
@ -1304,7 +1304,13 @@ class MTest
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
void infer();
|
||||
|
||||
// We cache whether our operand might emulate undefined, but we don't want
|
||||
// to do that from New() or the constructor, since those can be called on
|
||||
// background threads. So make callers explicitly call it if they want us
|
||||
// to check whether the operand might do this. If this method is never
|
||||
// called, we'll assume our operand can emulate undefined.
|
||||
void cacheOperandMightEmulateUndefined();
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
|
||||
bool *filtersNull);
|
||||
@ -3272,7 +3278,7 @@ class MTypeOf
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
void infer();
|
||||
void cacheInputMaybeCallableOrEmulatesUndefined();
|
||||
|
||||
bool inputMaybeCallableOrEmulatesUndefined() const {
|
||||
return inputMaybeCallableOrEmulatesUndefined_;
|
||||
@ -5839,7 +5845,7 @@ class MNot
|
||||
|
||||
INSTRUCTION_HEADER(Not);
|
||||
|
||||
void infer();
|
||||
void cacheOperandMightEmulateUndefined();
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
|
||||
void markOperandCantEmulateUndefined() {
|
||||
|
Loading…
Reference in New Issue
Block a user