json-stringifier.h 29.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_JSON_STRINGIFIER_H_
#define V8_JSON_STRINGIFIER_H_

#include "v8.h"
#include "v8utils.h"
#include "v8conversions.h"

namespace v8 {
namespace internal {

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

  MaybeObject* Stringify(Handle<Object> object);

44 45 46
  INLINE(static MaybeObject* StringifyString(Isolate* isolate,
                                             Handle<String> object));

47 48 49 50 51
 private:
  static const int kInitialPartLength = 32;
  static const int kMaxPartLength = 16 * 1024;
  static const int kPartLengthGrowthFactor = 2;

52
  enum Result { UNCHANGED, SUCCESS, EXCEPTION, CIRCULAR, STACK_OVERFLOW };
53

54
  void Extend();
55 56 57

  void ChangeEncoding();

58
  INLINE(void ShrinkCurrentPart());
59 60 61 62 63 64 65

  template <bool is_ascii, typename Char>
  INLINE(void Append_(Char c));

  template <bool is_ascii, typename Char>
  INLINE(void Append_(const Char* chars));

66
  INLINE(void Append(uint8_t c)) {
67 68 69 70 71 72 73
    if (is_ascii_) {
      Append_<true>(c);
    } else {
      Append_<false>(c);
    }
  }

74
  INLINE(void AppendAscii(const char* chars)) {
75
    if (is_ascii_) {
76
      Append_<true>(reinterpret_cast<const uint8_t*>(chars));
77
    } else {
78
      Append_<false>(reinterpret_cast<const uint8_t*>(chars));
79 80 81
    }
  }

82 83
  Handle<Object> ApplyToJsonFunction(Handle<Object> object,
                                     Handle<Object> key);
84

85 86 87 88 89
  Result SerializeGeneric(Handle<Object> object,
                          Handle<Object> key,
                          bool deferred_comma,
                          bool deferred_key);

90
  template <typename ResultType, typename Char>
91
  INLINE(static MaybeObject* StringifyString_(Isolate* isolate,
92
                                              Vector<Char> vector,
93 94
                                              Handle<String> result));

95 96
  // Entry point to serialize the object.
  INLINE(Result SerializeObject(Handle<Object> obj)) {
97
    return Serialize_<false>(obj, false, factory_->empty_string());
98 99
  }

100 101
  // Serialize an array element.
  // The index may serve as argument for the toJSON function.
102 103 104 105 106 107
  INLINE(Result SerializeElement(Isolate* isolate,
                                 Handle<Object> object,
                                 int i)) {
    return Serialize_<false>(object,
                             false,
                             Handle<Object>(Smi::FromInt(i), isolate));
108 109 110 111 112 113 114 115
  }

  // 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)) {
116 117 118 119
    ASSERT(!deferred_key.is_null());
    return Serialize_<true>(object, deferred_comma, deferred_key);
  }

120 121
  template <bool deferred_string_key>
  Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
122

123
  void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
124
    if (deferred_comma) Append(',');
125
    SerializeString(Handle<String>::cast(deferred_key));
126 127 128
    Append(':');
  }

129
  Result SerializeSmi(Smi* object);
130

131
  Result SerializeDouble(double number);
132 133 134 135
  INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
    return SerializeDouble(object->value());
  }

136 137 138 139 140 141
  Result SerializeJSValue(Handle<JSValue> object);

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

  Result SerializeJSArraySlow(Handle<JSArray> object, int length);
142 143 144

  void SerializeString(Handle<String> object);

145
  template <typename SrcChar, typename DestChar>
146 147 148
  INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
                                              DestChar* dest,
                                              int length));
149

150
  template <bool is_ascii, typename Char>
151
  INLINE(void SerializeString_(Handle<String> string));
152

153
  template <typename Char>
154
  INLINE(static bool DoNotEscape(Char c));
155

156
  template <typename Char>
157
  INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
158

159 160
  Result StackPush(Handle<Object> object);
  void StackPop();
161 162

  INLINE(Handle<String> accumulator()) {
163
    return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
164 165 166 167 168 169 170
  }

  INLINE(void set_accumulator(Handle<String> string)) {
    return accumulator_store_->set_value(*string);
  }

  Isolate* isolate_;
