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,
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,
Handle<JSObject> holder) {
LookupIterator it(receiver, name, holder,
......
......@@ -5,7 +5,6 @@
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
#include "src/accessors.h"
#include "src/bootstrapper.h"
#include "src/messages.h"
#include "src/property-descriptor.h"
......@@ -36,67 +35,24 @@ BUILTIN(ErrorCaptureStackTrace) {
Handle<Object> caller = args.atOrUndefined(isolate, 2);
FrameSkipMode mode = caller->IsJSFunction() ? SKIP_UNTIL_SEEN : SKIP_NONE;
// TODO(jgruber): Eagerly format the stack trace and remove accessors.h
// 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;
}
// Collect the stack trace.
PropertyDescriptor desc;
Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
isolate, object, isolate->factory()->stack_string(), &desc);
if (owned.FromMaybe(false)) {
if (!desc.configurable() || !desc.writable()) {
is_extensible = false;
}
}
RETURN_FAILURE_ON_EXCEPTION(isolate,
isolate->CaptureAndSetDetailedStackTrace(object));
if (!is_extensible) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kDefineDisallowed,
isolate->factory()->stack_string(), object));
}
// Eagerly format the stack trace and set the stack property.
// Add stack accessors to the given object
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);
}
}
Handle<Object> stack_trace =
isolate->CaptureSimpleStackTrace(object, mode, caller);
// 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(
isolate, isolate->CaptureAndSetSimpleStackTrace(object, mode, caller));
isolate, JSObject::SetProperty(object, isolate->factory()->stack_string(),
formatted_stack_trace, STRICT));
return *isolate->factory()->undefined_value();
}
......
......@@ -563,9 +563,8 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace(
Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
stack_trace_for_uncaught_exceptions_frame_limit_,
stack_trace_for_uncaught_exceptions_options_);
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces.
RETURN_ON_EXCEPTION(
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY),
this, JSReceiver::SetProperty(error_object, key, stack_trace, STRICT),
JSReceiver);
}
return error_object;
......@@ -578,9 +577,8 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace(
Handle<Name> key = factory()->stack_trace_symbol();
Handle<Object> stack_trace =
CaptureSimpleStackTrace(error_object, mode, caller);
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces.
RETURN_ON_EXCEPTION(
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY),
this, JSReceiver::SetProperty(error_object, key, stack_trace, STRICT),
JSReceiver);
return error_object;
}
......
......@@ -364,6 +364,23 @@ bool CallSite::IsConstructor() {
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,
int template_index,
......
......@@ -71,6 +71,11 @@ class CallSite {
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.
enum FrameSkipMode {
// Unconditionally skips the first frame. Used e.g. when the Error constructor
......
......@@ -380,3 +380,9 @@ assertEquals(undefined, error.stack);
// Check that repeated trace collection does not crash.
error = new 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