Commit 6c53efc7 authored by jgruber's avatar jgruber Committed by Commit bot

Move FormatStackTrace to C++

BUG=

Review-Url: https://codereview.chromium.org/2191293002
Cr-Commit-Position: refs/heads/master@{#38212}
parent ea45a210
......@@ -2650,6 +2650,8 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
callsite_fun->shared()->DontAdaptArguments();
callsite_fun->shared()->set_native(true);
isolate->native_context()->set_callsite_function(*callsite_fun);
{
Handle<JSObject> proto =
factory->NewJSObject(isolate->object_function(), TENURED);
......
......@@ -22,65 +22,21 @@ namespace internal {
isolate->factory()->NewStringFromAsciiChecked(method))); \
}
#define SET_CALLSITE_PROPERTY(target, key, value) \
RETURN_FAILURE_ON_EXCEPTION( \
isolate, JSObject::SetOwnPropertyIgnoreAttributes( \
target, isolate->factory()->key(), value, DONT_ENUM))
BUILTIN(CallSiteConstructor) {
HandleScope scope(isolate);
Handle<JSFunction> target = args.target<JSFunction>();
Handle<HeapObject> new_target_obj = args.new_target();
Handle<Object> new_target = Handle<Object>::cast(args.new_target());
Handle<Object> receiver = args.atOrUndefined(isolate, 1);
Handle<Object> fun = args.atOrUndefined(isolate, 2);
Handle<Object> pos = args.atOrUndefined(isolate, 3);
Handle<Object> strict_mode = args.atOrUndefined(isolate, 4);
// Create the JS object.
Handle<JSReceiver> new_target = new_target_obj->IsJSReceiver()
? Handle<JSReceiver>::cast(new_target_obj)
: Handle<JSReceiver>::cast(target);
Handle<JSObject> obj;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
JSObject::New(target, new_target));
// For wasm frames, receiver is the wasm object and fun is the function index
// instead of an actual function.
const bool is_wasm_object =
receiver->IsJSObject() && wasm::IsWasmObject(JSObject::cast(*receiver));
if (!fun->IsJSFunction() && !is_wasm_object) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCallSiteExpectsFunction,
Object::TypeOf(isolate, receiver),
Object::TypeOf(isolate, fun)));
}
if (is_wasm_object) {
DCHECK(fun->IsSmi());
DCHECK(wasm::GetNumberOfFunctions(JSObject::cast(*receiver)) >
Smi::cast(*fun)->value());
SET_CALLSITE_PROPERTY(obj, call_site_wasm_obj_symbol, receiver);
SET_CALLSITE_PROPERTY(obj, call_site_wasm_func_index_symbol, fun);
} else {
DCHECK(fun->IsJSFunction());
SET_CALLSITE_PROPERTY(obj, call_site_receiver_symbol, receiver);
SET_CALLSITE_PROPERTY(obj, call_site_function_symbol, fun);
}
DCHECK(pos->IsSmi());
SET_CALLSITE_PROPERTY(obj, call_site_position_symbol, pos);
SET_CALLSITE_PROPERTY(
obj, call_site_strict_symbol,
isolate->factory()->ToBoolean(strict_mode->BooleanValue()));
return *obj;
RETURN_RESULT_OR_FAILURE(
isolate, CallSiteUtils::Construct(isolate, target, new_target, receiver,
fun, pos, strict_mode));
}
#undef SET_CALLSITE_PROPERTY
namespace {
Object* PositiveNumberOrNull(int value, Isolate* isolate) {
......@@ -99,136 +55,13 @@ BUILTIN(CallSitePrototypeGetColumnNumber) {
return PositiveNumberOrNull(call_site.GetColumnNumber(), isolate);
}
namespace {
Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return *isolate->factory()->undefined_value();
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
// Find the name of the function calling eval.
if (shared->name()->BooleanValue()) {
return shared->name();
}
return shared->inferred_name();
}
Object* EvalFromScript(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return *isolate->factory()->undefined_value();
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
return eval_from_shared->script()->IsScript()
? eval_from_shared->script()
: *isolate->factory()->undefined_value();
}
MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
Handle<Object> sourceURL = Script::GetNameOrSourceURL(script);
if (!sourceURL->IsUndefined(isolate)) {
DCHECK(sourceURL->IsString());
return Handle<String>::cast(sourceURL);
}
IncrementalStringBuilder builder(isolate);
builder.AppendCString("eval at ");
Handle<Object> eval_from_function_name =
handle(EvalFromFunctionName(isolate, script), isolate);
if (eval_from_function_name->BooleanValue()) {
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, Object::ToString(isolate, eval_from_function_name),
String);
builder.AppendString(str);
} else {
builder.AppendCString("<anonymous>");
}
Handle<Object> eval_from_script_obj =
handle(EvalFromScript(isolate, script), isolate);
if (eval_from_script_obj->IsScript()) {
Handle<Script> eval_from_script =
Handle<Script>::cast(eval_from_script_obj);
builder.AppendCString(" (");
if (eval_from_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
// Eval script originated from another eval.
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, FormatEvalOrigin(isolate, eval_from_script), String);
builder.AppendString(str);
} else {
DCHECK(eval_from_script->compilation_type() !=
Script::COMPILATION_TYPE_EVAL);
// eval script originated from "real" source.
Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
if (eval_from_script->name()->IsString()) {
builder.AppendString(Handle<String>::cast(name_obj));
Script::PositionInfo info;
if (eval_from_script->GetPositionInfo(script->GetEvalPosition(), &info,
Script::NO_OFFSET)) {
builder.AppendCString(":");
Handle<String> str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.line + 1), isolate));
builder.AppendString(str);
builder.AppendCString(":");
str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.column + 1), isolate));
builder.AppendString(str);
}
} else {
DCHECK(!eval_from_script->name()->IsString());
builder.AppendCString("unknown source");
}
}
builder.AppendCString(")");
}
Handle<String> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
return result;
}
MaybeHandle<Object> GetEvalOrigin(Isolate* isolate, Handle<JSObject> object) {
CallSite call_site(isolate, object);
if (call_site.IsWasm()) return isolate->factory()->undefined_value();
// Retrieve the function's script object.
Handle<Object> function_obj;
Handle<Symbol> symbol = isolate->factory()->call_site_function_symbol();
ASSIGN_RETURN_ON_EXCEPTION(isolate, function_obj,
JSObject::GetProperty(object, symbol), Object);
DCHECK(function_obj->IsJSFunction());
Handle<JSFunction> function = Handle<JSFunction>::cast(function_obj);
Handle<Object> script = handle(function->shared()->script(), isolate);
if (!script->IsScript()) {
return isolate->factory()->undefined_value();
}
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, FormatEvalOrigin(isolate, Handle<Script>::cast(script)),
String);
return str;
}
} // namespace
BUILTIN(CallSitePrototypeGetEvalOrigin) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getEvalOrigin");
RETURN_RESULT_OR_FAILURE(isolate, GetEvalOrigin(isolate, recv));
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetEvalOrigin();
}
BUILTIN(CallSitePrototypeGetFileName) {
......@@ -328,32 +161,13 @@ BUILTIN(CallSitePrototypeGetThis) {
return *receiver;
}
namespace {
MaybeHandle<Object> GetTypeName(Isolate* isolate, Handle<JSObject> object) {
Handle<Object> receiver;
Handle<Symbol> symbol = isolate->factory()->call_site_receiver_symbol();
ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
JSObject::GetProperty(object, symbol), Object);
// TODO(jgruber): Check for strict/constructor here as above.
if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate))
return isolate->factory()->null_value();
if (receiver->IsJSProxy()) return isolate->factory()->Proxy_string();
Handle<JSReceiver> receiver_object =
Object::ToObject(isolate, receiver).ToHandleChecked();
return JSReceiver::GetConstructorName(receiver_object);
}
} // namespace
BUILTIN(CallSitePrototypeGetTypeName) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getTypeName");
RETURN_RESULT_OR_FAILURE(isolate, GetTypeName(isolate, recv));
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetTypeName();
}
BUILTIN(CallSitePrototypeIsConstructor) {
......@@ -392,217 +206,10 @@ BUILTIN(CallSitePrototypeIsToplevel) {
return isolate->heap()->ToBoolean(call_site.IsToplevel());
}
namespace {
bool IsNonEmptyString(Handle<Object> object) {
return (object->IsString() && String::cast(*object)->length() > 0);
}
MaybeHandle<JSObject> AppendWasmToString(Isolate* isolate,
Handle<JSObject> recv,
CallSite* call_site,
IncrementalStringBuilder* builder) {
Handle<Object> name = call_site->GetFunctionName();
if (name->IsNull(isolate)) {
builder->AppendCString("<WASM UNNAMED>");
} else {
DCHECK(name->IsString());
builder->AppendString(Handle<String>::cast(name));
}
builder->AppendCString(" (<WASM>[");
Handle<String> ix = isolate->factory()->NumberToString(
handle(Smi::FromInt(call_site->wasm_func_index()), isolate));
builder->AppendString(ix);
builder->AppendCString("]+");
Handle<Object> pos;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, pos, JSObject::GetProperty(
recv, isolate->factory()->call_site_position_symbol()),
JSObject);
DCHECK(pos->IsNumber());
builder->AppendString(isolate->factory()->NumberToString(pos));
builder->AppendCString(")");
return recv;
}
MaybeHandle<JSObject> AppendFileLocation(Isolate* isolate,
Handle<JSObject> recv,
CallSite* call_site,
IncrementalStringBuilder* builder) {
if (call_site->IsNative()) {
builder->AppendCString("native");
return recv;
}
Handle<Object> file_name = call_site->GetScriptNameOrSourceUrl();
if (!file_name->IsString() && call_site->IsEval()) {
Handle<Object> eval_origin;
ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_origin,
GetEvalOrigin(isolate, recv), JSObject);
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 = call_site->GetLineNumber();
if (line_number != -1) {
builder->AppendCharacter(':');
Handle<String> line_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(line_number), isolate), isolate);
builder->AppendString(line_string);
int column_number = call_site->GetColumnNumber();
if (column_number != -1) {
builder->AppendCharacter(':');
Handle<String> column_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(column_number), isolate), isolate);
builder->AppendString(column_string);
}
}
return recv;
}
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(subject, pattern)) return true;
FlatStringReader subject_reader(isolate, String::Flatten(subject));
FlatStringReader pattern_reader(isolate, String::Flatten(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;
}
MaybeHandle<JSObject> AppendMethodCall(Isolate* isolate, Handle<JSObject> recv,
CallSite* call_site,
IncrementalStringBuilder* builder) {
Handle<Object> type_name;
ASSIGN_RETURN_ON_EXCEPTION(isolate, type_name, GetTypeName(isolate, recv),
JSObject);
Handle<Object> method_name = call_site->GetMethodName();
Handle<Object> function_name = call_site->GetFunctionName();
if (IsNonEmptyString(function_name)) {
Handle<String> function_string = Handle<String>::cast(function_name);
if (type_name->IsString()) {
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 {
builder->AppendString(Handle<String>::cast(type_name));
builder->AppendCharacter('.');
if (IsNonEmptyString(method_name)) {
builder->AppendString(Handle<String>::cast(method_name));
} else {
builder->AppendCString("<anonymous>");
}
}
return recv;
}
} // namespace
BUILTIN(CallSitePrototypeToString) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "toString");
IncrementalStringBuilder builder(isolate);
CallSite call_site(isolate, recv);
if (call_site.IsWasm()) {
RETURN_FAILURE_ON_EXCEPTION(
isolate, AppendWasmToString(isolate, recv, &call_site, &builder));
RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
}
DCHECK(!call_site.IsWasm());
Handle<Object> function_name = call_site.GetFunctionName();
const bool is_toplevel = call_site.IsToplevel();
const bool is_constructor = call_site.IsConstructor();
const bool is_method_call = !(is_toplevel || is_constructor);
if (is_method_call) {
RETURN_FAILURE_ON_EXCEPTION(
isolate, AppendMethodCall(isolate, recv, &call_site, &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 {
RETURN_FAILURE_ON_EXCEPTION(
isolate, AppendFileLocation(isolate, recv, &call_site, &builder));
RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
}
builder.AppendCString(" (");
RETURN_FAILURE_ON_EXCEPTION(
isolate, AppendFileLocation(isolate, recv, &call_site, &builder));
builder.AppendCString(")");
RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
RETURN_RESULT_OR_FAILURE(isolate, CallSiteUtils::ToString(isolate, recv));
}
#undef CHECK_CALLSITE
......
......@@ -5,7 +5,6 @@
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
#include "src/bootstrapper.h"
#include "src/messages.h"
#include "src/property-descriptor.h"
#include "src/string-builder.h"
......@@ -18,9 +17,9 @@ BUILTIN(ErrorConstructor) {
HandleScope scope(isolate);
RETURN_RESULT_OR_FAILURE(
isolate,
ConstructError(isolate, args.target<JSFunction>(),
Handle<Object>::cast(args.new_target()),
args.atOrUndefined(isolate, 1), SKIP_FIRST, false));
ErrorUtils::Construct(isolate, args.target<JSFunction>(),
Handle<Object>::cast(args.new_target()),
args.atOrUndefined(isolate, 1), SKIP_FIRST, false));
}
// static
......@@ -63,69 +62,11 @@ BUILTIN(ErrorCaptureStackTrace) {
return isolate->heap()->undefined_value();
}
namespace {
MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
Handle<JSReceiver> recv,
Handle<String> key,
Handle<String> default_str) {
Handle<Object> obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, JSObject::GetProperty(recv, key),
String);
Handle<String> str;
if (obj->IsUndefined(isolate)) {
str = default_str;
} else {
ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
String);
}
return str;
}
} // namespace
// ES6 section 19.5.3.4 Error.prototype.toString ( )
BUILTIN(ErrorPrototypeToString) {
HandleScope scope(isolate);
// 1. Let O be the this value.
// 2. If Type(O) is not Object, throw a TypeError exception.
CHECK_RECEIVER(JSReceiver, receiver, "Error.prototype.toString");
// 3. Let name be ? Get(O, "name").
// 4. If name is undefined, let name be "Error"; otherwise let name be
// ? ToString(name).
Handle<String> name_key = isolate->factory()->name_string();
Handle<String> name_default = isolate->factory()->Error_string();
Handle<String> name;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, name,
GetStringPropertyOrDefault(isolate, receiver, name_key, name_default));
// 5. Let msg be ? Get(O, "message").
// 6. If msg is undefined, let msg be the empty String; otherwise let msg be
// ? ToString(msg).
Handle<String> msg_key = isolate->factory()->message_string();
Handle<String> msg_default = isolate->factory()->empty_string();
Handle<String> msg;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, msg,
GetStringPropertyOrDefault(isolate, receiver, msg_key, msg_default));
// 7. If name is the empty String, return msg.
// 8. If msg is the empty String, return name.
if (name->length() == 0) return *msg;
if (msg->length() == 0) return *name;
// 9. Return the result of concatenating name, the code unit 0x003A (COLON),
// the code unit 0x0020 (SPACE), and msg.
IncrementalStringBuilder builder(isolate);
builder.AppendString(name);
builder.AppendCString(": ");
builder.AppendString(msg);
RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
RETURN_RESULT_OR_FAILURE(isolate,
ErrorUtils::ToString(isolate, args.receiver()));
}
} // namespace internal
......
......@@ -101,7 +101,6 @@ enum BindingFlags {
V(ASYNC_FUNCTION_AWAIT_INDEX, JSFunction, async_function_await) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(ERROR_FORMAT_STACK_TRACE_INDEX, JSFunction, error_format_stack_trace) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
......@@ -159,6 +158,7 @@ enum BindingFlags {
V(CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, JSFunction, \
call_as_constructor_delegate) \
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
V(CALLSITE_FUNCTION_INDEX, JSFunction, callsite_function) \
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(DATA_PROPERTY_DESCRIPTOR_MAP_INDEX, Map, data_property_descriptor_map) \
V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \
......
......@@ -432,6 +432,17 @@ class StackTraceHelper {
bool encountered_strict_function_;
};
namespace {
// TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the
// receiver in RegExp constructor frames.
Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) {
return (in->IsTheHole(isolate))
? Handle<Object>::cast(isolate->factory()->undefined_value())
: in;
}
}
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
FrameSkipMode mode,
Handle<Object> caller) {
......@@ -491,7 +502,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
elements = MaybeGrow(this, elements, cursor, cursor + 4);
elements->set(cursor++, *recv);
elements->set(cursor++, *TheHoleToUndefined(this, recv));
elements->set(cursor++, *fun);
elements->set(cursor++, *abstract_code);
elements->set(cursor++, *offset);
......@@ -966,7 +977,8 @@ Object* Isolate::StackOverflow() {
MessageTemplate::TemplateString(MessageTemplate::kStackOverflow));
Handle<Object> exception;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
this, exception, ConstructError(this, fun, fun, msg, SKIP_NONE, true));
this, exception,
ErrorUtils::Construct(this, fun, fun, msg, SKIP_NONE, true));
Throw(*exception, nullptr);
......
......@@ -126,6 +126,16 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
#define RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, T) \
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, MaybeHandle<T>())
#define RETURN_RESULT(isolate, call, T) \
do { \
Handle<T> __result__; \
if (!(call).ToHandle(&__result__)) { \
DCHECK((isolate)->has_pending_exception()); \
return MaybeHandle<T>(); \
} \
return __result__; \
} while (false)
#define RETURN_RESULT_OR_FAILURE(isolate, call) \
do { \
Handle<Object> __result__; \
......@@ -424,6 +434,8 @@ typedef List<HeapObject*> DebugObjectCache;
V(int, bytecode_and_metadata_size, 0) \
/* true if being profiled. Causes collection of extra compile info. */ \
V(bool, is_profiling, false) \
/* true if a trace is being formatted through Error.prepareStackTrace. */ \
V(bool, formatting_stack_trace, false) \
ISOLATE_INIT_SIMULATOR_LIST(V)
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
......
......@@ -256,90 +256,6 @@ function GetStackTraceLine(recv, fun, pos, isGlobal) {
// ----------------------------------------------------------------------------
// Error implementation
function FormatErrorString(error) {
try {
return %_Call(ErrorToString, error);
} catch (e) {
try {
return "<error: " + e + ">";
} catch (ee) {
return "<error>";
}
}
}
function GetStackFrames(raw_stack) {
var internal_raw_stack = new InternalArray();
%MoveArrayContents(raw_stack, internal_raw_stack);
var frames = new InternalArray();
var sloppy_frames = internal_raw_stack[0];
for (var i = 1; i < internal_raw_stack.length; i += 4) {
var recv = internal_raw_stack[i];
var fun = internal_raw_stack[i + 1];
var code = internal_raw_stack[i + 2];
var pc = internal_raw_stack[i + 3];
// For traps in wasm, the bytecode offset is passed as (-1 - offset).
// Otherwise, lookup the position from the pc.
var pos = IS_NUMBER(fun) && pc < 0 ? (-1 - pc) :
%FunctionGetPositionForOffset(code, pc);
sloppy_frames--;
frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
}
return frames;
}
// Flag to prevent recursive call of Error.prepareStackTrace.
var formatting_custom_stack_trace = false;
function FormatStackTrace(obj, raw_stack) {
var frames = GetStackFrames(raw_stack);
if (IS_FUNCTION(GlobalError.prepareStackTrace) &&
!formatting_custom_stack_trace) {
var array = [];
%MoveArrayContents(frames, array);
formatting_custom_stack_trace = true;
var stack_trace = UNDEFINED;
try {
stack_trace = GlobalError.prepareStackTrace(obj, array);
} catch (e) {
throw e; // The custom formatting function threw. Rethrow.
} finally {
formatting_custom_stack_trace = false;
}
return stack_trace;
}
var lines = new InternalArray();
lines.push(FormatErrorString(obj));
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
var line;
try {
line = frame.toString();
} catch (e) {
try {
line = "<error: " + e + ">";
} catch (ee) {
// Any code that reaches this point is seriously nasty!
line = "<error>";
}
}
lines.push(" at " + line);
}
return %_Call(ArrayJoin, lines, "\n");
}
function GetTypeName(receiver, requireConstructor) {
if (IS_NULL_OR_UNDEFINED(receiver)) return null;
if (IS_PROXY(receiver)) return "Proxy";
return %GetConstructorName(receiver);
}
function ErrorToString() {
if (!IS_RECEIVER(this)) {
throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
......@@ -377,7 +293,6 @@ function MakeURIError() {
}
%InstallToContext([
"error_format_stack_trace", FormatStackTrace,
"get_stack_trace_line_fun", GetStackTraceLine,
"make_error_function", MakeGenericError,
"make_range_error", MakeRangeError,
......
......@@ -7,7 +7,6 @@
#include <memory>
#include "src/api.h"
#include "src/bootstrapper.h"
#include "src/execution.h"
#include "src/isolate-inl.h"
#include "src/keys.h"
......@@ -304,6 +303,129 @@ Handle<Object> CallSite::GetMethodName() {
return isolate_->factory()->null_value();
}
Handle<Object> CallSite::GetTypeName() {
// TODO(jgruber): Check for strict/constructor here as in
// CallSitePrototypeGetThis.
if (receiver_->IsNull(isolate_) || receiver_->IsUndefined(isolate_))
return isolate_->factory()->null_value();
if (receiver_->IsJSProxy()) return isolate_->factory()->Proxy_string();
Handle<JSReceiver> receiver_object =
Object::ToObject(isolate_, receiver_).ToHandleChecked();
return JSReceiver::GetConstructorName(receiver_object);
}
namespace {
Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return *isolate->factory()->undefined_value();
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
// Find the name of the function calling eval.
if (shared->name()->BooleanValue()) {
return shared->name();
}
return shared->inferred_name();
}
Object* EvalFromScript(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return *isolate->factory()->undefined_value();
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
return eval_from_shared->script()->IsScript()
? eval_from_shared->script()
: *isolate->factory()->undefined_value();
}
MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
Handle<Object> sourceURL = Script::GetNameOrSourceURL(script);
if (!sourceURL->IsUndefined(isolate)) {
DCHECK(sourceURL->IsString());
return Handle<String>::cast(sourceURL);
}
IncrementalStringBuilder builder(isolate);
builder.AppendCString("eval at ");
Handle<Object> eval_from_function_name =
handle(EvalFromFunctionName(isolate, script), isolate);
if (eval_from_function_name->BooleanValue()) {
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, Object::ToString(isolate, eval_from_function_name),
String);
builder.AppendString(str);
} else {
builder.AppendCString("<anonymous>");
}
Handle<Object> eval_from_script_obj =
handle(EvalFromScript(isolate, script), isolate);
if (eval_from_script_obj->IsScript()) {
Handle<Script> eval_from_script =
Handle<Script>::cast(eval_from_script_obj);
builder.AppendCString(" (");
if (eval_from_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
// Eval script originated from another eval.
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, FormatEvalOrigin(isolate, eval_from_script), String);
builder.AppendString(str);
} else {
DCHECK(eval_from_script->compilation_type() !=
Script::COMPILATION_TYPE_EVAL);
// eval script originated from "real" source.
Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
if (eval_from_script->name()->IsString()) {
builder.AppendString(Handle<String>::cast(name_obj));
Script::PositionInfo info;
if (eval_from_script->GetPositionInfo(script->GetEvalPosition(), &info,
Script::NO_OFFSET)) {
builder.AppendCString(":");
Handle<String> str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.line + 1), isolate));
builder.AppendString(str);
builder.AppendCString(":");
str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.column + 1), isolate));
builder.AppendString(str);
}
} else {
DCHECK(!eval_from_script->name()->IsString());
builder.AppendCString("unknown source");
}
}
builder.AppendCString(")");
}
Handle<String> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
return result;
}
} // namespace
Handle<Object> CallSite::GetEvalOrigin() {
if (IsWasm()) return isolate_->factory()->undefined_value();
DCHECK(IsJavaScript());
Handle<Object> script = handle(fun_->shared()->script(), isolate_);
if (!script->IsScript()) return isolate_->factory()->undefined_value();
return FormatEvalOrigin(isolate_, Handle<Script>::cast(script))
.ToHandleChecked();
}
int CallSite::GetLineNumber() {
if (pos_ >= 0 && IsJavaScript()) {
......@@ -365,22 +487,187 @@ bool CallSite::IsConstructor() {
return constructor.is_identical_to(fun_);
}
namespace {
// Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into
// a vector of JS CallSite objects.
MaybeHandle<FixedArray> GetStackFrames(Isolate* isolate,
Handle<Object> raw_stack) {
DCHECK(raw_stack->IsJSArray());
Handle<JSArray> raw_stack_array = Handle<JSArray>::cast(raw_stack);
DCHECK(raw_stack_array->elements()->IsFixedArray());
Handle<FixedArray> raw_stack_elements =
handle(FixedArray::cast(raw_stack_array->elements()), isolate);
const int raw_stack_len = raw_stack_elements->length();
DCHECK(raw_stack_len % 4 == 1); // Multiples of 4 plus sloppy frames count.
const int frame_count = (raw_stack_len - 1) / 4;
Handle<Object> sloppy_frames_obj =
FixedArray::get(*raw_stack_elements, 0, isolate);
int sloppy_frames = Handle<Smi>::cast(sloppy_frames_obj)->value();
Handle<JSFunction> callsite_ctor =
handle(isolate->native_context()->callsite_function(), isolate);
int dst_ix = 0;
Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count);
for (int i = 1; i < raw_stack_len; i += 4) {
Handle<Object> recv = FixedArray::get(*raw_stack_elements, i, isolate);
Handle<Object> fun = FixedArray::get(*raw_stack_elements, i + 1, isolate);
Handle<AbstractCode> code = Handle<AbstractCode>::cast(
FixedArray::get(*raw_stack_elements, i + 2, isolate));
Handle<Smi> pc =
Handle<Smi>::cast(FixedArray::get(*raw_stack_elements, i + 3, isolate));
Handle<Object> pos =
(fun->IsSmi() && pc->value() < 0)
? handle(Smi::FromInt(-1 - pc->value()), isolate)
: handle(Smi::FromInt(code->SourcePosition(pc->value())), isolate);
sloppy_frames--;
Handle<Object> strict = isolate->factory()->ToBoolean(sloppy_frames < 0);
Handle<Object> callsite;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, callsite,
CallSiteUtils::Construct(isolate, callsite_ctor, callsite_ctor, recv,
fun, pos, strict),
FixedArray);
frames->set(dst_ix++, *callsite);
}
DCHECK_EQ(frame_count, dst_ix);
return frames;
}
MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error,
IncrementalStringBuilder* builder) {
MaybeHandle<String> err_str =
ErrorUtils::ToString(isolate, Handle<Object>::cast(error));
if (err_str.is_null()) {
// Error.toString threw. Try to return a string representation of the thrown
// exception instead.
DCHECK(isolate->has_pending_exception());
Handle<Object> pending_exception =
handle(isolate->pending_exception(), isolate);
isolate->clear_pending_exception();
err_str = ErrorUtils::ToString(isolate, pending_exception);
if (err_str.is_null()) {
// Formatting the thrown exception threw again, give up.
DCHECK(isolate->has_pending_exception());
isolate->clear_pending_exception();
builder->AppendCString("<error>");
} else {
// Formatted thrown exception successfully, append it.
builder->AppendCString("<error: ");
builder->AppendString(err_str.ToHandleChecked());
builder->AppendCharacter('>');
}
} else {
builder->AppendString(err_str.ToHandleChecked());
}
return error;
}
class PrepareStackTraceScope {
public:
explicit PrepareStackTraceScope(Isolate* isolate) : isolate_(isolate) {
DCHECK(!isolate_->formatting_stack_trace());
isolate_->set_formatting_stack_trace(true);
}
~PrepareStackTraceScope() { isolate_->set_formatting_stack_trace(false); }
private:
Isolate* isolate_;
DISALLOW_COPY_AND_ASSIGN(PrepareStackTraceScope);
};
} // namespace
MaybeHandle<Object> FormatStackTrace(Isolate* isolate, Handle<JSObject> error,
Handle<Object> stack_trace) {
// TODO(jgruber): Port FormatStackTrace from JS.
Handle<JSFunction> fun = isolate->error_format_stack_trace();
Handle<Object> raw_stack) {
// Create JS CallSite objects from the raw stack frame array.
Handle<FixedArray> frames;
ASSIGN_RETURN_ON_EXCEPTION(isolate, frames,
GetStackFrames(isolate, raw_stack), Object);
int argc = 2;
ScopedVector<Handle<Object>> argv(argc);
argv[0] = error;
argv[1] = stack_trace;
// If there's a user-specified "prepareStackFrames" function, call it on the
// frames and use its result.
Handle<Object> formatted_stack_trace;
Handle<JSFunction> global_error = isolate->error_function();
Handle<Object> prepare_stack_trace;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, formatted_stack_trace,
Execution::Call(isolate, fun, error, argc, argv.start()), Object);
isolate, prepare_stack_trace,
JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"),
Object);
const bool in_recursion = isolate->formatting_stack_trace();
if (prepare_stack_trace->IsJSFunction() && !in_recursion) {
PrepareStackTraceScope scope(isolate);
Handle<JSArray> array = isolate->factory()->NewJSArrayWithElements(frames);
const int argc = 2;
ScopedVector<Handle<Object>> argv(argc);
argv[0] = error;
argv[1] = array;
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, Execution::Call(isolate, prepare_stack_trace,
global_error, argc, argv.start()),
Object);
return result;
}
IncrementalStringBuilder builder(isolate);
RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder),
Object);
for (int i = 0; i < frames->length(); i++) {
builder.AppendCString("\n at ");
Handle<Object> frame = FixedArray::get(*frames, i, isolate);
MaybeHandle<String> maybe_frame_string =
CallSiteUtils::ToString(isolate, frame);
if (maybe_frame_string.is_null()) {
// CallSite.toString threw. Try to return a string representation of the
// thrown exception instead.
return formatted_stack_trace;
DCHECK(isolate->has_pending_exception());
Handle<Object> pending_exception =
handle(isolate->pending_exception(), isolate);
isolate->clear_pending_exception();
maybe_frame_string = ErrorUtils::ToString(isolate, pending_exception);
if (maybe_frame_string.is_null()) {
// Formatting the thrown exception threw again, give up.
builder.AppendCString("<error>");
} else {
// Formatted thrown exception successfully, append it.
builder.AppendCString("<error: ");
builder.AppendString(maybe_frame_string.ToHandleChecked());
builder.AppendCString("<error>");
}
} else {
// CallSite.toString completed without throwing.
builder.AppendString(maybe_frame_string.ToHandleChecked());
}
}
RETURN_RESULT(isolate, builder.Finish(), Object);
}
Handle<String> MessageTemplate::FormatMessage(Isolate* isolate,
......@@ -464,10 +751,9 @@ MaybeHandle<String> MessageTemplate::FormatMessage(int template_index,
return builder.Finish();
}
MaybeHandle<Object> ConstructError(Isolate* isolate, Handle<JSFunction> target,
Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode,
bool suppress_detailed_trace) {
MaybeHandle<Object> ErrorUtils::Construct(
Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode, bool suppress_detailed_trace) {
// 1. If NewTarget is undefined, let newTarget be the active function object,
// else let newTarget be NewTarget.
......@@ -521,5 +807,365 @@ MaybeHandle<Object> ConstructError(Isolate* isolate, Handle<JSFunction> target,
return err;
}
namespace {
MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
Handle<JSReceiver> recv,
Handle<String> key,
Handle<String> default_str) {
Handle<Object> obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, JSObject::GetProperty(recv, key),
String);
Handle<String> str;
if (obj->IsUndefined(isolate)) {
str = default_str;
} else {
ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
String);
}
return str;
}
} // namespace
// ES6 section 19.5.3.4 Error.prototype.toString ( )
MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate,
Handle<Object> receiver) {
// 1. Let O be the this value.
// 2. If Type(O) is not Object, throw a TypeError exception.
if (!receiver->IsJSReceiver()) {
return isolate->Throw<String>(isolate->factory()->NewTypeError(
MessageTemplate::kIncompatibleMethodReceiver,
isolate->factory()->NewStringFromAsciiChecked(
"Error.prototype.toString"),
receiver));
}
Handle<JSReceiver> recv = Handle<JSReceiver>::cast(receiver);
// 3. Let name be ? Get(O, "name").
// 4. If name is undefined, let name be "Error"; otherwise let name be
// ? ToString(name).
Handle<String> name_key = isolate->factory()->name_string();
Handle<String> name_default = isolate->factory()->Error_string();
Handle<String> name;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, name,
GetStringPropertyOrDefault(isolate, recv, name_key, name_default),
String);
// 5. Let msg be ? Get(O, "message").
// 6. If msg is undefined, let msg be the empty String; otherwise let msg be
// ? ToString(msg).
Handle<String> msg_key = isolate->factory()->message_string();
Handle<String> msg_default = isolate->factory()->empty_string();
Handle<String> msg;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, msg,
GetStringPropertyOrDefault(isolate, recv, msg_key, msg_default), String);
// 7. If name is the empty String, return msg.
// 8. If msg is the empty String, return name.
if (name->length() == 0) return msg;
if (msg->length() == 0) return name;
// 9. Return the result of concatenating name, the code unit 0x003A (COLON),
// the code unit 0x0020 (SPACE), and msg.
IncrementalStringBuilder builder(isolate);
builder.AppendString(name);
builder.AppendCString(": ");
builder.AppendString(msg);
Handle<String> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
return result;
}
#define SET_CALLSITE_PROPERTY(target, key, value) \
RETURN_ON_EXCEPTION( \
isolate, JSObject::SetOwnPropertyIgnoreAttributes( \
target, isolate->factory()->key(), value, DONT_ENUM), \
Object)
MaybeHandle<Object> CallSiteUtils::Construct(
Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
Handle<Object> receiver, Handle<Object> fun, Handle<Object> pos,
Handle<Object> strict_mode) {
// Create the JS object.
Handle<JSReceiver> new_target_recv =
new_target->IsJSReceiver() ? Handle<JSReceiver>::cast(new_target)
: Handle<JSReceiver>::cast(target);
Handle<JSObject> obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj,
JSObject::New(target, new_target_recv), Object);
// For wasm frames, receiver is the wasm object and fun is the function index
// instead of an actual function.
const bool is_wasm_object =
receiver->IsJSObject() && wasm::IsWasmObject(JSObject::cast(*receiver));
if (!fun->IsJSFunction() && !is_wasm_object) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCallSiteExpectsFunction,
Object::TypeOf(isolate, receiver),
Object::TypeOf(isolate, fun)),
Object);
}
if (is_wasm_object) {
DCHECK(fun->IsSmi());
DCHECK(wasm::GetNumberOfFunctions(JSObject::cast(*receiver)) >
Smi::cast(*fun)->value());
SET_CALLSITE_PROPERTY(obj, call_site_wasm_obj_symbol, receiver);
SET_CALLSITE_PROPERTY(obj, call_site_wasm_func_index_symbol, fun);
} else {
DCHECK(fun->IsJSFunction());
SET_CALLSITE_PROPERTY(obj, call_site_receiver_symbol, receiver);
SET_CALLSITE_PROPERTY(obj, call_site_function_symbol, fun);
}
DCHECK(pos->IsSmi());
SET_CALLSITE_PROPERTY(obj, call_site_position_symbol, pos);
SET_CALLSITE_PROPERTY(
obj, call_site_strict_symbol,
isolate->factory()->ToBoolean(strict_mode->BooleanValue()));
return obj;
}
#undef SET_CALLSITE_PROPERTY
namespace {
bool IsNonEmptyString(Handle<Object> object) {
return (object->IsString() && String::cast(*object)->length() > 0);
}
MaybeHandle<JSObject> AppendWasmToString(Isolate* isolate,
Handle<JSObject> recv,
CallSite* call_site,
IncrementalStringBuilder* builder) {
Handle<Object> name = call_site->GetFunctionName();
if (name->IsNull(isolate)) {
builder->AppendCString("<WASM UNNAMED>");
} else {
DCHECK(name->IsString());
builder->AppendString(Handle<String>::cast(name));
}
builder->AppendCString(" (<WASM>[");
Handle<String> ix = isolate->factory()->NumberToString(
handle(Smi::FromInt(call_site->wasm_func_index()), isolate));
builder->AppendString(ix);
builder->AppendCString("]+");
Handle<Object> pos;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, pos, JSObject::GetProperty(
recv, isolate->factory()->call_site_position_symbol()),
JSObject);
DCHECK(pos->IsNumber());
builder->AppendString(isolate->factory()->NumberToString(pos));
builder->AppendCString(")");
return recv;
}
MaybeHandle<JSObject> AppendFileLocation(Isolate* isolate,
Handle<JSObject> recv,
CallSite* call_site,
IncrementalStringBuilder* builder) {
if (call_site->IsNative()) {
builder->AppendCString("native");
return recv;
}
Handle<Object> file_name = call_site->GetScriptNameOrSourceUrl();
if (!file_name->IsString() && call_site->IsEval()) {
Handle<Object> eval_origin = call_site->GetEvalOrigin();
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 = call_site->GetLineNumber();
if (line_number != -1) {
builder->AppendCharacter(':');
Handle<String> line_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(line_number), isolate), isolate);
builder->AppendString(line_string);
int column_number = call_site->GetColumnNumber();
if (column_number != -1) {
builder->AppendCharacter(':');
Handle<String> column_string = isolate->factory()->NumberToString(
handle(Smi::FromInt(column_number), isolate), isolate);
builder->AppendString(column_string);
}
}
return recv;
}
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(subject, pattern)) return true;
FlatStringReader subject_reader(isolate, String::Flatten(subject));
FlatStringReader pattern_reader(isolate, String::Flatten(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;
}
MaybeHandle<JSObject> AppendMethodCall(Isolate* isolate, Handle<JSObject> recv,
CallSite* call_site,
IncrementalStringBuilder* builder) {
Handle<Object> type_name = call_site->GetTypeName();
Handle<Object> method_name = call_site->GetMethodName();
Handle<Object> function_name = call_site->GetFunctionName();
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 {
builder->AppendString(Handle<String>::cast(type_name));
builder->AppendCharacter('.');
if (IsNonEmptyString(method_name)) {
builder->AppendString(Handle<String>::cast(method_name));
} else {
builder->AppendCString("<anonymous>");
}
}
return recv;
}
} // namespace
MaybeHandle<String> CallSiteUtils::ToString(Isolate* isolate,
Handle<Object> receiver) {
if (!receiver->IsJSObject()) {
THROW_NEW_ERROR(
isolate,
NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
isolate->factory()->NewStringFromAsciiChecked("toString"),
receiver),
String);
}
Handle<JSObject> recv = Handle<JSObject>::cast(receiver);
if (!JSReceiver::HasOwnProperty(
recv, isolate->factory()->call_site_position_symbol())
.FromMaybe(false)) {
THROW_NEW_ERROR(
isolate,
NewTypeError(MessageTemplate::kCallSiteMethod,
isolate->factory()->NewStringFromAsciiChecked("toString")),
String);
}
IncrementalStringBuilder builder(isolate);
CallSite call_site(isolate, recv);
if (call_site.IsWasm()) {
RETURN_ON_EXCEPTION(isolate,
AppendWasmToString(isolate, recv, &call_site, &builder),
String);
RETURN_RESULT(isolate, builder.Finish(), String);
}
DCHECK(!call_site.IsWasm());
Handle<Object> function_name = call_site.GetFunctionName();
const bool is_toplevel = call_site.IsToplevel();
const bool is_constructor = call_site.IsConstructor();
const bool is_method_call = !(is_toplevel || is_constructor);
if (is_method_call) {
RETURN_ON_EXCEPTION(
isolate, AppendMethodCall(isolate, recv, &call_site, &builder), String);
} 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 {
RETURN_ON_EXCEPTION(isolate,
AppendFileLocation(isolate, recv, &call_site, &builder),
String);
RETURN_RESULT(isolate, builder.Finish(), String);
}
builder.AppendCString(" (");
RETURN_ON_EXCEPTION(
isolate, AppendFileLocation(isolate, recv, &call_site, &builder), String);
builder.AppendCString(")");
RETURN_RESULT(isolate, builder.Finish(), String);
}
} // namespace internal
} // namespace v8
......@@ -51,6 +51,8 @@ class CallSite {
Handle<Object> GetFunctionName();
Handle<Object> GetScriptNameOrSourceUrl();
Handle<Object> GetMethodName();
Handle<Object> GetTypeName();
Handle<Object> GetEvalOrigin();
// Return 1-based line number, including line offset.
int GetLineNumber();
// Return 1-based column number, including column offset if first line.
......@@ -89,10 +91,26 @@ enum FrameSkipMode {
SKIP_NONE,
};
MaybeHandle<Object> ConstructError(Isolate* isolate, Handle<JSFunction> target,
Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode,
bool suppress_detailed_trace);
class ErrorUtils : public AllStatic {
public:
static MaybeHandle<Object> Construct(
Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode, bool suppress_detailed_trace);
static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv);
};
class CallSiteUtils : public AllStatic {
public:
static MaybeHandle<Object> Construct(Isolate* isolate,
Handle<JSFunction> target,
Handle<Object> new_target,
Handle<Object> receiver,
Handle<Object> fun, Handle<Object> pos,
Handle<Object> strict_mode);
static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv);
};
#define MESSAGE_TEMPLATES(T) \
/* Error */ \
......
......@@ -92,16 +92,6 @@ RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) {
return Smi::FromInt(pos);
}
RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(AbstractCode, abstract_code, 0);
CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
return Smi::FromInt(abstract_code->SourcePosition(offset));
}
RUNTIME_FUNCTION(Runtime_FunctionGetContextData) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
......
......@@ -219,7 +219,6 @@ namespace internal {
F(FunctionGetScript, 1, 1) \
F(FunctionGetSourceCode, 1, 1) \
F(FunctionGetScriptSourcePosition, 1, 1) \
F(FunctionGetPositionForOffset, 2, 1) \
F(FunctionGetContextData, 1, 1) \
F(FunctionSetInstanceClassName, 2, 1) \
F(FunctionSetLength, 2, 1) \
......
......@@ -80,7 +80,7 @@ bytecodes: [
/* 15 S> */ B(LdrUndefined), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(Star), R(1),
B(CallJSRuntime), U8(130), R(0), U8(2),
B(CallJSRuntime), U8(131), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
......
......@@ -411,3 +411,15 @@ try {
} catch (e) {
assertEquals(undefined, e.stack);
}
// Check that a tight recursion in prepareStackTrace fails gracefully, i.e.
// a range error is thrown and printed (but without showing the actual stack).
Error.prepareStackTrace = () => Error.prepareStackTrace();
try {
new Error().stack;
} catch (e) {
assertTrue(
e.stack.indexOf("RangeError: Maximum call stack size exceeded") != -1);
assertTrue(e.stack.indexOf("prepareStackTrace") == -1);
}
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