Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 38deeb825d4b291c707d5e76c1f3cffbf4f1b94a..0dd06f4c5f04a14173e41dcfc16cb466a5cbb227 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -219,6 +219,168 @@ MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) { |
| } |
| } |
| +namespace { |
| + |
| +bool IsErrorObject(Isolate* isolate, Handle<Object> object) { |
| + if (!object->IsJSReceiver()) return false; |
| + Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol(); |
| + return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol) |
| + .FromMaybe(false); |
| +} |
| + |
| +Handle<String> NoSideEffectsErrorToString(Isolate* isolate, |
| + Handle<Object> input) { |
| + Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); |
| + |
| + Handle<Name> name_key = isolate->factory()->name_string(); |
| + Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key); |
| + Handle<String> name_str = (name->IsUndefined(isolate)) |
| + ? isolate->factory()->Error_string() |
| + : Object::NoSideEffectsToString(isolate, name); |
| + |
| + Handle<Name> msg_key = isolate->factory()->message_string(); |
| + Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key); |
| + Handle<String> msg_str = (msg->IsUndefined(isolate)) |
| + ? isolate->factory()->empty_string() |
| + : Object::NoSideEffectsToString(isolate, msg); |
| + |
| + if (name_str->length() == 0) return msg_str; |
| + if (msg_str->length() == 0) return name_str; |
| + |
| + IncrementalStringBuilder builder(isolate); |
| + builder.AppendString(name_str); |
| + builder.AppendCString(": "); |
| + builder.AppendString(msg_str); |
| + |
| + return builder.Finish().ToHandleChecked(); |
| +} |
| + |
| +} // namespace |
| + |
| +// static |
| +Handle<String> Object::NoSideEffectsToString(Isolate* isolate, |
| + Handle<Object> input) { |
| + if (input->IsString()) { |
| + // -- S t r i n g |
| + return Handle<String>::cast(input); |
| + } else if (input->IsNumber()) { |
| + // -- N u m b e r |
| + return isolate->factory()->NumberToString(input); |
| + } else if (input->IsBoolean()) { |
| + // -- B o o l e a n |
| + return input->BooleanValue() ? isolate->factory()->true_string() |
| + : isolate->factory()->false_string(); |
| + } else if (input->IsUndefined(isolate)) { |
| + // -- U n d e f i n e d |
| + return isolate->factory()->undefined_string(); |
| + } else if (input->IsNull(isolate)) { |
| + // -- N u l l |
| + return isolate->factory()->null_string(); |
|
Yang
2016/08/03 09:13:18
Can we defer to Object::ToString for these cases a
jgruber
2016/08/03 11:17:15
Done.
|
| + } else if (input->IsFunction()) { |
| + // -- F u n c t i o n |
| + Handle<String> fun_str; |
| + if (input->IsJSBoundFunction()) { |
| + fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input)); |
| + } else { |
| + DCHECK(input->IsJSFunction()); |
| + fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input)); |
| + } |
| + |
| + if (fun_str->length() > 128) { |
| + IncrementalStringBuilder builder(isolate); |
| + builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); |
| + builder.AppendCString("...<omitted>..."); |
| + builder.AppendString(isolate->factory()->NewSubString( |
| + fun_str, fun_str->length() - 2, fun_str->length())); |
| + |
| + return builder.Finish().ToHandleChecked(); |
| + } |
| + return fun_str; |
| + } else if (input->IsSymbol()) { |
| + // -- S y m b o l |
| + Handle<Symbol> symbol = Handle<Symbol>::cast(input); |
| + |
| + IncrementalStringBuilder builder(isolate); |
| + builder.AppendCString("Symbol("); |
| + if (symbol->name()->IsString()) { |
| + builder.AppendString(handle(String::cast(symbol->name()), isolate)); |
| + } |
| + builder.AppendCharacter(')'); |
| + |
| + return builder.Finish().ToHandleChecked(); |
| + } else if (input->IsSimd128Value()) { |
|
Yang
2016/08/03 09:13:18
Same for simd
jgruber
2016/08/03 11:17:15
Done.
|
| + // -- S i m d 1 2 8 V a l u e |
| + return Simd128Value::ToString(Handle<Simd128Value>::cast(input)); |
| + } else if (input->IsJSReceiver()) { |
| + // -- J S R e c e i v e r |
| + Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input); |
| + Handle<Object> to_string = JSReceiver::GetDataProperty( |
| + receiver, isolate->factory()->toString_string()); |
| + |
| + if (IsErrorObject(isolate, input) || |
| + *to_string == *isolate->error_to_string()) { |
| + // When internally formatting error objects, use a side-effects-free |
| + // version of Error.prototype.toString independent of the actually |
| + // installed toString method. |
| + return NoSideEffectsErrorToString(isolate, input); |
| + } else if (*to_string == *isolate->object_to_string()) { |
| + Handle<Object> ctor = JSReceiver::GetDataProperty( |
| + receiver, isolate->factory()->constructor_string()); |
| + if (ctor->IsFunction()) { |
| + Handle<String> ctor_name; |
| + if (ctor->IsJSBoundFunction()) { |
| + ctor_name = JSBoundFunction::GetName( |
| + isolate, Handle<JSBoundFunction>::cast(ctor)) |
| + .ToHandleChecked(); |
| + } else if (ctor->IsJSFunction()) { |
| + Handle<Object> ctor_name_obj = |
| + JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor)); |
| + ctor_name = NoSideEffectsToString(isolate, ctor_name_obj); |
| + } |
| + |
| + if (ctor_name->length() != 0) { |
| + IncrementalStringBuilder builder(isolate); |
| + builder.AppendCString("#<"); |
| + builder.AppendString(ctor_name); |
| + builder.AppendCString(">"); |
| + |
| + return builder.Finish().ToHandleChecked(); |
| + } |
| + } |
| + } |
| + } |
| + |
| + // At this point, input is either none of the above or a JSReceiver. |
| + |
| + Handle<JSReceiver> receiver; |
| + if (input->IsJSReceiver()) { |
| + receiver = Handle<JSReceiver>::cast(input); |
| + } else { |
| + // This is the only case where Object::ToObject throws. |
| + DCHECK(!input->IsSmi()); |
| + int constructor_function_index = |
| + Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex(); |
| + if (constructor_function_index == Map::kNoConstructorFunctionIndex) { |
| + return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]"); |
| + } |
| + |
| + receiver = Object::ToObject(isolate, input, isolate->native_context()) |
| + .ToHandleChecked(); |
| + } |
| + |
| + Handle<String> builtin_tag = handle(receiver->class_name(), isolate); |
| + Handle<Object> tag_obj = JSReceiver::GetDataProperty( |
| + receiver, isolate->factory()->to_string_tag_symbol()); |
| + Handle<String> tag = |
| + tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag; |
| + |
| + IncrementalStringBuilder builder(isolate); |
| + builder.AppendCString("[object "); |
| + builder.AppendString(tag); |
| + builder.AppendCString("]"); |
| + |
| + return builder.Finish().ToHandleChecked(); |
| +} |
| // static |
| MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) { |