Line data Source code
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
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 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 : // Translation table to escape Latin1 characters.
17 : // Table entries start at a multiple of 8 and are null-terminated.
18 : const 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 :
84 3471988 : JsonStringifier::JsonStringifier(Isolate* isolate)
85 3471988 : : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) {
86 1735994 : tojson_string_ = factory()->toJSON_string();
87 1735994 : stack_ = factory()->NewJSArray(8);
88 1735994 : }
89 :
90 1735994 : MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object,
91 : Handle<Object> replacer,
92 423 : Handle<Object> gap) {
93 1735994 : if (!InitializeReplacer(replacer)) return MaybeHandle<Object>();
94 3471960 : if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) {
95 : return MaybeHandle<Object>();
96 : }
97 : Result result = SerializeObject(object);
98 1735980 : if (result == UNCHANGED) return factory()->undefined_value();
99 3470846 : if (result == SUCCESS) return builder_.Finish();
100 : DCHECK(result == EXCEPTION);
101 : return MaybeHandle<Object>();
102 : }
103 :
104 1736816 : bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
105 : DCHECK(property_list_.is_null());
106 : DCHECK(replacer_function_.is_null());
107 1735994 : Maybe<bool> is_array = Object::IsArray(replacer);
108 1735994 : if (is_array.IsNothing()) return false;
109 1735994 : if (is_array.FromJust()) {
110 476 : HandleScope handle_scope(isolate_);
111 476 : Handle<OrderedHashSet> set = factory()->NewOrderedHashSet();
112 : Handle<Object> length_obj;
113 952 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
114 : isolate_, length_obj,
115 : Object::GetLengthFromArrayLike(isolate_, replacer), false);
116 : uint32_t length;
117 462 : if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
118 1501 : for (uint32_t i = 0; i < length; i++) {
119 : Handle<Object> element;
120 : Handle<String> key;
121 3002 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
122 : isolate_, element, Object::GetElement(isolate_, replacer, i), false);
123 2719 : if (element->IsNumber() || element->IsString()) {
124 1554 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
125 : isolate_, key, Object::ToString(isolate_, element), false);
126 724 : } else if (element->IsJSValue()) {
127 45 : Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_);
128 60 : if (value->IsNumber() || value->IsString()) {
129 90 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
130 : isolate_, key, Object::ToString(isolate_, element), false);
131 : }
132 : }
133 1501 : if (key.is_null()) continue;
134 : // Object keys are internalized, so do it here.
135 822 : key = factory()->InternalizeString(key);
136 822 : set = OrderedHashSet::Add(set, key);
137 : }
138 : property_list_ = OrderedHashSet::ConvertToKeysArray(
139 462 : set, GetKeysConversion::kKeepNumbers);
140 462 : property_list_ = handle_scope.CloseAndEscape(property_list_);
141 1735518 : } else if (replacer->IsCallable()) {
142 2636 : replacer_function_ = Handle<JSReceiver>::cast(replacer);
143 : }
144 : return true;
145 : }
146 :
147 302636 : bool JsonStringifier::InitializeGap(Handle<Object> gap) {
148 : DCHECK_NULL(gap_);
149 302636 : HandleScope scope(isolate_);
150 302636 : if (gap->IsJSValue()) {
151 45 : Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_);
152 45 : if (value->IsString()) {
153 60 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
154 : Object::ToString(isolate_, gap), false);
155 15 : } else if (value->IsNumber()) {
156 30 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap),
157 : false);
158 : }
159 : }
160 :
161 302636 : if (gap->IsString()) {
162 : Handle<String> gap_string = Handle<String>::cast(gap);
163 2268 : if (gap_string->length() > 0) {
164 4488 : int gap_length = std::min(gap_string->length(), 10);
165 2244 : gap_ = NewArray<uc16>(gap_length + 1);
166 2244 : String::WriteToFlat(*gap_string, gap_, 0, gap_length);
167 4626 : for (int i = 0; i < gap_length; i++) {
168 2397 : if (gap_[i] > String::kMaxOneByteCharCode) {
169 15 : builder_.ChangeEncoding();
170 : break;
171 : }
172 : }
173 2244 : gap_[gap_length] = '\0';
174 : }
175 300368 : } else if (gap->IsNumber()) {
176 300353 : int num_value = DoubleToInt32(gap->Number());
177 300353 : if (num_value > 0) {
178 318 : int gap_length = std::min(num_value, 10);
179 159 : gap_ = NewArray<uc16>(gap_length + 1);
180 159 : for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
181 159 : gap_[gap_length] = '\0';
182 : }
183 : }
184 : return true;
185 : }
186 :
187 556088 : MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object,
188 371 : Handle<Object> key) {
189 556088 : HandleScope scope(isolate_);
190 : LookupIterator it(object, tojson_string_,
191 556088 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
192 : Handle<Object> fun;
193 1112176 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
194 556031 : if (!fun->IsCallable()) return object;
195 :
196 : // Call toJSON function.
197 1663 : if (key->IsSmi()) key = factory()->NumberToString(key);
198 1292 : Handle<Object> argv[] = {key};
199 2584 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, object,
200 : Execution::Call(isolate_, fun, object, 1, argv),
201 : Object);
202 1262 : return scope.CloseAndEscape(object);
203 : }
204 :
205 8171562 : MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction(
206 : Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) {
207 8171562 : HandleScope scope(isolate_);
208 8171562 : if (key->IsSmi()) key = factory()->NumberToString(key);
209 8171562 : Handle<Object> argv[] = {key, value};
210 8171562 : Handle<JSReceiver> holder = CurrentHolder(value, initial_holder);
211 16343124 : ASSIGN_RETURN_ON_EXCEPTION(
212 : isolate_, value,
213 : Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object);
214 8171562 : return scope.CloseAndEscape(value);
215 : }
216 :
217 8171562 : Handle<JSReceiver> JsonStringifier::CurrentHolder(
218 5272 : Handle<Object> value, Handle<Object> initial_holder) {
219 : int length = Smi::cast(stack_->length())->value();
220 8171562 : if (length == 0) {
221 : Handle<JSObject> holder =
222 5272 : factory()->NewJSObject(isolate_->object_function());
223 : JSObject::AddProperty(holder, factory()->empty_string(), initial_holder,
224 2636 : NONE);
225 2636 : return holder;
226 : } else {
227 : FixedArray* elements = FixedArray::cast(stack_->elements());
228 : return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)),
229 16337852 : isolate_);
230 : }
231 : }
232 :
233 550902 : JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) {
234 550801 : StackLimitCheck check(isolate_);
235 550801 : if (check.HasOverflowed()) {
236 30 : isolate_->StackOverflow();
237 30 : return EXCEPTION;
238 : }
239 :
240 : int length = Smi::cast(stack_->length())->value();
241 : {
242 : DisallowHeapAllocation no_allocation;
243 : FixedArray* elements = FixedArray::cast(stack_->elements());
244 5338644 : for (int i = 0; i < length; i++) {
245 4787974 : if (elements->get(i) == *object) {
246 : AllowHeapAllocation allow_to_return_error;
247 : Handle<Object> error =
248 101 : factory()->NewTypeError(MessageTemplate::kCircularStructure);
249 101 : isolate_->Throw(*error);
250 : return EXCEPTION;
251 : }
252 : }
253 : }
254 550670 : JSArray::SetLength(stack_, length + 1);
255 550670 : FixedArray::cast(stack_->elements())->set(length, *object);
256 550670 : return SUCCESS;
257 : }
258 :
259 533837 : void JsonStringifier::StackPop() {
260 : int length = Smi::cast(stack_->length())->value();
261 533837 : stack_->set_length(Smi::FromInt(length - 1));
262 533837 : }
263 :
264 : template <bool deferred_string_key>
265 19533400 : JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
266 : bool comma,
267 : Handle<Object> key) {
268 19533400 : StackLimitCheck interrupt_check(isolate_);
269 19533400 : Handle<Object> initial_value = object;
270 19533505 : if (interrupt_check.InterruptRequested() &&
271 105 : isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) {
272 : return EXCEPTION;
273 : }
274 19533398 : if (object->IsJSReceiver()) {
275 1112176 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
276 : isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION);
277 : }
278 19533311 : if (!replacer_function_.is_null()) {
279 16343124 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
280 : isolate_, object, ApplyReplacerFunction(object, key, initial_value),
281 : EXCEPTION);
282 : }
283 :
284 19533311 : if (object->IsSmi()) {
285 : if (deferred_string_key) SerializeDeferredKey(comma, key);
286 266481 : return SerializeSmi(Smi::cast(*object));
287 : }
288 :
289 20172029 : switch (HeapObject::cast(*object)->map()->instance_type()) {
290 : case HEAP_NUMBER_TYPE:
291 : case MUTABLE_HEAP_NUMBER_TYPE:
292 : if (deferred_string_key) SerializeDeferredKey(comma, key);
293 1257 : return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
294 : case ODDBALL_TYPE:
295 16077058 : switch (Oddball::cast(*object)->kind()) {
296 : case Oddball::kFalse:
297 : if (deferred_string_key) SerializeDeferredKey(comma, key);
298 134 : builder_.AppendCString("false");
299 : return SUCCESS;
300 : case Oddball::kTrue:
301 : if (deferred_string_key) SerializeDeferredKey(comma, key);
302 247 : builder_.AppendCString("true");
303 : return SUCCESS;
304 : case Oddball::kNull:
305 : if (deferred_string_key) SerializeDeferredKey(comma, key);
306 74 : builder_.AppendCString("null");
307 : return SUCCESS;
308 : default:
309 : return UNCHANGED;
310 : }
311 : case JS_ARRAY_TYPE:
312 : if (deferred_string_key) SerializeDeferredKey(comma, key);
313 15218 : return SerializeJSArray(Handle<JSArray>::cast(object));
314 : case JS_VALUE_TYPE:
315 : if (deferred_string_key) SerializeDeferredKey(comma, key);
316 1068 : return SerializeJSValue(Handle<JSValue>::cast(object));
317 : case SYMBOL_TYPE:
318 : return UNCHANGED;
319 : default:
320 3172173 : if (object->IsString()) {
321 : if (deferred_string_key) SerializeDeferredKey(comma, key);
322 2633271 : SerializeString(Handle<String>::cast(object));
323 2633271 : return SUCCESS;
324 : } else {
325 : DCHECK(object->IsJSReceiver());
326 538902 : if (object->IsCallable()) return UNCHANGED;
327 : // Go to slow path for global proxy and objects requiring access checks.
328 : if (deferred_string_key) SerializeDeferredKey(comma, key);
329 535415 : if (object->IsJSProxy()) {
330 630 : return SerializeJSProxy(Handle<JSProxy>::cast(object));
331 : }
332 534785 : return SerializeJSObject(Handle<JSObject>::cast(object));
333 : }
334 : }
335 :
336 : UNREACHABLE();
337 : return UNCHANGED;
338 : }
339 :
340 1068 : JsonStringifier::Result JsonStringifier::SerializeJSValue(
341 : Handle<JSValue> object) {
342 1068 : String* class_name = object->class_name();
343 1068 : if (class_name == isolate_->heap()->String_string()) {
344 : Handle<Object> value;
345 870 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
346 : isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
347 435 : SerializeString(Handle<String>::cast(value));
348 633 : } else if (class_name == isolate_->heap()->Number_string()) {
349 : Handle<Object> value;
350 750 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object),
351 : EXCEPTION);
352 375 : if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
353 : SerializeHeapNumber(Handle<HeapNumber>::cast(value));
354 258 : } else if (class_name == isolate_->heap()->Boolean_string()) {
355 : Object* value = JSValue::cast(*object)->value();
356 : DCHECK(value->IsBoolean());
357 90 : builder_.AppendCString(value->IsTrue(isolate_) ? "true" : "false");
358 : } else {
359 : // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
360 : return SerializeJSObject(object);
361 : }
362 : return SUCCESS;
363 : }
364 :
365 271035 : JsonStringifier::Result JsonStringifier::SerializeSmi(Smi* object) {
366 : static const int kBufferSize = 100;
367 : char chars[kBufferSize];
368 : Vector<char> buffer(chars, kBufferSize);
369 271035 : builder_.AppendCString(IntToCString(object->value(), buffer));
370 271035 : return SUCCESS;
371 : }
372 :
373 1317 : JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
374 1317 : if (std::isinf(number) || std::isnan(number)) {
375 268 : builder_.AppendCString("null");
376 : return SUCCESS;
377 : }
378 : static const int kBufferSize = 100;
379 : char chars[kBufferSize];
380 : Vector<char> buffer(chars, kBufferSize);
381 1049 : builder_.AppendCString(DoubleToCString(number, buffer));
382 : return SUCCESS;
383 : }
384 :
385 : JsonStringifier::Result JsonStringifier::SerializeJSArray(
386 : Handle<JSArray> object) {
387 15218 : HandleScope handle_scope(isolate_);
388 15218 : Result stack_push = StackPush(object);
389 15218 : if (stack_push != SUCCESS) return stack_push;
390 15145 : uint32_t length = 0;
391 15145 : CHECK(object->length()->ToArrayLength(&length));
392 : DCHECK(!object->IsAccessCheckNeeded());
393 11580 : builder_.AppendCharacter('[');
394 : Indent();
395 : uint32_t i = 0;
396 15145 : if (replacer_function_.is_null()) {
397 14209 : switch (object->GetElementsKind()) {
398 : case FAST_SMI_ELEMENTS: {
399 933 : Handle<FixedArray> elements(FixedArray::cast(object->elements()),
400 933 : isolate_);
401 933 : StackLimitCheck interrupt_check(isolate_);
402 5172 : while (i < length) {
403 4239 : if (interrupt_check.InterruptRequested() &&
404 : isolate_->stack_guard()->HandleInterrupts()->IsException(
405 0 : isolate_)) {
406 0 : return EXCEPTION;
407 : }
408 : Separator(i == 0);
409 8478 : SerializeSmi(Smi::cast(elements->get(i)));
410 4239 : i++;
411 : }
412 933 : break;
413 : }
414 : case FAST_DOUBLE_ELEMENTS: {
415 : // Empty array is FixedArray but not FixedDoubleArray.
416 15 : if (length == 0) break;
417 : Handle<FixedDoubleArray> elements(
418 0 : FixedDoubleArray::cast(object->elements()), isolate_);
419 0 : StackLimitCheck interrupt_check(isolate_);
420 0 : while (i < length) {
421 0 : if (interrupt_check.InterruptRequested() &&
422 : isolate_->stack_guard()->HandleInterrupts()->IsException(
423 0 : isolate_)) {
424 0 : return EXCEPTION;
425 : }
426 : Separator(i == 0);
427 0 : SerializeDouble(elements->get_scalar(i));
428 0 : i++;
429 : }
430 : break;
431 : }
432 : case FAST_ELEMENTS: {
433 25374 : Handle<Object> old_length(object->length(), isolate_);
434 622747 : while (i < length) {
435 1856574 : if (object->length() != *old_length ||
436 618808 : object->GetElementsKind() != FAST_ELEMENTS) {
437 : // Fall back to slow path.
438 : break;
439 : }
440 : Separator(i == 0);
441 : Result result = SerializeElement(
442 : isolate_,
443 618778 : Handle<Object>(FixedArray::cast(object->elements())->get(i),
444 : isolate_),
445 1856334 : i);
446 618778 : if (result == UNCHANGED) {
447 : builder_.AppendCString("null");
448 618604 : } else if (result != SUCCESS) {
449 : return result;
450 : }
451 610060 : i++;
452 : }
453 : break;
454 : }
455 : // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
456 : // the non-holey cases except that a lookup is necessary for holes.
457 : default:
458 : break;
459 : }
460 : }
461 6427 : if (i < length) {
462 : // Slow path for non-fast elements and fall-back in edge case.
463 1452 : Result result = SerializeArrayLikeSlow(object, i, length);
464 1452 : if (result != SUCCESS) return result;
465 : }
466 : Unindent();
467 6365 : if (length > 0) NewLine();
468 : builder_.AppendCharacter(']');
469 6365 : StackPop();
470 15218 : return SUCCESS;
471 : }
472 :
473 1508 : JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
474 : Handle<JSReceiver> object, uint32_t start, uint32_t length) {
475 : // We need to write out at least two characters per array element.
476 : static const int kMaxSerializableArrayLength = String::kMaxLength / 2;
477 1508 : if (length > kMaxSerializableArrayLength) {
478 10 : isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
479 5 : return EXCEPTION;
480 : }
481 16033549 : for (uint32_t i = start; i < length; i++) {
482 : Separator(i == 0);
483 : Handle<Object> element;
484 32067212 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
485 : isolate_, element, JSReceiver::GetElement(isolate_, object, i),
486 : EXCEPTION);
487 16033591 : Result result = SerializeElement(isolate_, element, i);
488 16033591 : if (result == SUCCESS) continue;
489 15729521 : if (result == UNCHANGED) {
490 : // Detect overflow sooner for large sparse arrays.
491 15729479 : if (builder_.HasOverflowed()) return EXCEPTION;
492 15729479 : builder_.AppendCString("null");
493 : } else {
494 : return result;
495 : }
496 : }
497 : return SUCCESS;
498 : }
499 :
500 : JsonStringifier::Result JsonStringifier::SerializeJSObject(
501 : Handle<JSObject> object) {
502 534953 : HandleScope handle_scope(isolate_);
503 534953 : Result stack_push = StackPush(object);
504 534953 : if (stack_push != SUCCESS) return stack_push;
505 :
506 1069342 : if (property_list_.is_null() &&
507 1068668 : object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
508 1602873 : object->HasFastProperties() &&
509 1602409 : Handle<JSObject>::cast(object)->elements()->length() == 0) {
510 : DCHECK(object->IsJSObject());
511 : DCHECK(!object->IsJSGlobalProxy());
512 533471 : Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
513 : DCHECK(!js_obj->HasIndexedInterceptor());
514 : DCHECK(!js_obj->HasNamedInterceptor());
515 533471 : Handle<Map> map(js_obj->map());
516 371212 : builder_.AppendCharacter('{');
517 : Indent();
518 : bool comma = false;
519 2795761 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
520 1139128 : Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
521 : // TODO(rossberg): Should this throw?
522 1139365 : if (!name->IsString()) continue;
523 1139128 : Handle<String> key = Handle<String>::cast(name);
524 1139128 : PropertyDetails details = map->instance_descriptors()->GetDetails(i);
525 1139128 : if (details.IsDontEnum()) continue;
526 : Handle<Object> property;
527 2276972 : if (details.location() == kField && *map == js_obj->map()) {
528 : DCHECK_EQ(kData, details.kind());
529 1138039 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
530 : property = JSObject::FastPropertyAt(js_obj, details.representation(),
531 1138039 : field_index);
532 : } else {
533 9687 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
534 : isolate_, property, Object::GetPropertyOrElement(js_obj, key),
535 : EXCEPTION);
536 : }
537 : Result result = SerializeProperty(property, comma, key);
538 1138891 : if (!comma && result == SUCCESS) comma = true;
539 1138891 : if (result == EXCEPTION) return result;
540 : }
541 : Unindent();
542 525488 : if (comma) NewLine();
543 : builder_.AppendCharacter('}');
544 : } else {
545 1424 : Result result = SerializeJSReceiverSlow(object);
546 1424 : if (result != SUCCESS) return result;
547 : }
548 526870 : StackPop();
549 534953 : return SUCCESS;
550 : }
551 :
552 1970 : JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
553 : Handle<JSReceiver> object) {
554 1970 : Handle<FixedArray> contents = property_list_;
555 1970 : if (contents.is_null()) {
556 3044 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
557 : isolate_, contents,
558 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
559 : ENUMERABLE_STRINGS,
560 : GetKeysConversion::kConvertToString),
561 : EXCEPTION);
562 : }
563 1970 : builder_.AppendCharacter('{');
564 : Indent();
565 : bool comma = false;
566 16176 : for (int i = 0; i < contents->length(); i++) {
567 6160 : Handle<String> key(String::cast(contents->get(i)), isolate_);
568 : Handle<Object> property;
569 12320 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property,
570 : Object::GetPropertyOrElement(object, key),
571 : EXCEPTION);
572 : Result result = SerializeProperty(property, comma, key);
573 6160 : if (!comma && result == SUCCESS) comma = true;
574 6160 : if (result == EXCEPTION) return result;
575 : }
576 : Unindent();
577 1928 : if (comma) NewLine();
578 : builder_.AppendCharacter('}');
579 : return SUCCESS;
580 : }
581 :
582 630 : JsonStringifier::Result JsonStringifier::SerializeJSProxy(
583 : Handle<JSProxy> object) {
584 630 : HandleScope scope(isolate_);
585 630 : Result stack_push = StackPush(object);
586 630 : if (stack_push != SUCCESS) return stack_push;
587 630 : Maybe<bool> is_array = Object::IsArray(object);
588 630 : if (is_array.IsNothing()) return EXCEPTION;
589 630 : if (is_array.FromJust()) {
590 : Handle<Object> length_object;
591 196 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
592 : isolate_, length_object,
593 : Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION);
594 : uint32_t length;
595 70 : if (!length_object->ToUint32(&length)) {
596 : // Technically, we need to be able to handle lengths outside the
597 : // uint32_t range. However, we would run into string size overflow
598 : // if we tried to stringify such an array.
599 28 : isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
600 14 : return EXCEPTION;
601 : }
602 56 : builder_.AppendCharacter('[');
603 : Indent();
604 112 : Result result = SerializeArrayLikeSlow(object, 0, length);
605 56 : if (result != SUCCESS) return result;
606 : Unindent();
607 56 : if (length > 0) NewLine();
608 : builder_.AppendCharacter(']');
609 : } else {
610 546 : Result result = SerializeJSReceiverSlow(object);
611 546 : if (result != SUCCESS) return result;
612 : }
613 602 : StackPop();
614 602 : return SUCCESS;
615 : }
616 :
617 : template <typename SrcChar, typename DestChar>
618 : void JsonStringifier::SerializeStringUnchecked_(
619 : Vector<const SrcChar> src,
620 : IncrementalStringBuilder::NoExtend<DestChar>* dest) {
621 : // Assert that uc16 character is not truncated down to 8 bit.
622 : // The <uc16, char> version of this method must not be called.
623 : DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
624 :
625 72014675 : for (int i = 0; i < src.length(); i++) {
626 72014675 : SrcChar c = src[i];
627 72014675 : if (DoNotEscape(c)) {
628 : dest->Append(c);
629 : } else {
630 6891 : dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
631 : }
632 : }
633 : }
634 :
635 : template <typename SrcChar, typename DestChar>
636 : void JsonStringifier::SerializeString_(Handle<String> string) {
637 3709783 : int length = string->length();
638 7419566 : builder_.Append<uint8_t, DestChar>('"');
639 : // We make a rough estimate to find out if the current string can be
640 : // serialized without allocating a new string part. The worst case length of
641 : // an escaped character is 6. Shifting the remainin string length right by 3
642 : // is a more pessimistic estimate, but faster to calculate.
643 3709783 : int worst_case_length = length << 3;
644 3709783 : if (builder_.CurrentPartCanFit(worst_case_length)) {
645 : DisallowHeapAllocation no_gc;
646 : Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
647 : IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
648 2707211 : &builder_, worst_case_length);
649 2707211 : SerializeStringUnchecked_(vector, &no_extend);
650 : } else {
651 1002572 : FlatStringReader reader(isolate_, string);
652 38301209 : for (int i = 0; i < reader.length(); i++) {
653 38301209 : SrcChar c = reader.Get<SrcChar>(i);
654 38301209 : if (DoNotEscape(c)) {
655 : builder_.Append<SrcChar, DestChar>(c);
656 : } else {
657 16257783 : builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
658 : }
659 1002572 : }
660 : }
661 :
662 : builder_.Append<uint8_t, DestChar>('"');
663 : }
664 :
665 : template <>
666 108585946 : bool JsonStringifier::DoNotEscape(uint8_t c) {
667 108585946 : return c >= '#' && c <= '~' && c != '\\';
668 : }
669 :
670 : template <>
671 1729938 : bool JsonStringifier::DoNotEscape(uint16_t c) {
672 1729938 : return c >= '#' && c != '\\' && c != 0x7f;
673 : }
674 :
675 : void JsonStringifier::NewLine() {
676 18256780 : if (gap_ == nullptr) return;
677 8017200 : builder_.AppendCharacter('\n');
678 16339824 : for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
679 : }
680 :
681 : void JsonStringifier::Separator(bool first) {
682 17732700 : if (!first) builder_.AppendCharacter(',');
683 : NewLine();
684 : }
685 :
686 : void JsonStringifier::SerializeDeferredKey(bool deferred_comma,
687 : Handle<Object> deferred_key) {
688 : Separator(!deferred_comma);
689 1076077 : SerializeString(Handle<String>::cast(deferred_key));
690 1076077 : builder_.AppendCharacter(':');
691 1076077 : if (gap_ != nullptr) builder_.AppendCharacter(' ');
692 : }
693 :
694 4839358 : void JsonStringifier::SerializeString(Handle<String> object) {
695 4839358 : object = String::Flatten(object);
696 4839358 : if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
697 3709533 : if (object->IsOneByteRepresentationUnderneath()) {
698 : SerializeString_<uint8_t, uint8_t>(object);
699 : } else {
700 1129575 : builder_.ChangeEncoding();
701 1129575 : SerializeString(object);
702 : }
703 : } else {
704 1129825 : if (object->IsOneByteRepresentationUnderneath()) {
705 : SerializeString_<uint8_t, uc16>(object);
706 : } else {
707 : SerializeString_<uc16, uc16>(object);
708 : }
709 : }
710 4839358 : }
711 :
712 : } // namespace internal
713 : } // namespace v8
|