Commit df5417ae authored by clemensh's avatar clemensh Committed by Commit bot

Refactor FrameSummary for JS and Wasm frames

Wasm frames can be either compiled or interpreted. For interpreted wasm
frames, there is only one physical stack frame representing an
arbitrary stack of interpreted functions. Hence the physical stack
frame needs to provide a summary of the underlying functions.
Summaries were tailored for JavaScript frames before. Now they are
universal.

The refactored FrameSummaries are now also used in the FrameInspector,
and from the StackFrame objects themselves, to avoid code duplication.

All dispatch is implemented "manually", making the FrameSummary still
stack-allocatable.

BUG=v8:5822
R=yangguo@chromium.org, titzer@chromium.org

Review-Url: https://codereview.chromium.org/2619353006
Cr-Commit-Position: refs/heads/master@{#42279}
parent 53137df8
......@@ -5,22 +5,28 @@
#include "src/debug/debug-frames.h"
#include "src/frames-inl.h"
#include "src/wasm/wasm-interpreter.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
namespace internal {
FrameInspector::FrameInspector(StandardFrame* frame, int inlined_jsframe_index,
FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index,
Isolate* isolate)
: frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
: frame_(frame),
frame_summary_(FrameSummary::Get(frame, inlined_frame_index)),
deoptimized_frame_(nullptr),
isolate_(isolate) {
JavaScriptFrame* js_frame =
frame->is_java_script() ? javascript_frame() : nullptr;
DCHECK(js_frame || frame->is_wasm());
has_adapted_arguments_ = js_frame && js_frame->has_adapted_arguments();
is_bottommost_ = inlined_jsframe_index == 0;
is_bottommost_ = inlined_frame_index == 0;
is_optimized_ = frame_->is_optimized();
is_interpreted_ = frame_->is_interpreted();
// Calculate the deoptimized frame.
if (frame->is_optimized()) {
if (is_optimized_) {
DCHECK(js_frame != nullptr);
// TODO(turbofan): Revisit once we support deoptimization.
if (js_frame->LookupCode()->is_turbofanned() &&
......@@ -30,7 +36,7 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_jsframe_index,
}
deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
js_frame, inlined_jsframe_index, isolate);
js_frame, inlined_frame_index, isolate);
}
}
......@@ -47,16 +53,11 @@ int FrameInspector::GetParametersCount() {
}
Handle<Script> FrameInspector::GetScript() {
Object* script = is_optimized_
? deoptimized_frame_->GetFunction()->shared()->script()
: frame_->script();
return handle(Script::cast(script), isolate_);
return Handle<Script>::cast(frame_summary_.script());
}
Handle<JSFunction> FrameInspector::GetFunction() {
DCHECK(!frame_->is_wasm());
return is_optimized_ ? deoptimized_frame_->GetFunction()
: handle(javascript_frame()->function(), isolate_);
return frame_summary_.AsJavaScript().function();
}
Handle<Object> FrameInspector::GetParameter(int index) {
......@@ -76,22 +77,16 @@ Handle<Object> FrameInspector::GetExpression(int index) {
}
int FrameInspector::GetSourcePosition() {
return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
: frame_->position();
return frame_summary_.SourcePosition();
}
bool FrameInspector::IsConstructor() {
return is_optimized_ && !is_bottommost_
? deoptimized_frame_->HasConstructStub()
: frame_->IsConstructor();
}
bool FrameInspector::IsConstructor() { return frame_summary_.is_constructor(); }
Handle<Object> FrameInspector::GetContext() {
return is_optimized_ ? deoptimized_frame_->GetContext()
: handle(frame_->context(), isolate_);
}
// To inspect all the provided arguments the frame might need to be
// replaced with the arguments frame.
void FrameInspector::SetArgumentsFrame(StandardFrame* frame) {
......@@ -209,15 +204,11 @@ int DebugFrameHelper::FindIndexedNonNativeFrame(StackTraceFrameIterator* it,
int index) {
int count = -1;
for (; !it->done(); it->Advance()) {
if (it->is_wasm()) {
if (++count == index) return 0;
continue;
}
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
it->javascript_frame()->Summarize(&frames);
it->frame()->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
// Omit functions from native and extension scripts.
if (!frames[i].function()->shared()->IsSubjectToDebugging()) continue;
if (!frames[i].is_subject_to_debugging()) continue;
if (++count == index) return i;
}
}
......
......@@ -15,11 +15,13 @@ namespace internal {
class FrameInspector {
public:
FrameInspector(StandardFrame* frame, int inlined_jsframe_index,
FrameInspector(StandardFrame* frame, int inlined_frame_index,
Isolate* isolate);
~FrameInspector();
FrameSummary& summary() { return frame_summary_; }
int GetParametersCount();
Handle<JSFunction> GetFunction();
Handle<Script> GetScript();
......@@ -33,9 +35,6 @@ class FrameInspector {
return frame_->is_arguments_adaptor() ? ArgumentsAdaptorFrame::cast(frame_)
: JavaScriptFrame::cast(frame_);
}
inline WasmCompiledFrame* wasm_frame() {
return WasmCompiledFrame::cast(frame_);
}
JavaScriptFrame* GetArgumentsFrame() { return javascript_frame(); }
void SetArgumentsFrame(StandardFrame* frame);
......@@ -54,6 +53,7 @@ class FrameInspector {
Handle<String> parameter_name);
StandardFrame* frame_;
FrameSummary frame_summary_;
DeoptimizedFrameInfo* deoptimized_frame_;
Isolate* isolate_;
bool is_optimized_;
......
......@@ -62,7 +62,7 @@ BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
JavaScriptFrame* frame) {
FrameSummary summary = FrameSummary::GetFirst(frame);
int offset = summary.code_offset();
Handle<AbstractCode> abstract_code = summary.abstract_code();
Handle<AbstractCode> abstract_code = summary.AsJavaScript().abstract_code();
if (abstract_code->IsCode()) offset = offset - 1;
auto it = BreakIterator::GetIterator(debug_info, abstract_code);
it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
......@@ -72,7 +72,7 @@ BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info,
JavaScriptFrame* frame,
List<BreakLocation>* result_out) {
FrameSummary summary = FrameSummary::GetFirst(frame);
auto summary = FrameSummary::GetFirst(frame).AsJavaScript();
int offset = summary.code_offset();
Handle<AbstractCode> abstract_code = summary.abstract_code();
if (abstract_code->IsCode()) offset = offset - 1;
......@@ -558,11 +558,9 @@ void Debug::Break(JavaScriptFrame* frame) {
// Fall through.
case StepIn: {
FrameSummary summary = FrameSummary::GetFirst(frame);
int offset = summary.code_offset();
step_break = step_break || location.IsReturn() ||
(current_fp != last_fp) ||
(thread_local_.last_statement_position_ !=
summary.abstract_code()->SourceStatementPosition(offset));
step_break = step_break || location.IsReturn() || current_fp != last_fp ||
thread_local_.last_statement_position_ !=
summary.SourceStatementPosition();
break;
}
case StepFrame:
......@@ -1000,7 +998,7 @@ void Debug::PrepareStep(StepAction step_action) {
}
// Get the debug info (create it if it does not exist).
FrameSummary summary = FrameSummary::GetFirst(frame);
auto summary = FrameSummary::GetFirst(frame).AsJavaScript();
Handle<JSFunction> function(summary.function());
Handle<SharedFunctionInfo> shared(function->shared());
if (!EnsureDebugInfo(shared, function)) {
......@@ -2259,11 +2257,10 @@ void Debug::PrintBreakLocation() {
if (iterator.done()) return;
JavaScriptFrame* frame = iterator.frame();
FrameSummary summary = FrameSummary::GetFirst(frame);
int source_position =
summary.abstract_code()->SourcePosition(summary.code_offset());
Handle<Object> script_obj(summary.function()->shared()->script(), isolate_);
int source_position = summary.SourcePosition();
Handle<Object> script_obj = summary.script();
PrintF("[debug] break in function '");
summary.function()->PrintName();
summary.FunctionName()->PrintOn(stdout);
PrintF("'.\n");
if (script_obj->IsScript()) {
Handle<Script> script = Handle<Script>::cast(script_obj);
......
......@@ -318,10 +318,6 @@ JavaScriptFrame* StackTraceFrameIterator::javascript_frame() const {
return JavaScriptFrame::cast(frame());
}
WasmCompiledFrame* StackTraceFrameIterator::wasm_compiled_frame() const {
return WasmCompiledFrame::cast(frame());
}
inline StackFrame* SafeStackFrameIterator::frame() const {
DCHECK(!done());
DCHECK(frame_->is_java_script() || frame_->is_exit() ||
......
......@@ -971,8 +971,9 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions,
Code* code = LookupCode();
int offset = static_cast<int>(pc() - code->instruction_start());
AbstractCode* abstract_code = AbstractCode::cast(code);
FrameSummary summary(receiver(), function(), abstract_code, offset,
IsConstructor(), mode);
FrameSummary::JavaScriptFrameSummary summary(isolate(), receiver(),
function(), abstract_code,
offset, IsConstructor(), mode);
functions->Add(summary);
}
......@@ -1129,12 +1130,14 @@ bool CannotDeoptFromAsmCode(Code* code, JSFunction* function) {
} // namespace
FrameSummary::FrameSummary(Object* receiver, JSFunction* function,
AbstractCode* abstract_code, int code_offset,
bool is_constructor, Mode mode)
: receiver_(receiver, function->GetIsolate()),
function_(function),
abstract_code_(abstract_code),
FrameSummary::JavaScriptFrameSummary::JavaScriptFrameSummary(
Isolate* isolate, Object* receiver, JSFunction* function,
AbstractCode* abstract_code, int code_offset, bool is_constructor,
Mode mode)
: FrameSummaryBase(isolate, JAVA_SCRIPT),
receiver_(receiver, isolate),
function_(function, isolate),
abstract_code_(abstract_code, isolate),
code_offset_(code_offset),
is_constructor_(is_constructor) {
DCHECK(abstract_code->IsBytecodeArray() ||
......@@ -1143,36 +1146,166 @@ FrameSummary::FrameSummary(Object* receiver, JSFunction* function,
mode == kApproximateSummary);
}
FrameSummary FrameSummary::GetFirst(StandardFrame* frame) {
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames);
return frames.first();
bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
return function()->shared()->IsSubjectToDebugging();
}
void FrameSummary::Print() {
PrintF("receiver: ");
receiver_->ShortPrint();
PrintF("\nfunction: ");
function_->shared()->DebugName()->ShortPrint();
PrintF("\ncode: ");
abstract_code_->ShortPrint();
if (abstract_code_->IsCode()) {
Code* code = abstract_code_->GetCode();
if (code->kind() == Code::FUNCTION) PrintF(" UNOPT ");
if (code->kind() == Code::OPTIMIZED_FUNCTION) {
if (function()->shared()->asm_function()) {
DCHECK(CannotDeoptFromAsmCode(code, *function()));
PrintF(" ASM ");
} else {
PrintF(" OPT (approximate)");
}
int FrameSummary::JavaScriptFrameSummary::SourcePosition() const {
return abstract_code()->SourcePosition(code_offset());
}
int FrameSummary::JavaScriptFrameSummary::SourceStatementPosition() const {
return abstract_code()->SourceStatementPosition(code_offset());
}
Handle<Object> FrameSummary::JavaScriptFrameSummary::script() const {
return handle(function_->shared()->script(), isolate());
}
Handle<String> FrameSummary::JavaScriptFrameSummary::FunctionName() const {
return JSFunction::GetDebugName(function_);
}
Handle<Context> FrameSummary::JavaScriptFrameSummary::native_context() const {
return handle(function_->context()->native_context(), isolate());
}
FrameSummary::WasmFrameSummary::WasmFrameSummary(
Isolate* isolate, FrameSummary::Kind kind,
Handle<WasmInstanceObject> instance, bool at_to_number_conversion)
: FrameSummaryBase(isolate, kind),
wasm_instance_(instance),
at_to_number_conversion_(at_to_number_conversion) {}
Handle<Object> FrameSummary::WasmFrameSummary::receiver() const {
return wasm_instance_->GetIsolate()->global_proxy();
}
#define WASM_SUMMARY_DISPATCH(type, name) \
type FrameSummary::WasmFrameSummary::name() const { \
DCHECK(kind() == Kind::WASM_COMPILED || kind() == Kind::WASM_INTERPRETED); \
return kind() == Kind::WASM_COMPILED \
? static_cast<const WasmCompiledFrameSummary*>(this)->name() \
: static_cast<const WasmInterpretedFrameSummary*>(this) \
->name(); \
}
WASM_SUMMARY_DISPATCH(uint32_t, function_index)
WASM_SUMMARY_DISPATCH(int, byte_offset)
#undef WASM_SUMMARY_DISPATCH
int FrameSummary::WasmFrameSummary::SourcePosition() const {
int offset = byte_offset();
Handle<WasmCompiledModule> compiled_module(wasm_instance()->compiled_module(),
isolate());
if (compiled_module->is_asm_js()) {
offset = WasmCompiledModule::GetAsmJsSourcePosition(
compiled_module, function_index(), offset, at_to_number_conversion());
} else {
PrintF(" BYTECODE ");
offset += compiled_module->GetFunctionOffset(function_index());
}
PrintF("\npc: %d\n", code_offset_);
return offset;
}
Handle<Script> FrameSummary::WasmFrameSummary::script() const {
return handle(wasm_instance()->compiled_module()->script());
}
Handle<String> FrameSummary::WasmFrameSummary::FunctionName() const {
Handle<WasmCompiledModule> compiled_module(
wasm_instance()->compiled_module());
return WasmCompiledModule::GetFunctionName(compiled_module->GetIsolate(),
compiled_module, function_index());
}
Handle<Context> FrameSummary::WasmFrameSummary::native_context() const {
return wasm_instance()->compiled_module()->native_context();
}
FrameSummary::WasmCompiledFrameSummary::WasmCompiledFrameSummary(
Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> code,
int code_offset, bool at_to_number_conversion)
: WasmFrameSummary(isolate, WASM_COMPILED, instance,
at_to_number_conversion),
code_(code),
code_offset_(code_offset) {}
uint32_t FrameSummary::WasmCompiledFrameSummary::function_index() const {
FixedArray* deopt_data = code()->deoptimization_data();
DCHECK_EQ(2, deopt_data->length());
DCHECK(deopt_data->get(1)->IsSmi());
int val = Smi::cast(deopt_data->get(1))->value();
DCHECK_LE(0, val);
return static_cast<uint32_t>(val);
}
int FrameSummary::WasmCompiledFrameSummary::byte_offset() const {
return AbstractCode::cast(*code())->SourcePosition(code_offset());
}
FrameSummary::WasmInterpretedFrameSummary::WasmInterpretedFrameSummary(
Isolate* isolate, Handle<WasmInstanceObject> instance,
uint32_t function_index, int byte_offset)
: WasmFrameSummary(isolate, WASM_INTERPRETED, instance, false),
function_index_(function_index),
byte_offset_(byte_offset) {}
FrameSummary::~FrameSummary() {
#define FRAME_SUMMARY_DESTR(kind, type, field, desc) \
case kind: \
field.~type(); \
break;
switch (base_.kind()) {
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_DESTR)
default:
UNREACHABLE();
}
#undef FRAME_SUMMARY_DESTR
}
FrameSummary FrameSummary::Get(const StandardFrame* frame, int index) {
DCHECK_LE(0, index);
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames);
DCHECK_GT(frames.length(), index);
return frames[index];
}
FrameSummary FrameSummary::GetSingle(const StandardFrame* frame) {
List<FrameSummary> frames(1);
frame->Summarize(&frames);
DCHECK_EQ(1, frames.length());
return frames.first();
}
#define FRAME_SUMMARY_DISPATCH(ret, name) \
ret FrameSummary::name() const { \
switch (base_.kind()) { \
case JAVA_SCRIPT: \
return java_script_summary_.name(); \
case WASM_COMPILED: \
return wasm_compiled_summary_.name(); \
case WASM_INTERPRETED: \
return wasm_interpreted_summary_.name(); \
default: \
UNREACHABLE(); \
return ret{}; \
} \
}
FRAME_SUMMARY_DISPATCH(Handle<Object>, receiver)
FRAME_SUMMARY_DISPATCH(int, code_offset)
FRAME_SUMMARY_DISPATCH(bool, is_constructor)
FRAME_SUMMARY_DISPATCH(bool, is_subject_to_debugging)
FRAME_SUMMARY_DISPATCH(Handle<Object>, script)
FRAME_SUMMARY_DISPATCH(int, SourcePosition)
FRAME_SUMMARY_DISPATCH(int, SourceStatementPosition)
FRAME_SUMMARY_DISPATCH(Handle<String>, FunctionName)
FRAME_SUMMARY_DISPATCH(Handle<Context>, native_context)
#undef FRAME_SUMMARY_DISPATCH
void OptimizedFrame::Summarize(List<FrameSummary>* frames,
FrameSummary::Mode mode) const {
DCHECK(frames->length() == 0);
......@@ -1269,8 +1402,9 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames,
code_offset = bailout_id.ToInt(); // Points to current bytecode.
abstract_code = AbstractCode::cast(shared_info->bytecode_array());
}
FrameSummary summary(receiver, function, abstract_code, code_offset,
is_constructor);
FrameSummary::JavaScriptFrameSummary summary(isolate(), receiver,
function, abstract_code,
code_offset, is_constructor);
frames->Add(summary);
is_constructor = false;
} else if (frame_opcode == Translation::CONSTRUCT_STUB_FRAME) {
......@@ -1484,8 +1618,9 @@ void InterpretedFrame::Summarize(List<FrameSummary>* functions,
DCHECK(functions->length() == 0);
AbstractCode* abstract_code =
AbstractCode::cast(function()->shared()->bytecode_array());
FrameSummary summary(receiver(), function(), abstract_code,
GetBytecodeOffset(), IsConstructor());
FrameSummary::JavaScriptFrameSummary summary(
isolate(), receiver(), function(), abstract_code, GetBytecodeOffset(),
IsConstructor());
functions->Add(summary);
}
......@@ -1572,9 +1707,7 @@ WasmInstanceObject* WasmCompiledFrame::wasm_instance() const {
}
uint32_t WasmCompiledFrame::function_index() const {
FixedArray* deopt_data = LookupCode()->deoptimization_data();
DCHECK(deopt_data->length() == 2);
return Smi::cast(deopt_data->get(1))->value();
return FrameSummary::GetSingle(this).AsWasmCompiled().function_index();
}
Script* WasmCompiledFrame::script() const {
......@@ -1582,22 +1715,18 @@ Script* WasmCompiledFrame::script() const {
}
int WasmCompiledFrame::position() const {
int position = StandardFrame::position();
if (wasm_instance()->compiled_module()->is_asm_js()) {
Handle<WasmCompiledModule> compiled_module(
WasmInstanceObject::cast(wasm_instance())->compiled_module(),
isolate());
DCHECK_LE(0, position);
position = WasmCompiledModule::GetAsmJsSourcePosition(
compiled_module, function_index(), static_cast<uint32_t>(position),
at_to_number_conversion());
}
return position;
return FrameSummary::GetSingle(this).SourcePosition();
}
void WasmCompiledFrame::Summarize(List<FrameSummary>* functions,
FrameSummary::Mode mode) const {
// TODO(clemensh): Implement.
DCHECK_EQ(0, functions->length());
Handle<Code> code(LookupCode(), isolate());
int offset = static_cast<int>(pc() - code->instruction_start());
Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
FrameSummary::WasmCompiledFrameSummary summary(
isolate(), instance, code, offset, at_to_number_conversion());
functions->Add(summary);
}
bool WasmCompiledFrame::at_to_number_conversion() const {
......@@ -1639,6 +1768,7 @@ void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode,
void WasmInterpreterEntryFrame::Summarize(List<FrameSummary>* functions,
FrameSummary::Mode mode) const {
// TODO(clemensh): Implement this.
UNIMPLEMENTED();
}
Code* WasmInterpreterEntryFrame::unchecked_code() const {
......@@ -1657,8 +1787,7 @@ Script* WasmInterpreterEntryFrame::script() const {
}
int WasmInterpreterEntryFrame::position() const {
// TODO(clemensh): Implement this.
return 0;
return FrameSummary::GetFirst(this).AsWasmInterpreted().SourcePosition();
}
Address WasmInterpreterEntryFrame::GetCallerStackPointer() const {
......
......@@ -748,19 +748,48 @@ class FrameSummary BASE_EMBEDDED {
// information, but it might miss frames.
enum Mode { kExactSummary, kApproximateSummary };
FrameSummary(Object* receiver, JSFunction* function,
AbstractCode* abstract_code, int code_offset,
bool is_constructor, Mode mode = kExactSummary);
// Subclasses for the different summary kinds:
#define FRAME_SUMMARY_VARIANTS(F) \
F(JAVA_SCRIPT, JavaScriptFrameSummary, java_script_summary_, JavaScript) \
F(WASM_COMPILED, WasmCompiledFrameSummary, wasm_compiled_summary_, \
WasmCompiled) \
F(WASM_INTERPRETED, WasmInterpretedFrameSummary, wasm_interpreted_summary_, \
WasmInterpreted)
#define FRAME_SUMMARY_KIND(kind, type, field, desc) kind,
enum Kind { FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_KIND) };
#undef FRAME_SUMMARY_KIND
class FrameSummaryBase {
public:
FrameSummaryBase(Isolate* isolate, Kind kind)
: isolate_(isolate), kind_(kind) {}
Isolate* isolate() const { return isolate_; }
Kind kind() const { return kind_; }
private:
Isolate* isolate_;
Kind kind_;
};
static FrameSummary GetFirst(StandardFrame* frame);
class JavaScriptFrameSummary : public FrameSummaryBase {
public:
JavaScriptFrameSummary(Isolate* isolate, Object* receiver,
JSFunction* function, AbstractCode* abstract_code,
int code_offset, bool is_constructor,
Mode mode = kExactSummary);
Handle<Object> receiver() const { return receiver_; }
Handle<JSFunction> function() const { return function_; }
Handle<AbstractCode> abstract_code() const { return abstract_code_; }
int code_offset() const { return code_offset_; }
bool is_constructor() const { return is_constructor_; }
void Print();
bool is_subject_to_debugging() const;
int SourcePosition() const;
int SourceStatementPosition() const;
Handle<Object> script() const;
Handle<String> FunctionName() const;
Handle<Context> native_context() const;
private:
Handle<Object> receiver_;
......@@ -768,6 +797,105 @@ class FrameSummary BASE_EMBEDDED {
Handle<AbstractCode> abstract_code_;
int code_offset_;
bool is_constructor_;
};
class WasmFrameSummary : public FrameSummaryBase {
protected:
WasmFrameSummary(Isolate*, Kind, Handle<WasmInstanceObject>,
bool at_to_number_conversion);
public:
Handle<Object> receiver() const;
uint32_t function_index() const;
int byte_offset() const;
bool is_constructor() const { return false; }
bool is_subject_to_debugging() const { return true; }
int SourcePosition() const;
int SourceStatementPosition() const { return SourcePosition(); }
Handle<Script> script() const;
Handle<WasmInstanceObject> wasm_instance() const { return wasm_instance_; }
Handle<String> FunctionName() const;
Handle<Context> native_context() const;
bool at_to_number_conversion() const { return at_to_number_conversion_; }
private:
Handle<WasmInstanceObject> wasm_instance_;
bool at_to_number_conversion_;
};
class WasmCompiledFrameSummary : public WasmFrameSummary {
public:
WasmCompiledFrameSummary(Isolate*, Handle<WasmInstanceObject>, Handle<Code>,
int code_offset, bool at_to_number_conversion);
uint32_t function_index() const;
Handle<Code> code() const { return code_; }
int code_offset() const { return code_offset_; }
int byte_offset() const;
private:
Handle<Code> code_;
int code_offset_;
};
class WasmInterpretedFrameSummary : public WasmFrameSummary {
public:
WasmInterpretedFrameSummary(Isolate*, Handle<WasmInstanceObject>,
uint32_t function_index, int byte_offset);
uint32_t function_index() const { return function_index_; }
int code_offset() const { return byte_offset_; }
int byte_offset() const { return byte_offset_; }
private:
uint32_t function_index_;
int byte_offset_;
};
#undef FRAME_SUMMARY_FIELD
#define FRAME_SUMMARY_CONS(kind, type, field, desc) \
FrameSummary(type summ) : field(summ) {} // NOLINT
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CONS)
#undef FRAME_SUMMARY_CONS
~FrameSummary();
static inline FrameSummary GetFirst(const StandardFrame* frame) {
return Get(frame, 0);
}
static FrameSummary Get(const StandardFrame* frame, int index);
static FrameSummary GetSingle(const StandardFrame* frame);
// Dispatched accessors.
Handle<Object> receiver() const;
int code_offset() const;
bool is_constructor() const;
bool is_subject_to_debugging() const;
Handle<Object> script() const;
int SourcePosition() const;
int SourceStatementPosition() const;
Handle<String> FunctionName() const;
Handle<Context> native_context() const;
#define FRAME_SUMMARY_CAST(kind_, type, field, desc) \
bool Is##desc() const { return base_.kind() == kind_; } \
const type& As##desc() const { \
DCHECK_EQ(base_.kind(), kind_); \
return field; \
}
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CAST)
#undef FRAME_SUMMARY_CAST
bool IsWasm() const { return IsWasmCompiled() || IsWasmInterpreted(); }
const WasmFrameSummary& AsWasm() const {
if (IsWasmCompiled()) return AsWasmCompiled();
return AsWasmInterpreted();
}
private:
#define FRAME_SUMMARY_FIELD(kind, type, field, desc) type field;
union {
FrameSummaryBase base_;
FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_FIELD)
};
};
class StandardFrame : public StackFrame {
......@@ -1365,9 +1493,6 @@ class StackTraceFrameIterator BASE_EMBEDDED {
inline bool is_javascript() const;
inline bool is_wasm() const;
inline JavaScriptFrame* javascript_frame() const;
// TODO(clemensh): Remove / refactor this for general wasm frames
// (compiled/interpreted).
inline WasmCompiledFrame* wasm_compiled_frame() const;
// Advance to the frame holding the arguments for the current
// frame. This only affects the current frame if it is a javascript frame and
......
......@@ -461,13 +461,14 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
js_frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
Handle<JSFunction> fun = frames[i].function();
const auto& summ = frames[i].AsJavaScript();
Handle<JSFunction> fun = summ.function();
// Filter out internal frames that we do not want to show.
if (!helper.IsVisibleInStackTrace(*fun)) continue;
Handle<Object> recv = frames[i].receiver();
Handle<AbstractCode> abstract_code = frames[i].abstract_code();
Handle<AbstractCode> abstract_code = summ.abstract_code();
const int offset = frames[i].code_offset();
bool force_constructor = false;
......@@ -627,21 +628,22 @@ class CaptureStackTraceHelper {
}
Handle<JSObject> NewStackFrameObject(FrameSummary& summ) {
int position = summ.abstract_code()->SourcePosition(summ.code_offset());
return NewStackFrameObject(summ.function(), position,
summ.is_constructor());
if (summ.IsJavaScript()) return NewStackFrameObject(summ.AsJavaScript());
if (summ.IsWasm()) return NewStackFrameObject(summ.AsWasm());
UNREACHABLE();
return Handle<JSObject>::null();
}
Handle<JSObject> NewStackFrameObject(Handle<JSFunction> fun, int position,
bool is_constructor) {
Handle<JSObject> NewStackFrameObject(
const FrameSummary::JavaScriptFrameSummary& summ) {
Handle<JSObject> stack_frame =
factory()->NewJSObject(isolate_->object_function());
Handle<Script> script(Script::cast(fun->shared()->script()), isolate_);
Handle<Script> script = Handle<Script>::cast(summ.script());
if (!line_key_.is_null()) {
Script::PositionInfo info;
bool valid_pos =
Script::GetPositionInfo(script, position, &info, Script::WITH_OFFSET);
bool valid_pos = Script::GetPositionInfo(script, summ.SourcePosition(),
&info, Script::WITH_OFFSET);
if (!column_key_.is_null() && valid_pos) {
JSObject::AddProperty(stack_frame, column_key_,
......@@ -676,12 +678,13 @@ class CaptureStackTraceHelper {
}
if (!function_key_.is_null()) {
Handle<Object> fun_name = JSFunction::GetDebugName(fun);
Handle<String> fun_name = summ.FunctionName();
JSObject::AddProperty(stack_frame, function_key_, fun_name, NONE);
}
if (!constructor_key_.is_null()) {
Handle<Object> is_constructor_obj = factory()->ToBoolean(is_constructor);
Handle<Object> is_constructor_obj =
factory()->ToBoolean(summ.is_constructor());
JSObject::AddProperty(stack_frame, constructor_key_, is_constructor_obj,
NONE);
}
......@@ -703,29 +706,28 @@ class CaptureStackTraceHelper {
return stack_frame;
}
Handle<JSObject> NewStackFrameObject(WasmCompiledFrame* frame) {
Handle<JSObject> NewStackFrameObject(
const FrameSummary::WasmFrameSummary& summ) {
Handle<JSObject> stack_frame =
factory()->NewJSObject(isolate_->object_function());
if (!function_key_.is_null()) {
Handle<WasmCompiledModule> compiled_module(
frame->wasm_instance()->compiled_module(), isolate_);
summ.wasm_instance()->compiled_module(), isolate_);
Handle<String> name = WasmCompiledModule::GetFunctionName(
isolate_, compiled_module, frame->function_index());
isolate_, compiled_module, summ.function_index());
JSObject::AddProperty(stack_frame, function_key_, name, NONE);
}
// Encode the function index as line number (1-based).
if (!line_key_.is_null()) {
JSObject::AddProperty(
stack_frame, line_key_,
isolate_->factory()->NewNumberFromInt(frame->function_index() + 1),
isolate_->factory()->NewNumberFromInt(summ.function_index() + 1),
NONE);
}
// Encode the byte offset as column (1-based).
if (!column_key_.is_null()) {
Code* code = frame->LookupCode();
int offset = static_cast<int>(frame->pc() - code->instruction_start());
int position = AbstractCode::cast(code)->SourcePosition(offset);
int position = summ.byte_offset();
// Make position 1-based.
if (position >= 0) ++position;
JSObject::AddProperty(stack_frame, column_key_,
......@@ -733,7 +735,7 @@ class CaptureStackTraceHelper {
NONE);
}
if (!script_id_key_.is_null()) {
int script_id = frame->script()->id();
int script_id = summ.script()->id();
JSObject::AddProperty(stack_frame, script_id_key_,
handle(Smi::FromInt(script_id), isolate_), NONE);
}
......@@ -770,28 +772,19 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace(
for (StackTraceFrameIterator it(this); !it.done() && (frames_seen < limit);
it.Advance()) {
StandardFrame* frame = it.frame();
if (frame->is_java_script()) {
// Set initial size to the maximum inlining level + 1 for the outermost
// function.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
JavaScriptFrame::cast(frame)->Summarize(&frames);
frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
Handle<JSFunction> fun = frames[i].function();
// Filter frames from other security contexts.
if (!(options & StackTrace::kExposeFramesAcrossSecurityOrigins) &&
!this->context()->HasSameSecurityTokenAs(fun->context()))
!this->context()->HasSameSecurityTokenAs(*frames[i].native_context()))
continue;
Handle<JSObject> new_frame_obj = helper.NewStackFrameObject(frames[i]);
stack_trace_elems->set(frames_seen, *new_frame_obj);
frames_seen++;
}
} else {
DCHECK(frame->is_wasm());
WasmCompiledFrame* wasm_frame = WasmCompiledFrame::cast(frame);
Handle<JSObject> new_frame_obj = helper.NewStackFrameObject(wasm_frame);
stack_trace_elems->set(frames_seen, *new_frame_obj);
frames_seen++;
}
}
stack_trace->set_length(Smi::FromInt(frames_seen));
......@@ -1345,7 +1338,7 @@ HandlerTable::CatchPrediction PredictException(JavaScriptFrame* frame) {
List<FrameSummary> summaries;
frame->Summarize(&summaries);
for (const FrameSummary& summary : summaries) {
Handle<AbstractCode> code = summary.abstract_code();
Handle<AbstractCode> code = summary.AsJavaScript().abstract_code();
if (code->IsCode() && code->kind() == AbstractCode::BUILTIN) {
if (code->GetCode()->is_promise_rejection()) {
return HandlerTable::PROMISE;
......@@ -1359,7 +1352,7 @@ HandlerTable::CatchPrediction PredictException(JavaScriptFrame* frame) {
}
if (code->kind() == AbstractCode::OPTIMIZED_FUNCTION) {
DCHECK(summary.function()->shared()->asm_function());
DCHECK(summary.AsJavaScript().function()->shared()->asm_function());
// asm code cannot contain try-catch.
continue;
}
......@@ -1503,23 +1496,27 @@ bool Isolate::ComputeLocation(MessageLocation* target) {
StackTraceFrameIterator it(this);
if (it.done()) return false;
StandardFrame* frame = it.frame();
// TODO(clemensh): handle wasm frames
if (!frame->is_java_script()) return false;
JSFunction* fun = JavaScriptFrame::cast(frame)->function();
Object* script = fun->shared()->script();
if (!script->IsScript() ||
(Script::cast(script)->source()->IsUndefined(this))) {
return false;
}
Handle<Script> casted_script(Script::cast(script), this);
// Compute the location from the function and the relocation info of the
// baseline code. For optimized code this will use the deoptimization
// information to get canonical location information.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
JavaScriptFrame::cast(frame)->Summarize(&frames);
frame->Summarize(&frames);
FrameSummary& summary = frames.last();
int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
*target = MessageLocation(casted_script, pos, pos + 1, handle(fun, this));
int pos = summary.SourcePosition();
Handle<JSFunction> fun;
Handle<Object> script = summary.script();
if (!script->IsScript() ||
(Script::cast(*script)->source()->IsUndefined(this))) {
return false;
}
// TODO(wasm): Remove this once trap-if is always on.
// Background: Without trap-if, the information on the stack trace is
// incomplete (see bug v8:5007).
if (summary.IsWasmCompiled() && !FLAG_wasm_trap_if) return false;
if (summary.IsJavaScript()) fun = summary.AsJavaScript().function();
*target = MessageLocation(Handle<Script>::cast(script), pos, pos + 1, fun);
return true;
}
......
......@@ -64,8 +64,8 @@ class List {
// not safe to use after operations that can change the list's
// backing store (e.g. Add).
inline T& operator[](int i) const {
DCHECK(0 <= i);
SLOW_DCHECK(static_cast<unsigned>(i) < static_cast<unsigned>(length_));
DCHECK_LE(0, i);
DCHECK_GT(length_, i);
return data_[i];
}
inline T& at(int i) const { return operator[](i); }
......
......@@ -12983,7 +12983,7 @@ void Script::SetEvalOrigin(Handle<Script> script,
StackTraceFrameIterator it(script->GetIsolate());
if (!it.done() && it.is_javascript()) {
FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame());
script->set_eval_from_shared(summary.function()->shared());
script->set_eval_from_shared(summary.AsJavaScript().function()->shared());
script->set_eval_from_position(-summary.code_offset());
return;
}
......
......@@ -435,22 +435,18 @@ RUNTIME_FUNCTION(Runtime_GetFrameCount) {
return Smi::kZero;
}
for (StackTraceFrameIterator it(isolate, id); !it.done(); it.Advance()) {
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
if (it.is_wasm()) {
n++;
} else {
it.javascript_frame()->Summarize(&frames);
for (StackTraceFrameIterator it(isolate, id); !it.done(); it.Advance()) {
frames.Clear();
it.frame()->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
// Omit functions from native and extension scripts.
if (frames[i].function()->shared()->IsSubjectToDebugging()) n++;
}
if (frames[i].is_subject_to_debugging()) n++;
}
}
return Smi::FromInt(n);
}
static const int kFrameDetailsFrameIdIndex = 0;
static const int kFrameDetailsReceiverIndex = 1;
static const int kFrameDetailsFunctionIndex = 2;
......@@ -499,11 +495,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
StackTraceFrameIterator it(isolate, id);
// Inlined frame index in optimized frame, starting from outer function.
int inlined_jsframe_index =
int inlined_frame_index =
DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
if (inlined_jsframe_index == -1) return heap->undefined_value();
if (inlined_frame_index == -1) return heap->undefined_value();
FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
// Traverse the saved contexts chain to find the active context for the
// selected frame.
......@@ -514,10 +510,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()),
isolate);
// Find source position in unoptimized code.
int position = frame_inspector.GetSourcePosition();
if (it.is_wasm()) {
if (frame_inspector.summary().IsWasm()) {
// Create the details array (no dynamic information for wasm).
Handle<FixedArray> details =
isolate->factory()->NewFixedArray(kFrameDetailsFirstDynamicIndex);
......@@ -526,11 +519,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
details->set(kFrameDetailsFrameIdIndex, *frame_id);
// Add the function name.
Handle<WasmCompiledModule> compiled_module(
it.wasm_compiled_frame()->wasm_instance()->compiled_module(), isolate);
int func_index = it.wasm_compiled_frame()->function_index();
Handle<String> func_name = WasmCompiledModule::GetFunctionName(
isolate, compiled_module, func_index);
Handle<String> func_name = frame_inspector.summary().FunctionName();
details->set(kFrameDetailsFunctionIndex, *func_name);
// Add the script wrapper
......@@ -545,20 +534,8 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
details->set(kFrameDetailsLocalCountIndex, Smi::kZero);
// Add the source position.
// For wasm, it is function-local, so translate it to a module-relative
// position, such that together with the script it uniquely identifies the
// position.
Handle<Object> positionValue;
if (position != kNoSourcePosition) {
int translated_position = position;
// No further translation needed for asm.js modules.
if (!compiled_module->is_asm_js()) {
translated_position +=
wasm::GetFunctionCodeOffset(compiled_module, func_index);
}
details->set(kFrameDetailsSourcePositionIndex,
Smi::FromInt(translated_position));
}
int position = frame_inspector.summary().SourcePosition();
details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
// Add the constructor information.
details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(false));
......@@ -579,6 +556,9 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
return *isolate->factory()->NewJSArrayWithElements(details);
}
// Find source position in unoptimized code.
int position = frame_inspector.GetSourcePosition();
// Handle JavaScript frames.
bool is_optimized = it.frame()->is_optimized();
......@@ -660,7 +640,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
// the provided parameters whereas the function frame always have the number
// of arguments matching the functions parameters. The rest of the
// information (except for what is collected above) is the same.
if ((inlined_jsframe_index == 0) &&
if ((inlined_frame_index == 0) &&
it.javascript_frame()->has_adapted_arguments()) {
it.AdvanceToArgumentsFrame();
frame_inspector.SetArgumentsFrame(it.frame());
......@@ -718,7 +698,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
}
if (is_optimized) {
flags |= 1 << 1;
flags |= inlined_jsframe_index << 2;
flags |= inlined_frame_index << 2;
}
details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
......
......@@ -332,7 +332,7 @@ bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
// information to get canonical location information.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
it.frame()->Summarize(&frames);
FrameSummary& summary = frames.last();
auto& summary = frames.last().AsJavaScript();
Handle<JSFunction> function = summary.function();
Handle<Object> script(function->shared()->script(), isolate);
int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
......
......@@ -450,6 +450,7 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
compiled_module->InitId();
compiled_module->set_shared(shared);
compiled_module->set_native_context(isolate->native_context());
return compiled_module;
}
......
......@@ -237,6 +237,7 @@ class WasmCompiledModule : public FixedArray {
#define CORE_WCM_PROPERTY_TABLE(MACRO) \
MACRO(WASM_OBJECT, WasmSharedModuleData, shared) \
MACRO(OBJECT, Context, native_context) \
MACRO(OBJECT, FixedArray, code_table) \
MACRO(OBJECT, FixedArray, function_tables) \
MACRO(OBJECT, FixedArray, signature_tables) \
......
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