171
  Factory* factory_;
172 173 174 175
  // We use a value wrapper for the string accumulator to keep the
  // (indirect) handle to it in the outermost handle scope.
  Handle<JSValue> accumulator_store_;
  Handle<String> current_part_;
176
  Handle<String> tojson_string_;
177 178 179 180 181
  Handle<JSArray> stack_;
  int current_index_;
  int part_length_;
  bool is_ascii_;

182 183
  static const int kJsonEscapeTableEntrySize = 8;
  static const char* const JsonEscapeTable;
184 185 186
};


187 188 189
// Translation table to escape ASCII characters.
// Table entries start at a multiple of 8 and are null-terminated.
const char* const BasicJsonStringifier::JsonEscapeTable =
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    "\\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      "
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    "|\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      ";
254

255

256 257
BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
    : isolate_(isolate), current_index_(0), is_ascii_(true) {
258
  factory_ = isolate_->factory();
259
  accumulator_store_ = Handle<JSValue>::cast(
260
                           factory_->ToObject(factory_->empty_string()));
261
  part_length_ = kInitialPartLength;
262 263
  current_part_ = factory_->NewRawOneByteString(part_length_);
  tojson_string_ = factory_->toJSON_string();
264
  stack_ = factory_->NewJSArray(8);
265 266 267 268
}


MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) {
269 270 271
  switch (SerializeObject(object)) {
    case UNCHANGED:
      return isolate_->heap()->undefined_value();
272 273
    case SUCCESS:
      ShrinkCurrentPart();
274
      return *factory_->NewConsString(accumulator(), current_part_);
275
    case CIRCULAR:
276
      return isolate_->Throw(*factory_->NewTypeError(
277 278 279 280
                 "circular_structure", HandleVector<Object>(NULL, 0)));
    case STACK_OVERFLOW:
      return isolate_->StackOverflow();
    default:
281
      return Failure::Exception();
282 283 284 285
  }
}


286 287 288 289 290 291 292 293 294 295 296 297
MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
                                                   Handle<String> object) {
  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);
  }

298
  FlattenString(object);
299
  ASSERT(object->IsFlat());
300
  if (object->IsOneByteRepresentationUnderneath()) {
301 302
    Handle<String> result =
        isolate->factory()->NewRawOneByteString(worst_case_length);
303
    DisallowHeapAllocation no_gc;
304 305
    return StringifyString_<SeqOneByteString>(
        isolate,
306
        object->GetFlatContent().ToOneByteVector(),
307
        result);
308
  } else {
309 310
    Handle<String> result =
        isolate->factory()->NewRawTwoByteString(worst_case_length);
311
    DisallowHeapAllocation no_gc;
312 313
    return StringifyString_<SeqTwoByteString>(
        isolate,
314
        object->GetFlatContent().ToUC16Vector(),
315
        result);
316 317 318 319
  }
}


320
template <typename ResultType, typename Char>
321
MaybeObject* BasicJsonStringifier::StringifyString_(Isolate* isolate,
322
                                                    Vector<Char> vector,
323
                                                    Handle<String> result) {
324
  DisallowHeapAllocation no_gc;
325
  int final_size = 0;
326
  ResultType* dest = ResultType::cast(*result);
327
  dest->Set(final_size++, '\"');
328
  final_size += SerializeStringUnchecked_(vector.start(),
329
                                          dest->GetChars() + 1,
330
                                          vector.length());
331
  dest->Set(final_size++, '\"');
332
  return *SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
333 334 335
}


336 337 338
template <bool is_ascii, typename Char>
void BasicJsonStringifier::Append_(Char c) {
  if (is_ascii) {
339
    SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
340 341 342 343 344
        current_index_++, c);
  } else {
    SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
        current_index_++, c);
  }
345
  if (current_index_ == part_length_) Extend();
346 347 348 349 350 351 352 353 354
}


template <bool is_ascii, typename Char>
void BasicJsonStringifier::Append_(const Char* chars) {
  for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars);
}


