Commit bb5b3926 authored by jarin@chromium.org's avatar jarin@chromium.org

Relax representation requirement in FrameStates.

This change enables non-tagged representations in FrameStates.

That allows us to run zlib with deoptimization support and have almost the same performance of the generated code (as the code with no deoptimization). Unfortunately, the frame states seem to confuse typer. As a consequence, we generate more representation changes, which in turn causes the scheduler to take a lot more time and memory (>4x). The added compiler time makes zlib with deopt be about 50% slower.

BUG=
R=titzer@chromium.org

Review URL: https://codereview.chromium.org/614713002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24454 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 73733bb3
...@@ -270,7 +270,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { ...@@ -270,7 +270,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
// by calls.) // by calls.)
for (size_t i = 0; i < descriptor->GetSize(); i++) { for (size_t i = 0; i < descriptor->GetSize(); i++) {
InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
CHECK(op->IsStackSlot() || op->IsImmediate()); CHECK(op->IsStackSlot() || op->IsDoubleStackSlot() || op->IsImmediate());
} }
#endif #endif
safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id); safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
...@@ -296,7 +296,15 @@ FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor( ...@@ -296,7 +296,15 @@ FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
return code()->GetFrameStateDescriptor(state_id); return code()->GetFrameStateDescriptor(state_id);
} }
static InstructionOperand* OperandForFrameState( struct OperandAndType {
OperandAndType(InstructionOperand* operand, MachineType type)
: operand_(operand), type_(type) {}
InstructionOperand* operand_;
MachineType type_;
};
static OperandAndType TypedOperandForFrameState(
FrameStateDescriptor* descriptor, Instruction* instr, FrameStateDescriptor* descriptor, Instruction* instr,
size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) { size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) {
DCHECK(index < descriptor->GetSize(combine)); DCHECK(index < descriptor->GetSize(combine));
...@@ -307,7 +315,8 @@ static InstructionOperand* OperandForFrameState( ...@@ -307,7 +315,8 @@ static InstructionOperand* OperandForFrameState(
descriptor->GetSize(OutputFrameStateCombine::Ignore()); descriptor->GetSize(OutputFrameStateCombine::Ignore());
// If the index is past the existing stack items, return the output. // If the index is past the existing stack items, return the output.
if (index >= size_without_output) { if (index >= size_without_output) {
return instr->OutputAt(index - size_without_output); return OperandAndType(instr->OutputAt(index - size_without_output),
kMachAnyTagged);
} }
break; break;
} }
...@@ -316,11 +325,13 @@ static InstructionOperand* OperandForFrameState( ...@@ -316,11 +325,13 @@ static InstructionOperand* OperandForFrameState(
descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt(); descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
if (index >= index_from_top && if (index >= index_from_top &&
index < index_from_top + instr->OutputCount()) { index < index_from_top + instr->OutputCount()) {
return instr->OutputAt(index - index_from_top); return OperandAndType(instr->OutputAt(index - index_from_top),
kMachAnyTagged);
} }
break; break;
} }
return instr->InputAt(frame_state_offset + index); return OperandAndType(instr->InputAt(frame_state_offset + index),
descriptor->GetType(index));
} }
...@@ -356,9 +367,9 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -356,9 +367,9 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
frame_state_offset += descriptor->outer_state()->GetTotalSize(); frame_state_offset += descriptor->outer_state()->GetTotalSize();
for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) { for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) {
InstructionOperand* op = OperandForFrameState( OperandAndType op = TypedOperandForFrameState(
descriptor, instr, frame_state_offset, i, state_combine); descriptor, instr, frame_state_offset, i, state_combine);
AddTranslationForOperand(translation, instr, op); AddTranslationForOperand(translation, instr, op.operand_, op.type_);
} }
} }
...@@ -387,15 +398,36 @@ int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset, ...@@ -387,15 +398,36 @@ int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
void CodeGenerator::AddTranslationForOperand(Translation* translation, void CodeGenerator::AddTranslationForOperand(Translation* translation,
Instruction* instr, Instruction* instr,
InstructionOperand* op) { InstructionOperand* op,
MachineType type) {
if (op->IsStackSlot()) { if (op->IsStackSlot()) {
translation->StoreStackSlot(op->index()); if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
type == kMachInt16) {
translation->StoreInt32StackSlot(op->index());
} else if (type == kMachUint32) {
translation->StoreUint32StackSlot(op->index());
} else if ((type & kRepMask) == kRepTagged) {
translation->StoreStackSlot(op->index());
} else {
CHECK(false);
}
} else if (op->IsDoubleStackSlot()) { } else if (op->IsDoubleStackSlot()) {
DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
translation->StoreDoubleStackSlot(op->index()); translation->StoreDoubleStackSlot(op->index());
} else if (op->IsRegister()) { } else if (op->IsRegister()) {
InstructionOperandConverter converter(this, instr); InstructionOperandConverter converter(this, instr);
translation->StoreRegister(converter.ToRegister(op)); if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
type == kMachInt16) {
translation->StoreInt32Register(converter.ToRegister(op));
} else if (type == kMachUint32) {
translation->StoreUint32Register(converter.ToRegister(op));
} else if ((type & kRepMask) == kRepTagged) {
translation->StoreRegister(converter.ToRegister(op));
} else {
CHECK(false);
}
} else if (op->IsDoubleRegister()) { } else if (op->IsDoubleRegister()) {
DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
InstructionOperandConverter converter(this, instr); InstructionOperandConverter converter(this, instr);
translation->StoreDoubleRegister(converter.ToDoubleRegister(op)); translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
} else if (op->IsImmediate()) { } else if (op->IsImmediate()) {
...@@ -404,22 +436,25 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation, ...@@ -404,22 +436,25 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
Handle<Object> constant_object; Handle<Object> constant_object;
switch (constant.type()) { switch (constant.type()) {
case Constant::kInt32: case Constant::kInt32:
DCHECK(type == kMachInt32 || type == kMachUint32);
constant_object = constant_object =
isolate()->factory()->NewNumberFromInt(constant.ToInt32()); isolate()->factory()->NewNumberFromInt(constant.ToInt32());
break; break;
case Constant::kFloat64: case Constant::kFloat64:
DCHECK(type == kMachFloat64 || type == kMachAnyTagged);
constant_object = isolate()->factory()->NewNumber(constant.ToFloat64()); constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
break; break;
case Constant::kHeapObject: case Constant::kHeapObject:
DCHECK((type & kRepMask) == kRepTagged);
constant_object = constant.ToHeapObject(); constant_object = constant.ToHeapObject();
break; break;
default: default:
UNREACHABLE(); CHECK(false);
} }
int literal_id = DefineDeoptimizationLiteral(constant_object); int literal_id = DefineDeoptimizationLiteral(constant_object);
translation->StoreLiteral(literal_id); translation->StoreLiteral(literal_id);
} else { } else {
UNREACHABLE(); CHECK(false);
} }
} }
......
...@@ -96,7 +96,7 @@ class CodeGenerator FINAL : public GapResolver::Assembler { ...@@ -96,7 +96,7 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
Translation* translation, size_t frame_state_offset, Translation* translation, size_t frame_state_offset,
OutputFrameStateCombine state_combine); OutputFrameStateCombine state_combine);
void AddTranslationForOperand(Translation* translation, Instruction* instr, void AddTranslationForOperand(Translation* translation, Instruction* instr,
InstructionOperand* op); InstructionOperand* op, MachineType type);
void AddNopForSmiCodeInlining(); void AddNopForSmiCodeInlining();
void EnsureSpaceForLazyDeopt(); void EnsureSpaceForLazyDeopt();
void MarkLazyDeoptSite(); void MarkLazyDeoptSite();
......
...@@ -440,6 +440,126 @@ void InstructionSelector::VisitControl(BasicBlock* block) { ...@@ -440,6 +440,126 @@ 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::kEffectPhi:
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::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::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::kFloat64Sqrt:
return kMachFloat64;
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
return kMachBool;
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) { void InstructionSelector::VisitNode(Node* node) {
DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes. DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes.
SourcePosition source_position = source_positions_->GetSourcePosition(node); SourcePosition source_position = source_positions_->GetSourcePosition(node);
...@@ -1010,11 +1130,23 @@ void InstructionSelector::VisitThrow(Node* value) { ...@@ -1010,11 +1130,23 @@ void InstructionSelector::VisitThrow(Node* value) {
} }
void InstructionSelector::FillTypeVectorFromStateValues(
ZoneVector<MachineType>* types, Node* state_values) {
DCHECK(state_values->opcode() == IrOpcode::kStateValues);
int count = OpParameter<int>(state_values);
types->reserve(static_cast<size_t>(count));
for (int i = 0; i < count; i++) {
types->push_back(GetMachineType(state_values->InputAt(i)));
}
}
FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor( FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
Node* state) { Node* state) {
DCHECK(state->opcode() == IrOpcode::kFrameState); DCHECK(state->opcode() == IrOpcode::kFrameState);
DCHECK_EQ(5, state->InputCount()); DCHECK_EQ(5, state->InputCount());
FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state); FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
int parameters = OpParameter<int>(state->InputAt(0)); int parameters = OpParameter<int>(state->InputAt(0));
int locals = OpParameter<int>(state->InputAt(1)); int locals = OpParameter<int>(state->InputAt(1));
int stack = OpParameter<int>(state->InputAt(2)); int stack = OpParameter<int>(state->InputAt(2));
...@@ -1025,8 +1157,8 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor( ...@@ -1025,8 +1157,8 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
outer_state = GetFrameStateDescriptor(outer_node); outer_state = GetFrameStateDescriptor(outer_node);
} }
return new (instruction_zone()) return new (instruction_zone()) FrameStateDescriptor(
FrameStateDescriptor(state_info, parameters, locals, stack, outer_state); instruction_zone(), state_info, parameters, locals, stack, outer_state);
} }
...@@ -1066,19 +1198,31 @@ void InstructionSelector::AddFrameStateInputs( ...@@ -1066,19 +1198,31 @@ void InstructionSelector::AddFrameStateInputs(
DCHECK_EQ(static_cast<int>(descriptor->locals_count()), locals->InputCount()); DCHECK_EQ(static_cast<int>(descriptor->locals_count()), locals->InputCount());
DCHECK_EQ(static_cast<int>(descriptor->stack_count()), stack->InputCount()); DCHECK_EQ(static_cast<int>(descriptor->stack_count()), stack->InputCount());
ZoneVector<MachineType> types(instruction_zone());
types.reserve(descriptor->GetSize());
OperandGenerator g(this); OperandGenerator g(this);
size_t value_index = 0;
for (int i = 0; i < static_cast<int>(descriptor->parameters_count()); i++) { for (int i = 0; i < static_cast<int>(descriptor->parameters_count()); i++) {
inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i))); Node* input_node = parameters->InputAt(i);
inputs->push_back(UseOrImmediate(&g, input_node));
descriptor->SetType(value_index++, GetMachineType(input_node));
} }
if (descriptor->HasContext()) { if (descriptor->HasContext()) {
inputs->push_back(UseOrImmediate(&g, context)); inputs->push_back(UseOrImmediate(&g, context));
descriptor->SetType(value_index++, kMachAnyTagged);
} }
for (int i = 0; i < static_cast<int>(descriptor->locals_count()); i++) { for (int i = 0; i < static_cast<int>(descriptor->locals_count()); i++) {
inputs->push_back(UseOrImmediate(&g, locals->InputAt(i))); Node* input_node = locals->InputAt(i);
inputs->push_back(UseOrImmediate(&g, input_node));
descriptor->SetType(value_index++, GetMachineType(input_node));
} }
for (int i = 0; i < static_cast<int>(descriptor->stack_count()); i++) { for (int i = 0; i < static_cast<int>(descriptor->stack_count()); i++) {
inputs->push_back(UseOrImmediate(&g, stack->InputAt(i))); Node* input_node = stack->InputAt(i);
inputs->push_back(UseOrImmediate(&g, input_node));
descriptor->SetType(value_index++, GetMachineType(input_node));
} }
DCHECK(value_index == descriptor->GetSize());
} }
......
...@@ -145,8 +145,11 @@ class InstructionSelector FINAL { ...@@ -145,8 +145,11 @@ class InstructionSelector FINAL {
bool call_address_immediate); bool call_address_immediate);
FrameStateDescriptor* GetFrameStateDescriptor(Node* node); FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
void FillTypeVectorFromStateValues(ZoneVector<MachineType>* parameters,
Node* state_values);
void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs, void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs,
FrameStateDescriptor* descriptor); FrameStateDescriptor* descriptor);
MachineType GetMachineType(Node* node);
// =========================================================================== // ===========================================================================
// ============= Architecture-specific graph covering methods. =============== // ============= Architecture-specific graph covering methods. ===============
......
...@@ -445,6 +445,78 @@ int InstructionSequence::GetFrameStateDescriptorCount() { ...@@ -445,6 +445,78 @@ int InstructionSequence::GetFrameStateDescriptorCount() {
} }
FrameStateDescriptor::FrameStateDescriptor(
Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
: type_(state_info.type()),
bailout_id_(state_info.bailout_id()),
frame_state_combine_(state_info.state_combine()),
parameters_count_(parameters_count),
locals_count_(locals_count),
stack_count_(stack_count),
types_(zone),
outer_state_(outer_state),
jsfunction_(state_info.jsfunction()) {
types_.resize(GetSize(), kMachNone);
}
size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
size_t size = parameters_count() + locals_count() + stack_count() +
(HasContext() ? 1 : 0);
switch (combine.kind()) {
case OutputFrameStateCombine::kPushOutput:
size += combine.GetPushCount();
break;
case OutputFrameStateCombine::kPokeAt:
break;
}
return size;
}
size_t FrameStateDescriptor::GetTotalSize() const {
size_t total_size = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
total_size += iter->GetSize();
}
return total_size;
}
size_t FrameStateDescriptor::GetFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
++count;
}
return count;
}
size_t FrameStateDescriptor::GetJSFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
if (iter->type_ == JS_FRAME) {
++count;
}
}
return count;
}
MachineType FrameStateDescriptor::GetType(size_t index) const {
return types_[index];
}
void FrameStateDescriptor::SetType(size_t index, MachineType type) {
DCHECK(index < GetSize());
types_[index] = type;
}
std::ostream& operator<<(std::ostream& os, const InstructionSequence& code) { std::ostream& operator<<(std::ostream& os, const InstructionSequence& code) {
for (size_t i = 0; i < code.immediates_.size(); ++i) { for (size_t i = 0; i < code.immediates_.size(); ++i) {
Constant constant = code.immediates_[i]; Constant constant = code.immediates_[i];
......
...@@ -711,18 +711,10 @@ class Constant FINAL { ...@@ -711,18 +711,10 @@ class Constant FINAL {
class FrameStateDescriptor : public ZoneObject { class FrameStateDescriptor : public ZoneObject {
public: public:
FrameStateDescriptor(const FrameStateCallInfo& state_info, FrameStateDescriptor(Zone* zone, const FrameStateCallInfo& state_info,
size_t parameters_count, size_t locals_count, size_t parameters_count, size_t locals_count,
size_t stack_count, size_t stack_count,
FrameStateDescriptor* outer_state = NULL) FrameStateDescriptor* outer_state = NULL);
: type_(state_info.type()),
bailout_id_(state_info.bailout_id()),
frame_state_combine_(state_info.state_combine()),
parameters_count_(parameters_count),
locals_count_(locals_count),
stack_count_(stack_count),
outer_state_(outer_state),
jsfunction_(state_info.jsfunction()) {}
FrameStateType type() const { return type_; } FrameStateType type() const { return type_; }
BailoutId bailout_id() const { return bailout_id_; } BailoutId bailout_id() const { return bailout_id_; }
...@@ -732,51 +724,16 @@ class FrameStateDescriptor : public ZoneObject { ...@@ -732,51 +724,16 @@ class FrameStateDescriptor : public ZoneObject {
size_t stack_count() const { return stack_count_; } size_t stack_count() const { return stack_count_; }
FrameStateDescriptor* outer_state() const { return outer_state_; } FrameStateDescriptor* outer_state() const { return outer_state_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; } MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
bool HasContext() const { return type_ == JS_FRAME; }
size_t GetSize(OutputFrameStateCombine combine = size_t GetSize(OutputFrameStateCombine combine =
OutputFrameStateCombine::Ignore()) const { OutputFrameStateCombine::Ignore()) const;
size_t size = parameters_count_ + locals_count_ + stack_count_ + size_t GetTotalSize() const;
(HasContext() ? 1 : 0); size_t GetFrameCount() const;
switch (combine.kind()) { size_t GetJSFrameCount() const;
case OutputFrameStateCombine::kPushOutput:
size += combine.GetPushCount();
break;
case OutputFrameStateCombine::kPokeAt:
break;
}
return size;
}
size_t GetTotalSize() const { MachineType GetType(size_t index) const;
size_t total_size = 0; void SetType(size_t index, MachineType type);
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
total_size += iter->GetSize();
}
return total_size;
}
size_t GetFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
++count;
}
return count;
}
size_t GetJSFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
if (iter->type_ == JS_FRAME) {
++count;
}
}
return count;
}
bool HasContext() const { return type_ == JS_FRAME; }
private: private:
FrameStateType type_; FrameStateType type_;
...@@ -785,6 +742,7 @@ class FrameStateDescriptor : public ZoneObject { ...@@ -785,6 +742,7 @@ class FrameStateDescriptor : public ZoneObject {
size_t parameters_count_; size_t parameters_count_;
size_t locals_count_; size_t locals_count_;
size_t stack_count_; size_t stack_count_;
ZoneVector<MachineType> types_;
FrameStateDescriptor* outer_state_; FrameStateDescriptor* outer_state_;
MaybeHandle<JSFunction> jsfunction_; MaybeHandle<JSFunction> jsfunction_;
}; };
......
...@@ -39,6 +39,7 @@ enum MachineType { ...@@ -39,6 +39,7 @@ enum MachineType {
// Machine types. // Machine types.
kMachNone = 0, kMachNone = 0,
kMachBool = kRepBit | kTypeBool,
kMachFloat32 = kRepFloat32 | kTypeNumber, kMachFloat32 = kRepFloat32 | kTypeNumber,
kMachFloat64 = kRepFloat64 | kTypeNumber, kMachFloat64 = kRepFloat64 | kTypeNumber,
kMachInt8 = kRepWord8 | kTypeInt32, kMachInt8 = kRepWord8 | kTypeInt32,
......
...@@ -284,7 +284,8 @@ class RepresentationSelector { ...@@ -284,7 +284,8 @@ class RepresentationSelector {
// Phis adapt to whatever output representation their uses demand, // Phis adapt to whatever output representation their uses demand,
// pushing representation changes to their inputs. // pushing representation changes to their inputs.
MachineTypeUnion use_rep = GetUseInfo(node) & kRepMask; MachineTypeUnion use_rep = GetUseInfo(node) & kRepMask;
MachineTypeUnion use_type = GetUseInfo(node) & kTypeMask; Type* upper = NodeProperties::GetBounds(node).upper;
MachineTypeUnion phi_type = changer_->TypeFromUpperBound(upper);
MachineTypeUnion rep = 0; MachineTypeUnion rep = 0;
if (use_rep & kRepTagged) { if (use_rep & kRepTagged) {
rep = kRepTagged; // Tagged overrides everything. rep = kRepTagged; // Tagged overrides everything.
...@@ -295,29 +296,31 @@ class RepresentationSelector { ...@@ -295,29 +296,31 @@ class RepresentationSelector {
} else if (use_rep & kRepWord64) { } else if (use_rep & kRepWord64) {
rep = kRepWord64; rep = kRepWord64;
} else if (use_rep & kRepWord32) { } else if (use_rep & kRepWord32) {
rep = kRepWord32; if (phi_type & kTypeNumber) {
rep = kRepFloat64;
} else {
rep = kRepWord32;
}
} else if (use_rep & kRepBit) { } else if (use_rep & kRepBit) {
rep = kRepBit; rep = kRepBit;
} else { } else {
// There was no representation associated with any of the uses. // There was no representation associated with any of the uses.
// TODO(titzer): Select the best rep using phi's type, not the usage type? if (phi_type & kTypeAny) {
if (use_type & kTypeAny) {
rep = kRepTagged; rep = kRepTagged;
} else if (use_type & kTypeNumber) { } else if (phi_type & kTypeNumber) {
rep = kRepFloat64; rep = kRepFloat64;
} else if (use_type & kTypeInt64 || use_type & kTypeUint64) { } else if (phi_type & kTypeInt64 || phi_type & kTypeUint64) {
rep = kRepWord64; rep = kRepWord64;
} else if (use_type & kTypeInt32 || use_type & kTypeUint32) { } else if (phi_type & kTypeInt32 || phi_type & kTypeUint32) {
rep = kRepWord32; rep = kRepWord32;
} else if (use_type & kTypeBool) { } else if (phi_type & kTypeBool) {
rep = kRepBit; rep = kRepBit;
} else { } else {
UNREACHABLE(); // should have at least a usage type! UNREACHABLE(); // should have at least a usage type!
} }
} }
// Preserve the usage type, but set the representation. // Preserve the usage type, but set the representation.
Type* upper = NodeProperties::GetBounds(node).upper; MachineTypeUnion output_type = rep | phi_type;
MachineTypeUnion output_type = rep | changer_->TypeFromUpperBound(upper);
SetOutput(node, output_type); SetOutput(node, output_type);
if (lower()) { if (lower()) {
...@@ -728,6 +731,12 @@ class RepresentationSelector { ...@@ -728,6 +731,12 @@ class RepresentationSelector {
return VisitFloat64Cmp(node); return VisitFloat64Cmp(node);
case IrOpcode::kLoadStackPointer: case IrOpcode::kLoadStackPointer:
return VisitLeaf(node, kMachPtr); return VisitLeaf(node, kMachPtr);
case IrOpcode::kStateValues:
for (int i = 0; i < node->InputCount(); i++) {
ProcessInput(node, i, kTypeAny);
}
SetOutput(node, kMachAnyTagged);
break;
default: default:
VisitInputs(node); VisitInputs(node);
break; break;
......
...@@ -375,8 +375,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { ...@@ -375,8 +375,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
// Build frame state for the state before the call. // Build frame state for the state before the call.
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5));
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant());
Node* context_sentinel = m.Int32Constant(0); Node* context_sentinel = m.Int32Constant(0);
Node* frame_state_before = m.NewNode( Node* frame_state_before = m.NewNode(
...@@ -425,9 +425,15 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { ...@@ -425,9 +425,15 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1u, desc_before->stack_count()); EXPECT_EQ(1u, desc_before->stack_count());
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); // This should be a context.
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4))); // We inserted 0 here.
EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(5))); EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4)));
EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined());
EXPECT_EQ(kMachInt32, desc_before->GetType(0));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); // context is always
// tagged/any.
EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3));
// Function. // Function.
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6))); EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6)));
...@@ -465,8 +471,10 @@ TARGET_TEST_F(InstructionSelectorTest, ...@@ -465,8 +471,10 @@ TARGET_TEST_F(InstructionSelectorTest,
Node* context2 = m.Int32Constant(46); Node* context2 = m.Int32Constant(46);
Node* parameters2 = Node* parameters2 =
m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); Node* locals2 =
Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.25));
Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44),
m.Int32Constant(45));
Node* frame_state_before = Node* frame_state_before =
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
OutputFrameStateCombine::Push()), OutputFrameStateCombine::Push()),
...@@ -494,7 +502,7 @@ TARGET_TEST_F(InstructionSelectorTest, ...@@ -494,7 +502,7 @@ TARGET_TEST_F(InstructionSelectorTest,
size_t num_operands = size_t num_operands =
1 + // Code object. 1 + // Code object.
1 + // Frame state deopt id 1 + // Frame state deopt id
4 + // One input for each value in frame state + context. 5 + // One input for each value in frame state + context.
4 + // One input for each value in the parent frame state + context. 4 + // One input for each value in the parent frame state + context.
1 + // Function. 1 + // Function.
1; // Context. 1; // Context.
...@@ -506,25 +514,40 @@ TARGET_TEST_F(InstructionSelectorTest, ...@@ -506,25 +514,40 @@ TARGET_TEST_F(InstructionSelectorTest,
int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
FrameStateDescriptor* desc_before = FrameStateDescriptor* desc_before =
s.GetFrameStateDescriptor(deopt_id_before); s.GetFrameStateDescriptor(deopt_id_before);
FrameStateDescriptor* desc_before_outer = desc_before->outer_state();
EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
EXPECT_EQ(1u, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before_outer->parameters_count());
EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(1u, desc_before_outer->locals_count());
EXPECT_EQ(1u, desc_before->stack_count()); EXPECT_EQ(1u, desc_before_outer->stack_count());
// Values from parent environment.
EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2))); EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0));
// Context: // Context:
EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3))); EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1));
EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4))); EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2));
EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5))); EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
// Values from parent environment should follow. EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3));
// Values from the nested frame.
EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(2u, desc_before->stack_count());
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6))); EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
EXPECT_EQ(kMachInt32, desc_before->GetType(0));
EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7))); EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(8))); EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));
EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(9))); EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8)));
EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9)));
EXPECT_EQ(kMachInt32, desc_before->GetType(3));
EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10)));
EXPECT_EQ(kMachInt32, desc_before->GetType(4));
// Function. // Function.
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(10))); EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11)));
// Context. // Context.
EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(11))); EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12)));
// Continuation. // Continuation.
EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
......
...@@ -146,6 +146,10 @@ class InstructionSelectorTest : public TestWithContext, public TestWithZone { ...@@ -146,6 +146,10 @@ class InstructionSelectorTest : public TestWithContext, public TestWithZone {
return ToConstant(operand).ToFloat32(); return ToConstant(operand).ToFloat32();
} }
double ToFloat64(const InstructionOperand* operand) const {
return ToConstant(operand).ToFloat64();
}
int32_t ToInt32(const InstructionOperand* operand) const { int32_t ToInt32(const InstructionOperand* operand) const {
return ToConstant(operand).ToInt32(); return ToConstant(operand).ToInt32();
} }
...@@ -154,6 +158,10 @@ class InstructionSelectorTest : public TestWithContext, public TestWithZone { ...@@ -154,6 +158,10 @@ class InstructionSelectorTest : public TestWithContext, public TestWithZone {
return ToConstant(operand).ToInt64(); return ToConstant(operand).ToInt64();
} }
Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const {
return ToConstant(operand).ToHeapObject();
}
int ToVreg(const InstructionOperand* operand) const { int ToVreg(const InstructionOperand* operand) const {
if (operand->IsConstant()) return operand->index(); if (operand->IsConstant()) return operand->index();
EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind()); EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment