json-stringifier.cc 25.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/json-stringifier.h"

#include "src/conversions.h"
#include "src/lookup.h"
#include "src/messages.h"
#include "src/objects-inl.h"
#include "src/utils.h"

namespace v8 {
namespace internal {

// Translation table to escape Latin1 characters.
// Table entries start at a multiple of 8 and are null-terminated.
18
const char* const JsonStringifier::JsonEscapeTable =
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
    "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
    "\\b\0     \\t\0     \\n\0     \\u000b\0 "
    "\\f\0     \\r\0     \\u000e\0 \\u000f\0 "
    "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
    "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
    "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
    "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
    " \0      !\0      \\\"\0     #\0      "
    "$\0      %\0      &\0      '\0      "
    "(\0      )\0      *\0      +\0      "
    ",\0      -\0      .\0      /\0      "
    "0\0      1\0      2\0      3\0      "
    "4\0      5\0      6\0      7\0      "
    "8\0      9\0      :\0      ;\0      "
    "<\0      =\0      >\0      ?\0      "
    "@\0      A\0      B\0      C\0      "
    "D\0      E\0      F\0      G\0      "
    "H\0      I\0      J\0      K\0      "
    "L\0      M\0      N\0      O\0      "
    "P\0      Q\0      R\0      S\0      "
    "T\0      U\0      V\0      W\0      "
    "X\0      Y\0      Z\0      [\0      "
    "\\\\\0     ]\0      ^\0      _\0      "
    "`\0      a\0      b\0      c\0      "
    "d\0      e\0      f\0      g\0      "
    "h\0      i\0      j\0      k\0      "
    "l\0      m\0      n\0      o\0      "
    "p\0      q\0      r\0      s\0      "
    "t\0      u\0      v\0      w\0      "
    "x\0      y\0      z\0      {\0      "
    "|\0      }\0      ~\0      \177\0      "
    "\200\0      \201\0      \202\0      \203\0      "
    "\204\0      \205\0      \206\0      \207\0      "
    "\210\0      \211\0      \212\0      \213\0      "
    "\214\0      \215\0      \216\0      \217\0      "
    "\220\0      \221\0      \222\0      \223\0      "
    "\224\0      \225\0      \226\0      \227\0      "
    "\230\0      \231\0      \232\0      \233\0      "
    "\234\0      \235\0      \236\0      \237\0      "
    "\240\0      \241\0      \242\0      \243\0      "
    "\244\0      \245\0      \246\0      \247\0      "
    "\250\0      \251\0      \252\0      \253\0      "
    "\254\0      \255\0      \256\0      \257\0      "
    "\260\0      \261\0      \262\0      \263\0      "
    "\264\0      \265\0      \266\0      \267\0      "
    "\270\0      \271\0      \272\0      \273\0      "
    "\274\0      \275\0      \276\0      \277\0      "
    "\300\0      \301\0      \302\0      \303\0      "
    "\304\0      \305\0      \306\0      \307\0      "
    "\310\0      \311\0      \312\0      \313\0      "
    "\314\0      \315\0      \316\0      \317\0      "
    "\320\0      \321\0      \322\0      \323\0      "
    "\324\0      \325\0      \326\0      \327\0      "
    "\330\0      \331\0      \332\0      \333\0      "
    "\334\0      \335\0      \336\0      \337\0      "
    "\340\0      \341\0      \342\0      \343\0      "
    "\344\0      \345\0      \346\0      \347\0      "
    "\350\0      \351\0      \352\0      \353\0      "
    "\354\0      \355\0      \356\0      \357\0      "
    "\360\0      \361\0      \362\0      \363\0      "
    "\364\0      \365\0      \366\0      \367\0      "
    "\370\0      \371\0      \372\0      \373\0      "
    "\374\0      \375\0      \376\0      \377\0      ";

84
JsonStringifier::JsonStringifier(Isolate* isolate)
85
    : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) {
86 87 88 89
  tojson_string_ = factory()->toJSON_string();
  stack_ = factory()->NewJSArray(8);
}

90 91 92
MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object,
                                               Handle<Object> replacer,
                                               Handle<Object> gap) {
93
  if (!InitializeReplacer(replacer)) return MaybeHandle<Object>();
94 95 96
  if (!gap->IsUndefined(isolate_) && !InitializeGap(gap)) {
    return MaybeHandle<Object>();
  }
97 98 99 100 101 102 103
  Result result = SerializeObject(object);
  if (result == UNCHANGED) return factory()->undefined_value();
  if (result == SUCCESS) return builder_.Finish();
  DCHECK(result == EXCEPTION);
  return MaybeHandle<Object>();
}

