blob: 29685c20e22b6eadceca8ea0eba12f668aa7035f [file] [log] [blame]
Ben Murdoch61f157c2016-09-16 13:49:30 +01001// 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
3// found in the LICENSE file.
4
5#include "src/json-stringifier.h"
6
7#include "src/conversions.h"
8#include "src/lookup.h"
9#include "src/messages.h"
10#include "src/objects-inl.h"
11#include "src/utils.h"
12
13namespace v8 {
14namespace internal {
15
16// Translation table to escape Latin1 characters.
17// Table entries start at a multiple of 8 and are null-terminated.
18const char* const JsonStringifier::JsonEscapeTable =
19 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
20 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
21 "\\b\0 \\t\0 \\n\0 \\u000b\0 "
22 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
23 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
24 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
25 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
26 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
27 " \0 !\0 \\\"\0 #\0 "
28 "$\0 %\0 &\0 '\0 "
29 "(\0 )\0 *\0 +\0 "
30 ",\0 -\0 .\0 /\0 "
31 "0\0 1\0 2\0 3\0 "
32 "4\0 5\0 6\0 7\0 "
33 "8\0 9\0 :\0 ;\0 "
34 "<\0 =\0 >\0 ?\0 "
35 "@\0 A\0 B\0 C\0 "
36 "D\0 E\0 F\0 G\0 "
37 "H\0 I\0 J\0 K\0 "
38 "L\0 M\0 N\0 O\0 "
39 "P\0 Q\0 R\0 S\0 "
40 "T\0 U\0 V\0 W\0 "
41 "X\0 Y\0 Z\0 [\0 "
42 "\\\\\0 ]\0 ^\0 _\0 "
43 "`\0 a\0 b\0 c\0 "
44 "d\0 e\0 f\0 g\0 "
45 "h\0 i\0 j\0 k\0 "
46 "l\0 m\0 n\0 o\0 "
47 "p\0 q\0 r\0 s\0 "
48 "t\0 u\0 v\0 w\0 "
49 "x\0 y\0 z\0 {\0 "
50 "|\0 }\0 ~\0 \177\0 "
51 "\200\0 \201\0 \202\0 \203\0 "
52 "\204\0 \205\0 \206\0 \207\0 "
53 "\210\0 \211\0 \212\0 \213\0 "
54 "\214\0 \215\0 \216\0 \217\0 "
55 "\220\0 \221\0 \222\0 \223\0 "
56 "\224\0 \225\0 \226\0 \227\0 "
57 "\230\0 \231\0 \232\0 \233\0 "
58 "\234\0 \235\0 \236\0 \237\0 "
59 "\240\0 \241\0 \242\0 \243\0 "
60 "\244\0 \245\0 \246\0 \247\0 "
61 "\250\0 \251\0 \252\0 \253\0 "
62 "\254\0 \255\0 \256\0 \257\0 "
63 "\260\0 \261\0 \262\0 \263\0 "
64 "\264\0 \265\0 \266\0 \267\0 "
65 "\270\0 \271\0 \272\0 \273\0 "
66 "\274\0 \275\0 \276\0 \277\0 "
67 "\300\0 \301\0 \302\0 \303\0 "
68 "\304\0 \305\0 \306\0 \307\0 "
69 "\310\0 \311\0 \312\0 \313\0 "
70 "\314\0 \315\0 \316\0 \317\0 "
71 "\320\0 \321\0 \322\0 \323\0 "
72 "\324\0 \325\0 \326\0 \327\0 "
73 "\330\0 \331\0 \332\0 \333\0 "
74 "\334\0 \335\0 \336\0 \337\0 "
75 "\340\0 \341\0 \342\0 \343\0 "
76 "\344\0 \345\0 \346\0 \347\0 "
77 "\350\0 \351\0 \352\0 \353\0 "
78 "\354\0 \355\0 \356\0 \357\0 "
79 "\360\0 \361\0 \362\0 \363\0 "
80 "\364\0 \365\0 \366\0 \367\0 "
81 "\370\0 \371\0 \372\0 \373\0 "
82 "\374\0 \375\0 \376\0 \377\0 ";
83
84JsonStringifier::JsonStringifier(Isolate* isolate)
85 : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) {
86 tojson_string_ = factory()->toJSON_string();
87 stack_ = factory()->NewJSArray(8);
88}
89
90MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object,
91 Handle<Object> replacer,
92 Handle<Object> gap) {
93 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>();
94 if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) {
95 return MaybeHandle<Object>();
96 }
97 Result result = SerializeObject(object);
98 if (result == UNCHANGED) return factory()->undefined_value();
99 if (result == SUCCESS) return builder_.Finish();
100 DCHECK(result == EXCEPTION);
101 return MaybeHandle<Object>();
102}
103
104bool IsInList(Handle<String> key, List<Handle<String> >* list) {
105 // TODO(yangguo): This is O(n^2) for n properties in the list. Deal with this
106 // if this becomes an issue.
107 for (const Handle<String>& existing : *list) {
108 if (String::Equals(existing, key)) return true;
109 }
110 return false;
111}
112
113bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
114 DCHECK(property_list_.is_null());
115 DCHECK(replacer_function_.is_null());
116 Maybe<bool> is_array = Object::IsArray(replacer);
117 if (is_array.IsNothing()) return false;
118 if (is_array.FromJust()) {
119 HandleScope handle_scope(isolate_);
120 List<Handle<String> > list;
121 Handle<Object> length_obj;
122 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
123 isolate_, length_obj,
124 Object::GetLengthFromArrayLike(isolate_, replacer), false);
125 uint32_t length;
126 if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
127 for (uint32_t i = 0; i < length; i++) {
128 Handle<Object> element;
129 Handle<String> key;
130 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
131 isolate_, element, Object::GetElement(isolate_, replacer, i), false);
132 if (element->IsNumber() || element->IsString()) {
133 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
134 isolate_, key, Object::ToString(isolate_, element), false);
135 } else if (element->IsJSValue()) {
136 Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_);
137 if (value->IsNumber() || value->IsString()) {
138 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
139 isolate_, key, Object::ToString(isolate_, element), false);
140 }
141 }
142 if (key.is_null()) continue;
143 if (!IsInList(key, &list)) list.Add(key);
144 }
145 property_list_ = factory()->NewUninitializedFixedArray(list.length());
146 for (int i = 0; i < list.length(); i++) {
147 property_list_->set(i, *list[i]);
148 }
149 property_list_ = handle_scope.CloseAndEscape(property_list_);
150 } else if (replacer->IsCallable()) {
151 replacer_function_ = Handle<JSReceiver>::cast(replacer);
152 }
153 return true;
154}
155
156bool JsonStringifier::InitializeGap(Handle<Object> gap) {
157 DCHECK_NULL(gap_);
158 HandleScope scope(isolate_);
159 if (gap->IsJSValue()) {
160 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_);
161 if (value->IsString()) {
162 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
163 Object::ToString(isolate_, gap), false);
164 } else if (value->IsNumber()) {
165 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap),
166 false);
167 }
168 }
169
170 if (gap->IsString()) {
171 Handle<String> gap_string = Handle<String>::cast(gap);
172 if (gap_string->length() > 0) {
173 int gap_length = std::min(gap_string->length(), 10);
174 gap_ = NewArray<uc16>(gap_length + 1);
175 String::WriteToFlat(*gap_string, gap_, 0, gap_length);
176 for (int i = 0; i < gap_length; i++) {
177 if (gap_[i] > String::kMaxOneByteCharCode) {
178 builder_.ChangeEncoding();
179 break;
180 }
181 }
182 gap_[gap_length] = '\0';
183 }
184 } else if (gap->IsNumber()) {
185 int num_value = DoubleToInt32(gap->Number());
186 if (num_value > 0) {
187 int gap_length = std::min(num_value, 10);
188 gap_ = NewArray<uc16>(gap_length + 1);
189 for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
190 gap_[gap_length] = '\0';
191 }
192 }
193 return true;
194}
195
196MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object,
197 Handle<Object> key) {
198 HandleScope scope(isolate_);
199 LookupIterator it(object, tojson_string_,
200 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
201 Handle<Object> fun;
202 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
203 if (!fun->IsCallable()) return object;
204
205 // Call toJSON function.
206 if (key->IsSmi()) key = factory()->NumberToString(key);
207 Handle<Object> argv[] = {key};
208 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object,
209 Execution::Call(isolate_, fun, object, 1, argv),
210 Object);
211 return scope.CloseAndEscape(object);
212}
213
214MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction(
215 Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) {
216 HandleScope scope(isolate_);
217 if (key->IsSmi()) key = factory()->NumberToString(key);
218 Handle<Object> argv[] = {key, value};
219 Handle<JSReceiver> holder = CurrentHolder(value, initial_holder);
220 ASSIGN_RETURN_ON_EXCEPTION(
221 isolate_, value,
222 Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object);
223 return scope.CloseAndEscape(value);
224}
225
226Handle<JSReceiver> JsonStringifier::CurrentHolder(
227 Handle<Object> value, Handle<Object> initial_holder) {
228 int length = Smi::cast(stack_->length())->value();
229 if (length == 0) {
230 Handle<JSObject> holder =
231 factory()->NewJSObject(isolate_->object_function());
232 JSObject::AddProperty(holder, factory()->empty_string(), initial_holder,
233 NONE);
234 return holder;
235 } else {
236 FixedArray* elements = FixedArray::cast(stack_->elements());
237 return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)),
238 isolate_);
239 }
240}
241
242JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) {
243 StackLimitCheck check(isolate_);
244 if (check.HasOverflowed()) {
245 isolate_->StackOverflow();
246 return EXCEPTION;
247 }
248
249 int length = Smi::cast(stack_->length())->value();
250 {
251 DisallowHeapAllocation no_allocation;
252 FixedArray* elements = FixedArray::cast(stack_->elements());
253 for (int i = 0; i < length; i++) {
254 if (elements->get(i) == *object) {
255 AllowHeapAllocation allow_to_return_error;
256 Handle<Object> error =
257 factory()->NewTypeError(MessageTemplate::kCircularStructure);
258 isolate_->Throw(*error);
259 return EXCEPTION;
260 }
261 }
262 }
263 JSArray::SetLength(stack_, length + 1);
264 FixedArray::cast(stack_->elements())->set(length, *object);
265 return SUCCESS;
266}
267
268void JsonStringifier::StackPop() {
269 int length = Smi::cast(stack_->length())->value();
270 stack_->set_length(Smi::FromInt(length - 1));
271}
272
273template <bool deferred_string_key>
274JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
275 bool comma,
276 Handle<Object> key) {
277 StackLimitCheck interrupt_check(isolate_);
278 Handle<Object> initial_value = object;
279 if (interrupt_check.InterruptRequested() &&
280 isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) {
281 return EXCEPTION;
282 }
283 if (object->IsJSReceiver()) {
284 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
285 isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION);
286 }
287 if (!replacer_function_.is_null()) {
288 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
289 isolate_, object, ApplyReplacerFunction(object, key, initial_value),
290 EXCEPTION);
291 }
292
293 if (object->IsSmi()) {
294 if (deferred_string_key) SerializeDeferredKey(comma, key);
295 return SerializeSmi(Smi::cast(*object));
296 }
297
298 switch (HeapObject::cast(*object)->map()->instance_type()) {
299 case HEAP_NUMBER_TYPE:
300 case MUTABLE_HEAP_NUMBER_TYPE:
301 if (deferred_string_key) SerializeDeferredKey(comma, key);
302 return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
303 case ODDBALL_TYPE:
304 switch (Oddball::cast(*object)->kind()) {
305 case Oddball::kFalse:
306 if (deferred_string_key) SerializeDeferredKey(comma, key);
307 builder_.AppendCString("false");
308 return SUCCESS;
309 case Oddball::kTrue:
310 if (deferred_string_key) SerializeDeferredKey(comma, key);
311 builder_.AppendCString("true");
312 return SUCCESS;
313 case Oddball::kNull:
314 if (deferred_string_key) SerializeDeferredKey(comma, key);
315 builder_.AppendCString("null");
316 return SUCCESS;
317 default:
318 return UNCHANGED;
319 }
320 case JS_ARRAY_TYPE:
321 if (deferred_string_key) SerializeDeferredKey(comma, key);
322 return SerializeJSArray(Handle<JSArray>::cast(object));
323 case JS_VALUE_TYPE:
324 if (deferred_string_key) SerializeDeferredKey(comma, key);
325 return SerializeJSValue(Handle<JSValue>::cast(object));
326 case SIMD128_VALUE_TYPE:
327 case SYMBOL_TYPE:
328 return UNCHANGED;
329 default:
330 if (object->IsString()) {
331 if (deferred_string_key) SerializeDeferredKey(comma, key);
332 SerializeString(Handle<String>::cast(object));
333 return SUCCESS;
334 } else {
335 DCHECK(object->IsJSReceiver());
336 if (object->IsCallable()) return UNCHANGED;
337 // Go to slow path for global proxy and objects requiring access checks.
338 if (deferred_string_key) SerializeDeferredKey(comma, key);
339 if (object->IsJSProxy()) {
340 return SerializeJSProxy(Handle<JSProxy>::cast(object));
341 }
342 return SerializeJSObject(Handle<JSObject>::cast(object));
343 }
344 }
345
346 UNREACHABLE();
347 return UNCHANGED;
348}
349
350JsonStringifier::Result JsonStringifier::SerializeJSValue(
351 Handle<JSValue> object) {
352 String* class_name = object->class_name();
353 if (class_name == isolate_->heap()->String_string()) {
354 Handle<Object> value;
355 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
356 isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
357 SerializeString(Handle<String>::cast(value));
358 } else if (class_name == isolate_->heap()->Number_string()) {
359 Handle<Object> value;
360 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object),
361 EXCEPTION);
362 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
363 SerializeHeapNumber(Handle<HeapNumber>::cast(value));
364 } else if (class_name == isolate_->heap()->Boolean_string()) {
365 Object* value = JSValue::cast(*object)->value();
366 DCHECK(value->IsBoolean());
367 builder_.AppendCString(value->IsTrue(isolate_) ? "true" : "false");
368 } else {
369 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
370 return SerializeJSObject(object);
371 }
372 return SUCCESS;
373}
374
375JsonStringifier::Result JsonStringifier::SerializeSmi(Smi* object) {
376 static const int kBufferSize = 100;
377 char chars[kBufferSize];
378 Vector<char> buffer(chars, kBufferSize);
379 builder_.AppendCString(IntToCString(object->value(), buffer));
380 return SUCCESS;
381}
382
383JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
384 if (std::isinf(number) || std::isnan(number)) {
385 builder_.AppendCString("null");
386 return SUCCESS;
387 }
388 static const int kBufferSize = 100;
389 char chars[kBufferSize];
390 Vector<char> buffer(chars, kBufferSize);
391 builder_.AppendCString(DoubleToCString(number, buffer));
392 return SUCCESS;
393}
394
395JsonStringifier::Result JsonStringifier::SerializeJSArray(
396 Handle<JSArray> object) {
397 HandleScope handle_scope(isolate_);
398 Result stack_push = StackPush(object);
399 if (stack_push != SUCCESS) return stack_push;
400 uint32_t length = 0;
401 CHECK(object->length()->ToArrayLength(&length));
402 DCHECK(!object->IsAccessCheckNeeded());
403 builder_.AppendCharacter('[');
404 Indent();
405 uint32_t i = 0;
406 if (replacer_function_.is_null()) {
407 switch (object->GetElementsKind()) {
408 case FAST_SMI_ELEMENTS: {
409 Handle<FixedArray> elements(FixedArray::cast(object->elements()),
410 isolate_);
411 StackLimitCheck interrupt_check(isolate_);
412 while (i < length) {
413 if (interrupt_check.InterruptRequested() &&
414 isolate_->stack_guard()->HandleInterrupts()->IsException(
415 isolate_)) {
416 return EXCEPTION;
417 }
418 Separator(i == 0);
419 SerializeSmi(Smi::cast(elements->get(i)));
420 i++;
421 }
422 break;
423 }
424 case FAST_DOUBLE_ELEMENTS: {
425 // Empty array is FixedArray but not FixedDoubleArray.
426 if (length == 0) break;
427 Handle<FixedDoubleArray> elements(
428 FixedDoubleArray::cast(object->elements()), isolate_);
429 StackLimitCheck interrupt_check(isolate_);
430 while (i < length) {
431 if (interrupt_check.InterruptRequested() &&
432 isolate_->stack_guard()->HandleInterrupts()->IsException(
433 isolate_)) {
434 return EXCEPTION;
435 }
436 Separator(i == 0);
437 SerializeDouble(elements->get_scalar(i));
438 i++;
439 }
440 break;
441 }
442 case FAST_ELEMENTS: {
443 Handle<Object> old_length(object->length(), isolate_);
444 while (i < length) {
445 if (object->length() != *old_length ||
446 object->GetElementsKind() != FAST_ELEMENTS) {
447 // Fall back to slow path.
448 break;
449 }
450 Separator(i == 0);
451 Result result = SerializeElement(
452 isolate_,
453 Handle<Object>(FixedArray::cast(object->elements())->get(i),
454 isolate_),
455 i);
456 if (result == UNCHANGED) {
457 builder_.AppendCString("null");
458 } else if (result != SUCCESS) {
459 return result;
460 }
461 i++;
462 }
463 break;
464 }
465 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
466 // the non-holey cases except that a lookup is necessary for holes.
467 default:
468 break;
469 }
470 }
471 if (i < length) {
472 // Slow path for non-fast elements and fall-back in edge case.
473 Result result = SerializeArrayLikeSlow(object, i, length);
474 if (result != SUCCESS) return result;
475 }
476 Unindent();
477 if (length > 0) NewLine();
478 builder_.AppendCharacter(']');
479 StackPop();
480 return SUCCESS;
481}
482
483JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
484 Handle<JSReceiver> object, uint32_t start, uint32_t length) {
485 // We need to write out at least two characters per array element.
486 static const int kMaxSerializableArrayLength = String::kMaxLength / 2;
487 if (length > kMaxSerializableArrayLength) {
488 isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
489 return EXCEPTION;
490 }
491 for (uint32_t i = start; i < length; i++) {
492 Separator(i == 0);
493 Handle<Object> element;
494 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
495 isolate_, element, JSReceiver::GetElement(isolate_, object, i),
496 EXCEPTION);
497 Result result = SerializeElement(isolate_, element, i);
498 if (result == SUCCESS) continue;
499 if (result == UNCHANGED) {
500 // Detect overflow sooner for large sparse arrays.
501 if (builder_.HasOverflowed()) return EXCEPTION;
502 builder_.AppendCString("null");
503 } else {
504 return result;
505 }
506 }
507 return SUCCESS;
508}
509
510JsonStringifier::Result JsonStringifier::SerializeJSObject(
511 Handle<JSObject> object) {
512 HandleScope handle_scope(isolate_);
513 Result stack_push = StackPush(object);
514 if (stack_push != SUCCESS) return stack_push;
515
516 if (property_list_.is_null() &&
517 object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
518 object->HasFastProperties() &&
519 Handle<JSObject>::cast(object)->elements()->length() == 0) {
520 DCHECK(object->IsJSObject());
521 DCHECK(!object->IsJSGlobalProxy());
522 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
523 DCHECK(!js_obj->HasIndexedInterceptor());
524 DCHECK(!js_obj->HasNamedInterceptor());
525 Handle<Map> map(js_obj->map());
526 builder_.AppendCharacter('{');
527 Indent();
528 bool comma = false;
529 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
530 Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
531 // TODO(rossberg): Should this throw?
532 if (!name->IsString()) continue;
533 Handle<String> key = Handle<String>::cast(name);
534 PropertyDetails details = map->instance_descriptors()->GetDetails(i);
535 if (details.IsDontEnum()) continue;
536 Handle<Object> property;
537 if (details.type() == DATA && *map == js_obj->map()) {
538 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
539 property = JSObject::FastPropertyAt(js_obj, details.representation(),
540 field_index);
541 } else {
542 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
543 isolate_, property, Object::GetPropertyOrElement(js_obj, key),
544 EXCEPTION);
545 }
546 Result result = SerializeProperty(property, comma, key);
547 if (!comma && result == SUCCESS) comma = true;
548 if (result == EXCEPTION) return result;
549 }
550 Unindent();
551 if (comma) NewLine();
552 builder_.AppendCharacter('}');
553 } else {
554 Result result = SerializeJSReceiverSlow(object);
555 if (result != SUCCESS) return result;
556 }
557 StackPop();
558 return SUCCESS;
559}
560
561JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
562 Handle<JSReceiver> object) {
563 Handle<FixedArray> contents = property_list_;
564 if (contents.is_null()) {
565 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
566 isolate_, contents,
567 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
568 ENUMERABLE_STRINGS,
569 GetKeysConversion::kConvertToString),
570 EXCEPTION);
571 }
572 builder_.AppendCharacter('{');
573 Indent();
574 bool comma = false;
575 for (int i = 0; i < contents->length(); i++) {
576 Handle<String> key(String::cast(contents->get(i)), isolate_);
577 Handle<Object> property;
578 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property,
579 Object::GetPropertyOrElement(object, key),
580 EXCEPTION);
581 Result result = SerializeProperty(property, comma, key);
582 if (!comma && result == SUCCESS) comma = true;
583 if (result == EXCEPTION) return result;
584 }
585 Unindent();
586 if (comma) NewLine();
587 builder_.AppendCharacter('}');
588 return SUCCESS;
589}
590
591JsonStringifier::Result JsonStringifier::SerializeJSProxy(
592 Handle<JSProxy> object) {
593 HandleScope scope(isolate_);
594 Result stack_push = StackPush(object);
595 if (stack_push != SUCCESS) return stack_push;
596 Maybe<bool> is_array = Object::IsArray(object);
597 if (is_array.IsNothing()) return EXCEPTION;
598 if (is_array.FromJust()) {
599 Handle<Object> length_object;
600 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
601 isolate_, length_object,
602 Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION);
603 uint32_t length;
604 if (!length_object->ToUint32(&length)) {
605 // Technically, we need to be able to handle lengths outside the
606 // uint32_t range. However, we would run into string size overflow
607 // if we tried to stringify such an array.
608 isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
609 return EXCEPTION;
610 }
611 builder_.AppendCharacter('[');
612 Indent();
613 Result result = SerializeArrayLikeSlow(object, 0, length);
614 if (result != SUCCESS) return result;
615 Unindent();
616 if (length > 0) NewLine();
617 builder_.AppendCharacter(']');
618 } else {
619 Result result = SerializeJSReceiverSlow(object);
620 if (result != SUCCESS) return result;
621 }
622 StackPop();
623 return SUCCESS;
624}
625
626template <typename SrcChar, typename DestChar>
627void JsonStringifier::SerializeStringUnchecked_(
628 Vector<const SrcChar> src,
629 IncrementalStringBuilder::NoExtend<DestChar>* dest) {
630 // Assert that uc16 character is not truncated down to 8 bit.
631 // The <uc16, char> version of this method must not be called.
632 DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
633
634 for (int i = 0; i < src.length(); i++) {
635 SrcChar c = src[i];
636 if (DoNotEscape(c)) {
637 dest->Append(c);
638 } else {
639 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
640 }
641 }
642}
643
644template <typename SrcChar, typename DestChar>
645void JsonStringifier::SerializeString_(Handle<String> string) {
646 int length = string->length();
647 builder_.Append<uint8_t, DestChar>('"');
648 // We make a rough estimate to find out if the current string can be
649 // serialized without allocating a new string part. The worst case length of
650 // an escaped character is 6. Shifting the remainin string length right by 3
651 // is a more pessimistic estimate, but faster to calculate.
652 int worst_case_length = length << 3;
653 if (builder_.CurrentPartCanFit(worst_case_length)) {
654 DisallowHeapAllocation no_gc;
655 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
656 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
657 &builder_, worst_case_length);
658 SerializeStringUnchecked_(vector, &no_extend);
659 } else {
660 FlatStringReader reader(isolate_, string);
661 for (int i = 0; i < reader.length(); i++) {
662 SrcChar c = reader.Get<SrcChar>(i);
663 if (DoNotEscape(c)) {
664 builder_.Append<SrcChar, DestChar>(c);
665 } else {
666 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
667 }
668 }
669 }
670
671 builder_.Append<uint8_t, DestChar>('"');
672}
673
674template <>
675bool JsonStringifier::DoNotEscape(uint8_t c) {
676 return c >= '#' && c <= '~' && c != '\\';
677}
678
679template <>
680bool JsonStringifier::DoNotEscape(uint16_t c) {
681 return c >= '#' && c != '\\' && c != 0x7f;
682}
683
684void JsonStringifier::NewLine() {
685 if (gap_ == nullptr) return;
686 builder_.AppendCharacter('\n');
687 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
688}
689
690void JsonStringifier::Separator(bool first) {
691 if (!first) builder_.AppendCharacter(',');
692 NewLine();
693}
694
695void JsonStringifier::SerializeDeferredKey(bool deferred_comma,
696 Handle<Object> deferred_key) {
697 Separator(!deferred_comma);
698 SerializeString(Handle<String>::cast(deferred_key));
699 builder_.AppendCharacter(':');
700 if (gap_ != nullptr) builder_.AppendCharacter(' ');
701}
702
703void JsonStringifier::SerializeString(Handle<String> object) {
704 object = String::Flatten(object);
705 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
706 if (object->IsOneByteRepresentationUnderneath()) {
707 SerializeString_<uint8_t, uint8_t>(object);
708 } else {
709 builder_.ChangeEncoding();
710 SerializeString(object);
711 }
712 } else {
713 if (object->IsOneByteRepresentationUnderneath()) {
714 SerializeString_<uint8_t, uc16>(object);
715 } else {
716 SerializeString_<uc16, uc16>(object);
717 }
718 }
719}
720
721} // namespace internal
722} // namespace v8