Prepare StackFrame hierarchy & iterators for WASM

This particularly changes the StackTraceFrameIterator such that is not
only returs JavaScriptFrames, but also WasmFrames. Because of that,
some methods (Summarize, function, receiver) were pulled up to the
StandardFrame, with specializations in JavaScriptFrame and WasmFrame.

R=jfb@chromium.org, titzer@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#35293}
This commit is contained in:
clemensh 2016-04-06 04:37:15 -07:00 committed by Commit bot
parent 141324cfdc
commit 0845448672
7 changed files with 125 additions and 71 deletions

View File

@ -199,11 +199,6 @@ inline int JavaScriptFrame::ComputeOperandsCount() const {
}
inline Object* JavaScriptFrame::receiver() const {
return GetParameter(-1);
}
inline void JavaScriptFrame::set_receiver(Object* value) {
Memory::Object_at(GetParameterSlot(-1)) = value;
}
@ -214,11 +209,6 @@ inline bool JavaScriptFrame::has_adapted_arguments() const {
}
inline JSFunction* JavaScriptFrame::function() const {
return JSFunction::cast(function_slot_object());
}
inline Object* JavaScriptFrame::function_slot_object() const {
const int offset = JavaScriptFrameConstants::kFunctionOffset;
return Memory::Object_at(fp() + offset);
@ -288,6 +278,28 @@ inline JavaScriptFrame* JavaScriptFrameIterator::frame() const {
return static_cast<JavaScriptFrame*>(frame);
}
inline StandardFrame* StackTraceFrameIterator::frame() const {
StackFrame* frame = iterator_.frame();
DCHECK(frame->is_java_script() || frame->is_arguments_adaptor() ||
frame->is_wasm());
return static_cast<StandardFrame*>(frame);
}
bool StackTraceFrameIterator::is_javascript() const {
return frame()->is_java_script();
}
bool StackTraceFrameIterator::is_wasm() const { return frame()->is_wasm(); }
JavaScriptFrame* StackTraceFrameIterator::javascript_frame() const {
DCHECK(is_javascript());
return static_cast<JavaScriptFrame*>(frame());
}
WasmFrame* StackTraceFrameIterator::wasm_frame() const {
DCHECK(is_wasm());
return static_cast<WasmFrame*>(frame());
}
inline StackFrame* SafeStackFrameIterator::frame() const {
DCHECK(!done());

View File

@ -160,28 +160,29 @@ void JavaScriptFrameIterator::AdvanceToArgumentsFrame() {
// -------------------------------------------------------------------------
StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
: JavaScriptFrameIterator(isolate) {
if (!done() && !IsValidFrame()) Advance();
: iterator_(isolate) {
if (!done() && !IsValidFrame(iterator_.frame())) Advance();
}
void StackTraceFrameIterator::Advance() {
while (true) {
JavaScriptFrameIterator::Advance();
if (done()) return;
if (IsValidFrame()) return;
}
do {
iterator_.Advance();
} while (!done() && !IsValidFrame(iterator_.frame()));
}
bool StackTraceFrameIterator::IsValidFrame() {
if (!frame()->function()->IsJSFunction()) return false;
Object* script = frame()->function()->shared()->script();
bool StackTraceFrameIterator::IsValidFrame(StackFrame* frame) const {
if (frame->is_java_script()) {
JavaScriptFrame* jsFrame = static_cast<JavaScriptFrame*>(frame);
if (!jsFrame->function()->IsJSFunction()) return false;
Object* script = jsFrame->function()->shared()->script();
// Don't show functions from native scripts to user.
return (script->IsScript() &&
Script::TYPE_NATIVE != Script::cast(script)->type());
}
// apart from javascript, only wasm is valid
return frame->is_wasm();
}
@ -616,6 +617,19 @@ void ExitFrame::FillState(Address fp, Address sp, State* state) {
state->constant_pool_address = NULL;
}
void StandardFrame::Summarize(List<FrameSummary>* functions) const {
DCHECK(functions->length() == 0);
// default implementation: no summary added
}
JSFunction* StandardFrame::function() const {
// this default implementation is overridden by JS and WASM frames
return nullptr;
}
Object* StandardFrame::receiver() const {
return isolate()->heap()->undefined_value();
}
Address StandardFrame::GetExpressionAddress(int n) const {
const int offset = StandardFrameConstants::kExpressionsOffset;
@ -846,8 +860,7 @@ void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) const {
functions->Add(function());
}
void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
void JavaScriptFrame::Summarize(List<FrameSummary>* functions) const {
DCHECK(functions->length() == 0);
Code* code = LookupCode();
int offset = static_cast<int>(pc() - code->instruction_start());
@ -857,6 +870,12 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
functions->Add(summary);
}
JSFunction* JavaScriptFrame::function() const {
return JSFunction::cast(function_slot_object());
}
Object* JavaScriptFrame::receiver() const { return GetParameter(-1); }
int JavaScriptFrame::LookupExceptionHandlerInTable(
int* stack_depth, HandlerTable::CatchPrediction* prediction) {
Code* code = LookupCode();
@ -978,8 +997,7 @@ void FrameSummary::Print() {
PrintF("\npc: %d\n", code_offset_);
}
void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
void OptimizedFrame::Summarize(List<FrameSummary>* frames) const {
DCHECK(frames->length() == 0);
DCHECK(is_optimized());
@ -1234,7 +1252,7 @@ Object* InterpretedFrame::GetInterpreterRegister(int register_index) const {
return GetExpression(index + register_index);
}
void InterpretedFrame::Summarize(List<FrameSummary>* functions) {
void InterpretedFrame::Summarize(List<FrameSummary>* functions) const {
DCHECK(functions->length() == 0);
AbstractCode* abstract_code =
AbstractCode::cast(function()->shared()->bytecode_array());
@ -1291,6 +1309,15 @@ Code* WasmFrame::unchecked_code() const {
return static_cast<Code*>(isolate()->FindCodeObject(pc()));
}
JSFunction* WasmFrame::function() const {
// TODO(clemensh): generate the right JSFunctions once per wasm function and
// cache them
Factory* factory = isolate()->factory();
Handle<JSFunction> fun =
factory->NewFunction(factory->NewStringFromAsciiChecked("<WASM>"));
return *fun;
}
void WasmFrame::Iterate(ObjectVisitor* v) const { IterateCompiledFrame(v); }
Address WasmFrame::GetCallerStackPointer() const {

View File

@ -640,8 +640,29 @@ class ExitFrame: public StackFrame {
friend class StackFrameIteratorBase;
};
class FrameSummary BASE_EMBEDDED {
public:
FrameSummary(Object* receiver, JSFunction* function,
AbstractCode* abstract_code, int code_offset,
bool is_constructor);
class StandardFrame: public StackFrame {
Handle<Object> receiver() { return receiver_; }
Handle<JSFunction> function() { return function_; }
Handle<AbstractCode> abstract_code() { return abstract_code_; }
int code_offset() { return code_offset_; }
bool is_constructor() { return is_constructor_; }
void Print();
private:
Handle<Object> receiver_;
Handle<JSFunction> function_;
Handle<AbstractCode> abstract_code_;
int code_offset_;
bool is_constructor_;
};
class StandardFrame : public StackFrame {
public:
// Testers.
bool is_standard() const override { return true; }
@ -661,6 +682,13 @@ class StandardFrame: public StackFrame {
return static_cast<StandardFrame*>(frame);
}
// Build a list with summaries for this frame including all inlined frames.
virtual void Summarize(List<FrameSummary>* frames) const;
// Accessors.
virtual JSFunction* function() const;
virtual Object* receiver() const;
protected:
inline explicit StandardFrame(StackFrameIteratorBase* iterator);
@ -702,35 +730,13 @@ class StandardFrame: public StackFrame {
};
class FrameSummary BASE_EMBEDDED {
public:
FrameSummary(Object* receiver, JSFunction* function,
AbstractCode* abstract_code, int code_offset,
bool is_constructor);
Handle<Object> receiver() { return receiver_; }
Handle<JSFunction> function() { return function_; }
Handle<AbstractCode> abstract_code() { return abstract_code_; }
int code_offset() { return code_offset_; }
bool is_constructor() { return is_constructor_; }
void Print();
private:
Handle<Object> receiver_;
Handle<JSFunction> function_;
Handle<AbstractCode> abstract_code_;
int code_offset_;
bool is_constructor_;
};
class JavaScriptFrame : public StandardFrame {
public:
Type type() const override { return JAVA_SCRIPT; }
// Accessors.
inline JSFunction* function() const;
inline Object* receiver() const;
JSFunction* function() const override;
Object* receiver() const override;
inline void set_receiver(Object* value);
// Access the parameters.
@ -777,8 +783,7 @@ class JavaScriptFrame : public StandardFrame {
// Return a list with JSFunctions of this frame.
virtual void GetFunctions(List<JSFunction*>* functions) const;
// Build a list with summaries for this frame including all inlined frames.
virtual void Summarize(List<FrameSummary>* frames);
void Summarize(List<FrameSummary>* frames) const override;
// Lookup exception handler for current {pc}, returns -1 if none found. Also
// returns data associated with the handler site specific to the frame type:
@ -856,7 +861,7 @@ class OptimizedFrame : public JavaScriptFrame {
// is the top-most activation)
void GetFunctions(List<JSFunction*>* functions) const override;
void Summarize(List<FrameSummary>* frames) override;
void Summarize(List<FrameSummary>* frames) const override;
// Lookup exception handler for current {pc}, returns -1 if none found.
int LookupExceptionHandlerInTable(
@ -902,7 +907,7 @@ class InterpretedFrame : public JavaScriptFrame {
Object* GetInterpreterRegister(int register_index) const;
// Build a list with summaries for this frame including all inlined frames.
void Summarize(List<FrameSummary>* frames) override;
void Summarize(List<FrameSummary>* frames) const override;
protected:
inline explicit InterpretedFrame(StackFrameIteratorBase* iterator);
@ -965,6 +970,8 @@ class WasmFrame : public StandardFrame {
return static_cast<WasmFrame*>(frame);
}
JSFunction* function() const override;
protected:
inline explicit WasmFrame(StackFrameIteratorBase* iterator);
@ -1142,17 +1149,25 @@ 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
// functions in runtime.js.
class StackTraceFrameIterator: public JavaScriptFrameIterator {
// NOTE: The stack trace frame iterator is an iterator that only traverse proper
// JavaScript frames that have proper JavaScript functions and WASM frames.
// This excludes the problematic functions in runtime.js.
class StackTraceFrameIterator BASE_EMBEDDED {
public:
explicit StackTraceFrameIterator(Isolate* isolate);
bool done() const { return iterator_.done(); }
void Advance();
inline StandardFrame* frame() const;
inline bool is_javascript() const;
inline bool is_wasm() const;
inline JavaScriptFrame* javascript_frame() const;
inline WasmFrame* wasm_frame() const;
private:
bool IsValidFrame();
StackFrameIterator iterator_;
bool IsValidFrame(StackFrame* frame) const;
};

View File

@ -687,7 +687,7 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace(
StackTraceFrameIterator it(this);
int frames_seen = 0;
while (!it.done() && (frames_seen < limit)) {
JavaScriptFrame* frame = it.frame();
StandardFrame* frame = it.frame();
// Set initial size to the maximum inlining level + 1 for the outermost
// function.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
@ -1318,7 +1318,7 @@ void Isolate::PrintCurrentStackTrace(FILE* out) {
while (!it.done()) {
HandleScope scope(this);
// Find code position if recorded in relocation info.
JavaScriptFrame* frame = it.frame();
StandardFrame* frame = it.frame();
Code* code = frame->LookupCode();
int offset = static_cast<int>(frame->pc() - code->instruction_start());
int pos = frame->LookupCode()->SourcePosition(offset);
@ -1344,7 +1344,7 @@ void Isolate::PrintCurrentStackTrace(FILE* out) {
bool Isolate::ComputeLocation(MessageLocation* target) {
StackTraceFrameIterator it(this);
if (!it.done()) {
JavaScriptFrame* frame = it.frame();
StandardFrame* frame = it.frame();
JSFunction* fun = frame->function();
Object* script = fun->shared()->script();
if (script->IsScript() &&
@ -1354,7 +1354,7 @@ bool Isolate::ComputeLocation(MessageLocation* target) {
// baseline code. For optimized code this will use the deoptimization
// information to get canonical location information.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
it.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));

View File

@ -233,7 +233,7 @@ void AllocationTracker::AllocationEvent(Address addr, int size) {
int length = 0;
StackTraceFrameIterator it(isolate);
while (!it.done() && length < kMaxAllocationTraceLength) {
JavaScriptFrame* frame = it.frame();
StandardFrame* frame = it.frame();
SharedFunctionInfo* shared = frame->function()->shared();
SnapshotObjectId id = ids_->FindOrAddEntry(
shared->address(), shared->Size(), false);

View File

@ -143,7 +143,7 @@ SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() {
StackTraceFrameIterator it(isolate_);
int frames_captured = 0;
while (!it.done() && frames_captured < stack_depth_) {
JavaScriptFrame* frame = it.frame();
StandardFrame* frame = it.frame();
SharedFunctionInfo* shared = frame->function()->shared();
stack.push_back(shared);

View File

@ -16,9 +16,9 @@ namespace {
void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
StackTraceFrameIterator it(CcTest::i_isolate());
int frames_seen = 0;
JavaScriptFrame* topmost = it.frame();
JavaScriptFrame* topmost = it.javascript_frame();
while (!it.done()) {
JavaScriptFrame* frame = it.frame();
JavaScriptFrame* frame = it.javascript_frame();
List<JSFunction*> functions(2);
frame->GetFunctions(&functions);
PrintF("%d %s, inline count: %d\n", frames_seen,