104
bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
105
  DCHECK(property_list_.is_null());
106
  DCHECK(replacer_function_.is_null());
107 108 109 110
  Maybe<bool> is_array = Object::IsArray(replacer);
  if (is_array.IsNothing()) return false;
  if (is_array.FromJust()) {
    HandleScope handle_scope(isolate_);
111
    Handle<OrderedHashSet> set = factory()->NewOrderedHashSet();
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    Handle<Object> length_obj;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, length_obj,
        Object::GetLengthFromArrayLike(isolate_, replacer), false);
    uint32_t length;
    if (!length_obj->ToUint32(&length)) length = kMaxUInt32;
    for (uint32_t i = 0; i < length; i++) {
      Handle<Object> element;
      Handle<String> key;
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
          isolate_, element, Object::GetElement(isolate_, replacer, i), false);
      if (element->IsNumber() || element->IsString()) {
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate_, key, Object::ToString(isolate_, element), false);
      } else if (element->IsJSValue()) {
        Handle<Object> value(Handle<JSValue>::cast(element)->value(), isolate_);
        if (value->IsNumber() || value->IsString()) {
          ASSIGN_RETURN_ON_EXCEPTION_VALUE(
              isolate_, key, Object::ToString(isolate_, element), false);
        }
      }
      if (key.is_null()) continue;
134 135 136
      // Object keys are internalized, so do it here.
      key = factory()->InternalizeString(key);
      set = OrderedHashSet::Add(set, key);
137
    }
138 139
    property_list_ = OrderedHashSet::ConvertToKeysArray(
        set, GetKeysConversion::kKeepNumbers);
140
    property_list_ = handle_scope.CloseAndEscape(property_list_);
141 142
  } else if (replacer->IsCallable()) {
    replacer_function_ = Handle<JSReceiver>::cast(replacer);
143 144 145 146
  }
  return true;
}

147
bool JsonStringifier::InitializeGap(Handle<Object> gap) {
148 149
  DCHECK_NULL(gap_);
  HandleScope scope(isolate_);
150 151 152
  if (gap->IsJSValue()) {
    Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_);
    if (value->IsString()) {
153 154
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap,
                                       Object::ToString(isolate_, gap), false);
155
    } else if (value->IsNumber()) {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap),
                                       false);
    }
  }

  if (gap->IsString()) {
    Handle<String> gap_string = Handle<String>::cast(gap);
    if (gap_string->length() > 0) {
      int gap_length = std::min(gap_string->length(), 10);
      gap_ = NewArray<uc16>(gap_length + 1);
      String::WriteToFlat(*gap_string, gap_, 0, gap_length);
      for (int i = 0; i < gap_length; i++) {
        if (gap_[i] > String::kMaxOneByteCharCode) {
          builder_.ChangeEncoding();
          break;
        }
      }
      gap_[gap_length] = '\0';
    }
  } else if (gap->IsNumber()) {
    int num_value = DoubleToInt32(gap->Number());
    if (num_value > 0) {
      int gap_length = std::min(num_value, 10);
      gap_ = NewArray<uc16>(gap_length + 1);
      for (int i = 0; i < gap_length; i++) gap_[i] = ' ';
      gap_[gap_length] = '\0';
    }
  }
  return true;
}

187 188 189
MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object,
                                                         Handle<Object> key) {
  HandleScope scope(isolate_);
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
  LookupIterator it(object, tojson_string_,
                    LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
  Handle<Object> fun;
  ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
  if (!fun->IsCallable()) return object;

  // Call toJSON function.
  if (key->IsSmi()) key = factory()->NumberToString(key);
  Handle<Object> argv[] = {key};
  ASSIGN_RETURN_ON_EXCEPTION(isolate_, object,
                             Execution::Call(isolate_, fun, object, 1, argv),
                             Object);
  return scope.CloseAndEscape(object);
}

205
MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction(
206
    Handle<Object> value, Handle<Object> key, Handle<Object> initial_holder) {
207 208
  HandleScope scope(isolate_);
  if (key->IsSmi()) key = factory()->NumberToString(key);
209 210
  Handle<Object> argv[] = {key, value};
  Handle<JSReceiver> holder = CurrentHolder(value, initial_holder);
211
  ASSIGN_RETURN_ON_EXCEPTION(
212
      isolate_, value,
213
      Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object);
214
  return scope.CloseAndEscape(value);
215 216
}

217 218
Handle<JSReceiver> JsonStringifier::CurrentHolder(
    Handle<Object> value, Handle<Object> initial_holder) {
219 220 221 222
  int length = Smi::cast(stack_->length())->value();
  if (length == 0) {
    Handle<JSObject> holder =
        factory()->NewJSObject(isolate_->object_function());
223 224
    JSObject::AddProperty(holder, factory()->empty_string(), initial_holder,
                          NONE);
225 226 227 228 229 230 231 232 233
    return holder;
  } else {
    FixedArray* elements = FixedArray::cast(stack_->elements());
    return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)),
                              isolate_);
  }
}

JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) {
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
  StackLimitCheck check(isolate_);
  if (check.HasOverflowed()) {
    isolate_->StackOverflow();
    return EXCEPTION;
  }

  int length = Smi::cast(stack_->length())->value();
  {
    DisallowHeapAllocation no_allocation;
    FixedArray* elements = FixedArray::cast(stack_->elements());
    for (int i = 0; i < length; i++) {
      if (elements->get(i) == *object) {
        AllowHeapAllocation allow_to_return_error;
        Handle<Object> error =
            factory()->NewTypeError(MessageTemplate::kCircularStructure);
        isolate_->Throw(*error);
        return EXCEPTION;
      }
    }
  }
  JSArray::SetLength(stack_, length + 1);
  FixedArray::cast(stack_->elements())->set(length, *object);
  return SUCCESS;
}

259
void JsonStringifier::StackPop() {
260 261 262 263 264
  int length = Smi::cast(stack_->length())->value();
  stack_->set_length(Smi::FromInt(length - 1));
}

template <bool deferred_string_key>
265 266 267
JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
                                                    bool comma,
                                                    Handle<Object> key) {
268
  StackLimitCheck interrupt_check(isolate_);
269
  Handle<Object> initial_value = object;
270
  if (interrupt_check.InterruptRequested() &&
271
      isolate_->stack_guard()->HandleInterrupts()->IsException(isolate_)) {
272 273
    return EXCEPTION;
  }
274 275 276 277
  if (object->IsJSReceiver()) {
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION);
  }
278 279
  if (!replacer_function_.is_null()) {
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
280 281
        isolate_, object, ApplyReplacerFunction(object, key, initial_value),
        EXCEPTION);
282
  }
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

  if (object->IsSmi()) {
    if (deferred_string_key) SerializeDeferredKey(comma, key);
    return SerializeSmi(Smi::cast(*object));
  }

  switch (HeapObject::cast(*object)->map()->instance_type()) {
    case HEAP_NUMBER_TYPE:
    case MUTABLE_HEAP_NUMBER_TYPE:
      if (deferred_string_key) SerializeDeferredKey(comma, key);
      return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
    case ODDBALL_TYPE:
      switch (Oddball::cast(*object)->kind()) {
        case Oddball::kFalse:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
          builder_.AppendCString("false");
          return SUCCESS;
        case Oddball::kTrue:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
          builder_.AppendCString("true");
          return SUCCESS;
        case Oddball::kNull:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
          builder_.AppendCString("null");
          return SUCCESS;
        default:
          return UNCHANGED;
      }
    case JS_ARRAY_TYPE:
      if (deferred_string_key) SerializeDeferredKey(comma, key);
      return SerializeJSArray(Handle<JSArray>::cast(object));
    case JS_VALUE_TYPE:
      if (deferred_string_key) SerializeDeferredKey(comma, key);
      return SerializeJSValue(Handle<JSValue>::cast(object));
    case SYMBOL_TYPE:
      return UNCHANGED;
    default:
      if (object->IsString()) {
        if (deferred_string_key) SerializeDeferredKey(comma, key);
        SerializeString(Handle<String>::cast(object));
        return SUCCESS;
      } else {
        DCHECK(object->IsJSReceiver());
        if (object->IsCallable()) return UNCHANGED;
        // Go to slow path for global proxy and objects requiring access checks.
        if (deferred_string_key) SerializeDeferredKey(comma, key);
        if (object->IsJSProxy()) {
          return SerializeJSProxy(Handle<JSProxy>::cast(object));
        }
        return SerializeJSObject(Handle<JSObject>::cast(object));
      }
  }

  UNREACHABLE();
}

