Commit 4feafee9 authored by jgruber's avatar jgruber Committed by Commit bot

Eagerly format traces in captureStackTrace

This allows us to skip complicated logic for setting the accessors.

BUG=

Review-Url: https://codereview.chromium.org/2164903004
Cr-Commit-Position: refs/heads/master@{#37969}
parent 76c4b6ef
...@@ -1132,24 +1132,6 @@ MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate, ...@@ -1132,24 +1132,6 @@ MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
return error; return error;
} }
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();
int argc = 2;
ScopedVector<Handle<Object>> argv(argc);
argv[0] = error;
argv[1] = stack_trace;
Handle<Object> formatted_stack_trace;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, formatted_stack_trace,
Execution::Call(isolate, fun, error, argc, argv.start()), Object);
return formatted_stack_trace;
}
bool IsAccessor(Handle<Object> receiver, Handle<Name> name, bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
Handle<JSObject> holder) { Handle<JSObject> holder) {
LookupIterator it(receiver, name, holder, LookupIterator it(receiver, name, holder,
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h" #include "src/builtins/builtins-utils.h"
#include "src/accessors.h"
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/messages.h" #include "src/messages.h"
#include "src/property-descriptor.h" #include "src/property-descriptor.h"
...@@ -36,67 +35,24 @@ BUILTIN(ErrorCaptureStackTrace) { ...@@ -36,67 +35,24 @@ BUILTIN(ErrorCaptureStackTrace) {
Handle<Object> caller = args.atOrUndefined(isolate, 2); Handle<Object> caller = args.atOrUndefined(isolate, 2);
FrameSkipMode mode = caller->IsJSFunction() ? SKIP_UNTIL_SEEN : SKIP_NONE; FrameSkipMode mode = caller->IsJSFunction() ? SKIP_UNTIL_SEEN : SKIP_NONE;
// TODO(jgruber): Eagerly format the stack trace and remove accessors.h // Collect the stack trace.
// include.
// Handle writes to the global object.
if (object->IsJSGlobalProxy()) {
Map* map = object->map();
if (map->has_hidden_prototype()) {
object = handle(JSGlobalObject::cast(map->prototype()), isolate);
}
}
// Check if the stack property is read-only.
bool is_extensible = true;
if (!JSObject::IsExtensible(object)) {
is_extensible = false;
}
PropertyDescriptor desc; RETURN_FAILURE_ON_EXCEPTION(isolate,
Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( isolate->CaptureAndSetDetailedStackTrace(object));
isolate, object, isolate->factory()->stack_string(), &desc);
if (owned.FromMaybe(false)) {
if (!desc.configurable() || !desc.writable()) {
is_extensible = false;
}
}
if (!is_extensible) { // Eagerly format the stack trace and set the stack property.
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kDefineDisallowed,
isolate->factory()->stack_string(), object));
}
// Add stack accessors to the given object Handle<Object> stack_trace =
isolate->CaptureSimpleStackTrace(object, mode, caller);
Handle<Map> map(object->map());
PropertyAttributes attribs = DONT_ENUM;
Handle<AccessorInfo> error_stack =
Accessors::ErrorStackInfo(isolate, attribs);
{
AccessorConstantDescriptor d(Handle<Name>(Name::cast(error_stack->name())),
error_stack, attribs);
Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
int index = old_descriptors->SearchWithCache(isolate, *d.GetKey(), *map);
if (index == DescriptorArray::kNotFound) {
// TODO(jgruber): This ensures we do not crash when CaptureStackTrace is
// called on an object with an existing "stack" property. This will be
// removed as soon as we move to eager trace formatting.
Handle<Map> new_map =
Map::CopyInsertDescriptor(map, &d, INSERT_TRANSITION);
JSObject::MigrateToMap(object, new_map, 1);
}
}
// Collect the stack trace. Handle<Object> formatted_stack_trace;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, formatted_stack_trace,
FormatStackTrace(isolate, object, stack_trace));
RETURN_FAILURE_ON_EXCEPTION(isolate,
isolate->CaptureAndSetDetailedStackTrace(object));
RETURN_FAILURE_ON_EXCEPTION( RETURN_FAILURE_ON_EXCEPTION(
isolate, isolate->CaptureAndSetSimpleStackTrace(object, mode, caller)); isolate, JSObject::SetProperty(object, isolate->factory()->stack_string(),
formatted_stack_trace, STRICT));
return *isolate->factory()->undefined_value(); return *isolate->factory()->undefined_value();
} }
......
...@@ -563,9 +563,8 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( ...@@ -563,9 +563,8 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace(
Handle<JSArray> stack_trace = CaptureCurrentStackTrace( Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
stack_trace_for_uncaught_exceptions_frame_limit_, stack_trace_for_uncaught_exceptions_frame_limit_,
stack_trace_for_uncaught_exceptions_options_); stack_trace_for_uncaught_exceptions_options_);
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces.
RETURN_ON_EXCEPTION( RETURN_ON_EXCEPTION(
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY), this, JSReceiver::SetProperty(error_object, key, stack_trace, STRICT),
JSReceiver); JSReceiver);
} }
return error_object; return error_object;
...@@ -578,9 +577,8 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace( ...@@ -578,9 +577,8 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace(
Handle<Name> key = factory()->stack_trace_symbol(); Handle<Name> key = factory()->stack_trace_symbol();
Handle<Object> stack_trace = Handle<Object> stack_trace =
CaptureSimpleStackTrace(error_object, mode, caller); CaptureSimpleStackTrace(error_object, mode, caller);
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces.
RETURN_ON_EXCEPTION( RETURN_ON_EXCEPTION(
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY), this, JSReceiver::SetProperty(error_object, key, stack_trace, STRICT),
JSReceiver); JSReceiver);
return error_object; return error_object;
} }
......
...@@ -364,6 +364,23 @@ bool CallSite::IsConstructor() { ...@@ -364,6 +364,23 @@ bool CallSite::IsConstructor() {
return constructor.is_identical_to(fun_); return constructor.is_identical_to(fun_);
} }
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();
int argc = 2;
ScopedVector<Handle<Object>> argv(argc);
argv[0] = error;
argv[1] = stack_trace;
Handle<Object> formatted_stack_trace;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, formatted_stack_trace,
Execution::Call(isolate, fun, error, argc, argv.start()), Object);
return formatted_stack_trace;
}
Handle<String> MessageTemplate::FormatMessage(Isolate* isolate, Handle<String> MessageTemplate::FormatMessage(Isolate* isolate,
int template_index, int template_index,
......
...@@ -71,6 +71,11 @@ class CallSite { ...@@ -71,6 +71,11 @@ class CallSite {
uint32_t wasm_func_index_ = static_cast<uint32_t>(-1); uint32_t wasm_func_index_ = static_cast<uint32_t>(-1);
}; };
// Formats a textual stack trace from the given structured stack trace.
// Note that this can call arbitrary JS code through Error.prepareStackTrace.
MaybeHandle<Object> FormatStackTrace(Isolate* isolate, Handle<JSObject> error,
Handle<Object> stack_trace);
// Determines how stack trace collection skips frames. // Determines how stack trace collection skips frames.
enum FrameSkipMode { enum FrameSkipMode {
// Unconditionally skips the first frame. Used e.g. when the Error constructor // Unconditionally skips the first frame. Used e.g. when the Error constructor
......
...@@ -380,3 +380,9 @@ assertEquals(undefined, error.stack); ...@@ -380,3 +380,9 @@ assertEquals(undefined, error.stack);
// Check that repeated trace collection does not crash. // Check that repeated trace collection does not crash.
error = new Error(); error = new Error();
Error.captureStackTrace(error); Error.captureStackTrace(error);
// Check that exceptions thrown within prepareStackTrace throws an exception.
Error.prepareStackTrace = function(e, frames) { throw 42; }
var x = {}
assertThrows(() => Error.captureStackTrace(x));
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