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/message-template.h"
10 : #include "src/objects-inl.h"
11 : #include "src/objects/heap-number-inl.h"
12 : #include "src/objects/js-array-inl.h"
13 : #include "src/objects/oddball-inl.h"
14 : #include "src/objects/smi.h"
15 : #include "src/string-builder-inl.h"
16 : #include "src/utils.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 : class JsonStringifier {
22 : public:
23 : explicit JsonStringifier(Isolate* isolate);
24 :
25 1140762 : ~JsonStringifier() { DeleteArray(gap_); }
26 :
27 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Stringify(Handle<Object> object,
28 : Handle<Object> replacer,
29 : Handle<Object> gap);
30 :
31 : private:
32 : enum Result { UNCHANGED, SUCCESS, EXCEPTION };
33 :
34 : bool InitializeReplacer(Handle<Object> replacer);
35 : bool InitializeGap(Handle<Object> gap);
36 :
37 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> ApplyToJsonFunction(
38 : Handle<Object> object, Handle<Object> key);
39 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> ApplyReplacerFunction(
40 : Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder);
41 :
42 : // Entry point to serialize the object.
43 1140753 : V8_INLINE Result SerializeObject(Handle<Object> obj) {
44 2281506 : return Serialize_<false>(obj, false, factory()->empty_string());
45 : }
46 :
47 : // Serialize an array element.
48 : // The index may serve as argument for the toJSON function.
49 : V8_INLINE Result SerializeElement(Isolate* isolate, Handle<Object> object,
50 : int i) {
51 : return Serialize_<false>(object, false,
52 20054260 : Handle<Object>(Smi::FromInt(i), isolate));
53 : }
54 :
55 : // Serialize a object property.
56 : // The key may or may not be serialized depending on the property.
57 : // The key may also serve as argument for the toJSON function.
58 : V8_INLINE Result SerializeProperty(Handle<Object> object, bool deferred_comma,
59 : Handle<String> deferred_key) {
60 : DCHECK(!deferred_key.is_null());
61 956970 : return Serialize_<true>(object, deferred_comma, deferred_key);
62 : }
63 :
64 : template <bool deferred_string_key>
65 36 : Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
66 :
67 : V8_INLINE void SerializeDeferredKey(bool deferred_comma,
68 : Handle<Object> deferred_key);
69 :
70 : Result SerializeSmi(Smi object);
71 :
72 : Result SerializeDouble(double number);
73 : V8_INLINE Result SerializeHeapNumber(Handle<HeapNumber> object) {
74 1802 : return SerializeDouble(object->value());
75 : }
76 :
77 : Result SerializeJSValue(Handle<JSValue> object);
78 :
79 : V8_INLINE Result SerializeJSArray(Handle<JSArray> object);
80 : V8_INLINE Result SerializeJSObject(Handle<JSObject> object);
81 :
82 : Result SerializeJSProxy(Handle<JSProxy> object);
83 : Result SerializeJSReceiverSlow(Handle<JSReceiver> object);
84 : Result SerializeArrayLikeSlow(Handle<JSReceiver> object, uint32_t start,
85 : uint32_t length);
86 :
87 : void SerializeString(Handle<String> object);
88 :
89 : template <typename SrcChar, typename DestChar>
90 : V8_INLINE static void SerializeStringUnchecked_(
91 : Vector<const SrcChar> src,
92 : IncrementalStringBuilder::NoExtend<DestChar>* dest);
93 :
94 : template <typename SrcChar, typename DestChar>
95 : V8_INLINE void SerializeString_(Handle<String> string);
96 :
97 : template <typename Char>
98 : V8_INLINE static bool DoNotEscape(Char c);
99 :
100 : V8_INLINE void NewLine();
101 434371 : V8_INLINE void Indent() { indent_++; }
102 432821 : V8_INLINE void Unindent() { indent_--; }
103 : V8_INLINE void Separator(bool first);
104 :
105 : Handle<JSReceiver> CurrentHolder(Handle<Object> value,
106 : Handle<Object> inital_holder);
107 :
108 : Result StackPush(Handle<Object> object);
109 : void StackPop();
110 :
111 1140753 : Factory* factory() { return isolate_->factory(); }
112 :
113 : Isolate* isolate_;
114 : IncrementalStringBuilder builder_;
115 : Handle<String> tojson_string_;
116 : Handle<JSArray> stack_;
117 : Handle<FixedArray> property_list_;
118 : Handle<JSReceiver> replacer_function_;
119 : uc16* gap_;
120 : int indent_;
121 :
122 : static const int kJsonEscapeTableEntrySize = 8;
123 : static const char* const JsonEscapeTable;
124 : };
125 :
126 1140762 : MaybeHandle<Object> JsonStringify(Isolate* isolate, Handle<Object> object,
127 : Handle<Object> replacer, Handle<Object> gap) {
128 1140762 : JsonStringifier stringifier(isolate);
129 2281524 : return stringifier.Stringify(object, replacer, gap);
130 : }
131 :
132 : // Translation table to escape Latin1 characters.
133 : // Table entries start at a multiple of 8 and are null-terminated.
134 : const char* const JsonStringifier::JsonEscapeTable =
135 : "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
136 : "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
137 : "\\b\0 \\t\0 \\n\0 \\u000b\0 "
138 : "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
139 : "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
140 : "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
141 : "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
142 : "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
143 : " \0 !\0 \\\"\0 #\0 "
144 : "$\0 %\0 &\0 '\0 "
145 : "(\0 )\0 *\0 +\0 "
146 : ",\0 -\0 .\0 /\0 "
147 : "0\0 1\0 2\0 3\0 "
148 : "4\0 5\0 6\0 7\0 "
149 : "8\0 9\0 :\0 ;\0 "
150 : "<\0 =\0 >\0 ?\0 "
151 : "@\0 A\0 B\0 C\0 "
152 : "D\0 E\0 F\0 G\0 "
153 : "H\0 I\0 J\0 K\0 "
154 : "L\0 M\0 N\0 O\0 "
155 : "P\0 Q\0 R\0 S\0 "
156 : "T\0 U\0 V\0 W\0 "
157 : "X\0 Y\0 Z\0 [\0 "
158 : "\\\\\0 ]\0 ^\0 _\0 "
159 : "`\0 a\0 b\0 c\0 "
160 : "d\0 e\0 f\0 g\0 "
161 : "h\0 i\0 j\0 k\0 "
162 : "l\0 m\0 n\0 o\0 "
163 : "p\0 q\0 r\0 s\0 "
164 : "t\0 u\0 v\0 w\0 "
165 : "x\0 y\0 z\0 {\0 "
166 : "|\0 }\0 ~\0 \x7F\0 "
167 : "\x80\0 \x81\0 \x82\0 \x83\0 "
168 : "\x84\0 \x85\0 \x86\0 \x87\0 "
169 : "\x88\0 \x89\0 \x8A\0 \x8B\0 "
170 : "\x8C\0 \x8D\0 \x8E\0 \x8F\0 "
171 : "\x90\0 \x91\0 \x92\0 \x93\0 "
172 : "\x94\0 \x95\0 \x96\0 \x97\0 "
173 : "\x98\0 \x99\0 \x9A\0 \x9B\0 "
174 : "\x9C\0 \x9D\0 \x9E\0 \x9F\0 "
175 : "\xA0\0 \xA1\0 \xA2\0 \xA3\0 "
176 : "\xA4\0 \xA5\0 \xA6\0 \xA7\0 "
177 : "\xA8\0 \xA9\0 \xAA\0 \xAB\0 "
178 : "\xAC\0 \xAD\0 \xAE\0 \xAF\0 "
179 : "\xB0\0 \xB1\0 \xB2\0 \xB3\0 "
180 : "\xB4\0 \xB5\0 \xB6\0 \xB7\0 "
181 : "\xB8\0 \xB9\0 \xBA\0 \xBB\0 "
182 : "\xBC\0 \xBD\0 \xBE\0 \xBF\0 "
183 : "\xC0\0 \xC1\0 \xC2\0 \xC3\0 "
184 : "\xC4\0 \xC5\0 \xC6\0 \xC7\0 "
185 : "\xC8\0 \xC9\0 \xCA\0 \xCB\0 "
186 : "\xCC\0 \xCD\0 \xCE\0 \xCF\0 "
187 : "\xD0\0 \xD1\0 \xD2\0 \xD3\0 "
188 : "\xD4\0 \xD5\0 \xD6\0 \xD7\0 "
189 : "\xD8\0 \xD9\0 \xDA\0 \xDB\0 "
190 : "\xDC\0 \xDD\0 \xDE\0 \xDF\0 "
191 : "\xE0\0 \xE1\0 \xE2\0 \xE3\0 "
192 : "\xE4\0 \xE5\0 \xE6\0 \xE7\0 "
193 : "\xE8\0 \xE9\0 \xEA\0 \xEB\0 "
194 : "\xEC\0 \xED\0 \xEE\0 \xEF\0 "
195 : "\xF0\0 \xF1\0 \xF2\0 \xF3\0 "
196 : "\xF4\0 \xF5\0 \xF6\0 \xF7\0 "
197 : "\xF8\0 \xF9\0 \xFA\0 \xFB\0 "
198 : "\xFC\0 \xFD\0 \xFE\0 \xFF\0 ";
199 :
200 2281524 : JsonStringifier::JsonStringifier(Isolate* isolate)
201 2281524 : : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) {
202 1140762 : tojson_string_ = factory()->toJSON_string();
203 1140762 : stack_ = factory()->NewJSArray(8);
204 1140762 : }
205 :
206 1140762 : MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object,
207 : Handle<Object> replacer,
208 268 : Handle<Object> gap) {
209 1140762 : if (!InitializeReplacer(replacer)) return MaybeHandle<Object>();
210 3422259 : if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) {
211 0 : return MaybeHandle<Object>();
212 : }
213 : Result result = SerializeObject(object);
214 1141021 : if (result == UNCHANGED) return factory()->undefined_value();
215 1140485 : if (result == SUCCESS) return builder_.Finish();
216 : DCHECK(result == EXCEPTION);
217 286 : return MaybeHandle<Object>();
218 : }
219 :
220 1141545 : bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
221 : DCHECK(property_list_.is_null());
222 : DCHECK(replacer_function_.is_null());
223 : Maybe<bool> is_array = Object::IsArray(replacer);
224 1140762 : if (is_array.IsNothing()) return false;
225 1140762 : if (is_array.FromJust()) {
226 288 : HandleScope handle_scope(isolate_);
227 288 : Handle<OrderedHashSet> set = factory()->NewOrderedHashSet();
228 : Handle<Object> length_obj;
229 576 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
230 : isolate_, length_obj,
231 : Object::GetLengthFromArrayLike(isolate_,
232 : Handle<JSReceiver>::cast(replacer)),
233 : false);
234 : uint32_t length;
235 279 : if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
236 927 : for (uint32_t i = 0; i < length; i++) {
237 : Handle<Object> element;
238 : Handle<String> key;
239 1854 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
240 : isolate_, element, Object::GetElement(isolate_, replacer, i), false);
241 3366 : if (element->IsNumber() || element->IsString()) {
242 936 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
243 : isolate_, key, Object::ToString(isolate_, element), false);
244 918 : } else if (element->IsJSValue()) {
245 81 : Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_);
246 72 : if (value->IsNumber() || value->IsString()) {
247 54 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
248 : isolate_, key, Object::ToString(isolate_, element), false);
249 : }
250 : }
251 927 : if (key.is_null()) continue;
252 : // Object keys are internalized, so do it here.
253 495 : key = factory()->InternalizeString(key);
254 495 : set = OrderedHashSet::Add(isolate_, set, key);
255 : }
256 : property_list_ = OrderedHashSet::ConvertToKeysArray(
257 279 : isolate_, set, GetKeysConversion::kKeepNumbers);
258 279 : property_list_ = handle_scope.CloseAndEscape(property_list_);
259 2280948 : } else if (replacer->IsCallable()) {
260 6824 : replacer_function_ = Handle<JSReceiver>::cast(replacer);
261 : }
262 : return true;
263 : }
264 :
265 181716 : bool JsonStringifier::InitializeGap(Handle<Object> gap) {
266 : DCHECK_NULL(gap_);
267 181716 : HandleScope scope(isolate_);
268 363432 : if (gap->IsJSValue()) {
269 81 : Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_);
270 54 : if (value->IsString()) {
271 36 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
272 : Object::ToString(isolate_, gap), false);
273 18 : } else if (value->IsNumber()) {
274 18 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
275 : Object::ToNumber(isolate_, gap), false);
276 : }
277 : }
278 :
279 363432 : if (gap->IsString()) {
280 1489 : Handle<String> gap_string = Handle<String>::cast(gap);
281 1489 : if (gap_string->length() > 0) {
282 4131 : int gap_length = std::min(gap_string->length(), 10);
283 1377 : gap_ = NewArray<uc16>(gap_length + 1);
284 1377 : String::WriteToFlat(*gap_string, gap_, 0, gap_length);
285 2841 : for (int i = 0; i < gap_length; i++) {
286 1473 : if (gap_[i] > String::kMaxOneByteCharCode) {
287 9 : builder_.ChangeEncoding();
288 : break;
289 : }
290 : }
291 1377 : gap_[gap_length] = '\0';
292 : }
293 360454 : } else if (gap->IsNumber()) {
294 180218 : int num_value = DoubleToInt32(gap->Number());
295 180218 : if (num_value > 0) {
296 202 : int gap_length = std::min(num_value, 10);
297 101 : gap_ = NewArray<uc16>(gap_length + 1);
298 101 : for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
299 101 : gap_[gap_length] = '\0';
300 : }
301 : }
302 : return true;
303 : }
304 :
305 438000 : MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object,
306 225 : Handle<Object> key) {
307 438000 : HandleScope scope(isolate_);
308 :
309 438000 : Handle<Object> object_for_lookup = object;
310 876000 : if (object->IsBigInt()) {
311 126 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, object_for_lookup,
312 : Object::ToObject(isolate_, object), Object);
313 : }
314 : DCHECK(object_for_lookup->IsJSReceiver());
315 :
316 : // Retrieve toJSON function.
317 : Handle<Object> fun;
318 : {
319 : LookupIterator it(isolate_, object_for_lookup, tojson_string_,
320 438000 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
321 876000 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
322 875912 : if (!fun->IsCallable()) return object;
323 : }
324 :
325 : // Call toJSON function.
326 1899 : if (key->IsSmi()) key = factory()->NumberToString(key);
327 837 : Handle<Object> argv[] = {key};
328 1674 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, object,
329 : Execution::Call(isolate_, fun, object, 1, argv),
330 : Object);
331 819 : return scope.CloseAndEscape(object);
332 : }
333 :
334 4967931 : MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction(
335 4906378 : Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) {
336 4967931 : HandleScope scope(isolate_);
337 14842240 : if (key->IsSmi()) key = factory()->NumberToString(key);
338 4967931 : Handle<Object> argv[] = {key, value};
339 4967931 : Handle<JSReceiver> holder = CurrentHolder(value, initial_holder);
340 9935862 : ASSIGN_RETURN_ON_EXCEPTION(
341 : isolate_, value,
342 : Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object);
343 4967931 : return scope.CloseAndEscape(value);
344 : }
345 :
346 4967931 : Handle<JSReceiver> JsonStringifier::CurrentHolder(
347 13648 : Handle<Object> value, Handle<Object> initial_holder) {
348 4967931 : int length = Smi::ToInt(stack_->length());
349 4967931 : if (length == 0) {
350 : Handle<JSObject> holder =
351 13648 : factory()->NewJSObject(isolate_->object_function());
352 : JSObject::AddProperty(isolate_, holder, factory()->empty_string(),
353 6824 : initial_holder, NONE);
354 6824 : return holder;
355 : } else {
356 9922214 : FixedArray elements = FixedArray::cast(stack_->elements());
357 : return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)),
358 9922214 : isolate_);
359 : }
360 : }
361 :
362 434554 : JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) {
363 434491 : StackLimitCheck check(isolate_);
364 434491 : if (check.HasOverflowed()) {
365 21 : isolate_->StackOverflow();
366 21 : return EXCEPTION;
367 : }
368 :
369 434470 : int length = Smi::ToInt(stack_->length());
370 : {
371 : DisallowHeapAllocation no_allocation;
372 868940 : FixedArray elements = FixedArray::cast(stack_->elements());
373 701642 : for (int i = 0; i < length; i++) {
374 267235 : if (elements->get(i) == *object) {
375 : AllowHeapAllocation allow_to_return_error;
376 : Handle<Object> error =
377 63 : factory()->NewTypeError(MessageTemplate::kCircularStructure);
378 63 : isolate_->Throw(*error);
379 : return EXCEPTION;
380 : }
381 : }
382 : }
383 434407 : JSArray::SetLength(stack_, length + 1);
384 868814 : FixedArray::cast(stack_->elements())->set(length, *object);
385 434407 : return SUCCESS;
386 : }
387 :
388 432821 : void JsonStringifier::StackPop() {
389 432821 : int length = Smi::ToInt(stack_->length());
390 1298463 : stack_->set_length(Smi::FromInt(length - 1));
391 432821 : }
392 :
393 : template <bool deferred_string_key>
394 12124853 : JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
395 : bool comma,
396 : Handle<Object> key) {
397 12124853 : StackLimitCheck interrupt_check(isolate_);
398 12124853 : Handle<Object> initial_value = object;
399 36374559 : if (interrupt_check.InterruptRequested() &&
400 12125569 : isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) {
401 : return EXCEPTION;
402 : }
403 47623538 : if (object->IsJSReceiver() || object->IsBigInt()) {
404 876000 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
405 : isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION);
406 : }
407 12124791 : if (!replacer_function_.is_null()) {
408 9935862 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
409 : isolate_, object, ApplyReplacerFunction(object, key, initial_value),
410 : EXCEPTION);
411 : }
412 :
413 24249582 : if (object->IsSmi()) {
414 : if (deferred_string_key) SerializeDeferredKey(comma, key);
415 241903 : return SerializeSmi(Smi::cast(*object));
416 : }
417 :
418 11882888 : switch (HeapObject::cast(*object)->map()->instance_type()) {
419 : case HEAP_NUMBER_TYPE:
420 : case MUTABLE_HEAP_NUMBER_TYPE:
421 : if (deferred_string_key) SerializeDeferredKey(comma, key);
422 3532 : return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
423 : case BIGINT_TYPE:
424 36 : isolate_->Throw(
425 108 : *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
426 36 : return EXCEPTION;
427 : case ODDBALL_TYPE:
428 9701992 : switch (Oddball::cast(*object)->kind()) {
429 : case Oddball::kFalse:
430 : if (deferred_string_key) SerializeDeferredKey(comma, key);
431 81 : builder_.AppendCString("false");
432 : return SUCCESS;
433 : case Oddball::kTrue:
434 : if (deferred_string_key) SerializeDeferredKey(comma, key);
435 153 : builder_.AppendCString("true");
436 : return SUCCESS;
437 : case Oddball::kNull:
438 : if (deferred_string_key) SerializeDeferredKey(comma, key);
439 190 : builder_.AppendCString("null");
440 : return SUCCESS;
441 : default:
442 : return UNCHANGED;
443 : }
444 : case JS_ARRAY_TYPE:
445 : if (deferred_string_key) SerializeDeferredKey(comma, key);
446 22522 : return SerializeJSArray(Handle<JSArray>::cast(object));
447 : case JS_VALUE_TYPE:
448 : if (deferred_string_key) SerializeDeferredKey(comma, key);
449 702 : return SerializeJSValue(Handle<JSValue>::cast(object));
450 : case SYMBOL_TYPE:
451 : return UNCHANGED;
452 : default:
453 4334190 : if (object->IsString()) {
454 : if (deferred_string_key) SerializeDeferredKey(comma, key);
455 1741678 : SerializeString(Handle<String>::cast(object));
456 1741678 : return SUCCESS;
457 : } else {
458 : DCHECK(object->IsJSReceiver());
459 850834 : if (object->IsCallable()) return UNCHANGED;
460 : // Go to slow path for global proxy and objects requiring access checks.
461 : if (deferred_string_key) SerializeDeferredKey(comma, key);
462 846244 : if (object->IsJSProxy()) {
463 405 : return SerializeJSProxy(Handle<JSProxy>::cast(object));
464 : }
465 845434 : return SerializeJSObject(Handle<JSObject>::cast(object));
466 : }
467 : }
468 :
469 : UNREACHABLE();
470 : }
471 :
472 702 : JsonStringifier::Result JsonStringifier::SerializeJSValue(
473 54 : Handle<JSValue> object) {
474 702 : Object raw = object->value();
475 702 : if (raw->IsString()) {
476 : Handle<Object> value;
477 522 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
478 : isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
479 261 : SerializeString(Handle<String>::cast(value));
480 441 : } else if (raw->IsNumber()) {
481 : Handle<Object> value;
482 450 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
483 : isolate_, value, Object::ToNumber(isolate_, object), EXCEPTION);
484 639 : if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
485 36 : SerializeHeapNumber(Handle<HeapNumber>::cast(value));
486 216 : } else if (raw->IsBigInt()) {
487 : isolate_->Throw(
488 108 : *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
489 54 : return EXCEPTION;
490 162 : } else if (raw->IsBoolean()) {
491 108 : builder_.AppendCString(raw->IsTrue(isolate_) ? "true" : "false");
492 : } else {
493 : // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
494 : return SerializeJSObject(object);
495 : }
496 : return SUCCESS;
497 : }
498 :
499 247860 : JsonStringifier::Result JsonStringifier::SerializeSmi(Smi object) {
500 : static const int kBufferSize = 100;
501 : char chars[kBufferSize];
502 : Vector<char> buffer(chars, kBufferSize);
503 247860 : builder_.AppendCString(IntToCString(object->value(), buffer));
504 247860 : return SUCCESS;
505 : }
506 :
507 2458 : JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
508 2458 : if (std::isinf(number) || std::isnan(number)) {
509 162 : builder_.AppendCString("null");
510 : return SUCCESS;
511 : }
512 : static const int kBufferSize = 100;
513 : char chars[kBufferSize];
514 : Vector<char> buffer(chars, kBufferSize);
515 2296 : builder_.AppendCString(DoubleToCString(number, buffer));
516 : return SUCCESS;
517 : }
518 :
519 : JsonStringifier::Result JsonStringifier::SerializeJSArray(
520 : Handle<JSArray> object) {
521 11261 : HandleScope handle_scope(isolate_);
522 11261 : Result stack_push = StackPush(object);
523 11261 : if (stack_push != SUCCESS) return stack_push;
524 11216 : uint32_t length = 0;
525 11216 : CHECK(object->length()->ToArrayLength(&length));
526 : DCHECK(!object->IsAccessCheckNeeded());
527 4192 : builder_.AppendCharacter('[');
528 : Indent();
529 : uint32_t i = 0;
530 11216 : if (replacer_function_.is_null()) {
531 7040 : switch (object->GetElementsKind()) {
532 : case PACKED_SMI_ELEMENTS: {
533 2272 : Handle<FixedArray> elements(FixedArray::cast(object->elements()),
534 3408 : isolate_);
535 1136 : StackLimitCheck interrupt_check(isolate_);
536 6904 : while (i < length) {
537 11536 : if (interrupt_check.InterruptRequested() &&
538 0 : isolate_->stack_guard()->HandleInterrupts()->IsException(
539 5768 : isolate_)) {
540 0 : return EXCEPTION;
541 : }
542 : Separator(i == 0);
543 17304 : SerializeSmi(Smi::cast(elements->get(i)));
544 5768 : i++;
545 : }
546 1136 : break;
547 : }
548 : case PACKED_DOUBLE_ELEMENTS: {
549 : // Empty array is FixedArray but not FixedDoubleArray.
550 641 : if (length == 0) break;
551 : Handle<FixedDoubleArray> elements(
552 1896 : FixedDoubleArray::cast(object->elements()), isolate_);
553 632 : StackLimitCheck interrupt_check(isolate_);
554 1288 : while (i < length) {
555 1312 : if (interrupt_check.InterruptRequested() &&
556 0 : isolate_->stack_guard()->HandleInterrupts()->IsException(
557 656 : isolate_)) {
558 0 : return EXCEPTION;
559 : }
560 : Separator(i == 0);
561 1312 : SerializeDouble(elements->get_scalar(i));
562 656 : i++;
563 : }
564 : break;
565 : }
566 : case PACKED_ELEMENTS: {
567 14190 : Handle<Object> old_length(object->length(), isolate_);
568 374628 : while (i < length) {
569 1112838 : if (object->length() != *old_length ||
570 741877 : object->GetElementsKind() != PACKED_ELEMENTS) {
571 : // Fall back to slow path.
572 : break;
573 : }
574 : Separator(i == 0);
575 : Result result = SerializeElement(
576 : isolate_,
577 741796 : Handle<Object>(FixedArray::cast(object->elements())->get(i),
578 : isolate_),
579 1483592 : i);
580 370898 : if (result == UNCHANGED) {
581 : builder_.AppendCString("null");
582 370727 : } else if (result != SUCCESS) {
583 : return result;
584 : }
585 369898 : i++;
586 : }
587 : break;
588 : }
589 : // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
590 : // the non-holey cases except that a lookup is necessary for holes.
591 : default:
592 : break;
593 : }
594 : }
595 10216 : if (i < length) {
596 : // Slow path for non-fast elements and fall-back in edge case.
597 4118 : Result result = SerializeArrayLikeSlow(object, i, length);
598 4118 : if (result != SUCCESS) return result;
599 : }
600 : Unindent();
601 10175 : if (length > 0) NewLine();
602 : builder_.AppendCharacter(']');
603 10175 : StackPop();
604 11261 : return SUCCESS;
605 : }
606 :
607 4154 : JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
608 : Handle<JSReceiver> object, uint32_t start, uint32_t length) {
609 : // We need to write out at least two characters per array element.
610 : static const int kMaxSerializableArrayLength = String::kMaxLength / 2;
611 4154 : if (length > kMaxSerializableArrayLength) {
612 10 : isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
613 5 : return EXCEPTION;
614 : }
615 9656205 : for (uint32_t i = start; i < length; i++) {
616 : Separator(i == 0);
617 : Handle<Object> element;
618 19312482 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
619 : isolate_, element, JSReceiver::GetElement(isolate_, object, i),
620 : EXCEPTION);
621 9656232 : Result result = SerializeElement(isolate_, element, i);
622 9656232 : if (result == SUCCESS) continue;
623 9467424 : if (result == UNCHANGED) {
624 : // Detect overflow sooner for large sparse arrays.
625 9467397 : if (builder_.HasOverflowed()) return EXCEPTION;
626 9467397 : builder_.AppendCString("null");
627 : } else {
628 : return result;
629 : }
630 : }
631 : return SUCCESS;
632 : }
633 :
634 : JsonStringifier::Result JsonStringifier::SerializeJSObject(
635 : Handle<JSObject> object) {
636 422825 : HandleScope handle_scope(isolate_);
637 422825 : Result stack_push = StackPush(object);
638 422825 : if (stack_push != SUCCESS) return stack_push;
639 :
640 845302 : if (property_list_.is_null() &&
641 1267636 : !object->map()->IsCustomElementsReceiverMap() &&
642 1267152 : object->HasFastProperties() && object->elements()->length() == 0) {
643 : DCHECK(!object->IsJSGlobalProxy());
644 : DCHECK(!object->HasIndexedInterceptor());
645 : DCHECK(!object->HasNamedInterceptor());
646 1265589 : Handle<Map> map(object->map(), isolate_);
647 283067 : builder_.AppendCharacter('{');
648 : Indent();
649 : bool comma = false;
650 2327119 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
651 2859330 : Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
652 : // TODO(rossberg): Should this throw?
653 1906364 : if (!name->IsString()) continue;
654 953110 : Handle<String> key = Handle<String>::cast(name);
655 953110 : PropertyDetails details = map->instance_descriptors()->GetDetails(i);
656 953110 : if (details.IsDontEnum()) continue;
657 : Handle<Object> property;
658 2857872 : if (details.location() == kField && *map == object->map()) {
659 : DCHECK_EQ(kData, details.kind());
660 952417 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
661 : property = JSObject::FastPropertyAt(object, details.representation(),
662 952417 : field_index);
663 : } else {
664 1580 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
665 : isolate_, property,
666 : Object::GetPropertyOrElement(isolate_, object, key), EXCEPTION);
667 : }
668 : Result result = SerializeProperty(property, comma, key);
669 952966 : if (!comma && result == SUCCESS) comma = true;
670 952966 : if (result == EXCEPTION) return result;
671 : }
672 : Unindent();
673 421381 : if (comma) NewLine();
674 : builder_.AppendCharacter('}');
675 : } else {
676 923 : Result result = SerializeJSReceiverSlow(object);
677 923 : if (result != SUCCESS) return result;
678 : }
679 422259 : StackPop();
680 422825 : return SUCCESS;
681 : }
682 :
683 1274 : JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
684 : Handle<JSReceiver> object) {
685 1274 : Handle<FixedArray> contents = property_list_;
686 1274 : if (contents.is_null()) {
687 2008 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
688 : isolate_, contents,
689 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
690 : ENUMERABLE_STRINGS,
691 : GetKeysConversion::kConvertToString),
692 : EXCEPTION);
693 : }
694 1256 : builder_.AppendCharacter('{');
695 : Indent();
696 : bool comma = false;
697 10466 : for (int i = 0; i < contents->length(); i++) {
698 4004 : Handle<String> key(String::cast(contents->get(i)), isolate_);
699 : Handle<Object> property;
700 8008 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
701 : isolate_, property, Object::GetPropertyOrElement(isolate_, object, key),
702 : EXCEPTION);
703 : Result result = SerializeProperty(property, comma, key);
704 4004 : if (!comma && result == SUCCESS) comma = true;
705 4004 : if (result == EXCEPTION) return result;
706 : }
707 : Unindent();
708 1229 : if (comma) NewLine();
709 : builder_.AppendCharacter('}');
710 : return SUCCESS;
711 : }
712 :
713 405 : JsonStringifier::Result JsonStringifier::SerializeJSProxy(
714 : Handle<JSProxy> object) {
715 405 : HandleScope scope(isolate_);
716 405 : Result stack_push = StackPush(object);
717 405 : if (stack_push != SUCCESS) return stack_push;
718 : Maybe<bool> is_array = Object::IsArray(object);
719 405 : if (is_array.IsNothing()) return EXCEPTION;
720 405 : if (is_array.FromJust()) {
721 : Handle<Object> length_object;
722 126 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
723 : isolate_, length_object,
724 : Object::GetLengthFromArrayLike(isolate_,
725 : Handle<JSReceiver>::cast(object)),
726 : EXCEPTION);
727 : uint32_t length;
728 45 : if (!length_object->ToUint32(&length)) {
729 : // Technically, we need to be able to handle lengths outside the
730 : // uint32_t range. However, we would run into string size overflow
731 : // if we tried to stringify such an array.
732 18 : isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
733 9 : return EXCEPTION;
734 : }
735 36 : builder_.AppendCharacter('[');
736 : Indent();
737 72 : Result result = SerializeArrayLikeSlow(object, 0, length);
738 36 : if (result != SUCCESS) return result;
739 : Unindent();
740 36 : if (length > 0) NewLine();
741 : builder_.AppendCharacter(']');
742 : } else {
743 351 : Result result = SerializeJSReceiverSlow(object);
744 351 : if (result != SUCCESS) return result;
745 : }
746 387 : StackPop();
747 387 : return SUCCESS;
748 : }
749 :
750 : template <typename SrcChar, typename DestChar>
751 : void JsonStringifier::SerializeStringUnchecked_(
752 : Vector<const SrcChar> src,
753 : IncrementalStringBuilder::NoExtend<DestChar>* dest) {
754 : // Assert that uc16 character is not truncated down to 8 bit.
755 : // The <uc16, char> version of this method must not be called.
756 : DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
757 44003929 : for (int i = 0; i < src.length(); i++) {
758 44003929 : SrcChar c = src[i];
759 44003929 : if (DoNotEscape(c)) {
760 : dest->Append(c);
761 57117 : } else if (FLAG_harmony_json_stringify && c >= 0xD800 && c <= 0xDFFF) {
762 : // The current character is a surrogate.
763 57108 : if (c <= 0xDBFF) {
764 : // The current character is a leading surrogate.
765 29430 : if (i + 1 < src.length()) {
766 : // There is a next character.
767 1752 : SrcChar next = src[i + 1];
768 1752 : if (next >= 0xDC00 && next <= 0xDFFF) {
769 : // The next character is a trailing surrogate, meaning this is a
770 : // surrogate pair.
771 : dest->Append(c);
772 : dest->Append(next);
773 : i++;
774 : } else {
775 : // The next character is not a trailing surrogate. Thus, the
776 : // current character is a lone leading surrogate.
777 : dest->AppendCString("\\u");
778 0 : char* const hex = DoubleToRadixCString(c, 16);
779 : dest->AppendCString(hex);
780 0 : DeleteArray(hex);
781 : }
782 : } else {
783 : // There is no next character. Thus, the current character is a lone
784 : // leading surrogate.
785 : dest->AppendCString("\\u");
786 27678 : char* const hex = DoubleToRadixCString(c, 16);
787 : dest->AppendCString(hex);
788 27678 : DeleteArray(hex);
789 : }
790 : } else {
791 : // The current character is a lone trailing surrogate. (If it had been
792 : // preceded by a leading surrogate, we would've ended up in the other
793 : // branch earlier on, and the current character would've been handled
794 : // as part of the surrogate pair already.)
795 : dest->AppendCString("\\u");
796 27678 : char* const hex = DoubleToRadixCString(c, 16);
797 : dest->AppendCString(hex);
798 27678 : DeleteArray(hex);
799 : }
800 : } else {
801 5933 : dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
802 : }
803 : }
804 : }
805 :
806 : template <typename SrcChar, typename DestChar>
807 : void JsonStringifier::SerializeString_(Handle<String> string) {
808 2652446 : int length = string->length();
809 2652446 : builder_.Append<uint8_t, DestChar>('"');
810 : // We might be able to fit the whole escaped string in the current string
811 : // part, or we might need to allocate.
812 2652446 : if (int worst_case_length = builder_.EscapedLengthIfCurrentPartFits(length)) {
813 : DisallowHeapAllocation no_gc;
814 2902058 : Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(no_gc);
815 : IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
816 1451029 : &builder_, worst_case_length, no_gc);
817 1451029 : SerializeStringUnchecked_(vector, &no_extend);
818 : } else {
819 1201417 : FlatStringReader reader(isolate_, string);
820 2441918991 : for (int i = 0; i < reader.length(); i++) {
821 2441918991 : SrcChar c = reader.Get<SrcChar>(i);
822 2441918991 : if (DoNotEscape(c)) {
823 : builder_.Append<SrcChar, DestChar>(c);
824 450 : } else if (FLAG_harmony_json_stringify && c >= 0xD800 && c <= 0xDFFF) {
825 : // The current character is a surrogate.
826 0 : if (c <= 0xDBFF) {
827 : // The current character is a leading surrogate.
828 0 : if (i + 1 < reader.length()) {
829 : // There is a next character.
830 0 : SrcChar next = reader.Get<SrcChar>(i + 1);
831 0 : if (next >= 0xDC00 && next <= 0xDFFF) {
832 : // The next character is a trailing surrogate, meaning this is a
833 : // surrogate pair.
834 : builder_.Append<SrcChar, DestChar>(c);
835 : builder_.Append<SrcChar, DestChar>(next);
836 : i++;
837 : } else {
838 : // The next character is not a trailing surrogate. Thus, the
839 : // current character is a lone leading surrogate.
840 : builder_.AppendCString("\\u");
841 0 : char* const hex = DoubleToRadixCString(c, 16);
842 : builder_.AppendCString(hex);
843 0 : DeleteArray(hex);
844 : }
845 : } else {
846 : // There is no next character. Thus, the current character is a
847 : // lone leading surrogate.
848 : builder_.AppendCString("\\u");
849 0 : char* const hex = DoubleToRadixCString(c, 16);
850 : builder_.AppendCString(hex);
851 0 : DeleteArray(hex);
852 : }
853 : } else {
854 : // The current character is a lone trailing surrogate. (If it had
855 : // been preceded by a leading surrogate, we would've ended up in the
856 : // other branch earlier on, and the current character would've been
857 : // handled as part of the surrogate pair already.)
858 : builder_.AppendCString("\\u");
859 0 : char* const hex = DoubleToRadixCString(c, 16);
860 : builder_.AppendCString(hex);
861 0 : DeleteArray(hex);
862 : }
863 : } else {
864 9842215 : builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
865 : }
866 1201417 : }
867 : }
868 : builder_.Append<uint8_t, DestChar>('"');
869 : }
870 :
871 : template <>
872 2484787242 : bool JsonStringifier::DoNotEscape(uint8_t c) {
873 : // https://tc39.github.io/ecma262/#table-json-single-character-escapes
874 2484787242 : return c >= 0x23 && c <= 0x7E && c != 0x5C;
875 : }
876 :
877 : template <>
878 1135678 : bool JsonStringifier::DoNotEscape(uint16_t c) {
879 : // https://tc39.github.io/ecma262/#table-json-single-character-escapes
880 2270897 : return c >= 0x23 && c != 0x5C && c != 0x7F &&
881 2270438 : (!FLAG_harmony_json_stringify || (c < 0xD800 || c > 0xDFFF));
882 : }
883 :
884 : void JsonStringifier::NewLine() {
885 11363111 : if (gap_ == nullptr) return;
886 4810404 : builder_.AppendCharacter('\n');
887 9804272 : for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
888 : }
889 :
890 : void JsonStringifier::Separator(bool first) {
891 10944070 : if (!first) builder_.AppendCharacter(',');
892 : NewLine();
893 : }
894 :
895 : void JsonStringifier::SerializeDeferredKey(bool deferred_comma,
896 : Handle<Object> deferred_key) {
897 : Separator(!deferred_comma);
898 910507 : SerializeString(Handle<String>::cast(deferred_key));
899 910507 : builder_.AppendCharacter(':');
900 910507 : if (gap_ != nullptr) builder_.AppendCharacter(' ');
901 : }
902 :
903 3371560 : void JsonStringifier::SerializeString(Handle<String> object) {
904 3371560 : object = String::Flatten(isolate_, object);
905 3371560 : if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
906 2652393 : if (String::IsOneByteRepresentationUnderneath(*object)) {
907 : SerializeString_<uint8_t, uint8_t>(object);
908 : } else {
909 719114 : builder_.ChangeEncoding();
910 719114 : SerializeString(object);
911 : }
912 : } else {
913 719167 : if (String::IsOneByteRepresentationUnderneath(*object)) {
914 : SerializeString_<uint8_t, uc16>(object);
915 : } else {
916 : SerializeString_<uc16, uc16>(object);
917 : }
918 : }
919 3371560 : }
920 :
921 : } // namespace internal
922 183867 : } // namespace v8
|