Operand(Code::kHeaderSize - kHeapObjectTag));
__ Call(ip);
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
}
__ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
__ Call(ip);
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
ArmOperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
Emit(kArmPush, g.NoOutput(), g.UseRegister(*i));
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
InstructionOperand* first_output =
__ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
__ Call(target);
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchCallJSFunction: {
}
__ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
__ Call(x10);
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchJmp:
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
Arm64OperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
}
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
InstructionOperand* first_output =
masm_(info->isolate(), NULL, 0),
resolver_(this),
safepoints_(code->zone()),
+ handlers_(code->zone()),
deoptimization_states_(code->zone()),
deoptimization_literals_(code->zone()),
translations_(code->zone()),
result->set_stack_slots(frame()->GetSpillSlotCount());
result->set_safepoint_table_offset(safepoints()->GetCodeOffset());
+ // Emit exception handler table.
+ if (!handlers_.empty()) {
+ Handle<FixedArray> table = isolate()->factory()->NewFixedArray(
+ static_cast<int>(handlers_.size()) * 2, TENURED);
+ for (size_t i = 0; i < handlers_.size(); ++i) {
+ int table_index = static_cast<int>(i * 2);
+ table->set(table_index + 0, Smi::FromInt(handlers_[i].pc_offset));
+ table->set(table_index + 1, Smi::FromInt(handlers_[i].handler->pos()));
+ }
+ result->set_handler_table(*table);
+ }
+
PopulateDeoptimizationData(result);
// Ensure there is space for lazy deoptimization in the relocation info.
}
-void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
+void CodeGenerator::RecordCallPosition(Instruction* instr) {
CallDescriptor::Flags flags(MiscField::decode(instr->opcode()));
bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState);
instr->pointer_map(), Safepoint::kSimple, 0,
needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt);
+ if (flags & CallDescriptor::kHasExceptionHandler) {
+ InstructionOperandConverter i(this, instr);
+ BasicBlock::RpoNumber handler_rpo =
+ i.InputRpo(static_cast<int>(instr->InputCount()) - 1);
+ handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()});
+ }
+
if (flags & CallDescriptor::kNeedsNopAfterCall) {
AddNopForSmiCodeInlining();
}
if (needs_frame_state) {
MarkLazyDeoptSite();
- // If the frame state is present, it starts at argument 1
- // (just after the code address).
- InstructionOperandConverter converter(this, instr);
- // Deoptimization info starts at argument 1
+ // If the frame state is present, it starts at argument 1 (just after the
+ // code address).
size_t frame_state_offset = 1;
FrameStateDescriptor* descriptor =
GetFrameStateDescriptor(instr, frame_state_offset);
void AssembleJumpTable(Label** targets, size_t target_count);
// ===========================================================================
- // Deoptimization table construction
- void AddSafepointAndDeopt(Instruction* instr);
+ // ================== Deoptimization table construction. =====================
+ // ===========================================================================
+
+ void RecordCallPosition(Instruction* instr);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
FrameStateDescriptor* GetFrameStateDescriptor(Instruction* instr,
void MarkLazyDeoptSite();
// ===========================================================================
+
struct DeoptimizationState : ZoneObject {
public:
BailoutId bailout_id() const { return bailout_id_; }
int pc_offset_;
};
+ struct HandlerInfo {
+ Label* handler;
+ int pc_offset;
+ };
+
friend class OutOfLineCode;
Frame* const frame_;
MacroAssembler masm_;
GapResolver resolver_;
SafepointTableBuilder safepoints_;
+ ZoneVector<HandlerInfo> handlers_;
ZoneDeque<DeoptimizationState*> deoptimization_states_;
- ZoneDeque<Handle<Object> > deoptimization_literals_;
+ ZoneDeque<Handle<Object>> deoptimization_literals_;
TranslationBuffer translations_;
int last_lazy_deopt_pc_;
JumpTable* jump_tables_;
Register reg = i.InputRegister(0);
__ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchCallJSFunction: {
__ Assert(equal, kWrongFunctionContext);
}
__ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchJmp:
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
IA32OperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
Emit(kIA32Push, g.NoOutput(), value);
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
InstructionOperand* first_output =
case BasicBlock::kCall: {
DCHECK_EQ(IrOpcode::kCall, input->opcode());
BasicBlock* success = block->SuccessorAt(0);
- // TODO(mstarzinger): Record location of {exception} in {handler_table}.
- // BasicBlock* exception = block->SuccessorAt(1);
- return VisitCall(input), VisitGoto(success);
+ BasicBlock* exception = block->SuccessorAt(1);
+ return VisitCall(input, exception), VisitGoto(success);
}
case BasicBlock::kBranch: {
DCHECK_EQ(IrOpcode::kBranch, input->opcode());
return VisitConstant(node);
}
case IrOpcode::kCall:
- return VisitCall(node);
+ return VisitCall(node, nullptr);
case IrOpcode::kFrameState:
case IrOpcode::kStateValues:
return;
void VisitPhi(Node* node);
void VisitProjection(Node* node);
void VisitConstant(Node* node);
- void VisitCall(Node* call);
+ void VisitCall(Node* call, BasicBlock* handler);
void VisitGoto(BasicBlock* target);
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
void VisitSwitch(Node* node, BasicBlock* default_branch,
};
enum Flag {
- // TODO(jarin) kLazyDeoptimization and kNeedsFrameState should be unified.
kNoFlags = 0u,
kNeedsFrameState = 1u << 0,
kPatchableCallSite = 1u << 1,
kNeedsNopAfterCall = 1u << 2,
+ kHasExceptionHandler = 1u << 3,
kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall
};
typedef base::Flags<Flag> Flags;
__ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
__ Call(at);
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchCallJSFunction: {
__ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
__ Call(at);
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchJmp:
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
MipsOperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
slot--;
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
InstructionOperand* first_output =
__ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
__ Call(at);
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchCallJSFunction: {
__ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
__ Call(at);
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchJmp:
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
Mips64OperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
slot--;
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
Instruction* call_instr =
__ Call(Handle<Code>::cast(i.InputHeapObject(0)),
RelocInfo::CODE_TARGET);
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
}
}
__ LoadP(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
__ Call(ip);
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
}
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
PPCOperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
Emit(kPPC_Push, g.NoOutput(), g.UseRegister(*i));
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
InstructionOperand* first_output =
int entry = Code::kHeaderSize - kHeapObjectTag;
__ Call(Operand(reg, entry));
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchCallJSFunction: {
__ Assert(equal, kWrongFunctionContext);
}
__ Call(FieldOperand(func, JSFunction::kCodeEntryOffset));
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
break;
}
case kArchJmp:
}
-void InstructionSelector::VisitCall(Node* node) {
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
X64OperandGenerator g(this);
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
Emit(kX64Push, g.NoOutput(), value);
}
+ // Pass label of exception handler block.
+ CallDescriptor::Flags flags = descriptor->flags();
+ if (handler != nullptr) {
+ flags |= CallDescriptor::kHasExceptionHandler;
+ buffer.instruction_args.push_back(g.Label(handler));
+ }
+
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
UNREACHABLE();
return;
}
- opcode |= MiscField::encode(descriptor->flags());
+ opcode |= MiscField::encode(flags);
// Emit the call instruction.
InstructionOperand* first_output =
#endif
}
+ if (handler_table()->length() > 0 && is_turbofanned()) {
+ os << "Handler Table (size = " << handler_table()->Size() << ")\n";
+ for (int i = 0; i < handler_table()->length(); i += 2) {
+ int pc_offset = Smi::cast(handler_table()->get(i))->value();
+ int handler = Smi::cast(handler_table()->get(i + 1))->value();
+ os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
+ Vector<char> buf = Vector<char>::New(20);
+ SNPrintF(buf, "%4d %4d\n", pc_offset, handler);
+ os << buf.start();
+ }
+ os << "\n";
+ }
+
os << "RelocInfo (size = " << relocation_size() << ")\n";
for (RelocIterator it(this); !it.done(); it.next()) {
it.rinfo()->Print(GetIsolate(), os);