355 356
Handle<Object> BasicJsonStringifier::ApplyToJsonFunction(
    Handle<Object> object, Handle<Object> key) {
357
  LookupResult lookup(isolate_);
358
  JSObject::cast(*object)->LookupRealNamedProperty(*tojson_string_, &lookup);
359 360 361
  if (!lookup.IsProperty()) return object;
  PropertyAttributes attr;
  Handle<Object> fun =
362
      Object::GetProperty(object, object, &lookup, tojson_string_, &attr);
363 364 365
  if (!fun->IsJSFunction()) return object;

  // Call toJSON function.
366
  if (key->IsSmi()) key = factory_->NumberToString(key);
367 368 369
  Handle<Object> argv[] = { key };
  bool has_exception = false;
  HandleScope scope(isolate_);
370
  object = Execution::Call(isolate_, fun, object, 1, argv, &has_exception);
371 372 373
  // Return empty handle to signal an exception.
  if (has_exception) return Handle<Object>::null();
  return scope.CloseAndEscape(object);
374 375 376 377 378
}


BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
    Handle<Object> object) {
379 380 381
  StackLimitCheck check(isolate_);
  if (check.HasOverflowed()) return STACK_OVERFLOW;

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
  int length = Smi::cast(stack_->length())->value();
  FixedArray* elements = FixedArray::cast(stack_->elements());
  for (int i = 0; i < length; i++) {
    if (elements->get(i) == *object) {
      return CIRCULAR;
    }
  }
  stack_->EnsureSize(length + 1);
  FixedArray::cast(stack_->elements())->set(length, *object);
  stack_->set_length(Smi::FromInt(length + 1));
  return SUCCESS;
}


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


402
template <bool deferred_string_key>
403
BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
404
    Handle<Object> object, bool comma, Handle<Object> key) {
405
  if (object->IsJSObject()) {
406 407 408 409
    object = ApplyToJsonFunction(object, key);
    if (object.is_null()) return EXCEPTION;
  }

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

415 416 417 418 419 420 421 422
  switch (HeapObject::cast(*object)->map()->instance_type()) {
    case 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);
423
          AppendAscii("false");
424 425 426
          return SUCCESS;
        case Oddball::kTrue:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
427
          AppendAscii("true");
428 429 430
          return SUCCESS;
        case Oddball::kNull:
          if (deferred_string_key) SerializeDeferredKey(comma, key);
431
          AppendAscii("null");
432 433 434 435 436
          return SUCCESS;
        default:
          return UNCHANGED;
      }
    case JS_ARRAY_TYPE:
437
      if (object->IsAccessCheckNeeded()) break;
438 439 440 441 442 443 444 445 446
      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()) {
447
        if (deferred_string_key) SerializeDeferredKey(comma, key);
448
        SerializeString(Handle<String>::cast(object));
449
        return SUCCESS;
450
      } else if (object->IsJSObject()) {
451
        if (object->IsAccessCheckNeeded()) break;
452
        if (deferred_string_key) SerializeDeferredKey(comma, key);
453 454
        return SerializeJSObject(Handle<JSObject>::cast(object));
      }
455
  }
456 457

  return SerializeGeneric(object, key, comma, deferred_string_key);
458 459
}

460

461 462 463 464 465 466
BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
    Handle<Object> object,
    Handle<Object> key,
    bool deferred_comma,
    bool deferred_key) {
  Handle<JSObject> builtins(isolate_->native_context()->builtins());
467 468
  Handle<JSFunction> builtin =
      Handle<JSFunction>::cast(GetProperty(builtins, "JSONSerializeAdapter"));
469 470 471 472

  Handle<Object> argv[] = { key, object };
  bool has_exception = false;
  Handle<Object> result =
473
      Execution::Call(isolate_, builtin, object, 2, argv, &has_exception);
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
  if (has_exception) return EXCEPTION;
  if (result->IsUndefined()) return UNCHANGED;
  if (deferred_key) {
    if (key->IsSmi()) key = factory_->NumberToString(key);
    SerializeDeferredKey(deferred_comma, key);
  }

  Handle<String> result_string = Handle<String>::cast(result);
  // Shrink current part, attach it to the accumulator, also attach the result
  // string to the accumulator, and allocate a new part.
  ShrinkCurrentPart();  // Shrink.
  part_length_ = kInitialPartLength;  // Allocate conservatively.
  Extend();             // Attach current part and allocate new part.
  // Attach result string to the accumulator.
  set_accumulator(factory_->NewConsString(accumulator(), result_string));
  return SUCCESS;
490 491 492
}


