Skip to content

Commit 97628ee

Browse files
mmarchiniCommit Bot
authored andcommitted
[error] extend error stack w/ function parameters
Extend FrameArray to hold weak references to parameters for functions in the call stack. The goal here is to provide more metadata for postmortem tools (such as llnode), especially in cases of rethrowing (this will be particularly useful when using postmortem with promises on Node.js). Besides postmortem, these changes allow us to print a more detailed stack trace for errors with parameters types (or even values), which can be useful since JavaScript functions can receive any number of parameters of any type, and having a function behave differently according to the number of parameters received as well as their types is a common pattern on JS libraries and frameworks. [email protected], [email protected] Change-Id: Idf0984d0dbac16041f11d738d4b1c095a8eecd61 Reviewed-on: https://chromium-review.googlesource.com/c/1289489 Commit-Queue: Yang Guo <[email protected]> Reviewed-by: Yang Guo <[email protected]> Cr-Commit-Position: refs/heads/master@{#58468}
1 parent 2b96d8a commit 97628ee

7 files changed

Lines changed: 241 additions & 31 deletions

File tree

src/flag-definitions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,9 @@ DEFINE_INT(fuzzer_random_seed, 0,
10721072
DEFINE_BOOL(trace_rail, false, "trace RAIL mode")
10731073
DEFINE_BOOL(print_all_exceptions, false,
10741074
"print exception object and stack trace on each thrown exception")
1075+
DEFINE_BOOL(
1076+
detailed_error_stack_trace, false,
1077+
"includes arguments for each function call in the error stack frames array")
10751078

10761079
// runtime.cc
10771080
DEFINE_BOOL(runtime_call_stats, false, "report runtime call counts and times")

src/frames.cc

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,9 +1082,10 @@ void JavaScriptFrame::Summarize(std::vector<FrameSummary>* functions) const {
10821082
Code code = LookupCode();
10831083
int offset = static_cast<int>(pc() - code->InstructionStart());
10841084
AbstractCode abstract_code = AbstractCode::cast(code);
1085-
FrameSummary::JavaScriptFrameSummary summary(isolate(), receiver(),
1086-
function(), abstract_code,
1087-
offset, IsConstructor());
1085+
Handle<FixedArray> params = GetParameters();
1086+
FrameSummary::JavaScriptFrameSummary summary(
1087+
isolate(), receiver(), function(), abstract_code, offset, IsConstructor(),
1088+
*params);
10881089
functions->push_back(summary);
10891090
}
10901091

@@ -1242,6 +1243,20 @@ int JavaScriptFrame::ComputeParametersCount() const {
12421243
return GetNumberOfIncomingArguments();
12431244
}
12441245

1246+
Handle<FixedArray> JavaScriptFrame::GetParameters() const {
1247+
if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
1248+
return isolate()->factory()->empty_fixed_array();
1249+
}
1250+
int param_count = ComputeParametersCount();
1251+
Handle<FixedArray> parameters =
1252+
isolate()->factory()->NewFixedArray(param_count);
1253+
for (int i = 0; i < param_count; i++) {
1254+
parameters->set(i, GetParameter(i));
1255+
}
1256+
1257+
return parameters;
1258+
}
1259+
12451260
int JavaScriptBuiltinContinuationFrame::ComputeParametersCount() const {
12461261
// Assert that the first allocatable register is also the argument count
12471262
// register.
@@ -1278,13 +1293,15 @@ void JavaScriptBuiltinContinuationWithCatchFrame::SetException(
12781293

12791294
FrameSummary::JavaScriptFrameSummary::JavaScriptFrameSummary(
12801295
Isolate* isolate, Object* receiver, JSFunction function,
1281-
AbstractCode abstract_code, int code_offset, bool is_constructor)
1296+
AbstractCode abstract_code, int code_offset, bool is_constructor,
1297+
FixedArray parameters)
12821298
: FrameSummaryBase(isolate, FrameSummary::JAVA_SCRIPT),
12831299
receiver_(receiver, isolate),
12841300
function_(function, isolate),
12851301
abstract_code_(abstract_code, isolate),
12861302
code_offset_(code_offset),
1287-
is_constructor_(is_constructor) {
1303+
is_constructor_(is_constructor),
1304+
parameters_(parameters, isolate) {
12881305
DCHECK(abstract_code->IsBytecodeArray() ||
12891306
Code::cast(abstract_code)->kind() != Code::OPTIMIZED_FUNCTION);
12901307
}
@@ -1530,9 +1547,10 @@ void OptimizedFrame::Summarize(std::vector<FrameSummary>* frames) const {
15301547
}
15311548

15321549
// Append full summary of the encountered JS frame.
1533-
FrameSummary::JavaScriptFrameSummary summary(isolate(), *receiver,
1534-
*function, *abstract_code,
1535-
code_offset, is_constructor);
1550+
Handle<FixedArray> params = GetParameters();
1551+
FrameSummary::JavaScriptFrameSummary summary(
1552+
isolate(), *receiver, *function, *abstract_code, code_offset,
1553+
is_constructor, *params);
15361554
frames->push_back(summary);
15371555
is_constructor = false;
15381556
} else if (it->kind() == TranslatedFrame::kConstructStub) {
@@ -1743,9 +1761,10 @@ void InterpretedFrame::WriteInterpreterRegister(int register_index,
17431761
void InterpretedFrame::Summarize(std::vector<FrameSummary>* functions) const {
17441762
DCHECK(functions->empty());
17451763
AbstractCode abstract_code = AbstractCode::cast(GetBytecodeArray());
1764+
Handle<FixedArray> params = GetParameters();
17461765
FrameSummary::JavaScriptFrameSummary summary(
17471766
isolate(), receiver(), function(), abstract_code, GetBytecodeOffset(),
1748-
IsConstructor());
1767+
IsConstructor(), *params);
17491768
functions->push_back(summary);
17501769
}
17511770

src/frames.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ class BuiltinExitFrame : public ExitFrame {
442442
inline Object* new_target_slot_object() const;
443443

444444
friend class StackFrameIteratorBase;
445+
friend class FrameArrayBuilder;
445446
};
446447

447448
class StandardFrame;
@@ -476,13 +477,15 @@ class FrameSummary {
476477
public:
477478
JavaScriptFrameSummary(Isolate* isolate, Object* receiver,
478479
JSFunction function, AbstractCode abstract_code,
479-
int code_offset, bool is_constructor);
480+
int code_offset, bool is_constructor,
481+
FixedArray parameters);
480482

481483
Handle<Object> receiver() const { return receiver_; }
482484
Handle<JSFunction> function() const { return function_; }
483485
Handle<AbstractCode> abstract_code() const { return abstract_code_; }
484486
int code_offset() const { return code_offset_; }
485487
bool is_constructor() const { return is_constructor_; }
488+
Handle<FixedArray> parameters() const { return parameters_; }
486489
bool is_subject_to_debugging() const;
487490
int SourcePosition() const;
488491
int SourceStatementPosition() const;
@@ -496,6 +499,7 @@ class FrameSummary {
496499
Handle<AbstractCode> abstract_code_;
497500
int code_offset_;
498501
bool is_constructor_;
502+
Handle<FixedArray> parameters_;
499503
};
500504

501505
class WasmFrameSummary : public FrameSummaryBase {
@@ -690,6 +694,7 @@ class JavaScriptFrame : public StandardFrame {
690694
inline Address GetParameterSlot(int index) const;
691695
Object* GetParameter(int index) const override;
692696
int ComputeParametersCount() const override;
697+
Handle<FixedArray> GetParameters() const;
693698

694699
// Debugger access.
695700
void SetParameterValue(int index, Object* value) const;

src/isolate.cc

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -470,8 +470,6 @@ StackTraceFailureMessage::StackTraceFailureMessage(Isolate* isolate, void* ptr1,
470470
}
471471
}
472472

473-
namespace {
474-
475473
class FrameArrayBuilder {
476474
public:
477475
FrameArrayBuilder(Isolate* isolate, FrameSkipMode mode, int limit,
@@ -507,8 +505,19 @@ class FrameArrayBuilder {
507505
// The stored bytecode offset is relative to a different base than what
508506
// is used in the source position table, hence the subtraction.
509507
offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
508+
509+
Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
510+
if (V8_UNLIKELY(FLAG_detailed_error_stack_trace)) {
511+
int param_count = function->shared()->internal_formal_parameter_count();
512+
parameters = isolate_->factory()->NewFixedArray(param_count);
513+
for (int i = 0; i < param_count; i++) {
514+
parameters->set(i,
515+
generator_object->parameters_and_registers()->get(i));
516+
}
517+
}
518+
510519
elements_ = FrameArray::AppendJSFrame(elements_, receiver, function, code,
511-
offset, flags);
520+
offset, flags, parameters);
512521
}
513522

514523
void AppendPromiseAllFrame(Handle<Context> context, int offset) {
@@ -521,8 +530,12 @@ class FrameArrayBuilder {
521530

522531
Handle<Object> receiver(native_context->promise_function(), isolate_);
523532
Handle<AbstractCode> code(AbstractCode::cast(function->code()), isolate_);
533+
534+
// TODO(mmarchini) save Promises list from Promise.all()
535+
Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
536+
524537
elements_ = FrameArray::AppendJSFrame(elements_, receiver, function, code,
525-
offset, flags);
538+
offset, flags, parameters);
526539
}
527540

528541
void AppendJavaScriptFrame(
@@ -540,9 +553,13 @@ class FrameArrayBuilder {
540553
if (IsStrictFrame(function)) flags |= FrameArray::kIsStrict;
541554
if (is_constructor) flags |= FrameArray::kIsConstructor;
542555

556+
Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
557+
if (V8_UNLIKELY(FLAG_detailed_error_stack_trace))
558+
parameters = summary.parameters();
559+
543560
elements_ = FrameArray::AppendJSFrame(
544561
elements_, TheHoleToUndefined(isolate_, summary.receiver()), function,
545-
abstract_code, offset, flags);
562+
abstract_code, offset, flags, parameters);
546563
}
547564

548565
void AppendWasmCompiledFrame(
@@ -589,9 +606,18 @@ class FrameArrayBuilder {
589606
if (IsStrictFrame(function)) flags |= FrameArray::kIsStrict;
590607
if (exit_frame->IsConstructor()) flags |= FrameArray::kIsConstructor;
591608

609+
Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
610+
if (V8_UNLIKELY(FLAG_detailed_error_stack_trace)) {
611+
int param_count = exit_frame->ComputeParametersCount();
612+
parameters = isolate_->factory()->NewFixedArray(param_count);
613+
for (int i = 0; i < param_count; i++) {
614+
parameters->set(i, exit_frame->GetParameter(i));
615+
}
616+
}
617+
592618
elements_ = FrameArray::AppendJSFrame(elements_, receiver, function,
593619
Handle<AbstractCode>::cast(code),
594-
offset, flags);
620+
offset, flags, parameters);
595621
}
596622

597623
bool full() { return elements_->FrameCount() >= limit_; }
@@ -790,8 +816,6 @@ void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise,
790816
}
791817
}
792818

793-
} // namespace
794-
795819
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
796820
FrameSkipMode mode,
797821
Handle<Object> caller) {

src/objects.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10733,7 +10733,8 @@ Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
1073310733
Handle<Object> receiver,
1073410734
Handle<JSFunction> function,
1073510735
Handle<AbstractCode> code,
10736-
int offset, int flags) {
10736+
int offset, int flags,
10737+
Handle<FixedArray> parameters) {
1073710738
const int frame_count = in->FrameCount();
1073810739
const int new_length = LengthFor(frame_count + 1);
1073910740
Handle<FrameArray> array =
@@ -10743,6 +10744,7 @@ Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
1074310744
array->SetCode(frame_count, *code);
1074410745
array->SetOffset(frame_count, Smi::FromInt(offset));
1074510746
array->SetFlags(frame_count, Smi::FromInt(flags));
10747+
array->SetParameters(frame_count, *parameters);
1074610748
array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
1074710749
return array;
1074810750
}

src/objects/frame-array.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class Handle;
2525
V(Function, JSFunction) \
2626
V(Code, AbstractCode) \
2727
V(Offset, Smi) \
28-
V(Flags, Smi)
28+
V(Flags, Smi) \
29+
V(Parameters, FixedArray)
2930

3031
// Container object for data collected during simple stack trace captures.
3132
class FrameArray : public FixedArray {
@@ -59,7 +60,8 @@ class FrameArray : public FixedArray {
5960
Handle<Object> receiver,
6061
Handle<JSFunction> function,
6162
Handle<AbstractCode> code, int offset,
62-
int flags);
63+
int flags,
64+
Handle<FixedArray> parameters);
6365
static Handle<FrameArray> AppendWasmFrame(
6466
Handle<FrameArray> in, Handle<WasmInstanceObject> wasm_instance,
6567
int wasm_function_index, wasm::WasmCode* code, int offset, int flags);
@@ -86,7 +88,9 @@ class FrameArray : public FixedArray {
8688

8789
static const int kFlagsOffset = 4;
8890

89-
static const int kElementsPerFrame = 5;
91+
static const int kParametersOffset = 5;
92+
93+
static const int kElementsPerFrame = 6;
9094

9195
// Array layout indices.
9296

0 commit comments

Comments
 (0)