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