json-stringifier.h 23.3 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_JSON_STRINGIFIER_H_
#define V8_JSON_STRINGIFIER_H_

8
#include "src/conversions.h"
9
#include "src/lookup.h"
10
#include "src/messages.h"
11
#include "src/string-builder.h"
12
#include "src/utils.h"
13 14 15 16 17 18 19 20

namespace v8 {
namespace internal {

class BasicJsonStringifier BASE_EMBEDDED {
 public:
  explicit BasicJsonStringifier(Isolate* isolate);

21
  MUST_USE_RESULT MaybeHandle<Object> Stringify(Handle<Object> object);
22

23 24 25
  MUST_USE_RESULT INLINE(static MaybeHandle<Object> StringifyString(
      Isolate* isolate,
      Handle<String> object));
26

27
 private:
28
  enum Result { UNCHANGED, SUCCESS, EXCEPTION };
29

30 31 32
  MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
      Handle<Object> object,
      Handle<Object> key);
33

34 35 36 37 38
  Result SerializeGeneric(Handle<Object> object,
                          Handle<Object> key,
                          bool deferred_comma,
                          bool deferred_key);

39 40
  // Entry point to serialize the object.
  INLINE(Result SerializeObject(Handle<Object> obj)) {
41
    return Serialize_<false>(obj, false, factory()->empty_string());
42 43
  }

44 45
  // Serialize an array element.
  // The index may serve as argument for the toJSON function.
46 47 48 49 50 51
  INLINE(Result SerializeElement(Isolate* isolate,
                                 Handle<Object> object,
                                 int i)) {
    return Serialize_<false>(object,
                             false,
                             Handle<Object>(Smi::FromInt(i), isolate));
52 53 54 55 56 57 58 59
  }

  // Serialize a object property.
  // The key may or may not be serialized depending on the property.
  // The key may also serve as argument for the toJSON function.
  INLINE(Result SerializeProperty(Handle<Object> object,
                                  bool deferred_comma,
                                  Handle<String> deferred_key)) {
60
    DCHECK(!deferred_key.is_null());
61 62 63
    return Serialize_<true>(object, deferred_comma, deferred_key);
  }

64 65
  template <bool deferred_string_key>
  Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
66

67
  void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
68
    if (deferred_comma) builder_.AppendCharacter(',');
69
    SerializeString(Handle<String>::cast(deferred_key));
70
    builder_.AppendCharacter(':');
71 72
  }

73
  Result SerializeSmi(Smi* object);
74

75
  Result SerializeDouble(double number);
76 77 78 79
  INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
    return SerializeDouble(object->value());
  }

80 81 82 83 84
  Result SerializeJSValue(Handle<JSValue> object);

  INLINE(Result SerializeJSArray(Handle<JSArray> object));
  INLINE(Result SerializeJSObject(Handle<JSObject> object));

85
  Result SerializeJSArraySlow(Handle<JSArray> object, uint32_t length);
86 87 88

  void SerializeString(Handle<String> object);

89
  template <typename SrcChar, typename DestChar>
90 91 92
  INLINE(static void SerializeStringUnchecked_(
      Vector<const SrcChar> src,
      IncrementalStringBuilder::NoExtend<DestChar>* dest));
93

94
  template <typename SrcChar, typename DestChar>
95
  INLINE(void SerializeString_(Handle<String> string));
96

97
  template <typename Char>
98
  INLINE(static bool DoNotEscape(Char c));
99

100 101
  Result StackPush(Handle<Object> object);
  void StackPop();
102

103
  Factory* factory() { return isolate_->factory(); }
104 105

  Isolate* isolate_;
106
  IncrementalStringBuilder builder_;
107
  Handle<String> tojson_string_;
108 109
  Handle<JSArray> stack_;

110 111
  static const int kJsonEscapeTableEntrySize = 8;
  static const char* const JsonEscapeTable;
112 113 114
};


115
// Translation table to escape Latin1 characters.
116 117
// Table entries start at a multiple of 8 and are null-terminated.
const char* const BasicJsonStringifier::JsonEscapeTable =
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    "\\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      "
149 150 151 152 153 154 155 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
    "|\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      ";
182

183

