OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/json-stringifier.h" | 5 #include "src/json-stringifier.h" |
6 | 6 |
7 #include "src/conversions.h" | 7 #include "src/conversions.h" |
8 #include "src/lookup.h" | 8 #include "src/lookup.h" |
9 #include "src/messages.h" | 9 #include "src/messages.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 "\370\0 \371\0 \372\0 \373\0 " | 81 "\370\0 \371\0 \372\0 \373\0 " |
82 "\374\0 \375\0 \376\0 \377\0 "; | 82 "\374\0 \375\0 \376\0 \377\0 "; |
83 | 83 |
84 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) | 84 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) |
85 : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) { | 85 : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) { |
86 tojson_string_ = factory()->toJSON_string(); | 86 tojson_string_ = factory()->toJSON_string(); |
87 stack_ = factory()->NewJSArray(8); | 87 stack_ = factory()->NewJSArray(8); |
88 } | 88 } |
89 | 89 |
90 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object, | 90 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object, |
| 91 Handle<Object> replacer, |
91 Handle<Object> gap) { | 92 Handle<Object> gap) { |
| 93 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); |
92 if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); | 94 if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); |
93 Result result = SerializeObject(object); | 95 Result result = SerializeObject(object); |
94 if (result == UNCHANGED) return factory()->undefined_value(); | 96 if (result == UNCHANGED) return factory()->undefined_value(); |
95 if (result == SUCCESS) return builder_.Finish(); | 97 if (result == SUCCESS) return builder_.Finish(); |
96 DCHECK(result == EXCEPTION); | 98 DCHECK(result == EXCEPTION); |
97 return MaybeHandle<Object>(); | 99 return MaybeHandle<Object>(); |
98 } | 100 } |
99 | 101 |
| 102 bool IsInList(Handle<String> key, List<Handle<String> >* list) { |
| 103 // TODO(yangguo): This is O(n^2) for n properties in the list. Deal with this |
| 104 // if this becomes an issue. |
| 105 for (const Handle<String>& existing : *list) { |
| 106 if (String::Equals(existing, key)) return true; |
| 107 } |
| 108 return false; |
| 109 } |
| 110 |
| 111 bool BasicJsonStringifier::InitializeReplacer(Handle<Object> replacer) { |
| 112 DCHECK(property_list_.is_null()); |
| 113 Maybe<bool> is_array = Object::IsArray(replacer); |
| 114 if (is_array.IsNothing()) return false; |
| 115 if (is_array.FromJust()) { |
| 116 HandleScope handle_scope(isolate_); |
| 117 List<Handle<String> > list; |
| 118 Handle<Object> length_obj; |
| 119 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 120 isolate_, length_obj, |
| 121 Object::GetLengthFromArrayLike(isolate_, replacer), false); |
| 122 uint32_t length; |
| 123 if (!length_obj->ToUint32(&length)) length = kMaxUInt32; |
| 124 for (uint32_t i = 0; i < length; i++) { |
| 125 Handle<Object> element; |
| 126 Handle<String> key; |
| 127 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 128 isolate_, element, Object::GetElement(isolate_, replacer, i), false); |
| 129 if (element->IsNumber() || element->IsString()) { |
| 130 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 131 isolate_, key, Object::ToString(isolate_, element), false); |
| 132 } else if (element->IsJSValue()) { |
| 133 Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_); |
| 134 if (value->IsNumber() || value->IsString()) { |
| 135 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 136 isolate_, key, Object::ToString(isolate_, element), false); |
| 137 } |
| 138 } |
| 139 if (key.is_null()) continue; |
| 140 if (!IsInList(key, &list)) list.Add(key); |
| 141 } |
| 142 property_list_ = factory()->NewUninitializedFixedArray(list.length()); |
| 143 for (int i = 0; i < list.length(); i++) { |
| 144 property_list_->set(i, *list[i]); |
| 145 } |
| 146 property_list_ = handle_scope.CloseAndEscape(property_list_); |
| 147 } |
| 148 return true; |
| 149 } |
| 150 |
100 bool BasicJsonStringifier::InitializeGap(Handle<Object> gap) { | 151 bool BasicJsonStringifier::InitializeGap(Handle<Object> gap) { |
101 DCHECK_NULL(gap_); | 152 DCHECK_NULL(gap_); |
102 HandleScope scope(isolate_); | 153 HandleScope scope(isolate_); |
103 if (gap->IsJSReceiver()) { | 154 if (gap->IsJSValue()) { |
104 Handle<String> class_name(Handle<JSReceiver>::cast(gap)->class_name()); | 155 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); |
105 if (class_name.is_identical_to(factory()->String_string())) { | 156 if (value->IsString()) { |
106 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, | 157 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, |
107 Object::ToString(isolate_, gap), false); | 158 Object::ToString(isolate_, gap), false); |
108 } else if (class_name.is_identical_to(factory()->number_string())) { | 159 } else if (value->IsNumber()) { |
109 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), | 160 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), |
110 false); | 161 false); |
111 } | 162 } |
112 } | 163 } |
113 | 164 |
114 if (gap->IsString()) { | 165 if (gap->IsString()) { |
115 Handle<String> gap_string = Handle<String>::cast(gap); | 166 Handle<String> gap_string = Handle<String>::cast(gap); |
116 if (gap_string->length() > 0) { | 167 if (gap_string->length() > 0) { |
117 int gap_length = std::min(gap_string->length(), 10); | 168 int gap_length = std::min(gap_string->length(), 10); |
118 gap_ = NewArray<uc16>(gap_length + 1); | 169 gap_ = NewArray<uc16>(gap_length + 1); |
(...skipping 20 matching lines...) Expand all Loading... |
139 | 190 |
140 MaybeHandle<Object> BasicJsonStringifier::StringifyString( | 191 MaybeHandle<Object> BasicJsonStringifier::StringifyString( |
141 Isolate* isolate, Handle<String> object) { | 192 Isolate* isolate, Handle<String> object) { |
142 static const int kJsonQuoteWorstCaseBlowup = 6; | 193 static const int kJsonQuoteWorstCaseBlowup = 6; |
143 static const int kSpaceForQuotes = 2; | 194 static const int kSpaceForQuotes = 2; |
144 int worst_case_length = | 195 int worst_case_length = |
145 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; | 196 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; |
146 | 197 |
147 if (worst_case_length > 32 * KB) { // Slow path if too large. | 198 if (worst_case_length > 32 * KB) { // Slow path if too large. |
148 BasicJsonStringifier stringifier(isolate); | 199 BasicJsonStringifier stringifier(isolate); |
149 return stringifier.Stringify(object, isolate->factory()->undefined_value()); | 200 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 201 return stringifier.Stringify(object, undefined, undefined); |
150 } | 202 } |
151 | 203 |
152 object = String::Flatten(object); | 204 object = String::Flatten(object); |
153 DCHECK(object->IsFlat()); | 205 DCHECK(object->IsFlat()); |
154 Handle<SeqString> result; | 206 Handle<SeqString> result; |
155 if (object->IsOneByteRepresentationUnderneath()) { | 207 if (object->IsOneByteRepresentationUnderneath()) { |
156 result = isolate->factory() | 208 result = isolate->factory() |
157 ->NewRawOneByteString(worst_case_length) | 209 ->NewRawOneByteString(worst_case_length) |
158 .ToHandleChecked(); | 210 .ToHandleChecked(); |
159 IncrementalStringBuilder::NoExtendString<uint8_t> no_extend( | 211 IncrementalStringBuilder::NoExtendString<uint8_t> no_extend( |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 } | 482 } |
431 return SUCCESS; | 483 return SUCCESS; |
432 } | 484 } |
433 | 485 |
434 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( | 486 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
435 Handle<JSObject> object) { | 487 Handle<JSObject> object) { |
436 HandleScope handle_scope(isolate_); | 488 HandleScope handle_scope(isolate_); |
437 Result stack_push = StackPush(object); | 489 Result stack_push = StackPush(object); |
438 if (stack_push != SUCCESS) return stack_push; | 490 if (stack_push != SUCCESS) return stack_push; |
439 | 491 |
440 if (object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && | 492 if (property_list_.is_null() && |
| 493 object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
441 object->HasFastProperties() && | 494 object->HasFastProperties() && |
442 Handle<JSObject>::cast(object)->elements()->length() == 0) { | 495 Handle<JSObject>::cast(object)->elements()->length() == 0) { |
443 DCHECK(object->IsJSObject()); | 496 DCHECK(object->IsJSObject()); |
444 DCHECK(!object->IsJSGlobalProxy()); | 497 DCHECK(!object->IsJSGlobalProxy()); |
445 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); | 498 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); |
446 DCHECK(!js_obj->HasIndexedInterceptor()); | 499 DCHECK(!js_obj->HasIndexedInterceptor()); |
447 DCHECK(!js_obj->HasNamedInterceptor()); | 500 DCHECK(!js_obj->HasNamedInterceptor()); |
448 Handle<Map> map(js_obj->map()); | 501 Handle<Map> map(js_obj->map()); |
449 builder_.AppendCharacter('{'); | 502 builder_.AppendCharacter('{'); |
450 Indent(); | 503 Indent(); |
(...skipping 29 matching lines...) Expand all Loading... |
480 } else { | 533 } else { |
481 Result result = SerializeJSReceiverSlow(object); | 534 Result result = SerializeJSReceiverSlow(object); |
482 if (result != SUCCESS) return result; | 535 if (result != SUCCESS) return result; |
483 } | 536 } |
484 StackPop(); | 537 StackPop(); |
485 return SUCCESS; | 538 return SUCCESS; |
486 } | 539 } |
487 | 540 |
488 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSReceiverSlow( | 541 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSReceiverSlow( |
489 Handle<JSReceiver> object) { | 542 Handle<JSReceiver> object) { |
490 Handle<FixedArray> contents; | 543 Handle<FixedArray> contents = property_list_; |
491 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 544 if (contents.is_null()) { |
492 isolate_, contents, | 545 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
493 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); | 546 isolate_, contents, |
| 547 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); |
| 548 } |
494 | 549 |
495 builder_.AppendCharacter('{'); | 550 builder_.AppendCharacter('{'); |
496 Indent(); | 551 Indent(); |
497 bool comma = false; | 552 bool comma = false; |
498 for (int i = 0; i < contents->length(); i++) { | 553 for (int i = 0; i < contents->length(); i++) { |
499 Object* key = contents->get(i); | 554 Object* key = contents->get(i); |
500 Handle<String> key_handle; | 555 Handle<String> key_handle; |
501 MaybeHandle<Object> maybe_property; | 556 MaybeHandle<Object> maybe_property; |
502 if (key->IsString()) { | 557 if (key->IsString()) { |
503 key_handle = Handle<String>(String::cast(key), isolate_); | 558 key_handle = Handle<String>(String::cast(key), isolate_); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 if (object->IsOneByteRepresentationUnderneath()) { | 704 if (object->IsOneByteRepresentationUnderneath()) { |
650 SerializeString_<uint8_t, uc16>(object); | 705 SerializeString_<uint8_t, uc16>(object); |
651 } else { | 706 } else { |
652 SerializeString_<uc16, uc16>(object); | 707 SerializeString_<uc16, uc16>(object); |
653 } | 708 } |
654 } | 709 } |
655 } | 710 } |
656 | 711 |
657 } // namespace internal | 712 } // namespace internal |
658 } // namespace v8 | 713 } // namespace v8 |
OLD | NEW |