Index: src/messages.cc |
diff --git a/src/messages.cc b/src/messages.cc |
index 55edfa89c45f96198c3d4df3dfa3499321a6a9b3..306fcc503f4ff4d34e75823bc6ced8246e7fd89d 100644 |
--- a/src/messages.cc |
+++ b/src/messages.cc |
@@ -367,5 +367,97 @@ MaybeHandle<String> MessageTemplate::FormatMessage(int template_index, |
return builder.Finish(); |
} |
+ |
+ |
+MaybeHandle<String> ErrorToStringHelper::Stringify(Isolate* isolate, |
+ Handle<JSObject> error) { |
+ VisitedScope scope(this, error); |
+ if (scope.has_visited()) return isolate->factory()->empty_string(); |
+ |
+ Handle<String> name; |
+ Handle<String> message; |
+ Handle<Name> internal_key = isolate->factory()->internal_error_symbol(); |
+ Handle<String> message_string = |
+ isolate->factory()->NewStringFromStaticChars("message"); |
+ Handle<String> name_string = isolate->factory()->name_string(); |
+ LookupIterator internal_error_lookup( |
+ error, internal_key, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); |
+ LookupIterator message_lookup( |
+ error, message_string, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); |
+ LookupIterator name_lookup(error, name_string, |
+ LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); |
+ |
+ // Find out whether an internally created error object is on the prototype |
+ // chain. If the name property is found on a holder prior to the internally |
+ // created error object, use that name property. Otherwise just use the |
+ // constructor name to avoid triggering possible side effects. |
+ // Similar for the message property. If the message property shadows the |
+ // internally created error object, use that message property. Otherwise |
+ // use empty string as message. |
+ if (internal_error_lookup.IsFound()) { |
+ if (!ShadowsInternalError(isolate, &name_lookup, &internal_error_lookup)) { |
+ Handle<JSObject> holder = internal_error_lookup.GetHolder<JSObject>(); |
+ name = Handle<String>(holder->constructor_name()); |
+ } |
+ if (!ShadowsInternalError(isolate, &message_lookup, |
+ &internal_error_lookup)) { |
+ message = isolate->factory()->empty_string(); |
+ } |
+ } |
+ if (name.is_null()) { |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, name, |
+ GetStringifiedProperty(isolate, &name_lookup, |
+ isolate->factory()->Error_string()), |
+ String); |
+ } |
+ if (message.is_null()) { |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, message, |
+ GetStringifiedProperty(isolate, &message_lookup, |
+ isolate->factory()->empty_string()), |
+ String); |
+ } |
+ |
+ if (name->length() == 0) return message; |
+ if (message->length() == 0) return name; |
+ IncrementalStringBuilder builder(isolate); |
+ builder.AppendString(name); |
+ builder.AppendCString(": "); |
+ builder.AppendString(message); |
+ return builder.Finish(); |
+} |
+ |
+ |
+bool ErrorToStringHelper::ShadowsInternalError( |
+ Isolate* isolate, LookupIterator* property_lookup, |
+ LookupIterator* internal_error_lookup) { |
+ Handle<JSObject> holder = property_lookup->GetHolder<JSObject>(); |
+ // It's fine if the property is defined on the error itself. |
+ if (holder.is_identical_to(property_lookup->GetReceiver())) return true; |
+ PrototypeIterator it(isolate, holder, PrototypeIterator::START_AT_RECEIVER); |
+ while (true) { |
+ if (it.IsAtEnd()) return false; |
+ if (it.IsAtEnd(internal_error_lookup->GetHolder<JSObject>())) return true; |
+ it.AdvanceIgnoringProxies(); |
+ } |
+} |
+ |
+ |
+MaybeHandle<String> ErrorToStringHelper::GetStringifiedProperty( |
+ Isolate* isolate, LookupIterator* property_lookup, |
+ Handle<String> default_value) { |
+ if (!property_lookup->IsFound()) return default_value; |
+ Handle<Object> obj; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::GetProperty(property_lookup), |
+ String); |
+ if (obj->IsUndefined()) return default_value; |
+ if (!obj->IsString()) { |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Execution::ToString(isolate, obj), |
+ String); |
+ } |
+ return Handle<String>::cast(obj); |
+} |
+ |
} // namespace internal |
} // namespace v8 |