184
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
185 186 187
    : isolate_(isolate), builder_(isolate) {
  tojson_string_ = factory()->toJSON_string();
  stack_ = factory()->NewJSArray(8);
188 189 190
}


191 192
MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
  Result result = SerializeObject(object);
193 194
  if (result == UNCHANGED) return factory()->undefined_value();
  if (result == SUCCESS) return builder_.Finish();
195
  DCHECK(result == EXCEPTION);
196
  return MaybeHandle<Object>();
197 198 199
}


200 201
MaybeHandle<Object> BasicJsonStringifier::StringifyString(
    Isolate* isolate,  Handle<String> object) {
202 203 204 205 206 207 208 209 210 211
  static const int kJsonQuoteWorstCaseBlowup = 6;
  static const int kSpaceForQuotes = 2;
  int worst_case_length =
      object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;

  if (worst_case_length > 32 * KB) {  // Slow path if too large.
    BasicJsonStringifier stringifier(isolate);
    return stringifier.Stringify(object);
  }

212
  object = String::Flatten(object);
213
  DCHECK(object->IsFlat());
214
  Handle<SeqString> result;
215
  if (object->IsOneByteRepresentationUnderneath()) {
216 217 218 219 220 221 222 223 224
    result = isolate->factory()
                 ->NewRawOneByteString(worst_case_length)
                 .ToHandleChecked();
    IncrementalStringBuilder::NoExtendString<uint8_t> no_extend(
        result, worst_case_length);
    no_extend.Append('\"');
    SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(),
                              &no_extend);
    no_extend.Append('\"');
225
  } else {
226 227 228 229 230 231 232 233 234
    result = isolate->factory()
                 ->NewRawTwoByteString(worst_case_length)
                 .ToHandleChecked();
    IncrementalStringBuilder::NoExtendString<uc16> no_extend(result,
                                                             worst_case_length);
    no_extend.Append('\"');
    SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(),
                              &no_extend);
    no_extend.Append('\"');
235
  }
236
  return result;
237 238 239
}


240
MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction(
241
    Handle<Object> object, Handle<Object> key) {
242
  LookupIterator it(object, tojson_string_,
243
                    LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
244
  Handle<Object> fun;
245
  ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object);
246 247 248
  if (!fun->IsJSFunction()) return object;

  // Call toJSON function.
249
  if (key->IsSmi()) key = factory()->NumberToString(key);
250 251
  Handle<Object> argv[] = { key };
  HandleScope scope(isolate_);
252 253 254 255
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate_, object,
      Execution::Call(isolate_, fun, object, 1, argv),
      Object);
256
  return scope.CloseAndEscape(object);
257 258 259 260 261
}


BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
    Handle<Object> object) {
262
  StackLimitCheck check(isolate_);
263 264 265 266
  if (check.HasOverflowed()) {
    isolate_->StackOverflow();
    return EXCEPTION;
  }
267

268
  int length = Smi::cast(stack_->length())->value();
269 270 271 272 273
  {
    DisallowHeapAllocation no_allocation;
    FixedArray* elements = FixedArray::cast(stack_->elements());
    for (int i = 0; i < length; i++) {
      if (elements->get(i) == *object) {
274
        AllowHeapAllocation allow_to_return_error;
275 276
        Handle<Object> error =
            factory()->NewTypeError(MessageTemplate::kCircularStructure);
277
        isolate_->Throw(*error);
278
        return EXCEPTION;
279
      }
280 281
    }
  }
282
  JSArray::SetLength(stack_, length + 1);
283 284 285 286 287 288 289 290 291 292 293
  FixedArray::cast(stack_->elements())->set(length, *object);
  return SUCCESS;
}


void BasicJsonStringifier::StackPop() {
  int length = Smi::cast(stack_->length())->value();
  stack_->set_length(Smi::FromInt(length - 1));
}


294
template <bool deferred_string_key>
295
BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
296
    Handle<Object> object, bool comma, Handle<Object> key) {
297
  if (object->IsJSObject()) {
298 299 300 301
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, object,
        ApplyToJsonFunction(object, key),
        EXCEPTION);
302 303
  }

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

