Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / v8 / src / json-stringifier.h
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #ifndef V8_JSON_STRINGIFIER_H_
29 #define V8_JSON_STRINGIFIER_H_
30
31 #include "v8.h"
32 #include "v8utils.h"
33 #include "v8conversions.h"
34
35 namespace v8 {
36 namespace internal {
37
38 class BasicJsonStringifier BASE_EMBEDDED {
39  public:
40   explicit BasicJsonStringifier(Isolate* isolate);
41
42   MaybeObject* Stringify(Handle<Object> object);
43
44   INLINE(static MaybeObject* StringifyString(Isolate* isolate,
45                                              Handle<String> object));
46
47  private:
48   static const int kInitialPartLength = 32;
49   static const int kMaxPartLength = 16 * 1024;
50   static const int kPartLengthGrowthFactor = 2;
51
52   enum Result { UNCHANGED, SUCCESS, EXCEPTION, CIRCULAR, STACK_OVERFLOW };
53
54   void Accumulate();
55
56   void Extend();
57
58   void ChangeEncoding();
59
60   INLINE(void ShrinkCurrentPart());
61
62   template <bool is_ascii, typename Char>
63   INLINE(void Append_(Char c));
64
65   template <bool is_ascii, typename Char>
66   INLINE(void Append_(const Char* chars));
67
68   INLINE(void Append(uint8_t c)) {
69     if (is_ascii_) {
70       Append_<true>(c);
71     } else {
72       Append_<false>(c);
73     }
74   }
75
76   INLINE(void AppendAscii(const char* chars)) {
77     if (is_ascii_) {
78       Append_<true>(reinterpret_cast<const uint8_t*>(chars));
79     } else {
80       Append_<false>(reinterpret_cast<const uint8_t*>(chars));
81     }
82   }
83
84   Handle<Object> ApplyToJsonFunction(Handle<Object> object,
85                                      Handle<Object> key);
86
87   Result SerializeGeneric(Handle<Object> object,
88                           Handle<Object> key,
89                           bool deferred_comma,
90                           bool deferred_key);
91
92   template <typename ResultType, typename Char>
93   INLINE(static MaybeObject* StringifyString_(Isolate* isolate,
94                                               Vector<Char> vector,
95                                               Handle<String> result));
96
97   // Entry point to serialize the object.
98   INLINE(Result SerializeObject(Handle<Object> obj)) {
99     return Serialize_<false>(obj, false, factory_->empty_string());
100   }
101
102   // Serialize an array element.
103   // The index may serve as argument for the toJSON function.
104   INLINE(Result SerializeElement(Isolate* isolate,
105                                  Handle<Object> object,
106                                  int i)) {
107     return Serialize_<false>(object,
108                              false,
109                              Handle<Object>(Smi::FromInt(i), isolate));
110   }
111
112   // Serialize a object property.
113   // The key may or may not be serialized depending on the property.
114   // The key may also serve as argument for the toJSON function.
115   INLINE(Result SerializeProperty(Handle<Object> object,
116                                   bool deferred_comma,
117                                   Handle<String> deferred_key)) {
118     ASSERT(!deferred_key.is_null());
119     return Serialize_<true>(object, deferred_comma, deferred_key);
120   }
121
122   template <bool deferred_string_key>
123   Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
124
125   void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
126     if (deferred_comma) Append(',');
127     SerializeString(Handle<String>::cast(deferred_key));
128     Append(':');
129   }
130
131   Result SerializeSmi(Smi* object);
132
133   Result SerializeDouble(double number);
134   INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
135     return SerializeDouble(object->value());
136   }
137
138   Result SerializeJSValue(Handle<JSValue> object);
139
140   INLINE(Result SerializeJSArray(Handle<JSArray> object));
141   INLINE(Result SerializeJSObject(Handle<JSObject> object));
142
143   Result SerializeJSArraySlow(Handle<JSArray> object, int length);
144
145   void SerializeString(Handle<String> object);
146
147   template <typename SrcChar, typename DestChar>
148   INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
149                                               DestChar* dest,
150                                               int length));
151
152   template <bool is_ascii, typename Char>
153   INLINE(void SerializeString_(Handle<String> string));
154
155   template <typename Char>
156   INLINE(static bool DoNotEscape(Char c));
157
158   template <typename Char>
159   INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
160
161   Result StackPush(Handle<Object> object);
162   void StackPop();
163
164   INLINE(Handle<String> accumulator()) {
165     return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
166   }
167
168   INLINE(void set_accumulator(Handle<String> string)) {
169     return accumulator_store_->set_value(*string);
170   }
171
172   Isolate* isolate_;
173   Factory* factory_;
174   // We use a value wrapper for the string accumulator to keep the
175   // (indirect) handle to it in the outermost handle scope.
176   Handle<JSValue> accumulator_store_;
177   Handle<String> current_part_;
178   Handle<String> tojson_string_;
179   Handle<JSArray> stack_;
180   int current_index_;
181   int part_length_;
182   bool is_ascii_;
183   bool overflowed_;
184
185   static const int kJsonEscapeTableEntrySize = 8;
186   static const char* const JsonEscapeTable;
187 };
188
189
190 // Translation table to escape ASCII characters.
191 // Table entries start at a multiple of 8 and are null-terminated.
192 const char* const BasicJsonStringifier::JsonEscapeTable =
193     "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
194     "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
195     "\\b\0     \\t\0     \\n\0     \\u000b\0 "
196     "\\f\0     \\r\0     \\u000e\0 \\u000f\0 "
197     "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
198     "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
199     "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
200     "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
201     " \0      !\0      \\\"\0     #\0      "
202     "$\0      %\0      &\0      '\0      "
203     "(\0      )\0      *\0      +\0      "
204     ",\0      -\0      .\0      /\0      "
205     "0\0      1\0      2\0      3\0      "
206     "4\0      5\0      6\0      7\0      "
207     "8\0      9\0      :\0      ;\0      "
208     "<\0      =\0      >\0      ?\0      "
209     "@\0      A\0      B\0      C\0      "
210     "D\0      E\0      F\0      G\0      "
211     "H\0      I\0      J\0      K\0      "
212     "L\0      M\0      N\0      O\0      "
213     "P\0      Q\0      R\0      S\0      "
214     "T\0      U\0      V\0      W\0      "
215     "X\0      Y\0      Z\0      [\0      "
216     "\\\\\0     ]\0      ^\0      _\0      "
217     "`\0      a\0      b\0      c\0      "
218     "d\0      e\0      f\0      g\0      "
219     "h\0      i\0      j\0      k\0      "
220     "l\0      m\0      n\0      o\0      "
221     "p\0      q\0      r\0      s\0      "
222     "t\0      u\0      v\0      w\0      "
223     "x\0      y\0      z\0      {\0      "
224     "|\0      }\0      ~\0      \177\0      "
225     "\200\0      \201\0      \202\0      \203\0      "
226     "\204\0      \205\0      \206\0      \207\0      "
227     "\210\0      \211\0      \212\0      \213\0      "
228     "\214\0      \215\0      \216\0      \217\0      "
229     "\220\0      \221\0      \222\0      \223\0      "
230     "\224\0      \225\0      \226\0      \227\0      "
231     "\230\0      \231\0      \232\0      \233\0      "
232     "\234\0      \235\0      \236\0      \237\0      "
233     "\240\0      \241\0      \242\0      \243\0      "
234     "\244\0      \245\0      \246\0      \247\0      "
235     "\250\0      \251\0      \252\0      \253\0      "
236     "\254\0      \255\0      \256\0      \257\0      "
237     "\260\0      \261\0      \262\0      \263\0      "
238     "\264\0      \265\0      \266\0      \267\0      "
239     "\270\0      \271\0      \272\0      \273\0      "
240     "\274\0      \275\0      \276\0      \277\0      "
241     "\300\0      \301\0      \302\0      \303\0      "
242     "\304\0      \305\0      \306\0      \307\0      "
243     "\310\0      \311\0      \312\0      \313\0      "
244     "\314\0      \315\0      \316\0      \317\0      "
245     "\320\0      \321\0      \322\0      \323\0      "
246     "\324\0      \325\0      \326\0      \327\0      "
247     "\330\0      \331\0      \332\0      \333\0      "
248     "\334\0      \335\0      \336\0      \337\0      "
249     "\340\0      \341\0      \342\0      \343\0      "
250     "\344\0      \345\0      \346\0      \347\0      "
251     "\350\0      \351\0      \352\0      \353\0      "
252     "\354\0      \355\0      \356\0      \357\0      "
253     "\360\0      \361\0      \362\0      \363\0      "
254     "\364\0      \365\0      \366\0      \367\0      "
255     "\370\0      \371\0      \372\0      \373\0      "
256     "\374\0      \375\0      \376\0      \377\0      ";
257
258
259 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
260     : isolate_(isolate),
261       current_index_(0),
262       is_ascii_(true),
263       overflowed_(false) {
264   factory_ = isolate_->factory();
265   accumulator_store_ = Handle<JSValue>::cast(
266                            factory_->ToObject(factory_->empty_string()));
267   part_length_ = kInitialPartLength;
268   current_part_ = factory_->NewRawOneByteString(part_length_);
269   ASSERT(!current_part_.is_null());
270   tojson_string_ = factory_->toJSON_string();
271   stack_ = factory_->NewJSArray(8);
272 }
273
274
275 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) {
276   switch (SerializeObject(object)) {
277     case UNCHANGED:
278       return isolate_->heap()->undefined_value();
279     case SUCCESS: {
280       ShrinkCurrentPart();
281       Accumulate();
282       if (overflowed_) return isolate_->ThrowInvalidStringLength();
283       return *accumulator();
284     }
285     case CIRCULAR:
286       return isolate_->Throw(*factory_->NewTypeError(
287                  "circular_structure", HandleVector<Object>(NULL, 0)));
288     case STACK_OVERFLOW:
289       return isolate_->StackOverflow();
290     default:
291       return Failure::Exception();
292   }
293 }
294
295
296 MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
297                                                    Handle<String> object) {
298   static const int kJsonQuoteWorstCaseBlowup = 6;
299   static const int kSpaceForQuotes = 2;
300   int worst_case_length =
301       object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
302
303   if (worst_case_length > 32 * KB) {  // Slow path if too large.
304     BasicJsonStringifier stringifier(isolate);
305     return stringifier.Stringify(object);
306   }
307
308   FlattenString(object);
309   ASSERT(object->IsFlat());
310   if (object->IsOneByteRepresentationUnderneath()) {
311     Handle<String> result =
312         isolate->factory()->NewRawOneByteString(worst_case_length);
313     ASSERT(!result.is_null());
314     DisallowHeapAllocation no_gc;
315     return StringifyString_<SeqOneByteString>(
316         isolate,
317         object->GetFlatContent().ToOneByteVector(),
318         result);
319   } else {
320     Handle<String> result =
321         isolate->factory()->NewRawTwoByteString(worst_case_length);
322     ASSERT(!result.is_null());
323     DisallowHeapAllocation no_gc;
324     return StringifyString_<SeqTwoByteString>(
325         isolate,
326         object->GetFlatContent().ToUC16Vector(),
327         result);
328   }
329 }
330
331
332 template <typename ResultType, typename Char>
333 MaybeObject* BasicJsonStringifier::StringifyString_(Isolate* isolate,
334                                                     Vector<Char> vector,
335                                                     Handle<String> result) {
336   DisallowHeapAllocation no_gc;
337   int final_size = 0;
338   ResultType* dest = ResultType::cast(*result);
339   dest->Set(final_size++, '\"');
340   final_size += SerializeStringUnchecked_(vector.start(),
341                                           dest->GetChars() + 1,
342                                           vector.length());
343   dest->Set(final_size++, '\"');
344   return *SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
345 }
346
347
348 template <bool is_ascii, typename Char>
349 void BasicJsonStringifier::Append_(Char c) {
350   if (is_ascii) {
351     SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
352         current_index_++, c);
353   } else {
354     SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
355         current_index_++, c);
356   }
357   if (current_index_ == part_length_) Extend();
358 }
359
360
361 template <bool is_ascii, typename Char>
362 void BasicJsonStringifier::Append_(const Char* chars) {
363   for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars);
364 }
365
366
367 Handle<Object> BasicJsonStringifier::ApplyToJsonFunction(
368     Handle<Object> object, Handle<Object> key) {
369   LookupResult lookup(isolate_);
370   JSObject::cast(*object)->LookupRealNamedProperty(*tojson_string_, &lookup);
371   if (!lookup.IsProperty()) return object;
372   PropertyAttributes attr;
373   Handle<Object> fun =
374       Object::GetProperty(object, object, &lookup, tojson_string_, &attr);
375   if (fun.is_null()) return Handle<Object>::null();
376   if (!fun->IsJSFunction()) return object;
377
378   // Call toJSON function.
379   if (key->IsSmi()) key = factory_->NumberToString(key);
380   Handle<Object> argv[] = { key };
381   bool has_exception = false;
382   HandleScope scope(isolate_);
383   object = Execution::Call(isolate_, fun, object, 1, argv, &has_exception);
384   // Return empty handle to signal an exception.
385   if (has_exception) return Handle<Object>::null();
386   return scope.CloseAndEscape(object);
387 }
388
389
390 BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
391     Handle<Object> object) {
392   StackLimitCheck check(isolate_);
393   if (check.HasOverflowed()) return STACK_OVERFLOW;
394
395   int length = Smi::cast(stack_->length())->value();
396   {
397     DisallowHeapAllocation no_allocation;
398     FixedArray* elements = FixedArray::cast(stack_->elements());
399     for (int i = 0; i < length; i++) {
400       if (elements->get(i) == *object) {
401         return CIRCULAR;
402       }
403     }
404   }
405   JSArray::EnsureSize(stack_, length + 1);
406   FixedArray::cast(stack_->elements())->set(length, *object);
407   stack_->set_length(Smi::FromInt(length + 1));
408   return SUCCESS;
409 }
410
411
412 void BasicJsonStringifier::StackPop() {
413   int length = Smi::cast(stack_->length())->value();
414   stack_->set_length(Smi::FromInt(length - 1));
415 }
416
417
418 template <bool deferred_string_key>
419 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
420     Handle<Object> object, bool comma, Handle<Object> key) {
421   if (object->IsJSObject()) {
422     object = ApplyToJsonFunction(object, key);
423     if (object.is_null()) return EXCEPTION;
424   }
425
426   if (object->IsSmi()) {
427     if (deferred_string_key) SerializeDeferredKey(comma, key);
428     return SerializeSmi(Smi::cast(*object));
429   }
430
431   switch (HeapObject::cast(*object)->map()->instance_type()) {
432     case HEAP_NUMBER_TYPE:
433       if (deferred_string_key) SerializeDeferredKey(comma, key);
434       return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
435     case ODDBALL_TYPE:
436       switch (Oddball::cast(*object)->kind()) {
437         case Oddball::kFalse:
438           if (deferred_string_key) SerializeDeferredKey(comma, key);
439           AppendAscii("false");
440           return SUCCESS;
441         case Oddball::kTrue:
442           if (deferred_string_key) SerializeDeferredKey(comma, key);
443           AppendAscii("true");
444           return SUCCESS;
445         case Oddball::kNull:
446           if (deferred_string_key) SerializeDeferredKey(comma, key);
447           AppendAscii("null");
448           return SUCCESS;
449         default:
450           return UNCHANGED;
451       }
452     case JS_ARRAY_TYPE:
453       if (object->IsAccessCheckNeeded()) break;
454       if (deferred_string_key) SerializeDeferredKey(comma, key);
455       return SerializeJSArray(Handle<JSArray>::cast(object));
456     case JS_VALUE_TYPE:
457       if (deferred_string_key) SerializeDeferredKey(comma, key);
458       return SerializeJSValue(Handle<JSValue>::cast(object));
459     case JS_FUNCTION_TYPE:
460       return UNCHANGED;
461     default:
462       if (object->IsString()) {
463         if (deferred_string_key) SerializeDeferredKey(comma, key);
464         SerializeString(Handle<String>::cast(object));
465         return SUCCESS;
466       } else if (object->IsJSObject()) {
467         if (object->IsAccessCheckNeeded()) break;
468         if (deferred_string_key) SerializeDeferredKey(comma, key);
469         return SerializeJSObject(Handle<JSObject>::cast(object));
470       }
471   }
472
473   return SerializeGeneric(object, key, comma, deferred_string_key);
474 }
475
476
477 BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
478     Handle<Object> object,
479     Handle<Object> key,
480     bool deferred_comma,
481     bool deferred_key) {
482   Handle<JSObject> builtins(isolate_->native_context()->builtins());
483   Handle<JSFunction> builtin =
484       Handle<JSFunction>::cast(GetProperty(builtins, "JSONSerializeAdapter"));
485
486   Handle<Object> argv[] = { key, object };
487   bool has_exception = false;
488   Handle<Object> result =
489       Execution::Call(isolate_, builtin, object, 2, argv, &has_exception);
490   if (has_exception) return EXCEPTION;
491   if (result->IsUndefined()) return UNCHANGED;
492   if (deferred_key) {
493     if (key->IsSmi()) key = factory_->NumberToString(key);
494     SerializeDeferredKey(deferred_comma, key);
495   }
496
497   Handle<String> result_string = Handle<String>::cast(result);
498   // Shrink current part, attach it to the accumulator, also attach the result
499   // string to the accumulator, and allocate a new part.
500   ShrinkCurrentPart();  // Shrink.
501   part_length_ = kInitialPartLength;  // Allocate conservatively.
502   Extend();             // Attach current part and allocate new part.
503   // Attach result string to the accumulator.
504   Handle<String> cons = factory_->NewConsString(accumulator(), result_string);
505   RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, cons, EXCEPTION);
506   set_accumulator(cons);
507   return SUCCESS;
508 }
509
510
511 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
512     Handle<JSValue> object) {
513   bool has_exception = false;
514   String* class_name = object->class_name();
515   if (class_name == isolate_->heap()->String_string()) {
516     Handle<Object> value =
517         Execution::ToString(isolate_, object, &has_exception);
518     if (has_exception) return EXCEPTION;
519     SerializeString(Handle<String>::cast(value));
520   } else if (class_name == isolate_->heap()->Number_string()) {
521     Handle<Object> value =
522         Execution::ToNumber(isolate_, object, &has_exception);
523     if (has_exception) return EXCEPTION;
524     if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
525     SerializeHeapNumber(Handle<HeapNumber>::cast(value));
526   } else {
527     ASSERT(class_name == isolate_->heap()->Boolean_string());
528     Object* value = JSValue::cast(*object)->value();
529     ASSERT(value->IsBoolean());
530     AppendAscii(value->IsTrue() ? "true" : "false");
531   }
532   return SUCCESS;
533 }
534
535
536 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
537   static const int kBufferSize = 100;
538   char chars[kBufferSize];
539   Vector<char> buffer(chars, kBufferSize);
540   AppendAscii(IntToCString(object->value(), buffer));
541   return SUCCESS;
542 }
543
544
545 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
546     double number) {
547   if (std::isinf(number) || std::isnan(number)) {
548     AppendAscii("null");
549     return SUCCESS;
550   }
551   static const int kBufferSize = 100;
552   char chars[kBufferSize];
553   Vector<char> buffer(chars, kBufferSize);
554   AppendAscii(DoubleToCString(number, buffer));
555   return SUCCESS;
556 }
557
558
559 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
560     Handle<JSArray> object) {
561   HandleScope handle_scope(isolate_);
562   Result stack_push = StackPush(object);
563   if (stack_push != SUCCESS) return stack_push;
564   int length = Smi::cast(object->length())->value();
565   Append('[');
566   switch (object->GetElementsKind()) {
567     case FAST_SMI_ELEMENTS: {
568       Handle<FixedArray> elements(
569           FixedArray::cast(object->elements()), isolate_);
570       for (int i = 0; i < length; i++) {
571         if (i > 0) Append(',');
572         SerializeSmi(Smi::cast(elements->get(i)));
573       }
574       break;
575     }
576     case FAST_DOUBLE_ELEMENTS: {
577       Handle<FixedDoubleArray> elements(
578           FixedDoubleArray::cast(object->elements()), isolate_);
579       for (int i = 0; i < length; i++) {
580         if (i > 0) Append(',');
581         SerializeDouble(elements->get_scalar(i));
582       }
583       break;
584     }
585     case FAST_ELEMENTS: {
586       Handle<FixedArray> elements(
587           FixedArray::cast(object->elements()), isolate_);
588       for (int i = 0; i < length; i++) {
589         if (i > 0) Append(',');
590         Result result =
591             SerializeElement(isolate_,
592                              Handle<Object>(elements->get(i), isolate_),
593                              i);
594         if (result == SUCCESS) continue;
595         if (result == UNCHANGED) {
596           AppendAscii("null");
597         } else {
598           return result;
599         }
600       }
601       break;
602     }
603     // TODO(yangguo):  The FAST_HOLEY_* cases could be handled in a faster way.
604     // They resemble the non-holey cases except that a prototype chain lookup
605     // is necessary for holes.
606     default: {
607       Result result = SerializeJSArraySlow(object, length);
608       if (result != SUCCESS) return result;
609       break;
610     }
611   }
612   Append(']');
613   StackPop();
614   current_part_ = handle_scope.CloseAndEscape(current_part_);
615   return SUCCESS;
616 }
617
618
619 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
620     Handle<JSArray> object, int length) {
621   for (int i = 0; i < length; i++) {
622     if (i > 0) Append(',');
623     Handle<Object> element = Object::GetElement(isolate_, object, i);
624     RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, element, EXCEPTION);
625     if (element->IsUndefined()) {
626       AppendAscii("null");
627     } else {
628       Result result = SerializeElement(isolate_, element, i);
629       if (result == SUCCESS) continue;
630       if (result == UNCHANGED) {
631         AppendAscii("null");
632       } else {
633         return result;
634       }
635     }
636   }
637   return SUCCESS;
638 }
639
640
641 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
642     Handle<JSObject> object) {
643   HandleScope handle_scope(isolate_);
644   Result stack_push = StackPush(object);
645   if (stack_push != SUCCESS) return stack_push;
646   if (object->IsJSGlobalProxy()) {
647     object = Handle<JSObject>(
648                  JSObject::cast(object->GetPrototype()), isolate_);
649     ASSERT(object->IsGlobalObject());
650   }
651
652   Append('{');
653   bool comma = false;
654
655   if (object->HasFastProperties() &&
656       !object->HasIndexedInterceptor() &&
657       !object->HasNamedInterceptor() &&
658       object->elements()->length() == 0) {
659     Handle<Map> map(object->map());
660     for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
661       Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
662       // TODO(rossberg): Should this throw?
663       if (!name->IsString()) continue;
664       Handle<String> key = Handle<String>::cast(name);
665       PropertyDetails details = map->instance_descriptors()->GetDetails(i);
666       if (details.IsDontEnum()) continue;
667       Handle<Object> property;
668       if (details.type() == FIELD && *map == object->map()) {
669         property = Handle<Object>(
670                        object->RawFastPropertyAt(
671                            map->instance_descriptors()->GetFieldIndex(i)),
672                        isolate_);
673       } else {
674         property = GetProperty(isolate_, object, key);
675         RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, property, EXCEPTION);
676       }
677       Result result = SerializeProperty(property, comma, key);
678       if (!comma && result == SUCCESS) comma = true;
679       if (result >= EXCEPTION) return result;
680     }
681   } else {
682     bool has_exception = false;
683     Handle<FixedArray> contents =
684         GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception);
685     if (has_exception) return EXCEPTION;
686
687     for (int i = 0; i < contents->length(); i++) {
688       Object* key = contents->get(i);
689       Handle<String> key_handle;
690       Handle<Object> property;
691       if (key->IsString()) {
692         key_handle = Handle<String>(String::cast(key), isolate_);
693         property = GetProperty(isolate_, object, key_handle);
694       } else {
695         ASSERT(key->IsNumber());
696         key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
697         uint32_t index;
698         if (key->IsSmi()) {
699           property = Object::GetElement(
700               isolate_, object, Smi::cast(key)->value());
701         } else if (key_handle->AsArrayIndex(&index)) {
702           property = Object::GetElement(isolate_, object, index);
703         } else {
704           property = GetProperty(isolate_, object, key_handle);
705         }
706       }
707       RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, property, EXCEPTION);
708       Result result = SerializeProperty(property, comma, key_handle);
709       if (!comma && result == SUCCESS) comma = true;
710       if (result >= EXCEPTION) return result;
711     }
712   }
713
714   Append('}');
715   StackPop();
716   current_part_ = handle_scope.CloseAndEscape(current_part_);
717   return SUCCESS;
718 }
719
720
721 void BasicJsonStringifier::ShrinkCurrentPart() {
722   ASSERT(current_index_ < part_length_);
723   current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
724                                       current_index_);
725 }
726
727
728 void BasicJsonStringifier::Accumulate() {
729   if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
730     // Screw it.  Simply set the flag and carry on.  Throw exception at the end.
731     set_accumulator(factory_->empty_string());
732     overflowed_ = true;
733   } else {
734     set_accumulator(factory_->NewConsString(accumulator(), current_part_));
735   }
736 }
737
738
739 void BasicJsonStringifier::Extend() {
740   Accumulate();
741   if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
742     part_length_ *= kPartLengthGrowthFactor;
743   }
744   if (is_ascii_) {
745     current_part_ = factory_->NewRawOneByteString(part_length_);
746   } else {
747     current_part_ = factory_->NewRawTwoByteString(part_length_);
748   }
749   ASSERT(!current_part_.is_null());
750   current_index_ = 0;
751 }
752
753
754 void BasicJsonStringifier::ChangeEncoding() {
755   ShrinkCurrentPart();
756   Accumulate();
757   current_part_ = factory_->NewRawTwoByteString(part_length_);
758   ASSERT(!current_part_.is_null());
759   current_index_ = 0;
760   is_ascii_ = false;
761 }
762
763
764 template <typename SrcChar, typename DestChar>
765 int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
766                                                     DestChar* dest,
767                                                     int length) {
768   DestChar* dest_start = dest;
769
770   // Assert that uc16 character is not truncated down to 8 bit.
771   // The <uc16, char> version of this method must not be called.
772   ASSERT(sizeof(*dest) >= sizeof(*src));
773
774   for (int i = 0; i < length; i++) {
775     SrcChar c = src[i];
776     if (DoNotEscape(c)) {
777       *(dest++) = static_cast<DestChar>(c);
778     } else {
779       const uint8_t* chars = reinterpret_cast<const uint8_t*>(
780           &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
781       while (*chars != '\0') *(dest++) = *(chars++);
782     }
783   }
784
785   return static_cast<int>(dest - dest_start);
786 }
787
788
789 template <bool is_ascii, typename Char>
790 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
791   int length = string->length();
792   Append_<is_ascii, char>('"');
793   // We make a rough estimate to find out if the current string can be
794   // serialized without allocating a new string part. The worst case length of
795   // an escaped character is 6.  Shifting the remainin string length right by 3
796   // is a more pessimistic estimate, but faster to calculate.
797
798   if (((part_length_ - current_index_) >> 3) > length) {
799     DisallowHeapAllocation no_gc;
800     Vector<const Char> vector = GetCharVector<Char>(string);
801     if (is_ascii) {
802       current_index_ += SerializeStringUnchecked_(
803           vector.start(),
804           SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
805           length);
806     } else {
807       current_index_ += SerializeStringUnchecked_(
808           vector.start(),
809           SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
810           length);
811     }
812   } else {
813     String* string_location = NULL;
814     Vector<const Char> vector(NULL, 0);
815     for (int i = 0; i < length; i++) {
816       // If GC moved the string, we need to refresh the vector.
817       if (*string != string_location) {
818         DisallowHeapAllocation no_gc;
819         // This does not actually prevent the string from being relocated later.
820         vector = GetCharVector<Char>(string);
821         string_location = *string;
822       }
823       Char c = vector[i];
824       if (DoNotEscape(c)) {
825         Append_<is_ascii, Char>(c);
826       } else {
827         Append_<is_ascii, uint8_t>(reinterpret_cast<const uint8_t*>(
828             &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
829       }
830     }
831   }
832
833   Append_<is_ascii, uint8_t>('"');
834 }
835
836
837 template <>
838 bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
839   return c >= '#' && c <= '~' && c != '\\';
840 }
841
842
843 template <>
844 bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
845   return c >= '#' && c != '\\' && c != 0x7f;
846 }
847
848
849 template <>
850 Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
851     Handle<String> string) {
852   String::FlatContent flat = string->GetFlatContent();
853   ASSERT(flat.IsAscii());
854   return flat.ToOneByteVector();
855 }
856
857
858 template <>
859 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
860   String::FlatContent flat = string->GetFlatContent();
861   ASSERT(flat.IsTwoByte());
862   return flat.ToUC16Vector();
863 }
864
865
866 void BasicJsonStringifier::SerializeString(Handle<String> object) {
867   object = FlattenGetString(object);
868   if (is_ascii_) {
869     if (object->IsOneByteRepresentationUnderneath()) {
870       SerializeString_<true, uint8_t>(object);
871     } else {
872       ChangeEncoding();
873       SerializeString(object);
874     }
875   } else {
876     if (object->IsOneByteRepresentationUnderneath()) {
877       SerializeString_<false, uint8_t>(object);
878     } else {
879       SerializeString_<false, uc16>(object);
880     }
881   }
882 }
883
884 } }  // namespace v8::internal
885
886 #endif  // V8_JSON_STRINGIFIER_H_