Commit f6b4e6ce authored by Victor Gomes's avatar Victor Gomes Committed by V8 LUCI CQ

[maglev] Preparation to support exception handlers

This does not enable exception handlers yet, we still bail out in
MaglevCompiler::Compile if we have an exception handler table in
the bytecode array.

This CL:
- Generates code for exception handler blocks (which previously were
set as dead code)
- Creates a machinery for nodes to set the property CanThrow
- Reads the exception handler table from the bytecode array and
identifies if we're emitting nodes inside a try-block and for which
handler we should jump in case of an exception
- Generates an exception handler table for Maglev code


Change-Id: Ifc9d4cb7440d3222f4fda48a86e4e482340b3b15
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3854061
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82726}
parent 64ca6cc4
......@@ -2235,8 +2235,7 @@ void OptimizedFrame::Summarize(std::vector<FrameSummary>* frames) const {
}
}
// TODO(leszeks): Move to OptimizedFrame when/if maglev supports exceptions.
int TurbofanFrame::LookupExceptionHandlerInTable(
int OptimizedFrame::LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) {
// We cannot perform exception prediction on optimized code. Instead, we need
// to use FrameSummary to find the corresponding code offset in unoptimized
......
......@@ -826,6 +826,10 @@ class OptimizedFrame : public JavaScriptFrame {
static int StackSlotOffsetRelativeToFp(int slot_index);
// Lookup exception handler for current {pc}, returns -1 if none found.
int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) override;
protected:
inline explicit OptimizedFrame(StackFrameIteratorBase* iterator);
};
......@@ -946,10 +950,6 @@ class TurbofanFrame : public OptimizedFrame {
public:
Type type() const override { return TURBOFAN; }
// Lookup exception handler for current {pc}, returns -1 if none found.
int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) override;
int ComputeParametersCount() const override;
bool HasTaggedOutgoingParams(CodeLookupResult& code_lookup) const;
......
......@@ -2114,11 +2114,12 @@ Object Isolate::UnwindAndFindHandler() {
}
#endif // V8_ENABLE_WEBASSEMBLY
case StackFrame::MAGLEV:
case StackFrame::TURBOFAN: {
// For optimized frames we perform a lookup in the handler table.
if (!catchable_by_js) break;
TurbofanFrame* js_frame = static_cast<TurbofanFrame*>(frame);
int offset = js_frame->LookupExceptionHandlerInTable(nullptr, nullptr);
OptimizedFrame* opt_frame = static_cast<OptimizedFrame*>(frame);
int offset = opt_frame->LookupExceptionHandlerInTable(nullptr, nullptr);
if (offset < 0) break;
// The code might be an optimized code or a turbofanned builtin.
CodeT code = frame->LookupCodeT().ToCodeT();
......
......@@ -100,6 +100,15 @@ class BasicBlock {
}
bool has_state() const { return !is_empty_block() && state_ != nullptr; }
#ifdef DEBUG
void set_is_exception_handler_block(bool value) {
is_exception_handler_block_ = value;
}
bool is_exception_handler_block() const {
return is_exception_handler_block_;
}
#endif // DEBUG
private:
bool is_empty_block_ = false;
Node::List nodes_;
......@@ -110,6 +119,10 @@ class BasicBlock {
};
BasicBlock* empty_block_predecessor_;
Label label_;
#ifdef DEBUG
bool is_exception_handler_block_ = false;
#endif // DEBUG
};
} // namespace maglev
......
......@@ -57,6 +57,14 @@ class MaglevCodeGenState {
}
inline void DefineLazyDeoptPoint(LazyDeoptInfo* info);
void PushHandlerInfo(ExceptionHandlerInfo* handler) {
handlers_.push_back(handler);
}
const std::vector<ExceptionHandlerInfo*>& handlers() const {
return handlers_;
}
inline void DefineExceptionHandlerPoint(ExceptionHandlerInfo* info);
compiler::NativeContextRef native_context() const {
return broker()->target_native_context();
}
......@@ -111,6 +119,8 @@ class MaglevCodeGenState {
std::vector<DeferredCodeInfo*> deferred_code_;
std::vector<EagerDeoptInfo*> eager_deopts_;
std::vector<LazyDeoptInfo*> lazy_deopts_;
std::vector<ExceptionHandlerInfo*> handlers_;
int untagged_slots_ = 0;
int tagged_slots_ = 0;
};
......@@ -156,6 +166,13 @@ inline void MaglevCodeGenState::DefineLazyDeoptPoint(LazyDeoptInfo* info) {
safepoint_table_builder()->DefineSafepoint(masm());
}
inline void MaglevCodeGenState::DefineExceptionHandlerPoint(
ExceptionHandlerInfo* info) {
if (!info->HasExceptionHandler()) return;
info->pc_offset = masm()->pc_offset_for_safepoint();
PushHandlerInfo(info);
}
} // namespace maglev
} // namespace internal
} // namespace v8
......
......@@ -813,13 +813,20 @@ class MaglevCodeGeneratorImpl final {
masm()->Align(Code::kMetadataAlignment);
safepoint_table_builder()->Emit(masm());
// Exception handler table.
handler_table_offset_ = HandlerTable::EmitReturnTableStart(masm());
for (ExceptionHandlerInfo* info : code_gen_state_.handlers()) {
HandlerTable::EmitReturnEntry(
masm(), info->pc_offset,
info->catch_block.block_ptr()->label()->pos());
}
}
MaybeHandle<Code> BuildCodeObject() {
CodeDesc desc;
static constexpr int kNoHandlerTableOffset = 0;
masm()->GetCode(isolate(), &desc, safepoint_table_builder(),
kNoHandlerTableOffset);
handler_table_offset_);
return Factory::CodeBuilder{isolate(), desc, CodeKind::MAGLEV}
.set_stack_slots(stack_slot_count_with_fixed_frame())
.set_deoptimization_data(GenerateDeoptimizationData())
......@@ -932,6 +939,7 @@ class MaglevCodeGeneratorImpl final {
Graph* const graph_;
int deopt_exit_start_offset_ = -1;
int handler_table_offset_ = 0;
};
// static
......
......@@ -50,7 +50,8 @@ MaglevGraphBuilder::MaglevGraphBuilder(LocalIsolate* local_isolate,
// exit when needed.
merge_states_(zone()->NewArray<MergePointInterpreterFrameState*>(
bytecode().length() + 1)),
current_interpreter_frame_(*compilation_unit_) {
current_interpreter_frame_(*compilation_unit_),
catch_block_stack_(zone()) {
memset(merge_states_, 0,
(bytecode().length() + 1) * sizeof(InterpreterFrameState*));
// Default construct basic block refs.
......
......@@ -130,6 +130,17 @@ class MaglevGraphBuilder {
return merge_states_[offset] != nullptr;
}
// Return true if current offset is the beginning of a catch block, that
// is, it is the offset handler in the exception handler table in the
// bytecode array.
bool IsHandlerOffset(int offset) const {
HandlerTable table(*bytecode().object());
for (int i = 0; i < table.NumberOfRangeEntries(); i++) {
if (offset == table.GetRangeHandler(i)) return true;
}
return false;
}
// Called when a block is killed by an unconditional eager deopt.
void EmitUnconditionalDeopt(DeoptimizeReason reason) {
// Create a block rather than calling finish, since we don't yet know the
......@@ -192,6 +203,19 @@ class MaglevGraphBuilder {
ProcessMergePoint(offset);
StartNewBlock(offset);
// If we have no predecessor, then we can be the start of an exception
// handler block.
} else if (predecessors_[offset] == 0 && IsHandlerOffset(offset)) {
// If we have no reference to this block, then the exception handler is
// dead.
if (!jump_targets_[offset].has_ref()) {
MarkBytecodeDead();
return;
}
StartNewBlock(offset);
#ifdef DEBUG
current_block_->set_is_exception_handler_block(true);
#endif // DEBUG
} else if (V8_UNLIKELY(current_block_ == nullptr)) {
// If we don't have a current block, the bytecode must be dead (because of
// some earlier deopt). Mark this bytecode dead too and return.
......@@ -208,6 +232,34 @@ class MaglevGraphBuilder {
MarkBytecodeDead();
return;
}
// Handle exceptions if we have a table.
if (bytecode().handler_table_size() > 0) {
if (catch_block_stack_.size() > 0) {
// Pop all entries where offset >= end.
while (catch_block_stack_.size() > 0) {
HandlerTableEntry& entry = catch_block_stack_.top();
if (offset < entry.end) break;
catch_block_stack_.pop();
}
}
// Push new entries from interpreter handler table where offset >= start
// && offset < end.
HandlerTable table(*bytecode().object());
while (next_handler_table_index_ < table.NumberOfRangeEntries()) {
int start = table.GetRangeStart(next_handler_table_index_);
if (offset < start) break;
int end = table.GetRangeEnd(next_handler_table_index_);
if (offset >= end) {
next_handler_table_index_++;
continue;
}
int handler = table.GetRangeHandler(next_handler_table_index_);
catch_block_stack_.push({end, handler});
next_handler_table_index_++;
}
}
DCHECK_NOT_NULL(current_block_);
if (FLAG_trace_maglev_graph_building) {
std::cout << std::setw(4) << iterator_.current_offset() << " : ";
......@@ -268,7 +320,7 @@ class MaglevGraphBuilder {
}
template <typename NodeT, typename... Args>
NodeT* CreateNewNode(Args&&... args) {
NodeT* CreateNewNodeHelper(Args&&... args) {
if constexpr (NodeT::kProperties.can_eager_deopt()) {
return NodeBase::New<NodeT>(zone(), *compilation_unit_,
GetLatestCheckpointedState(),
......@@ -282,6 +334,22 @@ class MaglevGraphBuilder {
}
}
template <typename NodeT, typename... Args>
NodeT* CreateNewNode(Args&&... args) {
NodeT* node = CreateNewNodeHelper<NodeT>(std::forward<Args>(args)...);
if constexpr (NodeT::kProperties.can_throw()) {
if (catch_block_stack_.size() > 0) {
// Inside a try-block.
new (node->exception_handler_info()) ExceptionHandlerInfo(
&jump_targets_[catch_block_stack_.top().handler]);
} else {
// Patch no exception handler marker.
new (node->exception_handler_info()) ExceptionHandlerInfo();
}
}
return node;
}
template <Builtin kBuiltin>
CallBuiltin* BuildCallBuiltin(std::initializer_list<ValueNode*> inputs) {
using Descriptor = typename CallInterfaceDescriptorFor<kBuiltin>::type;
......@@ -960,6 +1028,13 @@ class MaglevGraphBuilder {
InterpreterFrameState current_interpreter_frame_;
struct HandlerTableEntry {
int end;
int handler;
};
ZoneStack<HandlerTableEntry> catch_block_stack_;
int next_handler_table_index_ = 0;
#ifdef DEBUG
std::unordered_set<Node*> new_nodes_;
#endif
......
......@@ -354,7 +354,13 @@ void MaglevPrintingVisitor::PreProcessBasicBlock(
}
int block_id = graph_labeller->BlockId(block);
os_ << "Block b" << block_id << "\n";
os_ << "Block b" << block_id;
#ifdef DEBUG
if (block->is_exception_handler_block()) {
os_ << " (exception handler)";
}
#endif // DEBUG
os_ << "\n";
MaglevPrintingVisitorOstream::cast(os_for_additional_info_)->set_padding(1);
}
......
......@@ -2951,6 +2951,7 @@ void CallRuntime::GenerateCode(MaglevCodeGenState* code_gen_state,
__ CallRuntime(function_id(), num_args());
// TODO(victorgomes): Not sure if this is needed for all runtime calls.
code_gen_state->DefineLazyDeoptPoint(lazy_deopt_info());
code_gen_state->DefineExceptionHandlerPoint(exception_handler_info());
}
void CallRuntime::PrintParams(std::ostream& os,
MaglevGraphLabeller* graph_labeller) const {
......
This diff is collapsed.
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