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