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);
......
This diff is collapsed.
......@@ -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,
......
This diff is collapsed.
......@@ -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