493 494 495 496
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
    Handle<JSValue> object) {
  bool has_exception = false;
  String* class_name = object->class_name();
497
  if (class_name == isolate_->heap()->String_string()) {
498 499
    Handle<Object> value =
        Execution::ToString(isolate_, object, &has_exception);
500 501
    if (has_exception) return EXCEPTION;
    SerializeString(Handle<String>::cast(value));
502
  } else if (class_name == isolate_->heap()->Number_string()) {
503 504
    Handle<Object> value =
        Execution::ToNumber(isolate_, object, &has_exception);
505 506 507 508
    if (has_exception) return EXCEPTION;
    if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
    SerializeHeapNumber(Handle<HeapNumber>::cast(value));
  } else {
509
    ASSERT(class_name == isolate_->heap()->Boolean_string());
510 511
    Object* value = JSValue::cast(*object)->value();
    ASSERT(value->IsBoolean());
512
    AppendAscii(value->IsTrue() ? "true" : "false");
513 514 515 516 517
  }
  return SUCCESS;
}


518 519 520 521
BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
  static const int kBufferSize = 100;
  char chars[kBufferSize];
  Vector<char> buffer(chars, kBufferSize);
522
  AppendAscii(IntToCString(object->value(), buffer));
523 524 525 526 527 528
  return SUCCESS;
}


BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
    double number) {
529
  if (std::isinf(number) || std::isnan(number)) {
530
    AppendAscii("null");
531 532 533 534 535
    return SUCCESS;
  }
  static const int kBufferSize = 100;
  char chars[kBufferSize];
  Vector<char> buffer(chars, kBufferSize);
536
  AppendAscii(DoubleToCString(number, buffer));
537 538 539 540
  return SUCCESS;
}


541
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
542 543
    Handle<JSArray> object) {
  HandleScope handle_scope(isolate_);
544 545
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;
546 547 548 549
  int length = Smi::cast(object->length())->value();
  Append('[');
  switch (object->GetElementsKind()) {
    case FAST_SMI_ELEMENTS: {
550 551
      Handle<FixedArray> elements(
          FixedArray::cast(object->elements()), isolate_);
552 553 554 555 556 557 558
      for (int i = 0; i < length; i++) {
        if (i > 0) Append(',');
        SerializeSmi(Smi::cast(elements->get(i)));
      }
      break;
    }
    case FAST_DOUBLE_ELEMENTS: {
559
      Handle<FixedDoubleArray> elements(
560
          FixedDoubleArray::cast(object->elements()), isolate_);
561 562 563 564 565 566 567
      for (int i = 0; i < length; i++) {
        if (i > 0) Append(',');
        SerializeDouble(elements->get_scalar(i));
      }
      break;
    }
    case FAST_ELEMENTS: {
568 569
      Handle<FixedArray> elements(
          FixedArray::cast(object->elements()), isolate_);
570 571
      for (int i = 0; i < length; i++) {
        if (i > 0) Append(',');
572
        Result result =
573 574 575
            SerializeElement(isolate_,
                             Handle<Object>(elements->get(i), isolate_),
                             i);
576 577
        if (result == SUCCESS) continue;
        if (result == UNCHANGED) {
578
          AppendAscii("null");
579 580 581 582 583 584
        } else {
          return result;
        }
      }
      break;
    }
585 586 587 588 589 590 591 592
    // 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;
    }
593 594 595 596 597 598 599 600
  }
  Append(']');
  StackPop();
  current_part_ = handle_scope.CloseAndEscape(current_part_);
  return SUCCESS;
}


