OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 28 matching lines...) Expand all Loading... |
39 public: | 39 public: |
40 explicit BasicJsonStringifier(Isolate* isolate); | 40 explicit BasicJsonStringifier(Isolate* isolate); |
41 | 41 |
42 MaybeObject* Stringify(Handle<Object> object); | 42 MaybeObject* Stringify(Handle<Object> object); |
43 | 43 |
44 private: | 44 private: |
45 static const int kInitialPartLength = 32; | 45 static const int kInitialPartLength = 32; |
46 static const int kMaxPartLength = 16 * 1024; | 46 static const int kMaxPartLength = 16 * 1024; |
47 static const int kPartLengthGrowthFactor = 2; | 47 static const int kPartLengthGrowthFactor = 2; |
48 | 48 |
49 enum Result { UNCHANGED, SUCCESS, BAILOUT, CIRCULAR, STACK_OVERFLOW }; | 49 enum Result { UNCHANGED, SUCCESS, EXCEPTION, CIRCULAR, STACK_OVERFLOW }; |
50 | 50 |
51 template <bool is_ascii> void Extend(); | 51 template <bool is_ascii> void Extend(); |
52 | 52 |
53 void ChangeEncoding(); | 53 void ChangeEncoding(); |
54 | 54 |
55 void ShrinkCurrentPart(); | 55 void ShrinkCurrentPart(); |
56 | 56 |
57 template <bool is_ascii, typename Char> | 57 template <bool is_ascii, typename Char> |
58 INLINE(void Append_(Char c)); | 58 INLINE(void Append_(Char c)); |
59 | 59 |
(...skipping 12 matching lines...) Expand all Loading... |
72 if (is_ascii_) { | 72 if (is_ascii_) { |
73 Append_<true>(chars); | 73 Append_<true>(chars); |
74 } else { | 74 } else { |
75 Append_<false>(chars); | 75 Append_<false>(chars); |
76 } | 76 } |
77 } | 77 } |
78 | 78 |
79 Handle<Object> GetProperty(Handle<JSObject> object, | 79 Handle<Object> GetProperty(Handle<JSObject> object, |
80 Handle<String> key); | 80 Handle<String> key); |
81 | 81 |
82 bool MayHaveToJsonFunction(Handle<JSObject> object); | 82 Handle<Object> ApplyToJsonFunction(Handle<Object> object, |
| 83 Handle<Object> key); |
83 | 84 |
84 INLINE(Result Serialize(Handle<Object> object)) { | 85 // Entry point to serialize the object. |
85 return Serialize_<false>(object); | 86 INLINE(Result SerializeObject(Handle<Object> obj)) { |
| 87 return Serialize_<false>(obj, false, isolate_->factory()->empty_string()); |
86 } | 88 } |
87 | 89 |
88 INLINE(Result SerializeDeferred(Handle<Object> object, | 90 // Serialize an array element. |
89 bool deferred_comma, | 91 // The index may serve as argument for the toJSON function. |
90 Handle<String> deferred_key)) { | 92 INLINE(Result SerializeElement(Handle<Object> object, int i)) { |
| 93 return Serialize_<false>(object, false, Handle<Object>(Smi::FromInt(i))); |
| 94 } |
| 95 |
| 96 // Serialize a object property. |
| 97 // The key may or may not be serialized depending on the property. |
| 98 // The key may also serve as argument for the toJSON function. |
| 99 INLINE(Result SerializeProperty(Handle<Object> object, |
| 100 bool deferred_comma, |
| 101 Handle<String> deferred_key)) { |
91 ASSERT(!deferred_key.is_null()); | 102 ASSERT(!deferred_key.is_null()); |
92 return Serialize_<true>(object, deferred_comma, deferred_key); | 103 return Serialize_<true>(object, deferred_comma, deferred_key); |
93 } | 104 } |
94 | 105 |
95 template <bool deferred_key> | 106 template <bool deferred_string_key> |
96 Result Serialize_(Handle<Object> object, | 107 Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key); |
97 bool comma = false, | |
98 Handle<String> key = Handle<String>::null()); | |
99 | 108 |
100 void SerializeDeferredKey(bool deferred_comma, Handle<String> deferred_key) { | 109 void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) { |
101 if (deferred_comma) Append(','); | 110 if (deferred_comma) Append(','); |
102 SerializeString(deferred_key); | 111 SerializeString(Handle<String>::cast(deferred_key)); |
103 Append(':'); | 112 Append(':'); |
104 } | 113 } |
105 | 114 |
106 Result SerializeSmi(Smi* object); | 115 Result SerializeSmi(Smi* object); |
107 | 116 |
108 Result SerializeDouble(double number); | 117 Result SerializeDouble(double number); |
109 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) { | 118 INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) { |
110 return SerializeDouble(object->value()); | 119 return SerializeDouble(object->value()); |
111 } | 120 } |
112 | 121 |
113 INLINE(Result SerializeArray(Handle<JSArray> object)); | 122 Result SerializeJSValue(Handle<JSValue> object); |
114 INLINE(Result SerializeObject(Handle<JSObject> object)); | 123 |
| 124 INLINE(Result SerializeJSArray(Handle<JSArray> object)); |
| 125 INLINE(Result SerializeJSObject(Handle<JSObject> object)); |
| 126 |
| 127 Result SerializeJSArraySlow(Handle<JSArray> object, int length); |
115 | 128 |
116 void SerializeString(Handle<String> object); | 129 void SerializeString(Handle<String> object); |
117 | 130 |
118 template <typename SrcChar, typename DestChar> | 131 template <typename SrcChar, typename DestChar> |
119 INLINE(void SerializeStringUnchecked_(const SrcChar* src, | 132 INLINE(void SerializeStringUnchecked_(const SrcChar* src, |
120 DestChar* dest, | 133 DestChar* dest, |
121 int length)); | 134 int length)); |
122 | 135 |
123 template <bool is_ascii, typename Char> | 136 template <bool is_ascii, typename Char> |
124 INLINE(void SerializeString_(Vector<const Char> vector, | 137 INLINE(void SerializeString_(Vector<const Char> vector, |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 isolate_->factory()->ToObject(isolate_->factory()->empty_string())); | 213 isolate_->factory()->ToObject(isolate_->factory()->empty_string())); |
201 part_length_ = kInitialPartLength; | 214 part_length_ = kInitialPartLength; |
202 current_part_ = | 215 current_part_ = |
203 isolate_->factory()->NewRawAsciiString(kInitialPartLength); | 216 isolate_->factory()->NewRawAsciiString(kInitialPartLength); |
204 tojson_symbol_ = isolate_->factory()->LookupAsciiSymbol("toJSON"); | 217 tojson_symbol_ = isolate_->factory()->LookupAsciiSymbol("toJSON"); |
205 stack_ = isolate_->factory()->NewJSArray(8); | 218 stack_ = isolate_->factory()->NewJSArray(8); |
206 } | 219 } |
207 | 220 |
208 | 221 |
209 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) { | 222 MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) { |
210 switch (Serialize(object)) { | 223 switch (SerializeObject(object)) { |
| 224 case UNCHANGED: |
| 225 return isolate_->heap()->undefined_value(); |
211 case SUCCESS: | 226 case SUCCESS: |
212 ShrinkCurrentPart(); | 227 ShrinkCurrentPart(); |
213 return *isolate_->factory()->NewConsString(accumulator(), current_part_); | 228 return *isolate_->factory()->NewConsString(accumulator(), current_part_); |
214 case UNCHANGED: | |
215 return isolate_->heap()->undefined_value(); | |
216 case CIRCULAR: | 229 case CIRCULAR: |
217 return isolate_->Throw(*isolate_->factory()->NewTypeError( | 230 return isolate_->Throw(*isolate_->factory()->NewTypeError( |
218 "circular_structure", HandleVector<Object>(NULL, 0))); | 231 "circular_structure", HandleVector<Object>(NULL, 0))); |
219 case STACK_OVERFLOW: | 232 case STACK_OVERFLOW: |
220 return isolate_->StackOverflow(); | 233 return isolate_->StackOverflow(); |
221 default: | 234 default: |
222 return Smi::FromInt(0); | 235 return Failure::Exception(); |
223 } | 236 } |
224 } | 237 } |
225 | 238 |
226 | 239 |
227 template <bool is_ascii, typename Char> | 240 template <bool is_ascii, typename Char> |
228 void BasicJsonStringifier::Append_(Char c) { | 241 void BasicJsonStringifier::Append_(Char c) { |
229 if (is_ascii) { | 242 if (is_ascii) { |
230 SeqAsciiString::cast(*current_part_)->SeqAsciiStringSet( | 243 SeqAsciiString::cast(*current_part_)->SeqAsciiStringSet( |
231 current_index_++, c); | 244 current_index_++, c); |
232 } else { | 245 } else { |
(...skipping 21 matching lines...) Expand all Loading... |
254 ASSERT(!value->IsTheHole()); | 267 ASSERT(!value->IsTheHole()); |
255 return Handle<Object>(value); | 268 return Handle<Object>(value); |
256 } | 269 } |
257 case FIELD: { | 270 case FIELD: { |
258 Object* value = lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); | 271 Object* value = lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); |
259 ASSERT(!value->IsTheHole()); | 272 ASSERT(!value->IsTheHole()); |
260 return Handle<Object>(value); | 273 return Handle<Object>(value); |
261 } | 274 } |
262 case CONSTANT_FUNCTION: | 275 case CONSTANT_FUNCTION: |
263 return Handle<Object>(lookup.GetConstantFunction()); | 276 return Handle<Object>(lookup.GetConstantFunction()); |
264 case CALLBACKS: | 277 default: { |
265 case HANDLER: | 278 PropertyAttributes attr; |
266 case INTERCEPTOR: | 279 return Object::GetProperty(object, object, &lookup, key, &attr); |
267 return Handle<Object>::null(); | 280 } |
268 case TRANSITION: | |
269 case NONEXISTENT: | |
270 UNREACHABLE(); | |
271 break; | |
272 } | 281 } |
273 return Handle<Object>::null(); | 282 return Handle<Object>::null(); |
274 } | 283 } |
275 | 284 |
276 | 285 |
277 bool BasicJsonStringifier::MayHaveToJsonFunction(Handle<JSObject> object) { | 286 Handle<Object> BasicJsonStringifier::ApplyToJsonFunction( |
| 287 Handle<Object> object, Handle<Object> key) { |
278 LookupResult lookup(isolate_); | 288 LookupResult lookup(isolate_); |
279 object->LookupRealNamedProperty(*tojson_symbol_, &lookup); | 289 JSObject::cast(*object)->LookupRealNamedProperty(*tojson_symbol_, &lookup); |
280 if (!lookup.IsProperty()) return false; | 290 if (!lookup.IsProperty()) return object; |
281 Object* value; | 291 PropertyAttributes attr; |
282 switch (lookup.type()) { | 292 Handle<Object> fun = |
283 case NORMAL: | 293 Object::GetProperty(object, object, &lookup, tojson_symbol_, &attr); |
284 value = lookup.holder()->GetNormalizedProperty(&lookup); | 294 if (!fun->IsJSFunction()) return object; |
285 break; | 295 |
286 case FIELD: | 296 // Call toJSON function. |
287 value = lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); | 297 if (key->IsSmi()) key = isolate_->factory()->NumberToString(key); |
288 break; | 298 Handle<Object> argv[] = { key }; |
289 default: | 299 bool has_exception = false; |
290 return true; | 300 HandleScope scope(isolate_); |
291 } | 301 object = Execution::Call(fun, object, 1, argv, &has_exception); |
292 ASSERT(!value->IsTheHole()); | 302 // Return empty handle to signal an exception. |
293 return value->IsSpecFunction(); | 303 if (has_exception) return Handle<Object>::null(); |
| 304 return scope.CloseAndEscape(object); |
294 } | 305 } |
295 | 306 |
296 | 307 |
297 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( | 308 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( |
298 Handle<Object> object) { | 309 Handle<Object> object) { |
299 StackLimitCheck check(isolate_); | 310 StackLimitCheck check(isolate_); |
300 if (check.HasOverflowed()) return STACK_OVERFLOW; | 311 if (check.HasOverflowed()) return STACK_OVERFLOW; |
301 | 312 |
302 int length = Smi::cast(stack_->length())->value(); | 313 int length = Smi::cast(stack_->length())->value(); |
303 FixedArray* elements = FixedArray::cast(stack_->elements()); | 314 FixedArray* elements = FixedArray::cast(stack_->elements()); |
304 for (int i = 0; i < length; i++) { | 315 for (int i = 0; i < length; i++) { |
305 if (elements->get(i) == *object) { | 316 if (elements->get(i) == *object) { |
306 return CIRCULAR; | 317 return CIRCULAR; |
307 } | 318 } |
308 } | 319 } |
309 stack_->EnsureSize(length + 1); | 320 stack_->EnsureSize(length + 1); |
310 FixedArray::cast(stack_->elements())->set(length, *object); | 321 FixedArray::cast(stack_->elements())->set(length, *object); |
311 stack_->set_length(Smi::FromInt(length + 1)); | 322 stack_->set_length(Smi::FromInt(length + 1)); |
312 return SUCCESS; | 323 return SUCCESS; |
313 } | 324 } |
314 | 325 |
315 | 326 |
316 void BasicJsonStringifier::StackPop() { | 327 void BasicJsonStringifier::StackPop() { |
317 int length = Smi::cast(stack_->length())->value(); | 328 int length = Smi::cast(stack_->length())->value(); |
318 stack_->set_length(Smi::FromInt(length - 1)); | 329 stack_->set_length(Smi::FromInt(length - 1)); |
319 } | 330 } |
320 | 331 |
321 | 332 |
322 template <bool deferred_key> | 333 template <bool deferred_string_key> |
323 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( | 334 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( |
324 Handle<Object> object, bool comma, Handle<String> key) { | 335 Handle<Object> object, bool comma, Handle<Object> key) { |
325 if (object->IsJSObject()) { | 336 if (object->IsJSObject()) { |
326 // We don't deal with custom toJSON functions. | 337 object = ApplyToJsonFunction(object, key); |
327 if (MayHaveToJsonFunction(Handle<JSObject>::cast(object))) return BAILOUT; | 338 if (object.is_null()) return EXCEPTION; |
| 339 } |
328 | 340 |
329 if (object->IsJSFunction()) { | 341 if (object->IsJSObject()) { |
330 return UNCHANGED; | 342 if (object->IsJSFunction()) return UNCHANGED; |
331 } else if (object->IsJSArray()) { | 343 if (deferred_string_key) SerializeDeferredKey(comma, key); |
332 if (deferred_key) SerializeDeferredKey(comma, key); | 344 if (object->IsJSArray()) { |
333 return SerializeArray(Handle<JSArray>::cast(object)); | 345 return SerializeJSArray(Handle<JSArray>::cast(object)); |
334 } else if (object->IsJSValue()) { | 346 } else if (object->IsJSValue()) { |
335 // JSValue with a custom prototype. | 347 return SerializeJSValue(Handle<JSValue>::cast(object)); |
336 if (object->GetPrototype()->IsJSReceiver()) return BAILOUT; | |
337 // Unpack value wrapper and fall through. | |
338 object = Handle<Object>(JSValue::cast(*object)->value()); | |
339 } else { | 348 } else { |
340 if (deferred_key) SerializeDeferredKey(comma, key); | 349 return SerializeJSObject(Handle<JSObject>::cast(object)); |
341 return SerializeObject(Handle<JSObject>::cast(object)); | |
342 } | 350 } |
343 } | 351 } |
344 | 352 |
| 353 // Handle non-JSObject. |
345 if (object->IsString()) { | 354 if (object->IsString()) { |
346 if (deferred_key) SerializeDeferredKey(comma, key); | 355 if (deferred_string_key) SerializeDeferredKey(comma, key); |
347 SerializeString(Handle<String>::cast(object)); | 356 SerializeString(Handle<String>::cast(object)); |
348 return SUCCESS; | 357 return SUCCESS; |
349 } else if (object->IsSmi()) { | 358 } else if (object->IsSmi()) { |
350 if (deferred_key) SerializeDeferredKey(comma, key); | 359 if (deferred_string_key) SerializeDeferredKey(comma, key); |
351 return SerializeSmi(Smi::cast(*object)); | 360 return SerializeSmi(Smi::cast(*object)); |
352 } else if (object->IsHeapNumber()) { | 361 } else if (object->IsHeapNumber()) { |
353 if (deferred_key) SerializeDeferredKey(comma, key); | 362 if (deferred_string_key) SerializeDeferredKey(comma, key); |
354 return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); | 363 return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); |
355 } else if (object->IsOddball()) { | 364 } else if (object->IsOddball()) { |
356 switch (Oddball::cast(*object)->kind()) { | 365 switch (Oddball::cast(*object)->kind()) { |
357 case Oddball::kFalse: | 366 case Oddball::kFalse: |
358 if (deferred_key) SerializeDeferredKey(comma, key); | 367 if (deferred_string_key) SerializeDeferredKey(comma, key); |
359 Append("false"); | 368 Append("false"); |
360 return SUCCESS; | 369 return SUCCESS; |
361 case Oddball::kTrue: | 370 case Oddball::kTrue: |
362 if (deferred_key) SerializeDeferredKey(comma, key); | 371 if (deferred_string_key) SerializeDeferredKey(comma, key); |
363 Append("true"); | 372 Append("true"); |
364 return SUCCESS; | 373 return SUCCESS; |
365 case Oddball::kNull: | 374 case Oddball::kNull: |
366 if (deferred_key) SerializeDeferredKey(comma, key); | 375 if (deferred_string_key) SerializeDeferredKey(comma, key); |
367 Append("null"); | 376 Append("null"); |
368 return SUCCESS; | 377 return SUCCESS; |
369 } | 378 } |
370 } | 379 } |
371 | 380 |
372 return UNCHANGED; | 381 return UNCHANGED; |
373 } | 382 } |
374 | 383 |
375 | 384 |
| 385 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( |
| 386 Handle<JSValue> object) { |
| 387 bool has_exception = false; |
| 388 String* class_name = object->class_name(); |
| 389 if (class_name == isolate_->heap()->String_symbol()) { |
| 390 Handle<Object> value = Execution::ToString(object, &has_exception); |
| 391 if (has_exception) return EXCEPTION; |
| 392 SerializeString(Handle<String>::cast(value)); |
| 393 } else if (class_name == isolate_->heap()->Number_symbol()) { |
| 394 Handle<Object> value = Execution::ToNumber(object, &has_exception); |
| 395 if (has_exception) return EXCEPTION; |
| 396 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); |
| 397 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); |
| 398 } else { |
| 399 ASSERT(class_name == isolate_->heap()->Boolean_symbol()); |
| 400 Object* value = JSValue::cast(*object)->value(); |
| 401 ASSERT(value->IsBoolean()); |
| 402 Append(value->IsTrue() ? "true" : "false"); |
| 403 } |
| 404 return SUCCESS; |
| 405 } |
| 406 |
| 407 |
376 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { | 408 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { |
377 static const int kBufferSize = 100; | 409 static const int kBufferSize = 100; |
378 char chars[kBufferSize]; | 410 char chars[kBufferSize]; |
379 Vector<char> buffer(chars, kBufferSize); | 411 Vector<char> buffer(chars, kBufferSize); |
380 Append(IntToCString(object->value(), buffer)); | 412 Append(IntToCString(object->value(), buffer)); |
381 return SUCCESS; | 413 return SUCCESS; |
382 } | 414 } |
383 | 415 |
384 | 416 |
385 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( | 417 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( |
386 double number) { | 418 double number) { |
387 if (isinf(number) || isnan(number)) { | 419 if (isinf(number) || isnan(number)) { |
388 Append("null"); | 420 Append("null"); |
389 return SUCCESS; | 421 return SUCCESS; |
390 } | 422 } |
391 static const int kBufferSize = 100; | 423 static const int kBufferSize = 100; |
392 char chars[kBufferSize]; | 424 char chars[kBufferSize]; |
393 Vector<char> buffer(chars, kBufferSize); | 425 Vector<char> buffer(chars, kBufferSize); |
394 Append(DoubleToCString(number, buffer)); | 426 Append(DoubleToCString(number, buffer)); |
395 return SUCCESS; | 427 return SUCCESS; |
396 } | 428 } |
397 | 429 |
398 | 430 |
399 BasicJsonStringifier::Result BasicJsonStringifier::SerializeArray( | 431 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( |
400 Handle<JSArray> object) { | 432 Handle<JSArray> object) { |
401 HandleScope handle_scope(isolate_); | 433 HandleScope handle_scope(isolate_); |
402 Result stack_push = StackPush(object); | 434 Result stack_push = StackPush(object); |
403 if (stack_push != SUCCESS) return stack_push; | 435 if (stack_push != SUCCESS) return stack_push; |
404 int length = Smi::cast(object->length())->value(); | 436 int length = Smi::cast(object->length())->value(); |
405 Append('['); | 437 Append('['); |
406 switch (object->GetElementsKind()) { | 438 switch (object->GetElementsKind()) { |
407 case FAST_SMI_ELEMENTS: { | 439 case FAST_SMI_ELEMENTS: { |
408 Handle<FixedArray> elements = Handle<FixedArray>( | 440 Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
409 FixedArray::cast(object->elements())); | |
410 for (int i = 0; i < length; i++) { | 441 for (int i = 0; i < length; i++) { |
411 if (i > 0) Append(','); | 442 if (i > 0) Append(','); |
412 SerializeSmi(Smi::cast(elements->get(i))); | 443 SerializeSmi(Smi::cast(elements->get(i))); |
413 } | 444 } |
414 break; | 445 break; |
415 } | 446 } |
416 case FAST_DOUBLE_ELEMENTS: { | 447 case FAST_DOUBLE_ELEMENTS: { |
417 Handle<FixedDoubleArray> elements = Handle<FixedDoubleArray>( | 448 Handle<FixedDoubleArray> elements( |
418 FixedDoubleArray::cast(object->elements())); | 449 FixedDoubleArray::cast(object->elements())); |
419 for (int i = 0; i < length; i++) { | 450 for (int i = 0; i < length; i++) { |
420 if (i > 0) Append(','); | 451 if (i > 0) Append(','); |
421 SerializeDouble(elements->get_scalar(i)); | 452 SerializeDouble(elements->get_scalar(i)); |
422 } | 453 } |
423 break; | 454 break; |
424 } | 455 } |
425 case FAST_ELEMENTS: { | 456 case FAST_ELEMENTS: { |
426 Handle<FixedArray> elements = Handle<FixedArray>( | 457 Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
427 FixedArray::cast(object->elements())); | |
428 for (int i = 0; i < length; i++) { | 458 for (int i = 0; i < length; i++) { |
429 if (i > 0) Append(','); | 459 if (i > 0) Append(','); |
430 Result result = Serialize(Handle<Object>(elements->get(i))); | 460 Result result = SerializeElement(Handle<Object>(elements->get(i)), i); |
431 if (result == SUCCESS) continue; | 461 if (result == SUCCESS) continue; |
432 if (result == UNCHANGED) { | 462 if (result == UNCHANGED) { |
433 Append("null"); | 463 Append("null"); |
434 } else { | 464 } else { |
435 return result; | 465 return result; |
436 } | 466 } |
437 } | 467 } |
438 break; | 468 break; |
439 } | 469 } |
440 default: | 470 // TODO(yangguo): The FAST_HOLEY_* cases could be handled in a faster way. |
441 return BAILOUT; | 471 // They resemble the non-holey cases except that a prototype chain lookup |
| 472 // is necessary for holes. |
| 473 default: { |
| 474 Result result = SerializeJSArraySlow(object, length); |
| 475 if (result != SUCCESS) return result; |
| 476 break; |
| 477 } |
442 } | 478 } |
443 Append(']'); | 479 Append(']'); |
444 StackPop(); | 480 StackPop(); |
445 current_part_ = handle_scope.CloseAndEscape(current_part_); | 481 current_part_ = handle_scope.CloseAndEscape(current_part_); |
446 return SUCCESS; | 482 return SUCCESS; |
447 } | 483 } |
448 | 484 |
449 | 485 |
450 BasicJsonStringifier::Result BasicJsonStringifier::SerializeObject( | 486 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( |
| 487 Handle<JSArray> object, int length) { |
| 488 for (int i = 0; i < length; i++) { |
| 489 if (i > 0) Append(','); |
| 490 Handle<Object> element = Object::GetElement(object, i); |
| 491 if (element->IsUndefined()) { |
| 492 Append("null"); |
| 493 } else { |
| 494 Result result = SerializeElement(element, i); |
| 495 if (result == SUCCESS) continue; |
| 496 if (result == UNCHANGED) { |
| 497 Append("null"); |
| 498 } else { |
| 499 return result; |
| 500 } |
| 501 } |
| 502 } |
| 503 return SUCCESS; |
| 504 } |
| 505 |
| 506 |
| 507 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
451 Handle<JSObject> object) { | 508 Handle<JSObject> object) { |
452 HandleScope handle_scope(isolate_); | 509 HandleScope handle_scope(isolate_); |
453 Result stack_push = StackPush(object); | 510 Result stack_push = StackPush(object); |
454 if (stack_push != SUCCESS) return stack_push; | 511 if (stack_push != SUCCESS) return stack_push; |
455 if (object->IsJSGlobalProxy()) return BAILOUT; | 512 if (object->IsJSGlobalProxy()) { |
456 bool threw = false; | 513 object = Handle<JSObject>(JSObject::cast(object->GetPrototype())); |
| 514 ASSERT(object->IsGlobalObject()); |
| 515 } |
| 516 bool has_exception = false; |
457 Handle<FixedArray> contents = | 517 Handle<FixedArray> contents = |
458 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw); | 518 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception); |
459 if (threw) return BAILOUT; | 519 if (has_exception) return EXCEPTION; |
460 Append('{'); | 520 Append('{'); |
461 bool comma = false; | 521 bool comma = false; |
462 for (int i = 0; i < contents->length(); i++) { | 522 for (int i = 0; i < contents->length(); i++) { |
463 Object* key = contents->get(i); | 523 Object* key = contents->get(i); |
464 Handle<String> key_handle; | 524 Handle<String> key_handle; |
465 Handle<Object> property; | 525 Handle<Object> property; |
466 if (key->IsString()) { | 526 if (key->IsString()) { |
467 key_handle = Handle<String>(String::cast(key)); | 527 key_handle = Handle<String>(String::cast(key)); |
468 property = GetProperty(object, key_handle); | 528 property = GetProperty(object, key_handle); |
469 } else { | 529 } else { |
470 ASSERT(key->IsNumber()); | 530 ASSERT(key->IsNumber()); |
471 key_handle = isolate_->factory()->NumberToString(Handle<Object>(key)); | 531 key_handle = isolate_->factory()->NumberToString(Handle<Object>(key)); |
472 uint32_t index; | 532 uint32_t index; |
473 if (key->IsSmi()) { | 533 if (key->IsSmi()) { |
474 property = Object::GetElement(object, Smi::cast(key)->value()); | 534 property = Object::GetElement(object, Smi::cast(key)->value()); |
475 } else if (key_handle->AsArrayIndex(&index)) { | 535 } else if (key_handle->AsArrayIndex(&index)) { |
476 property = Object::GetElement(object, index); | 536 property = Object::GetElement(object, index); |
477 } else { | 537 } else { |
478 property = GetProperty(object, key_handle); | 538 property = GetProperty(object, key_handle); |
479 } | 539 } |
480 } | 540 } |
481 if (property.is_null()) return BAILOUT; | 541 if (property.is_null()) return EXCEPTION; |
482 Result result = SerializeDeferred(property, comma, key_handle); | 542 Result result = SerializeProperty(property, comma, key_handle); |
483 if (!comma && result == SUCCESS) comma = true; | 543 if (!comma && result == SUCCESS) comma = true; |
484 if (result >= BAILOUT) return result; | 544 if (result >= EXCEPTION) return result; |
485 } | 545 } |
486 Append('}'); | 546 Append('}'); |
487 StackPop(); | 547 StackPop(); |
488 current_part_ = handle_scope.CloseAndEscape(current_part_); | 548 current_part_ = handle_scope.CloseAndEscape(current_part_); |
489 return SUCCESS; | 549 return SUCCESS; |
490 } | 550 } |
491 | 551 |
492 | 552 |
493 void BasicJsonStringifier::ShrinkCurrentPart() { | 553 void BasicJsonStringifier::ShrinkCurrentPart() { |
494 ASSERT(current_index_ < part_length_); | 554 ASSERT(current_index_ < part_length_); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 SerializeString_<false, char>(flat.ToAsciiVector(), object); | 722 SerializeString_<false, char>(flat.ToAsciiVector(), object); |
663 } else { | 723 } else { |
664 SerializeString_<false, uc16>(flat.ToUC16Vector(), object); | 724 SerializeString_<false, uc16>(flat.ToUC16Vector(), object); |
665 } | 725 } |
666 } | 726 } |
667 } | 727 } |
668 | 728 |
669 } } // namespace v8::internal | 729 } } // namespace v8::internal |
670 | 730 |
671 #endif // V8_JSON_STRINGIFIER_H_ | 731 #endif // V8_JSON_STRINGIFIER_H_ |
OLD | NEW |