339
JsonStringifier::Result JsonStringifier::SerializeJSValue(
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
    Handle<JSValue> object) {
  String* class_name = object->class_name();
  if (class_name == isolate_->heap()->String_string()) {
    Handle<Object> value;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
    SerializeString(Handle<String>::cast(value));
  } else if (class_name == isolate_->heap()->Number_string()) {
    Handle<Object> value;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object),
                                     EXCEPTION);
    if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
    SerializeHeapNumber(Handle<HeapNumber>::cast(value));
  } else if (class_name == isolate_->heap()->Boolean_string()) {
    Object* value = JSValue::cast(*object)->value();
    DCHECK(value->IsBoolean());
356
    builder_.AppendCString(value->IsTrue(isolate_) ? "true" : "false");
357 358 359 360 361 362 363
  } else {
    // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject.
    return SerializeJSObject(object);
  }
  return SUCCESS;
}

364
JsonStringifier::Result JsonStringifier::SerializeSmi(Smi* object) {
365 366 367 368 369 370 371
  static const int kBufferSize = 100;
  char chars[kBufferSize];
  Vector<char> buffer(chars, kBufferSize);
  builder_.AppendCString(IntToCString(object->value(), buffer));
  return SUCCESS;
}

372
JsonStringifier::Result JsonStringifier::SerializeDouble(double number) {
373 374 375 376 377 378 379 380 381 382 383
  if (std::isinf(number) || std::isnan(number)) {
    builder_.AppendCString("null");
    return SUCCESS;
  }
  static const int kBufferSize = 100;
  char chars[kBufferSize];
  Vector<char> buffer(chars, kBufferSize);
  builder_.AppendCString(DoubleToCString(number, buffer));
  return SUCCESS;
}

384
JsonStringifier::Result JsonStringifier::SerializeJSArray(
385 386 387 388 389 390 391 392 393
    Handle<JSArray> object) {
  HandleScope handle_scope(isolate_);
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;
  uint32_t length = 0;
  CHECK(object->length()->ToArrayLength(&length));
  DCHECK(!object->IsAccessCheckNeeded());
  builder_.AppendCharacter('[');
  Indent();
394 395 396 397 398 399
  uint32_t i = 0;
  if (replacer_function_.is_null()) {
    switch (object->GetElementsKind()) {
      case FAST_SMI_ELEMENTS: {
        Handle<FixedArray> elements(FixedArray::cast(object->elements()),
                                    isolate_);
400
        StackLimitCheck interrupt_check(isolate_);
401
        while (i < length) {
402
          if (interrupt_check.InterruptRequested() &&
403 404
              isolate_->stack_guard()->HandleInterrupts()->IsException(
                  isolate_)) {
405 406
            return EXCEPTION;
          }
407 408 409 410 411
          Separator(i == 0);
          SerializeSmi(Smi::cast(elements->get(i)));
          i++;
        }
        break;
412
      }
413 414 415 416 417
      case FAST_DOUBLE_ELEMENTS: {
        // Empty array is FixedArray but not FixedDoubleArray.
        if (length == 0) break;
        Handle<FixedDoubleArray> elements(
            FixedDoubleArray::cast(object->elements()), isolate_);
418
        StackLimitCheck interrupt_check(isolate_);
419
        while (i < length) {
420
          if (interrupt_check.InterruptRequested() &&
421 422
              isolate_->stack_guard()->HandleInterrupts()->IsException(
                  isolate_)) {
423 424
            return EXCEPTION;
          }
425 426 427
          Separator(i == 0);
          SerializeDouble(elements->get_scalar(i));
          i++;
428
        }
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
        break;
      }
      case FAST_ELEMENTS: {
        Handle<Object> old_length(object->length(), isolate_);
        while (i < length) {
          if (object->length() != *old_length ||
              object->GetElementsKind() != FAST_ELEMENTS) {
            // Fall back to slow path.
            break;
          }
          Separator(i == 0);
          Result result = SerializeElement(
              isolate_,
              Handle<Object>(FixedArray::cast(object->elements())->get(i),
                             isolate_),
              i);
          if (result == UNCHANGED) {
            builder_.AppendCString("null");
          } else if (result != SUCCESS) {
            return result;
          }
          i++;
451
        }
452
        break;
453
      }
454 455 456 457
      // The FAST_HOLEY_* cases could be handled in a faster way. They resemble
      // the non-holey cases except that a lookup is necessary for holes.
      default:
        break;
458
    }
459
  }
460 461 462 463 464
  if (i < length) {
    // Slow path for non-fast elements and fall-back in edge case.
    Result result = SerializeArrayLikeSlow(object, i, length);
    if (result != SUCCESS) return result;
  }
465 466 467 468 469 470 471
  Unindent();
  if (length > 0) NewLine();
  builder_.AppendCharacter(']');
  StackPop();
  return SUCCESS;
}