601 602 603 604
BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
    Handle<JSArray> object, int length) {
  for (int i = 0; i < length; i++) {
    if (i > 0) Append(',');
605
    Handle<Object> element = Object::GetElement(isolate_, object, i);
606
    RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, element, EXCEPTION);
607
    if (element->IsUndefined()) {
608
      AppendAscii("null");
609
    } else {
610
      Result result = SerializeElement(isolate_, element, i);
611 612
      if (result == SUCCESS) continue;
      if (result == UNCHANGED) {
613
        AppendAscii("null");
614 615 616 617 618 619 620 621 622 623
      } else {
        return result;
      }
    }
  }
  return SUCCESS;
}


BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
624 625 626 627
    Handle<JSObject> object) {
  HandleScope handle_scope(isolate_);
  Result stack_push = StackPush(object);
  if (stack_push != SUCCESS) return stack_push;
628
  if (object->IsJSGlobalProxy()) {
629 630
    object = Handle<JSObject>(
                 JSObject::cast(object->GetPrototype()), isolate_);
631 632
    ASSERT(object->IsGlobalObject());
  }
633

634 635
  Append('{');
  bool comma = false;
636 637 638 639

  if (object->HasFastProperties() &&
      !object->HasIndexedInterceptor() &&
      !object->HasNamedInterceptor() &&
640
      object->elements()->length() == 0) {
641
    Handle<Map> map(object->map());
642
    for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
643 644 645 646
      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);
647
      PropertyDetails details = map->instance_descriptors()->GetDetails(i);
648
      if (details.IsDontEnum()) continue;
649
      Handle<Object> property;
650
      if (details.type() == FIELD && *map == object->map()) {
651
        property = Handle<Object>(
652
                       object->RawFastPropertyAt(
653 654
                           map->instance_descriptors()->GetFieldIndex(i)),
                       isolate_);
655
      } else {
656
        property = GetProperty(isolate_, object, key);
657
        if (property.is_null()) return EXCEPTION;
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
      }
      Result result = SerializeProperty(property, comma, key);
      if (!comma && result == SUCCESS) comma = true;
      if (result >= EXCEPTION) return result;
    }
  } else {
    bool has_exception = false;
    Handle<FixedArray> contents =
        GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception);
    if (has_exception) return EXCEPTION;

    for (int i = 0; i < contents->length(); i++) {
      Object* key = contents->get(i);
      Handle<String> key_handle;
      Handle<Object> property;
      if (key->IsString()) {
        key_handle = Handle<String>(String::cast(key), isolate_);
675
        property = GetProperty(isolate_, object, key_handle);
676 677 678 679 680
      } else {
        ASSERT(key->IsNumber());
        key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
        uint32_t index;
        if (key->IsSmi()) {
681 682
          property = Object::GetElement(
              isolate_, object, Smi::cast(key)->value());
683
        } else if (key_handle->AsArrayIndex(&index)) {
684
          property = Object::GetElement(isolate_, object, index);
685
        } else {
686
          property = GetProperty(isolate_, object, key_handle);
687
        }
688
      }
689 690 691 692
      if (property.is_null()) return EXCEPTION;
      Result result = SerializeProperty(property, comma, key_handle);
      if (!comma && result == SUCCESS) comma = true;
      if (result >= EXCEPTION) return result;
693 694
    }
  }
695

696 697 698 699 700 701 702 703 704
  Append('}');
  StackPop();
  current_part_ = handle_scope.CloseAndEscape(current_part_);
  return SUCCESS;
}


void BasicJsonStringifier::ShrinkCurrentPart() {
  ASSERT(current_index_ < part_length_);
705 706
  current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
                                      current_index_);
707 708 709 710
}


void BasicJsonStringifier::Extend() {
711
  set_accumulator(factory_->NewConsString(accumulator(), current_part_));
712 713 714
  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
    part_length_ *= kPartLengthGrowthFactor;
  }
715
  if (is_ascii_) {
716
    current_part_ = factory_->NewRawOneByteString(part_length_);
717
  } else {
718
    current_part_ = factory_->NewRawTwoByteString(part_length_);
719 720 721 722 723 724 725
  }
  current_index_ = 0;
}


