Commit aeca9457 authored by jfb's avatar jfb Committed by Commit bot

Add WasmFrame, backtraces reflect wasm's presence

For now WasmFrame doesn't summarize the wasm frames. That'll require adding the
metadata in wasm-compiler similar to DeoptimizationInputData.

Teach the basic backtrace to iterate over stack frames instead of JS frames.

Update the wasm stack test.

`git cl format` touches random lines in files I touch.

R=titzer@chromium.org
TEST=d8 --test --expose-wasm test/mjsunit/mjsunit.js test/mjsunit/wasm/stack.js

Review URL: https://codereview.chromium.org/1712003003

Cr-Commit-Position: refs/heads/master@{#34220}
parent cadc1e77
......@@ -151,11 +151,8 @@ inline bool StandardFrame::IsConstructFrame(Address fp) {
return marker == Smi::FromInt(StackFrame::CONSTRUCT);
}
inline JavaScriptFrame::JavaScriptFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) {
}
: StandardFrame(iterator) {}
Address JavaScriptFrame::GetParameterSlot(int index) const {
int param_count = ComputeParametersCount();
......@@ -242,6 +239,8 @@ inline ArgumentsAdaptorFrame::ArgumentsAdaptorFrame(
StackFrameIteratorBase* iterator) : JavaScriptFrame(iterator) {
}
inline WasmFrame::WasmFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) {}
inline InternalFrame::InternalFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) {
......@@ -257,21 +256,18 @@ inline ConstructFrame::ConstructFrame(StackFrameIteratorBase* iterator)
: InternalFrame(iterator) {
}
inline JavaScriptFrameIterator::JavaScriptFrameIterator(
Isolate* isolate)
: iterator_(isolate) {
if (!done()) Advance();
}
inline JavaScriptFrameIterator::JavaScriptFrameIterator(
Isolate* isolate, ThreadLocalTop* top)
: iterator_(isolate, top) {
if (!done()) Advance();
}
inline JavaScriptFrame* JavaScriptFrameIterator::frame() const {
// TODO(1233797): The frame hierarchy needs to change. It's
// problematic that we can't use the safe-cast operator to cast to
......
......@@ -134,12 +134,10 @@ StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type) {
#undef FRAME_TYPE_CASE
}
// -------------------------------------------------------------------------
JavaScriptFrameIterator::JavaScriptFrameIterator(
Isolate* isolate, StackFrame::Id id)
JavaScriptFrameIterator::JavaScriptFrameIterator(Isolate* isolate,
StackFrame::Id id)
: iterator_(isolate) {
while (!done()) {
Advance();
......@@ -446,7 +444,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
case Code::OPTIMIZED_FUNCTION:
return OPTIMIZED;
case Code::WASM_FUNCTION:
return STUB;
return WASM;
case Code::BUILTIN:
if (!marker->IsSmi()) {
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
......@@ -1222,6 +1220,20 @@ void StackFrame::PrintIndex(StringStream* accumulator,
accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
}
void WasmFrame::Print(StringStream* accumulator, PrintMode mode,
int index) const {
accumulator->Add("wasm frame");
}
Code* WasmFrame::unchecked_code() const {
return static_cast<Code*>(isolate()->FindCodeObject(pc()));
}
void WasmFrame::Iterate(ObjectVisitor* v) const { IterateCompiledFrame(v); }
Address WasmFrame::GetCallerStackPointer() const {
return fp() + ExitFrameConstants::kCallerSPDisplacement;
}
namespace {
......
......@@ -97,13 +97,13 @@ class StackHandler BASE_EMBEDDED {
DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
};
#define STACK_FRAME_TYPE_LIST(V) \
V(ENTRY, EntryFrame) \
V(ENTRY_CONSTRUCT, EntryConstructFrame) \
V(EXIT, ExitFrame) \
V(JAVA_SCRIPT, JavaScriptFrame) \
V(OPTIMIZED, OptimizedFrame) \
V(WASM, WasmFrame) \
V(INTERPRETED, InterpretedFrame) \
V(STUB, StubFrame) \
V(STUB_FAILURE_TRAMPOLINE, StubFailureTrampolineFrame) \
......@@ -310,6 +310,7 @@ class StackFrame BASE_EMBEDDED {
bool is_exit() const { return type() == EXIT; }
bool is_optimized() const { return type() == OPTIMIZED; }
bool is_interpreted() const { return type() == INTERPRETED; }
bool is_wasm() const { return type() == WASM; }
bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
bool is_internal() const { return type() == INTERNAL; }
bool is_stub_failure_trampoline() const {
......@@ -617,8 +618,7 @@ class FrameSummary BASE_EMBEDDED {
bool is_constructor_;
};
class JavaScriptFrame: public StandardFrame {
class JavaScriptFrame : public StandardFrame {
public:
Type type() const override { return JAVA_SCRIPT; }
......@@ -841,6 +841,28 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame {
friend class StackFrameIteratorBase;
};
class WasmFrame : public StandardFrame {
public:
Type type() const override { return WASM; }
// GC support.
void Iterate(ObjectVisitor* v) const override;
// Printing support.
void Print(StringStream* accumulator, PrintMode mode,
int index) const override;
// Determine the code for the frame.
Code* unchecked_code() const override;
protected:
inline explicit WasmFrame(StackFrameIteratorBase* iterator);
Address GetCallerStackPointer() const override;
private:
friend class StackFrameIteratorBase;
};
class InternalFrame: public StandardFrame {
public:
......@@ -974,7 +996,6 @@ class StackFrameIterator: public StackFrameIteratorBase {
DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
};
// Iterator that supports iterating through all JavaScript frames.
class JavaScriptFrameIterator BASE_EMBEDDED {
public:
......@@ -997,7 +1018,6 @@ class JavaScriptFrameIterator BASE_EMBEDDED {
StackFrameIterator iterator_;
};
// NOTE: The stack trace frame iterator is an iterator that only
// traverse proper JavaScript frames; that is JavaScript frames that
// have proper JavaScript functions. This excludes the problematic
......
......@@ -338,6 +338,21 @@ static bool IsVisibleInStackTrace(JSFunction* fun,
return true;
}
static Handle<FixedArray> MaybeGrow(Isolate* isolate,
Handle<FixedArray> elements,
int cur_position, int new_size) {
if (new_size > elements->length()) {
int new_capacity = JSObject::NewElementsCapacity(elements->length());
Handle<FixedArray> new_elements =
isolate->factory()->NewFixedArrayWithHoles(new_capacity);
for (int i = 0; i < cur_position; i++) {
new_elements->set(i, elements->get(i));
}
elements = new_elements;
}
DCHECK(new_size <= elements->length());
return elements;
}
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
Handle<Object> caller) {
......@@ -364,51 +379,68 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
int frames_seen = 0;
int sloppy_frames = 0;
bool encountered_strict_function = false;
for (JavaScriptFrameIterator iter(this);
!iter.done() && frames_seen < limit;
for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit;
iter.Advance()) {
JavaScriptFrame* frame = iter.frame();
// Set initial size to the maximum inlining level + 1 for the outermost
// function.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
Handle<JSFunction> fun = frames[i].function();
Handle<Object> recv = frames[i].receiver();
// Filter out internal frames that we do not want to show.
if (!IsVisibleInStackTrace(*fun, *caller, *recv, &seen_caller)) continue;
// Filter out frames from other security contexts.
if (!this->context()->HasSameSecurityTokenAs(fun->context())) continue;
if (cursor + 4 > elements->length()) {
int new_capacity = JSObject::NewElementsCapacity(elements->length());
Handle<FixedArray> new_elements =
factory()->NewFixedArrayWithHoles(new_capacity);
for (int i = 0; i < cursor; i++) {
new_elements->set(i, elements->get(i));
}
elements = new_elements;
}
DCHECK(cursor + 4 <= elements->length());
Handle<AbstractCode> abstract_code = frames[i].abstract_code();
Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
// The stack trace API should not expose receivers and function
// objects on frames deeper than the top-most one with a strict
// mode function. The number of sloppy frames is stored as
// first element in the result array.
if (!encountered_strict_function) {
if (is_strict(fun->shared()->language_mode())) {
encountered_strict_function = true;
} else {
sloppy_frames++;
StackFrame* frame = iter.frame();
switch (frame->type()) {
case StackFrame::JAVA_SCRIPT:
case StackFrame::OPTIMIZED:
case StackFrame::INTERPRETED: {
JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
// Set initial size to the maximum inlining level + 1 for the outermost
// function.
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();
Handle<Object> recv = frames[i].receiver();
// Filter out internal frames that we do not want to show.
if (!IsVisibleInStackTrace(*fun, *caller, *recv, &seen_caller)) {
continue;
}
// Filter out frames from other security contexts.
if (!this->context()->HasSameSecurityTokenAs(fun->context())) {
continue;
}
elements = MaybeGrow(this, elements, cursor, cursor + 4);
Handle<AbstractCode> abstract_code = frames[i].abstract_code();
Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
// The stack trace API should not expose receivers and function
// objects on frames deeper than the top-most one with a strict mode
// function. The number of sloppy frames is stored as first element in
// the result array.
if (!encountered_strict_function) {
if (is_strict(fun->shared()->language_mode())) {
encountered_strict_function = true;
} else {
sloppy_frames++;
}
}
elements->set(cursor++, *recv);
elements->set(cursor++, *fun);
elements->set(cursor++, *abstract_code);
elements->set(cursor++, *offset);
frames_seen++;
}
}
elements->set(cursor++, *recv);
elements->set(cursor++, *fun);
elements->set(cursor++, *abstract_code);
elements->set(cursor++, *offset);
frames_seen++;
} break;
case StackFrame::WASM: {
elements = MaybeGrow(this, elements, cursor, cursor + 4);
// TODO(jfb) Pass module object.
elements->set(cursor++, *factory()->undefined_value());
elements->set(cursor++,
*factory()->NewFunction(
factory()->NewStringFromAsciiChecked("<WASM>")));
elements->set(cursor++, Internals::IntToSmi(0));
elements->set(cursor++, Internals::IntToSmi(0));
frames_seen++;
} break;
default:
break;
}
}
elements->set(0, Smi::FromInt(sloppy_frames));
......@@ -419,7 +451,6 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
return result;
}
MaybeHandle<JSObject> Isolate::CaptureAndSetDetailedStackTrace(
Handle<JSObject> error_object) {
if (capture_stack_trace_for_uncaught_exceptions_) {
......
......@@ -4980,7 +4980,7 @@ bool Code::is_compare_ic_stub() { return kind() == COMPARE_IC; }
bool Code::is_compare_nil_ic_stub() { return kind() == COMPARE_NIL_IC; }
bool Code::is_to_boolean_ic_stub() { return kind() == TO_BOOLEAN_IC; }
bool Code::is_optimized_code() { return kind() == OPTIMIZED_FUNCTION; }
bool Code::is_wasm_code() { return kind() == WASM_FUNCTION; }
bool Code::embeds_maps_weakly() {
Kind k = kind();
......
......@@ -5002,6 +5002,7 @@ class Code: public HeapObject {
inline bool is_to_boolean_ic_stub();
inline bool is_keyed_stub();
inline bool is_optimized_code();
inline bool is_wasm_code();
inline bool embeds_maps_weakly();
inline bool IsCodeStubOrIC();
......
......@@ -62,8 +62,11 @@ function check_STACK() {
var expected = "Error\n" +
// The line numbers below will change as this test gains / loses lines..
" at STACK (stack.js:54:11)\n" + // --
" at <WASM> (<anonymous>)\n" + // --
" at <WASM> (<anonymous>)\n" + // --
" at <WASM> (<anonymous>)\n" + // --
" at testStack (stack.js:43:10)\n" +
// TODO(jfb) Add WebAssembly stack here.
" at stack.js:69:1";
" at stack.js:72:1";
testStack(STACK, check_STACK);
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