472
JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow(
473
    Handle<JSReceiver> object, uint32_t start, uint32_t length) {
474 475 476 477 478 479
  // We need to write out at least two characters per array element.
  static const int kMaxSerializableArrayLength = String::kMaxLength / 2;
  if (length > kMaxSerializableArrayLength) {
    isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
    return EXCEPTION;
  }
480 481 482 483 484 485
  for (uint32_t i = start; i < length; i++) {
    Separator(i == 0);
    Handle<Object> element;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, element, JSReceiver::GetElement(isolate_, object, i),
        EXCEPTION);
486 487 488
    Result result = SerializeElement(isolate_, element, i);
    if (result == SUCCESS) continue;
    if (result == UNCHANGED) {
489 490
      // Detect overflow sooner for large sparse arrays.
      if (builder_.HasOverflowed()) return EXCEPTION;
491 492
      builder_.AppendCString("null");
    } else {
493
      return result;
494 495 496 497 498
    }
  }
  return SUCCESS;
}

499
JsonStringifier::Result JsonStringifier::SerializeJSObject(
500 501 502 503 504
    Handle<JSObject> object) {
  HandleScope handle_scope(isolate_);
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;

505 506
  if (property_list_.is_null() &&
      object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
      object->HasFastProperties() &&
      Handle<JSObject>::cast(object)->elements()->length() == 0) {
    DCHECK(object->IsJSObject());
    DCHECK(!object->IsJSGlobalProxy());
    Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
    DCHECK(!js_obj->HasIndexedInterceptor());
    DCHECK(!js_obj->HasNamedInterceptor());
    Handle<Map> map(js_obj->map());
    builder_.AppendCharacter('{');
    Indent();
    bool comma = false;
    for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
      Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
      // TODO(rossberg): Should this throw?
      if (!name->IsString()) continue;
      Handle<String> key = Handle<String>::cast(name);
      PropertyDetails details = map->instance_descriptors()->GetDetails(i);
      if (details.IsDontEnum()) continue;
      Handle<Object> property;
526 527
      if (details.location() == kField && *map == js_obj->map()) {
        DCHECK_EQ(kData, details.kind());
528
        FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
529 530
        property = JSObject::FastPropertyAt(js_obj, details.representation(),
                                            field_index);
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
      } else {
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate_, property, Object::GetPropertyOrElement(js_obj, key),
            EXCEPTION);
      }
      Result result = SerializeProperty(property, comma, key);
      if (!comma && result == SUCCESS) comma = true;
      if (result == EXCEPTION) return result;
    }
    Unindent();
    if (comma) NewLine();
    builder_.AppendCharacter('}');
  } else {
    Result result = SerializeJSReceiverSlow(object);
    if (result != SUCCESS) return result;
  }
  StackPop();
  return SUCCESS;
}

551
JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow(
552
    Handle<JSReceiver> object) {
553 554 555 556
  Handle<FixedArray> contents = property_list_;
  if (contents.is_null()) {
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, contents,
557
        KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
558 559
                                ENUMERABLE_STRINGS,
                                GetKeysConversion::kConvertToString),
560
        EXCEPTION);
561
  }
562 563 564 565
  builder_.AppendCharacter('{');
  Indent();
  bool comma = false;
  for (int i = 0; i < contents->length(); i++) {
566
    Handle<String> key(String::cast(contents->get(i)), isolate_);
567
    Handle<Object> property;
568 569
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, property,
                                     Object::GetPropertyOrElement(object, key),
570
                                     EXCEPTION);
571
    Result result = SerializeProperty(property, comma, key);
572 573 574 575 576 577 578 579 580
    if (!comma && result == SUCCESS) comma = true;
    if (result == EXCEPTION) return result;
  }
  Unindent();
  if (comma) NewLine();
  builder_.AppendCharacter('}');
  return SUCCESS;
}

