• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20   MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object);
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 
37   void ChangeEncoding();
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 
INLINE(void Append (uint8_t c))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 
INLINE(void AppendOneByte (const char * chars))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 
63   MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
64       Handle<Object> object,
65       Handle<Object> key);
66 
67   Result SerializeGeneric(Handle<Object> object,
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.
INLINE(Result SerializeObject (Handle<Object> obj))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.
INLINE(Result SerializeElement (Isolate * isolate,Handle<Object> object,int i))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.
INLINE(Result SerializeProperty (Handle<Object> object,bool deferred_comma,Handle<String> deferred_key))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 
SerializeDeferredKey(bool deferred_comma,Handle<Object> deferred_key)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 
111   Result SerializeSmi(Smi* object);
112 
113   Result SerializeDouble(double number);
INLINE(Result SerializeHeapNumber (Handle<HeapNumber> object))114   INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
115     return SerializeDouble(object->value());
116   }
117 
118   Result SerializeJSValue(Handle<JSValue> object);
119 
120   INLINE(Result SerializeJSArray(Handle<JSArray> object));
121   INLINE(Result SerializeJSObject(Handle<JSObject> object));
122 
123   Result SerializeJSArraySlow(Handle<JSArray> object, uint32_t length);
124 
125   void SerializeString(Handle<String> object);
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>
139   INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
140 
141   Result StackPush(Handle<Object> object);
142   void StackPop();
143 
INLINE(Handle<String> accumulator ())144   INLINE(Handle<String> accumulator()) {
145     return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
146   }
147 
INLINE(void set_accumulator (Handle<String> string))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.
156   Handle<JSValue> accumulator_store_;
157   Handle<String> current_part_;
158   Handle<String> tojson_string_;
159   Handle<JSArray> stack_;
160   int current_index_;
161   int part_length_;
162   bool is_one_byte_;
163   bool overflowed_;
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 
BasicJsonStringifier(Isolate * isolate)239 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
240     : isolate_(isolate),
241       current_index_(0),
242       is_one_byte_(true),
243       overflowed_(false) {
244   factory_ = isolate_->factory();
245   accumulator_store_ = Handle<JSValue>::cast(
246       Object::ToObject(isolate, factory_->empty_string()).ToHandleChecked());
247   part_length_ = kInitialPartLength;
248   current_part_ = factory_->NewRawOneByteString(part_length_).ToHandleChecked();
249   tojson_string_ = factory_->toJSON_string();
250   stack_ = factory_->NewJSArray(8);
251 }
252 
253 
Stringify(Handle<Object> object)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 
StringifyString(Isolate * isolate,Handle<String> object)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();
287     DisallowHeapAllocation no_gc;
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();
295     DisallowHeapAllocation no_gc;
296     return StringifyString_<SeqTwoByteString>(
297         isolate,
298         object->GetFlatContent().ToUC16Vector(),
299         result);
300   }
301 }
302 
303 
304 template <typename ResultType, typename Char>
StringifyString_(Isolate * isolate,Vector<Char> vector,Handle<String> result)305 Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate,
306                                                       Vector<Char> vector,
307                                                       Handle<String> result) {
308   DisallowHeapAllocation no_gc;
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>
Append_(Char c)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>
Append_(const Char * chars)334 void BasicJsonStringifier::Append_(const Char* chars) {
335   for (; *chars != '\0'; chars++) Append_<is_one_byte, Char>(*chars);
336 }
337 
338 
ApplyToJsonFunction(Handle<Object> object,Handle<Object> key)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;
344   ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
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_);
351   ASSIGN_RETURN_ON_EXCEPTION(
352       isolate_, object,
353       Execution::Call(isolate_, fun, object, 1, argv),
354       Object);
355   return scope.CloseAndEscape(object);
356 }
357 
358 
StackPush(Handle<Object> object)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 
StackPop()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>
Serialize_(Handle<Object> object,bool comma,Handle<Object> key)396 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
397     Handle<Object> object, bool comma, Handle<Object> key) {
398   if (object->IsJSObject()) {
399     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
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:
412     case MUTABLE_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 
SerializeGeneric(Handle<Object> object,Handle<Object> key,bool deferred_comma,bool deferred_key)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;
469   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
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;
487   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
488       isolate_, cons,
489       factory_->NewConsString(accumulator(), result_string),
490       EXCEPTION);
491   set_accumulator(cons);
492   return SUCCESS;
493 }
494 
495 
SerializeJSValue(Handle<JSValue> object)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;
501     ASSIGN_RETURN_ON_EXCEPTION_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;
506     ASSIGN_RETURN_ON_EXCEPTION_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 
SerializeSmi(Smi * object)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 
SerializeDouble(double number)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 
SerializeJSArray(Handle<JSArray> object)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 
SerializeJSArraySlow(Handle<JSArray> object,uint32_t length)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;
611     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
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 
SerializeJSObject(Handle<JSObject> object)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 {
658         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
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;
669     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
670         isolate_, contents,
671         JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY),
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;
695       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
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 
ShrinkCurrentPart()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 
Accumulate()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 
Extend()729 void BasicJsonStringifier::Extend() {
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 
ChangeEncoding()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>
SerializeStringUnchecked_(const SrcChar * src,DestChar * dest,int length)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>
SerializeString_(Handle<String> string)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) {
792     DisallowHeapAllocation no_gc;
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) {
811         DisallowHeapAllocation no_gc;
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 <>
DoNotEscape(uint8_t c)831 bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
832   return c >= '#' && c <= '~' && c != '\\';
833 }
834 
835 
836 template <>
DoNotEscape(uint16_t c)837 bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
838   return c >= '#' && c != '\\' && c != 0x7f;
839 }
840 
841 
842 template <>
GetCharVector(Handle<String> string)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 <>
GetCharVector(Handle<String> string)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 
SerializeString(Handle<String> object)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_
880