| 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 |