Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / json-stringifier.h
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_ascii, typename Char>
42   INLINE(void Append_(Char c));
43
44   template <bool is_ascii, typename Char>
45   INLINE(void Append_(const Char* chars));
46
47   INLINE(void Append(uint8_t c)) {
48     if (is_ascii_) {
49       Append_<true>(c);
50     } else {
51       Append_<false>(c);
52     }
53   }
54
55   INLINE(void AppendAscii(const char* chars)) {
56     if (is_ascii_) {
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.
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
111   Result SerializeSmi(Smi* object);
112
113   Result SerializeDouble(double number);
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_ascii, 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
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.
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_ascii_;
163   bool overflowed_;
164
165   static const int kJsonEscapeTableEntrySize = 8;
166   static const char* const JsonEscapeTable;
167 };
168
169
170 // Translation table to escape ASCII 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_ascii_(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
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       return isolate_->Throw<Object>(
262           isolate_->factory()->NewInvalidStringLengthError());
263     }
264     return accumulator();
265   }
266   DCHECK(result == EXCEPTION);
267   return MaybeHandle<Object>();
268 }
269
270
271 MaybeHandle<Object> BasicJsonStringifier::StringifyString(
272     Isolate* isolate,  Handle<String> object) {
273   static const int kJsonQuoteWorstCaseBlowup = 6;
274   static const int kSpaceForQuotes = 2;
275   int worst_case_length =
276       object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
277
278   if (worst_case_length > 32 * KB) {  // Slow path if too large.
279     BasicJsonStringifier stringifier(isolate);
280     return stringifier.Stringify(object);
281   }
282
283   object = String::Flatten(object);
284   DCHECK(object->IsFlat());
285   if (object->IsOneByteRepresentationUnderneath()) {
286     Handle<String> result = isolate->factory()->NewRawOneByteString(
287         worst_case_length).ToHandleChecked();
288     DisallowHeapAllocation no_gc;
289     return StringifyString_<SeqOneByteString>(
290         isolate,
291         object->GetFlatContent().ToOneByteVector(),
292         result);
293   } else {
294     Handle<String> result = isolate->factory()->NewRawTwoByteString(
295         worst_case_length).ToHandleChecked();
296     DisallowHeapAllocation no_gc;
297     return StringifyString_<SeqTwoByteString>(
298         isolate,
299         object->GetFlatContent().ToUC16Vector(),
300         result);
301   }
302 }
303
304
305 template <typename ResultType, typename Char>
306 Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate,
307                                                       Vector<Char> vector,
308                                                       Handle<String> result) {
309   DisallowHeapAllocation no_gc;
310   int final_size = 0;
311   ResultType* dest = ResultType::cast(*result);
312   dest->Set(final_size++, '\"');
313   final_size += SerializeStringUnchecked_(vector.start(),
314                                           dest->GetChars() + 1,
315                                           vector.length());
316   dest->Set(final_size++, '\"');
317   return SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
318 }
319
320
321 template <bool is_ascii, typename Char>
322 void BasicJsonStringifier::Append_(Char c) {
323   if (is_ascii) {
324     SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
325         current_index_++, c);
326   } else {
327     SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
328         current_index_++, c);
329   }
330   if (current_index_ == part_length_) Extend();
331 }
332
333
334 template <bool is_ascii, typename Char>
335 void BasicJsonStringifier::Append_(const Char* chars) {
336   for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars);
337 }
338
339
340 MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
341     Handle<Object> object, Handle<Object> key) {
342   LookupIterator it(object, tojson_string_, LookupIterator::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
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         isolate_->Throw(*factory_->NewTypeError(
375             "circular_structure", HandleVector<Object>(NULL, 0)));
376         return EXCEPTION;
377       }
378     }
379   }
380   JSArray::EnsureSize(stack_, length + 1);
381   FixedArray::cast(stack_->elements())->set(length, *object);
382   stack_->set_length(Smi::FromInt(length + 1));
383   return SUCCESS;
384 }
385
386
387 void BasicJsonStringifier::StackPop() {
388   int length = Smi::cast(stack_->length())->value();
389   stack_->set_length(Smi::FromInt(length - 1));
390 }
391
392
393 template <bool deferred_string_key>
394 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
395     Handle<Object> object, bool comma, Handle<Object> key) {
396   if (object->IsJSObject()) {
397     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
398         isolate_, object,
399         ApplyToJsonFunction(object, key),
400         EXCEPTION);
401   }
402
403   if (object->IsSmi()) {
404     if (deferred_string_key) SerializeDeferredKey(comma, key);
405     return SerializeSmi(Smi::cast(*object));
406   }
407
408   switch (HeapObject::cast(*object)->map()->instance_type()) {
409     case HEAP_NUMBER_TYPE:
410     case MUTABLE_HEAP_NUMBER_TYPE:
411       if (deferred_string_key) SerializeDeferredKey(comma, key);
412       return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
413     case ODDBALL_TYPE:
414       switch (Oddball::cast(*object)->kind()) {
415         case Oddball::kFalse:
416           if (deferred_string_key) SerializeDeferredKey(comma, key);
417           AppendAscii("false");
418           return SUCCESS;
419         case Oddball::kTrue:
420           if (deferred_string_key) SerializeDeferredKey(comma, key);
421           AppendAscii("true");
422           return SUCCESS;
423         case Oddball::kNull:
424           if (deferred_string_key) SerializeDeferredKey(comma, key);
425           AppendAscii("null");
426           return SUCCESS;
427         default:
428           return UNCHANGED;
429       }
430     case JS_ARRAY_TYPE:
431       if (object->IsAccessCheckNeeded()) break;
432       if (deferred_string_key) SerializeDeferredKey(comma, key);
433       return SerializeJSArray(Handle<JSArray>::cast(object));
434     case JS_VALUE_TYPE:
435       if (deferred_string_key) SerializeDeferredKey(comma, key);
436       return SerializeJSValue(Handle<JSValue>::cast(object));
437     case JS_FUNCTION_TYPE:
438       return UNCHANGED;
439     default:
440       if (object->IsString()) {
441         if (deferred_string_key) SerializeDeferredKey(comma, key);
442         SerializeString(Handle<String>::cast(object));
443         return SUCCESS;
444       } else if (object->IsJSObject()) {
445         // Go to slow path for global proxy and objects requiring access checks.
446         if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break;
447         if (deferred_string_key) SerializeDeferredKey(comma, key);
448         return SerializeJSObject(Handle<JSObject>::cast(object));
449       }
450   }
451
452   return SerializeGeneric(object, key, comma, deferred_string_key);
453 }
454
455
456 BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
457     Handle<Object> object,
458     Handle<Object> key,
459     bool deferred_comma,
460     bool deferred_key) {
461   Handle<JSObject> builtins(isolate_->native_context()->builtins(), isolate_);
462   Handle<JSFunction> builtin = Handle<JSFunction>::cast(Object::GetProperty(
463       isolate_, builtins, "JSONSerializeAdapter").ToHandleChecked());
464
465   Handle<Object> argv[] = { key, object };
466   Handle<Object> result;
467   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
468       isolate_, result,
469       Execution::Call(isolate_, builtin, object, 2, argv),
470       EXCEPTION);
471   if (result->IsUndefined()) return UNCHANGED;
472   if (deferred_key) {
473     if (key->IsSmi()) key = factory_->NumberToString(key);
474     SerializeDeferredKey(deferred_comma, key);
475   }
476
477   Handle<String> result_string = Handle<String>::cast(result);
478   // Shrink current part, attach it to the accumulator, also attach the result
479   // string to the accumulator, and allocate a new part.
480   ShrinkCurrentPart();  // Shrink.
481   part_length_ = kInitialPartLength;  // Allocate conservatively.
482   Extend();             // Attach current part and allocate new part.
483   // Attach result string to the accumulator.
484   Handle<String> cons;
485   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
486       isolate_, cons,
487       factory_->NewConsString(accumulator(), result_string),
488       EXCEPTION);
489   set_accumulator(cons);
490   return SUCCESS;
491 }
492
493
494 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
495     Handle<JSValue> object) {
496   String* class_name = object->class_name();
497   if (class_name == isolate_->heap()->String_string()) {
498     Handle<Object> value;
499     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
500         isolate_, value, Execution::ToString(isolate_, object), EXCEPTION);
501     SerializeString(Handle<String>::cast(value));
502   } else if (class_name == isolate_->heap()->Number_string()) {
503     Handle<Object> value;
504     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
505         isolate_, value, Execution::ToNumber(isolate_, object), EXCEPTION);
506     if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
507     SerializeHeapNumber(Handle<HeapNumber>::cast(value));
508   } else {
509     DCHECK(class_name == isolate_->heap()->Boolean_string());
510     Object* value = JSValue::cast(*object)->value();
511     DCHECK(value->IsBoolean());
512     AppendAscii(value->IsTrue() ? "true" : "false");
513   }
514   return SUCCESS;
515 }
516
517
518 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
519   static const int kBufferSize = 100;
520   char chars[kBufferSize];
521   Vector<char> buffer(chars, kBufferSize);
522   AppendAscii(IntToCString(object->value(), buffer));
523   return SUCCESS;
524 }
525
526
527 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
528     double number) {
529   if (std::isinf(number) || std::isnan(number)) {
530     AppendAscii("null");
531     return SUCCESS;
532   }
533   static const int kBufferSize = 100;
534   char chars[kBufferSize];
535   Vector<char> buffer(chars, kBufferSize);
536   AppendAscii(DoubleToCString(number, buffer));
537   return SUCCESS;
538 }
539
540
541 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
542     Handle<JSArray> object) {
543   HandleScope handle_scope(isolate_);
544   Result stack_push = StackPush(object);
545   if (stack_push != SUCCESS) return stack_push;
546   uint32_t length = 0;
547   CHECK(object->length()->ToArrayIndex(&length));
548   Append('[');
549   switch (object->GetElementsKind()) {
550     case FAST_SMI_ELEMENTS: {
551       Handle<FixedArray> elements(
552           FixedArray::cast(object->elements()), isolate_);
553       for (uint32_t i = 0; i < length; i++) {
554         if (i > 0) Append(',');
555         SerializeSmi(Smi::cast(elements->get(i)));
556       }
557       break;
558     }
559     case FAST_DOUBLE_ELEMENTS: {
560       // Empty array is FixedArray but not FixedDoubleArray.
561       if (length == 0) break;
562       Handle<FixedDoubleArray> elements(
563           FixedDoubleArray::cast(object->elements()), isolate_);
564       for (uint32_t i = 0; i < length; i++) {
565         if (i > 0) Append(',');
566         SerializeDouble(elements->get_scalar(i));
567       }
568       break;
569     }
570     case FAST_ELEMENTS: {
571       Handle<FixedArray> elements(
572           FixedArray::cast(object->elements()), isolate_);
573       for (uint32_t i = 0; i < length; i++) {
574         if (i > 0) Append(',');
575         Result result =
576             SerializeElement(isolate_,
577                              Handle<Object>(elements->get(i), isolate_),
578                              i);
579         if (result == SUCCESS) continue;
580         if (result == UNCHANGED) {
581           AppendAscii("null");
582         } else {
583           return result;
584         }
585       }
586       break;
587     }
588     // TODO(yangguo):  The FAST_HOLEY_* cases could be handled in a faster way.
589     // They resemble the non-holey cases except that a prototype chain lookup
590     // is necessary for holes.
591     default: {
592       Result result = SerializeJSArraySlow(object, length);
593       if (result != SUCCESS) return result;
594       break;
595     }
596   }
597   Append(']');
598   StackPop();
599   current_part_ = handle_scope.CloseAndEscape(current_part_);
600   return SUCCESS;
601 }
602
603
604 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
605     Handle<JSArray> object, uint32_t length) {
606   for (uint32_t i = 0; i < length; i++) {
607     if (i > 0) Append(',');
608     Handle<Object> element;
609     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
610         isolate_, element,
611         Object::GetElement(isolate_, object, i),
612         EXCEPTION);
613     if (element->IsUndefined()) {
614       AppendAscii("null");
615     } else {
616       Result result = SerializeElement(isolate_, element, i);
617       if (result == SUCCESS) continue;
618       if (result == UNCHANGED) {
619         AppendAscii("null");
620       } else {
621         return result;
622       }
623     }
624   }
625   return SUCCESS;
626 }
627
628
629 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
630     Handle<JSObject> object) {
631   HandleScope handle_scope(isolate_);
632   Result stack_push = StackPush(object);
633   if (stack_push != SUCCESS) return stack_push;
634   DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject());
635
636   Append('{');
637   bool comma = false;
638
639   if (object->HasFastProperties() &&
640       !object->HasIndexedInterceptor() &&
641       !object->HasNamedInterceptor() &&
642       object->elements()->length() == 0) {
643     Handle<Map> map(object->map());
644     for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
645       Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
646       // TODO(rossberg): Should this throw?
647       if (!name->IsString()) continue;
648       Handle<String> key = Handle<String>::cast(name);
649       PropertyDetails details = map->instance_descriptors()->GetDetails(i);
650       if (details.IsDontEnum()) continue;
651       Handle<Object> property;
652       if (details.type() == FIELD && *map == object->map()) {
653         property = Handle<Object>(object->RawFastPropertyAt(
654             FieldIndex::ForDescriptor(*map, i)), isolate_);
655       } else {
656         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
657             isolate_, property,
658             Object::GetPropertyOrElement(object, key),
659             EXCEPTION);
660       }
661       Result result = SerializeProperty(property, comma, key);
662       if (!comma && result == SUCCESS) comma = true;
663       if (result == EXCEPTION) return result;
664     }
665   } else {
666     Handle<FixedArray> contents;
667     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
668         isolate_, contents,
669         JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY),
670         EXCEPTION);
671
672     for (int i = 0; i < contents->length(); i++) {
673       Object* key = contents->get(i);
674       Handle<String> key_handle;
675       MaybeHandle<Object> maybe_property;
676       if (key->IsString()) {
677         key_handle = Handle<String>(String::cast(key), isolate_);
678         maybe_property = Object::GetPropertyOrElement(object, key_handle);
679       } else {
680         DCHECK(key->IsNumber());
681         key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
682         uint32_t index;
683         if (key->IsSmi()) {
684           maybe_property = Object::GetElement(
685               isolate_, object, Smi::cast(key)->value());
686         } else if (key_handle->AsArrayIndex(&index)) {
687           maybe_property = Object::GetElement(isolate_, object, index);
688         } else {
689           maybe_property = Object::GetPropertyOrElement(object, key_handle);
690         }
691       }
692       Handle<Object> property;
693       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
694           isolate_, property, maybe_property, EXCEPTION);
695       Result result = SerializeProperty(property, comma, key_handle);
696       if (!comma && result == SUCCESS) comma = true;
697       if (result == EXCEPTION) return result;
698     }
699   }
700
701   Append('}');
702   StackPop();
703   current_part_ = handle_scope.CloseAndEscape(current_part_);
704   return SUCCESS;
705 }
706
707
708 void BasicJsonStringifier::ShrinkCurrentPart() {
709   DCHECK(current_index_ < part_length_);
710   current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
711                                       current_index_);
712 }
713
714
715 void BasicJsonStringifier::Accumulate() {
716   if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
717     // Screw it.  Simply set the flag and carry on.  Throw exception at the end.
718     set_accumulator(factory_->empty_string());
719     overflowed_ = true;
720   } else {
721     set_accumulator(factory_->NewConsString(accumulator(),
722                                             current_part_).ToHandleChecked());
723   }
724 }
725
726
727 void BasicJsonStringifier::Extend() {
728   Accumulate();
729   if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
730     part_length_ *= kPartLengthGrowthFactor;
731   }
732   if (is_ascii_) {
733     current_part_ =
734         factory_->NewRawOneByteString(part_length_).ToHandleChecked();
735   } else {
736     current_part_ =
737         factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
738   }
739   DCHECK(!current_part_.is_null());
740   current_index_ = 0;
741 }
742
743
744 void BasicJsonStringifier::ChangeEncoding() {
745   ShrinkCurrentPart();
746   Accumulate();
747   current_part_ =
748       factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
749   DCHECK(!current_part_.is_null());
750   current_index_ = 0;
751   is_ascii_ = false;
752 }
753
754
755 template <typename SrcChar, typename DestChar>
756 int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
757                                                     DestChar* dest,
758                                                     int length) {
759   DestChar* dest_start = dest;
760
761   // Assert that uc16 character is not truncated down to 8 bit.
762   // The <uc16, char> version of this method must not be called.
763   DCHECK(sizeof(*dest) >= sizeof(*src));
764
765   for (int i = 0; i < length; i++) {
766     SrcChar c = src[i];
767     if (DoNotEscape(c)) {
768       *(dest++) = static_cast<DestChar>(c);
769     } else {
770       const uint8_t* chars = reinterpret_cast<const uint8_t*>(
771           &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
772       while (*chars != '\0') *(dest++) = *(chars++);
773     }
774   }
775
776   return static_cast<int>(dest - dest_start);
777 }
778
779
780 template <bool is_ascii, typename Char>
781 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
782   int length = string->length();
783   Append_<is_ascii, char>('"');
784   // We make a rough estimate to find out if the current string can be
785   // serialized without allocating a new string part. The worst case length of
786   // an escaped character is 6.  Shifting the remainin string length right by 3
787   // is a more pessimistic estimate, but faster to calculate.
788
789   if (((part_length_ - current_index_) >> 3) > length) {
790     DisallowHeapAllocation no_gc;
791     Vector<const Char> vector = GetCharVector<Char>(string);
792     if (is_ascii) {
793       current_index_ += SerializeStringUnchecked_(
794           vector.start(),
795           SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
796           length);
797     } else {
798       current_index_ += SerializeStringUnchecked_(
799           vector.start(),
800           SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
801           length);
802     }
803   } else {
804     String* string_location = NULL;
805     Vector<const Char> vector(NULL, 0);
806     for (int i = 0; i < length; i++) {
807       // If GC moved the string, we need to refresh the vector.
808       if (*string != string_location) {
809         DisallowHeapAllocation no_gc;
810         // This does not actually prevent the string from being relocated later.
811         vector = GetCharVector<Char>(string);
812         string_location = *string;
813       }
814       Char c = vector[i];
815       if (DoNotEscape(c)) {
816         Append_<is_ascii, Char>(c);
817       } else {
818         Append_<is_ascii, uint8_t>(reinterpret_cast<const uint8_t*>(
819             &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
820       }
821     }
822   }
823
824   Append_<is_ascii, uint8_t>('"');
825 }
826
827
828 template <>
829 bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
830   return c >= '#' && c <= '~' && c != '\\';
831 }
832
833
834 template <>
835 bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
836   return c >= '#' && c != '\\' && c != 0x7f;
837 }
838
839
840 template <>
841 Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
842     Handle<String> string) {
843   String::FlatContent flat = string->GetFlatContent();
844   DCHECK(flat.IsAscii());
845   return flat.ToOneByteVector();
846 }
847
848
849 template <>
850 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
851   String::FlatContent flat = string->GetFlatContent();
852   DCHECK(flat.IsTwoByte());
853   return flat.ToUC16Vector();
854 }
855
856
857 void BasicJsonStringifier::SerializeString(Handle<String> object) {
858   object = String::Flatten(object);
859   if (is_ascii_) {
860     if (object->IsOneByteRepresentationUnderneath()) {
861       SerializeString_<true, uint8_t>(object);
862     } else {
863       ChangeEncoding();
864       SerializeString(object);
865     }
866   } else {
867     if (object->IsOneByteRepresentationUnderneath()) {
868       SerializeString_<false, uint8_t>(object);
869     } else {
870       SerializeString_<false, uc16>(object);
871     }
872   }
873 }
874
875 } }  // namespace v8::internal
876
877 #endif  // V8_JSON_STRINGIFIER_H_