[cleanup] Refactor Turbofan::Iterate and TypedFrame::Iterate
Change-Id: I317c42a6efd977ec990e28941fd7a9e638227be0 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3789517 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Victor Gomes <victorgomes@chromium.org> Cr-Commit-Position: refs/heads/main@{#82028}
This commit is contained in:
parent
ef1e65d9ae
commit
01f02a805c
@ -199,7 +199,7 @@ class SafepointTableBuilder : public SafepointTableBuilderBase {
|
|||||||
// Note it is only valid to specify stack slots here that are *not* in
|
// Note it is only valid to specify stack slots here that are *not* in
|
||||||
// the fixed part of the frame (e.g. argc, target, context, stored rbp,
|
// the fixed part of the frame (e.g. argc, target, context, stored rbp,
|
||||||
// return address). Frame iteration handles the fixed part of the frame
|
// return address). Frame iteration handles the fixed part of the frame
|
||||||
// with custom code, see CommonFrame::IterateCompiledFrame.
|
// with custom code, see Turbofan::Iterate.
|
||||||
entry_->stack_indexes->Add(index, table_->zone_);
|
entry_->stack_indexes->Add(index, table_->zone_);
|
||||||
table_->UpdateMinMaxStackIndex(index);
|
table_->UpdateMinMaxStackIndex(index);
|
||||||
}
|
}
|
||||||
|
@ -1131,6 +1131,20 @@ void VisitSpillSlot(Isolate* isolate, RootVisitor* v,
|
|||||||
v->VisitRootPointer(Root::kStackRoots, nullptr, spill_slot);
|
v->VisitRootPointer(Root::kStackRoots, nullptr, spill_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SafepointEntry GetSafepointEntryFromCodeCache(
|
||||||
|
Isolate* isolate, Address inner_pointer,
|
||||||
|
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry) {
|
||||||
|
if (!entry->safepoint_entry.is_initialized()) {
|
||||||
|
entry->safepoint_entry =
|
||||||
|
entry->code.GetSafepointEntry(isolate, inner_pointer);
|
||||||
|
DCHECK(entry->safepoint_entry.is_initialized());
|
||||||
|
} else {
|
||||||
|
DCHECK_EQ(entry->safepoint_entry,
|
||||||
|
entry->code.GetSafepointEntry(isolate, inner_pointer));
|
||||||
|
}
|
||||||
|
return entry->safepoint_entry;
|
||||||
|
}
|
||||||
|
|
||||||
MaglevSafepointEntry GetMaglevSafepointEntryFromCodeCache(
|
MaglevSafepointEntry GetMaglevSafepointEntryFromCodeCache(
|
||||||
Isolate* isolate, Address inner_pointer,
|
Isolate* isolate, Address inner_pointer,
|
||||||
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry) {
|
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry) {
|
||||||
@ -1147,11 +1161,33 @@ MaglevSafepointEntry GetMaglevSafepointEntryFromCodeCache(
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
|
void TypedFrame::Iterate(RootVisitor* v) const {
|
||||||
// Make sure that we're not doing "safe" stack frame iteration. We cannot
|
// Make sure that we're not doing "safe" stack frame iteration. We cannot
|
||||||
// possibly find pointers in optimized frames in that state.
|
// possibly find pointers in optimized frames in that state.
|
||||||
DCHECK(can_access_heap_objects());
|
DCHECK(can_access_heap_objects());
|
||||||
|
|
||||||
|
// === TypedFrame ===
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
// | out_param n | <-- parameters_base / sp
|
||||||
|
// | ... |
|
||||||
|
// | out_param 0 |
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
// | spill_slot n | <-- parameters_limit ^
|
||||||
|
// | ... | spill_slot_count
|
||||||
|
// | spill_slot 0 | v
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
// | Type Marker | <-- frame_header_base ^
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | [Constant Pool] | |
|
||||||
|
// |- - - - - - - - -| kFixedSlotCount
|
||||||
|
// | saved frame ptr | <-- fp |
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | return addr | v
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
|
||||||
|
// TODO(victorgomes): Simplify this function and separate into JS
|
||||||
|
// and Wasm versions.
|
||||||
|
|
||||||
// Find the code and compute the safepoint information.
|
// Find the code and compute the safepoint information.
|
||||||
Address inner_pointer = pc();
|
Address inner_pointer = pc();
|
||||||
SafepointEntry safepoint_entry;
|
SafepointEntry safepoint_entry;
|
||||||
@ -1202,6 +1238,8 @@ void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
|
|||||||
has_tagged_outgoing_params = entry->code.has_tagged_outgoing_params();
|
has_tagged_outgoing_params = entry->code.has_tagged_outgoing_params();
|
||||||
|
|
||||||
#if V8_ENABLE_WEBASSEMBLY
|
#if V8_ENABLE_WEBASSEMBLY
|
||||||
|
// TODO(victorgomes): Remove this for TypedFrame, since it can only
|
||||||
|
// happens with TF frames.
|
||||||
// With inlined JS-to-Wasm calls, we can be in an OptimizedFrame and
|
// With inlined JS-to-Wasm calls, we can be in an OptimizedFrame and
|
||||||
// directly call a Wasm function from JavaScript. In this case the
|
// directly call a Wasm function from JavaScript. In this case the
|
||||||
// parameters we pass to the callee are not tagged.
|
// parameters we pass to the callee are not tagged.
|
||||||
@ -1344,31 +1382,39 @@ void MaglevFrame::Iterate(RootVisitor* v) const {
|
|||||||
DCHECK(can_access_heap_objects());
|
DCHECK(can_access_heap_objects());
|
||||||
|
|
||||||
// === MaglevFrame ===
|
// === MaglevFrame ===
|
||||||
// +-----------------+
|
// +-----------------+-----------------------------------------
|
||||||
// | parameter n | <-- parameters_base / sp
|
// | out_param n | <-- parameters_base / sp
|
||||||
// | ... |
|
// | ... |
|
||||||
// | parameter 0 |
|
// | out_param 0 |
|
||||||
// +-----------------+-----------------------------^
|
// +-----------------+-----------------------------------------
|
||||||
// | pushed_reg n | <-- parameters_limit |
|
// | pushed_double n | <-- parameters_limit ^
|
||||||
// | ... | num_pushed_registers
|
// | ... | |
|
||||||
// | pushed_reg 0 | <-- pushed_register_base |
|
// | pushed_double 0 | |
|
||||||
// +-----------------+----------^------------------v
|
// +- - - - - - - - -+ num_pushed_registers
|
||||||
// | stack_slot n | |
|
// | pushed_reg n | |
|
||||||
// | ... | spill_slot_count
|
// | ... | |
|
||||||
// | stack_slot 0 | |
|
// | pushed_reg 0 | <-- pushed_register_base v
|
||||||
// +-----------------+----------v---------------^
|
// +-----------------+-----------------------------------------
|
||||||
// | argc | <-- frame_header_base |
|
// | untagged_slot n | ^
|
||||||
// |- - - - - - - - -| |
|
// | ... | |
|
||||||
// | JSFunction | |
|
// | untagged_slot 0 | |
|
||||||
// |- - - - - - - - -| frame_header_size
|
// +- - - - - - - - -+ spill_slot_count
|
||||||
// | Context | |
|
// | tagged_slot n | |
|
||||||
// |- - - - - - - - -| |
|
// | ... | |
|
||||||
// | [Constant Pool] | |
|
// | tagged_slot 0 | v
|
||||||
// |- - - - - - - - -|----------^---------------v
|
// +-----------------+-----------------------------------------
|
||||||
// | saved frame ptr | <-- fp |
|
// | argc | <-- frame_header_base ^
|
||||||
// |- - - - - - - - -| kFixedFrameSizeAboveFp
|
// |- - - - - - - - -| |
|
||||||
// | return addr | |
|
// | JSFunction | |
|
||||||
// +-----------------+----------v
|
// |- - - - - - - - -| |
|
||||||
|
// | Context | |
|
||||||
|
// |- - - - - - - - -| kFixedSlotCount
|
||||||
|
// | [Constant Pool] | |
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | saved frame ptr | <-- fp |
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | return addr | v
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
|
||||||
// Find the code and compute the safepoint information.
|
// Find the code and compute the safepoint information.
|
||||||
Address inner_pointer = pc();
|
Address inner_pointer = pc();
|
||||||
@ -1441,6 +1487,107 @@ void MaglevFrame::Iterate(RootVisitor* v) const {
|
|||||||
IteratePc(v, pc_address(), constant_pool_address(), entry->code);
|
IteratePc(v, pc_address(), constant_pool_address(), entry->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TurbofanFrame::HasTaggedOutgoingParams(
|
||||||
|
CodeLookupResult& code_lookup) const {
|
||||||
|
#if V8_ENABLE_WEBASSEMBLY
|
||||||
|
// With inlined JS-to-Wasm calls, we can be in an OptimizedFrame and
|
||||||
|
// directly call a Wasm function from JavaScript. In this case the
|
||||||
|
// parameters we pass to the callee are not tagged.
|
||||||
|
wasm::WasmCode* wasm_callee =
|
||||||
|
wasm::GetWasmCodeManager()->LookupCode(callee_pc());
|
||||||
|
return (wasm_callee == nullptr) && code_lookup.has_tagged_outgoing_params();
|
||||||
|
#else
|
||||||
|
return code_lookup.has_tagged_outgoing_params();
|
||||||
|
#endif // V8_ENABLE_WEBASSEMBLY
|
||||||
|
}
|
||||||
|
|
||||||
|
void TurbofanFrame::Iterate(RootVisitor* v) const {
|
||||||
|
// Make sure that we're not doing "safe" stack frame iteration. We cannot
|
||||||
|
// possibly find pointers in optimized frames in that state.
|
||||||
|
DCHECK(can_access_heap_objects());
|
||||||
|
|
||||||
|
// === TurbofanFrame ===
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
// | out_param n | <-- parameters_base / sp
|
||||||
|
// | ... |
|
||||||
|
// | out_param 0 |
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
// | spill_slot n | <-- parameters_limit ^
|
||||||
|
// | ... | spill_slot_count
|
||||||
|
// | spill_slot 0 | v
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
// | argc | <-- frame_header_base ^
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | JSFunction | |
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | Context | |
|
||||||
|
// |- - - - - - - - -| kFixedSlotCount
|
||||||
|
// | [Constant Pool] | |
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | saved frame ptr | <-- fp |
|
||||||
|
// |- - - - - - - - -| |
|
||||||
|
// | return addr | v
|
||||||
|
// +-----------------+-----------------------------------------
|
||||||
|
|
||||||
|
// Find the code and compute the safepoint information.
|
||||||
|
Address inner_pointer = pc();
|
||||||
|
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
|
||||||
|
isolate()->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
|
||||||
|
CHECK(entry->code.IsFound());
|
||||||
|
DCHECK(entry->code.is_turbofanned());
|
||||||
|
SafepointEntry safepoint_entry =
|
||||||
|
GetSafepointEntryFromCodeCache(isolate(), inner_pointer, entry);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Assert that it is a JS frame and it has a context.
|
||||||
|
intptr_t marker =
|
||||||
|
Memory<intptr_t>(fp() + CommonFrameConstants::kContextOrFrameTypeOffset);
|
||||||
|
DCHECK(!StackFrame::IsTypeMarker(marker));
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
// Determine the fixed header and spill slot area size.
|
||||||
|
int frame_header_size = StandardFrameConstants::kFixedFrameSizeFromFp;
|
||||||
|
int spill_slot_count =
|
||||||
|
entry->code.stack_slots() - StandardFrameConstants::kFixedSlotCount;
|
||||||
|
|
||||||
|
// Fixed frame slots.
|
||||||
|
FullObjectSlot frame_header_base(&Memory<Address>(fp() - frame_header_size));
|
||||||
|
FullObjectSlot frame_header_limit(
|
||||||
|
&Memory<Address>(fp() - StandardFrameConstants::kCPSlotSize));
|
||||||
|
// Parameters passed to the callee.
|
||||||
|
FullObjectSlot parameters_base(&Memory<Address>(sp()));
|
||||||
|
FullObjectSlot parameters_limit = frame_header_base - spill_slot_count;
|
||||||
|
|
||||||
|
// Visit the outgoing parameters if they are tagged.
|
||||||
|
if (HasTaggedOutgoingParams(entry->code)) {
|
||||||
|
v->VisitRootPointers(Root::kStackRoots, nullptr, parameters_base,
|
||||||
|
parameters_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spill slots are in the region ]frame_header_base, parameters_limit];
|
||||||
|
// Visit pointer spill slots and locals.
|
||||||
|
DCHECK_GE((entry->code.stack_slots() + kBitsPerByte) / kBitsPerByte,
|
||||||
|
safepoint_entry.tagged_slots().size());
|
||||||
|
int slot_offset = 0;
|
||||||
|
for (uint8_t bits : safepoint_entry.tagged_slots()) {
|
||||||
|
while (bits) {
|
||||||
|
const int bit = base::bits::CountTrailingZeros(bits);
|
||||||
|
bits &= ~(1 << bit);
|
||||||
|
FullObjectSlot spill_slot = parameters_limit + slot_offset + bit;
|
||||||
|
VisitSpillSlot(isolate(), v, spill_slot);
|
||||||
|
}
|
||||||
|
slot_offset += kBitsPerByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit fixed header region (the context and JSFunction), skipping the
|
||||||
|
// argument count since it is stored untagged.
|
||||||
|
v->VisitRootPointers(Root::kStackRoots, nullptr, frame_header_base + 1,
|
||||||
|
frame_header_limit);
|
||||||
|
|
||||||
|
// Visit the return address in the callee and incoming arguments.
|
||||||
|
IteratePc(v, pc_address(), constant_pool_address(), entry->code);
|
||||||
|
}
|
||||||
|
|
||||||
Code StubFrame::unchecked_code() const {
|
Code StubFrame::unchecked_code() const {
|
||||||
return isolate()->FindCodeObject(pc()).code();
|
return isolate()->FindCodeObject(pc()).code();
|
||||||
}
|
}
|
||||||
@ -1454,8 +1601,6 @@ int StubFrame::LookupExceptionHandlerInTable() {
|
|||||||
return table.LookupReturn(pc_offset);
|
return table.LookupReturn(pc_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptimizedFrame::Iterate(RootVisitor* v) const { IterateCompiledFrame(v); }
|
|
||||||
|
|
||||||
void JavaScriptFrame::SetParameterValue(int index, Object value) const {
|
void JavaScriptFrame::SetParameterValue(int index, Object value) const {
|
||||||
Memory<Address>(GetParameterSlot(index)) = value.ptr();
|
Memory<Address>(GetParameterSlot(index)) = value.ptr();
|
||||||
}
|
}
|
||||||
@ -2387,8 +2532,8 @@ void JsToWasmFrame::Iterate(RootVisitor* v) const {
|
|||||||
// |- - - - - - - - -| |
|
// |- - - - - - - - -| |
|
||||||
if (builtin != Builtin::kGenericJSToWasmWrapper) {
|
if (builtin != Builtin::kGenericJSToWasmWrapper) {
|
||||||
// If it's not the GenericJSToWasmWrapper, then it's the TurboFan compiled
|
// If it's not the GenericJSToWasmWrapper, then it's the TurboFan compiled
|
||||||
// specific wrapper. So we have to call IterateCompiledFrame.
|
// specific wrapper. So we have to call TypedFrame::Iterate.
|
||||||
IterateCompiledFrame(v);
|
TypedFrame::Iterate(v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The [fp + BuiltinFrameConstants::kGCScanSlotCount] on the stack is a value
|
// The [fp + BuiltinFrameConstants::kGCScanSlotCount] on the stack is a value
|
||||||
|
@ -537,9 +537,6 @@ class CommonFrame : public StackFrame {
|
|||||||
// Returns the address of the n'th expression stack element.
|
// Returns the address of the n'th expression stack element.
|
||||||
virtual Address GetExpressionAddress(int n) const;
|
virtual Address GetExpressionAddress(int n) const;
|
||||||
|
|
||||||
// Used by OptimizedFrames and StubFrames.
|
|
||||||
void IterateCompiledFrame(RootVisitor* v) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class StackFrame;
|
friend class StackFrame;
|
||||||
friend class SafeStackFrameIterator;
|
friend class SafeStackFrameIterator;
|
||||||
@ -548,7 +545,7 @@ class CommonFrame : public StackFrame {
|
|||||||
class TypedFrame : public CommonFrame {
|
class TypedFrame : public CommonFrame {
|
||||||
public:
|
public:
|
||||||
Code unchecked_code() const override { return {}; }
|
Code unchecked_code() const override { return {}; }
|
||||||
void Iterate(RootVisitor* v) const override { IterateCompiledFrame(v); }
|
void Iterate(RootVisitor* v) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline explicit TypedFrame(StackFrameIteratorBase* iterator);
|
inline explicit TypedFrame(StackFrameIteratorBase* iterator);
|
||||||
@ -818,9 +815,6 @@ class StubFrame : public TypedFrame {
|
|||||||
|
|
||||||
class OptimizedFrame : public JavaScriptFrame {
|
class OptimizedFrame : public JavaScriptFrame {
|
||||||
public:
|
public:
|
||||||
// GC support.
|
|
||||||
void Iterate(RootVisitor* v) const override;
|
|
||||||
|
|
||||||
// Return a list with {SharedFunctionInfo} objects of this frame.
|
// Return a list with {SharedFunctionInfo} objects of this frame.
|
||||||
// The functions are ordered bottom-to-top (i.e. functions.last()
|
// The functions are ordered bottom-to-top (i.e. functions.last()
|
||||||
// is the top-most activation)
|
// is the top-most activation)
|
||||||
@ -957,6 +951,9 @@ class TurbofanFrame : public OptimizedFrame {
|
|||||||
int* data, HandlerTable::CatchPrediction* prediction) override;
|
int* data, HandlerTable::CatchPrediction* prediction) override;
|
||||||
|
|
||||||
int ComputeParametersCount() const override;
|
int ComputeParametersCount() const override;
|
||||||
|
bool HasTaggedOutgoingParams(CodeLookupResult& code_lookup) const;
|
||||||
|
|
||||||
|
void Iterate(RootVisitor* v) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline explicit TurbofanFrame(StackFrameIteratorBase* iterator);
|
inline explicit TurbofanFrame(StackFrameIteratorBase* iterator);
|
||||||
|
Loading…
Reference in New Issue
Block a user