OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
999 switch (map()->instance_type()) { | 999 switch (map()->instance_type()) { |
1000 case MAP_TYPE: | 1000 case MAP_TYPE: |
1001 accumulator->Add("<Map>"); | 1001 accumulator->Add("<Map>"); |
1002 break; | 1002 break; |
1003 case FIXED_ARRAY_TYPE: | 1003 case FIXED_ARRAY_TYPE: |
1004 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); | 1004 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); |
1005 break; | 1005 break; |
1006 case BYTE_ARRAY_TYPE: | 1006 case BYTE_ARRAY_TYPE: |
1007 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); | 1007 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); |
1008 break; | 1008 break; |
| 1009 case PIXEL_ARRAY_TYPE: |
| 1010 accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length()); |
| 1011 break; |
1009 case SHARED_FUNCTION_INFO_TYPE: | 1012 case SHARED_FUNCTION_INFO_TYPE: |
1010 accumulator->Add("<SharedFunctionInfo>"); | 1013 accumulator->Add("<SharedFunctionInfo>"); |
1011 break; | 1014 break; |
1012 #define MAKE_STRUCT_CASE(NAME, Name, name) \ | 1015 #define MAKE_STRUCT_CASE(NAME, Name, name) \ |
1013 case NAME##_TYPE: \ | 1016 case NAME##_TYPE: \ |
1014 accumulator->Put('<'); \ | 1017 accumulator->Put('<'); \ |
1015 accumulator->Add(#Name); \ | 1018 accumulator->Add(#Name); \ |
1016 accumulator->Put('>'); \ | 1019 accumulator->Put('>'); \ |
1017 break; | 1020 break; |
1018 STRUCT_LIST(MAKE_STRUCT_CASE) | 1021 STRUCT_LIST(MAKE_STRUCT_CASE) |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 case CODE_TYPE: | 1143 case CODE_TYPE: |
1141 reinterpret_cast<Code*>(this)->CodeIterateBody(v); | 1144 reinterpret_cast<Code*>(this)->CodeIterateBody(v); |
1142 break; | 1145 break; |
1143 case JS_GLOBAL_PROPERTY_CELL_TYPE: | 1146 case JS_GLOBAL_PROPERTY_CELL_TYPE: |
1144 reinterpret_cast<JSGlobalPropertyCell*>(this) | 1147 reinterpret_cast<JSGlobalPropertyCell*>(this) |
1145 ->JSGlobalPropertyCellIterateBody(v); | 1148 ->JSGlobalPropertyCellIterateBody(v); |
1146 break; | 1149 break; |
1147 case HEAP_NUMBER_TYPE: | 1150 case HEAP_NUMBER_TYPE: |
1148 case FILLER_TYPE: | 1151 case FILLER_TYPE: |
1149 case BYTE_ARRAY_TYPE: | 1152 case BYTE_ARRAY_TYPE: |
| 1153 case PIXEL_ARRAY_TYPE: |
1150 break; | 1154 break; |
1151 case SHARED_FUNCTION_INFO_TYPE: { | 1155 case SHARED_FUNCTION_INFO_TYPE: { |
1152 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this); | 1156 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this); |
1153 shared->SharedFunctionInfoIterateBody(v); | 1157 shared->SharedFunctionInfoIterateBody(v); |
1154 break; | 1158 break; |
1155 } | 1159 } |
1156 #define MAKE_STRUCT_CASE(NAME, Name, name) \ | 1160 #define MAKE_STRUCT_CASE(NAME, Name, name) \ |
1157 case NAME##_TYPE: | 1161 case NAME##_TYPE: |
1158 STRUCT_LIST(MAKE_STRUCT_CASE) | 1162 STRUCT_LIST(MAKE_STRUCT_CASE) |
1159 #undef MAKE_STRUCT_CASE | 1163 #undef MAKE_STRUCT_CASE |
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1662 } | 1666 } |
1663 } | 1667 } |
1664 result->NotFound(); | 1668 result->NotFound(); |
1665 } | 1669 } |
1666 | 1670 |
1667 | 1671 |
1668 Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { | 1672 Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { |
1669 for (Object* pt = GetPrototype(); | 1673 for (Object* pt = GetPrototype(); |
1670 pt != Heap::null_value(); | 1674 pt != Heap::null_value(); |
1671 pt = pt->GetPrototype()) { | 1675 pt = pt->GetPrototype()) { |
1672 if (JSObject::cast(pt)->HasFastElements()) continue; | 1676 if (!JSObject::cast(pt)->HasDictionaryElements()) { |
| 1677 continue; |
| 1678 } |
1673 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); | 1679 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); |
1674 int entry = dictionary->FindEntry(index); | 1680 int entry = dictionary->FindEntry(index); |
1675 if (entry != NumberDictionary::kNotFound) { | 1681 if (entry != NumberDictionary::kNotFound) { |
1676 Object* element = dictionary->ValueAt(entry); | 1682 Object* element = dictionary->ValueAt(entry); |
1677 PropertyDetails details = dictionary->DetailsAt(entry); | 1683 PropertyDetails details = dictionary->DetailsAt(entry); |
1678 if (details.type() == CALLBACKS) { | 1684 if (details.type() == CALLBACKS) { |
1679 // Only accessors allowed as elements. | 1685 // Only accessors allowed as elements. |
1680 return FixedArray::cast(element)->get(kSetterIndex); | 1686 return FixedArray::cast(element)->get(kSetterIndex); |
1681 } | 1687 } |
1682 } | 1688 } |
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2224 | 2230 |
2225 Object* JSObject::TransformToFastProperties(int unused_property_fields) { | 2231 Object* JSObject::TransformToFastProperties(int unused_property_fields) { |
2226 if (HasFastProperties()) return this; | 2232 if (HasFastProperties()) return this; |
2227 ASSERT(!IsGlobalObject()); | 2233 ASSERT(!IsGlobalObject()); |
2228 return property_dictionary()-> | 2234 return property_dictionary()-> |
2229 TransformPropertiesToFastFor(this, unused_property_fields); | 2235 TransformPropertiesToFastFor(this, unused_property_fields); |
2230 } | 2236 } |
2231 | 2237 |
2232 | 2238 |
2233 Object* JSObject::NormalizeElements() { | 2239 Object* JSObject::NormalizeElements() { |
2234 if (!HasFastElements()) return this; | 2240 ASSERT(!HasPixelElements()); |
| 2241 if (HasDictionaryElements()) return this; |
2235 | 2242 |
2236 // Get number of entries. | 2243 // Get number of entries. |
2237 FixedArray* array = FixedArray::cast(elements()); | 2244 FixedArray* array = FixedArray::cast(elements()); |
2238 | 2245 |
2239 // Compute the effective length. | 2246 // Compute the effective length. |
2240 int length = IsJSArray() ? | 2247 int length = IsJSArray() ? |
2241 Smi::cast(JSArray::cast(this)->length())->value() : | 2248 Smi::cast(JSArray::cast(this)->length())->value() : |
2242 array->length(); | 2249 array->length(); |
2243 Object* obj = NumberDictionary::Allocate(length); | 2250 Object* obj = NumberDictionary::Allocate(length); |
2244 if (obj->IsFailure()) return obj; | 2251 if (obj->IsFailure()) return obj; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2310 } | 2317 } |
2311 Object* raw_result = | 2318 Object* raw_result = |
2312 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); | 2319 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); |
2313 RETURN_IF_SCHEDULED_EXCEPTION(); | 2320 RETURN_IF_SCHEDULED_EXCEPTION(); |
2314 return raw_result; | 2321 return raw_result; |
2315 } | 2322 } |
2316 | 2323 |
2317 | 2324 |
2318 Object* JSObject::DeleteElementPostInterceptor(uint32_t index, | 2325 Object* JSObject::DeleteElementPostInterceptor(uint32_t index, |
2319 DeleteMode mode) { | 2326 DeleteMode mode) { |
2320 if (HasFastElements()) { | 2327 ASSERT(!HasPixelElements()); |
2321 uint32_t length = IsJSArray() ? | 2328 switch (GetElementsKind()) { |
| 2329 case FAST_ELEMENTS: { |
| 2330 uint32_t length = IsJSArray() ? |
2322 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 2331 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
2323 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2332 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
2324 if (index < length) { | 2333 if (index < length) { |
2325 FixedArray::cast(elements())->set_the_hole(index); | 2334 FixedArray::cast(elements())->set_the_hole(index); |
| 2335 } |
| 2336 break; |
2326 } | 2337 } |
2327 return Heap::true_value(); | 2338 case DICTIONARY_ELEMENTS: { |
2328 } | 2339 NumberDictionary* dictionary = element_dictionary(); |
2329 ASSERT(!HasFastElements()); | 2340 int entry = dictionary->FindEntry(index); |
2330 NumberDictionary* dictionary = element_dictionary(); | 2341 if (entry != NumberDictionary::kNotFound) { |
2331 int entry = dictionary->FindEntry(index); | 2342 return dictionary->DeleteProperty(entry, mode); |
2332 if (entry != NumberDictionary::kNotFound) { | 2343 } |
2333 return dictionary->DeleteProperty(entry, mode); | 2344 break; |
| 2345 } |
| 2346 default: |
| 2347 UNREACHABLE(); |
| 2348 break; |
2334 } | 2349 } |
2335 return Heap::true_value(); | 2350 return Heap::true_value(); |
2336 } | 2351 } |
2337 | 2352 |
2338 | 2353 |
2339 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) { | 2354 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) { |
2340 // Make sure that the top context does not change when doing | 2355 // Make sure that the top context does not change when doing |
2341 // callbacks or interceptor calls. | 2356 // callbacks or interceptor calls. |
2342 AssertNoContextChange ncc; | 2357 AssertNoContextChange ncc; |
2343 HandleScope scope; | 2358 HandleScope scope; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2385 } | 2400 } |
2386 | 2401 |
2387 if (HasIndexedInterceptor()) { | 2402 if (HasIndexedInterceptor()) { |
2388 // Skip interceptor if forcing deletion. | 2403 // Skip interceptor if forcing deletion. |
2389 if (mode == FORCE_DELETION) { | 2404 if (mode == FORCE_DELETION) { |
2390 return DeleteElementPostInterceptor(index, mode); | 2405 return DeleteElementPostInterceptor(index, mode); |
2391 } | 2406 } |
2392 return DeleteElementWithInterceptor(index); | 2407 return DeleteElementWithInterceptor(index); |
2393 } | 2408 } |
2394 | 2409 |
2395 if (HasFastElements()) { | 2410 switch (GetElementsKind()) { |
2396 uint32_t length = IsJSArray() ? | 2411 case FAST_ELEMENTS: { |
| 2412 uint32_t length = IsJSArray() ? |
2397 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 2413 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
2398 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2414 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
2399 if (index < length) { | 2415 if (index < length) { |
2400 FixedArray::cast(elements())->set_the_hole(index); | 2416 FixedArray::cast(elements())->set_the_hole(index); |
| 2417 } |
| 2418 break; |
2401 } | 2419 } |
2402 return Heap::true_value(); | 2420 case PIXEL_ELEMENTS: { |
2403 } else { | 2421 // Pixel elements cannot be deleted. Just silently ignore here. |
2404 NumberDictionary* dictionary = element_dictionary(); | 2422 break; |
2405 int entry = dictionary->FindEntry(index); | |
2406 if (entry != NumberDictionary::kNotFound) { | |
2407 return dictionary->DeleteProperty(entry, mode); | |
2408 } | 2423 } |
| 2424 case DICTIONARY_ELEMENTS: { |
| 2425 NumberDictionary* dictionary = element_dictionary(); |
| 2426 int entry = dictionary->FindEntry(index); |
| 2427 if (entry != NumberDictionary::kNotFound) { |
| 2428 return dictionary->DeleteProperty(entry, mode); |
| 2429 } |
| 2430 break; |
| 2431 } |
| 2432 default: |
| 2433 UNREACHABLE(); |
| 2434 break; |
2409 } | 2435 } |
2410 return Heap::true_value(); | 2436 return Heap::true_value(); |
2411 } | 2437 } |
2412 | 2438 |
2413 | 2439 |
2414 Object* JSObject::DeleteProperty(String* name, DeleteMode mode) { | 2440 Object* JSObject::DeleteProperty(String* name, DeleteMode mode) { |
2415 // ECMA-262, 3rd, 8.6.2.5 | 2441 // ECMA-262, 3rd, 8.6.2.5 |
2416 ASSERT(name->IsString()); | 2442 ASSERT(name->IsString()); |
2417 | 2443 |
2418 // Check access rights if needed. | 2444 // Check access rights if needed. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2476 return true; | 2502 return true; |
2477 } | 2503 } |
2478 | 2504 |
2479 // Check if the object is among the named properties. | 2505 // Check if the object is among the named properties. |
2480 Object* key = SlowReverseLookup(obj); | 2506 Object* key = SlowReverseLookup(obj); |
2481 if (key != Heap::undefined_value()) { | 2507 if (key != Heap::undefined_value()) { |
2482 return true; | 2508 return true; |
2483 } | 2509 } |
2484 | 2510 |
2485 // Check if the object is among the indexed properties. | 2511 // Check if the object is among the indexed properties. |
2486 if (HasFastElements()) { | 2512 switch (GetElementsKind()) { |
2487 int length = IsJSArray() | 2513 case PIXEL_ELEMENTS: |
2488 ? Smi::cast(JSArray::cast(this)->length())->value() | 2514 // Raw pixels do not reference other objects. |
2489 : FixedArray::cast(elements())->length(); | 2515 break; |
2490 for (int i = 0; i < length; i++) { | 2516 case FAST_ELEMENTS: { |
2491 Object* element = FixedArray::cast(elements())->get(i); | 2517 int length = IsJSArray() ? |
2492 if (!element->IsTheHole() && element == obj) { | 2518 Smi::cast(JSArray::cast(this)->length())->value() : |
| 2519 FixedArray::cast(elements())->length(); |
| 2520 for (int i = 0; i < length; i++) { |
| 2521 Object* element = FixedArray::cast(elements())->get(i); |
| 2522 if (!element->IsTheHole() && element == obj) { |
| 2523 return true; |
| 2524 } |
| 2525 } |
| 2526 break; |
| 2527 } |
| 2528 case DICTIONARY_ELEMENTS: { |
| 2529 key = element_dictionary()->SlowReverseLookup(obj); |
| 2530 if (key != Heap::undefined_value()) { |
2493 return true; | 2531 return true; |
2494 } | 2532 } |
| 2533 break; |
2495 } | 2534 } |
2496 } else { | 2535 default: |
2497 key = element_dictionary()->SlowReverseLookup(obj); | 2536 UNREACHABLE(); |
2498 if (key != Heap::undefined_value()) { | 2537 break; |
2499 return true; | |
2500 } | |
2501 } | 2538 } |
2502 | 2539 |
2503 // For functions check the context. Boilerplate functions do | 2540 // For functions check the context. Boilerplate functions do |
2504 // not have to be traversed since they have no real context. | 2541 // not have to be traversed since they have no real context. |
2505 if (IsJSFunction() && !JSFunction::cast(this)->IsBoilerplate()) { | 2542 if (IsJSFunction() && !JSFunction::cast(this)->IsBoilerplate()) { |
2506 // Get the constructor function for arguments array. | 2543 // Get the constructor function for arguments array. |
2507 JSObject* arguments_boilerplate = | 2544 JSObject* arguments_boilerplate = |
2508 Top::context()->global_context()->arguments_boilerplate(); | 2545 Top::context()->global_context()->arguments_boilerplate(); |
2509 JSFunction* arguments_function = | 2546 JSFunction* arguments_function = |
2510 JSFunction::cast(arguments_boilerplate->map()->constructor()); | 2547 JSFunction::cast(arguments_boilerplate->map()->constructor()); |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2708 AccessorInfo::cast(obj)->prohibits_overwriting()) { | 2745 AccessorInfo::cast(obj)->prohibits_overwriting()) { |
2709 return Heap::undefined_value(); | 2746 return Heap::undefined_value(); |
2710 } | 2747 } |
2711 } | 2748 } |
2712 | 2749 |
2713 uint32_t index; | 2750 uint32_t index; |
2714 bool is_element = name->AsArrayIndex(&index); | 2751 bool is_element = name->AsArrayIndex(&index); |
2715 if (is_element && IsJSArray()) return Heap::undefined_value(); | 2752 if (is_element && IsJSArray()) return Heap::undefined_value(); |
2716 | 2753 |
2717 if (is_element) { | 2754 if (is_element) { |
2718 // Lookup the index. | 2755 switch (GetElementsKind()) { |
2719 if (!HasFastElements()) { | 2756 case FAST_ELEMENTS: |
2720 NumberDictionary* dictionary = element_dictionary(); | 2757 break; |
2721 int entry = dictionary->FindEntry(index); | 2758 case PIXEL_ELEMENTS: |
2722 if (entry != NumberDictionary::kNotFound) { | 2759 // Ignore getters and setters on pixel elements. |
2723 Object* result = dictionary->ValueAt(entry); | 2760 return Heap::undefined_value(); |
2724 PropertyDetails details = dictionary->DetailsAt(entry); | 2761 case DICTIONARY_ELEMENTS: { |
2725 if (details.IsReadOnly()) return Heap::undefined_value(); | 2762 // Lookup the index. |
2726 if (details.type() == CALLBACKS) { | 2763 NumberDictionary* dictionary = element_dictionary(); |
2727 // Only accessors allowed as elements. | 2764 int entry = dictionary->FindEntry(index); |
2728 ASSERT(result->IsFixedArray()); | 2765 if (entry != NumberDictionary::kNotFound) { |
2729 return result; | 2766 Object* result = dictionary->ValueAt(entry); |
| 2767 PropertyDetails details = dictionary->DetailsAt(entry); |
| 2768 if (details.IsReadOnly()) return Heap::undefined_value(); |
| 2769 if (details.type() == CALLBACKS) { |
| 2770 // Only accessors allowed as elements. |
| 2771 ASSERT(result->IsFixedArray()); |
| 2772 return result; |
| 2773 } |
2730 } | 2774 } |
| 2775 break; |
2731 } | 2776 } |
| 2777 default: |
| 2778 UNREACHABLE(); |
| 2779 break; |
2732 } | 2780 } |
2733 } else { | 2781 } else { |
2734 // Lookup the name. | 2782 // Lookup the name. |
2735 LookupResult result; | 2783 LookupResult result; |
2736 LocalLookup(name, &result); | 2784 LocalLookup(name, &result); |
2737 if (result.IsValid()) { | 2785 if (result.IsValid()) { |
2738 if (result.IsReadOnly()) return Heap::undefined_value(); | 2786 if (result.IsReadOnly()) return Heap::undefined_value(); |
2739 if (result.type() == CALLBACKS) { | 2787 if (result.type() == CALLBACKS) { |
2740 Object* obj = result.GetCallbackObject(); | 2788 Object* obj = result.GetCallbackObject(); |
2741 if (obj->IsFixedArray()) return obj; | 2789 if (obj->IsFixedArray()) return obj; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2820 return Heap::undefined_value(); | 2868 return Heap::undefined_value(); |
2821 } | 2869 } |
2822 | 2870 |
2823 // Make the lookup and include prototypes. | 2871 // Make the lookup and include prototypes. |
2824 int accessor_index = is_getter ? kGetterIndex : kSetterIndex; | 2872 int accessor_index = is_getter ? kGetterIndex : kSetterIndex; |
2825 uint32_t index; | 2873 uint32_t index; |
2826 if (name->AsArrayIndex(&index)) { | 2874 if (name->AsArrayIndex(&index)) { |
2827 for (Object* obj = this; | 2875 for (Object* obj = this; |
2828 obj != Heap::null_value(); | 2876 obj != Heap::null_value(); |
2829 obj = JSObject::cast(obj)->GetPrototype()) { | 2877 obj = JSObject::cast(obj)->GetPrototype()) { |
2830 JSObject* jsObject = JSObject::cast(obj); | 2878 JSObject* js_object = JSObject::cast(obj); |
2831 if (!jsObject->HasFastElements()) { | 2879 if (js_object->HasDictionaryElements()) { |
2832 NumberDictionary* dictionary = jsObject->element_dictionary(); | 2880 NumberDictionary* dictionary = js_object->element_dictionary(); |
2833 int entry = dictionary->FindEntry(index); | 2881 int entry = dictionary->FindEntry(index); |
2834 if (entry != NumberDictionary::kNotFound) { | 2882 if (entry != NumberDictionary::kNotFound) { |
2835 Object* element = dictionary->ValueAt(entry); | 2883 Object* element = dictionary->ValueAt(entry); |
2836 PropertyDetails details = dictionary->DetailsAt(entry); | 2884 PropertyDetails details = dictionary->DetailsAt(entry); |
2837 if (details.type() == CALLBACKS) { | 2885 if (details.type() == CALLBACKS) { |
2838 // Only accessors allowed as elements. | 2886 // Only accessors allowed as elements. |
2839 return FixedArray::cast(element)->get(accessor_index); | 2887 return FixedArray::cast(element)->get(accessor_index); |
2840 } | 2888 } |
2841 } | 2889 } |
2842 } | 2890 } |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3022 if (element->IsString() && | 3070 if (element->IsString() && |
3023 key->IsString() && String::cast(element)->Equals(String::cast(key))) { | 3071 key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
3024 return true; | 3072 return true; |
3025 } | 3073 } |
3026 } | 3074 } |
3027 return false; | 3075 return false; |
3028 } | 3076 } |
3029 | 3077 |
3030 | 3078 |
3031 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { | 3079 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { |
3032 if (array->HasFastElements()) { | 3080 ASSERT(!array->HasPixelElements()); |
3033 return UnionOfKeys(array->elements()); | 3081 switch (array->GetElementsKind()) { |
| 3082 case JSObject::FAST_ELEMENTS: |
| 3083 return UnionOfKeys(FixedArray::cast(array->elements())); |
| 3084 case JSObject::DICTIONARY_ELEMENTS: { |
| 3085 NumberDictionary* dict = array->element_dictionary(); |
| 3086 int size = dict->NumberOfElements(); |
| 3087 |
| 3088 // Allocate a temporary fixed array. |
| 3089 Object* object = Heap::AllocateFixedArray(size); |
| 3090 if (object->IsFailure()) return object; |
| 3091 FixedArray* key_array = FixedArray::cast(object); |
| 3092 |
| 3093 int capacity = dict->Capacity(); |
| 3094 int pos = 0; |
| 3095 // Copy the elements from the JSArray to the temporary fixed array. |
| 3096 for (int i = 0; i < capacity; i++) { |
| 3097 if (dict->IsKey(dict->KeyAt(i))) { |
| 3098 key_array->set(pos++, dict->ValueAt(i)); |
| 3099 } |
| 3100 } |
| 3101 // Compute the union of this and the temporary fixed array. |
| 3102 return UnionOfKeys(key_array); |
| 3103 } |
| 3104 default: |
| 3105 UNREACHABLE(); |
3034 } | 3106 } |
3035 ASSERT(!array->HasFastElements()); | 3107 UNREACHABLE(); |
3036 NumberDictionary* dict = array->element_dictionary(); | 3108 return Heap::null_value(); // Failure case needs to "return" a value. |
3037 int size = dict->NumberOfElements(); | |
3038 | |
3039 // Allocate a temporary fixed array. | |
3040 Object* object = Heap::AllocateFixedArray(size); | |
3041 if (object->IsFailure()) return object; | |
3042 FixedArray* key_array = FixedArray::cast(object); | |
3043 | |
3044 int capacity = dict->Capacity(); | |
3045 int pos = 0; | |
3046 // Copy the elements from the JSArray to the temporary fixed array. | |
3047 for (int i = 0; i < capacity; i++) { | |
3048 if (dict->IsKey(dict->KeyAt(i))) { | |
3049 key_array->set(pos++, dict->ValueAt(i)); | |
3050 } | |
3051 } | |
3052 // Compute the union of this and the temporary fixed array. | |
3053 return UnionOfKeys(key_array); | |
3054 } | 3109 } |
3055 | 3110 |
3056 | 3111 |
3057 Object* FixedArray::UnionOfKeys(FixedArray* other) { | 3112 Object* FixedArray::UnionOfKeys(FixedArray* other) { |
3058 int len0 = length(); | 3113 int len0 = length(); |
3059 int len1 = other->length(); | 3114 int len1 = other->length(); |
3060 // Optimize if either is empty. | 3115 // Optimize if either is empty. |
3061 if (len0 == 0) return other; | 3116 if (len0 == 0) return other; |
3062 if (len1 == 0) return this; | 3117 if (len1 == 0) return this; |
3063 | 3118 |
(...skipping 2018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5082 | 5137 |
5083 PrintF("RelocInfo (size = %d)\n", relocation_size()); | 5138 PrintF("RelocInfo (size = %d)\n", relocation_size()); |
5084 for (RelocIterator it(this); !it.done(); it.next()) | 5139 for (RelocIterator it(this); !it.done(); it.next()) |
5085 it.rinfo()->Print(); | 5140 it.rinfo()->Print(); |
5086 PrintF("\n"); | 5141 PrintF("\n"); |
5087 } | 5142 } |
5088 #endif // ENABLE_DISASSEMBLER | 5143 #endif // ENABLE_DISASSEMBLER |
5089 | 5144 |
5090 | 5145 |
5091 void JSObject::SetFastElements(FixedArray* elems) { | 5146 void JSObject::SetFastElements(FixedArray* elems) { |
| 5147 // We should never end in here with a pixel array. |
| 5148 ASSERT(!HasPixelElements()); |
5092 #ifdef DEBUG | 5149 #ifdef DEBUG |
5093 // Check the provided array is filled with the_hole. | 5150 // Check the provided array is filled with the_hole. |
5094 uint32_t len = static_cast<uint32_t>(elems->length()); | 5151 uint32_t len = static_cast<uint32_t>(elems->length()); |
5095 for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole()); | 5152 for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole()); |
5096 #endif | 5153 #endif |
5097 WriteBarrierMode mode = elems->GetWriteBarrierMode(); | 5154 WriteBarrierMode mode = elems->GetWriteBarrierMode(); |
5098 if (HasFastElements()) { | 5155 switch (GetElementsKind()) { |
5099 FixedArray* old_elements = FixedArray::cast(elements()); | 5156 case FAST_ELEMENTS: { |
5100 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 5157 FixedArray* old_elements = FixedArray::cast(elements()); |
5101 // Fill out the new array with this content and array holes. | 5158 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
5102 for (uint32_t i = 0; i < old_length; i++) { | 5159 // Fill out the new array with this content and array holes. |
5103 elems->set(i, old_elements->get(i), mode); | 5160 for (uint32_t i = 0; i < old_length; i++) { |
| 5161 elems->set(i, old_elements->get(i), mode); |
| 5162 } |
| 5163 break; |
5104 } | 5164 } |
5105 } else { | 5165 case DICTIONARY_ELEMENTS: { |
5106 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 5166 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
5107 for (int i = 0; i < dictionary->Capacity(); i++) { | 5167 for (int i = 0; i < dictionary->Capacity(); i++) { |
5108 Object* key = dictionary->KeyAt(i); | 5168 Object* key = dictionary->KeyAt(i); |
5109 if (key->IsNumber()) { | 5169 if (key->IsNumber()) { |
5110 uint32_t entry = static_cast<uint32_t>(key->Number()); | 5170 uint32_t entry = static_cast<uint32_t>(key->Number()); |
5111 elems->set(entry, dictionary->ValueAt(i), mode); | 5171 elems->set(entry, dictionary->ValueAt(i), mode); |
| 5172 } |
5112 } | 5173 } |
| 5174 break; |
5113 } | 5175 } |
| 5176 default: |
| 5177 UNREACHABLE(); |
| 5178 break; |
5114 } | 5179 } |
5115 set_elements(elems); | 5180 set_elements(elems); |
5116 } | 5181 } |
5117 | 5182 |
5118 | 5183 |
5119 Object* JSObject::SetSlowElements(Object* len) { | 5184 Object* JSObject::SetSlowElements(Object* len) { |
| 5185 // We should never end in here with a pixel array. |
| 5186 ASSERT(!HasPixelElements()); |
| 5187 |
5120 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 5188 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
5121 | 5189 |
5122 if (!HasFastElements()) { | 5190 switch (GetElementsKind()) { |
5123 if (IsJSArray()) { | 5191 case FAST_ELEMENTS: { |
5124 uint32_t old_length = | 5192 // Make sure we never try to shrink dense arrays into sparse arrays. |
5125 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 5193 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= |
5126 element_dictionary()->RemoveNumberEntries(new_length, old_length), | 5194 new_length); |
5127 JSArray::cast(this)->set_length(len); | 5195 Object* obj = NormalizeElements(); |
| 5196 if (obj->IsFailure()) return obj; |
| 5197 |
| 5198 // Update length for JSArrays. |
| 5199 if (IsJSArray()) JSArray::cast(this)->set_length(len); |
| 5200 break; |
5128 } | 5201 } |
5129 return this; | 5202 case DICTIONARY_ELEMENTS: { |
| 5203 if (IsJSArray()) { |
| 5204 uint32_t old_length = |
| 5205 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 5206 element_dictionary()->RemoveNumberEntries(new_length, old_length), |
| 5207 JSArray::cast(this)->set_length(len); |
| 5208 } |
| 5209 break; |
| 5210 } |
| 5211 default: |
| 5212 UNREACHABLE(); |
| 5213 break; |
5130 } | 5214 } |
5131 | |
5132 // Make sure we never try to shrink dense arrays into sparse arrays. | |
5133 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= | |
5134 new_length); | |
5135 Object* obj = NormalizeElements(); | |
5136 if (obj->IsFailure()) return obj; | |
5137 | |
5138 // Update length for JSArrays. | |
5139 if (IsJSArray()) JSArray::cast(this)->set_length(len); | |
5140 return this; | 5215 return this; |
5141 } | 5216 } |
5142 | 5217 |
5143 | 5218 |
5144 Object* JSArray::Initialize(int capacity) { | 5219 Object* JSArray::Initialize(int capacity) { |
5145 ASSERT(capacity >= 0); | 5220 ASSERT(capacity >= 0); |
5146 set_length(Smi::FromInt(0), SKIP_WRITE_BARRIER); | 5221 set_length(Smi::FromInt(0), SKIP_WRITE_BARRIER); |
5147 FixedArray* new_elements; | 5222 FixedArray* new_elements; |
5148 if (capacity == 0) { | 5223 if (capacity == 0) { |
5149 new_elements = Heap::empty_fixed_array(); | 5224 new_elements = Heap::empty_fixed_array(); |
5150 } else { | 5225 } else { |
5151 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); | 5226 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); |
5152 if (obj->IsFailure()) return obj; | 5227 if (obj->IsFailure()) return obj; |
5153 new_elements = FixedArray::cast(obj); | 5228 new_elements = FixedArray::cast(obj); |
5154 } | 5229 } |
5155 set_elements(new_elements); | 5230 set_elements(new_elements); |
5156 return this; | 5231 return this; |
5157 } | 5232 } |
5158 | 5233 |
5159 | 5234 |
5160 void JSArray::Expand(int required_size) { | 5235 void JSArray::Expand(int required_size) { |
5161 Handle<JSArray> self(this); | 5236 Handle<JSArray> self(this); |
5162 Handle<FixedArray> old_backing(elements()); | 5237 Handle<FixedArray> old_backing(FixedArray::cast(elements())); |
5163 int old_size = old_backing->length(); | 5238 int old_size = old_backing->length(); |
5164 // Doubling in size would be overkill, but leave some slack to avoid | 5239 // Doubling in size would be overkill, but leave some slack to avoid |
5165 // constantly growing. | 5240 // constantly growing. |
5166 int new_size = required_size + (required_size >> 3); | 5241 int new_size = required_size + (required_size >> 3); |
5167 Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size); | 5242 Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size); |
5168 // Can't use this any more now because we may have had a GC! | 5243 // Can't use this any more now because we may have had a GC! |
5169 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); | 5244 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); |
5170 self->SetContent(*new_backing); | 5245 self->SetContent(*new_backing); |
5171 } | 5246 } |
5172 | 5247 |
5173 | 5248 |
5174 // Computes the new capacity when expanding the elements of a JSObject. | 5249 // Computes the new capacity when expanding the elements of a JSObject. |
5175 static int NewElementsCapacity(int old_capacity) { | 5250 static int NewElementsCapacity(int old_capacity) { |
5176 // (old_capacity + 50%) + 16 | 5251 // (old_capacity + 50%) + 16 |
5177 return old_capacity + (old_capacity >> 1) + 16; | 5252 return old_capacity + (old_capacity >> 1) + 16; |
5178 } | 5253 } |
5179 | 5254 |
5180 | 5255 |
5181 static Object* ArrayLengthRangeError() { | 5256 static Object* ArrayLengthRangeError() { |
5182 HandleScope scope; | 5257 HandleScope scope; |
5183 return Top::Throw(*Factory::NewRangeError("invalid_array_length", | 5258 return Top::Throw(*Factory::NewRangeError("invalid_array_length", |
5184 HandleVector<Object>(NULL, 0))); | 5259 HandleVector<Object>(NULL, 0))); |
5185 } | 5260 } |
5186 | 5261 |
5187 | 5262 |
5188 Object* JSObject::SetElementsLength(Object* len) { | 5263 Object* JSObject::SetElementsLength(Object* len) { |
| 5264 // We should never end in here with a pixel array. |
| 5265 ASSERT(!HasPixelElements()); |
| 5266 |
5189 Object* smi_length = len->ToSmi(); | 5267 Object* smi_length = len->ToSmi(); |
5190 if (smi_length->IsSmi()) { | 5268 if (smi_length->IsSmi()) { |
5191 int value = Smi::cast(smi_length)->value(); | 5269 int value = Smi::cast(smi_length)->value(); |
5192 if (value < 0) return ArrayLengthRangeError(); | 5270 if (value < 0) return ArrayLengthRangeError(); |
5193 if (HasFastElements()) { | 5271 switch (GetElementsKind()) { |
5194 int old_capacity = FixedArray::cast(elements())->length(); | 5272 case FAST_ELEMENTS: { |
5195 if (value <= old_capacity) { | 5273 int old_capacity = FixedArray::cast(elements())->length(); |
| 5274 if (value <= old_capacity) { |
| 5275 if (IsJSArray()) { |
| 5276 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); |
| 5277 // NOTE: We may be able to optimize this by removing the |
| 5278 // last part of the elements backing storage array and |
| 5279 // setting the capacity to the new size. |
| 5280 for (int i = value; i < old_length; i++) { |
| 5281 FixedArray::cast(elements())->set_the_hole(i); |
| 5282 } |
| 5283 JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); |
| 5284 } |
| 5285 return this; |
| 5286 } |
| 5287 int min = NewElementsCapacity(old_capacity); |
| 5288 int new_capacity = value > min ? value : min; |
| 5289 if (new_capacity <= kMaxFastElementsLength || |
| 5290 !ShouldConvertToSlowElements(new_capacity)) { |
| 5291 Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); |
| 5292 if (obj->IsFailure()) return obj; |
| 5293 if (IsJSArray()) JSArray::cast(this)->set_length(smi_length, |
| 5294 SKIP_WRITE_BARRIER); |
| 5295 SetFastElements(FixedArray::cast(obj)); |
| 5296 return this; |
| 5297 } |
| 5298 break; |
| 5299 } |
| 5300 case DICTIONARY_ELEMENTS: { |
5196 if (IsJSArray()) { | 5301 if (IsJSArray()) { |
5197 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); | 5302 if (value == 0) { |
5198 // NOTE: We may be able to optimize this by removing the | 5303 // If the length of a slow array is reset to zero, we clear |
5199 // last part of the elements backing storage array and | 5304 // the array and flush backing storage. This has the added |
5200 // setting the capacity to the new size. | 5305 // benefit that the array returns to fast mode. |
5201 for (int i = value; i < old_length; i++) { | 5306 initialize_elements(); |
5202 FixedArray::cast(elements())->set_the_hole(i); | 5307 } else { |
| 5308 // Remove deleted elements. |
| 5309 uint32_t old_length = |
| 5310 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 5311 element_dictionary()->RemoveNumberEntries(value, old_length); |
5203 } | 5312 } |
5204 JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); | 5313 JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); |
5205 } | 5314 } |
5206 return this; | 5315 return this; |
5207 } | 5316 } |
5208 int min = NewElementsCapacity(old_capacity); | 5317 default: |
5209 int new_capacity = value > min ? value : min; | 5318 UNREACHABLE(); |
5210 if (new_capacity <= kMaxFastElementsLength || | 5319 break; |
5211 !ShouldConvertToSlowElements(new_capacity)) { | |
5212 Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); | |
5213 if (obj->IsFailure()) return obj; | |
5214 if (IsJSArray()) JSArray::cast(this)->set_length(smi_length, | |
5215 SKIP_WRITE_BARRIER); | |
5216 SetFastElements(FixedArray::cast(obj)); | |
5217 return this; | |
5218 } | |
5219 } else { | |
5220 if (IsJSArray()) { | |
5221 if (value == 0) { | |
5222 // If the length of a slow array is reset to zero, we clear | |
5223 // the array and flush backing storage. This has the added | |
5224 // benefit that the array returns to fast mode. | |
5225 initialize_elements(); | |
5226 } else { | |
5227 // Remove deleted elements. | |
5228 uint32_t old_length = | |
5229 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | |
5230 element_dictionary()->RemoveNumberEntries(value, old_length); | |
5231 } | |
5232 JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); | |
5233 } | |
5234 return this; | |
5235 } | 5320 } |
5236 } | 5321 } |
5237 | 5322 |
5238 // General slow case. | 5323 // General slow case. |
5239 if (len->IsNumber()) { | 5324 if (len->IsNumber()) { |
5240 uint32_t length; | 5325 uint32_t length; |
5241 if (Array::IndexFromObject(len, &length)) { | 5326 if (Array::IndexFromObject(len, &length)) { |
5242 return SetSlowElements(len); | 5327 return SetSlowElements(len); |
5243 } else { | 5328 } else { |
5244 return ArrayLengthRangeError(); | 5329 return ArrayLengthRangeError(); |
5245 } | 5330 } |
5246 } | 5331 } |
5247 | 5332 |
5248 // len is not a number so make the array size one and | 5333 // len is not a number so make the array size one and |
5249 // set only element to len. | 5334 // set only element to len. |
5250 Object* obj = Heap::AllocateFixedArray(1); | 5335 Object* obj = Heap::AllocateFixedArray(1); |
5251 if (obj->IsFailure()) return obj; | 5336 if (obj->IsFailure()) return obj; |
5252 FixedArray::cast(obj)->set(0, len); | 5337 FixedArray::cast(obj)->set(0, len); |
5253 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1), | 5338 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1), |
5254 SKIP_WRITE_BARRIER); | 5339 SKIP_WRITE_BARRIER); |
5255 set_elements(FixedArray::cast(obj)); | 5340 set_elements(FixedArray::cast(obj)); |
5256 return this; | 5341 return this; |
5257 } | 5342 } |
5258 | 5343 |
5259 | 5344 |
5260 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { | 5345 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { |
5261 if (HasFastElements()) { | 5346 switch (GetElementsKind()) { |
5262 uint32_t length = IsJSArray() ? | 5347 case FAST_ELEMENTS: { |
5263 static_cast<uint32_t>( | 5348 uint32_t length = IsJSArray() ? |
5264 Smi::cast(JSArray::cast(this)->length())->value()) : | 5349 static_cast<uint32_t> |
5265 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 5350 (Smi::cast(JSArray::cast(this)->length())->value()) : |
5266 if ((index < length) && | 5351 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
5267 !FixedArray::cast(elements())->get(index)->IsTheHole()) { | 5352 if ((index < length) && |
5268 return true; | 5353 !FixedArray::cast(elements())->get(index)->IsTheHole()) { |
| 5354 return true; |
| 5355 } |
| 5356 break; |
5269 } | 5357 } |
5270 } else { | 5358 case PIXEL_ELEMENTS: { |
5271 if (element_dictionary()->FindEntry(index) | 5359 // TODO(iposva): Add testcase. |
5272 != NumberDictionary::kNotFound) { | 5360 PixelArray* pixels = PixelArray::cast(elements()); |
5273 return true; | 5361 if (index < static_cast<uint32_t>(pixels->length())) { |
| 5362 return true; |
| 5363 } |
| 5364 break; |
5274 } | 5365 } |
| 5366 case DICTIONARY_ELEMENTS: { |
| 5367 if (element_dictionary()->FindEntry(index) |
| 5368 != NumberDictionary::kNotFound) { |
| 5369 return true; |
| 5370 } |
| 5371 break; |
| 5372 } |
| 5373 default: |
| 5374 UNREACHABLE(); |
| 5375 break; |
5275 } | 5376 } |
5276 | 5377 |
5277 // Handle [] on String objects. | 5378 // Handle [] on String objects. |
5278 if (this->IsStringObjectWithCharacterAt(index)) return true; | 5379 if (this->IsStringObjectWithCharacterAt(index)) return true; |
5279 | 5380 |
5280 Object* pt = GetPrototype(); | 5381 Object* pt = GetPrototype(); |
5281 if (pt == Heap::null_value()) return false; | 5382 if (pt == Heap::null_value()) return false; |
5282 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 5383 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
5283 } | 5384 } |
5284 | 5385 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5331 } | 5432 } |
5332 | 5433 |
5333 // Check for lookup interceptor | 5434 // Check for lookup interceptor |
5334 if (HasIndexedInterceptor()) { | 5435 if (HasIndexedInterceptor()) { |
5335 return HasElementWithInterceptor(this, index); | 5436 return HasElementWithInterceptor(this, index); |
5336 } | 5437 } |
5337 | 5438 |
5338 // Handle [] on String objects. | 5439 // Handle [] on String objects. |
5339 if (this->IsStringObjectWithCharacterAt(index)) return true; | 5440 if (this->IsStringObjectWithCharacterAt(index)) return true; |
5340 | 5441 |
5341 if (HasFastElements()) { | 5442 switch (GetElementsKind()) { |
5342 uint32_t length = IsJSArray() ? | 5443 case FAST_ELEMENTS: { |
5343 static_cast<uint32_t>( | 5444 uint32_t length = IsJSArray() ? |
5344 Smi::cast(JSArray::cast(this)->length())->value()) : | 5445 static_cast<uint32_t> |
5345 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 5446 (Smi::cast(JSArray::cast(this)->length())->value()) : |
5346 return (index < length) && | 5447 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
5347 !FixedArray::cast(elements())->get(index)->IsTheHole(); | 5448 return (index < length) && |
5348 } else { | 5449 !FixedArray::cast(elements())->get(index)->IsTheHole(); |
5349 return element_dictionary()->FindEntry(index) | 5450 } |
5350 != NumberDictionary::kNotFound; | 5451 case PIXEL_ELEMENTS: { |
| 5452 PixelArray* pixels = PixelArray::cast(elements()); |
| 5453 return (index < static_cast<uint32_t>(pixels->length())); |
| 5454 } |
| 5455 case DICTIONARY_ELEMENTS: { |
| 5456 return element_dictionary()->FindEntry(index) |
| 5457 != NumberDictionary::kNotFound; |
| 5458 } |
| 5459 default: |
| 5460 UNREACHABLE(); |
| 5461 break; |
5351 } | 5462 } |
| 5463 UNREACHABLE(); |
| 5464 return Heap::null_value(); |
5352 } | 5465 } |
5353 | 5466 |
5354 | 5467 |
5355 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { | 5468 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { |
5356 // Check access rights if needed. | 5469 // Check access rights if needed. |
5357 if (IsAccessCheckNeeded() && | 5470 if (IsAccessCheckNeeded() && |
5358 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | 5471 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
5359 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 5472 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
5360 return false; | 5473 return false; |
5361 } | 5474 } |
5362 | 5475 |
5363 // Check for lookup interceptor | 5476 // Check for lookup interceptor |
5364 if (HasIndexedInterceptor()) { | 5477 if (HasIndexedInterceptor()) { |
5365 return HasElementWithInterceptor(receiver, index); | 5478 return HasElementWithInterceptor(receiver, index); |
5366 } | 5479 } |
5367 | 5480 |
5368 if (HasFastElements()) { | 5481 switch (GetElementsKind()) { |
5369 uint32_t length = IsJSArray() ? | 5482 case FAST_ELEMENTS: { |
5370 static_cast<uint32_t>( | 5483 uint32_t length = IsJSArray() ? |
5371 Smi::cast(JSArray::cast(this)->length())->value()) : | 5484 static_cast<uint32_t> |
5372 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 5485 (Smi::cast(JSArray::cast(this)->length())->value()) : |
5373 if ((index < length) && | 5486 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
5374 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; | 5487 if ((index < length) && |
5375 } else { | 5488 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; |
5376 if (element_dictionary()->FindEntry(index) | 5489 break; |
5377 != NumberDictionary::kNotFound) { | |
5378 return true; | |
5379 } | 5490 } |
| 5491 case PIXEL_ELEMENTS: { |
| 5492 PixelArray* pixels = PixelArray::cast(elements()); |
| 5493 if (index < static_cast<uint32_t>(pixels->length())) { |
| 5494 return true; |
| 5495 } |
| 5496 break; |
| 5497 } |
| 5498 case DICTIONARY_ELEMENTS: { |
| 5499 if (element_dictionary()->FindEntry(index) |
| 5500 != NumberDictionary::kNotFound) { |
| 5501 return true; |
| 5502 } |
| 5503 break; |
| 5504 } |
| 5505 default: |
| 5506 UNREACHABLE(); |
| 5507 break; |
5380 } | 5508 } |
5381 | 5509 |
5382 // Handle [] on String objects. | 5510 // Handle [] on String objects. |
5383 if (this->IsStringObjectWithCharacterAt(index)) return true; | 5511 if (this->IsStringObjectWithCharacterAt(index)) return true; |
5384 | 5512 |
5385 Object* pt = GetPrototype(); | 5513 Object* pt = GetPrototype(); |
5386 if (pt == Heap::null_value()) return false; | 5514 if (pt == Heap::null_value()) return false; |
5387 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 5515 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
5388 } | 5516 } |
5389 | 5517 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5465 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(index + 1), | 5593 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(index + 1), |
5466 SKIP_WRITE_BARRIER); | 5594 SKIP_WRITE_BARRIER); |
5467 FixedArray::cast(elements())->set(index, value); | 5595 FixedArray::cast(elements())->set(index, value); |
5468 return value; | 5596 return value; |
5469 } | 5597 } |
5470 } | 5598 } |
5471 | 5599 |
5472 // Otherwise default to slow case. | 5600 // Otherwise default to slow case. |
5473 Object* obj = NormalizeElements(); | 5601 Object* obj = NormalizeElements(); |
5474 if (obj->IsFailure()) return obj; | 5602 if (obj->IsFailure()) return obj; |
5475 ASSERT(!HasFastElements()); | 5603 ASSERT(HasDictionaryElements()); |
5476 return SetElement(index, value); | 5604 return SetElement(index, value); |
5477 } | 5605 } |
5478 | 5606 |
5479 Object* JSObject::SetElement(uint32_t index, Object* value) { | 5607 Object* JSObject::SetElement(uint32_t index, Object* value) { |
5480 // Check access rights if needed. | 5608 // Check access rights if needed. |
5481 if (IsAccessCheckNeeded() && | 5609 if (IsAccessCheckNeeded() && |
5482 !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) { | 5610 !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) { |
5483 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); | 5611 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); |
5484 return value; | 5612 return value; |
5485 } | 5613 } |
5486 | 5614 |
5487 if (IsJSGlobalProxy()) { | 5615 if (IsJSGlobalProxy()) { |
5488 Object* proto = GetPrototype(); | 5616 Object* proto = GetPrototype(); |
5489 if (proto->IsNull()) return value; | 5617 if (proto->IsNull()) return value; |
5490 ASSERT(proto->IsJSGlobalObject()); | 5618 ASSERT(proto->IsJSGlobalObject()); |
5491 return JSObject::cast(proto)->SetElement(index, value); | 5619 return JSObject::cast(proto)->SetElement(index, value); |
5492 } | 5620 } |
5493 | 5621 |
5494 // Check for lookup interceptor | 5622 // Check for lookup interceptor |
5495 if (HasIndexedInterceptor()) { | 5623 if (HasIndexedInterceptor()) { |
5496 return SetElementWithInterceptor(index, value); | 5624 return SetElementWithInterceptor(index, value); |
5497 } | 5625 } |
5498 | 5626 |
5499 return SetElementWithoutInterceptor(index, value); | 5627 return SetElementWithoutInterceptor(index, value); |
5500 } | 5628 } |
5501 | 5629 |
5502 | 5630 |
5503 Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { | 5631 Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { |
5504 // Fast case. | 5632 switch (GetElementsKind()) { |
5505 if (HasFastElements()) return SetFastElement(index, value); | 5633 case FAST_ELEMENTS: |
| 5634 // Fast case. |
| 5635 return SetFastElement(index, value); |
| 5636 case PIXEL_ELEMENTS: { |
| 5637 PixelArray* pixels = PixelArray::cast(elements()); |
| 5638 return pixels->SetValue(index, value); |
| 5639 } |
| 5640 case DICTIONARY_ELEMENTS: { |
| 5641 // Insert element in the dictionary. |
| 5642 FixedArray* elms = FixedArray::cast(elements()); |
| 5643 NumberDictionary* dictionary = NumberDictionary::cast(elms); |
5506 | 5644 |
5507 // Dictionary case. | 5645 int entry = dictionary->FindEntry(index); |
5508 ASSERT(!HasFastElements()); | 5646 if (entry != NumberDictionary::kNotFound) { |
| 5647 Object* element = dictionary->ValueAt(entry); |
| 5648 PropertyDetails details = dictionary->DetailsAt(entry); |
| 5649 if (details.type() == CALLBACKS) { |
| 5650 // Only accessors allowed as elements. |
| 5651 FixedArray* structure = FixedArray::cast(element); |
| 5652 if (structure->get(kSetterIndex)->IsJSFunction()) { |
| 5653 JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex)); |
| 5654 return SetPropertyWithDefinedSetter(setter, value); |
| 5655 } else { |
| 5656 Handle<Object> self(this); |
| 5657 Handle<Object> key(Factory::NewNumberFromUint(index)); |
| 5658 Handle<Object> args[2] = { key, self }; |
| 5659 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", |
| 5660 HandleVector(args, 2))); |
| 5661 } |
| 5662 } else { |
| 5663 dictionary->UpdateMaxNumberKey(index); |
| 5664 dictionary->ValueAtPut(entry, value); |
| 5665 } |
| 5666 } else { |
| 5667 // Index not already used. Look for an accessor in the prototype chain. |
| 5668 if (!IsJSArray()) { |
| 5669 Object* setter = LookupCallbackSetterInPrototypes(index); |
| 5670 if (setter->IsJSFunction()) { |
| 5671 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), |
| 5672 value); |
| 5673 } |
| 5674 } |
| 5675 Object* result = dictionary->AtNumberPut(index, value); |
| 5676 if (result->IsFailure()) return result; |
| 5677 if (elms != FixedArray::cast(result)) { |
| 5678 set_elements(FixedArray::cast(result)); |
| 5679 } |
| 5680 } |
5509 | 5681 |
5510 // Insert element in the dictionary. | 5682 // Update the array length if this JSObject is an array. |
5511 FixedArray* elms = FixedArray::cast(elements()); | 5683 if (IsJSArray()) { |
5512 NumberDictionary* dictionary = NumberDictionary::cast(elms); | 5684 JSArray* array = JSArray::cast(this); |
| 5685 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, |
| 5686 value); |
| 5687 if (return_value->IsFailure()) return return_value; |
| 5688 } |
5513 | 5689 |
5514 int entry = dictionary->FindEntry(index); | 5690 // Attempt to put this object back in fast case. |
5515 if (entry != NumberDictionary::kNotFound) { | 5691 if (ShouldConvertToFastElements()) { |
5516 Object* element = dictionary->ValueAt(entry); | 5692 uint32_t new_length = 0; |
5517 PropertyDetails details = dictionary->DetailsAt(entry); | 5693 if (IsJSArray()) { |
5518 if (details.type() == CALLBACKS) { | 5694 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), |
5519 // Only accessors allowed as elements. | 5695 &new_length)); |
5520 FixedArray* structure = FixedArray::cast(element); | 5696 JSArray::cast(this)->set_length(Smi::FromInt(new_length)); |
5521 if (structure->get(kSetterIndex)->IsJSFunction()) { | 5697 } else { |
5522 JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex)); | 5698 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; |
5523 return SetPropertyWithDefinedSetter(setter, value); | 5699 } |
5524 } else { | 5700 Object* obj = Heap::AllocateFixedArrayWithHoles(new_length); |
5525 Handle<Object> self(this); | 5701 if (obj->IsFailure()) return obj; |
5526 Handle<Object> key(Factory::NewNumberFromUint(index)); | 5702 SetFastElements(FixedArray::cast(obj)); |
5527 Handle<Object> args[2] = { key, self }; | 5703 #ifdef DEBUG |
5528 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", | 5704 if (FLAG_trace_normalization) { |
5529 HandleVector(args, 2))); | 5705 PrintF("Object elements are fast case again:\n"); |
| 5706 Print(); |
| 5707 } |
| 5708 #endif |
5530 } | 5709 } |
5531 } else { | 5710 |
5532 dictionary->UpdateMaxNumberKey(index); | 5711 return value; |
5533 dictionary->ValueAtPut(entry, value); | |
5534 } | 5712 } |
5535 } else { | 5713 default: |
5536 // Index not already used. Look for an accessor in the prototype chain. | 5714 UNREACHABLE(); |
5537 if (!IsJSArray()) { | 5715 break; |
5538 Object* setter = LookupCallbackSetterInPrototypes(index); | |
5539 if (setter->IsJSFunction()) { | |
5540 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); | |
5541 } | |
5542 } | |
5543 Object* result = dictionary->AtNumberPut(index, value); | |
5544 if (result->IsFailure()) return result; | |
5545 if (elms != FixedArray::cast(result)) { | |
5546 set_elements(FixedArray::cast(result)); | |
5547 } | |
5548 } | 5716 } |
5549 | 5717 // All possible cases have been handled above. Add a return to avoid the |
5550 // Update the array length if this JSObject is an array. | 5718 // complaints from the compiler. |
5551 if (IsJSArray()) { | 5719 UNREACHABLE(); |
5552 JSArray* array = JSArray::cast(this); | 5720 return Heap::null_value(); |
5553 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value); | |
5554 if (return_value->IsFailure()) return return_value; | |
5555 } | |
5556 | |
5557 // Attempt to put this object back in fast case. | |
5558 if (ShouldConvertToFastElements()) { | |
5559 uint32_t new_length = 0; | |
5560 if (IsJSArray()) { | |
5561 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length)); | |
5562 JSArray::cast(this)->set_length(Smi::FromInt(new_length)); | |
5563 } else { | |
5564 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; | |
5565 } | |
5566 Object* obj = Heap::AllocateFixedArrayWithHoles(new_length); | |
5567 if (obj->IsFailure()) return obj; | |
5568 SetFastElements(FixedArray::cast(obj)); | |
5569 #ifdef DEBUG | |
5570 if (FLAG_trace_normalization) { | |
5571 PrintF("Object elements are fast case again:\n"); | |
5572 Print(); | |
5573 } | |
5574 #endif | |
5575 } | |
5576 | |
5577 return value; | |
5578 } | 5721 } |
5579 | 5722 |
5580 | 5723 |
5581 Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) { | 5724 Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) { |
5582 uint32_t old_len = 0; | 5725 uint32_t old_len = 0; |
5583 CHECK(Array::IndexFromObject(length(), &old_len)); | 5726 CHECK(Array::IndexFromObject(length(), &old_len)); |
5584 // Check to see if we need to update the length. For now, we make | 5727 // Check to see if we need to update the length. For now, we make |
5585 // sure that the length stays within 32-bits (unsigned). | 5728 // sure that the length stays within 32-bits (unsigned). |
5586 if (index >= old_len && index != 0xffffffff) { | 5729 if (index >= old_len && index != 0xffffffff) { |
5587 Object* len = | 5730 Object* len = |
5588 Heap::NumberFromDouble(static_cast<double>(index) + 1); | 5731 Heap::NumberFromDouble(static_cast<double>(index) + 1); |
5589 if (len->IsFailure()) return len; | 5732 if (len->IsFailure()) return len; |
5590 set_length(len); | 5733 set_length(len); |
5591 } | 5734 } |
5592 return value; | 5735 return value; |
5593 } | 5736 } |
5594 | 5737 |
5595 | 5738 |
5596 Object* JSObject::GetElementPostInterceptor(JSObject* receiver, | 5739 Object* JSObject::GetElementPostInterceptor(JSObject* receiver, |
5597 uint32_t index) { | 5740 uint32_t index) { |
5598 // Get element works for both JSObject and JSArray since | 5741 // Get element works for both JSObject and JSArray since |
5599 // JSArray::length cannot change. | 5742 // JSArray::length cannot change. |
5600 if (HasFastElements()) { | 5743 switch (GetElementsKind()) { |
5601 FixedArray* elms = FixedArray::cast(elements()); | 5744 case FAST_ELEMENTS: { |
5602 if (index < static_cast<uint32_t>(elms->length())) { | 5745 FixedArray* elms = FixedArray::cast(elements()); |
5603 Object* value = elms->get(index); | 5746 if (index < static_cast<uint32_t>(elms->length())) { |
5604 if (!value->IsTheHole()) return value; | 5747 Object* value = elms->get(index); |
| 5748 if (!value->IsTheHole()) return value; |
| 5749 } |
| 5750 break; |
5605 } | 5751 } |
5606 } else { | 5752 case PIXEL_ELEMENTS: { |
5607 NumberDictionary* dictionary = element_dictionary(); | 5753 // TODO(iposva): Add testcase and implement. |
5608 int entry = dictionary->FindEntry(index); | 5754 UNIMPLEMENTED(); |
5609 if (entry != NumberDictionary::kNotFound) { | 5755 break; |
5610 Object* element = dictionary->ValueAt(entry); | 5756 } |
5611 PropertyDetails details = dictionary->DetailsAt(entry); | 5757 case DICTIONARY_ELEMENTS: { |
5612 if (details.type() == CALLBACKS) { | 5758 NumberDictionary* dictionary = element_dictionary(); |
5613 // Only accessors allowed as elements. | 5759 int entry = dictionary->FindEntry(index); |
5614 FixedArray* structure = FixedArray::cast(element); | 5760 if (entry != NumberDictionary::kNotFound) { |
5615 Object* getter = structure->get(kGetterIndex); | 5761 Object* element = dictionary->ValueAt(entry); |
5616 if (getter->IsJSFunction()) { | 5762 PropertyDetails details = dictionary->DetailsAt(entry); |
5617 return GetPropertyWithDefinedGetter(receiver, | 5763 if (details.type() == CALLBACKS) { |
5618 JSFunction::cast(getter)); | 5764 // Only accessors allowed as elements. |
5619 } else { | 5765 FixedArray* structure = FixedArray::cast(element); |
5620 // Getter is not a function. | 5766 Object* getter = structure->get(kGetterIndex); |
5621 return Heap::undefined_value(); | 5767 if (getter->IsJSFunction()) { |
| 5768 return GetPropertyWithDefinedGetter(receiver, |
| 5769 JSFunction::cast(getter)); |
| 5770 } else { |
| 5771 // Getter is not a function. |
| 5772 return Heap::undefined_value(); |
| 5773 } |
5622 } | 5774 } |
| 5775 return element; |
5623 } | 5776 } |
5624 return element; | 5777 break; |
5625 } | 5778 } |
| 5779 default: |
| 5780 UNREACHABLE(); |
| 5781 break; |
5626 } | 5782 } |
5627 | 5783 |
5628 // Continue searching via the prototype chain. | 5784 // Continue searching via the prototype chain. |
5629 Object* pt = GetPrototype(); | 5785 Object* pt = GetPrototype(); |
5630 if (pt == Heap::null_value()) return Heap::undefined_value(); | 5786 if (pt == Heap::null_value()) return Heap::undefined_value(); |
5631 return pt->GetElementWithReceiver(receiver, index); | 5787 return pt->GetElementWithReceiver(receiver, index); |
5632 } | 5788 } |
5633 | 5789 |
5634 | 5790 |
5635 Object* JSObject::GetElementWithInterceptor(JSObject* receiver, | 5791 Object* JSObject::GetElementWithInterceptor(JSObject* receiver, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5674 Top::ReportFailedAccessCheck(this, v8::ACCESS_GET); | 5830 Top::ReportFailedAccessCheck(this, v8::ACCESS_GET); |
5675 return Heap::undefined_value(); | 5831 return Heap::undefined_value(); |
5676 } | 5832 } |
5677 | 5833 |
5678 if (HasIndexedInterceptor()) { | 5834 if (HasIndexedInterceptor()) { |
5679 return GetElementWithInterceptor(receiver, index); | 5835 return GetElementWithInterceptor(receiver, index); |
5680 } | 5836 } |
5681 | 5837 |
5682 // Get element works for both JSObject and JSArray since | 5838 // Get element works for both JSObject and JSArray since |
5683 // JSArray::length cannot change. | 5839 // JSArray::length cannot change. |
5684 if (HasFastElements()) { | 5840 switch (GetElementsKind()) { |
5685 FixedArray* elms = FixedArray::cast(elements()); | 5841 case FAST_ELEMENTS: { |
5686 if (index < static_cast<uint32_t>(elms->length())) { | 5842 FixedArray* elms = FixedArray::cast(elements()); |
5687 Object* value = elms->get(index); | 5843 if (index < static_cast<uint32_t>(elms->length())) { |
5688 if (!value->IsTheHole()) return value; | 5844 Object* value = elms->get(index); |
| 5845 if (!value->IsTheHole()) return value; |
| 5846 } |
| 5847 break; |
5689 } | 5848 } |
5690 } else { | 5849 case PIXEL_ELEMENTS: { |
5691 NumberDictionary* dictionary = element_dictionary(); | 5850 PixelArray* pixels = PixelArray::cast(elements()); |
5692 int entry = dictionary->FindEntry(index); | 5851 if (index < static_cast<uint32_t>(pixels->length())) { |
5693 if (entry != NumberDictionary::kNotFound) { | 5852 uint8_t value = pixels->get(index); |
5694 Object* element = dictionary->ValueAt(entry); | 5853 return Smi::FromInt(value); |
5695 PropertyDetails details = dictionary->DetailsAt(entry); | 5854 } |
5696 if (details.type() == CALLBACKS) { | 5855 break; |
5697 // Only accessors allowed as elements. | 5856 } |
5698 FixedArray* structure = FixedArray::cast(element); | 5857 case DICTIONARY_ELEMENTS: { |
5699 Object* getter = structure->get(kGetterIndex); | 5858 NumberDictionary* dictionary = element_dictionary(); |
5700 if (getter->IsJSFunction()) { | 5859 int entry = dictionary->FindEntry(index); |
5701 return GetPropertyWithDefinedGetter(receiver, | 5860 if (entry != NumberDictionary::kNotFound) { |
5702 JSFunction::cast(getter)); | 5861 Object* element = dictionary->ValueAt(entry); |
5703 } else { | 5862 PropertyDetails details = dictionary->DetailsAt(entry); |
5704 // Getter is not a function. | 5863 if (details.type() == CALLBACKS) { |
5705 return Heap::undefined_value(); | 5864 // Only accessors allowed as elements. |
| 5865 FixedArray* structure = FixedArray::cast(element); |
| 5866 Object* getter = structure->get(kGetterIndex); |
| 5867 if (getter->IsJSFunction()) { |
| 5868 return GetPropertyWithDefinedGetter(receiver, |
| 5869 JSFunction::cast(getter)); |
| 5870 } else { |
| 5871 // Getter is not a function. |
| 5872 return Heap::undefined_value(); |
| 5873 } |
5706 } | 5874 } |
| 5875 return element; |
5707 } | 5876 } |
5708 return element; | 5877 break; |
5709 } | 5878 } |
5710 } | 5879 } |
5711 | 5880 |
5712 Object* pt = GetPrototype(); | 5881 Object* pt = GetPrototype(); |
5713 if (pt == Heap::null_value()) return Heap::undefined_value(); | 5882 if (pt == Heap::null_value()) return Heap::undefined_value(); |
5714 return pt->GetElementWithReceiver(receiver, index); | 5883 return pt->GetElementWithReceiver(receiver, index); |
5715 } | 5884 } |
5716 | 5885 |
5717 | 5886 |
5718 bool JSObject::HasDenseElements() { | 5887 bool JSObject::HasDenseElements() { |
5719 int capacity = 0; | 5888 int capacity = 0; |
5720 int number_of_elements = 0; | 5889 int number_of_elements = 0; |
5721 | 5890 |
5722 if (HasFastElements()) { | 5891 switch (GetElementsKind()) { |
5723 FixedArray* elms = FixedArray::cast(elements()); | 5892 case FAST_ELEMENTS: { |
5724 capacity = elms->length(); | 5893 FixedArray* elms = FixedArray::cast(elements()); |
5725 for (int i = 0; i < capacity; i++) { | 5894 capacity = elms->length(); |
5726 if (!elms->get(i)->IsTheHole()) number_of_elements++; | 5895 for (int i = 0; i < capacity; i++) { |
| 5896 if (!elms->get(i)->IsTheHole()) number_of_elements++; |
| 5897 } |
| 5898 break; |
5727 } | 5899 } |
5728 } else { | 5900 case PIXEL_ELEMENTS: { |
5729 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 5901 return true; |
5730 capacity = dictionary->Capacity(); | 5902 } |
5731 number_of_elements = dictionary->NumberOfElements(); | 5903 case DICTIONARY_ELEMENTS: { |
| 5904 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| 5905 capacity = dictionary->Capacity(); |
| 5906 number_of_elements = dictionary->NumberOfElements(); |
| 5907 break; |
| 5908 } |
| 5909 default: |
| 5910 UNREACHABLE(); |
| 5911 break; |
5732 } | 5912 } |
5733 | 5913 |
5734 if (capacity == 0) return true; | 5914 if (capacity == 0) return true; |
5735 return (number_of_elements > (capacity / 2)); | 5915 return (number_of_elements > (capacity / 2)); |
5736 } | 5916 } |
5737 | 5917 |
5738 | 5918 |
5739 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { | 5919 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { |
5740 ASSERT(HasFastElements()); | 5920 ASSERT(HasFastElements()); |
5741 // Keep the array in fast case if the current backing storage is | 5921 // Keep the array in fast case if the current backing storage is |
5742 // almost filled and if the new capacity is no more than twice the | 5922 // almost filled and if the new capacity is no more than twice the |
5743 // old capacity. | 5923 // old capacity. |
5744 int elements_length = FixedArray::cast(elements())->length(); | 5924 int elements_length = FixedArray::cast(elements())->length(); |
5745 return !HasDenseElements() || ((new_capacity / 2) > elements_length); | 5925 return !HasDenseElements() || ((new_capacity / 2) > elements_length); |
5746 } | 5926 } |
5747 | 5927 |
5748 | 5928 |
5749 bool JSObject::ShouldConvertToFastElements() { | 5929 bool JSObject::ShouldConvertToFastElements() { |
5750 ASSERT(!HasFastElements()); | 5930 ASSERT(HasDictionaryElements()); |
5751 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 5931 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
5752 // If the elements are sparse, we should not go back to fast case. | 5932 // If the elements are sparse, we should not go back to fast case. |
5753 if (!HasDenseElements()) return false; | 5933 if (!HasDenseElements()) return false; |
5754 // If an element has been added at a very high index in the elements | 5934 // If an element has been added at a very high index in the elements |
5755 // dictionary, we cannot go back to fast case. | 5935 // dictionary, we cannot go back to fast case. |
5756 if (dictionary->requires_slow_elements()) return false; | 5936 if (dictionary->requires_slow_elements()) return false; |
5757 // An object requiring access checks is never allowed to have fast | 5937 // An object requiring access checks is never allowed to have fast |
5758 // elements. If it had fast elements we would skip security checks. | 5938 // elements. If it had fast elements we would skip security checks. |
5759 if (IsAccessCheckNeeded()) return false; | 5939 if (IsAccessCheckNeeded()) return false; |
5760 // If the dictionary backing storage takes up roughly half as much | 5940 // If the dictionary backing storage takes up roughly half as much |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5994 // Check access rights if needed. | 6174 // Check access rights if needed. |
5995 if (IsAccessCheckNeeded() && | 6175 if (IsAccessCheckNeeded() && |
5996 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | 6176 !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
5997 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 6177 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
5998 return false; | 6178 return false; |
5999 } | 6179 } |
6000 | 6180 |
6001 // Handle [] on String objects. | 6181 // Handle [] on String objects. |
6002 if (this->IsStringObjectWithCharacterAt(index)) return true; | 6182 if (this->IsStringObjectWithCharacterAt(index)) return true; |
6003 | 6183 |
6004 if (HasFastElements()) { | 6184 switch (GetElementsKind()) { |
6005 uint32_t length = IsJSArray() ? | 6185 case FAST_ELEMENTS: { |
6006 static_cast<uint32_t>( | 6186 uint32_t length = IsJSArray() ? |
6007 Smi::cast(JSArray::cast(this)->length())->value()) : | 6187 static_cast<uint32_t>( |
6008 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 6188 Smi::cast(JSArray::cast(this)->length())->value()) : |
6009 return (index < length) && | 6189 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
6010 !FixedArray::cast(elements())->get(index)->IsTheHole(); | 6190 return (index < length) && |
| 6191 !FixedArray::cast(elements())->get(index)->IsTheHole(); |
| 6192 } |
| 6193 case PIXEL_ELEMENTS: { |
| 6194 PixelArray* pixels = PixelArray::cast(elements()); |
| 6195 return index < static_cast<uint32_t>(pixels->length()); |
| 6196 } |
| 6197 case DICTIONARY_ELEMENTS: { |
| 6198 return element_dictionary()->FindEntry(index) |
| 6199 != NumberDictionary::kNotFound; |
| 6200 } |
| 6201 default: |
| 6202 UNREACHABLE(); |
| 6203 break; |
6011 } | 6204 } |
6012 return element_dictionary()->FindEntry(index) | 6205 // All possibilities have been handled above already. |
6013 != NumberDictionary::kNotFound; | 6206 UNREACHABLE(); |
| 6207 return Heap::null_value(); |
6014 } | 6208 } |
6015 | 6209 |
6016 | 6210 |
6017 bool JSObject::HasRealNamedCallbackProperty(String* key) { | 6211 bool JSObject::HasRealNamedCallbackProperty(String* key) { |
6018 // Check access rights if needed. | 6212 // Check access rights if needed. |
6019 if (IsAccessCheckNeeded() && | 6213 if (IsAccessCheckNeeded() && |
6020 !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) { | 6214 !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) { |
6021 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 6215 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
6022 return false; | 6216 return false; |
6023 } | 6217 } |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6186 | 6380 |
6187 | 6381 |
6188 int JSObject::NumberOfEnumElements() { | 6382 int JSObject::NumberOfEnumElements() { |
6189 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM)); | 6383 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM)); |
6190 } | 6384 } |
6191 | 6385 |
6192 | 6386 |
6193 int JSObject::GetLocalElementKeys(FixedArray* storage, | 6387 int JSObject::GetLocalElementKeys(FixedArray* storage, |
6194 PropertyAttributes filter) { | 6388 PropertyAttributes filter) { |
6195 int counter = 0; | 6389 int counter = 0; |
6196 if (HasFastElements()) { | 6390 switch (GetElementsKind()) { |
6197 int length = IsJSArray() | 6391 case FAST_ELEMENTS: { |
6198 ? Smi::cast(JSArray::cast(this)->length())->value() | 6392 int length = IsJSArray() ? |
6199 : FixedArray::cast(elements())->length(); | 6393 Smi::cast(JSArray::cast(this)->length())->value() : |
6200 for (int i = 0; i < length; i++) { | 6394 FixedArray::cast(elements())->length(); |
6201 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { | 6395 for (int i = 0; i < length; i++) { |
6202 if (storage) { | 6396 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { |
6203 storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 6397 if (storage != NULL) { |
| 6398 storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER); |
| 6399 } |
| 6400 counter++; |
| 6401 } |
| 6402 } |
| 6403 ASSERT(!storage || storage->length() >= counter); |
| 6404 break; |
| 6405 } |
| 6406 case PIXEL_ELEMENTS: { |
| 6407 int length = PixelArray::cast(elements())->length(); |
| 6408 while (counter < length) { |
| 6409 if (storage != NULL) { |
| 6410 storage->set(counter, Smi::FromInt(counter), SKIP_WRITE_BARRIER); |
6204 } | 6411 } |
6205 counter++; | 6412 counter++; |
6206 } | 6413 } |
| 6414 ASSERT(!storage || storage->length() >= counter); |
| 6415 break; |
6207 } | 6416 } |
6208 ASSERT(!storage || storage->length() >= counter); | 6417 case DICTIONARY_ELEMENTS: { |
6209 } else { | 6418 if (storage != NULL) { |
6210 if (storage) { | 6419 element_dictionary()->CopyKeysTo(storage, filter); |
6211 element_dictionary()->CopyKeysTo(storage, filter); | 6420 } |
| 6421 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); |
| 6422 break; |
6212 } | 6423 } |
6213 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); | 6424 default: |
| 6425 UNREACHABLE(); |
| 6426 break; |
6214 } | 6427 } |
6215 | 6428 |
6216 if (this->IsJSValue()) { | 6429 if (this->IsJSValue()) { |
6217 Object* val = JSValue::cast(this)->value(); | 6430 Object* val = JSValue::cast(this)->value(); |
6218 if (val->IsString()) { | 6431 if (val->IsString()) { |
6219 String* str = String::cast(val); | 6432 String* str = String::cast(val); |
6220 if (storage) { | 6433 if (storage) { |
6221 for (int i = 0; i < str->length(); i++) { | 6434 for (int i = 0; i < str->length(); i++) { |
6222 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); | 6435 storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER); |
6223 } | 6436 } |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6662 | 6875 |
6663 template | 6876 template |
6664 int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements(); | 6877 int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements(); |
6665 | 6878 |
6666 template | 6879 template |
6667 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements(); | 6880 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements(); |
6668 | 6881 |
6669 // Collates undefined and unexisting elements below limit from position | 6882 // Collates undefined and unexisting elements below limit from position |
6670 // zero of the elements. The object stays in Dictionary mode. | 6883 // zero of the elements. The object stays in Dictionary mode. |
6671 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { | 6884 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { |
6672 ASSERT(!HasFastElements()); | 6885 ASSERT(HasDictionaryElements()); |
6673 // Must stay in dictionary mode, either because of requires_slow_elements, | 6886 // Must stay in dictionary mode, either because of requires_slow_elements, |
6674 // or because we are not going to sort (and therefore compact) all of the | 6887 // or because we are not going to sort (and therefore compact) all of the |
6675 // elements. | 6888 // elements. |
6676 NumberDictionary* dict = element_dictionary(); | 6889 NumberDictionary* dict = element_dictionary(); |
6677 HeapNumber* result_double = NULL; | 6890 HeapNumber* result_double = NULL; |
6678 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | 6891 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { |
6679 // Allocate space for result before we start mutating the object. | 6892 // Allocate space for result before we start mutating the object. |
6680 Object* new_double = Heap::AllocateHeapNumber(0.0); | 6893 Object* new_double = Heap::AllocateHeapNumber(0.0); |
6681 if (new_double->IsFailure()) return new_double; | 6894 if (new_double->IsFailure()) return new_double; |
6682 result_double = HeapNumber::cast(new_double); | 6895 result_double = HeapNumber::cast(new_double); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6736 result_double->set_value(static_cast<double>(result)); | 6949 result_double->set_value(static_cast<double>(result)); |
6737 return result_double; | 6950 return result_double; |
6738 } | 6951 } |
6739 | 6952 |
6740 | 6953 |
6741 // Collects all defined (non-hole) and non-undefined (array) elements at | 6954 // Collects all defined (non-hole) and non-undefined (array) elements at |
6742 // the start of the elements array. | 6955 // the start of the elements array. |
6743 // If the object is in dictionary mode, it is converted to fast elements | 6956 // If the object is in dictionary mode, it is converted to fast elements |
6744 // mode. | 6957 // mode. |
6745 Object* JSObject::PrepareElementsForSort(uint32_t limit) { | 6958 Object* JSObject::PrepareElementsForSort(uint32_t limit) { |
6746 if (!HasFastElements()) { | 6959 ASSERT(!HasPixelElements()); |
| 6960 |
| 6961 if (HasDictionaryElements()) { |
6747 // Convert to fast elements containing only the existing properties. | 6962 // Convert to fast elements containing only the existing properties. |
6748 // Ordering is irrelevant, since we are going to sort anyway. | 6963 // Ordering is irrelevant, since we are going to sort anyway. |
6749 NumberDictionary* dict = element_dictionary(); | 6964 NumberDictionary* dict = element_dictionary(); |
6750 if (IsJSArray() || dict->requires_slow_elements() || | 6965 if (IsJSArray() || dict->requires_slow_elements() || |
6751 dict->max_number_key() >= limit) { | 6966 dict->max_number_key() >= limit) { |
6752 return PrepareSlowElementsForSort(limit); | 6967 return PrepareSlowElementsForSort(limit); |
6753 } | 6968 } |
6754 // Convert to fast elements. | 6969 // Convert to fast elements. |
6755 | 6970 |
6756 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; | 6971 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; |
6757 Object* new_array = | 6972 Object* new_array = |
6758 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); | 6973 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); |
6759 if (new_array->IsFailure()) { | 6974 if (new_array->IsFailure()) { |
6760 return new_array; | 6975 return new_array; |
6761 } | 6976 } |
6762 FixedArray* fast_elements = FixedArray::cast(new_array); | 6977 FixedArray* fast_elements = FixedArray::cast(new_array); |
6763 dict->CopyValuesTo(fast_elements); | 6978 dict->CopyValuesTo(fast_elements); |
6764 set_elements(fast_elements); | 6979 set_elements(fast_elements); |
6765 } | 6980 } |
6766 ASSERT(HasFastElements()); | 6981 ASSERT(HasFastElements()); |
6767 | 6982 |
6768 // Collect holes at the end, undefined before that and the rest at the | 6983 // Collect holes at the end, undefined before that and the rest at the |
6769 // start, and return the number of non-hole, non-undefined values. | 6984 // start, and return the number of non-hole, non-undefined values. |
6770 | 6985 |
6771 FixedArray* elements = this->elements(); | 6986 FixedArray* elements = FixedArray::cast(this->elements()); |
6772 uint32_t elements_length = static_cast<uint32_t>(elements->length()); | 6987 uint32_t elements_length = static_cast<uint32_t>(elements->length()); |
6773 if (limit > elements_length) { | 6988 if (limit > elements_length) { |
6774 limit = elements_length ; | 6989 limit = elements_length ; |
6775 } | 6990 } |
6776 if (limit == 0) { | 6991 if (limit == 0) { |
6777 return Smi::FromInt(0); | 6992 return Smi::FromInt(0); |
6778 } | 6993 } |
6779 | 6994 |
6780 HeapNumber* result_double = NULL; | 6995 HeapNumber* result_double = NULL; |
6781 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | 6996 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6831 | 7046 |
6832 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { | 7047 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { |
6833 return Smi::FromInt(static_cast<int>(result)); | 7048 return Smi::FromInt(static_cast<int>(result)); |
6834 } | 7049 } |
6835 ASSERT_NE(NULL, result_double); | 7050 ASSERT_NE(NULL, result_double); |
6836 result_double->set_value(static_cast<double>(result)); | 7051 result_double->set_value(static_cast<double>(result)); |
6837 return result_double; | 7052 return result_double; |
6838 } | 7053 } |
6839 | 7054 |
6840 | 7055 |
| 7056 Object* PixelArray::SetValue(uint32_t index, Object* value) { |
| 7057 uint8_t clamped_value = 0; |
| 7058 if (index < static_cast<uint32_t>(length())) { |
| 7059 int int_value = 0; |
| 7060 if (value->IsSmi()) { |
| 7061 int_value = Smi::cast(value)->value(); |
| 7062 } else if (value->IsHeapNumber()) { |
| 7063 static const DoubleRepresentation nan(OS::nan_value()); |
| 7064 DoubleRepresentation double_value = HeapNumber::cast(value)->value(); |
| 7065 if (nan.bits != double_value.bits) { |
| 7066 int_value = static_cast<int>(double_value.value + 0.5); |
| 7067 } else { |
| 7068 // NaN clamps to zero. |
| 7069 int_value = 0; |
| 7070 } |
| 7071 } else if (value->IsUndefined()) { |
| 7072 int_value = 0; |
| 7073 } else { |
| 7074 // All other types have been converted to a number type further up in the |
| 7075 // call chain. |
| 7076 UNREACHABLE(); |
| 7077 } |
| 7078 if (int_value < 0) { |
| 7079 clamped_value = 0; |
| 7080 } else if (int_value > 255) { |
| 7081 clamped_value = 255; |
| 7082 } else { |
| 7083 clamped_value = static_cast<uint8_t>(int_value); |
| 7084 } |
| 7085 set(index, clamped_value); |
| 7086 } |
| 7087 return Smi::FromInt(clamped_value); |
| 7088 } |
| 7089 |
| 7090 |
6841 Object* GlobalObject::GetPropertyCell(LookupResult* result) { | 7091 Object* GlobalObject::GetPropertyCell(LookupResult* result) { |
6842 ASSERT(!HasFastProperties()); | 7092 ASSERT(!HasFastProperties()); |
6843 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); | 7093 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); |
6844 ASSERT(value->IsJSGlobalPropertyCell()); | 7094 ASSERT(value->IsJSGlobalPropertyCell()); |
6845 return value; | 7095 return value; |
6846 } | 7096 } |
6847 | 7097 |
6848 | 7098 |
6849 Object* GlobalObject::EnsurePropertyCell(String* name) { | 7099 Object* GlobalObject::EnsurePropertyCell(String* name) { |
6850 ASSERT(!HasFastProperties()); | 7100 ASSERT(!HasFastProperties()); |
(...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7747 if (break_point_objects()->IsUndefined()) return 0; | 7997 if (break_point_objects()->IsUndefined()) return 0; |
7748 // Single beak point. | 7998 // Single beak point. |
7749 if (!break_point_objects()->IsFixedArray()) return 1; | 7999 if (!break_point_objects()->IsFixedArray()) return 1; |
7750 // Multiple break points. | 8000 // Multiple break points. |
7751 return FixedArray::cast(break_point_objects())->length(); | 8001 return FixedArray::cast(break_point_objects())->length(); |
7752 } | 8002 } |
7753 #endif | 8003 #endif |
7754 | 8004 |
7755 | 8005 |
7756 } } // namespace v8::internal | 8006 } } // namespace v8::internal |
OLD | NEW |