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