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" |
11 #include "src/utils.h" | 11 #include "src/utils.h" |
12 | 12 |
13 namespace v8 { | 13 namespace v8 { |
14 namespace internal { | 14 namespace internal { |
15 | 15 |
16 // Translation table to escape Latin1 characters. | 16 // Translation table to escape Latin1 characters. |
17 // Table entries start at a multiple of 8 and are null-terminated. | 17 // Table entries start at a multiple of 8 and are null-terminated. |
18 const char* const JsonStringifier::JsonEscapeTable = | 18 const char* const BasicJsonStringifier::JsonEscapeTable = |
19 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " | 19 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " |
20 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " | 20 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " |
21 "\\b\0 \\t\0 \\n\0 \\u000b\0 " | 21 "\\b\0 \\t\0 \\n\0 \\u000b\0 " |
22 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " | 22 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " |
23 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " | 23 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " |
24 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " | 24 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " |
25 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " | 25 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " |
26 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " | 26 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " |
27 " \0 !\0 \\\"\0 #\0 " | 27 " \0 !\0 \\\"\0 #\0 " |
28 "$\0 %\0 &\0 '\0 " | 28 "$\0 %\0 &\0 '\0 " |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 "\334\0 \335\0 \336\0 \337\0 " | 74 "\334\0 \335\0 \336\0 \337\0 " |
75 "\340\0 \341\0 \342\0 \343\0 " | 75 "\340\0 \341\0 \342\0 \343\0 " |
76 "\344\0 \345\0 \346\0 \347\0 " | 76 "\344\0 \345\0 \346\0 \347\0 " |
77 "\350\0 \351\0 \352\0 \353\0 " | 77 "\350\0 \351\0 \352\0 \353\0 " |
78 "\354\0 \355\0 \356\0 \357\0 " | 78 "\354\0 \355\0 \356\0 \357\0 " |
79 "\360\0 \361\0 \362\0 \363\0 " | 79 "\360\0 \361\0 \362\0 \363\0 " |
80 "\364\0 \365\0 \366\0 \367\0 " | 80 "\364\0 \365\0 \366\0 \367\0 " |
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 JsonStringifier::JsonStringifier(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> JsonStringifier::Stringify(Handle<Object> object, | 90 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object, |
91 Handle<Object> replacer, | 91 Handle<Object> replacer, |
92 Handle<Object> gap) { | 92 Handle<Object> gap) { |
93 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); | 93 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); |
94 if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); | 94 if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); |
95 Result result = SerializeObject(object); | 95 Result result = SerializeObject(object); |
96 if (result == UNCHANGED) return factory()->undefined_value(); | 96 if (result == UNCHANGED) return factory()->undefined_value(); |
97 if (result == SUCCESS) return builder_.Finish(); | 97 if (result == SUCCESS) return builder_.Finish(); |
98 DCHECK(result == EXCEPTION); | 98 DCHECK(result == EXCEPTION); |
99 return MaybeHandle<Object>(); | 99 return MaybeHandle<Object>(); |
100 } | 100 } |
101 | 101 |
102 bool IsInList(Handle<String> key, List<Handle<String> >* list) { | 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 | 103 // TODO(yangguo): This is O(n^2) for n properties in the list. Deal with this |
104 // if this becomes an issue. | 104 // if this becomes an issue. |
105 for (const Handle<String>& existing : *list) { | 105 for (const Handle<String>& existing : *list) { |
106 if (String::Equals(existing, key)) return true; | 106 if (String::Equals(existing, key)) return true; |
107 } | 107 } |
108 return false; | 108 return false; |
109 } | 109 } |
110 | 110 |
111 bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) { | 111 bool BasicJsonStringifier::InitializeReplacer(Handle<Object> replacer) { |
112 DCHECK(property_list_.is_null()); | 112 DCHECK(property_list_.is_null()); |
113 DCHECK(replacer_function_.is_null()); | |
114 Maybe<bool> is_array = Object::IsArray(replacer); | 113 Maybe<bool> is_array = Object::IsArray(replacer); |
115 if (is_array.IsNothing()) return false; | 114 if (is_array.IsNothing()) return false; |
116 if (is_array.FromJust()) { | 115 if (is_array.FromJust()) { |
117 HandleScope handle_scope(isolate_); | 116 HandleScope handle_scope(isolate_); |
118 List<Handle<String> > list; | 117 List<Handle<String> > list; |
119 Handle<Object> length_obj; | 118 Handle<Object> length_obj; |
120 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 119 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
121 isolate_, length_obj, | 120 isolate_, length_obj, |
122 Object::GetLengthFromArrayLike(isolate_, replacer), false); | 121 Object::GetLengthFromArrayLike(isolate_, replacer), false); |
123 uint32_t length; | 122 uint32_t length; |
(...skipping 14 matching lines...) Expand all Loading... |
138 } | 137 } |
139 } | 138 } |
140 if (key.is_null()) continue; | 139 if (key.is_null()) continue; |
141 if (!IsInList(key, &list)) list.Add(key); | 140 if (!IsInList(key, &list)) list.Add(key); |
142 } | 141 } |
143 property_list_ = factory()->NewUninitializedFixedArray(list.length()); | 142 property_list_ = factory()->NewUninitializedFixedArray(list.length()); |
144 for (int i = 0; i < list.length(); i++) { | 143 for (int i = 0; i < list.length(); i++) { |
145 property_list_->set(i, *list[i]); | 144 property_list_->set(i, *list[i]); |
146 } | 145 } |
147 property_list_ = handle_scope.CloseAndEscape(property_list_); | 146 property_list_ = handle_scope.CloseAndEscape(property_list_); |
148 } else if (replacer->IsCallable()) { | |
149 replacer_function_ = Handle<JSReceiver>::cast(replacer); | |
150 } | 147 } |
151 return true; | 148 return true; |
152 } | 149 } |
153 | 150 |
154 bool JsonStringifier::InitializeGap(Handle<Object> gap) { | 151 bool BasicJsonStringifier::InitializeGap(Handle<Object> gap) { |
155 DCHECK_NULL(gap_); | 152 DCHECK_NULL(gap_); |
156 HandleScope scope(isolate_); | 153 HandleScope scope(isolate_); |
157 if (gap->IsJSValue()) { | 154 if (gap->IsJSValue()) { |
158 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); | 155 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); |
159 if (value->IsString()) { | 156 if (value->IsString()) { |
160 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, | 157 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, |
161 Object::ToString(isolate_, gap), false); | 158 Object::ToString(isolate_, gap), false); |
162 } else if (value->IsNumber()) { | 159 } else if (value->IsNumber()) { |
163 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), | 160 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), |
164 false); | 161 false); |
(...skipping 19 matching lines...) Expand all Loading... |
184 if (num_value > 0) { | 181 if (num_value > 0) { |
185 int gap_length = std::min(num_value, 10); | 182 int gap_length = std::min(num_value, 10); |
186 gap_ = NewArray<uc16>(gap_length + 1); | 183 gap_ = NewArray<uc16>(gap_length + 1); |
187 for (int i = 0; i < gap_length; i++) gap_[i] = ' '; | 184 for (int i = 0; i < gap_length; i++) gap_[i] = ' '; |
188 gap_[gap_length] = '\0'; | 185 gap_[gap_length] = '\0'; |
189 } | 186 } |
190 } | 187 } |
191 return true; | 188 return true; |
192 } | 189 } |
193 | 190 |
194 MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object, | 191 MaybeHandle<Object> BasicJsonStringifier::StringifyString( |
195 Handle<Object> key) { | 192 Isolate* isolate, Handle<String> object) { |
196 HandleScope scope(isolate_); | 193 static const int kJsonQuoteWorstCaseBlowup = 6; |
| 194 static const int kSpaceForQuotes = 2; |
| 195 int worst_case_length = |
| 196 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; |
| 197 |
| 198 if (worst_case_length > 32 * KB) { // Slow path if too large. |
| 199 BasicJsonStringifier stringifier(isolate); |
| 200 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 201 return stringifier.Stringify(object, undefined, undefined); |
| 202 } |
| 203 |
| 204 object = String::Flatten(object); |
| 205 DCHECK(object->IsFlat()); |
| 206 Handle<SeqString> result; |
| 207 if (object->IsOneByteRepresentationUnderneath()) { |
| 208 result = isolate->factory() |
| 209 ->NewRawOneByteString(worst_case_length) |
| 210 .ToHandleChecked(); |
| 211 IncrementalStringBuilder::NoExtendString<uint8_t> no_extend( |
| 212 result, worst_case_length); |
| 213 no_extend.Append('\"'); |
| 214 SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(), |
| 215 &no_extend); |
| 216 no_extend.Append('\"'); |
| 217 return no_extend.Finalize(); |
| 218 } else { |
| 219 result = isolate->factory() |
| 220 ->NewRawTwoByteString(worst_case_length) |
| 221 .ToHandleChecked(); |
| 222 IncrementalStringBuilder::NoExtendString<uc16> no_extend(result, |
| 223 worst_case_length); |
| 224 no_extend.Append('\"'); |
| 225 SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(), |
| 226 &no_extend); |
| 227 no_extend.Append('\"'); |
| 228 return no_extend.Finalize(); |
| 229 } |
| 230 } |
| 231 |
| 232 MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction( |
| 233 Handle<Object> object, Handle<Object> key) { |
197 LookupIterator it(object, tojson_string_, | 234 LookupIterator it(object, tojson_string_, |
198 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); | 235 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); |
199 Handle<Object> fun; | 236 Handle<Object> fun; |
200 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); | 237 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); |
201 if (!fun->IsCallable()) return object; | 238 if (!fun->IsCallable()) return object; |
202 | 239 |
203 // Call toJSON function. | 240 // Call toJSON function. |
204 if (key->IsSmi()) key = factory()->NumberToString(key); | 241 if (key->IsSmi()) key = factory()->NumberToString(key); |
205 Handle<Object> argv[] = {key}; | 242 Handle<Object> argv[] = {key}; |
| 243 HandleScope scope(isolate_); |
206 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object, | 244 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object, |
207 Execution::Call(isolate_, fun, object, 1, argv), | 245 Execution::Call(isolate_, fun, object, 1, argv), |
208 Object); | 246 Object); |
209 return scope.CloseAndEscape(object); | 247 return scope.CloseAndEscape(object); |
210 } | 248 } |
211 | 249 |
212 MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction( | 250 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( |
213 Handle<Object> object, Handle<Object> key) { | 251 Handle<Object> object) { |
214 HandleScope scope(isolate_); | |
215 if (key->IsSmi()) key = factory()->NumberToString(key); | |
216 Handle<Object> argv[] = {key, object}; | |
217 Handle<JSReceiver> holder = CurrentHolder(object); | |
218 ASSIGN_RETURN_ON_EXCEPTION( | |
219 isolate_, object, | |
220 Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object); | |
221 return scope.CloseAndEscape(object); | |
222 } | |
223 | |
224 Handle<JSReceiver> JsonStringifier::CurrentHolder(Handle<Object> value) { | |
225 int length = Smi::cast(stack_->length())->value(); | |
226 if (length == 0) { | |
227 Handle<JSObject> holder = | |
228 factory()->NewJSObject(isolate_->object_function()); | |
229 JSObject::AddProperty(holder, factory()->empty_string(), value, NONE); | |
230 return holder; | |
231 } else { | |
232 FixedArray* elements = FixedArray::cast(stack_->elements()); | |
233 return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)), | |
234 isolate_); | |
235 } | |
236 } | |
237 | |
238 JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) { | |
239 StackLimitCheck check(isolate_); | 252 StackLimitCheck check(isolate_); |
240 if (check.HasOverflowed()) { | 253 if (check.HasOverflowed()) { |
241 isolate_->StackOverflow(); | 254 isolate_->StackOverflow(); |
242 return EXCEPTION; | 255 return EXCEPTION; |
243 } | 256 } |
244 | 257 |
245 int length = Smi::cast(stack_->length())->value(); | 258 int length = Smi::cast(stack_->length())->value(); |
246 { | 259 { |
247 DisallowHeapAllocation no_allocation; | 260 DisallowHeapAllocation no_allocation; |
248 FixedArray* elements = FixedArray::cast(stack_->elements()); | 261 FixedArray* elements = FixedArray::cast(stack_->elements()); |
249 for (int i = 0; i < length; i++) { | 262 for (int i = 0; i < length; i++) { |
250 if (elements->get(i) == *object) { | 263 if (elements->get(i) == *object) { |
251 AllowHeapAllocation allow_to_return_error; | 264 AllowHeapAllocation allow_to_return_error; |
252 Handle<Object> error = | 265 Handle<Object> error = |
253 factory()->NewTypeError(MessageTemplate::kCircularStructure); | 266 factory()->NewTypeError(MessageTemplate::kCircularStructure); |
254 isolate_->Throw(*error); | 267 isolate_->Throw(*error); |
255 return EXCEPTION; | 268 return EXCEPTION; |
256 } | 269 } |
257 } | 270 } |
258 } | 271 } |
259 JSArray::SetLength(stack_, length + 1); | 272 JSArray::SetLength(stack_, length + 1); |
260 FixedArray::cast(stack_->elements())->set(length, *object); | 273 FixedArray::cast(stack_->elements())->set(length, *object); |
261 return SUCCESS; | 274 return SUCCESS; |
262 } | 275 } |
263 | 276 |
264 void JsonStringifier::StackPop() { | 277 void BasicJsonStringifier::StackPop() { |
265 int length = Smi::cast(stack_->length())->value(); | 278 int length = Smi::cast(stack_->length())->value(); |
266 stack_->set_length(Smi::FromInt(length - 1)); | 279 stack_->set_length(Smi::FromInt(length - 1)); |
267 } | 280 } |
268 | 281 |
269 template <bool deferred_string_key> | 282 template <bool deferred_string_key> |
270 JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object, | 283 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( |
271 bool comma, | 284 Handle<Object> object, bool comma, Handle<Object> key) { |
272 Handle<Object> key) { | |
273 if (object->IsJSReceiver()) { | 285 if (object->IsJSReceiver()) { |
274 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 286 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
275 isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION); | 287 isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION); |
276 } | 288 } |
277 if (!replacer_function_.is_null()) { | |
278 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
279 isolate_, object, ApplyReplacerFunction(object, key), EXCEPTION); | |
280 } | |
281 | 289 |
282 if (object->IsSmi()) { | 290 if (object->IsSmi()) { |
283 if (deferred_string_key) SerializeDeferredKey(comma, key); | 291 if (deferred_string_key) SerializeDeferredKey(comma, key); |
284 return SerializeSmi(Smi::cast(*object)); | 292 return SerializeSmi(Smi::cast(*object)); |
285 } | 293 } |
286 | 294 |
287 switch (HeapObject::cast(*object)->map()->instance_type()) { | 295 switch (HeapObject::cast(*object)->map()->instance_type()) { |
288 case HEAP_NUMBER_TYPE: | 296 case HEAP_NUMBER_TYPE: |
289 case MUTABLE_HEAP_NUMBER_TYPE: | 297 case MUTABLE_HEAP_NUMBER_TYPE: |
290 if (deferred_string_key) SerializeDeferredKey(comma, key); | 298 if (deferred_string_key) SerializeDeferredKey(comma, key); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 return SerializeJSProxy(Handle<JSProxy>::cast(object)); | 337 return SerializeJSProxy(Handle<JSProxy>::cast(object)); |
330 } | 338 } |
331 return SerializeJSObject(Handle<JSObject>::cast(object)); | 339 return SerializeJSObject(Handle<JSObject>::cast(object)); |
332 } | 340 } |
333 } | 341 } |
334 | 342 |
335 UNREACHABLE(); | 343 UNREACHABLE(); |
336 return UNCHANGED; | 344 return UNCHANGED; |
337 } | 345 } |
338 | 346 |
339 JsonStringifier::Result JsonStringifier::SerializeJSValue( | 347 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( |
340 Handle<JSValue> object) { | 348 Handle<JSValue> object) { |
341 String* class_name = object->class_name(); | 349 String* class_name = object->class_name(); |
342 if (class_name == isolate_->heap()->String_string()) { | 350 if (class_name == isolate_->heap()->String_string()) { |
343 Handle<Object> value; | 351 Handle<Object> value; |
344 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 352 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
345 isolate_, value, Object::ToString(isolate_, object), EXCEPTION); | 353 isolate_, value, Object::ToString(isolate_, object), EXCEPTION); |
346 SerializeString(Handle<String>::cast(value)); | 354 SerializeString(Handle<String>::cast(value)); |
347 } else if (class_name == isolate_->heap()->Number_string()) { | 355 } else if (class_name == isolate_->heap()->Number_string()) { |
348 Handle<Object> value; | 356 Handle<Object> value; |
349 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object), | 357 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object), |
350 EXCEPTION); | 358 EXCEPTION); |
351 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); | 359 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); |
352 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); | 360 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); |
353 } else if (class_name == isolate_->heap()->Boolean_string()) { | 361 } else if (class_name == isolate_->heap()->Boolean_string()) { |
354 Object* value = JSValue::cast(*object)->value(); | 362 Object* value = JSValue::cast(*object)->value(); |
355 DCHECK(value->IsBoolean()); | 363 DCHECK(value->IsBoolean()); |
356 builder_.AppendCString(value->IsTrue() ? "true" : "false"); | 364 builder_.AppendCString(value->IsTrue() ? "true" : "false"); |
357 } else { | 365 } else { |
358 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. | 366 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. |
359 return SerializeJSObject(object); | 367 return SerializeJSObject(object); |
360 } | 368 } |
361 return SUCCESS; | 369 return SUCCESS; |
362 } | 370 } |
363 | 371 |
364 JsonStringifier::Result JsonStringifier::SerializeSmi(Smi* object) { | 372 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { |
365 static const int kBufferSize = 100; | 373 static const int kBufferSize = 100; |
366 char chars[kBufferSize]; | 374 char chars[kBufferSize]; |
367 Vector<char> buffer(chars, kBufferSize); | 375 Vector<char> buffer(chars, kBufferSize); |
368 builder_.AppendCString(IntToCString(object->value(), buffer)); | 376 builder_.AppendCString(IntToCString(object->value(), buffer)); |
369 return SUCCESS; | 377 return SUCCESS; |
370 } | 378 } |
371 | 379 |
372 JsonStringifier::Result JsonStringifier::SerializeDouble(double number) { | 380 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( |
| 381 double number) { |
373 if (std::isinf(number) || std::isnan(number)) { | 382 if (std::isinf(number) || std::isnan(number)) { |
374 builder_.AppendCString("null"); | 383 builder_.AppendCString("null"); |
375 return SUCCESS; | 384 return SUCCESS; |
376 } | 385 } |
377 static const int kBufferSize = 100; | 386 static const int kBufferSize = 100; |
378 char chars[kBufferSize]; | 387 char chars[kBufferSize]; |
379 Vector<char> buffer(chars, kBufferSize); | 388 Vector<char> buffer(chars, kBufferSize); |
380 builder_.AppendCString(DoubleToCString(number, buffer)); | 389 builder_.AppendCString(DoubleToCString(number, buffer)); |
381 return SUCCESS; | 390 return SUCCESS; |
382 } | 391 } |
383 | 392 |
384 JsonStringifier::Result JsonStringifier::SerializeJSArray( | 393 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( |
385 Handle<JSArray> object) { | 394 Handle<JSArray> object) { |
386 HandleScope handle_scope(isolate_); | 395 HandleScope handle_scope(isolate_); |
387 Result stack_push = StackPush(object); | 396 Result stack_push = StackPush(object); |
388 if (stack_push != SUCCESS) return stack_push; | 397 if (stack_push != SUCCESS) return stack_push; |
389 uint32_t length = 0; | 398 uint32_t length = 0; |
390 CHECK(object->length()->ToArrayLength(&length)); | 399 CHECK(object->length()->ToArrayLength(&length)); |
391 DCHECK(!object->IsAccessCheckNeeded()); | 400 DCHECK(!object->IsAccessCheckNeeded()); |
392 builder_.AppendCharacter('['); | 401 builder_.AppendCharacter('['); |
393 Indent(); | 402 Indent(); |
394 uint32_t i = 0; | 403 switch (object->GetElementsKind()) { |
395 if (replacer_function_.is_null()) { | 404 case FAST_SMI_ELEMENTS: { |
396 switch (object->GetElementsKind()) { | 405 Handle<FixedArray> elements(FixedArray::cast(object->elements()), |
397 case FAST_SMI_ELEMENTS: { | 406 isolate_); |
398 Handle<FixedArray> elements(FixedArray::cast(object->elements()), | 407 for (uint32_t i = 0; i < length; i++) { |
399 isolate_); | 408 Separator(i == 0); |
400 while (i < length) { | 409 SerializeSmi(Smi::cast(elements->get(i))); |
401 Separator(i == 0); | 410 } |
402 SerializeSmi(Smi::cast(elements->get(i))); | 411 break; |
403 i++; | 412 } |
| 413 case FAST_DOUBLE_ELEMENTS: { |
| 414 // Empty array is FixedArray but not FixedDoubleArray. |
| 415 if (length == 0) break; |
| 416 Handle<FixedDoubleArray> elements( |
| 417 FixedDoubleArray::cast(object->elements()), isolate_); |
| 418 for (uint32_t i = 0; i < length; i++) { |
| 419 Separator(i == 0); |
| 420 SerializeDouble(elements->get_scalar(i)); |
| 421 } |
| 422 break; |
| 423 } |
| 424 case FAST_ELEMENTS: { |
| 425 Handle<Object> old_length(object->length(), isolate_); |
| 426 for (uint32_t i = 0; i < length; i++) { |
| 427 if (object->length() != *old_length || |
| 428 object->GetElementsKind() != FAST_ELEMENTS) { |
| 429 Result result = SerializeArrayLikeSlow(object, i, length); |
| 430 if (result != SUCCESS) return result; |
| 431 break; |
404 } | 432 } |
405 break; | 433 Separator(i == 0); |
| 434 Result result = SerializeElement( |
| 435 isolate_, |
| 436 Handle<Object>(FixedArray::cast(object->elements())->get(i), |
| 437 isolate_), |
| 438 i); |
| 439 if (result == SUCCESS) continue; |
| 440 if (result == UNCHANGED) { |
| 441 builder_.AppendCString("null"); |
| 442 } else { |
| 443 return result; |
| 444 } |
406 } | 445 } |
407 case FAST_DOUBLE_ELEMENTS: { | 446 break; |
408 // Empty array is FixedArray but not FixedDoubleArray. | |
409 if (length == 0) break; | |
410 Handle<FixedDoubleArray> elements( | |
411 FixedDoubleArray::cast(object->elements()), isolate_); | |
412 while (i < length) { | |
413 Separator(i == 0); | |
414 SerializeDouble(elements->get_scalar(i)); | |
415 i++; | |
416 } | |
417 break; | |
418 } | |
419 case FAST_ELEMENTS: { | |
420 Handle<Object> old_length(object->length(), isolate_); | |
421 while (i < length) { | |
422 if (object->length() != *old_length || | |
423 object->GetElementsKind() != FAST_ELEMENTS) { | |
424 // Fall back to slow path. | |
425 break; | |
426 } | |
427 Separator(i == 0); | |
428 Result result = SerializeElement( | |
429 isolate_, | |
430 Handle<Object>(FixedArray::cast(object->elements())->get(i), | |
431 isolate_), | |
432 i); | |
433 if (result == UNCHANGED) { | |
434 builder_.AppendCString("null"); | |
435 } else if (result != SUCCESS) { | |
436 return result; | |
437 } | |
438 i++; | |
439 } | |
440 break; | |
441 } | |
442 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble | |
443 // the non-holey cases except that a lookup is necessary for holes. | |
444 default: | |
445 break; | |
446 } | 447 } |
447 } | 448 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble |
448 if (i < length) { | 449 // the non-holey cases except that a lookup is necessary for holes. |
449 // Slow path for non-fast elements and fall-back in edge case. | 450 default: { |
450 Result result = SerializeArrayLikeSlow(object, i, length); | 451 Result result = SerializeArrayLikeSlow(object, 0, length); |
451 if (result != SUCCESS) return result; | 452 if (result != SUCCESS) return result; |
| 453 break; |
| 454 } |
452 } | 455 } |
453 Unindent(); | 456 Unindent(); |
454 if (length > 0) NewLine(); | 457 if (length > 0) NewLine(); |
455 builder_.AppendCharacter(']'); | 458 builder_.AppendCharacter(']'); |
456 StackPop(); | 459 StackPop(); |
457 return SUCCESS; | 460 return SUCCESS; |
458 } | 461 } |
459 | 462 |
460 JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow( | 463 BasicJsonStringifier::Result BasicJsonStringifier::SerializeArrayLikeSlow( |
461 Handle<JSReceiver> object, uint32_t start, uint32_t length) { | 464 Handle<JSReceiver> object, uint32_t start, uint32_t length) { |
462 for (uint32_t i = start; i < length; i++) { | 465 for (uint32_t i = start; i < length; i++) { |
463 Separator(i == 0); | 466 Separator(i == 0); |
464 Handle<Object> element; | 467 Handle<Object> element; |
465 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 468 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
466 isolate_, element, JSReceiver::GetElement(isolate_, object, i), | 469 isolate_, element, JSReceiver::GetElement(isolate_, object, i), |
467 EXCEPTION); | 470 EXCEPTION); |
468 Result result = SerializeElement(isolate_, element, i); | 471 if (element->IsUndefined()) { |
469 if (result == SUCCESS) continue; | |
470 if (result == UNCHANGED) { | |
471 builder_.AppendCString("null"); | 472 builder_.AppendCString("null"); |
472 } else { | 473 } else { |
473 return result; | 474 Result result = SerializeElement(isolate_, element, i); |
| 475 if (result == SUCCESS) continue; |
| 476 if (result == UNCHANGED) { |
| 477 builder_.AppendCString("null"); |
| 478 } else { |
| 479 return result; |
| 480 } |
474 } | 481 } |
475 } | 482 } |
476 return SUCCESS; | 483 return SUCCESS; |
477 } | 484 } |
478 | 485 |
479 JsonStringifier::Result JsonStringifier::SerializeJSObject( | 486 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
480 Handle<JSObject> object) { | 487 Handle<JSObject> object) { |
481 HandleScope handle_scope(isolate_); | 488 HandleScope handle_scope(isolate_); |
482 Result stack_push = StackPush(object); | 489 Result stack_push = StackPush(object); |
483 if (stack_push != SUCCESS) return stack_push; | 490 if (stack_push != SUCCESS) return stack_push; |
484 | 491 |
485 if (property_list_.is_null() && | 492 if (property_list_.is_null() && |
486 object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && | 493 object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
487 object->HasFastProperties() && | 494 object->HasFastProperties() && |
488 Handle<JSObject>::cast(object)->elements()->length() == 0) { | 495 Handle<JSObject>::cast(object)->elements()->length() == 0) { |
489 DCHECK(object->IsJSObject()); | 496 DCHECK(object->IsJSObject()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 if (comma) NewLine(); | 531 if (comma) NewLine(); |
525 builder_.AppendCharacter('}'); | 532 builder_.AppendCharacter('}'); |
526 } else { | 533 } else { |
527 Result result = SerializeJSReceiverSlow(object); | 534 Result result = SerializeJSReceiverSlow(object); |
528 if (result != SUCCESS) return result; | 535 if (result != SUCCESS) return result; |
529 } | 536 } |
530 StackPop(); | 537 StackPop(); |
531 return SUCCESS; | 538 return SUCCESS; |
532 } | 539 } |
533 | 540 |
534 JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow( | 541 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSReceiverSlow( |
535 Handle<JSReceiver> object) { | 542 Handle<JSReceiver> object) { |
536 Handle<FixedArray> contents = property_list_; | 543 Handle<FixedArray> contents = property_list_; |
537 if (contents.is_null()) { | 544 if (contents.is_null()) { |
538 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 545 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
539 isolate_, contents, | 546 isolate_, contents, |
540 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); | 547 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); |
541 } | 548 } |
542 | 549 |
543 builder_.AppendCharacter('{'); | 550 builder_.AppendCharacter('{'); |
544 Indent(); | 551 Indent(); |
(...skipping 21 matching lines...) Expand all Loading... |
566 Result result = SerializeProperty(property, comma, key_handle); | 573 Result result = SerializeProperty(property, comma, key_handle); |
567 if (!comma && result == SUCCESS) comma = true; | 574 if (!comma && result == SUCCESS) comma = true; |
568 if (result == EXCEPTION) return result; | 575 if (result == EXCEPTION) return result; |
569 } | 576 } |
570 Unindent(); | 577 Unindent(); |
571 if (comma) NewLine(); | 578 if (comma) NewLine(); |
572 builder_.AppendCharacter('}'); | 579 builder_.AppendCharacter('}'); |
573 return SUCCESS; | 580 return SUCCESS; |
574 } | 581 } |
575 | 582 |
576 JsonStringifier::Result JsonStringifier::SerializeJSProxy( | 583 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSProxy( |
577 Handle<JSProxy> object) { | 584 Handle<JSProxy> object) { |
578 Result stack_push = StackPush(object); | 585 Result stack_push = StackPush(object); |
579 if (stack_push != SUCCESS) return stack_push; | 586 if (stack_push != SUCCESS) return stack_push; |
580 Maybe<bool> is_array = Object::IsArray(object); | 587 Maybe<bool> is_array = Object::IsArray(object); |
581 if (is_array.IsNothing()) return EXCEPTION; | 588 if (is_array.IsNothing()) return EXCEPTION; |
582 if (is_array.FromJust()) { | 589 if (is_array.FromJust()) { |
583 Handle<Object> length_object; | 590 Handle<Object> length_object; |
584 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 591 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
585 isolate_, length_object, | 592 isolate_, length_object, |
586 Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION); | 593 Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION); |
(...skipping 14 matching lines...) Expand all Loading... |
601 builder_.AppendCharacter(']'); | 608 builder_.AppendCharacter(']'); |
602 } else { | 609 } else { |
603 Result result = SerializeJSReceiverSlow(object); | 610 Result result = SerializeJSReceiverSlow(object); |
604 if (result != SUCCESS) return result; | 611 if (result != SUCCESS) return result; |
605 } | 612 } |
606 StackPop(); | 613 StackPop(); |
607 return SUCCESS; | 614 return SUCCESS; |
608 } | 615 } |
609 | 616 |
610 template <typename SrcChar, typename DestChar> | 617 template <typename SrcChar, typename DestChar> |
611 void JsonStringifier::SerializeStringUnchecked_( | 618 void BasicJsonStringifier::SerializeStringUnchecked_( |
612 Vector<const SrcChar> src, | 619 Vector<const SrcChar> src, |
613 IncrementalStringBuilder::NoExtend<DestChar>* dest) { | 620 IncrementalStringBuilder::NoExtend<DestChar>* dest) { |
614 // Assert that uc16 character is not truncated down to 8 bit. | 621 // Assert that uc16 character is not truncated down to 8 bit. |
615 // The <uc16, char> version of this method must not be called. | 622 // The <uc16, char> version of this method must not be called. |
616 DCHECK(sizeof(DestChar) >= sizeof(SrcChar)); | 623 DCHECK(sizeof(DestChar) >= sizeof(SrcChar)); |
617 | 624 |
618 for (int i = 0; i < src.length(); i++) { | 625 for (int i = 0; i < src.length(); i++) { |
619 SrcChar c = src[i]; | 626 SrcChar c = src[i]; |
620 if (DoNotEscape(c)) { | 627 if (DoNotEscape(c)) { |
621 dest->Append(c); | 628 dest->Append(c); |
622 } else { | 629 } else { |
623 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); | 630 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); |
624 } | 631 } |
625 } | 632 } |
626 } | 633 } |
627 | 634 |
628 template <typename SrcChar, typename DestChar> | 635 template <typename SrcChar, typename DestChar> |
629 void JsonStringifier::SerializeString_(Handle<String> string) { | 636 void BasicJsonStringifier::SerializeString_(Handle<String> string) { |
630 int length = string->length(); | 637 int length = string->length(); |
631 builder_.Append<uint8_t, DestChar>('"'); | 638 builder_.Append<uint8_t, DestChar>('"'); |
632 // We make a rough estimate to find out if the current string can be | 639 // We make a rough estimate to find out if the current string can be |
633 // serialized without allocating a new string part. The worst case length of | 640 // serialized without allocating a new string part. The worst case length of |
634 // an escaped character is 6. Shifting the remainin string length right by 3 | 641 // an escaped character is 6. Shifting the remainin string length right by 3 |
635 // is a more pessimistic estimate, but faster to calculate. | 642 // is a more pessimistic estimate, but faster to calculate. |
636 int worst_case_length = length << 3; | 643 int worst_case_length = length << 3; |
637 if (builder_.CurrentPartCanFit(worst_case_length)) { | 644 if (builder_.CurrentPartCanFit(worst_case_length)) { |
638 DisallowHeapAllocation no_gc; | 645 DisallowHeapAllocation no_gc; |
639 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(); | 646 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(); |
640 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend( | 647 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend( |
641 &builder_, worst_case_length); | 648 &builder_, worst_case_length); |
642 SerializeStringUnchecked_(vector, &no_extend); | 649 SerializeStringUnchecked_(vector, &no_extend); |
643 } else { | 650 } else { |
644 FlatStringReader reader(isolate_, string); | 651 FlatStringReader reader(isolate_, string); |
645 for (int i = 0; i < reader.length(); i++) { | 652 for (int i = 0; i < reader.length(); i++) { |
646 SrcChar c = reader.Get<SrcChar>(i); | 653 SrcChar c = reader.Get<SrcChar>(i); |
647 if (DoNotEscape(c)) { | 654 if (DoNotEscape(c)) { |
648 builder_.Append<SrcChar, DestChar>(c); | 655 builder_.Append<SrcChar, DestChar>(c); |
649 } else { | 656 } else { |
650 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); | 657 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); |
651 } | 658 } |
652 } | 659 } |
653 } | 660 } |
654 | 661 |
655 builder_.Append<uint8_t, DestChar>('"'); | 662 builder_.Append<uint8_t, DestChar>('"'); |
656 } | 663 } |
657 | 664 |
658 template <> | 665 template <> |
659 bool JsonStringifier::DoNotEscape(uint8_t c) { | 666 bool BasicJsonStringifier::DoNotEscape(uint8_t c) { |
660 return c >= '#' && c <= '~' && c != '\\'; | 667 return c >= '#' && c <= '~' && c != '\\'; |
661 } | 668 } |
662 | 669 |
663 template <> | 670 template <> |
664 bool JsonStringifier::DoNotEscape(uint16_t c) { | 671 bool BasicJsonStringifier::DoNotEscape(uint16_t c) { |
665 return c >= '#' && c != '\\' && c != 0x7f; | 672 return c >= '#' && c != '\\' && c != 0x7f; |
666 } | 673 } |
667 | 674 |
668 void JsonStringifier::NewLine() { | 675 void BasicJsonStringifier::NewLine() { |
669 if (gap_ == nullptr) return; | 676 if (gap_ == nullptr) return; |
670 builder_.AppendCharacter('\n'); | 677 builder_.AppendCharacter('\n'); |
671 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_); | 678 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_); |
672 } | 679 } |
673 | 680 |
674 void JsonStringifier::Separator(bool first) { | 681 void BasicJsonStringifier::Separator(bool first) { |
675 if (!first) builder_.AppendCharacter(','); | 682 if (!first) builder_.AppendCharacter(','); |
676 NewLine(); | 683 NewLine(); |
677 } | 684 } |
678 | 685 |
679 void JsonStringifier::SerializeDeferredKey(bool deferred_comma, | 686 void BasicJsonStringifier::SerializeDeferredKey(bool deferred_comma, |
680 Handle<Object> deferred_key) { | 687 Handle<Object> deferred_key) { |
681 Separator(!deferred_comma); | 688 Separator(!deferred_comma); |
682 SerializeString(Handle<String>::cast(deferred_key)); | 689 SerializeString(Handle<String>::cast(deferred_key)); |
683 builder_.AppendCharacter(':'); | 690 builder_.AppendCharacter(':'); |
684 if (gap_ != nullptr) builder_.AppendCharacter(' '); | 691 if (gap_ != nullptr) builder_.AppendCharacter(' '); |
685 } | 692 } |
686 | 693 |
687 void JsonStringifier::SerializeString(Handle<String> object) { | 694 void BasicJsonStringifier::SerializeString(Handle<String> object) { |
688 object = String::Flatten(object); | 695 object = String::Flatten(object); |
689 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) { | 696 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) { |
690 if (object->IsOneByteRepresentationUnderneath()) { | 697 if (object->IsOneByteRepresentationUnderneath()) { |
691 SerializeString_<uint8_t, uint8_t>(object); | 698 SerializeString_<uint8_t, uint8_t>(object); |
692 } else { | 699 } else { |
693 builder_.ChangeEncoding(); | 700 builder_.ChangeEncoding(); |
694 SerializeString(object); | 701 SerializeString(object); |
695 } | 702 } |
696 } else { | 703 } else { |
697 if (object->IsOneByteRepresentationUnderneath()) { | 704 if (object->IsOneByteRepresentationUnderneath()) { |
698 SerializeString_<uint8_t, uc16>(object); | 705 SerializeString_<uint8_t, uc16>(object); |
699 } else { | 706 } else { |
700 SerializeString_<uc16, uc16>(object); | 707 SerializeString_<uc16, uc16>(object); |
701 } | 708 } |
702 } | 709 } |
703 } | 710 } |
704 | 711 |
705 } // namespace internal | 712 } // namespace internal |
706 } // namespace v8 | 713 } // namespace v8 |
OLD | NEW |