OLD | NEW |
| (Empty) |
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 private: | |
45 static const int kInitialPartLength = 32; | |
46 static const int kMaxPartLength = 16 * 1024; | |
47 static const int kPartLengthGrowthFactor = 2; | |
48 static const int kStackLimit = 8 * 1024; | |
49 | |
50 enum Result { UNCHANGED, SUCCESS, BAILOUT, CIRCULAR, STACK_OVERFLOW }; | |
51 | |
52 template <bool is_ascii> void Extend(); | |
53 | |
54 void ChangeEncoding(); | |
55 | |
56 void ShrinkCurrentPart(); | |
57 | |
58 template <bool is_ascii, typename Char> | |
59 INLINE(void Append_(Char c)); | |
60 | |
61 template <bool is_ascii, typename Char> | |
62 INLINE(void AppendUnchecked_(Char c)); | |
63 | |
64 template <bool is_ascii, typename Char> | |
65 INLINE(void Append_(Char* chars)); | |
66 | |
67 template <bool is_ascii, typename Char> | |
68 INLINE(void Append_(const Char* chars)); | |
69 | |
70 template <bool is_ascii, typename Char> | |
71 INLINE(void AppendUnchecked_(const Char* chars)); | |
72 | |
73 INLINE(void Append(char c)) { | |
74 if (is_ascii_) { | |
75 Append_<true>(c); | |
76 } else { | |
77 Append_<false>(c); | |
78 } | |
79 } | |
80 | |
81 INLINE(void Append(const char* chars)) { | |
82 if (is_ascii_) { | |
83 Append_<true>(chars); | |
84 } else { | |
85 Append_<false>(chars); | |
86 } | |
87 } | |
88 | |
89 INLINE(Handle<Object> GetProperty(Handle<JSObject> object, | |
90 Handle<String> key)); | |
91 | |
92 INLINE(bool MayHaveToJsonFunction(Handle<JSObject> object)); | |
93 | |
94 INLINE(Result Serialize(Handle<Object> object)) { | |
95 return Serialize_<false>(object); | |
96 } | |
97 | |
98 INLINE(Result SerializeDeferred(Handle<Object> object, | |
99 bool deferred_comma, | |
100 Handle<String> deferred_key)) { | |
101 ASSERT(!deferred_key.is_null()); | |
102 return Serialize_<true>(object, deferred_comma, deferred_key); | |
103 } | |
104 | |
105 template <bool deferred_key> | |
106 Result Serialize_(Handle<Object> object, | |
107 bool comma = false, | |
108 Handle<String> key = Handle<String>::null()); | |
109 | |
110 INLINE(void SerializeDeferredKey(bool deferred_comma, | |
111 Handle<String> deferred_key)) { | |
112 if (deferred_comma) Append(','); | |
113 SerializeString(deferred_key); | |
114 Append(':'); | |
115 } | |
116 | |
117 INLINE(Result SerializeSmi(Smi* object)); | |
118 | |
119 INLINE(Result SerializeDouble(double number)); | |
120 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) { | |
121 return SerializeDouble(object->value()); | |
122 } | |
123 | |
124 Result SerializeArray(Handle<JSArray> object); | |
125 Result SerializeObject(Handle<JSObject> object); | |
126 | |
127 void SerializeString(Handle<String> object); | |
128 | |
129 template <bool is_ascii, typename Char> | |
130 INLINE(void SerializeString_(Vector<const Char> vector)); | |
131 | |
132 INLINE(Result StackPush(Handle<Object> object)); | |
133 INLINE(void StackPop()); | |
134 | |
135 INLINE(Handle<String> accumulator()) { | |
136 return Handle<String>(String::cast(accumulator_store_->value())); | |
137 } | |
138 | |
139 INLINE(void set_accumulator(Handle<String> string)) { | |
140 return accumulator_store_->set_value(*string); | |
141 } | |
142 | |
143 Isolate* isolate_; | |
144 // We use a value wrapper for the string accumulator to keep the | |
145 // (indirect) handle to it in the outermost handle scope. | |
146 Handle<JSValue> accumulator_store_; | |
147 Handle<String> current_part_; | |
148 Handle<String> tojson_symbol_; | |
149 Handle<JSArray> stack_; | |
150 int current_index_; | |
151 int part_length_; | |
152 bool is_ascii_; | |
153 | |
154 static const int kJsonQuotesCharactersPerEntry = 8; | |
155 static const char* const JsonQuotes; | |
156 }; | |
157 | |
158 | |
159 const char* const BasicJsonStringifier::JsonQuotes = | |
160 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " | |
161 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " | |
162 "\\b\0 \\t\0 \\n\0 \\u000b\0 " | |
163 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " | |
164 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " | |
165 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " | |
166 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " | |
167 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " | |
168 " \0 !\0 \\\"\0 #\0 " | |
169 "$\0 %\0 &\0 '\0 " | |
170 "(\0 )\0 *\0 +\0 " | |
171 ",\0 -\0 .\0 /\0 " | |
172 "0\0 1\0 2\0 3\0 " | |
173 "4\0 5\0 6\0 7\0 " | |
174 "8\0 9\0 :\0 ;\0 " | |
175 "<\0 =\0 >\0 ?\0 " | |
176 "@\0 A\0 B\0 C\0 " | |
177 "D\0 E\0 F\0 G\0 " | |
178 "H\0 I\0 J\0 K\0 " | |
179 "L\0 M\0 N\0 O\0 " | |
180 "P\0 Q\0 R\0 S\0 " | |
181 "T\0 U\0 V\0 W\0 " | |
182 "X\0 Y\0 Z\0 [\0 " | |
183 "\\\\\0 ]\0 ^\0 _\0 " | |
184 "`\0 a\0 b\0 c\0 " | |
185 "d\0 e\0 f\0 g\0 " | |
186 "h\0 i\0 j\0 k\0 " | |
187 "l\0 m\0 n\0 o\0 " | |
188 "p\0 q\0 r\0 s\0 " | |
189 "t\0 u\0 v\0 w\0 " | |
190 "x\0 y\0 z\0 {\0 " | |
191 "|\0 }\0 ~\0 \177\0 "; | |
192 | |
193 | |
194 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) | |
195 : isolate_(isolate), current_index_(0), is_ascii_(true) { | |
196 accumulator_store_ = Handle<JSValue>::cast( | |
197 isolate_->factory()->ToObject(isolate_->factory()->empty_string())); | |
198 part_length_ = kInitialPartLength; | |
199 current_part_ = | |
200 isolate_->factory()->NewRawAsciiString(kInitialPartLength); | |
201 tojson_symbol_ = isolate_->factory()->LookupAsciiSymbol("toJSON"); | |
202 stack_ = isolate_->factory()->NewJSArray(8); | |
203 } | |
204 | |
205 | |
206 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) { | |
207 switch (Serialize(object)) { | |
208 case SUCCESS: | |
209 ShrinkCurrentPart(); | |
210 return *isolate_->factory()->NewConsString(accumulator(), current_part_); | |
211 case UNCHANGED: | |
212 return isolate_->heap()->undefined_value(); | |
213 case CIRCULAR: | |
214 return isolate_->Throw(*isolate_->factory()->NewTypeError( | |
215 "circular_structure", HandleVector<Object>(NULL, 0))); | |
216 case STACK_OVERFLOW: | |
217 return isolate_->StackOverflow(); | |
218 default: | |
219 return Smi::FromInt(0); | |
220 } | |
221 } | |
222 | |
223 | |
224 template <bool is_ascii, typename Char> | |
225 void BasicJsonStringifier::Append_(Char c) { | |
226 if (is_ascii) { | |
227 SeqAsciiString::cast(*current_part_)->SeqAsciiStringSet( | |
228 current_index_++, c); | |
229 } else { | |
230 SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet( | |
231 current_index_++, c); | |
232 } | |
233 if (current_index_ == part_length_) Extend<is_ascii>(); | |
234 } | |
235 | |
236 | |
237 template <bool is_ascii, typename Char> | |
238 void BasicJsonStringifier::AppendUnchecked_(Char c) { | |
239 if (is_ascii) { | |
240 SeqAsciiString::cast(*current_part_)->SeqAsciiStringSet( | |
241 current_index_++, c); | |
242 } else { | |
243 SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet( | |
244 current_index_++, c); | |
245 } | |
246 ASSERT(current_index_ < part_length_); | |
247 } | |
248 | |
249 | |
250 template <bool is_ascii, typename Char> | |
251 void BasicJsonStringifier::Append_(Char* chars) { | |
252 for ( ; *chars != '\0'; chars++) Append_<is_ascii>(*chars); | |
253 } | |
254 | |
255 | |
256 template <bool is_ascii, typename Char> | |
257 void BasicJsonStringifier::Append_(const Char* chars) { | |
258 for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars); | |
259 } | |
260 | |
261 | |
262 template <bool is_ascii, typename Char> | |
263 void BasicJsonStringifier::AppendUnchecked_(const Char* chars) { | |
264 for ( ; *chars != '\0'; chars++) AppendUnchecked_<is_ascii, Char>(*chars); | |
265 } | |
266 | |
267 | |
268 Handle<Object> BasicJsonStringifier::GetProperty(Handle<JSObject> object, | |
269 Handle<String> key) { | |
270 LookupResult lookup(isolate_); | |
271 object->LocalLookupRealNamedProperty(*key, &lookup); | |
272 if (!lookup.IsProperty()) return isolate_->factory()->undefined_value(); | |
273 switch (lookup.type()) { | |
274 case NORMAL: { | |
275 Object* value = lookup.holder()->GetNormalizedProperty(&lookup); | |
276 ASSERT(!value->IsTheHole()); | |
277 return Handle<Object>(value); | |
278 } | |
279 case FIELD: { | |
280 Object* value = lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); | |
281 ASSERT(!value->IsTheHole()); | |
282 return Handle<Object>(value); | |
283 } | |
284 case CONSTANT_FUNCTION: | |
285 return Handle<Object>(lookup.GetConstantFunction()); | |
286 case CALLBACKS: | |
287 case HANDLER: | |
288 case INTERCEPTOR: | |
289 return Handle<Object>::null(); | |
290 case TRANSITION: | |
291 case NONEXISTENT: | |
292 UNREACHABLE(); | |
293 break; | |
294 } | |
295 return Handle<Object>::null(); | |
296 } | |
297 | |
298 | |
299 bool BasicJsonStringifier::MayHaveToJsonFunction(Handle<JSObject> object) { | |
300 LookupResult lookup(isolate_); | |
301 object->LookupRealNamedProperty(*tojson_symbol_, &lookup); | |
302 if (!lookup.IsProperty()) return false; | |
303 Object* value; | |
304 switch (lookup.type()) { | |
305 case NORMAL: | |
306 value = lookup.holder()->GetNormalizedProperty(&lookup); | |
307 break; | |
308 case FIELD: | |
309 value = lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); | |
310 break; | |
311 default: | |
312 return true; | |
313 } | |
314 ASSERT(!value->IsTheHole()); | |
315 return value->IsSpecFunction(); | |
316 } | |
317 | |
318 | |
319 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( | |
320 Handle<Object> object) { | |
321 int length = Smi::cast(stack_->length())->value(); | |
322 if (length > kStackLimit) return STACK_OVERFLOW; | |
323 FixedArray* elements = FixedArray::cast(stack_->elements()); | |
324 for (int i = 0; i < length; i++) { | |
325 if (elements->get(i) == *object) { | |
326 return CIRCULAR; | |
327 } | |
328 } | |
329 stack_->EnsureSize(length + 1); | |
330 FixedArray::cast(stack_->elements())->set(length, *object); | |
331 stack_->set_length(Smi::FromInt(length + 1)); | |
332 return SUCCESS; | |
333 } | |
334 | |
335 | |
336 void BasicJsonStringifier::StackPop() { | |
337 int length = Smi::cast(stack_->length())->value(); | |
338 stack_->set_length(Smi::FromInt(length - 1)); | |
339 } | |
340 | |
341 | |
342 template <bool deferred_key> | |
343 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( | |
344 Handle<Object> object, bool comma, Handle<String> key) { | |
345 if (object->IsJSObject()) { | |
346 // We don't deal with custom toJSON functions. | |
347 if (MayHaveToJsonFunction(Handle<JSObject>::cast(object))) return BAILOUT; | |
348 | |
349 if (object->IsJSFunction()) { | |
350 return UNCHANGED; | |
351 } else if (object->IsJSArray()) { | |
352 if (deferred_key) SerializeDeferredKey(comma, key); | |
353 return SerializeArray(Handle<JSArray>::cast(object)); | |
354 } else if (object->IsJSValue()) { | |
355 // JSValue with a custom prototype. | |
356 if (object->GetPrototype()->IsJSReceiver()) return BAILOUT; | |
357 // Unpack value wrapper and fall through. | |
358 object = Handle<Object>(JSValue::cast(*object)->value()); | |
359 } else { | |
360 if (deferred_key) SerializeDeferredKey(comma, key); | |
361 return SerializeObject(Handle<JSObject>::cast(object)); | |
362 } | |
363 } | |
364 | |
365 if (object->IsString()) { | |
366 if (deferred_key) SerializeDeferredKey(comma, key); | |
367 SerializeString(Handle<String>::cast(object)); | |
368 return SUCCESS; | |
369 } else if (object->IsSmi()) { | |
370 if (deferred_key) SerializeDeferredKey(comma, key); | |
371 return SerializeSmi(Smi::cast(*object)); | |
372 } else if (object->IsHeapNumber()) { | |
373 if (deferred_key) SerializeDeferredKey(comma, key); | |
374 return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); | |
375 } else if (object->IsOddball()) { | |
376 switch (Oddball::cast(*object)->kind()) { | |
377 case Oddball::kFalse: | |
378 if (deferred_key) SerializeDeferredKey(comma, key); | |
379 Append("false"); | |
380 return SUCCESS; | |
381 case Oddball::kTrue: | |
382 if (deferred_key) SerializeDeferredKey(comma, key); | |
383 Append("true"); | |
384 return SUCCESS; | |
385 case Oddball::kNull: | |
386 if (deferred_key) SerializeDeferredKey(comma, key); | |
387 Append("null"); | |
388 return SUCCESS; | |
389 } | |
390 } | |
391 | |
392 return UNCHANGED; | |
393 } | |
394 | |
395 | |
396 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { | |
397 static const int kBufferSize = 100; | |
398 char chars[kBufferSize]; | |
399 Vector<char> buffer(chars, kBufferSize); | |
400 Append(IntToCString(object->value(), buffer)); | |
401 return SUCCESS; | |
402 } | |
403 | |
404 | |
405 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( | |
406 double number) { | |
407 if (isinf(number) || isnan(number)) { | |
408 Append("null"); | |
409 return SUCCESS; | |
410 } | |
411 static const int kBufferSize = 100; | |
412 char chars[kBufferSize]; | |
413 Vector<char> buffer(chars, kBufferSize); | |
414 Append(DoubleToCString(number, buffer)); | |
415 return SUCCESS; | |
416 } | |
417 | |
418 | |
419 BasicJsonStringifier::Result BasicJsonStringifier::SerializeArray( | |
420 Handle<JSArray> object) { | |
421 HandleScope handle_scope(isolate_); | |
422 if (StackPush(object) == CIRCULAR) return CIRCULAR; | |
423 int length = Smi::cast(object->length())->value(); | |
424 Append('['); | |
425 switch (object->GetElementsKind()) { | |
426 case FAST_SMI_ELEMENTS: { | |
427 Handle<FixedArray> elements = Handle<FixedArray>( | |
428 FixedArray::cast(object->elements())); | |
429 for (int i = 0; i < length; i++) { | |
430 if (i > 0) Append(','); | |
431 SerializeSmi(Smi::cast(elements->get(i))); | |
432 } | |
433 break; | |
434 } | |
435 case FAST_HOLEY_SMI_ELEMENTS: { | |
436 Handle<FixedArray> elements = Handle<FixedArray>( | |
437 FixedArray::cast(object->elements())); | |
438 for (int i = 0; i < length; i++) { | |
439 if (i > 0) Append(','); | |
440 if (elements->is_the_hole(i)) { | |
441 Append("null"); | |
442 } else { | |
443 SerializeSmi(Smi::cast(elements->get(i))); | |
444 } | |
445 } | |
446 break; | |
447 } | |
448 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
449 case FAST_DOUBLE_ELEMENTS: { | |
450 Handle<FixedDoubleArray> elements = Handle<FixedDoubleArray>( | |
451 FixedDoubleArray::cast(object->elements())); | |
452 for (int i = 0; i < length; i++) { | |
453 if (i > 0) Append(','); | |
454 SerializeDouble(elements->get_scalar(i)); | |
455 } | |
456 break; | |
457 } | |
458 case FAST_HOLEY_ELEMENTS: | |
459 case FAST_ELEMENTS: { | |
460 Handle<FixedArray> elements = Handle<FixedArray>( | |
461 FixedArray::cast(object->elements())); | |
462 for (int i = 0; i < length; i++) { | |
463 if (i > 0) Append(','); | |
464 Result result = Serialize(Handle<Object>(elements->get(i))); | |
465 if (result == SUCCESS) continue; | |
466 if (result == UNCHANGED) { | |
467 Append("null"); | |
468 } else { | |
469 return result; | |
470 } | |
471 } | |
472 break; | |
473 } | |
474 default: | |
475 return BAILOUT; | |
476 } | |
477 Append(']'); | |
478 StackPop(); | |
479 current_part_ = handle_scope.CloseAndEscape(current_part_); | |
480 return SUCCESS; | |
481 } | |
482 | |
483 | |
484 BasicJsonStringifier::Result BasicJsonStringifier::SerializeObject( | |
485 Handle<JSObject> object) { | |
486 HandleScope handle_scope(isolate_); | |
487 Result stack_push = StackPush(object); | |
488 if (stack_push != SUCCESS) return stack_push; | |
489 if (object->IsJSGlobalProxy()) return BAILOUT; | |
490 bool threw = false; | |
491 Handle<FixedArray> contents = | |
492 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw); | |
493 if (threw) return BAILOUT; | |
494 Append('{'); | |
495 int length = contents->length(); | |
496 bool comma = false; | |
497 for (int i = 0; i < length; i++) { | |
498 Object* key = contents->get(i); | |
499 Handle<String> key_handle; | |
500 Handle<Object> property; | |
501 if (key->IsString()) { | |
502 key_handle = Handle<String>(String::cast(key)); | |
503 property = GetProperty(object, key_handle); | |
504 } else { | |
505 ASSERT(key->IsNumber()); | |
506 key_handle = isolate_->factory()->NumberToString(Handle<Object>(key)); | |
507 uint32_t index; | |
508 if (key->IsSmi()) { | |
509 property = Object::GetElement(object, Smi::cast(key)->value()); | |
510 } else if (key_handle->AsArrayIndex(&index)) { | |
511 property = Object::GetElement(object, index); | |
512 } else { | |
513 property = GetProperty(object, key_handle); | |
514 } | |
515 } | |
516 if (property.is_null()) return BAILOUT; | |
517 Result result = SerializeDeferred(property, comma, key_handle); | |
518 if (!comma && result == SUCCESS) comma = true; | |
519 if (result >= BAILOUT) return result; | |
520 } | |
521 Append('}'); | |
522 StackPop(); | |
523 current_part_ = handle_scope.CloseAndEscape(current_part_); | |
524 return SUCCESS; | |
525 } | |
526 | |
527 | |
528 void BasicJsonStringifier::ShrinkCurrentPart() { | |
529 ASSERT(current_index_ < part_length_); | |
530 if (current_index_ == 0) { | |
531 current_part_ = isolate_->factory()->empty_string(); | |
532 return; | |
533 } | |
534 | |
535 int string_size, allocated_string_size; | |
536 if (is_ascii_) { | |
537 allocated_string_size = SeqAsciiString::SizeFor(part_length_); | |
538 string_size = SeqAsciiString::SizeFor(current_index_); | |
539 } else { | |
540 allocated_string_size = SeqTwoByteString::SizeFor(part_length_); | |
541 string_size = SeqTwoByteString::SizeFor(current_index_); | |
542 } | |
543 | |
544 int delta = allocated_string_size - string_size; | |
545 current_part_->set_length(current_index_); | |
546 | |
547 // String sizes are pointer size aligned, so that we can use filler objects | |
548 // that are a multiple of pointer size. | |
549 Address end_of_string = current_part_->address() + string_size; | |
550 isolate_->heap()->CreateFillerObjectAt(end_of_string, delta); | |
551 if (Marking::IsBlack(Marking::MarkBitFrom(*current_part_))) { | |
552 MemoryChunk::IncrementLiveBytesFromMutator( | |
553 current_part_->address(), -delta); | |
554 } | |
555 } | |
556 | |
557 | |
558 template <bool is_ascii> | |
559 void BasicJsonStringifier::Extend() { | |
560 set_accumulator( | |
561 isolate_->factory()->NewConsString(accumulator(), current_part_)); | |
562 if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { | |
563 part_length_ *= kPartLengthGrowthFactor; | |
564 } | |
565 if (is_ascii) { | |
566 current_part_ = | |
567 isolate_->factory()->NewRawAsciiString(part_length_); | |
568 } else { | |
569 current_part_ = | |
570 isolate_->factory()->NewRawTwoByteString(part_length_); | |
571 } | |
572 current_index_ = 0; | |
573 } | |
574 | |
575 | |
576 void BasicJsonStringifier::ChangeEncoding() { | |
577 ShrinkCurrentPart(); | |
578 set_accumulator( | |
579 isolate_->factory()->NewConsString(accumulator(), current_part_)); | |
580 current_part_ = | |
581 isolate_->factory()->NewRawTwoByteString(part_length_); | |
582 current_index_ = 0; | |
583 is_ascii_ = false; | |
584 } | |
585 | |
586 | |
587 template <bool is_ascii, typename Char> | |
588 void BasicJsonStringifier::SerializeString_(Vector<const Char> vector) { | |
589 int length = vector.length(); | |
590 if (current_index_ + (length << 3) < (part_length_ - 2)) { | |
591 AppendUnchecked_<is_ascii, char>('"'); | |
592 for (int i = 0; i < length; i++) { | |
593 Char c = vector[i]; | |
594 if ((c >= '#' && c <= '~' && c != '\\') || | |
595 (!is_ascii && ((c & 0xFF80) != 0))) { | |
596 AppendUnchecked_<is_ascii, Char>(c); | |
597 } else { | |
598 AppendUnchecked_<is_ascii, char>( | |
599 &JsonQuotes[c * kJsonQuotesCharactersPerEntry]); | |
600 } | |
601 } | |
602 AppendUnchecked_<is_ascii, char>('"'); | |
603 } else { | |
604 Append_<is_ascii, char>('"'); | |
605 for (int i = 0; i < length; i++) { | |
606 Char c = vector[i]; | |
607 if ((c >= '#' && c <= '~' && c != '\\') || | |
608 (!is_ascii && ((c & 0xFF80) != 0))) { | |
609 Append_<is_ascii, Char>(c); | |
610 } else { | |
611 Append_<is_ascii, char>(&JsonQuotes[c * kJsonQuotesCharactersPerEntry]); | |
612 } | |
613 } | |
614 Append_<is_ascii, char>('"'); | |
615 } | |
616 } | |
617 | |
618 | |
619 void BasicJsonStringifier::SerializeString(Handle<String> object) { | |
620 FlattenString(object); | |
621 String::FlatContent flat = object->GetFlatContent(); | |
622 if (is_ascii_) { | |
623 if (flat.IsAscii()) { | |
624 SerializeString_<true, char>(flat.ToAsciiVector()); | |
625 } else { | |
626 ChangeEncoding(); | |
627 SerializeString(object); | |
628 } | |
629 } else { | |
630 if (flat.IsAscii()) { | |
631 SerializeString_<false, char>(flat.ToAsciiVector()); | |
632 } else { | |
633 SerializeString_<false, uc16>(flat.ToUC16Vector()); | |
634 } | |
635 } | |
636 } | |
637 | |
638 } } // namespace v8::internal | |
639 | |
640 #endif // V8_JSON_STRINGIFIER_H_ | |
OLD | NEW |