[refactor] Introduce BuiltinExitFrame::Summarize()

This CL overrides the Summarize() method on the BuiltinExitFrame,
similar to what is already implemented on UnoptimizedFrame. This
way the stack trace capturing logic can be unified further, and
only needs to distinguish between JavaScript(ish) and WebAssembly
frames now.

Bug: chromium:1258599, chromium:1278650, chromium:1278647
Change-Id: I15f4dd61199ff047930796ce285bd938e8bcd22f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3327142
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78347}
This commit is contained in:
Benedikt Meurer 2021-12-13 06:21:19 +01:00 committed by V8 LUCI CQ
parent 2e1f8c825a
commit 3312b952d1
3 changed files with 44 additions and 56 deletions

View File

@ -869,16 +869,24 @@ void ExitFrame::FillState(Address fp, Address sp, State* state) {
state->constant_pool_address = nullptr;
}
void BuiltinExitFrame::Summarize(std::vector<FrameSummary>* frames) const {
DCHECK(frames->empty());
Handle<FixedArray> parameters = GetParameters();
DisallowGarbageCollection no_gc;
Code code = LookupCode();
int code_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
FrameSummary::JavaScriptFrameSummary summary(
isolate(), receiver(), function(), AbstractCode::cast(code), code_offset,
IsConstructor(), *parameters);
frames->push_back(summary);
}
JSFunction BuiltinExitFrame::function() const {
return JSFunction::cast(target_slot_object());
}
Object BuiltinExitFrame::receiver() const { return receiver_slot_object(); }
bool BuiltinExitFrame::IsConstructor() const {
return !new_target_slot_object().IsUndefined(isolate());
}
Object BuiltinExitFrame::GetParameter(int i) const {
DCHECK(i >= 0 && i < ComputeParametersCount());
int offset =
@ -896,6 +904,22 @@ int BuiltinExitFrame::ComputeParametersCount() const {
return argc;
}
Handle<FixedArray> BuiltinExitFrame::GetParameters() const {
if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
return isolate()->factory()->empty_fixed_array();
}
int param_count = ComputeParametersCount();
auto parameters = isolate()->factory()->NewFixedArray(param_count);
for (int i = 0; i < param_count; i++) {
parameters->set(i, GetParameter(i));
}
return parameters;
}
bool BuiltinExitFrame::IsConstructor() const {
return !new_target_slot_object().IsUndefined(isolate());
}
namespace {
void PrintIndex(StringStream* accumulator, StackFrame::PrintMode mode,
int index) {

View File

@ -756,25 +756,26 @@ class BuiltinExitFrame : public ExitFrame {
public:
Type type() const override { return BUILTIN_EXIT; }
static BuiltinExitFrame* cast(StackFrame* frame) {
DCHECK(frame->is_builtin_exit());
return static_cast<BuiltinExitFrame*>(frame);
}
JSFunction function() const;
Object receiver() const;
Object GetParameter(int i) const;
int ComputeParametersCount() const;
Handle<FixedArray> GetParameters() const;
// Check if this frame is a constructor frame invoked through 'new'.
bool IsConstructor() const;
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
// Summarize Frame
void Summarize(std::vector<FrameSummary>* frames) const override;
protected:
inline explicit BuiltinExitFrame(StackFrameIteratorBase* iterator);
private:
Object GetParameter(int i) const;
int ComputeParametersCount() const;
inline Object receiver_slot_object() const;
inline Object argc_slot_object() const;
inline Object target_slot_object() const;

View File

@ -785,38 +785,6 @@ class StackTraceBuilder {
}
#endif // V8_ENABLE_WEBASSEMBLY
void AppendBuiltinExitFrame(BuiltinExitFrame* exit_frame) {
Handle<JSFunction> function(exit_frame->function(), isolate_);
if (!IsVisibleInStackTrace(function)) return;
// TODO(szuend): Remove this check once the flag is enabled
// by default.
if (!FLAG_experimental_stack_trace_frames &&
function->shared().IsApiFunction()) {
return;
}
Handle<Object> receiver(exit_frame->receiver(), isolate_);
Handle<Code> code(exit_frame->LookupCode(), isolate_);
const int offset =
code->GetOffsetFromInstructionStart(isolate_, exit_frame->pc());
int flags = 0;
if (IsStrictFrame(function)) flags |= StackFrameInfo::kIsStrict;
if (exit_frame->IsConstructor()) flags |= StackFrameInfo::kIsConstructor;
Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
if (V8_UNLIKELY(FLAG_detailed_error_stack_trace)) {
int param_count = exit_frame->ComputeParametersCount();
parameters = isolate_->factory()->NewFixedArray(param_count);
for (int i = 0; i < param_count; i++) {
parameters->set(i, exit_frame->GetParameter(i));
}
}
AppendFrame(receiver, function, code, offset, flags, parameters);
}
bool Full() { return index_ >= limit_; }
Handle<FixedArray> Build() {
@ -866,6 +834,12 @@ class StackTraceBuilder {
}
bool IsNotHidden(Handle<JSFunction> function) {
// TODO(szuend): Remove this check once the flag is enabled
// by default.
if (!FLAG_experimental_stack_trace_frames &&
function->shared().IsApiFunction()) {
return false;
}
// Functions defined not in user scripts are not visible unless directly
// exposed, in which case the native flag is set.
// The --builtins-in-stack-traces command line flag allows including
@ -1059,7 +1033,6 @@ struct CaptureStackTraceOptions {
FrameSkipMode skip_mode;
StackTraceBuilder::FrameFilterMode filter_mode;
bool capture_builtin_exit_frames;
bool capture_only_frames_subject_to_debugging;
bool async_stack_trace;
};
@ -1085,6 +1058,7 @@ Handle<FixedArray> CaptureStackTrace(Isolate* isolate, Handle<Object> caller,
it.Advance()) {
StackFrame* const frame = it.frame();
switch (frame->type()) {
case StackFrame::BUILTIN_EXIT:
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION:
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
case StackFrame::OPTIMIZED:
@ -1125,14 +1099,6 @@ Handle<FixedArray> CaptureStackTrace(Isolate* isolate, Handle<Object> caller,
break;
}
case StackFrame::BUILTIN_EXIT:
if (!options.capture_builtin_exit_frames) continue;
// BuiltinExitFrames are not standard frames, so they do not have
// Summarize(). However, they may have one JS frame worth showing.
builder.AppendBuiltinExitFrame(BuiltinExitFrame::cast(frame));
break;
default:
break;
}
@ -1221,7 +1187,6 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
CaptureStackTraceOptions options;
options.limit = limit;
options.skip_mode = mode;
options.capture_builtin_exit_frames = true;
options.async_stack_trace = FLAG_async_stack_traces;
options.filter_mode = StackTraceBuilder::CURRENT_SECURITY_CONTEXT;
options.capture_only_frames_subject_to_debugging = false;
@ -1313,7 +1278,6 @@ Handle<FixedArray> Isolate::CaptureCurrentStackTrace(
CaptureStackTraceOptions options;
options.limit = std::max(frame_limit, 0); // Ensure no negative values.
options.skip_mode = SKIP_NONE;
options.capture_builtin_exit_frames = false;
options.async_stack_trace = false;
options.filter_mode =
(stack_trace_options & StackTrace::kExposeFramesAcrossSecurityOrigins)
@ -2230,7 +2194,6 @@ void Isolate::PrintCurrentStackTrace(std::ostream& out) {
CaptureStackTraceOptions options;
options.limit = 0;
options.skip_mode = SKIP_NONE;
options.capture_builtin_exit_frames = true;
options.async_stack_trace = FLAG_async_stack_traces;
options.filter_mode = StackTraceBuilder::CURRENT_SECURITY_CONTEXT;
options.capture_only_frames_subject_to_debugging = false;