LCOV - code coverage report
Current view: top level - src - json-stringifier.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 323 340 95.0 %
Date: 2019-01-20 Functions: 24 24 100.0 %

          Line data    Source code
       1             : // Copyright 2016 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             : #include "src/json-stringifier.h"
       6             : 
       7             : #include "src/conversions.h"
       8             : #include "src/lookup.h"
       9             : #include "src/message-template.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/objects/heap-number-inl.h"
      12             : #include "src/objects/js-array-inl.h"
      13             : #include "src/objects/oddball-inl.h"
      14             : #include "src/objects/smi.h"
      15             : #include "src/string-builder-inl.h"
      16             : #include "src/utils.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : 
      21             : class JsonStringifier {
      22             :  public:
      23             :   explicit JsonStringifier(Isolate* isolate);
      24             : 
      25     1140762 :   ~JsonStringifier() { DeleteArray(gap_); }
      26             : 
      27             :   V8_WARN_UNUSED_RESULT MaybeHandle<Object> Stringify(Handle<Object> object,
      28             :                                                       Handle<Object> replacer,
      29             :                                                       Handle<Object> gap);
      30             : 
      31             :  private:
      32             :   enum Result { UNCHANGED, SUCCESS, EXCEPTION };
      33             : 
      34             :   bool InitializeReplacer(Handle<Object> replacer);
      35             :   bool InitializeGap(Handle<Object> gap);
      36             : 
      37             :   V8_WARN_UNUSED_RESULT MaybeHandle<Object> ApplyToJsonFunction(
      38             :       Handle<Object> object, Handle<Object> key);
      39             :   V8_WARN_UNUSED_RESULT MaybeHandle<Object> ApplyReplacerFunction(
      40             :       Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder);
      41             : 
      42             :   // Entry point to serialize the object.
      43     1140753 :   V8_INLINE Result SerializeObject(Handle<Object> obj) {
      44     2281506 :     return Serialize_<false>(obj, false, factory()->empty_string());
      45             :   }
      46             : 
      47             :   // Serialize an array element.
      48             :   // The index may serve as argument for the toJSON function.
      49             :   V8_INLINE Result SerializeElement(Isolate* isolate, Handle<Object> object,
      50             :                                     int i) {
      51             :     return Serialize_<false>(object, false,
      52    20054260 :                              Handle<Object>(Smi::FromInt(i), isolate));
      53             :   }
      54             : 
      55             :   // Serialize a object property.
      56             :   // The key may or may not be serialized depending on the property.
      57             :   // The key may also serve as argument for the toJSON function.
      58             :   V8_INLINE Result SerializeProperty(Handle<Object> object, bool deferred_comma,
      59             :                                      Handle<String> deferred_key) {
      60             :     DCHECK(!deferred_key.is_null());
      61      956970 :     return Serialize_<true>(object, deferred_comma, deferred_key);
      62             :   }
      63             : 
      64             :   template <bool deferred_string_key>
      65          36 :   Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
      66             : 
      67             :   V8_INLINE void SerializeDeferredKey(bool deferred_comma,
      68             :                                       Handle<Object> deferred_key);
      69             : 
      70             :   Result SerializeSmi(Smi object);
      71             : 
      72             :   Result SerializeDouble(double number);
      73             :   V8_INLINE Result SerializeHeapNumber(Handle<HeapNumber> object) {
      74        1802 :     return SerializeDouble(object->value());
      75             :   }
      76             : 
      77             :   Result SerializeJSValue(Handle<JSValue> object);
      78             : 
      79             :   V8_INLINE Result SerializeJSArray(Handle<JSArray> object);
      80             :   V8_INLINE Result SerializeJSObject(Handle<JSObject> object);
      81             : 
      82             :   Result SerializeJSProxy(Handle<JSProxy> object);
      83             :   Result SerializeJSReceiverSlow(Handle<JSReceiver> object);
      84             :   Result SerializeArrayLikeSlow(Handle<JSReceiver> object, uint32_t start,
      85             :                                 uint32_t length);
      86             : 
      87             :   void SerializeString(Handle<String> object);
      88             : 
      89             :   template <typename SrcChar, typename DestChar>
      90             :   V8_INLINE static void SerializeStringUnchecked_(
      91             :       Vector<const SrcChar> src,
      92             :       IncrementalStringBuilder::NoExtend<DestChar>* dest);
      93             : 
      94             :   template <typename SrcChar, typename DestChar>
      95             :   V8_INLINE void SerializeString_(Handle<String> string);
      96             : 
      97             :   template <typename Char>
      98             :   V8_INLINE static bool DoNotEscape(Char c);
      99             : 
     100             :   V8_INLINE void NewLine();
     101      434371 :   V8_INLINE void Indent() { indent_++; }
     102      432821 :   V8_INLINE void Unindent() { indent_--; }
     103             :   V8_INLINE void Separator(bool first);
     104             : 
     105             :   Handle<JSReceiver> CurrentHolder(Handle<Object> value,
     106             :                                    Handle<Object> inital_holder);
     107             : 
     108             :   Result StackPush(Handle<Object> object);
     109             :   void StackPop();
     110             : 
     111     1140753 :   Factory* factory() { return isolate_->factory(); }
     112             : 
     113             :   Isolate* isolate_;
     114             :   IncrementalStringBuilder builder_;
     115             :   Handle<String> tojson_string_;
     116             :   Handle<JSArray> stack_;
     117             :   Handle<FixedArray> property_list_;
     118             :   Handle<JSReceiver> replacer_function_;
     119             :   uc16* gap_;
     120             :   int indent_;
     121             : 
     122             :   static const int kJsonEscapeTableEntrySize = 8;
     123             :   static const char* const JsonEscapeTable;
     124             : };
     125             : 
     126     1140762 : MaybeHandle<Object> JsonStringify(Isolate* isolate, Handle<Object> object,
     127             :                                   Handle<Object> replacer, Handle<Object> gap) {
     128     1140762 :   JsonStringifier stringifier(isolate);
     129     2281524 :   return stringifier.Stringify(object, replacer, gap);
     130             : }
     131             : 
     132             : // Translation table to escape Latin1 characters.
     133             : // Table entries start at a multiple of 8 and are null-terminated.
     134             : const char* const JsonStringifier::JsonEscapeTable =
     135             :     "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
     136             :     "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
     137             :     "\\b\0     \\t\0     \\n\0     \\u000b\0 "
     138             :     "\\f\0     \\r\0     \\u000e\0 \\u000f\0 "
     139             :     "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
     140             :     "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
     141             :     "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
     142             :     "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
     143             :     " \0      !\0      \\\"\0     #\0      "
     144             :     "$\0      %\0      &\0      '\0      "
     145             :     "(\0      )\0      *\0      +\0      "
     146             :     ",\0      -\0      .\0      /\0      "
     147             :     "0\0      1\0      2\0      3\0      "
     148             :     "4\0      5\0      6\0      7\0      "
     149             :     "8\0      9\0      :\0      ;\0      "
     150             :     "<\0      =\0      >\0      ?\0      "
     151             :     "@\0      A\0      B\0      C\0      "
     152             :     "D\0      E\0      F\0      G\0      "
     153             :     "H\0      I\0      J\0      K\0      "
     154             :     "L\0      M\0      N\0      O\0      "
     155             :     "P\0      Q\0      R\0      S\0      "
     156             :     "T\0      U\0      V\0      W\0      "
     157             :     "X\0      Y\0      Z\0      [\0      "
     158             :     "\\\\\0     ]\0      ^\0      _\0      "
     159             :     "`\0      a\0      b\0      c\0      "
     160             :     "d\0      e\0      f\0      g\0      "
     161             :     "h\0      i\0      j\0      k\0      "
     162             :     "l\0      m\0      n\0      o\0      "
     163             :     "p\0      q\0      r\0      s\0      "
     164             :     "t\0      u\0      v\0      w\0      "
     165             :     "x\0      y\0      z\0      {\0      "
     166             :     "|\0      }\0      ~\0      \x7F\0      "
     167             :     "\x80\0      \x81\0      \x82\0      \x83\0      "
     168             :     "\x84\0      \x85\0      \x86\0      \x87\0      "
     169             :     "\x88\0      \x89\0      \x8A\0      \x8B\0      "
     170             :     "\x8C\0      \x8D\0      \x8E\0      \x8F\0      "
     171             :     "\x90\0      \x91\0      \x92\0      \x93\0      "
     172             :     "\x94\0      \x95\0      \x96\0      \x97\0      "
     173             :     "\x98\0      \x99\0      \x9A\0      \x9B\0      "
     174             :     "\x9C\0      \x9D\0      \x9E\0      \x9F\0      "
     175             :     "\xA0\0      \xA1\0      \xA2\0      \xA3\0      "
     176             :     "\xA4\0      \xA5\0      \xA6\0      \xA7\0      "
     177             :     "\xA8\0      \xA9\0      \xAA\0      \xAB\0      "
     178             :     "\xAC\0      \xAD\0      \xAE\0      \xAF\0      "
     179             :     "\xB0\0      \xB1\0      \xB2\0      \xB3\0      "
     180             :     "\xB4\0      \xB5\0      \xB6\0      \xB7\0      "
     181             :     "\xB8\0      \xB9\0      \xBA\0      \xBB\0      "
     182             :     "\xBC\0      \xBD\0      \xBE\0      \xBF\0      "
     183             :     "\xC0\0      \xC1\0      \xC2\0      \xC3\0      "
     184             :     "\xC4\0      \xC5\0      \xC6\0      \xC7\0      "
     185             :     "\xC8\0      \xC9\0      \xCA\0      \xCB\0      "
     186             :     "\xCC\0      \xCD\0      \xCE\0      \xCF\0      "
     187             :     "\xD0\0      \xD1\0      \xD2\0      \xD3\0      "
     188             :     "\xD4\0      \xD5\0      \xD6\0      \xD7\0      "
     189             :     "\xD8\0      \xD9\0      \xDA\0      \xDB\0      "
     190             :     "\xDC\0      \xDD\0      \xDE\0      \xDF\0      "
     191             :     "\xE0\0      \xE1\0      \xE2\0      \xE3\0      "
     192             :     "\xE4\0      \xE5\0      \xE6\0      \xE7\0      "
     193             :     "\xE8\0      \xE9\0      \xEA\0      \xEB\0      "
     194             :     "\xEC\0      \xED\0      \xEE\0      \xEF\0      "
     195             :     "\xF0\0      \xF1\0      \xF2\0      \xF3\0      "
     196             :     "\xF4\0      \xF5\0      \xF6\0      \xF7\0      "
     197             :     "\xF8\0      \xF9\0      \xFA\0      \xFB\0      "
     198             :     "\xFC\0      \xFD\0      \xFE\0      \xFF\0      ";
     199             : 
     200     2281524 : JsonStringifier::JsonStringifier(Isolate* isolate)
     201     2281524 :     : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) {
     202     1140762 :   tojson_string_ = factory()->toJSON_string();
     203     1140762 :   stack_ = factory()->NewJSArray(8);
     204     1140762 : }
     205             : 
     206     1140762 : MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object,
     207             :                                                Handle<Object> replacer,
     208         268 :                                                Handle<Object> gap) {
     209     1140762 :   if (!InitializeReplacer(replacer)) return MaybeHandle<Object>();
     210     3422259 :   if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) {
     211           0 :     return MaybeHandle<Object>();
     212             :   }
     213             :   Result result = SerializeObject(object);
     214     1141021 :   if (result == UNCHANGED) return factory()->undefined_value();
     215     1140485 :   if (result == SUCCESS) return builder_.Finish();
     216             :   DCHECK(result == EXCEPTION);
     217         286 :   return MaybeHandle<Object>();
     218             : }
     219             : 
     220     1141545 : bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
     221             :   DCHECK(property_list_.is_null());
     222             :   DCHECK(replacer_function_.is_null());
     223             :   Maybe<bool> is_array = Object::IsArray(replacer);
     224     1140762 :   if (is_array.IsNothing()) return false;
     225     1140762 :   if (is_array.FromJust()) {
     226         288 :     HandleScope handle_scope(isolate_);
     227         288 :     Handle<OrderedHashSet> set = factory()->NewOrderedHashSet();
     228             :     Handle<Object> length_obj;
     229         576 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     230             :         isolate_, length_obj,
     231             :         Object::GetLengthFromArrayLike(isolate_,
     232             :                                        Handle<JSReceiver>::cast(replacer)),
     233             :         false);
     234             :     uint32_t length;
     235         279 :     if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
     236         927 :     for (uint32_t i = 0; i < length; i++) {
     237             :       Handle<Object> element;
     238             :       Handle<String> key;
     239        1854 :       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     240             :           isolate_, element, Object::GetElement(isolate_, replacer, i), false);
     241        3366 :       if (element->IsNumber() || element->IsString()) {
     242         936 :         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     243             :             isolate_, key, Object::ToString(isolate_, element), false);
     244         918 :       } else if (element->IsJSValue()) {
     245          81 :         Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_);
     246          72 :         if (value->IsNumber() || value->IsString()) {
     247          54 :           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     248             :               isolate_, key, Object::ToString(isolate_, element), false);
     249             :         }
     250             :       }
     251         927 :       if (key.is_null()) continue;
     252             :       // Object keys are internalized, so do it here.
     253         495 :       key = factory()->InternalizeString(key);
     254         495 :       set = OrderedHashSet::Add(isolate_, set, key);
     255             :     }
     256             :     property_list_ = OrderedHashSet::ConvertToKeysArray(
     257         279 :         isolate_, set, GetKeysConversion::kKeepNumbers);
     258         279 :     property_list_ = handle_scope.CloseAndEscape(property_list_);
     259     2280948 :   } else if (replacer->IsCallable()) {
     260        6824 :     replacer_function_ = Handle<JSReceiver>::cast(replacer);
     261             :   }
     262             :   return true;
     263             : }
     264             : 
     265      181716 : bool JsonStringifier::InitializeGap(Handle<Object> gap) {
     266             :   DCHECK_NULL(gap_);
     267      181716 :   HandleScope scope(isolate_);
     268      363432 :   if (gap->IsJSValue()) {
     269          81 :     Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_);
     270          54 :     if (value->IsString()) {
     271          36 :       ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
     272             :                                        Object::ToString(isolate_, gap), false);
     273          18 :     } else if (value->IsNumber()) {
     274          18 :       ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
     275             :                                        Object::ToNumber(isolate_, gap), false);
     276             :     }
     277             :   }
     278             : 
     279      363432 :   if (gap->IsString()) {
     280        1489 :     Handle<String> gap_string = Handle<String>::cast(gap);
     281        1489 :     if (gap_string->length() > 0) {
     282        4131 :       int gap_length = std::min(gap_string->length(), 10);
     283        1377 :       gap_ = NewArray<uc16>(gap_length + 1);
     284        1377 :       String::WriteToFlat(*gap_string, gap_, 0, gap_length);
     285        2841 :       for (int i = 0; i < gap_length; i++) {
     286        1473 :         if (gap_[i] > String::kMaxOneByteCharCode) {
     287           9 :           builder_.ChangeEncoding();
     288             :           break;
     289             :         }
     290             :       }
     291        1377 :       gap_[gap_length] = '\0';
     292             :     }
     293      360454 :   } else if (gap->IsNumber()) {
     294      180218 :     int num_value = DoubleToInt32(gap->Number());
     295      180218 :     if (num_value > 0) {
     296         202 :       int gap_length = std::min(num_value, 10);
     297         101 :       gap_ = NewArray<uc16>(gap_length + 1);
     298         101 :       for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
     299         101 :       gap_[gap_length] = '\0';
     300             :     }
     301             :   }
     302             :   return true;
     303             : }
     304             : 
     305      438000 : MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object,
     306         225 :                                                          Handle<Object> key) {
     307      438000 :   HandleScope scope(isolate_);
     308             : 
     309      438000 :   Handle<Object> object_for_lookup = object;
     310      876000 :   if (object->IsBigInt()) {
     311         126 :     ASSIGN_RETURN_ON_EXCEPTION(isolate_, object_for_lookup,
     312             :                                Object::ToObject(isolate_, object), Object);
     313             :   }
     314             :   DCHECK(object_for_lookup->IsJSReceiver());
     315             : 
     316             :   // Retrieve toJSON function.
     317             :   Handle<Object> fun;
     318             :   {
     319             :     LookupIterator it(isolate_, object_for_lookup, tojson_string_,
     320      438000 :                       LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
     321      876000 :     ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
     322      875912 :     if (!fun->IsCallable()) return object;
     323             :   }
     324             : 
     325             :   // Call toJSON function.
     326        1899 :   if (key->IsSmi()) key = factory()->NumberToString(key);
     327         837 :   Handle<Object> argv[] = {key};
     328        1674 :   ASSIGN_RETURN_ON_EXCEPTION(isolate_, object,
     329             :                              Execution::Call(isolate_, fun, object, 1, argv),
     330             :                              Object);
     331         819 :   return scope.CloseAndEscape(object);
     332             : }
     333             : 
     334     4967931 : MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction(
     335     4906378 :     Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) {
     336     4967931 :   HandleScope scope(isolate_);
     337    14842240 :   if (key->IsSmi()) key = factory()->NumberToString(key);
     338     4967931 :   Handle<Object> argv[] = {key, value};
     339     4967931 :   Handle<JSReceiver> holder = CurrentHolder(value, initial_holder);
     340     9935862 :   ASSIGN_RETURN_ON_EXCEPTION(
     341             :       isolate_, value,
     342             :       Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object);
     343     4967931 :   return scope.CloseAndEscape(value);
     344             : }
     345             : 
     346     4967931 : Handle<JSReceiver> JsonStringifier::CurrentHolder(
     347       13648 :     Handle<Object> value, Handle<Object> initial_holder) {
     348     4967931 :   int length = Smi::ToInt(stack_->length());
     349     4967931 :   if (length == 0) {
     350             :     Handle<JSObject> holder =
     351       13648 :         factory()->NewJSObject(isolate_->object_function());
     352             :     JSObject::AddProperty(isolate_, holder, factory()->empty_string(),
     353        6824 :                           initial_holder, NONE);
     354        6824 :     return holder;
     355             :   } else {
     356     9922214 :     FixedArray elements = FixedArray::cast(stack_->elements());
     357             :     return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)),
     358     9922214 :                               isolate_);
     359             :   }
     360             : }
     361             : 
     362      434554 : JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) {
     363      434491 :   StackLimitCheck check(isolate_);
     364      434491 :   if (check.HasOverflowed()) {
     365          21 :     isolate_->StackOverflow();
     366          21 :     return EXCEPTION;
     367             :   }
     368             : 
     369      434470 :   int length = Smi::ToInt(stack_->length());
     370             :   {
     371             :     DisallowHeapAllocation no_allocation;
     372      868940 :     FixedArray elements = FixedArray::cast(stack_->elements());
     373      701642 :     for (int i = 0; i < length; i++) {
     374      267235 :       if (elements->get(i) == *object) {
     375             :         AllowHeapAllocation allow_to_return_error;
     376             :         Handle<Object> error =
     377          63 :             factory()->NewTypeError(MessageTemplate::kCircularStructure);
     378          63 :         isolate_->Throw(*error);
     379             :         return EXCEPTION;
     380             :       }
     381             :     }
     382             :   }
     383      434407 :   JSArray::SetLength(stack_, length + 1);
     384      868814 :   FixedArray::cast(stack_->elements())->set(length, *object);
     385      434407 :   return SUCCESS;
     386             : }
     387             : 
     388      432821 : void JsonStringifier::StackPop() {
     389      432821 :   int length = Smi::ToInt(stack_->length());
     390     1298463 :   stack_->set_length(Smi::FromInt(length - 1));
     391      432821 : }
     392             : 
     393             : template <bool deferred_string_key>
     394    12124853 : JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
     395             :                                                     bool comma,
     396             :                                                     Handle<Object> key) {
     397    12124853 :   StackLimitCheck interrupt_check(isolate_);
     398    12124853 :   Handle<Object> initial_value = object;
     399    36374559 :   if (interrupt_check.InterruptRequested() &&
     400    12125569 :       isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) {
     401             :     return EXCEPTION;
     402             :   }
     403    47623538 :   if (object->IsJSReceiver() || object->IsBigInt()) {
     404      876000 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     405             :         isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION);
     406             :   }
     407    12124791 :   if (!replacer_function_.is_null()) {
     408     9935862 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     409             :         isolate_, object, ApplyReplacerFunction(object, key, initial_value),
     410             :         EXCEPTION);
     411             :   }
     412             : 
     413    24249582 :   if (object->IsSmi()) {
     414             :     if (deferred_string_key) SerializeDeferredKey(comma, key);
     415      241903 :     return SerializeSmi(Smi::cast(*object));
     416             :   }
     417             : 
     418    11882888 :   switch (HeapObject::cast(*object)->map()->instance_type()) {
     419             :     case HEAP_NUMBER_TYPE:
     420             :     case MUTABLE_HEAP_NUMBER_TYPE:
     421             :       if (deferred_string_key) SerializeDeferredKey(comma, key);
     422        3532 :       return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
     423             :     case BIGINT_TYPE:
     424          36 :       isolate_->Throw(
     425         108 :           *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
     426          36 :       return EXCEPTION;
     427             :     case ODDBALL_TYPE:
     428     9701992 :       switch (Oddball::cast(*object)->kind()) {
     429             :         case Oddball::kFalse:
     430             :           if (deferred_string_key) SerializeDeferredKey(comma, key);
     431          81 :           builder_.AppendCString("false");
     432             :           return SUCCESS;
     433             :         case Oddball::kTrue:
     434             :           if (deferred_string_key) SerializeDeferredKey(comma, key);
     435         153 :           builder_.AppendCString("true");
     436             :           return SUCCESS;
     437             :         case Oddball::kNull:
     438             :           if (deferred_string_key) SerializeDeferredKey(comma, key);
     439         190 :           builder_.AppendCString("null");
     440             :           return SUCCESS;
     441             :         default:
     442             :           return UNCHANGED;
     443             :       }
     444             :     case JS_ARRAY_TYPE:
     445             :       if (deferred_string_key) SerializeDeferredKey(comma, key);
     446       22522 :       return SerializeJSArray(Handle<JSArray>::cast(object));
     447             :     case JS_VALUE_TYPE:
     448             :       if (deferred_string_key) SerializeDeferredKey(comma, key);
     449         702 :       return SerializeJSValue(Handle<JSValue>::cast(object));
     450             :     case SYMBOL_TYPE:
     451             :       return UNCHANGED;
     452             :     default:
     453     4334190 :       if (object->IsString()) {
     454             :         if (deferred_string_key) SerializeDeferredKey(comma, key);
     455     1741678 :         SerializeString(Handle<String>::cast(object));
     456     1741678 :         return SUCCESS;
     457             :       } else {
     458             :         DCHECK(object->IsJSReceiver());
     459      850834 :         if (object->IsCallable()) return UNCHANGED;
     460             :         // Go to slow path for global proxy and objects requiring access checks.
     461             :         if (deferred_string_key) SerializeDeferredKey(comma, key);
     462      846244 :         if (object->IsJSProxy()) {
     463         405 :           return SerializeJSProxy(Handle<JSProxy>::cast(object));
     464             :         }
     465      845434 :         return SerializeJSObject(Handle<JSObject>::cast(object));
     466             :       }
     467             :   }
     468             : 
     469             :   UNREACHABLE();
     470             : }
     471             : 
     472         702 : JsonStringifier::Result JsonStringifier::SerializeJSValue(
     473          54 :     Handle<JSValue> object) {
     474         702 :   Object raw = object->value();
     475         702 :   if (raw->IsString()) {
     476             :     Handle<Object> value;
     477         522 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     478             :         isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
     479         261 :     SerializeString(Handle<String>::cast(value));
     480         441 :   } else if (raw->IsNumber()) {
     481             :     Handle<Object> value;
     482         450 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     483             :         isolate_, value, Object::ToNumber(isolate_, object), EXCEPTION);
     484         639 :     if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
     485          36 :     SerializeHeapNumber(Handle<HeapNumber>::cast(value));
     486         216 :   } else if (raw->IsBigInt()) {
     487             :     isolate_->Throw(
     488         108 :         *factory()->NewTypeError(MessageTemplate::kBigIntSerializeJSON));
     489          54 :     return EXCEPTION;
     490         162 :   } else if (raw->IsBoolean()) {
     491         108 :     builder_.AppendCString(raw->IsTrue(isolate_) ? "true" : "false");
     492             :   } else {
     493             :     // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
     494             :     return SerializeJSObject(object);
     495             :   }
     496             :   return SUCCESS;
     497             : }
     498             : 
     499      247860 : JsonStringifier::Result JsonStringifier::SerializeSmi(Smi object) {
     500             :   static const int kBufferSize = 100;
     501             :   char chars[kBufferSize];
     502             :   Vector<char> buffer(chars, kBufferSize);
     503      247860 :   builder_.AppendCString(IntToCString(object->value(), buffer));
     504      247860 :   return SUCCESS;
     505             : }
     506             : 
     507        2458 : JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
     508        2458 :   if (std::isinf(number) || std::isnan(number)) {
     509         162 :     builder_.AppendCString("null");
     510             :     return SUCCESS;
     511             :   }
     512             :   static const int kBufferSize = 100;
     513             :   char chars[kBufferSize];
     514             :   Vector<char> buffer(chars, kBufferSize);
     515        2296 :   builder_.AppendCString(DoubleToCString(number, buffer));
     516             :   return SUCCESS;
     517             : }
     518             : 
     519             : JsonStringifier::Result JsonStringifier::SerializeJSArray(
     520             :     Handle<JSArray> object) {
     521       11261 :   HandleScope handle_scope(isolate_);
     522       11261 :   Result stack_push = StackPush(object);
     523       11261 :   if (stack_push != SUCCESS) return stack_push;
     524       11216 :   uint32_t length = 0;
     525       11216 :   CHECK(object->length()->ToArrayLength(&length));
     526             :   DCHECK(!object->IsAccessCheckNeeded());
     527        4192 :   builder_.AppendCharacter('[');
     528             :   Indent();
     529             :   uint32_t i = 0;
     530       11216 :   if (replacer_function_.is_null()) {
     531        7040 :     switch (object->GetElementsKind()) {
     532             :       case PACKED_SMI_ELEMENTS: {
     533        2272 :         Handle<FixedArray> elements(FixedArray::cast(object->elements()),
     534        3408 :                                     isolate_);
     535        1136 :         StackLimitCheck interrupt_check(isolate_);
     536        6904 :         while (i < length) {
     537       11536 :           if (interrupt_check.InterruptRequested() &&
     538           0 :               isolate_->stack_guard()->HandleInterrupts()->IsException(
     539        5768 :                   isolate_)) {
     540           0 :             return EXCEPTION;
     541             :           }
     542             :           Separator(i == 0);
     543       17304 :           SerializeSmi(Smi::cast(elements->get(i)));
     544        5768 :           i++;
     545             :         }
     546        1136 :         break;
     547             :       }
     548             :       case PACKED_DOUBLE_ELEMENTS: {
     549             :         // Empty array is FixedArray but not FixedDoubleArray.
     550         641 :         if (length == 0) break;
     551             :         Handle<FixedDoubleArray> elements(
     552        1896 :             FixedDoubleArray::cast(object->elements()), isolate_);
     553         632 :         StackLimitCheck interrupt_check(isolate_);
     554        1288 :         while (i < length) {
     555        1312 :           if (interrupt_check.InterruptRequested() &&
     556           0 :               isolate_->stack_guard()->HandleInterrupts()->IsException(
     557         656 :                   isolate_)) {
     558           0 :             return EXCEPTION;
     559             :           }
     560             :           Separator(i == 0);
     561        1312 :           SerializeDouble(elements->get_scalar(i));
     562         656 :           i++;
     563             :         }
     564             :         break;
     565             :       }
     566             :       case PACKED_ELEMENTS: {
     567       14190 :         Handle<Object> old_length(object->length(), isolate_);
     568      374628 :         while (i < length) {
     569     1112838 :           if (object->length() != *old_length ||
     570      741877 :               object->GetElementsKind() != PACKED_ELEMENTS) {
     571             :             // Fall back to slow path.
     572             :             break;
     573             :           }
     574             :           Separator(i == 0);
     575             :           Result result = SerializeElement(
     576             :               isolate_,
     577      741796 :               Handle<Object>(FixedArray::cast(object->elements())->get(i),
     578             :                              isolate_),
     579     1483592 :               i);
     580      370898 :           if (result == UNCHANGED) {
     581             :             builder_.AppendCString("null");
     582      370727 :           } else if (result != SUCCESS) {
     583             :             return result;
     584             :           }
     585      369898 :           i++;
     586             :         }
     587             :         break;
     588             :       }
     589             :       // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
     590             :       // the non-holey cases except that a lookup is necessary for holes.
     591             :       default:
     592             :         break;
     593             :     }
     594             :   }
     595       10216 :   if (i < length) {
     596             :     // Slow path for non-fast elements and fall-back in edge case.
     597        4118 :     Result result = SerializeArrayLikeSlow(object, i, length);
     598        4118 :     if (result != SUCCESS) return result;
     599             :   }
     600             :   Unindent();
     601       10175 :   if (length > 0) NewLine();
     602             :   builder_.AppendCharacter(']');
     603       10175 :   StackPop();
     604       11261 :   return SUCCESS;
     605             : }
     606             : 
     607        4154 : JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
     608             :     Handle<JSReceiver> object, uint32_t start, uint32_t length) {
     609             :   // We need to write out at least two characters per array element.
     610             :   static const int kMaxSerializableArrayLength = String::kMaxLength / 2;
     611        4154 :   if (length > kMaxSerializableArrayLength) {
     612          10 :     isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
     613           5 :     return EXCEPTION;
     614             :   }
     615     9656205 :   for (uint32_t i = start; i < length; i++) {
     616             :     Separator(i == 0);
     617             :     Handle<Object> element;
     618    19312482 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     619             :         isolate_, element, JSReceiver::GetElement(isolate_, object, i),
     620             :         EXCEPTION);
     621     9656232 :     Result result = SerializeElement(isolate_, element, i);
     622     9656232 :     if (result == SUCCESS) continue;
     623     9467424 :     if (result == UNCHANGED) {
     624             :       // Detect overflow sooner for large sparse arrays.
     625     9467397 :       if (builder_.HasOverflowed()) return EXCEPTION;
     626     9467397 :       builder_.AppendCString("null");
     627             :     } else {
     628             :       return result;
     629             :     }
     630             :   }
     631             :   return SUCCESS;
     632             : }
     633             : 
     634             : JsonStringifier::Result JsonStringifier::SerializeJSObject(
     635             :     Handle<JSObject> object) {
     636      422825 :   HandleScope handle_scope(isolate_);
     637      422825 :   Result stack_push = StackPush(object);
     638      422825 :   if (stack_push != SUCCESS) return stack_push;
     639             : 
     640      845302 :   if (property_list_.is_null() &&
     641     1267636 :       !object->map()->IsCustomElementsReceiverMap() &&
     642     1267152 :       object->HasFastProperties() && object->elements()->length() == 0) {
     643             :     DCHECK(!object->IsJSGlobalProxy());
     644             :     DCHECK(!object->HasIndexedInterceptor());
     645             :     DCHECK(!object->HasNamedInterceptor());
     646     1265589 :     Handle<Map> map(object->map(), isolate_);
     647      283067 :     builder_.AppendCharacter('{');
     648             :     Indent();
     649             :     bool comma = false;
     650     2327119 :     for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
     651     2859330 :       Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
     652             :       // TODO(rossberg): Should this throw?
     653     1906364 :       if (!name->IsString()) continue;
     654      953110 :       Handle<String> key = Handle<String>::cast(name);
     655      953110 :       PropertyDetails details = map->instance_descriptors()->GetDetails(i);
     656      953110 :       if (details.IsDontEnum()) continue;
     657             :       Handle<Object> property;
     658     2857872 :       if (details.location() == kField && *map == object->map()) {
     659             :         DCHECK_EQ(kData, details.kind());
     660      952417 :         FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
     661             :         property = JSObject::FastPropertyAt(object, details.representation(),
     662      952417 :                                             field_index);
     663             :       } else {
     664        1580 :         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     665             :             isolate_, property,
     666             :             Object::GetPropertyOrElement(isolate_, object, key), EXCEPTION);
     667             :       }
     668             :       Result result = SerializeProperty(property, comma, key);
     669      952966 :       if (!comma && result == SUCCESS) comma = true;
     670      952966 :       if (result == EXCEPTION) return result;
     671             :     }
     672             :     Unindent();
     673      421381 :     if (comma) NewLine();
     674             :     builder_.AppendCharacter('}');
     675             :   } else {
     676         923 :     Result result = SerializeJSReceiverSlow(object);
     677         923 :     if (result != SUCCESS) return result;
     678             :   }
     679      422259 :   StackPop();
     680      422825 :   return SUCCESS;
     681             : }
     682             : 
     683        1274 : JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
     684             :     Handle<JSReceiver> object) {
     685        1274 :   Handle<FixedArray> contents = property_list_;
     686        1274 :   if (contents.is_null()) {
     687        2008 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     688             :         isolate_, contents,
     689             :         KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
     690             :                                 ENUMERABLE_STRINGS,
     691             :                                 GetKeysConversion::kConvertToString),
     692             :         EXCEPTION);
     693             :   }
     694        1256 :   builder_.AppendCharacter('{');
     695             :   Indent();
     696             :   bool comma = false;
     697       10466 :   for (int i = 0; i < contents->length(); i++) {
     698        4004 :     Handle<String> key(String::cast(contents->get(i)), isolate_);
     699             :     Handle<Object> property;
     700        8008 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     701             :         isolate_, property, Object::GetPropertyOrElement(isolate_, object, key),
     702             :         EXCEPTION);
     703             :     Result result = SerializeProperty(property, comma, key);
     704        4004 :     if (!comma && result == SUCCESS) comma = true;
     705        4004 :     if (result == EXCEPTION) return result;
     706             :   }
     707             :   Unindent();
     708        1229 :   if (comma) NewLine();
     709             :   builder_.AppendCharacter('}');
     710             :   return SUCCESS;
     711             : }
     712             : 
     713         405 : JsonStringifier::Result JsonStringifier::SerializeJSProxy(
     714             :     Handle<JSProxy> object) {
     715         405 :   HandleScope scope(isolate_);
     716         405 :   Result stack_push = StackPush(object);
     717         405 :   if (stack_push != SUCCESS) return stack_push;
     718             :   Maybe<bool> is_array = Object::IsArray(object);
     719         405 :   if (is_array.IsNothing()) return EXCEPTION;
     720         405 :   if (is_array.FromJust()) {
     721             :     Handle<Object> length_object;
     722         126 :     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     723             :         isolate_, length_object,
     724             :         Object::GetLengthFromArrayLike(isolate_,
     725             :                                        Handle<JSReceiver>::cast(object)),
     726             :         EXCEPTION);
     727             :     uint32_t length;
     728          45 :     if (!length_object->ToUint32(&length)) {
     729             :       // Technically, we need to be able to handle lengths outside the
     730             :       // uint32_t range. However, we would run into string size overflow
     731             :       // if we tried to stringify such an array.
     732          18 :       isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
     733           9 :       return EXCEPTION;
     734             :     }
     735          36 :     builder_.AppendCharacter('[');
     736             :     Indent();
     737          72 :     Result result = SerializeArrayLikeSlow(object, 0, length);
     738          36 :     if (result != SUCCESS) return result;
     739             :     Unindent();
     740          36 :     if (length > 0) NewLine();
     741             :     builder_.AppendCharacter(']');
     742             :   } else {
     743         351 :     Result result = SerializeJSReceiverSlow(object);
     744         351 :     if (result != SUCCESS) return result;
     745             :   }
     746         387 :   StackPop();
     747         387 :   return SUCCESS;
     748             : }
     749             : 
     750             : template <typename SrcChar, typename DestChar>
     751             : void JsonStringifier::SerializeStringUnchecked_(
     752             :     Vector<const SrcChar> src,
     753             :     IncrementalStringBuilder::NoExtend<DestChar>* dest) {
     754             :   // Assert that uc16 character is not truncated down to 8 bit.
     755             :   // The <uc16, char> version of this method must not be called.
     756             :   DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
     757    44003929 :   for (int i = 0; i < src.length(); i++) {
     758    44003929 :     SrcChar c = src[i];
     759    44003929 :     if (DoNotEscape(c)) {
     760             :       dest->Append(c);
     761       57117 :     } else if (FLAG_harmony_json_stringify && c >= 0xD800 && c <= 0xDFFF) {
     762             :       // The current character is a surrogate.
     763       57108 :       if (c <= 0xDBFF) {
     764             :         // The current character is a leading surrogate.
     765       29430 :         if (i + 1 < src.length()) {
     766             :           // There is a next character.
     767        1752 :           SrcChar next = src[i + 1];
     768        1752 :           if (next >= 0xDC00 && next <= 0xDFFF) {
     769             :             // The next character is a trailing surrogate, meaning this is a
     770             :             // surrogate pair.
     771             :             dest->Append(c);
     772             :             dest->Append(next);
     773             :             i++;
     774             :           } else {
     775             :             // The next character is not a trailing surrogate. Thus, the
     776             :             // current character is a lone leading surrogate.
     777             :             dest->AppendCString("\\u");
     778           0 :             char* const hex = DoubleToRadixCString(c, 16);
     779             :             dest->AppendCString(hex);
     780           0 :             DeleteArray(hex);
     781             :           }
     782             :         } else {
     783             :           // There is no next character. Thus, the current character is a lone
     784             :           // leading surrogate.
     785             :           dest->AppendCString("\\u");
     786       27678 :           char* const hex = DoubleToRadixCString(c, 16);
     787             :           dest->AppendCString(hex);
     788       27678 :           DeleteArray(hex);
     789             :         }
     790             :       } else {
     791             :         // The current character is a lone trailing surrogate. (If it had been
     792             :         // preceded by a leading surrogate, we would've ended up in the other
     793             :         // branch earlier on, and the current character would've been handled
     794             :         // as part of the surrogate pair already.)
     795             :         dest->AppendCString("\\u");
     796       27678 :         char* const hex = DoubleToRadixCString(c, 16);
     797             :         dest->AppendCString(hex);
     798       27678 :         DeleteArray(hex);
     799             :       }
     800             :     } else {
     801        5933 :       dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
     802             :     }
     803             :   }
     804             : }
     805             : 
     806             : template <typename SrcChar, typename DestChar>
     807             : void JsonStringifier::SerializeString_(Handle<String> string) {
     808     2652446 :   int length = string->length();
     809     2652446 :   builder_.Append<uint8_t, DestChar>('"');
     810             :   // We might be able to fit the whole escaped string in the current string
     811             :   // part, or we might need to allocate.
     812     2652446 :   if (int worst_case_length = builder_.EscapedLengthIfCurrentPartFits(length)) {
     813             :     DisallowHeapAllocation no_gc;
     814     2902058 :     Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(no_gc);
     815             :     IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
     816     1451029 :         &builder_, worst_case_length, no_gc);
     817     1451029 :     SerializeStringUnchecked_(vector, &no_extend);
     818             :   } else {
     819     1201417 :     FlatStringReader reader(isolate_, string);
     820  2441918991 :     for (int i = 0; i < reader.length(); i++) {
     821  2441918991 :       SrcChar c = reader.Get<SrcChar>(i);
     822  2441918991 :       if (DoNotEscape(c)) {
     823             :         builder_.Append<SrcChar, DestChar>(c);
     824         450 :       } else if (FLAG_harmony_json_stringify && c >= 0xD800 && c <= 0xDFFF) {
     825             :         // The current character is a surrogate.
     826           0 :         if (c <= 0xDBFF) {
     827             :           // The current character is a leading surrogate.
     828           0 :           if (i + 1 < reader.length()) {
     829             :             // There is a next character.
     830           0 :             SrcChar next = reader.Get<SrcChar>(i + 1);
     831           0 :             if (next >= 0xDC00 && next <= 0xDFFF) {
     832             :               // The next character is a trailing surrogate, meaning this is a
     833             :               // surrogate pair.
     834             :               builder_.Append<SrcChar, DestChar>(c);
     835             :               builder_.Append<SrcChar, DestChar>(next);
     836             :               i++;
     837             :             } else {
     838             :               // The next character is not a trailing surrogate. Thus, the
     839             :               // current character is a lone leading surrogate.
     840             :               builder_.AppendCString("\\u");
     841           0 :               char* const hex = DoubleToRadixCString(c, 16);
     842             :               builder_.AppendCString(hex);
     843           0 :               DeleteArray(hex);
     844             :             }
     845             :           } else {
     846             :             // There is no next character. Thus, the current character is a
     847             :             // lone leading surrogate.
     848             :             builder_.AppendCString("\\u");
     849           0 :             char* const hex = DoubleToRadixCString(c, 16);
     850             :             builder_.AppendCString(hex);
     851           0 :             DeleteArray(hex);
     852             :           }
     853             :         } else {
     854             :           // The current character is a lone trailing surrogate. (If it had
     855             :           // been preceded by a leading surrogate, we would've ended up in the
     856             :           // other branch earlier on, and the current character would've been
     857             :           // handled as part of the surrogate pair already.)
     858             :           builder_.AppendCString("\\u");
     859           0 :           char* const hex = DoubleToRadixCString(c, 16);
     860             :           builder_.AppendCString(hex);
     861           0 :           DeleteArray(hex);
     862             :         }
     863             :       } else {
     864     9842215 :         builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
     865             :       }
     866     1201417 :     }
     867             :   }
     868             :   builder_.Append<uint8_t, DestChar>('"');
     869             : }
     870             : 
     871             : template <>
     872  2484787242 : bool JsonStringifier::DoNotEscape(uint8_t c) {
     873             :   // https://tc39.github.io/ecma262/#table-json-single-character-escapes
     874  2484787242 :   return c >= 0x23 && c <= 0x7E && c != 0x5C;
     875             : }
     876             : 
     877             : template <>
     878     1135678 : bool JsonStringifier::DoNotEscape(uint16_t c) {
     879             :   // https://tc39.github.io/ecma262/#table-json-single-character-escapes
     880     2270897 :   return c >= 0x23 && c != 0x5C && c != 0x7F &&
     881     2270438 :          (!FLAG_harmony_json_stringify || (c < 0xD800 || c > 0xDFFF));
     882             : }
     883             : 
     884             : void JsonStringifier::NewLine() {
     885    11363111 :   if (gap_ == nullptr) return;
     886     4810404 :   builder_.AppendCharacter('\n');
     887     9804272 :   for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
     888             : }
     889             : 
     890             : void JsonStringifier::Separator(bool first) {
     891    10944070 :   if (!first) builder_.AppendCharacter(',');
     892             :   NewLine();
     893             : }
     894             : 
     895             : void JsonStringifier::SerializeDeferredKey(bool deferred_comma,
     896             :                                            Handle<Object> deferred_key) {
     897             :   Separator(!deferred_comma);
     898      910507 :   SerializeString(Handle<String>::cast(deferred_key));
     899      910507 :   builder_.AppendCharacter(':');
     900      910507 :   if (gap_ != nullptr) builder_.AppendCharacter(' ');
     901             : }
     902             : 
     903     3371560 : void JsonStringifier::SerializeString(Handle<String> object) {
     904     3371560 :   object = String::Flatten(isolate_, object);
     905     3371560 :   if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
     906     2652393 :     if (String::IsOneByteRepresentationUnderneath(*object)) {
     907             :       SerializeString_<uint8_t, uint8_t>(object);
     908             :     } else {
     909      719114 :       builder_.ChangeEncoding();
     910      719114 :       SerializeString(object);
     911             :     }
     912             :   } else {
     913      719167 :     if (String::IsOneByteRepresentationUnderneath(*object)) {
     914             :       SerializeString_<uint8_t, uc16>(object);
     915             :     } else {
     916             :       SerializeString_<uc16, uc16>(object);
     917             :     }
     918             :   }
     919     3371560 : }
     920             : 
     921             : }  // namespace internal
     922      183867 : }  // namespace v8

Generated by: LCOV version 1.10