581
JsonStringifier::Result JsonStringifier::SerializeJSProxy(
582
    Handle<JSProxy> object) {
583
  HandleScope scope(isolate_);
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;
  Maybe<bool> is_array = Object::IsArray(object);
  if (is_array.IsNothing()) return EXCEPTION;
  if (is_array.FromJust()) {
    Handle<Object> length_object;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, length_object,
        Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION);
    uint32_t length;
    if (!length_object->ToUint32(&length)) {
      // Technically, we need to be able to handle lengths outside the
      // uint32_t range. However, we would run into string size overflow
      // if we tried to stringify such an array.
      isolate_->Throw(*isolate_->factory()->NewInvalidStringLengthError());
      return EXCEPTION;
    }
    builder_.AppendCharacter('[');
    Indent();
    Result result = SerializeArrayLikeSlow(object, 0, length);
    if (result != SUCCESS) return result;
    Unindent();
    if (length > 0) NewLine();
    builder_.AppendCharacter(']');
  } else {
    Result result = SerializeJSReceiverSlow(object);
    if (result != SUCCESS) return result;
  }
  StackPop();
  return SUCCESS;
}

template <typename SrcChar, typename DestChar>
617
void JsonStringifier::SerializeStringUnchecked_(
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
    Vector<const SrcChar> src,
    IncrementalStringBuilder::NoExtend<DestChar>* dest) {
  // Assert that uc16 character is not truncated down to 8 bit.
  // The <uc16, char> version of this method must not be called.
  DCHECK(sizeof(DestChar) >= sizeof(SrcChar));

  for (int i = 0; i < src.length(); i++) {
    SrcChar c = src[i];
    if (DoNotEscape(c)) {
      dest->Append(c);
    } else {
      dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
    }
  }
}

template <typename SrcChar, typename DestChar>
635
void JsonStringifier::SerializeString_(Handle<String> string) {
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
  int length = string->length();
  builder_.Append<uint8_t, DestChar>('"');
  // We make a rough estimate to find out if the current string can be
  // serialized without allocating a new string part. The worst case length of
  // an escaped character is 6.  Shifting the remainin string length right by 3
  // is a more pessimistic estimate, but faster to calculate.
  int worst_case_length = length << 3;
  if (builder_.CurrentPartCanFit(worst_case_length)) {
    DisallowHeapAllocation no_gc;
    Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
    IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
        &builder_, worst_case_length);
    SerializeStringUnchecked_(vector, &no_extend);
  } else {
    FlatStringReader reader(isolate_, string);
    for (int i = 0; i < reader.length(); i++) {
      SrcChar c = reader.Get<SrcChar>(i);
      if (DoNotEscape(c)) {
        builder_.Append<SrcChar, DestChar>(c);
      } else {
        builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
      }
    }
  }

  builder_.Append<uint8_t, DestChar>('"');
}

template <>
665
bool JsonStringifier::DoNotEscape(uint8_t c) {
666 667 668 669
  return c >= '#' && c <= '~' && c != '\\';
}

template <>
670
bool JsonStringifier::DoNotEscape(uint16_t c) {
671 672 673
  return c >= '#' && c != '\\' && c != 0x7f;
}

674
void JsonStringifier::NewLine() {
675 676 677 678 679
  if (gap_ == nullptr) return;
  builder_.AppendCharacter('\n');
  for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_);
}

680
void JsonStringifier::Separator(bool first) {
681 682 683 684
  if (!first) builder_.AppendCharacter(',');
  NewLine();
}

685 686
void JsonStringifier::SerializeDeferredKey(bool deferred_comma,
                                           Handle<Object> deferred_key) {
687 688 689 690 691 692
  Separator(!deferred_comma);
  SerializeString(Handle<String>::cast(deferred_key));
  builder_.AppendCharacter(':');
  if (gap_ != nullptr) builder_.AppendCharacter(' ');
}

693
void JsonStringifier::SerializeString(Handle<String> object) {
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
  object = String::Flatten(object);
  if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
    if (object->IsOneByteRepresentationUnderneath()) {
      SerializeString_<uint8_t, uint8_t>(object);
    } else {
      builder_.ChangeEncoding();
      SerializeString(object);
    }
  } else {
    if (object->IsOneByteRepresentationUnderneath()) {
      SerializeString_<uint8_t, uc16>(object);
    } else {
      SerializeString_<uc16, uc16>(object);
    }
  }
}

}  // namespace internal
}  // namespace v8