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 @@
#include "src/accessors.h"
#include "src/bootstrapper.h"
#include "src/messages.h"
#include "src/property-descriptor.h"
#include "src/string-builder.h"
......@@ -16,53 +17,11 @@ namespace internal {
// ES6 section 19.5.1.1 Error ( message )
BUILTIN(ErrorConstructor) {
HandleScope scope(isolate);
// 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,
JSObject::SetOwnPropertyIgnoreAttributes(
err, isolate->factory()->message_string(), msg_string, DONT_ENUM));
}
// 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;
RETURN_RESULT_OR_FAILURE(
isolate,
ConstructError(isolate, args.target<JSFunction>(),
Handle<Object>::cast(args.new_target()),
args.atOrUndefined(isolate, 1), SKIP_FIRST, false));
}
// static
......@@ -75,6 +34,7 @@ BUILTIN(ErrorCaptureStackTrace) {
}
Handle<JSObject> object = Handle<JSObject>::cast(object_obj);
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.
......@@ -136,7 +96,7 @@ BUILTIN(ErrorCaptureStackTrace) {
RETURN_FAILURE_ON_EXCEPTION(isolate,
isolate->CaptureAndSetDetailedStackTrace(object));
RETURN_FAILURE_ON_EXCEPTION(
isolate, isolate->CaptureAndSetSimpleStackTrace(object, caller));
isolate, isolate->CaptureAndSetSimpleStackTrace(object, mode, caller));
return *isolate->factory()->undefined_value();
}
......
......@@ -133,7 +133,6 @@ enum BindingFlags {
V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \
V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \
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(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function)
......
......@@ -329,16 +329,12 @@ static Handle<FixedArray> MaybeGrow(Isolate* isolate,
}
class StackTraceHelper {
private:
enum FrameSkipMode {
SKIP_FIRST,
SKIP_UNTIL_SEEN,
SKIP_NONE,
};
public:
StackTraceHelper(Isolate* isolate, Handle<Object> caller)
: isolate_(isolate), caller_(caller) {
StackTraceHelper(Isolate* isolate, FrameSkipMode mode, Handle<Object> 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
// stack trace. It can be:
// * null, when called from a standard error constructor. We unconditionally
......@@ -347,15 +343,18 @@ class StackTraceHelper {
// * a JSFunction, when called by the user from Error.captureStackTrace().
// We skip each frame until encountering the caller function.
// * For any other value, all frames are included in the trace.
if (caller_.is_null()) {
mode_ = SKIP_FIRST;
skip_next_frame_ = true;
} else if (caller_->IsJSFunction()) {
mode_ = SKIP_UNTIL_SEEN;
skip_next_frame_ = true;
} else {
mode_ = SKIP_NONE;
skip_next_frame_ = false;
switch (mode_) {
case SKIP_FIRST:
DCHECK(caller_.is_null());
skip_next_frame_ = true;
break;
case SKIP_UNTIL_SEEN:
DCHECK(caller_->IsJSFunction());
skip_next_frame_ = true;
break;
case SKIP_NONE:
skip_next_frame_ = false;
break;
}
encountered_strict_function_ = false;
sloppy_frames_ = 0;
......@@ -425,8 +424,8 @@ class StackTraceHelper {
Isolate* isolate_;
FrameSkipMode mode_;
Handle<Object> caller_;
const FrameSkipMode mode_;
const Handle<Object> caller_;
bool skip_next_frame_;
int sloppy_frames_;
......@@ -434,6 +433,7 @@ class StackTraceHelper {
};
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
FrameSkipMode mode,
Handle<Object> caller) {
DisallowJavascriptExecution no_js(this);
......@@ -452,7 +452,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
Handle<FixedArray> elements =
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.
int cursor = 1;
......@@ -572,10 +572,12 @@ MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace(
}
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.
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.
RETURN_ON_EXCEPTION(
this, JSReceiver::SetProperty(error_object, key, stack_trace, SLOPPY),
......@@ -960,20 +962,14 @@ bool Isolate::MayAccess(Handle<Context> accessing_context,
Object* Isolate::StackOverflow() {
DisallowJavascriptExecution no_js(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
// attach the stack trace as a hidden property.
Handle<JSFunction> fun = range_error_function();
Handle<Object> msg = factory()->NewStringFromAsciiChecked(
MessageTemplate::TemplateString(MessageTemplate::kStackOverflow));
Handle<Object> exception;
if (bootstrapper()->IsActive()) {
// There is no boilerplate to use during bootstrapping.
exception = factory()->NewStringFromAsciiChecked(
MessageTemplate::TemplateString(MessageTemplate::kStackOverflow));
} else {
Handle<JSObject> boilerplate = stack_overflow_boilerplate();
Handle<JSObject> copy = factory()->CopyJSObject(boilerplate);
CaptureAndSetSimpleStackTrace(copy, factory()->undefined_value());
exception = copy;
}
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
this, exception, ConstructError(this, fun, fun, msg, SKIP_NONE, true));
Throw(*exception, nullptr);
#ifdef VERIFY_HEAP
......
......@@ -696,12 +696,13 @@ class Isolate {
int frame_limit,
StackTrace::StackTraceOptions options);
Handle<Object> CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
FrameSkipMode mode,
Handle<Object> caller);
MaybeHandle<JSReceiver> CaptureAndSetDetailedStackTrace(
Handle<JSReceiver> error_object);
MaybeHandle<JSReceiver> CaptureAndSetSimpleStackTrace(
Handle<JSReceiver> error_object,
Handle<Object> caller = Handle<Object>());
Handle<JSReceiver> error_object, FrameSkipMode mode,
Handle<Object> caller);
Handle<JSArray> GetDetailedStackTrace(Handle<JSObject> error_object);
// Returns if the given context may access the given global object. If
......
......@@ -637,10 +637,6 @@ function MakeURIError() {
return MakeGenericError(GlobalURIError, kURIMalformed);
}
// Boilerplate for exceptions for stack overflows. Used from
// Isolate::StackOverflow().
var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
%InstallToContext([
"error_format_stack_trace", FormatStackTrace,
"get_stack_trace_line_fun", GetStackTraceLine,
......@@ -651,7 +647,6 @@ var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
"message_get_line_number", GetLineNumber,
"message_get_source_line", GetSourceLine,
"no_side_effects_to_string_fun", NoSideEffectsToString,
"stack_overflow_boilerplate", StackOverflowBoilerplate,
]);
utils.Export(function(to) {
......
......@@ -5,6 +5,7 @@
#include "src/messages.h"
#include "src/api.h"
#include "src/bootstrapper.h"
#include "src/execution.h"
#include "src/isolate-inl.h"
#include "src/keys.h"
......@@ -445,6 +446,52 @@ 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) {
// 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 v8
......@@ -71,6 +71,21 @@ class CallSite {
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) \
/* Error */ \
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