V8 Project
json-stringifier.h
Go to the documentation of this file.
1 // Copyright 2012 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 #ifndef V8_JSON_STRINGIFIER_H_
6 #define V8_JSON_STRINGIFIER_H_
7 
8 #include "src/v8.h"
9 
10 #include "src/conversions.h"
11 #include "src/utils.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 class BasicJsonStringifier BASE_EMBEDDED {
17  public:
18  explicit BasicJsonStringifier(Isolate* isolate);
19 
21 
22  MUST_USE_RESULT INLINE(static MaybeHandle<Object> StringifyString(
23  Isolate* isolate,
24  Handle<String> object));
25 
26  private:
27  static const int kInitialPartLength = 32;
28  static const int kMaxPartLength = 16 * 1024;
29  static const int kPartLengthGrowthFactor = 2;
30 
31  enum Result { UNCHANGED, SUCCESS, EXCEPTION };
32 
33  void Accumulate();
34 
35  void Extend();
36 
38 
39  INLINE(void ShrinkCurrentPart());
40 
41  template <bool is_one_byte, typename Char>
42  INLINE(void Append_(Char c));
43 
44  template <bool is_one_byte, typename Char>
45  INLINE(void Append_(const Char* chars));
46 
47  INLINE(void Append(uint8_t c)) {
48  if (is_one_byte_) {
49  Append_<true>(c);
50  } else {
51  Append_<false>(c);
52  }
53  }
54 
55  INLINE(void AppendOneByte(const char* chars)) {
56  if (is_one_byte_) {
57  Append_<true>(reinterpret_cast<const uint8_t*>(chars));
58  } else {
59  Append_<false>(reinterpret_cast<const uint8_t*>(chars));
60  }
61  }
62 
64  Handle<Object> object,
65  Handle<Object> key);
66 
68  Handle<Object> key,
69  bool deferred_comma,
70  bool deferred_key);
71 
72  template <typename ResultType, typename Char>
73  INLINE(static Handle<String> StringifyString_(Isolate* isolate,
74  Vector<Char> vector,
75  Handle<String> result));
76 
77  // Entry point to serialize the object.
78  INLINE(Result SerializeObject(Handle<Object> obj)) {
79  return Serialize_<false>(obj, false, factory_->empty_string());
80  }
81 
82  // Serialize an array element.
83  // The index may serve as argument for the toJSON function.
84  INLINE(Result SerializeElement(Isolate* isolate,
85  Handle<Object> object,
86  int i)) {
87  return Serialize_<false>(object,
88  false,
89  Handle<Object>(Smi::FromInt(i), isolate));
90  }
91 
92  // Serialize a object property.
93  // The key may or may not be serialized depending on the property.
94  // The key may also serve as argument for the toJSON function.
95  INLINE(Result SerializeProperty(Handle<Object> object,
96  bool deferred_comma,
97  Handle<String> deferred_key)) {
98  DCHECK(!deferred_key.is_null());
99  return Serialize_<true>(object, deferred_comma, deferred_key);
100  }
101 
102  template <bool deferred_string_key>
103  Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
104 
105  void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
106  if (deferred_comma) Append(',');
107  SerializeString(Handle<String>::cast(deferred_key));
108  Append(':');
109  }
110 
112 
113  Result SerializeDouble(double number);
114  INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
115  return SerializeDouble(object->value());
116  }
117 
119 
120  INLINE(Result SerializeJSArray(Handle<JSArray> object));
121  INLINE(Result SerializeJSObject(Handle<JSObject> object));
122 
124 
126 
127  template <typename SrcChar, typename DestChar>
128  INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
129  DestChar* dest,
130  int length));
131 
132  template <bool is_one_byte, typename Char>
133  INLINE(void SerializeString_(Handle<String> string));
134 
135  template <typename Char>
136  INLINE(static bool DoNotEscape(Char c));
137 
138  template <typename Char>
140 
142  void StackPop();
143 
144  INLINE(Handle<String> accumulator()) {
145  return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
146  }
147 
148  INLINE(void set_accumulator(Handle<String> string)) {
149  return accumulator_store_->set_value(*string);
150  }
151 
152  Isolate* isolate_;
153  Factory* factory_;
154  // We use a value wrapper for the string accumulator to keep the
155  // (indirect) handle to it in the outermost handle scope.
164 
165  static const int kJsonEscapeTableEntrySize = 8;
166  static const char* const JsonEscapeTable;
167 };
168 
169 
170 // Translation table to escape Latin1 characters.
171 // Table entries start at a multiple of 8 and are null-terminated.
172 const char* const BasicJsonStringifier::JsonEscapeTable =
173  "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
174  "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
175  "\\b\0 \\t\0 \\n\0 \\u000b\0 "
176  "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
177  "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
178  "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
179  "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
180  "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
181  " \0 !\0 \\\"\0 #\0 "
182  "$\0 %\0 &\0 '\0 "
183  "(\0 )\0 *\0 +\0 "
184  ",\0 -\0 .\0 /\0 "
185  "0\0 1\0 2\0 3\0 "
186  "4\0 5\0 6\0 7\0 "
187  "8\0 9\0 :\0 ;\0 "
188  "<\0 =\0 >\0 ?\0 "
189  "@\0 A\0 B\0 C\0 "
190  "D\0 E\0 F\0 G\0 "
191  "H\0 I\0 J\0 K\0 "
192  "L\0 M\0 N\0 O\0 "
193  "P\0 Q\0 R\0 S\0 "
194  "T\0 U\0 V\0 W\0 "
195  "X\0 Y\0 Z\0 [\0 "
196  "\\\\\0 ]\0 ^\0 _\0 "
197  "`\0 a\0 b\0 c\0 "
198  "d\0 e\0 f\0 g\0 "
199  "h\0 i\0 j\0 k\0 "
200  "l\0 m\0 n\0 o\0 "
201  "p\0 q\0 r\0 s\0 "
202  "t\0 u\0 v\0 w\0 "
203  "x\0 y\0 z\0 {\0 "
204  "|\0 }\0 ~\0 \177\0 "
205  "\200\0 \201\0 \202\0 \203\0 "
206  "\204\0 \205\0 \206\0 \207\0 "
207  "\210\0 \211\0 \212\0 \213\0 "
208  "\214\0 \215\0 \216\0 \217\0 "
209  "\220\0 \221\0 \222\0 \223\0 "
210  "\224\0 \225\0 \226\0 \227\0 "
211  "\230\0 \231\0 \232\0 \233\0 "
212  "\234\0 \235\0 \236\0 \237\0 "
213  "\240\0 \241\0 \242\0 \243\0 "
214  "\244\0 \245\0 \246\0 \247\0 "
215  "\250\0 \251\0 \252\0 \253\0 "
216  "\254\0 \255\0 \256\0 \257\0 "
217  "\260\0 \261\0 \262\0 \263\0 "
218  "\264\0 \265\0 \266\0 \267\0 "
219  "\270\0 \271\0 \272\0 \273\0 "
220  "\274\0 \275\0 \276\0 \277\0 "
221  "\300\0 \301\0 \302\0 \303\0 "
222  "\304\0 \305\0 \306\0 \307\0 "
223  "\310\0 \311\0 \312\0 \313\0 "
224  "\314\0 \315\0 \316\0 \317\0 "
225  "\320\0 \321\0 \322\0 \323\0 "
226  "\324\0 \325\0 \326\0 \327\0 "
227  "\330\0 \331\0 \332\0 \333\0 "
228  "\334\0 \335\0 \336\0 \337\0 "
229  "\340\0 \341\0 \342\0 \343\0 "
230  "\344\0 \345\0 \346\0 \347\0 "
231  "\350\0 \351\0 \352\0 \353\0 "
232  "\354\0 \355\0 \356\0 \357\0 "
233  "\360\0 \361\0 \362\0 \363\0 "
234  "\364\0 \365\0 \366\0 \367\0 "
235  "\370\0 \371\0 \372\0 \373\0 "
236  "\374\0 \375\0 \376\0 \377\0 ";
237 
238 
239 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
240  : isolate_(isolate),
241  current_index_(0),
242  is_one_byte_(true),
243  overflowed_(false) {
246  Object::ToObject(isolate, factory_->empty_string()).ToHandleChecked());
248  current_part_ = factory_->NewRawOneByteString(part_length_).ToHandleChecked();
249  tojson_string_ = factory_->toJSON_string();
250  stack_ = factory_->NewJSArray(8);
251 }
252 
253 
254 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
255  Result result = SerializeObject(object);
256  if (result == UNCHANGED) return isolate_->factory()->undefined_value();
257  if (result == SUCCESS) {
258  ShrinkCurrentPart();
259  Accumulate();
260  if (overflowed_) {
261  THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), Object);
262  }
263  return accumulator();
264  }
265  DCHECK(result == EXCEPTION);
266  return MaybeHandle<Object>();
267 }
268 
269 
270 MaybeHandle<Object> BasicJsonStringifier::StringifyString(
271  Isolate* isolate, Handle<String> object) {
272  static const int kJsonQuoteWorstCaseBlowup = 6;
273  static const int kSpaceForQuotes = 2;
274  int worst_case_length =
275  object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
276 
277  if (worst_case_length > 32 * KB) { // Slow path if too large.
278  BasicJsonStringifier stringifier(isolate);
279  return stringifier.Stringify(object);
280  }
281 
282  object = String::Flatten(object);
283  DCHECK(object->IsFlat());
284  if (object->IsOneByteRepresentationUnderneath()) {
285  Handle<String> result = isolate->factory()->NewRawOneByteString(
286  worst_case_length).ToHandleChecked();
288  return StringifyString_<SeqOneByteString>(
289  isolate,
290  object->GetFlatContent().ToOneByteVector(),
291  result);
292  } else {
293  Handle<String> result = isolate->factory()->NewRawTwoByteString(
294  worst_case_length).ToHandleChecked();
296  return StringifyString_<SeqTwoByteString>(
297  isolate,
298  object->GetFlatContent().ToUC16Vector(),
299  result);
300  }
301 }
302 
303 
304 template <typename ResultType, typename Char>
305 Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate,
306  Vector<Char> vector,
307  Handle<String> result) {
309  int final_size = 0;
310  ResultType* dest = ResultType::cast(*result);
311  dest->Set(final_size++, '\"');
312  final_size += SerializeStringUnchecked_(vector.start(),
313  dest->GetChars() + 1,
314  vector.length());
315  dest->Set(final_size++, '\"');
316  return SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
317 }
318 
319 
320 template <bool is_one_byte, typename Char>
321 void BasicJsonStringifier::Append_(Char c) {
322  if (is_one_byte) {
323  SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
324  current_index_++, c);
325  } else {
326  SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
327  current_index_++, c);
328  }
329  if (current_index_ == part_length_) Extend();
330 }
331 
332 
333 template <bool is_one_byte, typename Char>
334 void BasicJsonStringifier::Append_(const Char* chars) {
335  for (; *chars != '\0'; chars++) Append_<is_one_byte, Char>(*chars);
336 }
337 
338 
339 MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
340  Handle<Object> object, Handle<Object> key) {
341  LookupIterator it(object, tojson_string_,
342  LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
343  Handle<Object> fun;
345  if (!fun->IsJSFunction()) return object;
346 
347  // Call toJSON function.
348  if (key->IsSmi()) key = factory_->NumberToString(key);
349  Handle<Object> argv[] = { key };
350  HandleScope scope(isolate_);
352  isolate_, object,
353  Execution::Call(isolate_, fun, object, 1, argv),
354  Object);
355  return scope.CloseAndEscape(object);
356 }
357 
358 
359 BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
360  Handle<Object> object) {
361  StackLimitCheck check(isolate_);
362  if (check.HasOverflowed()) {
363  isolate_->StackOverflow();
364  return EXCEPTION;
365  }
366 
367  int length = Smi::cast(stack_->length())->value();
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  MaybeHandle<Object> maybe_error = factory_->NewTypeError(
376  "circular_structure", HandleVector<Object>(NULL, 0));
377  if (maybe_error.ToHandle(&error)) isolate_->Throw(*error);
378  return EXCEPTION;
379  }
380  }
381  }
382  JSArray::EnsureSize(stack_, length + 1);
383  FixedArray::cast(stack_->elements())->set(length, *object);
384  stack_->set_length(Smi::FromInt(length + 1));
385  return SUCCESS;
386 }
387 
388 
389 void BasicJsonStringifier::StackPop() {
390  int length = Smi::cast(stack_->length())->value();
391  stack_->set_length(Smi::FromInt(length - 1));
392 }
393 
394 
395 template <bool deferred_string_key>
396 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
397  Handle<Object> object, bool comma, Handle<Object> key) {
398  if (object->IsJSObject()) {
400  isolate_, object,
401  ApplyToJsonFunction(object, key),
402  EXCEPTION);
403  }
404 
405  if (object->IsSmi()) {
406  if (deferred_string_key) SerializeDeferredKey(comma, key);
407  return SerializeSmi(Smi::cast(*object));
408  }
409 
410  switch (HeapObject::cast(*object)->map()->instance_type()) {
411  case HEAP_NUMBER_TYPE:
413  if (deferred_string_key) SerializeDeferredKey(comma, key);
414  return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
415  case ODDBALL_TYPE:
416  switch (Oddball::cast(*object)->kind()) {
417  case Oddball::kFalse:
418  if (deferred_string_key) SerializeDeferredKey(comma, key);
419  AppendOneByte("false");
420  return SUCCESS;
421  case Oddball::kTrue:
422  if (deferred_string_key) SerializeDeferredKey(comma, key);
423  AppendOneByte("true");
424  return SUCCESS;
425  case Oddball::kNull:
426  if (deferred_string_key) SerializeDeferredKey(comma, key);
427  AppendOneByte("null");
428  return SUCCESS;
429  default:
430  return UNCHANGED;
431  }
432  case JS_ARRAY_TYPE:
433  if (object->IsAccessCheckNeeded()) break;
434  if (deferred_string_key) SerializeDeferredKey(comma, key);
435  return SerializeJSArray(Handle<JSArray>::cast(object));
436  case JS_VALUE_TYPE:
437  if (deferred_string_key) SerializeDeferredKey(comma, key);
438  return SerializeJSValue(Handle<JSValue>::cast(object));
439  case JS_FUNCTION_TYPE:
440  return UNCHANGED;
441  default:
442  if (object->IsString()) {
443  if (deferred_string_key) SerializeDeferredKey(comma, key);
444  SerializeString(Handle<String>::cast(object));
445  return SUCCESS;
446  } else if (object->IsJSObject()) {
447  // Go to slow path for global proxy and objects requiring access checks.
448  if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break;
449  if (deferred_string_key) SerializeDeferredKey(comma, key);
450  return SerializeJSObject(Handle<JSObject>::cast(object));
451  }
452  }
453 
454  return SerializeGeneric(object, key, comma, deferred_string_key);
455 }
456 
457 
458 BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
459  Handle<Object> object,
460  Handle<Object> key,
461  bool deferred_comma,
462  bool deferred_key) {
463  Handle<JSObject> builtins(isolate_->native_context()->builtins(), isolate_);
464  Handle<JSFunction> builtin = Handle<JSFunction>::cast(Object::GetProperty(
465  isolate_, builtins, "JSONSerializeAdapter").ToHandleChecked());
466 
467  Handle<Object> argv[] = { key, object };
468  Handle<Object> result;
470  isolate_, result,
471  Execution::Call(isolate_, builtin, object, 2, argv),
472  EXCEPTION);
473  if (result->IsUndefined()) return UNCHANGED;
474  if (deferred_key) {
475  if (key->IsSmi()) key = factory_->NumberToString(key);
476  SerializeDeferredKey(deferred_comma, key);
477  }
478 
479  Handle<String> result_string = Handle<String>::cast(result);
480  // Shrink current part, attach it to the accumulator, also attach the result
481  // string to the accumulator, and allocate a new part.
482  ShrinkCurrentPart(); // Shrink.
483  part_length_ = kInitialPartLength; // Allocate conservatively.
484  Extend(); // Attach current part and allocate new part.
485  // Attach result string to the accumulator.
486  Handle<String> cons;
488  isolate_, cons,
489  factory_->NewConsString(accumulator(), result_string),
490  EXCEPTION);
491  set_accumulator(cons);
492  return SUCCESS;
493 }
494 
495 
496 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
497  Handle<JSValue> object) {
498  String* class_name = object->class_name();
499  if (class_name == isolate_->heap()->String_string()) {
500  Handle<Object> value;
502  isolate_, value, Execution::ToString(isolate_, object), EXCEPTION);
503  SerializeString(Handle<String>::cast(value));
504  } else if (class_name == isolate_->heap()->Number_string()) {
505  Handle<Object> value;
507  isolate_, value, Execution::ToNumber(isolate_, object), EXCEPTION);
508  if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
509  SerializeHeapNumber(Handle<HeapNumber>::cast(value));
510  } else {
511  DCHECK(class_name == isolate_->heap()->Boolean_string());
512  Object* value = JSValue::cast(*object)->value();
513  DCHECK(value->IsBoolean());
514  AppendOneByte(value->IsTrue() ? "true" : "false");
515  }
516  return SUCCESS;
517 }
518 
519 
520 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
521  static const int kBufferSize = 100;
522  char chars[kBufferSize];
523  Vector<char> buffer(chars, kBufferSize);
524  AppendOneByte(IntToCString(object->value(), buffer));
525  return SUCCESS;
526 }
527 
528 
529 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
530  double number) {
531  if (std::isinf(number) || std::isnan(number)) {
532  AppendOneByte("null");
533  return SUCCESS;
534  }
535  static const int kBufferSize = 100;
536  char chars[kBufferSize];
537  Vector<char> buffer(chars, kBufferSize);
538  AppendOneByte(DoubleToCString(number, buffer));
539  return SUCCESS;
540 }
541 
542 
543 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
544  Handle<JSArray> object) {
545  HandleScope handle_scope(isolate_);
546  Result stack_push = StackPush(object);
547  if (stack_push != SUCCESS) return stack_push;
548  uint32_t length = 0;
549  CHECK(object->length()->ToArrayIndex(&length));
550  Append('[');
551  switch (object->GetElementsKind()) {
552  case FAST_SMI_ELEMENTS: {
553  Handle<FixedArray> elements(
554  FixedArray::cast(object->elements()), isolate_);
555  for (uint32_t i = 0; i < length; i++) {
556  if (i > 0) Append(',');
557  SerializeSmi(Smi::cast(elements->get(i)));
558  }
559  break;
560  }
561  case FAST_DOUBLE_ELEMENTS: {
562  // Empty array is FixedArray but not FixedDoubleArray.
563  if (length == 0) break;
564  Handle<FixedDoubleArray> elements(
565  FixedDoubleArray::cast(object->elements()), isolate_);
566  for (uint32_t i = 0; i < length; i++) {
567  if (i > 0) Append(',');
568  SerializeDouble(elements->get_scalar(i));
569  }
570  break;
571  }
572  case FAST_ELEMENTS: {
573  Handle<FixedArray> elements(
574  FixedArray::cast(object->elements()), isolate_);
575  for (uint32_t i = 0; i < length; i++) {
576  if (i > 0) Append(',');
577  Result result =
578  SerializeElement(isolate_,
579  Handle<Object>(elements->get(i), isolate_),
580  i);
581  if (result == SUCCESS) continue;
582  if (result == UNCHANGED) {
583  AppendOneByte("null");
584  } else {
585  return result;
586  }
587  }
588  break;
589  }
590  // TODO(yangguo): The FAST_HOLEY_* cases could be handled in a faster way.
591  // They resemble the non-holey cases except that a prototype chain lookup
592  // is necessary for holes.
593  default: {
594  Result result = SerializeJSArraySlow(object, length);
595  if (result != SUCCESS) return result;
596  break;
597  }
598  }
599  Append(']');
600  StackPop();
601  current_part_ = handle_scope.CloseAndEscape(current_part_);
602  return SUCCESS;
603 }
604 
605 
606 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
607  Handle<JSArray> object, uint32_t length) {
608  for (uint32_t i = 0; i < length; i++) {
609  if (i > 0) Append(',');
610  Handle<Object> element;
612  isolate_, element,
613  Object::GetElement(isolate_, object, i),
614  EXCEPTION);
615  if (element->IsUndefined()) {
616  AppendOneByte("null");
617  } else {
618  Result result = SerializeElement(isolate_, element, i);
619  if (result == SUCCESS) continue;
620  if (result == UNCHANGED) {
621  AppendOneByte("null");
622  } else {
623  return result;
624  }
625  }
626  }
627  return SUCCESS;
628 }
629 
630 
631 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
632  Handle<JSObject> object) {
633  HandleScope handle_scope(isolate_);
634  Result stack_push = StackPush(object);
635  if (stack_push != SUCCESS) return stack_push;
636  DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject());
637 
638  Append('{');
639  bool comma = false;
640 
641  if (object->HasFastProperties() &&
642  !object->HasIndexedInterceptor() &&
643  !object->HasNamedInterceptor() &&
644  object->elements()->length() == 0) {
645  Handle<Map> map(object->map());
646  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
647  Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
648  // TODO(rossberg): Should this throw?
649  if (!name->IsString()) continue;
650  Handle<String> key = Handle<String>::cast(name);
651  PropertyDetails details = map->instance_descriptors()->GetDetails(i);
652  if (details.IsDontEnum()) continue;
653  Handle<Object> property;
654  if (details.type() == FIELD && *map == object->map()) {
655  property = Handle<Object>(object->RawFastPropertyAt(
656  FieldIndex::ForDescriptor(*map, i)), isolate_);
657  } else {
659  isolate_, property,
660  Object::GetPropertyOrElement(object, key),
661  EXCEPTION);
662  }
663  Result result = SerializeProperty(property, comma, key);
664  if (!comma && result == SUCCESS) comma = true;
665  if (result == EXCEPTION) return result;
666  }
667  } else {
668  Handle<FixedArray> contents;
670  isolate_, contents,
672  EXCEPTION);
673 
674  for (int i = 0; i < contents->length(); i++) {
675  Object* key = contents->get(i);
676  Handle<String> key_handle;
677  MaybeHandle<Object> maybe_property;
678  if (key->IsString()) {
679  key_handle = Handle<String>(String::cast(key), isolate_);
680  maybe_property = Object::GetPropertyOrElement(object, key_handle);
681  } else {
682  DCHECK(key->IsNumber());
683  key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
684  uint32_t index;
685  if (key->IsSmi()) {
686  maybe_property = Object::GetElement(
687  isolate_, object, Smi::cast(key)->value());
688  } else if (key_handle->AsArrayIndex(&index)) {
689  maybe_property = Object::GetElement(isolate_, object, index);
690  } else {
691  maybe_property = Object::GetPropertyOrElement(object, key_handle);
692  }
693  }
694  Handle<Object> property;
696  isolate_, property, maybe_property, EXCEPTION);
697  Result result = SerializeProperty(property, comma, key_handle);
698  if (!comma && result == SUCCESS) comma = true;
699  if (result == EXCEPTION) return result;
700  }
701  }
702 
703  Append('}');
704  StackPop();
705  current_part_ = handle_scope.CloseAndEscape(current_part_);
706  return SUCCESS;
707 }
708 
709 
710 void BasicJsonStringifier::ShrinkCurrentPart() {
711  DCHECK(current_index_ < part_length_);
712  current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
713  current_index_);
714 }
715 
716 
717 void BasicJsonStringifier::Accumulate() {
718  if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
719  // Screw it. Simply set the flag and carry on. Throw exception at the end.
720  set_accumulator(factory_->empty_string());
721  overflowed_ = true;
722  } else {
723  set_accumulator(factory_->NewConsString(accumulator(),
724  current_part_).ToHandleChecked());
725  }
726 }
727 
728 
730  Accumulate();
731  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
732  part_length_ *= kPartLengthGrowthFactor;
733  }
734  if (is_one_byte_) {
735  current_part_ =
736  factory_->NewRawOneByteString(part_length_).ToHandleChecked();
737  } else {
738  current_part_ =
739  factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
740  }
741  DCHECK(!current_part_.is_null());
742  current_index_ = 0;
743 }
744 
745 
746 void BasicJsonStringifier::ChangeEncoding() {
747  ShrinkCurrentPart();
748  Accumulate();
749  current_part_ =
750  factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
751  DCHECK(!current_part_.is_null());
752  current_index_ = 0;
753  is_one_byte_ = false;
754 }
755 
756 
757 template <typename SrcChar, typename DestChar>
758 int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
759  DestChar* dest,
760  int length) {
761  DestChar* dest_start = dest;
762 
763  // Assert that uc16 character is not truncated down to 8 bit.
764  // The <uc16, char> version of this method must not be called.
765  DCHECK(sizeof(*dest) >= sizeof(*src));
766 
767  for (int i = 0; i < length; i++) {
768  SrcChar c = src[i];
769  if (DoNotEscape(c)) {
770  *(dest++) = static_cast<DestChar>(c);
771  } else {
772  const uint8_t* chars = reinterpret_cast<const uint8_t*>(
773  &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
774  while (*chars != '\0') *(dest++) = *(chars++);
775  }
776  }
777 
778  return static_cast<int>(dest - dest_start);
779 }
780 
781 
782 template <bool is_one_byte, typename Char>
783 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
784  int length = string->length();
785  Append_<is_one_byte, char>('"');
786  // We make a rough estimate to find out if the current string can be
787  // serialized without allocating a new string part. The worst case length of
788  // an escaped character is 6. Shifting the remainin string length right by 3
789  // is a more pessimistic estimate, but faster to calculate.
790 
791  if (((part_length_ - current_index_) >> 3) > length) {
793  Vector<const Char> vector = GetCharVector<Char>(string);
794  if (is_one_byte) {
795  current_index_ += SerializeStringUnchecked_(
796  vector.start(),
797  SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
798  length);
799  } else {
800  current_index_ += SerializeStringUnchecked_(
801  vector.start(),
802  SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
803  length);
804  }
805  } else {
806  String* string_location = NULL;
807  Vector<const Char> vector(NULL, 0);
808  for (int i = 0; i < length; i++) {
809  // If GC moved the string, we need to refresh the vector.
810  if (*string != string_location) {
812  // This does not actually prevent the string from being relocated later.
813  vector = GetCharVector<Char>(string);
814  string_location = *string;
815  }
816  Char c = vector[i];
817  if (DoNotEscape(c)) {
818  Append_<is_one_byte, Char>(c);
819  } else {
820  Append_<is_one_byte, uint8_t>(reinterpret_cast<const uint8_t*>(
821  &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
822  }
823  }
824  }
825 
826  Append_<is_one_byte, uint8_t>('"');
827 }
828 
829 
830 template <>
831 bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
832  return c >= '#' && c <= '~' && c != '\\';
833 }
834 
835 
836 template <>
837 bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
838  return c >= '#' && c != '\\' && c != 0x7f;
839 }
840 
841 
842 template <>
843 Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
844  Handle<String> string) {
845  String::FlatContent flat = string->GetFlatContent();
846  DCHECK(flat.IsOneByte());
847  return flat.ToOneByteVector();
848 }
849 
850 
851 template <>
852 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
853  String::FlatContent flat = string->GetFlatContent();
854  DCHECK(flat.IsTwoByte());
855  return flat.ToUC16Vector();
856 }
857 
858 
859 void BasicJsonStringifier::SerializeString(Handle<String> object) {
860  object = String::Flatten(object);
861  if (is_one_byte_) {
862  if (object->IsOneByteRepresentationUnderneath()) {
863  SerializeString_<true, uint8_t>(object);
864  } else {
865  ChangeEncoding();
866  SerializeString(object);
867  }
868  } else {
869  if (object->IsOneByteRepresentationUnderneath()) {
870  SerializeString_<false, uint8_t>(object);
871  } else {
872  SerializeString_<false, uc16>(object);
873  }
874  }
875 }
876 
877 } } // namespace v8::internal
878 
879 #endif // V8_JSON_STRINGIFIER_H_
#define BASE_EMBEDDED
Definition: allocation.h:45
An object reference managed by the v8 garbage collector.
Definition: v8.h:198
A JavaScript object (ECMA-262, 4.3.3)
Definition: v8.h:2283
Result SerializeGeneric(Handle< Object > object, Handle< Object > key, bool deferred_comma, bool deferred_key)
void SerializeString(Handle< String > object)
Isolate * isolate() const
INLINE(static Vector< const Char > GetCharVector(Handle< String > string))
INLINE(Result SerializeObject(Handle< Object > obj))
INLINE(Result SerializeJSArray(Handle< JSArray > object))
void SerializeDeferredKey(bool deferred_comma, Handle< Object > deferred_key)
INLINE(Handle< String > accumulator())
INLINE(void Append_(const Char *chars))
INLINE(void Append_(Char c))
MUST_USE_RESULT MaybeHandle< Object > ApplyToJsonFunction(Handle< Object > object, Handle< Object > key)
INLINE(void set_accumulator(Handle< String > string))
Handle< JSValue > accumulator_store_
MUST_USE_RESULT MaybeHandle< Object > Stringify(Handle< Object > object)
INLINE(static int SerializeStringUnchecked_(const SrcChar *src, DestChar *dest, int length))
INLINE(Result SerializeHeapNumber(Handle< HeapNumber > object))
INLINE(void Append(uint8_t c))
INLINE(void SerializeString_(Handle< String > string))
Result SerializeDouble(double number)
INLINE(Result SerializeElement(Isolate *isolate, Handle< Object > object, int i))
INLINE(static Handle< String > StringifyString_(Isolate *isolate, Vector< Char > vector, Handle< String > result))
Result SerializeJSArraySlow(Handle< JSArray > object, uint32_t length)
static const int kInitialPartLength
static const char *const JsonEscapeTable
Result SerializeSmi(Smi *object)
INLINE(static bool DoNotEscape(Char c))
Result SerializeJSValue(Handle< JSValue > object)
Result Serialize_(Handle< Object > object, bool comma, Handle< Object > key)
INLINE(Result SerializeJSObject(Handle< JSObject > object))
INLINE(Result SerializeProperty(Handle< Object > object, bool deferred_comma, Handle< String > deferred_key))
INLINE(void ShrinkCurrentPart())
INLINE(void AppendOneByte(const char *chars))
MUST_USE_RESULT INLINE(static MaybeHandle< Object > StringifyString(Isolate *isolate, Handle< String > object))
BasicJsonStringifier(Isolate *isolate)
Result StackPush(Handle< Object > object)
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
bool is_null() const
Definition: handles.h:124
Factory * factory()
Definition: isolate.h:982
static void EnsureSize(Handle< JSArray > array, int minimum_size_of_backing_fixed_array)
Definition: objects-inl.h:6955
static MUST_USE_RESULT MaybeHandle< FixedArray > GetKeys(Handle< JSReceiver > object, KeyCollectionType type)
Definition: objects.cc:5797
static MUST_USE_RESULT MaybeHandle< Object > GetPropertyOrElement(Handle< Object > object, Handle< Name > key)
Definition: objects-inl.h:1124
static MaybeHandle< JSReceiver > ToObject(Isolate *isolate, Handle< Object > object)
Definition: objects-inl.h:1094
static MUST_USE_RESULT MaybeHandle< Object > GetElement(Isolate *isolate, Handle< Object > object, uint32_t index)
Definition: objects-inl.h:1113
static MUST_USE_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it)
Definition: objects.cc:109
static const byte kFalse
Definition: objects.h:9400
static const byte kTrue
Definition: objects.h:9401
static const byte kNull
Definition: objects.h:9404
static MUST_USE_RESULT Handle< String > Truncate(Handle< SeqString > string, int new_length)
Definition: objects.cc:8883
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const int kMaxLength
Definition: objects.h:8820
static Handle< String > Flatten(Handle< String > string, PretenureFlag pretenure=NOT_TENURED)
Definition: objects-inl.h:3354
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions true
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition: isolate.h:123
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call, T)
Definition: isolate.h:135
#define THROW_NEW_ERROR(isolate, call, T)
Definition: isolate.h:138
#define CHECK(condition)
Definition: logging.h:36
#define DCHECK(condition)
Definition: logging.h:205
#define MUST_USE_RESULT
Definition: macros.h:266
unsigned short uint16_t
Definition: unicode.cc:23
const int KB
Definition: globals.h:106
Vector< const uint8_t > GetCharVector(Handle< String > string)
Definition: runtime-uri.cc:23
PerThreadAssertScopeDebugOnly< HEAP_ALLOCATION_ASSERT, false > DisallowHeapAllocation
Definition: assert-scope.h:110
PerThreadAssertScopeDebugOnly< HEAP_ALLOCATION_ASSERT, true > AllowHeapAllocation
Definition: assert-scope.h:114
int ToNumber(Register reg)
kSerializedDataOffset Object
Definition: objects-inl.h:5322
@ JS_VALUE_TYPE
Definition: objects.h:728
@ JS_ARRAY_TYPE
Definition: objects.h:738
@ ODDBALL_TYPE
Definition: objects.h:663
@ MUTABLE_HEAP_NUMBER_TYPE
Definition: objects.h:670
@ HEAP_NUMBER_TYPE
Definition: objects.h:669
@ JS_FUNCTION_TYPE
Definition: objects.h:749
const char * DoubleToCString(double v, Vector< char > buffer)
Definition: conversions.cc:121
const char * IntToCString(int n, Vector< char > buffer)
Definition: conversions.cc:176
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20