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