309 310
  switch (HeapObject::cast(*object)->map()->instance_type()) {
    case HEAP_NUMBER_TYPE:
311
    case MUTABLE_HEAP_NUMBER_TYPE:
312 313 314 315 316 317
      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);
318
          builder_.AppendCString("false");
319 320 321
          return SUCCESS;
        case Oddball::kTrue:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
322
          builder_.AppendCString("true");
323 324 325
          return SUCCESS;
        case Oddball::kNull:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
326
          builder_.AppendCString("null");
327 328 329 330 331
          return SUCCESS;
        default:
          return UNCHANGED;
      }
    case JS_ARRAY_TYPE:
332
      if (object->IsAccessCheckNeeded()) break;
333 334 335 336 337 338 339 340 341
      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 JS_FUNCTION_TYPE:
      return UNCHANGED;
    default:
      if (object->IsString()) {
342
        if (deferred_string_key) SerializeDeferredKey(comma, key);
343
        SerializeString(Handle<String>::cast(object));
344
        return SUCCESS;
345
      } else if (object->IsJSObject()) {
346 347
        // Go to slow path for global proxy and objects requiring access checks.
        if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break;
348
        if (deferred_string_key) SerializeDeferredKey(comma, key);
349 350
        return SerializeJSObject(Handle<JSObject>::cast(object));
      }
351
  }
352 353

  return SerializeGeneric(object, key, comma, deferred_string_key);
354 355
}

356

357 358 359 360 361
BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
    Handle<Object> object,
    Handle<Object> key,
    bool deferred_comma,
    bool deferred_key) {
362
  Handle<JSFunction> fun = isolate_->json_serialize_adapter();
363
  Handle<Object> argv[] = { key, object };
364 365
  Handle<Object> result;
  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
366
      isolate_, result, Execution::Call(isolate_, fun, object, 2, argv),
367
      EXCEPTION);
368 369
  if (result->IsUndefined()) return UNCHANGED;
  if (deferred_key) {
370
    if (key->IsSmi()) key = factory()->NumberToString(key);
371 372 373
    SerializeDeferredKey(deferred_comma, key);
  }

374
  builder_.AppendString(Handle<String>::cast(result));
375
  return SUCCESS;
376 377 378
}


379 380 381
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
    Handle<JSValue> object) {
  String* class_name = object->class_name();
382
  if (class_name == isolate_->heap()->String_string()) {
383 384
    Handle<Object> value;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
385
        isolate_, value, Object::ToString(isolate_, object), EXCEPTION);
386
    SerializeString(Handle<String>::cast(value));
387
  } else if (class_name == isolate_->heap()->Number_string()) {
388
    Handle<Object> value;
389 390
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object),
                                     EXCEPTION);
391 392
    if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
    SerializeHeapNumber(Handle<HeapNumber>::cast(value));
393
  } else if (class_name == isolate_->heap()->Boolean_string()) {
394
    Object* value = JSValue::cast(*object)->value();
395
    DCHECK(value->IsBoolean());
396
    builder_.AppendCString(value->IsTrue() ? "true" : "false");
397 398 399 400
  } else {
    // Fail gracefully for special value wrappers.
    isolate_->ThrowIllegalOperation();
    return EXCEPTION;
401 402 403 404 405
  }
  return SUCCESS;
}


406 407 408 409
BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
  static const int kBufferSize = 100;
  char chars[kBufferSize];
  Vector<char> buffer(chars, kBufferSize);
410
  builder_.AppendCString(IntToCString(object->value(), buffer));
411 412 413 414 415 416
  return SUCCESS;
}


BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
    double number) {
417
  if (std::isinf(number) || std::isnan(number)) {
418
    builder_.AppendCString("null");
419 420 421 422 423
    return SUCCESS;
  }
  static const int kBufferSize = 100;
  char chars[kBufferSize];
  Vector<char> buffer(chars, kBufferSize);
424
  builder_.AppendCString(DoubleToCString(number, buffer));
425 426 427 428
  return SUCCESS;
}


