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