[turbofan] Introduce TypedObjectState common operator.

This adds a new TypedObjectState operator, which is a version of
ObjectState that carries along MachineTypes for the inputs, so we
can tell the deoptimizer how to interpret the inputs, instead of
having to force everything to Tagged.

Drive-by-fix: Remove the unused id parameter from ObjectState.

R=tebbi@chromium.org
BUG=v8:5609

Review-Url: https://codereview.chromium.org/2488623002
Cr-Commit-Position: refs/heads/master@{#40832}
This commit is contained in:
bmeurer 2016-11-08 05:44:55 -08:00 committed by Commit bot
parent e4bae13309
commit a5d251defe
9 changed files with 82 additions and 23 deletions

View File

@ -235,6 +235,12 @@ OsrGuardType OsrGuardTypeOf(Operator const* op) {
return OpParameter<OsrGuardType>(op);
}
ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) {
DCHECK(op->opcode() == IrOpcode::kTypedObjectState ||
op->opcode() == IrOpcode::kTypedStateValues);
return OpParameter<const ZoneVector<MachineType>*>(op);
}
#define CACHED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
@ -1004,23 +1010,31 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) {
arguments, 0, 0, 1, 0, 0); // counts
}
const Operator* CommonOperatorBuilder::ObjectState(int pointer_slots, int id) {
return new (zone()) Operator1<int>( // --
IrOpcode::kObjectState, Operator::kPure, // opcode
"ObjectState", // name
pointer_slots, 0, 0, 1, 0, 0, id); // counts
}
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
static_cast<int>(types->size()), 0, 0, 1, 0, 0, // counts
types); // parameter
}
const Operator* CommonOperatorBuilder::ObjectState(int pointer_slots) {
return new (zone()) Operator1<int>( // --
IrOpcode::kObjectState, Operator::kPure, // opcode
"ObjectState", // name
pointer_slots, 0, 0, 1, 0, 0, // counts
pointer_slots); // parameter
}
const Operator* CommonOperatorBuilder::TypedObjectState(
const ZoneVector<MachineType>* types) {
return new (zone()) Operator1<const ZoneVector<MachineType>*>( // --
IrOpcode::kTypedObjectState, Operator::kPure, // opcode
"TypedObjectState", // name
static_cast<int>(types->size()), 0, 0, 1, 0, 0, // counts
types); // parameter
}
const Operator* CommonOperatorBuilder::FrameState(
BailoutId bailout_id, OutputFrameStateCombine state_combine,

View File

@ -181,6 +181,9 @@ size_t hash_value(OsrGuardType type);
std::ostream& operator<<(std::ostream&, OsrGuardType);
OsrGuardType OsrGuardTypeOf(Operator const*);
ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
WARN_UNUSED_RESULT;
// Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level.
class V8_EXPORT_PRIVATE CommonOperatorBuilder final
@ -240,8 +243,9 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
const Operator* BeginRegion(RegionObservability);
const Operator* FinishRegion();
const Operator* StateValues(int arguments);
const Operator* ObjectState(int pointer_slots, int id);
const Operator* TypedStateValues(const ZoneVector<MachineType>* types);
const Operator* ObjectState(int pointer_slots);
const Operator* TypedObjectState(const ZoneVector<MachineType>* types);
const Operator* FrameState(BailoutId bailout_id,
OutputFrameStateCombine state_combine,
const FrameStateFunctionInfo* function_info);

View File

@ -1578,8 +1578,8 @@ Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) {
}
int input_count = static_cast<int>(cache_->fields().size());
Node* new_object_state =
graph()->NewNode(common()->ObjectState(input_count, vobj->id()),
input_count, &cache_->fields().front());
graph()->NewNode(common()->ObjectState(input_count), input_count,
&cache_->fields().front());
vobj->SetObjectState(new_object_state);
TRACE(
"Creating object state #%d for vobj %p (from node #%d) at effect "

View File

@ -434,6 +434,7 @@ InstructionOperand OperandForDeopt(OperandGenerator* g, Node* input,
case IrOpcode::kHeapConstant:
return g->UseImmediate(input);
case IrOpcode::kObjectState:
case IrOpcode::kTypedObjectState:
UNREACHABLE();
break;
default:
@ -485,6 +486,10 @@ size_t AddOperandToStateValueDescriptor(StateValueDescriptor* descriptor,
FrameStateInputKind kind, Zone* zone) {
switch (input->opcode()) {
case IrOpcode::kObjectState: {
UNREACHABLE();
return 0;
}
case IrOpcode::kTypedObjectState: {
size_t id = deduplicator->GetObjectId(input);
if (id == StateObjectDeduplicator::kNotDuplicated) {
size_t entries = 0;
@ -492,10 +497,12 @@ size_t AddOperandToStateValueDescriptor(StateValueDescriptor* descriptor,
descriptor->fields().push_back(
StateValueDescriptor::Recursive(zone, id));
StateValueDescriptor* new_desc = &descriptor->fields().back();
for (Edge edge : input->input_edges()) {
int const input_count = input->op()->ValueInputCount();
ZoneVector<MachineType> const* types = MachineTypesOf(input->op());
for (int i = 0; i < input_count; ++i) {
entries += AddOperandToStateValueDescriptor(
new_desc, inputs, g, deduplicator, edge.to(),
MachineType::AnyTagged(), kind, zone);
new_desc, inputs, g, deduplicator, input->InputAt(i),
types->at(i), kind, zone);
}
return entries;
} else {
@ -506,7 +513,6 @@ size_t AddOperandToStateValueDescriptor(StateValueDescriptor* descriptor,
StateValueDescriptor::Duplicate(zone, id));
return 0;
}
break;
}
default: {
inputs->push_back(OperandForDeopt(g, input, kind, type.representation()));

View File

@ -57,6 +57,7 @@
V(StateValues) \
V(TypedStateValues) \
V(ObjectState) \
V(TypedObjectState) \
V(Call) \
V(Parameter) \
V(OsrValue) \

View File

@ -1012,6 +1012,36 @@ class RepresentationSelector {
SetOutput(node, MachineRepresentation::kTagged);
}
void VisitObjectState(Node* node) {
if (propagate()) {
for (int i = 0; i < node->InputCount(); i++) {
EnqueueInput(node, i, UseInfo::Any());
}
} else if (lower()) {
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++) {
Node* input = node->InputAt(i);
NodeInfo* input_info = GetInfo(input);
Type* input_type = TypeOf(input);
MachineRepresentation rep = input_type->IsInhabited()
? input_info->representation()
: MachineRepresentation::kNone;
MachineType machine_type(rep, DeoptValueSemanticOf(input_type));
DCHECK(machine_type.representation() !=
MachineRepresentation::kWord32 ||
machine_type.semantic() == MachineSemantic::kInt32 ||
machine_type.semantic() == MachineSemantic::kUint32);
(*types)[i] = machine_type;
}
NodeProperties::ChangeOp(node,
jsgraph_->common()->TypedObjectState(types));
}
SetOutput(node, MachineRepresentation::kTagged);
}
const Operator* Int32Op(Node* node) {
return changer_->Int32OperatorFor(node->opcode());
}
@ -2456,6 +2486,8 @@ class RepresentationSelector {
return;
case IrOpcode::kStateValues:
return VisitStateValues(node);
case IrOpcode::kObjectState:
return VisitObjectState(node);
case IrOpcode::kTypeGuard: {
// We just get rid of the sigma here. In principle, it should be
// possible to refine the truncation and representation based on
@ -2497,7 +2529,6 @@ class RepresentationSelector {
case IrOpcode::kThrow:
case IrOpcode::kBeginRegion:
case IrOpcode::kProjection:
case IrOpcode::kObjectState:
case IrOpcode::kOsrValue:
// All JavaScript operators except JSToNumber have uniform handling.
#define OPCODE_CASE(name) case IrOpcode::k##name:

View File

@ -274,8 +274,7 @@ MachineType StateValuesAccess::iterator::type() {
return MachineType::AnyTagged();
} else {
DCHECK_EQ(IrOpcode::kTypedStateValues, state->opcode());
const ZoneVector<MachineType>* types =
OpParameter<const ZoneVector<MachineType>*>(state);
ZoneVector<MachineType> const* types = MachineTypesOf(state->op());
return (*types)[Top()->index];
}
}

View File

@ -820,12 +820,15 @@ Type* Typer::Visitor::TypeFrameState(Node* node) {
Type* Typer::Visitor::TypeStateValues(Node* node) { return Type::Internal(); }
Type* Typer::Visitor::TypeObjectState(Node* node) { return Type::Internal(); }
Type* Typer::Visitor::TypeTypedStateValues(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeObjectState(Node* node) { return Type::Internal(); }
Type* Typer::Visitor::TypeTypedObjectState(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeCall(Node* node) { return Type::Any(); }

View File

@ -488,8 +488,9 @@ void Verifier::Visitor::Check(Node* node) {
break;
}
case IrOpcode::kStateValues:
case IrOpcode::kObjectState:
case IrOpcode::kTypedStateValues:
case IrOpcode::kObjectState:
case IrOpcode::kTypedObjectState:
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kCall: