Index: src/accessors.cc |
diff --git a/src/accessors.cc b/src/accessors.cc |
index 5c89c2552fe840173697654e26efc545552fdf43..2dcc367d36383eb51a70a33fb9563672b94eee97 100644 |
--- a/src/accessors.cc |
+++ b/src/accessors.cc |
@@ -1116,6 +1116,139 @@ Handle<AccessorInfo> Accessors::BoundFunctionNameInfo( |
attributes); |
} |
+// |
+// Accessors::ErrorStack |
+// |
+ |
+namespace { |
+ |
+MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate, |
+ Handle<JSObject> error) { |
+ RETURN_ON_EXCEPTION( |
+ isolate, |
+ JSReceiver::SetProperty(error, isolate->factory()->stack_trace_symbol(), |
+ isolate->factory()->undefined_value(), STRICT), |
+ JSReceiver); |
+ 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, |
+ LookupIterator::OWN_SKIP_INTERCEPTOR); |
+ // Skip any access checks we might hit. This accessor should never hit in a |
+ // situation where the caller does not have access. |
+ if (it.state() == LookupIterator::ACCESS_CHECK) { |
+ CHECK(it.HasAccess()); |
+ it.Next(); |
+ } |
+ return (it.state() == LookupIterator::ACCESSOR); |
+} |
+ |
+} // namespace |
+ |
+void Accessors::ErrorStackGetter( |
+ v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); |
+ HandleScope scope(isolate); |
+ Handle<JSObject> holder = |
+ Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder())); |
+ |
+ // Retrieve the structured stack trace. |
+ |
+ Handle<Object> stack_trace; |
+ Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol(); |
+ MaybeHandle<Object> maybe_stack_trace = |
+ JSObject::GetProperty(holder, stack_trace_symbol); |
+ if (!maybe_stack_trace.ToHandle(&stack_trace) || |
+ stack_trace->IsUndefined(isolate)) { |
+ Handle<Object> result = isolate->factory()->undefined_value(); |
+ info.GetReturnValue().Set(Utils::ToLocal(result)); |
+ return; |
+ } |
+ |
+ // Format it, clear the internal structured trace and reconfigure as a data |
+ // property. |
+ |
+ Handle<Object> formatted_stack_trace; |
+ if (!FormatStackTrace(isolate, holder, stack_trace) |
+ .ToHandle(&formatted_stack_trace)) { |
+ isolate->OptionalRescheduleException(false); |
+ return; |
+ } |
+ |
+ MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder); |
+ if (result.is_null()) { |
+ isolate->OptionalRescheduleException(false); |
+ return; |
+ } |
+ |
+ // If stack is still an accessor (this could have changed in the meantime |
+ // since FormatStackTrace can execute arbitrary JS), replace it with a data |
+ // property. |
+ Handle<Object> receiver = Utils::OpenHandle(*info.This()); |
+ Handle<Name> name = Utils::OpenHandle(*key); |
+ if (IsAccessor(receiver, name, holder)) { |
+ result = ReplaceAccessorWithDataProperty(isolate, receiver, holder, name, |
+ formatted_stack_trace); |
+ if (result.is_null()) { |
+ isolate->OptionalRescheduleException(false); |
+ return; |
+ } |
+ } else { |
+ // The stack property has been modified in the meantime. |
+ if (!JSObject::GetProperty(holder, name).ToHandle(&formatted_stack_trace)) { |
+ isolate->OptionalRescheduleException(false); |
+ return; |
+ } |
+ } |
+ |
+ v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace); |
+ info.GetReturnValue().Set(value); |
+} |
+ |
+void Accessors::ErrorStackSetter(v8::Local<v8::Name> name, |
+ v8::Local<v8::Value> val, |
+ const v8::PropertyCallbackInfo<void>& info) { |
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); |
+ HandleScope scope(isolate); |
+ Handle<JSObject> obj = |
+ Handle<JSObject>::cast(Utils::OpenHandle(*info.This())); |
+ |
+ // Clear internal properties to avoid memory leaks. |
+ Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol(); |
+ if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) { |
+ ClearInternalStackTrace(isolate, obj); |
+ } |
+ |
+ Accessors::ReconfigureToDataProperty(name, val, info); |
+} |
+ |
+Handle<AccessorInfo> Accessors::ErrorStackInfo(Isolate* isolate, |
+ PropertyAttributes attributes) { |
+ Handle<AccessorInfo> info = |
+ MakeAccessor(isolate, isolate->factory()->stack_string(), |
+ &ErrorStackGetter, &ErrorStackSetter, attributes); |
+ return info; |
+} |
} // namespace internal |
} // namespace v8 |