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