429
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
430 431
    Handle<JSArray> object) {
  HandleScope handle_scope(isolate_);
432 433
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;
434
  uint32_t length = 0;
435
  CHECK(object->length()->ToArrayLength(&length));
436
  builder_.AppendCharacter('[');
437 438
  switch (object->GetElementsKind()) {
    case FAST_SMI_ELEMENTS: {
439 440
      Handle<FixedArray> elements(
          FixedArray::cast(object->elements()), isolate_);
441
      for (uint32_t i = 0; i < length; i++) {
442
        if (i > 0) builder_.AppendCharacter(',');
443 444 445 446 447
        SerializeSmi(Smi::cast(elements->get(i)));
      }
      break;
    }
    case FAST_DOUBLE_ELEMENTS: {
448 449
      // Empty array is FixedArray but not FixedDoubleArray.
      if (length == 0) break;
450
      Handle<FixedDoubleArray> elements(
451
          FixedDoubleArray::cast(object->elements()), isolate_);
452
      for (uint32_t i = 0; i < length; i++) {
453
        if (i > 0) builder_.AppendCharacter(',');
454 455 456 457 458
        SerializeDouble(elements->get_scalar(i));
      }
      break;
    }
    case FAST_ELEMENTS: {
459 460
      Handle<FixedArray> elements(
          FixedArray::cast(object->elements()), isolate_);
461
      for (uint32_t i = 0; i < length; i++) {
462
        if (i > 0) builder_.AppendCharacter(',');
463
        Result result =
464 465 466
            SerializeElement(isolate_,
                             Handle<Object>(elements->get(i), isolate_),
                             i);
467 468
        if (result == SUCCESS) continue;
        if (result == UNCHANGED) {
469
          builder_.AppendCString("null");
470 471 472 473 474 475
        } else {
          return result;
        }
      }
      break;
    }
476 477 478 479 480 481 482 483
    // TODO(yangguo):  The FAST_HOLEY_* cases could be handled in a faster way.
    // They resemble the non-holey cases except that a prototype chain lookup
    // is necessary for holes.
    default: {
      Result result = SerializeJSArraySlow(object, length);
      if (result != SUCCESS) return result;
      break;
    }
484
  }
485
  builder_.AppendCharacter(']');
486 487 488 489 490
  StackPop();
  return SUCCESS;
}


491
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
492 493
    Handle<JSArray> object, uint32_t length) {
  for (uint32_t i = 0; i < length; i++) {
494
    if (i > 0) builder_.AppendCharacter(',');
495 496 497 498 499
    Handle<Object> element;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, element,
        Object::GetElement(isolate_, object, i),
        EXCEPTION);
500
    if (element->IsUndefined()) {
501
      builder_.AppendCString("null");
502
    } else {
503
      Result result = SerializeElement(isolate_, element, i);
504 505
      if (result == SUCCESS) continue;
      if (result == UNCHANGED) {
506
        builder_.AppendCString("null");
507 508 509 510 511 512 513 514 515 516
      } else {
        return result;
      }
    }
  }
  return SUCCESS;
}


BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
517 518 519 520
    Handle<JSObject> object) {
  HandleScope handle_scope(isolate_);
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;
521
  DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject());
522

523
  builder_.AppendCharacter('{');
524
  bool comma = false;
525 526 527 528

  if (object->HasFastProperties() &&
      !object->HasIndexedInterceptor() &&
      !object->HasNamedInterceptor() &&
529
      object->elements()->length() == 0) {
530
    Handle<Map> map(object->map());
531
    for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
532 533 534 535
      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);
536
      PropertyDetails details = map->instance_descriptors()->GetDetails(i);
537
      if (details.IsDontEnum()) continue;
538
      Handle<Object> property;
539
      if (details.type() == DATA && *map == object->map()) {
540 541 542 543 544 545 546 547 548
        FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
        Isolate* isolate = object->GetIsolate();
        if (object->IsUnboxedDoubleField(field_index)) {
          double value = object->RawFastDoublePropertyAt(field_index);
          property = isolate->factory()->NewHeapNumber(value);

        } else {
          property = handle(object->RawFastPropertyAt(field_index), isolate);
        }
549
      } else {
550 551 552 553
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate_, property,
            Object::GetPropertyOrElement(object, key),
            EXCEPTION);
554 555 556
      }
      Result result = SerializeProperty(property, comma, key);
      if (!comma && result == SUCCESS) comma = true;
