v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
json-stringifier.h
Go to the documentation of this file.
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 
35 namespace v8 {
36 namespace internal {
37 
38 class 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 Accumulate();
55 
56  void Extend();
57 
58  void ChangeEncoding();
59 
60  INLINE(void ShrinkCurrentPart());
61 
62  template <bool is_ascii, typename Char>
63  INLINE(void Append_(Char c));
64 
65  template <bool is_ascii, typename Char>
66  INLINE(void Append_(const Char* chars));
67 
68  INLINE(void Append(uint8_t c)) {
69  if (is_ascii_) {
70  Append_<true>(c);
71  } else {
72  Append_<false>(c);
73  }
74  }
75 
76  INLINE(void AppendAscii(const char* chars)) {
77  if (is_ascii_) {
78  Append_<true>(reinterpret_cast<const uint8_t*>(chars));
79  } else {
80  Append_<false>(reinterpret_cast<const uint8_t*>(chars));
81  }
82  }
83 
84  Handle<Object> ApplyToJsonFunction(Handle<Object> object,
85  Handle<Object> key);
86 
87  Result SerializeGeneric(Handle<Object> object,
88  Handle<Object> key,
89  bool deferred_comma,
90  bool deferred_key);
91 
92  template <typename ResultType, typename Char>
93  INLINE(static MaybeObject* StringifyString_(Isolate* isolate,
94  Vector<Char> vector,
95  Handle<String> result));
96 
97  // Entry point to serialize the object.
98  INLINE(Result SerializeObject(Handle<Object> obj)) {
99  return Serialize_<false>(obj, false, factory_->empty_string());
100  }
101 
102  // Serialize an array element.
103  // The index may serve as argument for the toJSON function.
104  INLINE(Result SerializeElement(Isolate* isolate,
105  Handle<Object> object,
106  int i)) {
107  return Serialize_<false>(object,
108  false,
109  Handle<Object>(Smi::FromInt(i), isolate));
110  }
111 
112  // Serialize a object property.
113  // The key may or may not be serialized depending on the property.
114  // The key may also serve as argument for the toJSON function.
115  INLINE(Result SerializeProperty(Handle<Object> object,
116  bool deferred_comma,
117  Handle<String> deferred_key)) {
118  ASSERT(!deferred_key.is_null());
119  return Serialize_<true>(object, deferred_comma, deferred_key);
120  }
121 
122  template <bool deferred_string_key>
123  Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
124 
125  void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
126  if (deferred_comma) Append(',');
127  SerializeString(Handle<String>::cast(deferred_key));
128  Append(':');
129  }
130 
131  Result SerializeSmi(Smi* object);
132 
133  Result SerializeDouble(double number);
134  INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) {
135  return SerializeDouble(object->value());
136  }
137 
138  Result SerializeJSValue(Handle<JSValue> object);
139 
140  INLINE(Result SerializeJSArray(Handle<JSArray> object));
141  INLINE(Result SerializeJSObject(Handle<JSObject> object));
142 
143  Result SerializeJSArraySlow(Handle<JSArray> object, int length);
144 
145  void SerializeString(Handle<String> object);
146 
147  template <typename SrcChar, typename DestChar>
148  INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
149  DestChar* dest,
150  int length));
151 
152  template <bool is_ascii, typename Char>
153  INLINE(void SerializeString_(Handle<String> string));
154 
155  template <typename Char>
156  INLINE(static bool DoNotEscape(Char c));
157 
158  template <typename Char>
159  INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
160 
161  Result StackPush(Handle<Object> object);
162  void StackPop();
163 
164  INLINE(Handle<String> accumulator()) {
165  return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
166  }
167 
168  INLINE(void set_accumulator(Handle<String> string)) {
169  return accumulator_store_->set_value(*string);
170  }
171 
172  Isolate* isolate_;
173  Factory* factory_;
174  // We use a value wrapper for the string accumulator to keep the
175  // (indirect) handle to it in the outermost handle scope.
176  Handle<JSValue> accumulator_store_;
177  Handle<String> current_part_;
178  Handle<String> tojson_string_;
179  Handle<JSArray> stack_;
180  int current_index_;
181  int part_length_;
182  bool is_ascii_;
183  bool overflowed_;
184 
185  static const int kJsonEscapeTableEntrySize = 8;
186  static const char* const JsonEscapeTable;
187 };
188 
189 
190 // Translation table to escape ASCII characters.
191 // Table entries start at a multiple of 8 and are null-terminated.
192 const char* const BasicJsonStringifier::JsonEscapeTable =
193  "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 "
194  "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 "
195  "\\b\0 \\t\0 \\n\0 \\u000b\0 "
196  "\\f\0 \\r\0 \\u000e\0 \\u000f\0 "
197  "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 "
198  "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 "
199  "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 "
200  "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 "
201  " \0 !\0 \\\"\0 #\0 "
202  "$\0 %\0 &\0 '\0 "
203  "(\0 )\0 *\0 +\0 "
204  ",\0 -\0 .\0 /\0 "
205  "0\0 1\0 2\0 3\0 "
206  "4\0 5\0 6\0 7\0 "
207  "8\0 9\0 :\0 ;\0 "
208  "<\0 =\0 >\0 ?\0 "
209  "@\0 A\0 B\0 C\0 "
210  "D\0 E\0 F\0 G\0 "
211  "H\0 I\0 J\0 K\0 "
212  "L\0 M\0 N\0 O\0 "
213  "P\0 Q\0 R\0 S\0 "
214  "T\0 U\0 V\0 W\0 "
215  "X\0 Y\0 Z\0 [\0 "
216  "\\\\\0 ]\0 ^\0 _\0 "
217  "`\0 a\0 b\0 c\0 "
218  "d\0 e\0 f\0 g\0 "
219  "h\0 i\0 j\0 k\0 "
220  "l\0 m\0 n\0 o\0 "
221  "p\0 q\0 r\0 s\0 "
222  "t\0 u\0 v\0 w\0 "
223  "x\0 y\0 z\0 {\0 "
224  "|\0 }\0 ~\0 \177\0 "
225  "\200\0 \201\0 \202\0 \203\0 "
226  "\204\0 \205\0 \206\0 \207\0 "
227  "\210\0 \211\0 \212\0 \213\0 "
228  "\214\0 \215\0 \216\0 \217\0 "
229  "\220\0 \221\0 \222\0 \223\0 "
230  "\224\0 \225\0 \226\0 \227\0 "
231  "\230\0 \231\0 \232\0 \233\0 "
232  "\234\0 \235\0 \236\0 \237\0 "
233  "\240\0 \241\0 \242\0 \243\0 "
234  "\244\0 \245\0 \246\0 \247\0 "
235  "\250\0 \251\0 \252\0 \253\0 "
236  "\254\0 \255\0 \256\0 \257\0 "
237  "\260\0 \261\0 \262\0 \263\0 "
238  "\264\0 \265\0 \266\0 \267\0 "
239  "\270\0 \271\0 \272\0 \273\0 "
240  "\274\0 \275\0 \276\0 \277\0 "
241  "\300\0 \301\0 \302\0 \303\0 "
242  "\304\0 \305\0 \306\0 \307\0 "
243  "\310\0 \311\0 \312\0 \313\0 "
244  "\314\0 \315\0 \316\0 \317\0 "
245  "\320\0 \321\0 \322\0 \323\0 "
246  "\324\0 \325\0 \326\0 \327\0 "
247  "\330\0 \331\0 \332\0 \333\0 "
248  "\334\0 \335\0 \336\0 \337\0 "
249  "\340\0 \341\0 \342\0 \343\0 "
250  "\344\0 \345\0 \346\0 \347\0 "
251  "\350\0 \351\0 \352\0 \353\0 "
252  "\354\0 \355\0 \356\0 \357\0 "
253  "\360\0 \361\0 \362\0 \363\0 "
254  "\364\0 \365\0 \366\0 \367\0 "
255  "\370\0 \371\0 \372\0 \373\0 "
256  "\374\0 \375\0 \376\0 \377\0 ";
257 
258 
259 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
260  : isolate_(isolate),
261  current_index_(0),
262  is_ascii_(true),
263  overflowed_(false) {
264  factory_ = isolate_->factory();
265  accumulator_store_ = Handle<JSValue>::cast(
266  factory_->ToObject(factory_->empty_string()));
267  part_length_ = kInitialPartLength;
268  current_part_ = factory_->NewRawOneByteString(part_length_);
269  ASSERT(!current_part_.is_null());
270  tojson_string_ = factory_->toJSON_string();
271  stack_ = factory_->NewJSArray(8);
272 }
273 
274 
275 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) {
276  switch (SerializeObject(object)) {
277  case UNCHANGED:
278  return isolate_->heap()->undefined_value();
279  case SUCCESS: {
280  ShrinkCurrentPart();
281  Accumulate();
282  if (overflowed_) return isolate_->ThrowInvalidStringLength();
283  return *accumulator();
284  }
285  case CIRCULAR:
286  return isolate_->Throw(*factory_->NewTypeError(
287  "circular_structure", HandleVector<Object>(NULL, 0)));
288  case STACK_OVERFLOW:
289  return isolate_->StackOverflow();
290  default:
291  return Failure::Exception();
292  }
293 }
294 
295 
296 MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
297  Handle<String> object) {
298  static const int kJsonQuoteWorstCaseBlowup = 6;
299  static const int kSpaceForQuotes = 2;
300  int worst_case_length =
301  object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
302 
303  if (worst_case_length > 32 * KB) { // Slow path if too large.
304  BasicJsonStringifier stringifier(isolate);
305  return stringifier.Stringify(object);
306  }
307 
308  FlattenString(object);
309  ASSERT(object->IsFlat());
310  if (object->IsOneByteRepresentationUnderneath()) {
311  Handle<String> result =
312  isolate->factory()->NewRawOneByteString(worst_case_length);
313  ASSERT(!result.is_null());
315  return StringifyString_<SeqOneByteString>(
316  isolate,
317  object->GetFlatContent().ToOneByteVector(),
318  result);
319  } else {
320  Handle<String> result =
321  isolate->factory()->NewRawTwoByteString(worst_case_length);
322  ASSERT(!result.is_null());
324  return StringifyString_<SeqTwoByteString>(
325  isolate,
326  object->GetFlatContent().ToUC16Vector(),
327  result);
328  }
329 }
330 
331 
332 template <typename ResultType, typename Char>
333 MaybeObject* BasicJsonStringifier::StringifyString_(Isolate* isolate,
334  Vector<Char> vector,
335  Handle<String> result) {
337  int final_size = 0;
338  ResultType* dest = ResultType::cast(*result);
339  dest->Set(final_size++, '\"');
340  final_size += SerializeStringUnchecked_(vector.start(),
341  dest->GetChars() + 1,
342  vector.length());
343  dest->Set(final_size++, '\"');
344  return *SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
345 }
346 
347 
348 template <bool is_ascii, typename Char>
349 void BasicJsonStringifier::Append_(Char c) {
350  if (is_ascii) {
351  SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
352  current_index_++, c);
353  } else {
354  SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
355  current_index_++, c);
356  }
357  if (current_index_ == part_length_) Extend();
358 }
359 
360 
361 template <bool is_ascii, typename Char>
362 void BasicJsonStringifier::Append_(const Char* chars) {
363  for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars);
364 }
365 
366 
367 Handle<Object> BasicJsonStringifier::ApplyToJsonFunction(
368  Handle<Object> object, Handle<Object> key) {
369  LookupResult lookup(isolate_);
370  JSObject::cast(*object)->LookupRealNamedProperty(*tojson_string_, &lookup);
371  if (!lookup.IsProperty()) return object;
372  PropertyAttributes attr;
373  Handle<Object> fun =
374  Object::GetProperty(object, object, &lookup, tojson_string_, &attr);
375  if (fun.is_null()) return Handle<Object>::null();
376  if (!fun->IsJSFunction()) return object;
377 
378  // Call toJSON function.
379  if (key->IsSmi()) key = factory_->NumberToString(key);
380  Handle<Object> argv[] = { key };
381  bool has_exception = false;
382  HandleScope scope(isolate_);
383  object = Execution::Call(isolate_, fun, object, 1, argv, &has_exception);
384  // Return empty handle to signal an exception.
385  if (has_exception) return Handle<Object>::null();
386  return scope.CloseAndEscape(object);
387 }
388 
389 
390 BasicJsonStringifier::Result BasicJsonStringifier::StackPush(
391  Handle<Object> object) {
392  StackLimitCheck check(isolate_);
393  if (check.HasOverflowed()) return STACK_OVERFLOW;
394 
395  int length = Smi::cast(stack_->length())->value();
396  {
397  DisallowHeapAllocation no_allocation;
398  FixedArray* elements = FixedArray::cast(stack_->elements());
399  for (int i = 0; i < length; i++) {
400  if (elements->get(i) == *object) {
401  return CIRCULAR;
402  }
403  }
404  }
405  JSArray::EnsureSize(stack_, length + 1);
406  FixedArray::cast(stack_->elements())->set(length, *object);
407  stack_->set_length(Smi::FromInt(length + 1));
408  return SUCCESS;
409 }
410 
411 
412 void BasicJsonStringifier::StackPop() {
413  int length = Smi::cast(stack_->length())->value();
414  stack_->set_length(Smi::FromInt(length - 1));
415 }
416 
417 
418 template <bool deferred_string_key>
419 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
420  Handle<Object> object, bool comma, Handle<Object> key) {
421  if (object->IsJSObject()) {
422  object = ApplyToJsonFunction(object, key);
423  if (object.is_null()) return EXCEPTION;
424  }
425 
426  if (object->IsSmi()) {
427  if (deferred_string_key) SerializeDeferredKey(comma, key);
428  return SerializeSmi(Smi::cast(*object));
429  }
430 
431  switch (HeapObject::cast(*object)->map()->instance_type()) {
432  case HEAP_NUMBER_TYPE:
433  if (deferred_string_key) SerializeDeferredKey(comma, key);
434  return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
435  case ODDBALL_TYPE:
436  switch (Oddball::cast(*object)->kind()) {
437  case Oddball::kFalse:
438  if (deferred_string_key) SerializeDeferredKey(comma, key);
439  AppendAscii("false");
440  return SUCCESS;
441  case Oddball::kTrue:
442  if (deferred_string_key) SerializeDeferredKey(comma, key);
443  AppendAscii("true");
444  return SUCCESS;
445  case Oddball::kNull:
446  if (deferred_string_key) SerializeDeferredKey(comma, key);
447  AppendAscii("null");
448  return SUCCESS;
449  default:
450  return UNCHANGED;
451  }
452  case JS_ARRAY_TYPE:
453  if (object->IsAccessCheckNeeded()) break;
454  if (deferred_string_key) SerializeDeferredKey(comma, key);
455  return SerializeJSArray(Handle<JSArray>::cast(object));
456  case JS_VALUE_TYPE:
457  if (deferred_string_key) SerializeDeferredKey(comma, key);
458  return SerializeJSValue(Handle<JSValue>::cast(object));
459  case JS_FUNCTION_TYPE:
460  return UNCHANGED;
461  default:
462  if (object->IsString()) {
463  if (deferred_string_key) SerializeDeferredKey(comma, key);
464  SerializeString(Handle<String>::cast(object));
465  return SUCCESS;
466  } else if (object->IsJSObject()) {
467  if (object->IsAccessCheckNeeded()) break;
468  if (deferred_string_key) SerializeDeferredKey(comma, key);
469  return SerializeJSObject(Handle<JSObject>::cast(object));
470  }
471  }
472 
473  return SerializeGeneric(object, key, comma, deferred_string_key);
474 }
475 
476 
477 BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric(
478  Handle<Object> object,
479  Handle<Object> key,
480  bool deferred_comma,
481  bool deferred_key) {
482  Handle<JSObject> builtins(isolate_->native_context()->builtins());
483  Handle<JSFunction> builtin =
484  Handle<JSFunction>::cast(GetProperty(builtins, "JSONSerializeAdapter"));
485 
486  Handle<Object> argv[] = { key, object };
487  bool has_exception = false;
488  Handle<Object> result =
489  Execution::Call(isolate_, builtin, object, 2, argv, &has_exception);
490  if (has_exception) return EXCEPTION;
491  if (result->IsUndefined()) return UNCHANGED;
492  if (deferred_key) {
493  if (key->IsSmi()) key = factory_->NumberToString(key);
494  SerializeDeferredKey(deferred_comma, key);
495  }
496 
497  Handle<String> result_string = Handle<String>::cast(result);
498  // Shrink current part, attach it to the accumulator, also attach the result
499  // string to the accumulator, and allocate a new part.
500  ShrinkCurrentPart(); // Shrink.
501  part_length_ = kInitialPartLength; // Allocate conservatively.
502  Extend(); // Attach current part and allocate new part.
503  // Attach result string to the accumulator.
504  Handle<String> cons = factory_->NewConsString(accumulator(), result_string);
505  RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, cons, EXCEPTION);
506  set_accumulator(cons);
507  return SUCCESS;
508 }
509 
510 
511 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue(
512  Handle<JSValue> object) {
513  bool has_exception = false;
514  String* class_name = object->class_name();
515  if (class_name == isolate_->heap()->String_string()) {
516  Handle<Object> value =
517  Execution::ToString(isolate_, object, &has_exception);
518  if (has_exception) return EXCEPTION;
519  SerializeString(Handle<String>::cast(value));
520  } else if (class_name == isolate_->heap()->Number_string()) {
521  Handle<Object> value =
522  Execution::ToNumber(isolate_, object, &has_exception);
523  if (has_exception) return EXCEPTION;
524  if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
525  SerializeHeapNumber(Handle<HeapNumber>::cast(value));
526  } else {
527  ASSERT(class_name == isolate_->heap()->Boolean_string());
528  Object* value = JSValue::cast(*object)->value();
529  ASSERT(value->IsBoolean());
530  AppendAscii(value->IsTrue() ? "true" : "false");
531  }
532  return SUCCESS;
533 }
534 
535 
536 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) {
537  static const int kBufferSize = 100;
538  char chars[kBufferSize];
539  Vector<char> buffer(chars, kBufferSize);
540  AppendAscii(IntToCString(object->value(), buffer));
541  return SUCCESS;
542 }
543 
544 
545 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
546  double number) {
547  if (std::isinf(number) || std::isnan(number)) {
548  AppendAscii("null");
549  return SUCCESS;
550  }
551  static const int kBufferSize = 100;
552  char chars[kBufferSize];
553  Vector<char> buffer(chars, kBufferSize);
554  AppendAscii(DoubleToCString(number, buffer));
555  return SUCCESS;
556 }
557 
558 
559 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray(
560  Handle<JSArray> object) {
561  HandleScope handle_scope(isolate_);
562  Result stack_push = StackPush(object);
563  if (stack_push != SUCCESS) return stack_push;
564  int length = Smi::cast(object->length())->value();
565  Append('[');
566  switch (object->GetElementsKind()) {
567  case FAST_SMI_ELEMENTS: {
568  Handle<FixedArray> elements(
569  FixedArray::cast(object->elements()), isolate_);
570  for (int i = 0; i < length; i++) {
571  if (i > 0) Append(',');
572  SerializeSmi(Smi::cast(elements->get(i)));
573  }
574  break;
575  }
576  case FAST_DOUBLE_ELEMENTS: {
577  Handle<FixedDoubleArray> elements(
578  FixedDoubleArray::cast(object->elements()), isolate_);
579  for (int i = 0; i < length; i++) {
580  if (i > 0) Append(',');
581  SerializeDouble(elements->get_scalar(i));
582  }
583  break;
584  }
585  case FAST_ELEMENTS: {
586  Handle<FixedArray> elements(
587  FixedArray::cast(object->elements()), isolate_);
588  for (int i = 0; i < length; i++) {
589  if (i > 0) Append(',');
590  Result result =
591  SerializeElement(isolate_,
592  Handle<Object>(elements->get(i), isolate_),
593  i);
594  if (result == SUCCESS) continue;
595  if (result == UNCHANGED) {
596  AppendAscii("null");
597  } else {
598  return result;
599  }
600  }
601  break;
602  }
603  // TODO(yangguo): The FAST_HOLEY_* cases could be handled in a faster way.
604  // They resemble the non-holey cases except that a prototype chain lookup
605  // is necessary for holes.
606  default: {
607  Result result = SerializeJSArraySlow(object, length);
608  if (result != SUCCESS) return result;
609  break;
610  }
611  }
612  Append(']');
613  StackPop();
614  current_part_ = handle_scope.CloseAndEscape(current_part_);
615  return SUCCESS;
616 }
617 
618 
619 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
620  Handle<JSArray> object, int length) {
621  for (int i = 0; i < length; i++) {
622  if (i > 0) Append(',');
623  Handle<Object> element = Object::GetElement(isolate_, object, i);
624  RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, element, EXCEPTION);
625  if (element->IsUndefined()) {
626  AppendAscii("null");
627  } else {
628  Result result = SerializeElement(isolate_, element, i);
629  if (result == SUCCESS) continue;
630  if (result == UNCHANGED) {
631  AppendAscii("null");
632  } else {
633  return result;
634  }
635  }
636  }
637  return SUCCESS;
638 }
639 
640 
641 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
642  Handle<JSObject> object) {
643  HandleScope handle_scope(isolate_);
644  Result stack_push = StackPush(object);
645  if (stack_push != SUCCESS) return stack_push;
646  if (object->IsJSGlobalProxy()) {
647  object = Handle<JSObject>(
648  JSObject::cast(object->GetPrototype()), isolate_);
649  ASSERT(object->IsGlobalObject());
650  }
651 
652  Append('{');
653  bool comma = false;
654 
655  if (object->HasFastProperties() &&
656  !object->HasIndexedInterceptor() &&
657  !object->HasNamedInterceptor() &&
658  object->elements()->length() == 0) {
659  Handle<Map> map(object->map());
660  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
661  Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
662  // TODO(rossberg): Should this throw?
663  if (!name->IsString()) continue;
664  Handle<String> key = Handle<String>::cast(name);
665  PropertyDetails details = map->instance_descriptors()->GetDetails(i);
666  if (details.IsDontEnum()) continue;
667  Handle<Object> property;
668  if (details.type() == FIELD && *map == object->map()) {
669  property = Handle<Object>(
670  object->RawFastPropertyAt(
671  map->instance_descriptors()->GetFieldIndex(i)),
672  isolate_);
673  } else {
674  property = GetProperty(isolate_, object, key);
675  RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, property, EXCEPTION);
676  }
677  Result result = SerializeProperty(property, comma, key);
678  if (!comma && result == SUCCESS) comma = true;
679  if (result >= EXCEPTION) return result;
680  }
681  } else {
682  bool has_exception = false;
683  Handle<FixedArray> contents =
684  GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception);
685  if (has_exception) return EXCEPTION;
686 
687  for (int i = 0; i < contents->length(); i++) {
688  Object* key = contents->get(i);
689  Handle<String> key_handle;
690  Handle<Object> property;
691  if (key->IsString()) {
692  key_handle = Handle<String>(String::cast(key), isolate_);
693  property = GetProperty(isolate_, object, key_handle);
694  } else {
695  ASSERT(key->IsNumber());
696  key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
697  uint32_t index;
698  if (key->IsSmi()) {
699  property = Object::GetElement(
700  isolate_, object, Smi::cast(key)->value());
701  } else if (key_handle->AsArrayIndex(&index)) {
702  property = Object::GetElement(isolate_, object, index);
703  } else {
704  property = GetProperty(isolate_, object, key_handle);
705  }
706  }
707  RETURN_IF_EMPTY_HANDLE_VALUE(isolate_, property, EXCEPTION);
708  Result result = SerializeProperty(property, comma, key_handle);
709  if (!comma && result == SUCCESS) comma = true;
710  if (result >= EXCEPTION) return result;
711  }
712  }
713 
714  Append('}');
715  StackPop();
716  current_part_ = handle_scope.CloseAndEscape(current_part_);
717  return SUCCESS;
718 }
719 
720 
721 void BasicJsonStringifier::ShrinkCurrentPart() {
722  ASSERT(current_index_ < part_length_);
723  current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
724  current_index_);
725 }
726 
727 
728 void BasicJsonStringifier::Accumulate() {
729  if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
730  // Screw it. Simply set the flag and carry on. Throw exception at the end.
731  set_accumulator(factory_->empty_string());
732  overflowed_ = true;
733  } else {
734  set_accumulator(factory_->NewConsString(accumulator(), current_part_));
735  }
736 }
737 
738 
740  Accumulate();
741  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
742  part_length_ *= kPartLengthGrowthFactor;
743  }
744  if (is_ascii_) {
745  current_part_ = factory_->NewRawOneByteString(part_length_);
746  } else {
747  current_part_ = factory_->NewRawTwoByteString(part_length_);
748  }
749  ASSERT(!current_part_.is_null());
750  current_index_ = 0;
751 }
752 
753 
754 void BasicJsonStringifier::ChangeEncoding() {
755  ShrinkCurrentPart();
756  Accumulate();
757  current_part_ = factory_->NewRawTwoByteString(part_length_);
758  ASSERT(!current_part_.is_null());
759  current_index_ = 0;
760  is_ascii_ = false;
761 }
762 
763 
764 template <typename SrcChar, typename DestChar>
765 int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
766  DestChar* dest,
767  int length) {
768  DestChar* dest_start = dest;
769 
770  // Assert that uc16 character is not truncated down to 8 bit.
771  // The <uc16, char> version of this method must not be called.
772  ASSERT(sizeof(*dest) >= sizeof(*src));
773 
774  for (int i = 0; i < length; i++) {
775  SrcChar c = src[i];
776  if (DoNotEscape(c)) {
777  *(dest++) = static_cast<DestChar>(c);
778  } else {
779  const uint8_t* chars = reinterpret_cast<const uint8_t*>(
780  &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
781  while (*chars != '\0') *(dest++) = *(chars++);
782  }
783  }
784 
785  return static_cast<int>(dest - dest_start);
786 }
787 
788 
789 template <bool is_ascii, typename Char>
790 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
791  int length = string->length();
792  Append_<is_ascii, char>('"');
793  // We make a rough estimate to find out if the current string can be
794  // serialized without allocating a new string part. The worst case length of
795  // an escaped character is 6. Shifting the remainin string length right by 3
796  // is a more pessimistic estimate, but faster to calculate.
797 
798  if (((part_length_ - current_index_) >> 3) > length) {
800  Vector<const Char> vector = GetCharVector<Char>(string);
801  if (is_ascii) {
802  current_index_ += SerializeStringUnchecked_(
803  vector.start(),
804  SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
805  length);
806  } else {
807  current_index_ += SerializeStringUnchecked_(
808  vector.start(),
809  SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
810  length);
811  }
812  } else {
813  String* string_location = NULL;
814  Vector<const Char> vector(NULL, 0);
815  for (int i = 0; i < length; i++) {
816  // If GC moved the string, we need to refresh the vector.
817  if (*string != string_location) {
819  // This does not actually prevent the string from being relocated later.
820  vector = GetCharVector<Char>(string);
821  string_location = *string;
822  }
823  Char c = vector[i];
824  if (DoNotEscape(c)) {
825  Append_<is_ascii, Char>(c);
826  } else {
827  Append_<is_ascii, uint8_t>(reinterpret_cast<const uint8_t*>(
828  &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
829  }
830  }
831  }
832 
833  Append_<is_ascii, uint8_t>('"');
834 }
835 
836 
837 template <>
838 bool BasicJsonStringifier::DoNotEscape(uint8_t c) {
839  return c >= '#' && c <= '~' && c != '\\';
840 }
841 
842 
843 template <>
844 bool BasicJsonStringifier::DoNotEscape(uint16_t c) {
845  return c >= '#' && c != '\\' && c != 0x7f;
846 }
847 
848 
849 template <>
850 Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
851  Handle<String> string) {
852  String::FlatContent flat = string->GetFlatContent();
853  ASSERT(flat.IsAscii());
854  return flat.ToOneByteVector();
855 }
856 
857 
858 template <>
859 Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
860  String::FlatContent flat = string->GetFlatContent();
861  ASSERT(flat.IsTwoByte());
862  return flat.ToUC16Vector();
863 }
864 
865 
866 void BasicJsonStringifier::SerializeString(Handle<String> object) {
867  object = FlattenGetString(object);
868  if (is_ascii_) {
869  if (object->IsOneByteRepresentationUnderneath()) {
870  SerializeString_<true, uint8_t>(object);
871  } else {
872  ChangeEncoding();
873  SerializeString(object);
874  }
875  } else {
876  if (object->IsOneByteRepresentationUnderneath()) {
877  SerializeString_<false, uint8_t>(object);
878  } else {
879  SerializeString_<false, uc16>(object);
880  }
881  }
882 }
883 
884 } } // namespace v8::internal
885 
886 #endif // V8_JSON_STRINGIFIER_H_
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
void FlattenString(Handle< String > string)
Definition: handles.cc:151
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths true
Definition: flags.cc:208
static String * cast(Object *obj)
Vector< const uint8_t > GetCharVector(Handle< String > string)
Definition: uri.h:46
static Smi * FromInt(int value)
Definition: objects-inl.h:1209
const int KB
Definition: globals.h:245
static Handle< String > cast(Handle< S > that)
Definition: handles.h:75
kSerializedDataOffset Object
Definition: objects-inl.h:5016
#define ASSERT(condition)
Definition: checks.h:329
unsigned short uint16_t
Definition: unicode.cc:46
Handle< Object > GetProperty(Handle< JSReceiver > obj, const char *name)
Definition: handles.cc:196
PropertyAttributes
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in name
#define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value)
Definition: isolate.h:137
Handle< String > FlattenGetString(Handle< String > string)
Definition: handles.cc:156
int isnan(double x)
const char * IntToCString(int n, Vector< char > buffer)
Definition: conversions.cc:136
void check(i::Vector< const uint8_t > string)
const char * DoubleToCString(double v, Vector< char > buffer)
Definition: conversions.cc:81
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf map
Handle< FixedArray > GetKeysInFixedArrayFor(Handle< JSReceiver > object, KeyCollectionType type, bool *threw)
Definition: handles.cc:505
#define BASE_EMBEDDED
Definition: allocation.h:68
int isinf(double x)
V8_INLINE bool IsString() const
Definition: v8.h:6265
int ToNumber(Register reg)
INLINE(static HeapObject *EnsureDoubleAligned(Heap *heap, HeapObject *object, int size))
PerThreadAssertScopeDebugOnly< HEAP_ALLOCATION_ASSERT, false > DisallowHeapAllocation
Definition: assert-scope.h:214
HeapObject * obj