summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/stack-frame-info.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects/stack-frame-info.cc')
-rw-r--r--deps/v8/src/objects/stack-frame-info.cc313
1 files changed, 313 insertions, 0 deletions
diff --git a/deps/v8/src/objects/stack-frame-info.cc b/deps/v8/src/objects/stack-frame-info.cc
index f427d7eae2..558449d85a 100644
--- a/deps/v8/src/objects/stack-frame-info.cc
+++ b/deps/v8/src/objects/stack-frame-info.cc
@@ -5,85 +5,144 @@
#include "src/objects/stack-frame-info.h"
#include "src/objects/stack-frame-info-inl.h"
+#include "src/strings/string-builder-inl.h"
namespace v8 {
namespace internal {
+// static
int StackTraceFrame::GetLineNumber(Handle<StackTraceFrame> frame) {
int line = GetFrameInfo(frame)->line_number();
return line != StackFrameBase::kNone ? line : Message::kNoLineNumberInfo;
}
+// static
+int StackTraceFrame::GetOneBasedLineNumber(Handle<StackTraceFrame> frame) {
+ // JavaScript line numbers are already 1-based. Wasm line numbers need
+ // to be adjusted.
+ int line = StackTraceFrame::GetLineNumber(frame);
+ if (StackTraceFrame::IsWasm(frame) && line >= 0) line++;
+ return line;
+}
+
+// static
int StackTraceFrame::GetColumnNumber(Handle<StackTraceFrame> frame) {
int column = GetFrameInfo(frame)->column_number();
return column != StackFrameBase::kNone ? column : Message::kNoColumnInfo;
}
+// static
+int StackTraceFrame::GetOneBasedColumnNumber(Handle<StackTraceFrame> frame) {
+ // JavaScript colun numbers are already 1-based. Wasm column numbers need
+ // to be adjusted.
+ int column = StackTraceFrame::GetColumnNumber(frame);
+ if (StackTraceFrame::IsWasm(frame) && column >= 0) column++;
+ return column;
+}
+
+// static
int StackTraceFrame::GetScriptId(Handle<StackTraceFrame> frame) {
int id = GetFrameInfo(frame)->script_id();
return id != StackFrameBase::kNone ? id : Message::kNoScriptIdInfo;
}
+// static
int StackTraceFrame::GetPromiseAllIndex(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->promise_all_index();
}
+// static
Handle<Object> StackTraceFrame::GetFileName(Handle<StackTraceFrame> frame) {
auto name = GetFrameInfo(frame)->script_name();
return handle(name, frame->GetIsolate());
}
+// static
Handle<Object> StackTraceFrame::GetScriptNameOrSourceUrl(
Handle<StackTraceFrame> frame) {
auto name = GetFrameInfo(frame)->script_name_or_source_url();
return handle(name, frame->GetIsolate());
}
+// static
Handle<Object> StackTraceFrame::GetFunctionName(Handle<StackTraceFrame> frame) {
auto name = GetFrameInfo(frame)->function_name();
return handle(name, frame->GetIsolate());
}
+// static
+Handle<Object> StackTraceFrame::GetMethodName(Handle<StackTraceFrame> frame) {
+ auto name = GetFrameInfo(frame)->method_name();
+ return handle(name, frame->GetIsolate());
+}
+
+// static
+Handle<Object> StackTraceFrame::GetTypeName(Handle<StackTraceFrame> frame) {
+ auto name = GetFrameInfo(frame)->type_name();
+ return handle(name, frame->GetIsolate());
+}
+
+// static
+Handle<Object> StackTraceFrame::GetEvalOrigin(Handle<StackTraceFrame> frame) {
+ auto origin = GetFrameInfo(frame)->eval_origin();
+ return handle(origin, frame->GetIsolate());
+}
+
+// static
Handle<Object> StackTraceFrame::GetWasmModuleName(
Handle<StackTraceFrame> frame) {
auto module = GetFrameInfo(frame)->wasm_module_name();
return handle(module, frame->GetIsolate());
}
+// static
bool StackTraceFrame::IsEval(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_eval();
}
+// static
bool StackTraceFrame::IsConstructor(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_constructor();
}
+// static
bool StackTraceFrame::IsWasm(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_wasm();
}
+// static
+bool StackTraceFrame::IsAsmJsWasm(Handle<StackTraceFrame> frame) {
+ return GetFrameInfo(frame)->is_asmjs_wasm();
+}
+
+// static
bool StackTraceFrame::IsUserJavaScript(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_user_java_script();
}
+// static
bool StackTraceFrame::IsToplevel(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_toplevel();
}
+// static
bool StackTraceFrame::IsAsync(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_async();
}
+// static
bool StackTraceFrame::IsPromiseAll(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_promise_all();
}
+// static
Handle<StackFrameInfo> StackTraceFrame::GetFrameInfo(
Handle<StackTraceFrame> frame) {
if (frame->frame_info().IsUndefined()) InitializeFrameInfo(frame);
return handle(StackFrameInfo::cast(frame->frame_info()), frame->GetIsolate());
}
+// static
void StackTraceFrame::InitializeFrameInfo(Handle<StackTraceFrame> frame) {
Isolate* isolate = frame->GetIsolate();
Handle<StackFrameInfo> frame_info = isolate->factory()->NewStackFrameInfo(
@@ -97,5 +156,259 @@ void StackTraceFrame::InitializeFrameInfo(Handle<StackTraceFrame> frame) {
frame->set_frame_index(-1);
}
+Handle<FrameArray> GetFrameArrayFromStackTrace(Isolate* isolate,
+ Handle<FixedArray> stack_trace) {
+ // For the empty case, a empty FrameArray needs to be allocated so the rest
+ // of the code doesn't has to be special cased everywhere.
+ if (stack_trace->length() == 0) {
+ return isolate->factory()->NewFrameArray(0);
+ }
+
+ // Retrieve the FrameArray from the first StackTraceFrame.
+ DCHECK_GT(stack_trace->length(), 0);
+ Handle<StackTraceFrame> frame(StackTraceFrame::cast(stack_trace->get(0)),
+ isolate);
+ return handle(FrameArray::cast(frame->frame_array()), isolate);
+}
+
+namespace {
+
+bool IsNonEmptyString(Handle<Object> object) {
+ return (object->IsString() && String::cast(*object).length() > 0);
+}
+
+void AppendFileLocation(Isolate* isolate, Handle<StackTraceFrame> frame,
+ IncrementalStringBuilder* builder) {
+ Handle<Object> file_name = StackTraceFrame::GetScriptNameOrSourceUrl(frame);
+ if (!file_name->IsString() && StackTraceFrame::IsEval(frame)) {
+ Handle<Object> eval_origin = StackTraceFrame::GetEvalOrigin(frame);
+ DCHECK(eval_origin->IsString());
+ builder->AppendString(Handle<String>::cast(eval_origin));
+ builder->AppendCString(", "); // Expecting source position to follow.
+ }
+
+ if (IsNonEmptyString(file_name)) {
+ builder->AppendString(Handle<String>::cast(file_name));
+ } else {
+ // Source code does not originate from a file and is not native, but we
+ // can still get the source position inside the source string, e.g. in
+ // an eval string.
+ builder->AppendCString("<anonymous>");
+ }
+
+ int line_number = StackTraceFrame::GetLineNumber(frame);
+ if (line_number != Message::kNoLineNumberInfo) {
+ builder->AppendCharacter(':');
+ builder->AppendInt(line_number);
+
+ int column_number = StackTraceFrame::GetColumnNumber(frame);
+ if (column_number != Message::kNoColumnInfo) {
+ builder->AppendCharacter(':');
+ builder->AppendInt(column_number);
+ }
+ }
+}
+
+int StringIndexOf(Isolate* isolate, Handle<String> subject,
+ Handle<String> pattern) {
+ if (pattern->length() > subject->length()) return -1;
+ return String::IndexOf(isolate, subject, pattern, 0);
+}
+
+// Returns true iff
+// 1. the subject ends with '.' + pattern, or
+// 2. subject == pattern.
+bool StringEndsWithMethodName(Isolate* isolate, Handle<String> subject,
+ Handle<String> pattern) {
+ if (String::Equals(isolate, subject, pattern)) return true;
+
+ FlatStringReader subject_reader(isolate, String::Flatten(isolate, subject));
+ FlatStringReader pattern_reader(isolate, String::Flatten(isolate, pattern));
+
+ int pattern_index = pattern_reader.length() - 1;
+ int subject_index = subject_reader.length() - 1;
+ for (int i = 0; i <= pattern_reader.length(); i++) { // Iterate over len + 1.
+ if (subject_index < 0) {
+ return false;
+ }
+
+ const uc32 subject_char = subject_reader.Get(subject_index);
+ if (i == pattern_reader.length()) {
+ if (subject_char != '.') return false;
+ } else if (subject_char != pattern_reader.Get(pattern_index)) {
+ return false;
+ }
+
+ pattern_index--;
+ subject_index--;
+ }
+
+ return true;
+}
+
+void AppendMethodCall(Isolate* isolate, Handle<StackTraceFrame> frame,
+ IncrementalStringBuilder* builder) {
+ Handle<Object> type_name = StackTraceFrame::GetTypeName(frame);
+ Handle<Object> method_name = StackTraceFrame::GetMethodName(frame);
+ Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame);
+
+ if (IsNonEmptyString(function_name)) {
+ Handle<String> function_string = Handle<String>::cast(function_name);
+ if (IsNonEmptyString(type_name)) {
+ Handle<String> type_string = Handle<String>::cast(type_name);
+ bool starts_with_type_name =
+ (StringIndexOf(isolate, function_string, type_string) == 0);
+ if (!starts_with_type_name) {
+ builder->AppendString(type_string);
+ builder->AppendCharacter('.');
+ }
+ }
+ builder->AppendString(function_string);
+
+ if (IsNonEmptyString(method_name)) {
+ Handle<String> method_string = Handle<String>::cast(method_name);
+ if (!StringEndsWithMethodName(isolate, function_string, method_string)) {
+ builder->AppendCString(" [as ");
+ builder->AppendString(method_string);
+ builder->AppendCharacter(']');
+ }
+ }
+ } else {
+ if (IsNonEmptyString(type_name)) {
+ builder->AppendString(Handle<String>::cast(type_name));
+ builder->AppendCharacter('.');
+ }
+ if (IsNonEmptyString(method_name)) {
+ builder->AppendString(Handle<String>::cast(method_name));
+ } else {
+ builder->AppendCString("<anonymous>");
+ }
+ }
+}
+
+void SerializeJSStackFrame(
+ Isolate* isolate, Handle<StackTraceFrame> frame,
+ IncrementalStringBuilder& builder // NOLINT(runtime/references)
+) {
+ Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame);
+
+ const bool is_toplevel = StackTraceFrame::IsToplevel(frame);
+ const bool is_async = StackTraceFrame::IsAsync(frame);
+ const bool is_promise_all = StackTraceFrame::IsPromiseAll(frame);
+ const bool is_constructor = StackTraceFrame::IsConstructor(frame);
+ // Note: Keep the {is_method_call} predicate in sync with the corresponding
+ // predicate in factory.cc where the StackFrameInfo is created.
+ // Otherwise necessary fields for serialzing this frame might be
+ // missing.
+ const bool is_method_call = !(is_toplevel || is_constructor);
+
+ if (is_async) {
+ builder.AppendCString("async ");
+ }
+ if (is_promise_all) {
+ builder.AppendCString("Promise.all (index ");
+ builder.AppendInt(StackTraceFrame::GetPromiseAllIndex(frame));
+ builder.AppendCString(")");
+ return;
+ }
+ if (is_method_call) {
+ AppendMethodCall(isolate, frame, &builder);
+ } else if (is_constructor) {
+ builder.AppendCString("new ");
+ if (IsNonEmptyString(function_name)) {
+ builder.AppendString(Handle<String>::cast(function_name));
+ } else {
+ builder.AppendCString("<anonymous>");
+ }
+ } else if (IsNonEmptyString(function_name)) {
+ builder.AppendString(Handle<String>::cast(function_name));
+ } else {
+ AppendFileLocation(isolate, frame, &builder);
+ return;
+ }
+
+ builder.AppendCString(" (");
+ AppendFileLocation(isolate, frame, &builder);
+ builder.AppendCString(")");
+}
+
+void SerializeAsmJsWasmStackFrame(
+ Isolate* isolate, Handle<StackTraceFrame> frame,
+ IncrementalStringBuilder& builder // NOLINT(runtime/references)
+) {
+ // The string should look exactly as the respective javascript frame string.
+ // Keep this method in line to
+ // JSStackFrame::ToString(IncrementalStringBuilder&).
+ Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame);
+
+ if (IsNonEmptyString(function_name)) {
+ builder.AppendString(Handle<String>::cast(function_name));
+ builder.AppendCString(" (");
+ }
+
+ AppendFileLocation(isolate, frame, &builder);
+
+ if (IsNonEmptyString(function_name)) builder.AppendCString(")");
+
+ return;
+}
+
+void SerializeWasmStackFrame(
+ Isolate* isolate, Handle<StackTraceFrame> frame,
+ IncrementalStringBuilder& builder // NOLINT(runtime/references)
+) {
+ Handle<Object> module_name = StackTraceFrame::GetWasmModuleName(frame);
+ Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame);
+ const bool has_name = !module_name->IsNull() || !function_name->IsNull();
+ if (has_name) {
+ if (module_name->IsNull()) {
+ builder.AppendString(Handle<String>::cast(function_name));
+ } else {
+ builder.AppendString(Handle<String>::cast(module_name));
+ if (!function_name->IsNull()) {
+ builder.AppendCString(".");
+ builder.AppendString(Handle<String>::cast(function_name));
+ }
+ }
+ builder.AppendCString(" (");
+ }
+
+ const int wasm_func_index = StackTraceFrame::GetLineNumber(frame);
+
+ builder.AppendCString("wasm-function[");
+ builder.AppendInt(wasm_func_index);
+ builder.AppendCString("]:");
+
+ char buffer[16];
+ SNPrintF(ArrayVector(buffer), "0x%x",
+ StackTraceFrame::GetColumnNumber(frame));
+ builder.AppendCString(buffer);
+
+ if (has_name) builder.AppendCString(")");
+}
+
+} // namespace
+
+void SerializeStackTraceFrame(
+ Isolate* isolate, Handle<StackTraceFrame> frame,
+ IncrementalStringBuilder& builder // NOLINT(runtime/references)
+) {
+ // Ordering here is important, as AsmJs frames are also marked as Wasm.
+ if (StackTraceFrame::IsAsmJsWasm(frame)) {
+ SerializeAsmJsWasmStackFrame(isolate, frame, builder);
+ } else if (StackTraceFrame::IsWasm(frame)) {
+ SerializeWasmStackFrame(isolate, frame, builder);
+ } else {
+ SerializeJSStackFrame(isolate, frame, builder);
+ }
+}
+
+MaybeHandle<String> SerializeStackTraceFrame(Isolate* isolate,
+ Handle<StackTraceFrame> frame) {
+ IncrementalStringBuilder builder(isolate);
+ SerializeStackTraceFrame(isolate, frame, builder);
+ return builder.Finish();
+}
+
} // namespace internal
} // namespace v8