557
      if (result == EXCEPTION) return result;
558 559
    }
  } else {
560 561 562
    Handle<FixedArray> contents;
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate_, contents,
563
        JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY),
564
        EXCEPTION);
565 566 567 568

    for (int i = 0; i < contents->length(); i++) {
      Object* key = contents->get(i);
      Handle<String> key_handle;
569
      MaybeHandle<Object> maybe_property;
570 571
      if (key->IsString()) {
        key_handle = Handle<String>(String::cast(key), isolate_);
572
        maybe_property = Object::GetPropertyOrElement(object, key_handle);
573
      } else {
574
        DCHECK(key->IsNumber());
575
        key_handle = factory()->NumberToString(Handle<Object>(key, isolate_));
576
        if (key->IsSmi()) {
577
          maybe_property = Object::GetElement(
578
              isolate_, object, Smi::cast(key)->value());
579
        } else {
580
          maybe_property = Object::GetPropertyOrElement(object, key_handle);
581
        }
582
      }
583 584 585
      Handle<Object> property;
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
          isolate_, property, maybe_property, EXCEPTION);
586 587
      Result result = SerializeProperty(property, comma, key_handle);
      if (!comma && result == SUCCESS) comma = true;
588
      if (result == EXCEPTION) return result;
589 590
    }
  }
591

592
  builder_.AppendCharacter('}');
593 594 595 596 597
  StackPop();
  return SUCCESS;
}


598
template <typename SrcChar, typename DestChar>
599 600 601
void BasicJsonStringifier::SerializeStringUnchecked_(
    Vector<const SrcChar> src,
    IncrementalStringBuilder::NoExtend<DestChar>* dest) {
602 603
  // Assert that uc16 character is not truncated down to 8 bit.
  // The <uc16, char> version of this method must not be called.
604
  DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
605

606
  for (int i = 0; i < src.length(); i++) {
607 608
    SrcChar c = src[i];
    if (DoNotEscape(c)) {
609
      dest->Append(c);
610
    } else {
611
      dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
612 613 614 615 616
    }
  }
}


617
template <typename SrcChar, typename DestChar>
618 619
void BasicJsonStringifier::SerializeString_(Handle<String> string) {
  int length = string->length();
620
  builder_.Append<uint8_t, DestChar>('"');
621 622
  // 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
623 624
  // an escaped character is 6.  Shifting the remainin string length right by 3
  // is a more pessimistic estimate, but faster to calculate.
625 626
  int worst_case_length = length << 3;
  if (builder_.CurrentPartCanFit(worst_case_length)) {
627
    DisallowHeapAllocation no_gc;
628
    Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
629 630 631
    IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
        &builder_, worst_case_length);
    SerializeStringUnchecked_(vector, &no_extend);
632
  } else {
633 634
    FlatStringReader reader(isolate_, string);
    for (int i = 0; i < reader.length(); i++) {
635
      SrcChar c = reader.Get<SrcChar>(i);
636
      if (DoNotEscape(c)) {
637
        builder_.Append<SrcChar, DestChar>(c);
638
      } else {
639
        builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
640 641 642
      }
    }
  }
643

644
  builder_.Append<uint8_t, DestChar>('"');
645 646 647
}


648 649 650 651 652 653 654 655 656
template <>
bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
  return c >= '#' && c <= '~' && c != '\\';
}


template <>
bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
  return c >= '#' && c != '\\' && c != 0x7f;
657 658 659
}


660
void BasicJsonStringifier::SerializeString(Handle<String> object) {
661
  object = String::Flatten(object);
662
  if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
663
    if (object->IsOneByteRepresentationUnderneath()) {
664
      SerializeString_<uint8_t, uint8_t>(object);
665
    } else {
666
      builder_.ChangeEncoding();
667 668 669
      SerializeString(object);
    }
  } else {
670
    if (object->IsOneByteRepresentationUnderneath()) {
671
      SerializeString_<uint8_t, uc16>(object);
672
    } else {
673
      SerializeString_<uc16, uc16>(object);
674 675 676 677
    }
  }
}

678 679
}  // namespace internal
}  // namespace v8
680 681

#endif  // V8_JSON_STRINGIFIER_H_