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 2278080 : ~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 1139031 : V8_INLINE Result SerializeObject(Handle<Object> obj) {
44 2278062 : 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 20040636 : 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 949899 : 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 1574 : return SerializeDouble(object->value());
75 : }
76 :
77 : Result SerializeJSValue(Handle<JSValue> object, Handle<Object> key);
78 :
79 : V8_INLINE Result SerializeJSArray(Handle<JSArray> object, Handle<Object> key);
80 : V8_INLINE Result SerializeJSObject(Handle<JSObject> object,
81 : Handle<Object> key);
82 :
83 : Result SerializeJSProxy(Handle<JSProxy> object, Handle<Object> key);
84 : Result SerializeJSReceiverSlow(Handle<JSReceiver> object);
85 : Result SerializeArrayLikeSlow(Handle<JSReceiver> object, uint32_t start,
86 : uint32_t length);
87 :
88 : void SerializeString(Handle<String> object);
89 :
90 : template <typename SrcChar, typename DestChar>
91 : V8_INLINE static void SerializeStringUnchecked_(
92 : Vector<const SrcChar> src,
93 : IncrementalStringBuilder::NoExtend<DestChar>* dest);
94 :
95 : template <typename SrcChar, typename DestChar>
96 : V8_INLINE void SerializeString_(Handle<String> string);
97 :
98 : template <typename Char>
99 : V8_INLINE static bool DoNotEscape(Char c);
100 :
101 : V8_INLINE void NewLine();
102 430232 : V8_INLINE void Indent() { indent_++; }
103 428543 : V8_INLINE void Unindent() { indent_--; }
104 : V8_INLINE void Separator(bool first);
105 :
106 : Handle<JSReceiver> CurrentHolder(Handle<Object> value,
107 : Handle<Object> inital_holder);
108 :
109 : Result StackPush(Handle<Object> object, Handle<Object> key);
110 : void StackPop();
111 :
112 : // Uses the current stack_ to provide a detailed error message of
113 : // the objects involved in the circular structure.
114 : Handle<String> ConstructCircularStructureErrorMessage(Handle<Object> last_key,
115 : size_t start_index);
116 : // The prefix and postfix count do NOT include the starting and
117 : // closing lines of the error message.
118 : static const int kCircularErrorMessagePrefixCount = 2;
119 : static const int kCircularErrorMessagePostfixCount = 1;
120 :
121 1139031 : Factory* factory() { return isolate_->factory(); }
122 :
123 : Isolate* isolate_;
124 : IncrementalStringBuilder builder_;
125 : Handle<String> tojson_string_;
126 : Handle<FixedArray> property_list_;
127 : Handle<JSReceiver> replacer_function_;
128 : uc16* gap_;
129 : int indent_;
130 :
131 : using KeyObject = std::pair<Handle<Object>, Handle<Object>>;
132 : std::vector<KeyObject> stack_;
133 :
134 : static const int kJsonEscapeTableEntrySize = 8;
135 : static const char* const JsonEscapeTable;
136 : };
137 :
138 1139040 : MaybeHandle<Object> JsonStringify(Isolate* isolate, Handle<Object> object,
139 : Handle<Object> replacer, Handle<Object> gap) {
140 1139040 : JsonStringifier stringifier(isolate);
141 1139040 : return stringifier.Stringify(object, replacer, gap);
142 : }
143 :
144 : // Translation table to escape Latin1 characters.
145 : // Table entries start at a multiple of 8 and are null-terminated.
146 : const char* const JsonStringifier::JsonEscapeTable =
147 : "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
148 : "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
149 : "\\b\0 \\t\0 \\n\0 \\u000b\0 "
150 : "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
151 : "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
152 : "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
153 : "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
154 : "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
155 : " \0 !\0 \\\"\0 #\0 "
156 : "$\0 %\0 &\0 '\0 "
157 : "(\0 )\0 *\0 +\0 "
158 : ",\0 -\0 .\0 /\0 "
159 : "0\0 1\0 2\0 3\0 "
160 : "4\0 5\0 6\0 7\0 "
161 : "8\0 9\0 :\0 ;\0 "
162 : "<\0 =\0 >\0 ?\0 "
163 : "@\0 A\0 B\0 C\0 "
164 : "D\0 E\0 F\0 G\0 "
165 : "H\0 I\0 J\0 K\0 "
166 : "L\0 M\0 N\0 O\0 "
167 : "P\0 Q\0 R\0 S\0 "
168 : "T\0 U\0 V\0 W\0 "
169 : "X\0 Y\0 Z\0 [\0 "
170 : "\\\\\0 ]\0 ^\0 _\0 "
171 : "`\0 a\0 b\0 c\0 "
172 : "d\0 e\0 f\0 g\0 "
173 : "h\0 i\0 j\0 k\0 "
174 : "l\0 m\0 n\0 o\0 "
175 : "p\0 q\0 r\0 s\0 "
176 : "t\0 u\0 v\0 w\0 "
177 : "x\0 y\0 z\0 {\0 "
178 : "|\0 }\0 ~\0 \x7F\0 "
179 : "\x80\0 \x81\0 \x82\0 \x83\0 "
180 : "\x84\0 \x85\0 \x86\0 \x87\0 "
181 : "\x88\0 \x89\0 \x8A\0 \x8B\0 "
182 : "\x8C\0 \x8D\0 \x8E\0 \x8F\0 "
183 : "\x90\0 \x91\0 \x92\0 \x93\0 "
184 : "\x94\0 \x95\0 \x96\0 \x97\0 "
185 : "\x98\0 \x99\0 \x9A\0 \x9B\0 "
186 : "\x9C\0 \x9D\0 \x9E\0 \x9F\0 "
187 : "\xA0\0 \xA1\0 \xA2\0 \xA3\0 "
188 : "\xA4\0 \xA5\0 \xA6\0 \xA7\0 "
189 : "\xA8\0 \xA9\0 \xAA\0 \xAB\0 "
190 : "\xAC\0 \xAD\0 \xAE\0 \xAF\0 "
191 : "\xB0\0 \xB1\0 \xB2\0 \xB3\0 "
192 : "\xB4\0 \xB5\0 \xB6\0 \xB7\0 "
193 : "\xB8\0 \xB9\0 \xBA\0 \xBB\0 "
194 : "\xBC\0 \xBD\0 \xBE\0 \xBF\0 "
195 : "\xC0\0 \xC1\0 \xC2\0 \xC3\0 "
196 : "\xC4\0 \xC5\0 \xC6\0 \xC7\0 "
197 : "\xC8\0 \xC9\0 \xCA\0 \xCB\0 "
198 : "\xCC\0 \xCD\0 \xCE\0 \xCF\0 "
199 : "\xD0\0 \xD1\0 \xD2\0 \xD3\0 "
200 : "\xD4\0 \xD5\0 \xD6\0 \xD7\0 "
201 : "\xD8\0 \xD9\0 \xDA\0 \xDB\0 "
202 : "\xDC\0 \xDD\0 \xDE\0 \xDF\0 "
203 : "\xE0\0 \xE1\0 \xE2\0 \xE3\0 "
204 : "\xE4\0 \xE5\0 \xE6\0 \xE7\0 "
205 : "\xE8\0 \xE9\0 \xEA\0 \xEB\0 "
206 : "\xEC\0 \xED\0 \xEE\0 \xEF\0 "
207 : "\xF0\0 \xF1\0 \xF2\0 \xF3\0 "
208 : "\xF4\0 \xF5\0 \xF6\0 \xF7\0 "
209 : "\xF8\0 \xF9\0 \xFA\0 \xFB\0 "
210 : "\xFC\0 \xFD\0 \xFE\0 \xFF\0 ";
211 :
212 2278080 : JsonStringifier::JsonStringifier(Isolate* isolate)
213 : : isolate_(isolate),
214 : builder_(isolate),
215 : gap_(nullptr),
216 : indent_(0),
217 2278080 : stack_() {
218 1139040 : tojson_string_ = factory()->toJSON_string();
219 1139040 : }
220 :
221 1139040 : MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object,
222 : Handle<Object> replacer,
223 264 : Handle<Object> gap) {
224 1139040 : if (!InitializeReplacer(replacer)) return MaybeHandle<Object>();
225 3417093 : if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) {
226 0 : return MaybeHandle<Object>();
227 : }
228 : Result result = SerializeObject(object);
229 1139295 : if (result == UNCHANGED) return factory()->undefined_value();
230 1138767 : if (result == SUCCESS) return builder_.Finish();
231 : DCHECK(result == EXCEPTION);
232 302 : return MaybeHandle<Object>();
233 : }
234 :
235 1139823 : bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
236 : DCHECK(property_list_.is_null());
237 : DCHECK(replacer_function_.is_null());
238 : Maybe<bool> is_array = Object::IsArray(replacer);
239 1139040 : if (is_array.IsNothing()) return false;
240 1139040 : if (is_array.FromJust()) {
241 288 : HandleScope handle_scope(isolate_);
242 288 : Handle<OrderedHashSet> set = factory()->NewOrderedHashSet();
243 : Handle<Object> length_obj;
244 576 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
245 : isolate_, length_obj,
246 : Object::GetLengthFromArrayLike(isolate_,
247 : Handle<JSReceiver>::cast(replacer)),
248 : false);
249 : uint32_t length;
250 279 : if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
251 927 : for (uint32_t i = 0; i < length; i++) {
252 : Handle<Object> element;
253 : Handle<String> key;
254 1854 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
255 : isolate_, element, Object::GetElement(isolate_, replacer, i), false);
256 3366 : if (element->IsNumber() || element->IsString()) {
257 936 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
258 : isolate_, key, Object::ToString(isolate_, element), false);
259 918 : } else if (element->IsJSValue()) {
260 54 : Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_);
261 72 : if (value->IsNumber() || value->IsString()) {
262 54 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
263 : isolate_, key, Object::ToString(isolate_, element), false);
264 : }
265 : }
266 927 : if (key.is_null()) continue;
267 : // Object keys are internalized, so do it here.
268 495 : key = factory()->InternalizeString(key);
269 495 : set = OrderedHashSet::Add(isolate_, set, key);
270 : }
271 : property_list_ = OrderedHashSet::ConvertToKeysArray(
272 279 : isolate_, set, GetKeysConversion::kKeepNumbers);
273 279 : property_list_ = handle_scope.CloseAndEscape(property_list_);
274 2277504 : } else if (replacer->IsCallable()) {
275 6714 : replacer_function_ = Handle<JSReceiver>::cast(replacer);
276 : }
277 : return true;
278 : }
279 :
280 181716 : bool JsonStringifier::InitializeGap(Handle<Object> gap) {
281 : DCHECK_NULL(gap_);
282 181716 : HandleScope scope(isolate_);
283 363432 : if (gap->IsJSValue()) {
284 54 : Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_);
285 54 : if (value->IsString()) {
286 36 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
287 : Object::ToString(isolate_, gap), false);
288 18 : } else if (value->IsNumber()) {
289 18 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
290 : Object::ToNumber(isolate_, gap), false);
291 : }
292 : }
293 :
294 363432 : if (gap->IsString()) {
295 1489 : Handle<String> gap_string = Handle<String>::cast(gap);
296 1489 : if (gap_string->length() > 0) {
297 4131 : int gap_length = std::min(gap_string->length(), 10);
298 1377 : gap_ = NewArray<uc16>(gap_length + 1);
299 1377 : String::WriteToFlat(*gap_string, gap_, 0, gap_length);
300 2841 : for (int i = 0; i < gap_length; i++) {
301 1473 : if (gap_[i] > String::kMaxOneByteCharCode) {
302 9 : builder_.ChangeEncoding();
303 : break;
304 : }
305 : }
306 1377 : gap_[gap_length] = '\0';
307 : }
308 360454 : } else if (gap->IsNumber()) {
309 180218 : int num_value = DoubleToInt32(gap->Number());
310 180218 : if (num_value > 0) {
311 202 : int gap_length = std::min(num_value, 10);
312 101 : gap_ = NewArray<uc16>(gap_length + 1);
313 101 : for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
314 101 : gap_[gap_length] = '\0';
315 : }
316 : }
317 : return true;
318 : }
319 :
320 433904 : MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object,
321 225 : Handle<Object> key) {
322 433904 : HandleScope scope(isolate_);
323 :
324 433904 : Handle<Object> object_for_lookup = object;
325 867808 : if (object->IsBigInt()) {
326 126 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, object_for_lookup,
327 : Object::ToObject(isolate_, object), Object);
328 : }
329 : DCHECK(object_for_lookup->IsJSReceiver());
330 :
331 : // Retrieve toJSON function.
332 : Handle<Object> fun;
333 : {
334 : LookupIterator it(isolate_, object_for_lookup, tojson_string_,
335 433904 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
336 867808 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
337 867720 : if (!fun->IsCallable()) return object;
338 : }
339 :
340 : // Call toJSON function.
341 1899 : if (key->IsSmi()) key = factory()->NumberToString(key);
342 837 : Handle<Object> argv[] = {key};
343 1674 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, object,
344 : Execution::Call(isolate_, fun, object, 1, argv),
345 : Object);
346 819 : return scope.CloseAndEscape(object);
347 : }
348 :
349 4966635 : MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction(
350 4906135 : Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) {
351 4966635 : HandleScope scope(isolate_);
352 14839405 : if (key->IsSmi()) key = factory()->NumberToString(key);
353 4966635 : Handle<Object> argv[] = {key, value};
354 4966635 : Handle<JSReceiver> holder = CurrentHolder(value, initial_holder);
355 9933270 : ASSIGN_RETURN_ON_EXCEPTION(
356 : isolate_, value,
357 : Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object);
358 4966635 : return scope.CloseAndEscape(value);
359 : }
360 :
361 4966635 : Handle<JSReceiver> JsonStringifier::CurrentHolder(
362 13428 : Handle<Object> value, Handle<Object> initial_holder) {
363 4966635 : if (stack_.empty()) {
364 : Handle<JSObject> holder =
365 13428 : factory()->NewJSObject(isolate_->object_function());
366 : JSObject::AddProperty(isolate_, holder, factory()->empty_string(),
367 6714 : initial_holder, NONE);
368 6714 : return holder;
369 : } else {
370 : return Handle<JSReceiver>(JSReceiver::cast(*stack_.back().second),
371 9919842 : isolate_);
372 : }
373 : }
374 :
375 430368 : JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object,
376 79 : Handle<Object> key) {
377 430368 : StackLimitCheck check(isolate_);
378 430368 : if (check.HasOverflowed()) {
379 21 : isolate_->StackOverflow();
380 21 : return EXCEPTION;
381 : }
382 :
383 : {
384 : DisallowHeapAllocation no_allocation;
385 964421 : for (size_t i = 0; i < stack_.size(); ++i) {
386 1231616 : if (*stack_[i].second == *object) {
387 : AllowHeapAllocation allow_to_return_error;
388 : Handle<String> circle_description =
389 79 : ConstructCircularStructureErrorMessage(key, i);
390 : Handle<Object> error = factory()->NewTypeError(
391 79 : MessageTemplate::kCircularStructure, circle_description);
392 79 : isolate_->Throw(*error);
393 : return EXCEPTION;
394 : }
395 : }
396 : }
397 430268 : stack_.emplace_back(key, object);
398 430268 : return SUCCESS;
399 : }
400 :
401 856312 : void JsonStringifier::StackPop() { stack_.pop_back(); }
402 :
403 : class CircularStructureMessageBuilder {
404 : public:
405 : explicit CircularStructureMessageBuilder(Isolate* isolate)
406 79 : : builder_(isolate) {}
407 :
408 79 : void AppendStartLine(Handle<Object> start_object) {
409 79 : builder_.AppendCString(kStartPrefix);
410 : builder_.AppendCString("starting at object with constructor ");
411 79 : AppendConstructorName(start_object);
412 79 : }
413 :
414 45 : void AppendNormalLine(Handle<Object> key, Handle<Object> object) {
415 45 : builder_.AppendCString(kLinePrefix);
416 45 : AppendKey(key);
417 : builder_.AppendCString(" -> object with constructor ");
418 45 : AppendConstructorName(object);
419 45 : }
420 :
421 79 : void AppendClosingLine(Handle<Object> closing_key) {
422 79 : builder_.AppendCString(kEndPrefix);
423 79 : AppendKey(closing_key);
424 : builder_.AppendCString(" closes the circle");
425 79 : }
426 :
427 10 : void AppendEllipsis() {
428 10 : builder_.AppendCString(kLinePrefix);
429 : builder_.AppendCString("...");
430 10 : }
431 :
432 79 : MaybeHandle<String> Finish() { return builder_.Finish(); }
433 :
434 : private:
435 124 : void AppendConstructorName(Handle<Object> object) {
436 124 : builder_.AppendCharacter('\'');
437 : Handle<String> constructor_name =
438 124 : JSReceiver::GetConstructorName(Handle<JSReceiver>::cast(object));
439 124 : builder_.AppendString(constructor_name);
440 : builder_.AppendCharacter('\'');
441 124 : }
442 :
443 : // A key can either be a string, the empty string or a Smi.
444 124 : void AppendKey(Handle<Object> key) {
445 248 : if (key->IsSmi()) {
446 51 : builder_.AppendCString("index ");
447 51 : AppendSmi(Smi::cast(*key));
448 175 : return;
449 : }
450 :
451 146 : CHECK(key->IsString());
452 73 : Handle<String> key_as_string = Handle<String>::cast(key);
453 73 : if (key_as_string->length() == 0) {
454 0 : builder_.AppendCString("<anonymous>");
455 : } else {
456 73 : builder_.AppendCString("property '");
457 73 : builder_.AppendString(key_as_string);
458 : builder_.AppendCharacter('\'');
459 : }
460 : }
461 :
462 51 : void AppendSmi(Smi smi) {
463 : static const int kBufferSize = 100;
464 : char chars[kBufferSize];
465 : Vector<char> buffer(chars, kBufferSize);
466 51 : builder_.AppendCString(IntToCString(smi->value(), buffer));
467 51 : }
468 :
469 : IncrementalStringBuilder builder_;
470 : static constexpr const char* kStartPrefix = "\n --> ";
471 : static constexpr const char* kEndPrefix = "\n --- ";
472 : static constexpr const char* kLinePrefix = "\n | ";
473 : };
474 :
475 79 : Handle<String> JsonStringifier::ConstructCircularStructureErrorMessage(
476 0 : Handle<Object> last_key, size_t start_index) {
477 : DCHECK(start_index < stack_.size());
478 79 : CircularStructureMessageBuilder builder(isolate_);
479 :
480 : // We track the index to be printed next for better readability.
481 79 : size_t index = start_index;
482 203 : const size_t stack_size = stack_.size();
483 :
484 158 : builder.AppendStartLine(stack_[index++].second);
485 :
486 : // Append a maximum of kCircularErrorMessagePrefixCount normal lines.
487 : const size_t prefix_end =
488 158 : std::min(stack_size, index + kCircularErrorMessagePrefixCount);
489 109 : for (; index < prefix_end; ++index) {
490 30 : builder.AppendNormalLine(stack_[index].first, stack_[index].second);
491 : }
492 :
493 : // If the circle consists of too many objects, we skip them and just
494 : // print an ellipsis.
495 79 : if (stack_size > index + kCircularErrorMessagePostfixCount) {
496 10 : builder.AppendEllipsis();
497 : }
498 :
499 : // Since we calculate the postfix lines from the back of the stack,
500 : // we have to ensure that lines are not printed twice.
501 158 : index = std::max(index, stack_size - kCircularErrorMessagePostfixCount);
502 94 : for (; index < stack_size; ++index) {
503 15 : builder.AppendNormalLine(stack_[index].first, stack_[index].second);
504 : }
505 :
506 79 : builder.AppendClosingLine(last_key);
507 :
508 : Handle<String> result;
509 79 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, result, builder.Finish(),
510 : factory()->empty_string());
511 79 : return result;
512 : }
513 :
514 : template <bool deferred_string_key>
515 12109248 : JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
516 : bool comma,
517 : Handle<Object> key) {
518 12109248 : StackLimitCheck interrupt_check(isolate_);
519 12109248 : Handle<Object> initial_value = object;
520 36327744 : if (interrupt_check.InterruptRequested() &&
521 12109658 : isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) {
522 : return EXCEPTION;
523 : }
524 47569310 : if (object->IsJSReceiver() || object->IsBigInt()) {
525 867808 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
526 : isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION);
527 : }
528 12109186 : if (!replacer_function_.is_null()) {
529 9933270 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
530 : isolate_, object, ApplyReplacerFunction(object, key, initial_value),
531 : EXCEPTION);
532 : }
533 :
534 24218372 : if (object->IsSmi()) {
535 : if (deferred_string_key) SerializeDeferredKey(comma, key);
536 238544 : return SerializeSmi(Smi::cast(*object));
537 : }
538 :
539 11870642 : switch (HeapObject::cast(*object)->map()->instance_type()) {
540 : case HEAP_NUMBER_TYPE:
541 : case MUTABLE_HEAP_NUMBER_TYPE:
542 : if (deferred_string_key) SerializeDeferredKey(comma, key);
543 3076 : return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
544 : case BIGINT_TYPE:
545 36 : isolate_->Throw(
546 108 : *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
547 36 : return EXCEPTION;
548 : case ODDBALL_TYPE:
549 9695870 : switch (Oddball::cast(*object)->kind()) {
550 : case Oddball::kFalse:
551 : if (deferred_string_key) SerializeDeferredKey(comma, key);
552 85 : builder_.AppendCString("false");
553 : return SUCCESS;
554 : case Oddball::kTrue:
555 : if (deferred_string_key) SerializeDeferredKey(comma, key);
556 153 : builder_.AppendCString("true");
557 : return SUCCESS;
558 : case Oddball::kNull:
559 : if (deferred_string_key) SerializeDeferredKey(comma, key);
560 190 : builder_.AppendCString("null");
561 : return SUCCESS;
562 : default:
563 : return UNCHANGED;
564 : }
565 : case JS_ARRAY_TYPE:
566 : if (deferred_string_key) SerializeDeferredKey(comma, key);
567 20842 : return SerializeJSArray(Handle<JSArray>::cast(object), key);
568 : case JS_VALUE_TYPE:
569 : if (deferred_string_key) SerializeDeferredKey(comma, key);
570 702 : return SerializeJSValue(Handle<JSValue>::cast(object), key);
571 : case SYMBOL_TYPE:
572 : return UNCHANGED;
573 : default:
574 4324078 : if (object->IsString()) {
575 : if (deferred_string_key) SerializeDeferredKey(comma, key);
576 1739878 : SerializeString(Handle<String>::cast(object));
577 1739878 : return SUCCESS;
578 : } else {
579 : DCHECK(object->IsJSReceiver());
580 844322 : if (object->IsCallable()) return UNCHANGED;
581 : // Go to slow path for global proxy and objects requiring access checks.
582 : if (deferred_string_key) SerializeDeferredKey(comma, key);
583 839678 : if (object->IsJSProxy()) {
584 410 : return SerializeJSProxy(Handle<JSProxy>::cast(object), key);
585 : }
586 838858 : return SerializeJSObject(Handle<JSObject>::cast(object), key);
587 : }
588 : }
589 :
590 : UNREACHABLE();
591 : }
592 :
593 702 : JsonStringifier::Result JsonStringifier::SerializeJSValue(
594 54 : Handle<JSValue> object, Handle<Object> key) {
595 702 : Object raw = object->value();
596 702 : if (raw->IsString()) {
597 : Handle<Object> value;
598 522 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
599 : isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
600 261 : SerializeString(Handle<String>::cast(value));
601 441 : } else if (raw->IsNumber()) {
602 : Handle<Object> value;
603 450 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
604 : isolate_, value, Object::ToNumber(isolate_, object), EXCEPTION);
605 639 : if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
606 36 : SerializeHeapNumber(Handle<HeapNumber>::cast(value));
607 216 : } else if (raw->IsBigInt()) {
608 : isolate_->Throw(
609 108 : *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
610 54 : return EXCEPTION;
611 162 : } else if (raw->IsBoolean()) {
612 108 : builder_.AppendCString(raw->IsTrue(isolate_) ? "true" : "false");
613 : } else {
614 : // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
615 : return SerializeJSObject(object, key);
616 : }
617 : return SUCCESS;
618 : }
619 :
620 242990 : JsonStringifier::Result JsonStringifier::SerializeSmi(Smi object) {
621 : static const int kBufferSize = 100;
622 : char chars[kBufferSize];
623 : Vector<char> buffer(chars, kBufferSize);
624 242990 : builder_.AppendCString(IntToCString(object->value(), buffer));
625 242990 : return SUCCESS;
626 : }
627 :
628 2106 : JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
629 2106 : if (std::isinf(number) || std::isnan(number)) {
630 162 : builder_.AppendCString("null");
631 : return SUCCESS;
632 : }
633 : static const int kBufferSize = 100;
634 : char chars[kBufferSize];
635 : Vector<char> buffer(chars, kBufferSize);
636 1944 : builder_.AppendCString(DoubleToCString(number, buffer));
637 : return SUCCESS;
638 : }
639 :
640 : JsonStringifier::Result JsonStringifier::SerializeJSArray(
641 : Handle<JSArray> object, Handle<Object> key) {
642 10421 : HandleScope handle_scope(isolate_);
643 10421 : Result stack_push = StackPush(object, key);
644 10421 : if (stack_push != SUCCESS) return stack_push;
645 10376 : uint32_t length = 0;
646 10376 : CHECK(object->length()->ToArrayLength(&length));
647 : DCHECK(!object->IsAccessCheckNeeded());
648 4010 : builder_.AppendCharacter('[');
649 : Indent();
650 : uint32_t i = 0;
651 10376 : if (replacer_function_.is_null()) {
652 6357 : switch (object->GetElementsKind()) {
653 : case PACKED_SMI_ELEMENTS: {
654 1980 : Handle<FixedArray> elements(FixedArray::cast(object->elements()),
655 2970 : isolate_);
656 990 : StackLimitCheck interrupt_check(isolate_);
657 5247 : while (i < length) {
658 8514 : if (interrupt_check.InterruptRequested() &&
659 0 : isolate_->stack_guard()->HandleInterrupts()->IsException(
660 4257 : isolate_)) {
661 0 : return EXCEPTION;
662 : }
663 : Separator(i == 0);
664 12771 : SerializeSmi(Smi::cast(elements->get(i)));
665 4257 : i++;
666 : }
667 990 : break;
668 : }
669 : case PACKED_DOUBLE_ELEMENTS: {
670 : // Empty array is FixedArray but not FixedDoubleArray.
671 517 : if (length == 0) break;
672 : Handle<FixedDoubleArray> elements(
673 1524 : FixedDoubleArray::cast(object->elements()), isolate_);
674 508 : StackLimitCheck interrupt_check(isolate_);
675 1040 : while (i < length) {
676 1064 : if (interrupt_check.InterruptRequested() &&
677 0 : isolate_->stack_guard()->HandleInterrupts()->IsException(
678 532 : isolate_)) {
679 0 : return EXCEPTION;
680 : }
681 : Separator(i == 0);
682 1064 : SerializeDouble(elements->get_scalar(i));
683 532 : i++;
684 : }
685 : break;
686 : }
687 : case PACKED_ELEMENTS: {
688 13251 : Handle<Object> old_length(object->length(), isolate_);
689 373799 : while (i < length) {
690 1111431 : if (object->length() != *old_length ||
691 740939 : object->GetElementsKind() != PACKED_ELEMENTS) {
692 : // Fall back to slow path.
693 : break;
694 : }
695 : Separator(i == 0);
696 : Result result = SerializeElement(
697 : isolate_,
698 740858 : Handle<Object>(FixedArray::cast(object->elements())->get(i),
699 : isolate_),
700 1481716 : i);
701 370429 : if (result == UNCHANGED) {
702 : builder_.AppendCString("null");
703 370265 : } else if (result != SUCCESS) {
704 : return result;
705 : }
706 369382 : i++;
707 : }
708 : break;
709 : }
710 : // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
711 : // the non-holey cases except that a lookup is necessary for holes.
712 : default:
713 : break;
714 : }
715 : }
716 9329 : if (i < length) {
717 : // Slow path for non-fast elements and fall-back in edge case.
718 3876 : Result result = SerializeArrayLikeSlow(object, i, length);
719 3876 : if (result != SUCCESS) return result;
720 : }
721 : Unindent();
722 9273 : if (length > 0) NewLine();
723 : builder_.AppendCharacter(']');
724 9273 : StackPop();
725 10421 : return SUCCESS;
726 : }
727 :
728 3912 : JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
729 : Handle<JSReceiver> object, uint32_t start, uint32_t length) {
730 : // We need to write out at least two characters per array element.
731 : static const int kMaxSerializableArrayLength = String::kMaxLength / 2;
732 3912 : if (length > kMaxSerializableArrayLength) {
733 10 : isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
734 5 : return EXCEPTION;
735 : }
736 9649847 : for (uint32_t i = start; i < length; i++) {
737 : Separator(i == 0);
738 : Handle<Object> element;
739 19299796 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
740 : isolate_, element, JSReceiver::GetElement(isolate_, object, i),
741 : EXCEPTION);
742 9649889 : Result result = SerializeElement(isolate_, element, i);
743 9649889 : if (result == SUCCESS) continue;
744 9461514 : if (result == UNCHANGED) {
745 : // Detect overflow sooner for large sparse arrays.
746 9461472 : if (builder_.HasOverflowed()) return EXCEPTION;
747 9461472 : builder_.AppendCString("null");
748 : } else {
749 : return result;
750 : }
751 : }
752 : return SUCCESS;
753 : }
754 :
755 : JsonStringifier::Result JsonStringifier::SerializeJSObject(
756 : Handle<JSObject> object, Handle<Object> key) {
757 419537 : HandleScope handle_scope(isolate_);
758 419537 : Result stack_push = StackPush(object, key);
759 419537 : if (stack_push != SUCCESS) return stack_push;
760 :
761 838694 : if (property_list_.is_null() &&
762 1257724 : !object->map()->IsCustomElementsReceiverMap() &&
763 1257240 : object->HasFastProperties() && object->elements()->length() == 0) {
764 : DCHECK(!object->IsJSGlobalProxy());
765 : DCHECK(!object->HasIndexedInterceptor());
766 : DCHECK(!object->HasNamedInterceptor());
767 1255719 : Handle<Map> map(object->map(), isolate_);
768 280691 : builder_.AppendCharacter('{');
769 : Indent();
770 : bool comma = false;
771 2309511 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
772 2838069 : Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
773 : // TODO(rossberg): Should this throw?
774 1892190 : if (!name->IsString()) continue;
775 946023 : Handle<String> key = Handle<String>::cast(name);
776 946023 : PropertyDetails details = map->instance_descriptors()->GetDetails(i);
777 946023 : if (details.IsDontEnum()) continue;
778 : Handle<Object> property;
779 2837583 : if (details.location() == kField && *map == object->map()) {
780 : DCHECK_EQ(kData, details.kind());
781 945816 : FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
782 : property = JSObject::FastPropertyAt(object, details.representation(),
783 945816 : field_index);
784 : } else {
785 680 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
786 : isolate_, property,
787 : Object::GetPropertyOrElement(isolate_, object, key), EXCEPTION);
788 : }
789 : Result result = SerializeProperty(property, comma, key);
790 945879 : if (!comma && result == SUCCESS) comma = true;
791 945879 : if (result == EXCEPTION) return result;
792 : }
793 : Unindent();
794 418019 : if (comma) NewLine();
795 : builder_.AppendCharacter('}');
796 : } else {
797 909 : Result result = SerializeJSReceiverSlow(object);
798 909 : if (result != SUCCESS) return result;
799 : }
800 418883 : StackPop();
801 419537 : return SUCCESS;
802 : }
803 :
804 1265 : JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
805 : Handle<JSReceiver> object) {
806 1265 : Handle<FixedArray> contents = property_list_;
807 1265 : if (contents.is_null()) {
808 1990 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
809 : isolate_, contents,
810 : KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
811 : ENUMERABLE_STRINGS,
812 : GetKeysConversion::kConvertToString),
813 : EXCEPTION);
814 : }
815 1247 : builder_.AppendCharacter('{');
816 : Indent();
817 : bool comma = false;
818 10470 : for (int i = 0; i < contents->length(); i++) {
819 4020 : Handle<String> key(String::cast(contents->get(i)), isolate_);
820 : Handle<Object> property;
821 8040 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
822 : isolate_, property, Object::GetPropertyOrElement(isolate_, object, key),
823 : EXCEPTION);
824 : Result result = SerializeProperty(property, comma, key);
825 4020 : if (!comma && result == SUCCESS) comma = true;
826 4020 : if (result == EXCEPTION) return result;
827 : }
828 : Unindent();
829 1215 : if (comma) NewLine();
830 : builder_.AppendCharacter('}');
831 : return SUCCESS;
832 : }
833 :
834 410 : JsonStringifier::Result JsonStringifier::SerializeJSProxy(
835 : Handle<JSProxy> object, Handle<Object> key) {
836 410 : HandleScope scope(isolate_);
837 410 : Result stack_push = StackPush(object, key);
838 410 : if (stack_push != SUCCESS) return stack_push;
839 : Maybe<bool> is_array = Object::IsArray(object);
840 410 : if (is_array.IsNothing()) return EXCEPTION;
841 410 : if (is_array.FromJust()) {
842 : Handle<Object> length_object;
843 126 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
844 : isolate_, length_object,
845 : Object::GetLengthFromArrayLike(isolate_,
846 : Handle<JSReceiver>::cast(object)),
847 : EXCEPTION);
848 : uint32_t length;
849 45 : if (!length_object->ToUint32(&length)) {
850 : // Technically, we need to be able to handle lengths outside the
851 : // uint32_t range. However, we would run into string size overflow
852 : // if we tried to stringify such an array.
853 18 : isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
854 9 : return EXCEPTION;
855 : }
856 36 : builder_.AppendCharacter('[');
857 : Indent();
858 72 : Result result = SerializeArrayLikeSlow(object, 0, length);
859 36 : if (result != SUCCESS) return result;
860 : Unindent();
861 36 : if (length > 0) NewLine();
862 : builder_.AppendCharacter(']');
863 : } else {
864 356 : Result result = SerializeJSReceiverSlow(object);
865 356 : if (result != SUCCESS) return result;
866 : }
867 : StackPop();
868 387 : return SUCCESS;
869 : }
870 :
871 : template <typename SrcChar, typename DestChar>
872 : void JsonStringifier::SerializeStringUnchecked_(
873 : Vector<const SrcChar> src,
874 : IncrementalStringBuilder::NoExtend<DestChar>* dest) {
875 : // Assert that uc16 character is not truncated down to 8 bit.
876 : // The <uc16, char> version of this method must not be called.
877 : DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
878 43985323 : for (int i = 0; i < src.length(); i++) {
879 43985323 : SrcChar c = src[i];
880 43985323 : if (DoNotEscape(c)) {
881 : dest->Append(c);
882 57117 : } else if (FLAG_harmony_json_stringify && c >= 0xD800 && c <= 0xDFFF) {
883 : // The current character is a surrogate.
884 57108 : if (c <= 0xDBFF) {
885 : // The current character is a leading surrogate.
886 29430 : if (i + 1 < src.length()) {
887 : // There is a next character.
888 1752 : SrcChar next = src[i + 1];
889 1752 : if (next >= 0xDC00 && next <= 0xDFFF) {
890 : // The next character is a trailing surrogate, meaning this is a
891 : // surrogate pair.
892 : dest->Append(c);
893 : dest->Append(next);
894 : i++;
895 : } else {
896 : // The next character is not a trailing surrogate. Thus, the
897 : // current character is a lone leading surrogate.
898 : dest->AppendCString("\\u");
899 0 : char* const hex = DoubleToRadixCString(c, 16);
900 : dest->AppendCString(hex);
901 0 : DeleteArray(hex);
902 : }
903 : } else {
904 : // There is no next character. Thus, the current character is a lone
905 : // leading surrogate.
906 : dest->AppendCString("\\u");
907 27678 : char* const hex = DoubleToRadixCString(c, 16);
908 : dest->AppendCString(hex);
909 27678 : DeleteArray(hex);
910 : }
911 : } else {
912 : // The current character is a lone trailing surrogate. (If it had been
913 : // preceded by a leading surrogate, we would've ended up in the other
914 : // branch earlier on, and the current character would've been handled
915 : // as part of the surrogate pair already.)
916 : dest->AppendCString("\\u");
917 27678 : char* const hex = DoubleToRadixCString(c, 16);
918 : dest->AppendCString(hex);
919 27678 : DeleteArray(hex);
920 : }
921 : } else {
922 5975 : dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
923 : }
924 : }
925 : }
926 :
927 : template <typename SrcChar, typename DestChar>
928 : void JsonStringifier::SerializeString_(Handle<String> string) {
929 2643549 : int length = string->length();
930 2643549 : builder_.Append<uint8_t, DestChar>('"');
931 : // We might be able to fit the whole escaped string in the current string
932 : // part, or we might need to allocate.
933 2643549 : if (int worst_case_length = builder_.EscapedLengthIfCurrentPartFits(length)) {
934 : DisallowHeapAllocation no_gc;
935 2894002 : Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(no_gc);
936 : IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
937 1447001 : &builder_, worst_case_length, no_gc);
938 1447001 : SerializeStringUnchecked_(vector, &no_extend);
939 : } else {
940 1196548 : FlatStringReader reader(isolate_, string);
941 2441860297 : for (int i = 0; i < reader.length(); i++) {
942 2441860297 : SrcChar c = reader.Get<SrcChar>(i);
943 2441860297 : if (DoNotEscape(c)) {
944 : builder_.Append<SrcChar, DestChar>(c);
945 369 : } else if (FLAG_harmony_json_stringify && c >= 0xD800 && c <= 0xDFFF) {
946 : // The current character is a surrogate.
947 0 : if (c <= 0xDBFF) {
948 : // The current character is a leading surrogate.
949 0 : if (i + 1 < reader.length()) {
950 : // There is a next character.
951 0 : SrcChar next = reader.Get<SrcChar>(i + 1);
952 0 : if (next >= 0xDC00 && next <= 0xDFFF) {
953 : // The next character is a trailing surrogate, meaning this is a
954 : // surrogate pair.
955 : builder_.Append<SrcChar, DestChar>(c);
956 : builder_.Append<SrcChar, DestChar>(next);
957 : i++;
958 : } else {
959 : // The next character is not a trailing surrogate. Thus, the
960 : // current character is a lone leading surrogate.
961 : builder_.AppendCString("\\u");
962 0 : char* const hex = DoubleToRadixCString(c, 16);
963 : builder_.AppendCString(hex);
964 0 : DeleteArray(hex);
965 : }
966 : } else {
967 : // There is no next character. Thus, the current character is a
968 : // lone leading surrogate.
969 : builder_.AppendCString("\\u");
970 0 : char* const hex = DoubleToRadixCString(c, 16);
971 : builder_.AppendCString(hex);
972 0 : DeleteArray(hex);
973 : }
974 : } else {
975 : // The current character is a lone trailing surrogate. (If it had
976 : // been preceded by a leading surrogate, we would've ended up in the
977 : // other branch earlier on, and the current character would've been
978 : // handled as part of the surrogate pair already.)
979 : builder_.AppendCString("\\u");
980 0 : char* const hex = DoubleToRadixCString(c, 16);
981 : builder_.AppendCString(hex);
982 0 : DeleteArray(hex);
983 : }
984 : } else {
985 9839442 : builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
986 : }
987 1196548 : }
988 : }
989 : builder_.Append<uint8_t, DestChar>('"');
990 : }
991 :
992 : template <>
993 2484710284 : bool JsonStringifier::DoNotEscape(uint8_t c) {
994 : // https://tc39.github.io/ecma262/#table-json-single-character-escapes
995 2484710284 : return c >= 0x23 && c <= 0x7E && c != 0x5C;
996 : }
997 :
998 : template <>
999 1135336 : bool JsonStringifier::DoNotEscape(uint16_t c) {
1000 : // https://tc39.github.io/ecma262/#table-json-single-character-escapes
1001 2270294 : return c >= 0x23 && c != 0x5C && c != 0x7F &&
1002 2269916 : (!FLAG_harmony_json_stringify || (c < 0xD800 || c > 0xDFFF));
1003 : }
1004 :
1005 : void JsonStringifier::NewLine() {
1006 11343824 : if (gap_ == nullptr) return;
1007 4810404 : builder_.AppendCharacter('\n');
1008 9804272 : for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
1009 : }
1010 :
1011 : void JsonStringifier::Separator(bool first) {
1012 10928526 : if (!first) builder_.AppendCharacter(',');
1013 : NewLine();
1014 : }
1015 :
1016 : void JsonStringifier::SerializeDeferredKey(bool deferred_comma,
1017 : Handle<Object> deferred_key) {
1018 : Separator(!deferred_comma);
1019 903410 : SerializeString(Handle<String>::cast(deferred_key));
1020 903410 : builder_.AppendCharacter(':');
1021 903410 : if (gap_ != nullptr) builder_.AppendCharacter(' ');
1022 : }
1023 :
1024 3362662 : void JsonStringifier::SerializeString(Handle<String> object) {
1025 3362662 : object = String::Flatten(isolate_, object);
1026 3362662 : if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
1027 2643496 : if (String::IsOneByteRepresentationUnderneath(*object)) {
1028 : SerializeString_<uint8_t, uint8_t>(object);
1029 : } else {
1030 719113 : builder_.ChangeEncoding();
1031 719113 : SerializeString(object);
1032 : }
1033 : } else {
1034 719166 : if (String::IsOneByteRepresentationUnderneath(*object)) {
1035 : SerializeString_<uint8_t, uc16>(object);
1036 : } else {
1037 : SerializeString_<uc16, uc16>(object);
1038 : }
1039 : }
1040 3362662 : }
1041 :
1042 : } // namespace internal
1043 178779 : } // namespace v8
|