Commit 46e896e7 authored by jgruber's avatar jgruber Committed by Commit bot

Remove stack overflow boilerplate

We no longer need to prepare the stack overflow error in advance now that
Errors are constructed in C++.

R=yangguo@chromium.org
BUG=

Committed: https://crrev.com/ba95d10ccbe13e2fca427228483b045576f2dc4c
Review-Url: https://codereview.chromium.org/2161953003
Cr-Original-Commit-Position: refs/heads/master@{#37923}
Cr-Commit-Position: refs/heads/master@{#37949}
parent 767d7fff
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/accessors.h" #include "src/accessors.h"
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/messages.h"
#include "src/property-descriptor.h" #include "src/property-descriptor.h"
#include "src/string-builder.h" #include "src/string-builder.h"
...@@ -16,53 +17,11 @@ namespace internal { ...@@ -16,53 +17,11 @@ namespace internal {
// ES6 section 19.5.1.1 Error ( message ) // ES6 section 19.5.1.1 Error ( message )
BUILTIN(ErrorConstructor) { BUILTIN(ErrorConstructor) {
HandleScope scope(isolate); HandleScope scope(isolate);
RETURN_RESULT_OR_FAILURE(
// 1. If NewTarget is undefined, let newTarget be the active function object,
// else let newTarget be NewTarget.
Handle<JSFunction> target = args.target<JSFunction>();
Handle<JSReceiver> new_target;
if (args.new_target()->IsJSReceiver()) {
new_target = Handle<JSReceiver>::cast(args.new_target());
} else {
new_target = target;
}
// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
// « [[ErrorData]] »).
Handle<JSObject> err;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, err,
JSObject::New(target, new_target));
// 3. If message is not undefined, then
// a. Let msg be ? ToString(message).
// b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
// true, [[Enumerable]]: false, [[Configurable]]: true}.
// c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
// 4. Return O.
Handle<Object> msg = args.atOrUndefined(isolate, 1);
if (!msg->IsUndefined(isolate)) {
Handle<String> msg_string;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, msg_string,
Object::ToString(isolate, msg));
RETURN_FAILURE_ON_EXCEPTION(
isolate, isolate,
JSObject::SetOwnPropertyIgnoreAttributes( ConstructError(isolate, args.target<JSFunction>(),
err, isolate->factory()->message_string(), msg_string, DONT_ENUM)); Handle<Object>::cast(args.new_target()),
} args.atOrUndefined(isolate, 1), SKIP_FIRST, false));
// Capture the stack trace unless we're setting up.
if (!isolate->bootstrapper()->IsActive()) {
// Optionally capture a more detailed stack trace for the message.
RETURN_FAILURE_ON_EXCEPTION(isolate,
isolate->CaptureAndSetDetailedStackTrace(err));
// Capture a simple stack trace for the stack property.
RETURN_FAILURE_ON_EXCEPTION(isolate,
isolate->CaptureAndSetSimpleStackTrace(err));
}
return *err;
} }
// static // static
...@@ -75,6 +34,7 @@ BUILTIN(ErrorCaptureStackTrace) { ...@@ -75,6 +34,7 @@ BUILTIN(ErrorCaptureStackTrace) {
} }
Handle<JSObject> object = Handle<JSObject>::cast(object_obj); Handle<JSObject> object = Handle<JSObject>::cast(object_obj);
Handle<Object> caller = args.atOrUndefined(isolate, 2); 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 // TODO(jgruber): Eagerly format the stack trace and remove accessors.h
// include. // include.
...@@ -136,7 +96,7 @@ BUILTIN(ErrorCaptureStackTrace) { ...@@ -136,7 +96,7 @@ BUILTIN(ErrorCaptureStackTrace) {
RETURN_FAILURE_ON_EXCEPTION(isolate, RETURN_FAILURE_ON_EXCEPTION(isolate,
isolate->CaptureAndSetDetailedStackTrace(object)); isolate->CaptureAndSetDetailedStackTrace(object));
RETURN_FAILURE_ON_EXCEPTION( RETURN_FAILURE_ON_EXCEPTION(
isolate, isolate->CaptureAndSetSimpleStackTrace(object, caller)); isolate, isolate->CaptureAndSetSimpleStackTrace(object, mode, caller));
return *isolate->factory()->undefined_value(); return *isolate->factory()->undefined_value();
} }
......
...@@ -133,7 +133,6 @@ enum BindingFlags { ...@@ -133,7 +133,6 @@ enum BindingFlags {
V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \ V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \
V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \ V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \
V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \ V(SET_HAS_METHOD_INDEX, JSFunction, set_has) \
V(STACK_OVERFLOW_BOILERPLATE_INDEX, JSObject, stack_overflow_boilerplate) \
V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \ V(SYNTAX_ERROR_FUNCTION_INDEX, JSFunction, syntax_error_function) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \ V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function)
......
...@@ -329,16 +329,12 @@ static Handle<FixedArray> MaybeGrow(Isolate* isolate, ...@@ -329,16 +329,12 @@ static Handle<FixedArray> MaybeGrow(Isolate* isolate,
} }
class StackTraceHelper { class StackTraceHelper {
private:
enum FrameSkipMode {
SKIP_FIRST,
SKIP_UNTIL_SEEN,
SKIP_NONE,
};
public: public:
StackTraceHelper(Isolate* isolate, Handle<Object> caller) StackTraceHelper(Isolate* isolate, FrameSkipMode mode, Handle<Object> caller)
: isolate_(isolate), caller_(caller) { : isolate_(isolate),
mode_(mode),
caller_(caller),
skip_next_frame_(true) {
// The caller parameter can be used to skip a specific set of frames in the // The caller parameter can be used to skip a specific set of frames in the
// stack trace. It can be: // stack trace. It can be:
// * null, when called from a standard error constructor. We unconditionally // * null, when called from a standard error constructor. We unconditionally
...@@ -347,15 +343,18 @@ class StackTraceHelper { ...@@ -347,15 +343,18 @@ class StackTraceHelper {
// * a JSFunction, when called by the user from Error.captureStackTrace(). // * a JSFunction, when called by the user from Error.captureStackTrace().
// We skip each frame until encountering the caller function. // We skip each frame until encountering the caller function.
// * For any other value, all frames are included in the trace. // * For any other value, all frames are included in the trace.
if (caller_.is_null()) { switch (mode_) {
mode_ = SKIP_FIRST; case SKIP_FIRST:
DCHECK(caller_.is_null());
skip_next_frame_ = true; skip_next_frame_ = true;
} else if (caller_->IsJSFunction()) { break;
mode_ = SKIP_UNTIL_SEEN; case SKIP_UNTIL_SEEN:
DCHECK(caller_->IsJSFunction());
skip_next_frame_ = true; skip_next_frame_ = true;
} else { break;
mode_ = SKIP_NONE; case SKIP_NONE:
skip_next_frame_ = false; skip_next_frame_ = false;
break;
} }
encountered_strict_function_ = false; encountered_strict_function_ = false;
sloppy_frames_ = 0; sloppy_frames_ = 0;
...@@ -425,8 +424,8 @@ class StackTraceHelper { ...@@ -425,8 +424,8 @@ class StackTraceHelper {
Isolate* isolate_; Isolate* isolate_;
FrameSkipMode mode_; const FrameSkipMode mode_;
Handle<Object> caller_; const Handle<Object> caller_;
bool skip_next_frame_; bool skip_next_frame_;
int sloppy_frames_; int sloppy_frames_;
...@@ -434,6 +433,7 @@ class StackTraceHelper { ...@@ -434,6 +433,7 @@ class StackTraceHelper {
}; };
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
FrameSkipMode mode,
Handle<Object> caller) { Handle<Object> caller) {
DisallowJavascriptExecution no_js(this); DisallowJavascriptExecution no_js(this);
...@@ -452,7 +452,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, ...@@ -452,7 +452,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
Handle<FixedArray> elements = Handle<FixedArray> elements =
factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); factory()->NewFixedArrayWithHoles(initial_size * 4 + 1);
StackTraceHelper helper(this, caller); StackTraceHelper helper(this, mode, caller);
// First element is reserved to store the number of sloppy frames. // First element is reserved to store the number of sloppy frames.
int cursor = 1; int cursor = 1;
...@@ -572,10 +572,12 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( ...@@ -572,10 +572,12 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace(
} }
MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace( MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace(
Handle<JSReceiver> error_object, Handle<Object> caller) { Handle<JSReceiver> error_object, FrameSkipMode mode,
Handle<Object> caller) {
// Capture stack trace for simple stack trace string formatting. // Capture stack trace for simple stack trace string formatting.
Handle<Name> key = factory()->stack_trace_symbol(); Handle<Name> key = factory()->stack_trace_symbol();
Handle<Object> stack_trace = CaptureSimpleStackTrace(error_object, caller); Handle<Object> stack_trace =
CaptureSimpleStackTrace(error_object, mode, caller);
// TODO(jgruber): Set back to STRICT once we have eagerly formatted traces. // 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, SLOPPY),
...@@ -960,20 +962,14 @@ bool Isolate::MayAccess(Handle<Context> accessing_context, ...@@ -960,20 +962,14 @@ bool Isolate::MayAccess(Handle<Context> accessing_context,
Object* Isolate::StackOverflow() { Object* Isolate::StackOverflow() {
DisallowJavascriptExecution no_js(this); DisallowJavascriptExecution no_js(this);
HandleScope scope(this); HandleScope scope(this);
// At this point we cannot create an Error object using its javascript
// constructor. Instead, we copy the pre-constructed boilerplate and Handle<JSFunction> fun = range_error_function();
// attach the stack trace as a hidden property. Handle<Object> msg = factory()->NewStringFromAsciiChecked(
Handle<Object> exception;
if (bootstrapper()->IsActive()) {
// There is no boilerplate to use during bootstrapping.
exception = factory()->NewStringFromAsciiChecked(
MessageTemplate::TemplateString(MessageTemplate::kStackOverflow)); MessageTemplate::TemplateString(MessageTemplate::kStackOverflow));
} else { Handle<Object> exception;
Handle<JSObject> boilerplate = stack_overflow_boilerplate(); ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
Handle<JSObject> copy = factory()->CopyJSObject(boilerplate); this, exception, ConstructError(this, fun, fun, msg, SKIP_NONE, true));
CaptureAndSetSimpleStackTrace(copy, factory()->undefined_value());
exception = copy;
}
Throw(*exception, nullptr); Throw(*exception, nullptr);
#ifdef VERIFY_HEAP #ifdef VERIFY_HEAP
......
...@@ -696,12 +696,13 @@ class Isolate { ...@@ -696,12 +696,13 @@ class Isolate {
int frame_limit, int frame_limit,
StackTrace::StackTraceOptions options); StackTrace::StackTraceOptions options);
Handle<Object> CaptureSimpleStackTrace(Handle<JSReceiver> error_object, Handle<Object> CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
FrameSkipMode mode,
Handle<Object> caller); Handle<Object> caller);
MaybeHandle<JSReceiver> CaptureAndSetDetailedStackTrace( MaybeHandle<JSReceiver> CaptureAndSetDetailedStackTrace(
Handle<JSReceiver> error_object); Handle<JSReceiver> error_object);
MaybeHandle<JSReceiver> CaptureAndSetSimpleStackTrace( MaybeHandle<JSReceiver> CaptureAndSetSimpleStackTrace(
Handle<JSReceiver> error_object, Handle<JSReceiver> error_object, FrameSkipMode mode,
Handle<Object> caller = Handle<Object>()); Handle<Object> caller);
Handle<JSArray> GetDetailedStackTrace(Handle<JSObject> error_object); Handle<JSArray> GetDetailedStackTrace(Handle<JSObject> error_object);
// Returns if the given context may access the given global object. If // Returns if the given context may access the given global object. If
......
...@@ -637,10 +637,6 @@ function MakeURIError() { ...@@ -637,10 +637,6 @@ function MakeURIError() {
return MakeGenericError(GlobalURIError, kURIMalformed); return MakeGenericError(GlobalURIError, kURIMalformed);
} }
// Boilerplate for exceptions for stack overflows. Used from
// Isolate::StackOverflow().
var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
%InstallToContext([ %InstallToContext([
"error_format_stack_trace", FormatStackTrace, "error_format_stack_trace", FormatStackTrace,
"get_stack_trace_line_fun", GetStackTraceLine, "get_stack_trace_line_fun", GetStackTraceLine,
...@@ -651,7 +647,6 @@ var StackOverflowBoilerplate = MakeRangeError(kStackOverflow); ...@@ -651,7 +647,6 @@ var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
"message_get_line_number", GetLineNumber, "message_get_line_number", GetLineNumber,
"message_get_source_line", GetSourceLine, "message_get_source_line", GetSourceLine,
"no_side_effects_to_string_fun", NoSideEffectsToString, "no_side_effects_to_string_fun", NoSideEffectsToString,
"stack_overflow_boilerplate", StackOverflowBoilerplate,
]); ]);
utils.Export(function(to) { utils.Export(function(to) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/messages.h" #include "src/messages.h"
#include "src/api.h" #include "src/api.h"
#include "src/bootstrapper.h"
#include "src/execution.h" #include "src/execution.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/keys.h" #include "src/keys.h"
...@@ -445,6 +446,52 @@ MaybeHandle<String> MessageTemplate::FormatMessage(int template_index, ...@@ -445,6 +446,52 @@ MaybeHandle<String> MessageTemplate::FormatMessage(int template_index,
return builder.Finish(); return builder.Finish();
} }
MaybeHandle<Object> ConstructError(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.
Handle<JSReceiver> new_target_recv =
new_target->IsJSReceiver() ? Handle<JSReceiver>::cast(new_target)
: Handle<JSReceiver>::cast(target);
// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
// « [[ErrorData]] »).
Handle<JSObject> err;
ASSIGN_RETURN_ON_EXCEPTION(isolate, err,
JSObject::New(target, new_target_recv), Object);
// 3. If message is not undefined, then
// a. Let msg be ? ToString(message).
// b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
// true, [[Enumerable]]: false, [[Configurable]]: true}.
// c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
// 4. Return O.
if (!message->IsUndefined(isolate)) {
Handle<String> msg_string;
ASSIGN_RETURN_ON_EXCEPTION(isolate, msg_string,
Object::ToString(isolate, message), Object);
RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
err, isolate->factory()->message_string(),
msg_string, DONT_ENUM),
Object);
}
// Optionally capture a more detailed stack trace for the message.
if (!suppress_detailed_trace) {
RETURN_ON_EXCEPTION(isolate, isolate->CaptureAndSetDetailedStackTrace(err),
Object);
}
// Capture a simple stack trace for the stack property.
RETURN_ON_EXCEPTION(isolate, isolate->CaptureAndSetSimpleStackTrace(
err, mode, Handle<Object>()),
Object);
return err;
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -71,6 +71,21 @@ class CallSite { ...@@ -71,6 +71,21 @@ class CallSite {
uint32_t wasm_func_index_ = static_cast<uint32_t>(-1); uint32_t wasm_func_index_ = static_cast<uint32_t>(-1);
}; };
// Determines how stack trace collection skips frames.
enum FrameSkipMode {
// Unconditionally skips the first frame. Used e.g. when the Error constructor
// is called, in which case the first frame is always a BUILTIN_EXIT frame.
SKIP_FIRST,
// Skip all frames until a specified caller function is seen.
SKIP_UNTIL_SEEN,
SKIP_NONE,
};
MaybeHandle<Object> ConstructError(Isolate* isolate, Handle<JSFunction> target,
Handle<Object> new_target,
Handle<Object> message, FrameSkipMode mode,
bool suppress_detailed_trace);
#define MESSAGE_TEMPLATES(T) \ #define MESSAGE_TEMPLATES(T) \
/* Error */ \ /* Error */ \
T(None, "") \ T(None, "") \
......
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