Index: src/js/messages.js |
diff --git a/src/js/messages.js b/src/js/messages.js |
index f327fee18dae7b8c5bdae830a1827550b7975b5d..934d44f73d1b5b07c475e6240f35edcb06e5a6dd 100644 |
--- a/src/js/messages.js |
+++ b/src/js/messages.js |
@@ -30,14 +30,9 @@ |
var callSiteWasmFunctionIndexSymbol = |
utils.ImportNow("call_site_wasm_func_index_symbol"); |
var Float32x4ToString; |
+var formattedStackTraceSymbol = |
+ utils.ImportNow("formatted_stack_trace_symbol"); |
var GlobalObject = global.Object; |
-var GlobalError = global.Error; |
-var GlobalEvalError = global.EvalError; |
-var GlobalRangeError = global.RangeError; |
-var GlobalReferenceError = global.ReferenceError; |
-var GlobalSyntaxError = global.SyntaxError; |
-var GlobalTypeError = global.TypeError; |
-var GlobalURIError = global.URIError; |
var Int16x8ToString; |
var Int32x4ToString; |
var Int8x16ToString; |
@@ -71,6 +66,13 @@ |
// ------------------------------------------------------------------- |
+var GlobalError; |
+var GlobalTypeError; |
+var GlobalRangeError; |
+var GlobalURIError; |
+var GlobalSyntaxError; |
+var GlobalReferenceError; |
+var GlobalEvalError; |
function NoSideEffectsObjectToString() { |
@@ -601,6 +603,92 @@ |
return %GetConstructorName(receiver); |
} |
+ |
+// Format the stack trace if not yet done, and return it. |
+// Cache the formatted stack trace on the holder. |
+var StackTraceGetter = function() { |
+ var formatted_stack_trace = UNDEFINED; |
+ var holder = this; |
+ while (holder) { |
+ var formatted_stack_trace = |
+ GET_PRIVATE(holder, formattedStackTraceSymbol); |
+ if (IS_UNDEFINED(formatted_stack_trace)) { |
+ // No formatted stack trace available. |
+ var stack_trace = GET_PRIVATE(holder, stackTraceSymbol); |
+ if (IS_UNDEFINED(stack_trace)) { |
+ // Neither formatted nor structured stack trace available. |
+ // Look further up the prototype chain. |
+ holder = %object_get_prototype_of(holder); |
+ continue; |
+ } |
+ formatted_stack_trace = FormatStackTrace(holder, stack_trace); |
+ SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED); |
+ SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace); |
+ } |
+ return formatted_stack_trace; |
+ } |
+ return UNDEFINED; |
+}; |
+ |
+ |
+// If the receiver equals the holder, set the formatted stack trace that the |
+// getter returns. |
+var StackTraceSetter = function(v) { |
+ if (IsErrorObject(this)) { |
+ SET_PRIVATE(this, stackTraceSymbol, UNDEFINED); |
+ SET_PRIVATE(this, formattedStackTraceSymbol, v); |
+ } |
+}; |
+ |
+ |
+// Use a dummy function since we do not actually want to capture a stack trace |
+// when constructing the initial Error prototytpes. |
+var captureStackTrace = function() {}; |
+ |
+ |
+// Set up special error type constructors. |
+function SetUpError(error_function) { |
+ %FunctionSetInstanceClassName(error_function, 'Error'); |
+ var name = error_function.name; |
+ var prototype = new GlobalObject(); |
+ if (name !== 'Error') { |
+ %InternalSetPrototype(error_function, GlobalError); |
+ %InternalSetPrototype(prototype, GlobalError.prototype); |
+ } |
+ %FunctionSetPrototype(error_function, prototype); |
+ |
+ %AddNamedProperty(error_function.prototype, 'name', name, DONT_ENUM); |
+ %AddNamedProperty(error_function.prototype, 'message', '', DONT_ENUM); |
+ %AddNamedProperty( |
+ error_function.prototype, 'constructor', error_function, DONT_ENUM); |
+ |
+ %SetCode(error_function, function(m) { |
+ if (IS_UNDEFINED(new.target)) return new error_function(m); |
+ |
+ try { captureStackTrace(this, error_function); } catch (e) { } |
+ // Define all the expected properties directly on the error |
+ // object. This avoids going through getters and setters defined |
+ // on prototype objects. |
+ if (!IS_UNDEFINED(m)) { |
+ %AddNamedProperty(this, 'message', TO_STRING(m), DONT_ENUM); |
+ } |
+ }); |
+ |
+ %SetNativeFlag(error_function); |
+ return error_function; |
+}; |
+ |
+GlobalError = SetUpError(global.Error); |
+GlobalEvalError = SetUpError(global.EvalError); |
+GlobalRangeError = SetUpError(global.RangeError); |
+GlobalReferenceError = SetUpError(global.ReferenceError); |
+GlobalSyntaxError = SetUpError(global.SyntaxError); |
+GlobalTypeError = SetUpError(global.TypeError); |
+GlobalURIError = SetUpError(global.URIError); |
+ |
+utils.InstallFunctions(GlobalError.prototype, DONT_ENUM, |
+ ['toString', ErrorToString]); |
+ |
function ErrorToString() { |
if (!IS_RECEIVER(this)) { |
throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString"); |
@@ -640,9 +728,21 @@ |
// Boilerplate for exceptions for stack overflows. Used from |
// Isolate::StackOverflow(). |
var StackOverflowBoilerplate = MakeRangeError(kStackOverflow); |
+utils.InstallGetterSetter(StackOverflowBoilerplate, 'stack', |
+ StackTraceGetter, StackTraceSetter) |
+ |
+// Define actual captureStackTrace function after everything has been set up. |
+captureStackTrace = function captureStackTrace(obj, cons_opt) { |
+ // Define accessors first, as this may fail and throw. |
+ %object_define_property(obj, 'stack', { get: StackTraceGetter, |
+ set: StackTraceSetter, |
+ configurable: true }); |
+ %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace); |
+}; |
+ |
+GlobalError.captureStackTrace = captureStackTrace; |
%InstallToContext([ |
- "error_format_stack_trace", FormatStackTrace, |
"get_stack_trace_line_fun", GetStackTraceLine, |
"make_error_function", MakeGenericError, |
"make_range_error", MakeRangeError, |