Chromium Code Reviews| Index: src/messages.cc |
| diff --git a/src/messages.cc b/src/messages.cc |
| index ebec3532fe2a4ca9b1505af9e0bc35281dd95a88..767781913ed60b8bf949fdf55f948bb97ec84ad7 100644 |
| --- a/src/messages.cc |
| +++ b/src/messages.cc |
| @@ -368,5 +368,98 @@ 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.HasVisited()) 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()->NewStringFromStaticChars("name"); |
|
Jakob Kummerow
2015/08/08 21:56:09
we already have 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 |