// by calls.)
for (size_t i = 0; i < descriptor->GetSize(); i++) {
InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
- CHECK(op->IsStackSlot() || op->IsImmediate());
+ CHECK(op->IsStackSlot() || op->IsDoubleStackSlot() || op->IsImmediate());
}
#endif
safepoints()->RecordLazyDeoptimizationIndex(deopt_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,
size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) {
DCHECK(index < descriptor->GetSize(combine));
descriptor->GetSize(OutputFrameStateCombine::Ignore());
// If the index is past the existing stack items, return the output.
if (index >= size_without_output) {
- return instr->OutputAt(index - size_without_output);
+ return OperandAndType(instr->OutputAt(index - size_without_output),
+ kMachAnyTagged);
}
break;
}
descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
if (index >= index_from_top &&
index < index_from_top + instr->OutputCount()) {
- return instr->OutputAt(index - index_from_top);
+ return OperandAndType(instr->OutputAt(index - index_from_top),
+ kMachAnyTagged);
}
break;
}
- return instr->InputAt(frame_state_offset + index);
+ return OperandAndType(instr->InputAt(frame_state_offset + index),
+ descriptor->GetType(index));
}
frame_state_offset += descriptor->outer_state()->GetTotalSize();
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);
- AddTranslationForOperand(translation, instr, op);
+ AddTranslationForOperand(translation, instr, op.operand_, op.type_);
}
}
void CodeGenerator::AddTranslationForOperand(Translation* translation,
Instruction* instr,
- InstructionOperand* op) {
+ InstructionOperand* op,
+ MachineType type) {
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()) {
+ DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
translation->StoreDoubleStackSlot(op->index());
} else if (op->IsRegister()) {
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()) {
+ DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
InstructionOperandConverter converter(this, instr);
translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
} else if (op->IsImmediate()) {
Handle<Object> constant_object;
switch (constant.type()) {
case Constant::kInt32:
+ DCHECK(type == kMachInt32 || type == kMachUint32);
constant_object =
isolate()->factory()->NewNumberFromInt(constant.ToInt32());
break;
case Constant::kFloat64:
+ DCHECK(type == kMachFloat64 || type == kMachAnyTagged);
constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
break;
case Constant::kHeapObject:
+ DCHECK((type & kRepMask) == kRepTagged);
constant_object = constant.ToHeapObject();
break;
default:
- UNREACHABLE();
+ CHECK(false);
}
int literal_id = DefineDeoptimizationLiteral(constant_object);
translation->StoreLiteral(literal_id);
} else {
- UNREACHABLE();
+ CHECK(false);
}
}
Translation* translation, size_t frame_state_offset,
OutputFrameStateCombine state_combine);
void AddTranslationForOperand(Translation* translation, Instruction* instr,
- InstructionOperand* op);
+ InstructionOperand* op, MachineType type);
void AddNopForSmiCodeInlining();
void EnsureSpaceForLazyDeopt();
void MarkLazyDeoptSite();
}
+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) {
DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes.
SourcePosition source_position = source_positions_->GetSourcePosition(node);
}
+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(
Node* state) {
DCHECK(state->opcode() == IrOpcode::kFrameState);
DCHECK_EQ(5, state->InputCount());
FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
+
int parameters = OpParameter<int>(state->InputAt(0));
int locals = OpParameter<int>(state->InputAt(1));
int stack = OpParameter<int>(state->InputAt(2));
outer_state = GetFrameStateDescriptor(outer_node);
}
- return new (instruction_zone())
- FrameStateDescriptor(state_info, parameters, locals, stack, outer_state);
+ return new (instruction_zone()) FrameStateDescriptor(
+ instruction_zone(), state_info, parameters, locals, stack, outer_state);
}
DCHECK_EQ(static_cast<int>(descriptor->locals_count()), locals->InputCount());
DCHECK_EQ(static_cast<int>(descriptor->stack_count()), stack->InputCount());
+ ZoneVector<MachineType> types(instruction_zone());
+ types.reserve(descriptor->GetSize());
+
OperandGenerator g(this);
+ size_t value_index = 0;
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()) {
inputs->push_back(UseOrImmediate(&g, context));
+ descriptor->SetType(value_index++, kMachAnyTagged);
}
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++) {
- 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());
}
bool call_address_immediate);
FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
+ void FillTypeVectorFromStateValues(ZoneVector<MachineType>* parameters,
+ Node* state_values);
void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs,
FrameStateDescriptor* descriptor);
+ MachineType GetMachineType(Node* node);
// ===========================================================================
// ============= Architecture-specific graph covering methods. ===============
}
+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) {
for (size_t i = 0; i < code.immediates_.size(); ++i) {
Constant constant = code.immediates_[i];
class FrameStateDescriptor : public ZoneObject {
public:
- FrameStateDescriptor(const FrameStateCallInfo& state_info,
+ FrameStateDescriptor(Zone* zone, const FrameStateCallInfo& state_info,
size_t parameters_count, size_t locals_count,
size_t stack_count,
- 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()) {}
+ FrameStateDescriptor* outer_state = NULL);
FrameStateType type() const { return type_; }
BailoutId bailout_id() const { return bailout_id_; }
size_t stack_count() const { return stack_count_; }
FrameStateDescriptor* outer_state() const { return outer_state_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
+ bool HasContext() const { return type_ == JS_FRAME; }
size_t GetSize(OutputFrameStateCombine combine =
- OutputFrameStateCombine::Ignore()) 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;
- }
+ OutputFrameStateCombine::Ignore()) const;
+ size_t GetTotalSize() const;
+ size_t GetFrameCount() const;
+ size_t GetJSFrameCount() const;
- size_t 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 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; }
+ MachineType GetType(size_t index) const;
+ void SetType(size_t index, MachineType type);
private:
FrameStateType type_;
size_t parameters_count_;
size_t locals_count_;
size_t stack_count_;
+ ZoneVector<MachineType> types_;
FrameStateDescriptor* outer_state_;
MaybeHandle<JSFunction> jsfunction_;
};
// Machine types.
kMachNone = 0,
+ kMachBool = kRepBit | kTypeBool,
kMachFloat32 = kRepFloat32 | kTypeNumber,
kMachFloat64 = kRepFloat64 | kTypeNumber,
kMachInt8 = kRepWord8 | kTypeInt32,
// Phis adapt to whatever output representation their uses demand,
// pushing representation changes to their inputs.
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;
if (use_rep & kRepTagged) {
rep = kRepTagged; // Tagged overrides everything.
} else if (use_rep & kRepWord64) {
rep = kRepWord64;
} else if (use_rep & kRepWord32) {
- rep = kRepWord32;
+ if (phi_type & kTypeNumber) {
+ rep = kRepFloat64;
+ } else {
+ rep = kRepWord32;
+ }
} else if (use_rep & kRepBit) {
rep = kRepBit;
} else {
// 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 (use_type & kTypeAny) {
+ if (phi_type & kTypeAny) {
rep = kRepTagged;
- } else if (use_type & kTypeNumber) {
+ } else if (phi_type & kTypeNumber) {
rep = kRepFloat64;
- } else if (use_type & kTypeInt64 || use_type & kTypeUint64) {
+ } else if (phi_type & kTypeInt64 || phi_type & kTypeUint64) {
rep = kRepWord64;
- } else if (use_type & kTypeInt32 || use_type & kTypeUint32) {
+ } else if (phi_type & kTypeInt32 || phi_type & kTypeUint32) {
rep = kRepWord32;
- } else if (use_type & kTypeBool) {
+ } else if (phi_type & kTypeBool) {
rep = kRepBit;
} else {
UNREACHABLE(); // should have at least a usage type!
}
}
// Preserve the usage type, but set the representation.
- Type* upper = NodeProperties::GetBounds(node).upper;
- MachineTypeUnion output_type = rep | changer_->TypeFromUpperBound(upper);
+ MachineTypeUnion output_type = rep | phi_type;
SetOutput(node, output_type);
if (lower()) {
return VisitFloat64Cmp(node);
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);
+ break;
default:
VisitInputs(node);
break;
// 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.Int32Constant(44));
- Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
+ Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5));
+ Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant());
Node* context_sentinel = m.Int32Constant(0);
Node* frame_state_before = m.NewNode(
EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1u, desc_before->stack_count());
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
- EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));
- EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4)));
- EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(5)));
+ EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); // This should be a context.
+ // We inserted 0 here.
+ 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.
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6)));
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.Int32Constant(44));
- Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
+ 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));
Node* frame_state_before =
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
OutputFrameStateCombine::Push()),
size_t num_operands =
1 + // Code object.
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.
1 + // Function.
1; // Context.
int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
FrameStateDescriptor* desc_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(1u, desc_before->parameters_count());
- EXPECT_EQ(1u, desc_before->locals_count());
- EXPECT_EQ(1u, desc_before->stack_count());
+ EXPECT_EQ(1u, desc_before_outer->parameters_count());
+ EXPECT_EQ(1u, desc_before_outer->locals_count());
+ EXPECT_EQ(1u, desc_before_outer->stack_count());
+ // Values from parent environment.
EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
+ EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0));
// Context:
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(kMachInt32, desc_before_outer->GetType(2));
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(kMachInt32, desc_before->GetType(0));
EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
- EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(8)));
- EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(9)));
+ EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));
+ 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.
- 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.
- EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(11)));
+ EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12)));
// Continuation.
EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
return ToConstant(operand).ToFloat32();
}
+ double ToFloat64(const InstructionOperand* operand) const {
+ return ToConstant(operand).ToFloat64();
+ }
+
int32_t ToInt32(const InstructionOperand* operand) const {
return ToConstant(operand).ToInt32();
}
return ToConstant(operand).ToInt64();
}
+ Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const {
+ return ToConstant(operand).ToHeapObject();
+ }
+
int ToVreg(const InstructionOperand* operand) const {
if (operand->IsConstant()) return operand->index();
EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());