[turbofan] Remember types for deoptimization during simplified lowering.
With this change, we remember the types of frame state inputs (in a new operator, called TypedStateValues). Instead of inferring the value types when building translations, we used the recorded types. The original approach was not reliable because the passes after simplified lowering can change node types, and this in turn confuses the translation builder. BUG=chromium:468727 LOG=n R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/1015423002 Cr-Commit-Position: refs/heads/master@{#27310}
This commit is contained in:
parent
87af601824
commit
b7dc9c580a
@ -509,8 +509,10 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
|
||||
InstructionOperand* op,
|
||||
MachineType type) {
|
||||
if (op->IsStackSlot()) {
|
||||
if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
|
||||
type == kMachInt16) {
|
||||
// TODO(jarin) kMachBool and kRepBit should materialize true and false
|
||||
// rather than creating an int value.
|
||||
if (type == kMachBool || type == kRepBit || type == kMachInt32 ||
|
||||
type == kMachInt8 || type == kMachInt16) {
|
||||
translation->StoreInt32StackSlot(op->index());
|
||||
} else if (type == kMachUint32 || type == kMachUint16 ||
|
||||
type == kMachUint8) {
|
||||
@ -525,8 +527,10 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
|
||||
translation->StoreDoubleStackSlot(op->index());
|
||||
} else if (op->IsRegister()) {
|
||||
InstructionOperandConverter converter(this, instr);
|
||||
if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
|
||||
type == kMachInt16) {
|
||||
// TODO(jarin) kMachBool and kRepBit should materialize true and false
|
||||
// rather than creating an int value.
|
||||
if (type == kMachBool || type == kRepBit || type == kMachInt32 ||
|
||||
type == kMachInt8 || type == kMachInt16) {
|
||||
translation->StoreInt32Register(converter.ToRegister(op));
|
||||
} else if (type == kMachUint32 || type == kMachUint16 ||
|
||||
type == kMachUint8) {
|
||||
@ -546,12 +550,14 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
|
||||
Handle<Object> constant_object;
|
||||
switch (constant.type()) {
|
||||
case Constant::kInt32:
|
||||
DCHECK(type == kMachInt32 || type == kMachUint32);
|
||||
DCHECK(type == kMachInt32 || type == kMachUint32 || type == kRepBit);
|
||||
constant_object =
|
||||
isolate()->factory()->NewNumberFromInt(constant.ToInt32());
|
||||
break;
|
||||
case Constant::kFloat64:
|
||||
DCHECK(type == kMachFloat64 || type == kMachAnyTagged);
|
||||
DCHECK(type == kMachFloat64 || type == kMachAnyTagged ||
|
||||
type == kRepTagged || type == (kTypeInt32 | kRepTagged) ||
|
||||
type == (kTypeUint32 | kRepTagged));
|
||||
constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
|
||||
break;
|
||||
case Constant::kHeapObject:
|
||||
|
@ -604,6 +604,15 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) {
|
||||
}
|
||||
|
||||
|
||||
const Operator* CommonOperatorBuilder::TypedStateValues(
|
||||
const ZoneVector<MachineType>* types) {
|
||||
return new (zone()) Operator1<const ZoneVector<MachineType>*>( // --
|
||||
IrOpcode::kTypedStateValues, Operator::kPure, // opcode
|
||||
"TypedStateValues", // name
|
||||
static_cast<int>(types->size()), 0, 0, 1, 0, 0, types); // counts
|
||||
}
|
||||
|
||||
|
||||
const Operator* CommonOperatorBuilder::FrameState(
|
||||
FrameStateType type, BailoutId bailout_id,
|
||||
OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
|
||||
|
@ -205,6 +205,7 @@ class CommonOperatorBuilder FINAL : public ZoneObject {
|
||||
const Operator* ValueEffect(int arguments);
|
||||
const Operator* Finish(int arguments);
|
||||
const Operator* StateValues(int arguments);
|
||||
const Operator* TypedStateValues(const ZoneVector<MachineType>* types);
|
||||
const Operator* FrameState(
|
||||
FrameStateType type, BailoutId bailout_id,
|
||||
OutputFrameStateCombine state_combine,
|
||||
|
@ -574,147 +574,6 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
|
||||
}
|
||||
|
||||
|
||||
MachineType InstructionSelector::GetMachineType(Node* node) {
|
||||
DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes.
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kStart:
|
||||
case IrOpcode::kLoop:
|
||||
case IrOpcode::kEnd:
|
||||
case IrOpcode::kBranch:
|
||||
case IrOpcode::kIfTrue:
|
||||
case IrOpcode::kIfFalse:
|
||||
case IrOpcode::kSwitch:
|
||||
case IrOpcode::kIfValue:
|
||||
case IrOpcode::kIfDefault:
|
||||
case IrOpcode::kEffectPhi:
|
||||
case IrOpcode::kEffectSet:
|
||||
case IrOpcode::kMerge:
|
||||
// No code needed for these graph artifacts.
|
||||
return kMachNone;
|
||||
case IrOpcode::kFinish:
|
||||
return kMachAnyTagged;
|
||||
case IrOpcode::kParameter:
|
||||
return linkage()->GetParameterType(OpParameter<int>(node));
|
||||
case IrOpcode::kOsrValue:
|
||||
return kMachAnyTagged;
|
||||
case IrOpcode::kPhi:
|
||||
return OpParameter<MachineType>(node);
|
||||
case IrOpcode::kProjection:
|
||||
// TODO(jarin) Really project from outputs.
|
||||
return kMachAnyTagged;
|
||||
case IrOpcode::kInt32Constant:
|
||||
return kMachInt32;
|
||||
case IrOpcode::kInt64Constant:
|
||||
return kMachInt64;
|
||||
case IrOpcode::kExternalConstant:
|
||||
return kMachPtr;
|
||||
case IrOpcode::kFloat64Constant:
|
||||
return kMachFloat64;
|
||||
case IrOpcode::kHeapConstant:
|
||||
case IrOpcode::kNumberConstant:
|
||||
return kMachAnyTagged;
|
||||
case IrOpcode::kCall:
|
||||
return kMachAnyTagged;
|
||||
case IrOpcode::kFrameState:
|
||||
case IrOpcode::kStateValues:
|
||||
return kMachNone;
|
||||
case IrOpcode::kLoad:
|
||||
return OpParameter<LoadRepresentation>(node);
|
||||
case IrOpcode::kStore:
|
||||
return kMachNone;
|
||||
case IrOpcode::kCheckedLoad:
|
||||
return OpParameter<MachineType>(node);
|
||||
case IrOpcode::kCheckedStore:
|
||||
return kMachNone;
|
||||
case IrOpcode::kWord32And:
|
||||
case IrOpcode::kWord32Or:
|
||||
case IrOpcode::kWord32Xor:
|
||||
case IrOpcode::kWord32Shl:
|
||||
case IrOpcode::kWord32Shr:
|
||||
case IrOpcode::kWord32Sar:
|
||||
case IrOpcode::kWord32Ror:
|
||||
return kMachInt32;
|
||||
case IrOpcode::kWord32Equal:
|
||||
return kMachBool;
|
||||
case IrOpcode::kWord64And:
|
||||
case IrOpcode::kWord64Or:
|
||||
case IrOpcode::kWord64Xor:
|
||||
case IrOpcode::kWord64Shl:
|
||||
case IrOpcode::kWord64Shr:
|
||||
case IrOpcode::kWord64Sar:
|
||||
case IrOpcode::kWord64Ror:
|
||||
return kMachInt64;
|
||||
case IrOpcode::kWord64Equal:
|
||||
return kMachBool;
|
||||
case IrOpcode::kInt32Add:
|
||||
case IrOpcode::kInt32AddWithOverflow:
|
||||
case IrOpcode::kInt32Sub:
|
||||
case IrOpcode::kInt32SubWithOverflow:
|
||||
case IrOpcode::kInt32Mul:
|
||||
case IrOpcode::kInt32Div:
|
||||
case IrOpcode::kInt32Mod:
|
||||
return kMachInt32;
|
||||
case IrOpcode::kInt32LessThan:
|
||||
case IrOpcode::kInt32LessThanOrEqual:
|
||||
case IrOpcode::kUint32LessThan:
|
||||
case IrOpcode::kUint32LessThanOrEqual:
|
||||
return kMachBool;
|
||||
case IrOpcode::kInt64Add:
|
||||
case IrOpcode::kInt64Sub:
|
||||
case IrOpcode::kInt64Mul:
|
||||
case IrOpcode::kInt64Div:
|
||||
case IrOpcode::kInt64Mod:
|
||||
return kMachInt64;
|
||||
case IrOpcode::kInt64LessThan:
|
||||
case IrOpcode::kInt64LessThanOrEqual:
|
||||
return kMachBool;
|
||||
case IrOpcode::kChangeFloat32ToFloat64:
|
||||
case IrOpcode::kChangeInt32ToFloat64:
|
||||
case IrOpcode::kChangeUint32ToFloat64:
|
||||
return kMachFloat64;
|
||||
case IrOpcode::kChangeFloat64ToInt32:
|
||||
return kMachInt32;
|
||||
case IrOpcode::kChangeFloat64ToUint32:
|
||||
return kMachUint32;
|
||||
case IrOpcode::kChangeInt32ToInt64:
|
||||
return kMachInt64;
|
||||
case IrOpcode::kChangeUint32ToUint64:
|
||||
return kMachUint64;
|
||||
case IrOpcode::kTruncateFloat64ToFloat32:
|
||||
return kMachFloat32;
|
||||
case IrOpcode::kTruncateFloat64ToInt32:
|
||||
case IrOpcode::kTruncateInt64ToInt32:
|
||||
return kMachInt32;
|
||||
case IrOpcode::kFloat64Add:
|
||||
case IrOpcode::kFloat64Sub:
|
||||
case IrOpcode::kFloat64Mul:
|
||||
case IrOpcode::kFloat64Div:
|
||||
case IrOpcode::kFloat64Mod:
|
||||
case IrOpcode::kFloat64Max:
|
||||
case IrOpcode::kFloat64Min:
|
||||
case IrOpcode::kFloat64Sqrt:
|
||||
case IrOpcode::kFloat64RoundDown:
|
||||
case IrOpcode::kFloat64RoundTruncate:
|
||||
case IrOpcode::kFloat64RoundTiesAway:
|
||||
return kMachFloat64;
|
||||
case IrOpcode::kFloat64Equal:
|
||||
case IrOpcode::kFloat64LessThan:
|
||||
case IrOpcode::kFloat64LessThanOrEqual:
|
||||
return kMachBool;
|
||||
case IrOpcode::kFloat64ExtractLowWord32:
|
||||
case IrOpcode::kFloat64ExtractHighWord32:
|
||||
return kMachInt32;
|
||||
case IrOpcode::kFloat64InsertLowWord32:
|
||||
case IrOpcode::kFloat64InsertHighWord32:
|
||||
return kMachFloat64;
|
||||
default:
|
||||
V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
|
||||
node->opcode(), node->op()->mnemonic(), node->id());
|
||||
}
|
||||
return kMachNone;
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitNode(Node* node) {
|
||||
DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes.
|
||||
SourcePosition source_position = source_positions_->GetSourcePosition(node);
|
||||
@ -1149,9 +1008,9 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
|
||||
Node* state) {
|
||||
DCHECK(state->opcode() == IrOpcode::kFrameState);
|
||||
DCHECK_EQ(5, state->InputCount());
|
||||
DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(0)->opcode());
|
||||
DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(1)->opcode());
|
||||
DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(2)->opcode());
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(0)->opcode());
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(1)->opcode());
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(2)->opcode());
|
||||
FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
|
||||
|
||||
int parameters =
|
||||
@ -1197,9 +1056,9 @@ void InstructionSelector::AddFrameStateInputs(
|
||||
Node* stack = state->InputAt(2);
|
||||
Node* context = state->InputAt(3);
|
||||
|
||||
DCHECK_EQ(IrOpcode::kStateValues, parameters->op()->opcode());
|
||||
DCHECK_EQ(IrOpcode::kStateValues, locals->op()->opcode());
|
||||
DCHECK_EQ(IrOpcode::kStateValues, stack->op()->opcode());
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, parameters->op()->opcode());
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, locals->op()->opcode());
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, stack->op()->opcode());
|
||||
|
||||
DCHECK_EQ(descriptor->parameters_count(),
|
||||
StateValuesAccess(parameters).size());
|
||||
@ -1211,21 +1070,22 @@ void InstructionSelector::AddFrameStateInputs(
|
||||
|
||||
OperandGenerator g(this);
|
||||
size_t value_index = 0;
|
||||
for (Node* input_node : StateValuesAccess(parameters)) {
|
||||
inputs->push_back(UseOrImmediate(&g, input_node));
|
||||
descriptor->SetType(value_index++, GetMachineType(input_node));
|
||||
for (StateValuesAccess::TypedNode input_node :
|
||||
StateValuesAccess(parameters)) {
|
||||
inputs->push_back(UseOrImmediate(&g, input_node.node));
|
||||
descriptor->SetType(value_index++, input_node.type);
|
||||
}
|
||||
if (descriptor->HasContext()) {
|
||||
inputs->push_back(UseOrImmediate(&g, context));
|
||||
descriptor->SetType(value_index++, kMachAnyTagged);
|
||||
}
|
||||
for (Node* input_node : StateValuesAccess(locals)) {
|
||||
inputs->push_back(UseOrImmediate(&g, input_node));
|
||||
descriptor->SetType(value_index++, GetMachineType(input_node));
|
||||
for (StateValuesAccess::TypedNode input_node : StateValuesAccess(locals)) {
|
||||
inputs->push_back(UseOrImmediate(&g, input_node.node));
|
||||
descriptor->SetType(value_index++, input_node.type);
|
||||
}
|
||||
for (Node* input_node : StateValuesAccess(stack)) {
|
||||
inputs->push_back(UseOrImmediate(&g, input_node));
|
||||
descriptor->SetType(value_index++, GetMachineType(input_node));
|
||||
for (StateValuesAccess::TypedNode input_node : StateValuesAccess(stack)) {
|
||||
inputs->push_back(UseOrImmediate(&g, input_node.node));
|
||||
descriptor->SetType(value_index++, input_node.type);
|
||||
}
|
||||
DCHECK(value_index == descriptor->GetSize());
|
||||
}
|
||||
|
@ -173,7 +173,6 @@ class InstructionSelector FINAL {
|
||||
FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
|
||||
void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs,
|
||||
FrameStateDescriptor* descriptor);
|
||||
MachineType GetMachineType(Node* node);
|
||||
|
||||
// ===========================================================================
|
||||
// ============= Architecture-specific graph covering methods. ===============
|
||||
|
@ -142,12 +142,12 @@ void NonLiveFrameStateSlotReplacer::ClearNonLiveFrameStateSlots(
|
||||
Node* NonLiveFrameStateSlotReplacer::ClearNonLiveStateValues(
|
||||
Node* values, BitVector* liveness) {
|
||||
DCHECK(inputs_buffer_.empty());
|
||||
for (Node* node : StateValuesAccess(values)) {
|
||||
for (StateValuesAccess::TypedNode node : StateValuesAccess(values)) {
|
||||
// Index of the next variable is its furure index in the inputs buffer,
|
||||
// i.e., the buffer's size.
|
||||
int var = static_cast<int>(inputs_buffer_.size());
|
||||
bool live = liveness->Contains(var) || permanently_live_.Contains(var);
|
||||
inputs_buffer_.push_back(live ? node : replacement_node_);
|
||||
inputs_buffer_.push_back(live ? node.node : replacement_node_);
|
||||
}
|
||||
Node* result = state_values_cache()->GetNodeForValues(
|
||||
inputs_buffer_.empty() ? nullptr : &(inputs_buffer_.front()),
|
||||
|
@ -48,6 +48,7 @@
|
||||
V(Finish) \
|
||||
V(FrameState) \
|
||||
V(StateValues) \
|
||||
V(TypedStateValues) \
|
||||
V(Call) \
|
||||
V(Parameter) \
|
||||
V(OsrValue) \
|
||||
|
@ -424,6 +424,25 @@ class RepresentationSelector {
|
||||
}
|
||||
}
|
||||
|
||||
void VisitStateValues(Node* node) {
|
||||
if (phase_ == PROPAGATE) {
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
Enqueue(node->InputAt(i), kTypeAny);
|
||||
}
|
||||
} else {
|
||||
Zone* zone = jsgraph_->zone();
|
||||
ZoneVector<MachineType>* types =
|
||||
new (zone->New(sizeof(ZoneVector<MachineType>)))
|
||||
ZoneVector<MachineType>(node->InputCount(), zone);
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output;
|
||||
(*types)[i] = static_cast<MachineType>(input_type);
|
||||
}
|
||||
node->set_op(jsgraph_->common()->TypedStateValues(types));
|
||||
}
|
||||
SetOutput(node, kMachAnyTagged);
|
||||
}
|
||||
|
||||
const Operator* Int32Op(Node* node) {
|
||||
return changer_->Int32OperatorFor(node->opcode());
|
||||
}
|
||||
@ -1021,10 +1040,7 @@ class RepresentationSelector {
|
||||
case IrOpcode::kLoadStackPointer:
|
||||
return VisitLeaf(node, kMachPtr);
|
||||
case IrOpcode::kStateValues:
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
ProcessInput(node, i, kTypeAny);
|
||||
}
|
||||
SetOutput(node, kMachAnyTagged);
|
||||
VisitStateValues(node);
|
||||
break;
|
||||
default:
|
||||
VisitInputs(node);
|
||||
|
@ -173,6 +173,7 @@ Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) {
|
||||
#if DEBUG
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
DCHECK_NE(values[i]->opcode(), IrOpcode::kStateValues);
|
||||
DCHECK_NE(values[i]->opcode(), IrOpcode::kTypedStateValues);
|
||||
}
|
||||
#endif
|
||||
if (count == 0) {
|
||||
@ -190,7 +191,8 @@ Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) {
|
||||
Node* tree = BuildTree(&it, height);
|
||||
|
||||
// If the 'tree' is a single node, equip it with a StateValues wrapper.
|
||||
if (tree->opcode() != IrOpcode::kStateValues) {
|
||||
if (tree->opcode() != IrOpcode::kStateValues &&
|
||||
tree->opcode() != IrOpcode::kTypedStateValues) {
|
||||
tree = GetValuesNodeFromCache(&tree, 1);
|
||||
}
|
||||
|
||||
@ -249,7 +251,8 @@ void StateValuesAccess::iterator::Advance() {
|
||||
return;
|
||||
}
|
||||
Top()->index++;
|
||||
} else if (node->InputAt(index)->opcode() == IrOpcode::kStateValues) {
|
||||
} else if (node->InputAt(index)->opcode() == IrOpcode::kStateValues ||
|
||||
node->InputAt(index)->opcode() == IrOpcode::kTypedStateValues) {
|
||||
// Nested state, we need to push to the stack.
|
||||
Push(node->InputAt(index));
|
||||
} else {
|
||||
@ -265,6 +268,19 @@ Node* StateValuesAccess::iterator::node() {
|
||||
}
|
||||
|
||||
|
||||
MachineType StateValuesAccess::iterator::type() {
|
||||
Node* state = Top()->node;
|
||||
if (state->opcode() == IrOpcode::kStateValues) {
|
||||
return kMachAnyTagged;
|
||||
} else {
|
||||
DCHECK_EQ(IrOpcode::kTypedStateValues, state->opcode());
|
||||
const ZoneVector<MachineType>* types =
|
||||
OpParameter<const ZoneVector<MachineType>*>(state);
|
||||
return (*types)[Top()->index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool StateValuesAccess::iterator::operator!=(iterator& other) {
|
||||
// We only allow comparison with end().
|
||||
CHECK(other.done());
|
||||
@ -278,13 +294,16 @@ StateValuesAccess::iterator& StateValuesAccess::iterator::operator++() {
|
||||
}
|
||||
|
||||
|
||||
Node* StateValuesAccess::iterator::operator*() { return node(); }
|
||||
StateValuesAccess::TypedNode StateValuesAccess::iterator::operator*() {
|
||||
return TypedNode(node(), type());
|
||||
}
|
||||
|
||||
|
||||
size_t StateValuesAccess::size() {
|
||||
size_t count = 0;
|
||||
for (int i = 0; i < node_->InputCount(); i++) {
|
||||
if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues) {
|
||||
if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues ||
|
||||
node_->InputAt(i)->opcode() == IrOpcode::kTypedStateValues) {
|
||||
count += StateValuesAccess(node_->InputAt(i)).size();
|
||||
} else {
|
||||
count++;
|
||||
|
@ -62,12 +62,18 @@ class StateValuesCache {
|
||||
|
||||
class StateValuesAccess {
|
||||
public:
|
||||
struct TypedNode {
|
||||
Node* node;
|
||||
MachineType type;
|
||||
TypedNode(Node* node, MachineType type) : node(node), type(type) {}
|
||||
};
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
// Bare minimum of operators needed for range iteration.
|
||||
bool operator!=(iterator& other);
|
||||
iterator& operator++();
|
||||
Node* operator*();
|
||||
TypedNode operator*();
|
||||
|
||||
private:
|
||||
friend class StateValuesAccess;
|
||||
@ -76,6 +82,7 @@ class StateValuesAccess {
|
||||
explicit iterator(Node* node);
|
||||
|
||||
Node* node();
|
||||
MachineType type();
|
||||
bool done();
|
||||
void Advance();
|
||||
|
||||
|
@ -716,6 +716,11 @@ Bounds Typer::Visitor::TypeStateValues(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeTypedStateValues(Node* node) {
|
||||
return Bounds(Type::None(zone()), Type::Internal(zone()));
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeCall(Node* node) {
|
||||
return Bounds::Unbounded(zone());
|
||||
}
|
||||
|
@ -427,6 +427,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
// TODO(jarin): what are the constraints on these?
|
||||
break;
|
||||
case IrOpcode::kStateValues:
|
||||
case IrOpcode::kTypedStateValues:
|
||||
// TODO(jarin): what are the constraints on these?
|
||||
break;
|
||||
case IrOpcode::kCall:
|
||||
|
@ -46,7 +46,9 @@ class DeoptCodegenTester {
|
||||
function(NewFunction(src)),
|
||||
parse_info(scope->main_zone(), function),
|
||||
info(&parse_info),
|
||||
bailout_id(-1) {
|
||||
bailout_id(-1),
|
||||
tagged_type(1, kMachAnyTagged, zone()),
|
||||
empty_types(zone()) {
|
||||
CHECK(Parser::ParseStatic(&parse_info));
|
||||
info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
|
||||
CHECK(Compiler::Analyze(&parse_info));
|
||||
@ -83,6 +85,8 @@ class DeoptCodegenTester {
|
||||
Handle<Code> result_code;
|
||||
TestInstrSeq* code;
|
||||
Graph* graph;
|
||||
ZoneVector<MachineType> tagged_type;
|
||||
ZoneVector<MachineType> empty_types;
|
||||
};
|
||||
|
||||
|
||||
@ -120,9 +124,10 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
||||
m.NewNode(common.HeapConstant(caller_context_constant));
|
||||
|
||||
bailout_id = GetCallBailoutId();
|
||||
Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
|
||||
Node* locals = m.NewNode(common.StateValues(0));
|
||||
Node* stack = m.NewNode(common.StateValues(0));
|
||||
Node* parameters =
|
||||
m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant());
|
||||
Node* locals = m.NewNode(common.TypedStateValues(&empty_types));
|
||||
Node* stack = m.NewNode(common.TypedStateValues(&empty_types));
|
||||
|
||||
Node* state_node = m.NewNode(
|
||||
common.FrameState(JS_FRAME, bailout_id,
|
||||
@ -235,9 +240,10 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
|
||||
Node* context_node = m.NewNode(common.HeapConstant(context_constant));
|
||||
|
||||
bailout_id = GetCallBailoutId();
|
||||
Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
|
||||
Node* locals = m.NewNode(common.StateValues(0));
|
||||
Node* stack = m.NewNode(common.StateValues(0));
|
||||
Node* parameters =
|
||||
m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant());
|
||||
Node* locals = m.NewNode(common.TypedStateValues(&empty_types));
|
||||
Node* stack = m.NewNode(common.TypedStateValues(&empty_types));
|
||||
|
||||
Node* state_node = m.NewNode(
|
||||
common.FrameState(JS_FRAME, bailout_id,
|
||||
|
16
test/mjsunit/compiler/regress-468727.js
Normal file
16
test/mjsunit/compiler/regress-468727.js
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --noanalyze-environment-liveness
|
||||
|
||||
function f() {
|
||||
var __v_7 = -126 - __v_3;
|
||||
var __v_17 = ((__v_15 & __v_14) != 4) | 16;
|
||||
if (__v_17) {
|
||||
var __v_11 = 1 << __v_7;
|
||||
}
|
||||
__v_12 >>= __v_3;
|
||||
}
|
||||
|
||||
assertThrows(f);
|
@ -347,9 +347,13 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
|
||||
Node* receiver = m.Parameter(1);
|
||||
Node* context = m.Parameter(2);
|
||||
|
||||
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
|
||||
Node* locals = m.NewNode(m.common()->StateValues(0));
|
||||
Node* stack = m.NewNode(m.common()->StateValues(0));
|
||||
ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
|
||||
ZoneVector<MachineType> empty_types(zone());
|
||||
|
||||
Node* parameters =
|
||||
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1));
|
||||
Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types));
|
||||
Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types));
|
||||
Node* context_dummy = m.Int32Constant(0);
|
||||
|
||||
Node* state_node = m.NewNode(
|
||||
@ -387,10 +391,17 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
|
||||
Node* receiver = m.Parameter(1);
|
||||
Node* context = m.Int32Constant(1); // Context is ignored.
|
||||
|
||||
ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
|
||||
ZoneVector<MachineType> float64_type(1, kMachFloat64, zone());
|
||||
ZoneVector<MachineType> tagged_type(1, kMachAnyTagged, zone());
|
||||
|
||||
// Build frame state for the state before the call.
|
||||
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
|
||||
Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5));
|
||||
Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant());
|
||||
Node* parameters =
|
||||
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43));
|
||||
Node* locals = m.NewNode(m.common()->TypedStateValues(&float64_type),
|
||||
m.Float64Constant(0.5));
|
||||
Node* stack = m.NewNode(m.common()->TypedStateValues(&tagged_type),
|
||||
m.UndefinedConstant());
|
||||
|
||||
Node* context_sentinel = m.Int32Constant(0);
|
||||
Node* frame_state_before = m.NewNode(
|
||||
@ -473,10 +484,17 @@ TARGET_TEST_F(InstructionSelectorTest,
|
||||
Node* receiver = m.Parameter(1);
|
||||
Node* context = m.Int32Constant(66);
|
||||
|
||||
ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
|
||||
ZoneVector<MachineType> int32x2_type(2, kMachInt32, zone());
|
||||
ZoneVector<MachineType> float64_type(1, kMachFloat64, zone());
|
||||
|
||||
// Build frame state for the state before the call.
|
||||
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
|
||||
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
|
||||
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
|
||||
Node* parameters =
|
||||
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63));
|
||||
Node* locals =
|
||||
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64));
|
||||
Node* stack =
|
||||
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65));
|
||||
Node* frame_state_parent =
|
||||
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
|
||||
OutputFrameStateCombine::Ignore()),
|
||||
@ -484,11 +502,11 @@ TARGET_TEST_F(InstructionSelectorTest,
|
||||
|
||||
Node* context2 = m.Int32Constant(46);
|
||||
Node* parameters2 =
|
||||
m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
|
||||
Node* locals2 =
|
||||
m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.25));
|
||||
Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44),
|
||||
m.Int32Constant(45));
|
||||
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43));
|
||||
Node* locals2 = m.NewNode(m.common()->TypedStateValues(&float64_type),
|
||||
m.Float64Constant(0.25));
|
||||
Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type),
|
||||
m.Int32Constant(44), m.Int32Constant(45));
|
||||
Node* frame_state_before =
|
||||
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
|
||||
OutputFrameStateCombine::Push()),
|
||||
|
@ -115,15 +115,15 @@ class LivenessAnalysisTest : public GraphTest {
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
for (Node* value : locals) {
|
||||
for (StateValuesAccess::TypedNode value : locals) {
|
||||
if (liveness_[i] == 'L') {
|
||||
StringMatchResultListener value_listener;
|
||||
if (value == replacement_) {
|
||||
*listener << "whose local #" << i << " was " << value->opcode()
|
||||
if (value.node == replacement_) {
|
||||
*listener << "whose local #" << i << " was " << value.node->opcode()
|
||||
<< " but should have been 'undefined'";
|
||||
return false;
|
||||
} else if (!IsInt32Constant(first_const + i)
|
||||
.MatchAndExplain(value, &value_listener)) {
|
||||
.MatchAndExplain(value.node, &value_listener)) {
|
||||
*listener << "whose local #" << i << " does not match";
|
||||
if (value_listener.str() != "") {
|
||||
*listener << ", " << value_listener.str();
|
||||
@ -131,8 +131,8 @@ class LivenessAnalysisTest : public GraphTest {
|
||||
return false;
|
||||
}
|
||||
} else if (liveness_[i] == '.') {
|
||||
if (value != replacement_) {
|
||||
*listener << "whose local #" << i << " is " << value
|
||||
if (value.node != replacement_) {
|
||||
*listener << "whose local #" << i << " is " << value.node
|
||||
<< " but should have been " << replacement_
|
||||
<< " (undefined)";
|
||||
return false;
|
||||
|
@ -32,8 +32,8 @@ TEST_F(StateValuesIteratorTest, SimpleIteration) {
|
||||
}
|
||||
Node* state_values = StateValuesFromVector(&inputs);
|
||||
int i = 0;
|
||||
for (Node* node : StateValuesAccess(state_values)) {
|
||||
EXPECT_THAT(node, IsInt32Constant(i));
|
||||
for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
|
||||
EXPECT_THAT(node.node, IsInt32Constant(i));
|
||||
i++;
|
||||
}
|
||||
EXPECT_EQ(count, i);
|
||||
@ -43,7 +43,7 @@ TEST_F(StateValuesIteratorTest, SimpleIteration) {
|
||||
TEST_F(StateValuesIteratorTest, EmptyIteration) {
|
||||
NodeVector inputs(zone());
|
||||
Node* state_values = StateValuesFromVector(&inputs);
|
||||
for (Node* node : StateValuesAccess(state_values)) {
|
||||
for (auto node : StateValuesAccess(state_values)) {
|
||||
USE(node);
|
||||
FAIL();
|
||||
}
|
||||
@ -82,8 +82,8 @@ TEST_F(StateValuesIteratorTest, NestedIteration) {
|
||||
}
|
||||
Node* state_values = StateValuesFromVector(&inputs);
|
||||
int i = 0;
|
||||
for (Node* node : StateValuesAccess(state_values)) {
|
||||
EXPECT_THAT(node, IsInt32Constant(i));
|
||||
for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
|
||||
EXPECT_THAT(node.node, IsInt32Constant(i));
|
||||
i++;
|
||||
}
|
||||
EXPECT_EQ(count, i);
|
||||
@ -110,8 +110,8 @@ TEST_F(StateValuesIteratorTest, TreeFromVector) {
|
||||
|
||||
// Check the tree contents with vector.
|
||||
int i = 0;
|
||||
for (Node* node : StateValuesAccess(values_node)) {
|
||||
EXPECT_THAT(node, IsInt32Constant(i));
|
||||
for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) {
|
||||
EXPECT_THAT(node.node, IsInt32Constant(i));
|
||||
i++;
|
||||
}
|
||||
EXPECT_EQ(inputs.size(), static_cast<size_t>(i));
|
||||
|
Loading…
Reference in New Issue
Block a user