void BasicJsonStringifier::ChangeEncoding() {
  ShrinkCurrentPart();
726 727
  set_accumulator(factory_->NewConsString(accumulator(), current_part_));
  current_part_ = factory_->NewRawTwoByteString(part_length_);
728 729 730 731 732
  current_index_ = 0;
  is_ascii_ = false;
}


733
template <typename SrcChar, typename DestChar>
734 735 736
int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
                                                    DestChar* dest,
                                                    int length) {
737 738
  DestChar* dest_start = dest;

739 740 741 742
  // Assert that uc16 character is not truncated down to 8 bit.
  // The <uc16, char> version of this method must not be called.
  ASSERT(sizeof(*dest) >= sizeof(*src));

743 744 745
  for (int i = 0; i < length; i++) {
    SrcChar c = src[i];
    if (DoNotEscape(c)) {
746
      *(dest++) = static_cast<DestChar>(c);
747
    } else {
748 749
      const uint8_t* chars = reinterpret_cast<const uint8_t*>(
          &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
750 751 752 753
      while (*chars != '\0') *(dest++) = *(chars++);
    }
  }

754
  return static_cast<int>(dest - dest_start);
755 756 757
}


758
template <bool is_ascii, typename Char>
759 760
void BasicJsonStringifier::SerializeString_(Handle<String> string) {
  int length = string->length();
761
  Append_<is_ascii, char>('"');
762 763
  // 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
764 765 766 767
  // an escaped character is 6.  Shifting the remainin string length right by 3
  // is a more pessimistic estimate, but faster to calculate.

  if (((part_length_ - current_index_) >> 3) > length) {
768
    DisallowHeapAllocation no_gc;
769
    Vector<const Char> vector = GetCharVector<Char>(string);
770
    if (is_ascii) {
771
      current_index_ += SerializeStringUnchecked_(
772
          vector.start(),
773
          SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
774 775
          length);
    } else {
776
      current_index_ += SerializeStringUnchecked_(
777
          vector.start(),
778
          SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
779
          length);
780 781
    }
  } else {
782 783
    String* string_location = NULL;
    Vector<const Char> vector(NULL, 0);
784
    for (int i = 0; i < length; i++) {
785 786
      // If GC moved the string, we need to refresh the vector.
      if (*string != string_location) {
787
        DisallowHeapAllocation no_gc;
788 789 790 791
        // This does not actually prevent the string from being relocated later.
        vector = GetCharVector<Char>(string);
        string_location = *string;
      }
792
      Char c = vector[i];
793
      if (DoNotEscape(c)) {
794 795
        Append_<is_ascii, Char>(c);
      } else {
796 797
        Append_<is_ascii, uint8_t>(reinterpret_cast<const uint8_t*>(
            &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
798 799 800
      }
    }
  }
801

802
  Append_<is_ascii, uint8_t>('"');
803 804 805
}


806 807 808 809 810 811 812 813 814
template <>
bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
  return c >= '#' && c <= '~' && c != '\\';
}


template <>
bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
  return c >= '#' && c != '\\' && c != 0x7f;
815 816 817
}


818
template <>
819 820
Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
    Handle<String> string) {
821 822
  String::FlatContent flat = string->GetFlatContent();
  ASSERT(flat.IsAscii());
823
  return flat.ToOneByteVector();
824 825 826 827 828 829 830 831 832 833 834 835
}


template <>
Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
  String::FlatContent flat = string->GetFlatContent();
  ASSERT(flat.IsTwoByte());
  return flat.ToUC16Vector();
}


void BasicJsonStringifier::SerializeString(Handle<String> object) {
836
  object = FlattenGetString(object);
837
  if (is_ascii_) {
838
    if (object->IsOneByteRepresentationUnderneath()) {
839
      SerializeString_<true, uint8_t>(object);
840 841 842 843 844
    } else {
      ChangeEncoding();
      SerializeString(object);
    }
  } else {
845
    if (object->IsOneByteRepresentationUnderneath()) {
846
      SerializeString_<false, uint8_t>(object);
847
    } else {
848
      SerializeString_<false, uc16>(object);
849 850 851 852 853 854 855
    }
  }
}

} }  // namespace v8::internal

#endif  // V8_JSON_STRINGIFIER_H_