| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 15 matching lines...) Expand all Loading... |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "api.h" | 30 #include "api.h" |
| 31 #include "arguments.h" | 31 #include "arguments.h" |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "codegen.h" | 33 #include "codegen.h" |
| 34 #include "debug.h" | 34 #include "debug.h" |
| 35 #include "deoptimizer.h" | 35 #include "deoptimizer.h" |
| 36 #include "elements.h" |
| 36 #include "execution.h" | 37 #include "execution.h" |
| 37 #include "full-codegen.h" | 38 #include "full-codegen.h" |
| 38 #include "hydrogen.h" | 39 #include "hydrogen.h" |
| 39 #include "objects-inl.h" | 40 #include "objects-inl.h" |
| 40 #include "objects-visiting.h" | 41 #include "objects-visiting.h" |
| 41 #include "objects-visiting-inl.h" | 42 #include "objects-visiting-inl.h" |
| 42 #include "macro-assembler.h" | 43 #include "macro-assembler.h" |
| 43 #include "mark-compact.h" | 44 #include "mark-compact.h" |
| 44 #include "safepoint-table.h" | 45 #include "safepoint-table.h" |
| 45 #include "scanner-base.h" | 46 #include "scanner-base.h" |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 case CONSTANT_TRANSITION: | 598 case CONSTANT_TRANSITION: |
| 598 case NULL_DESCRIPTOR: | 599 case NULL_DESCRIPTOR: |
| 599 break; | 600 break; |
| 600 } | 601 } |
| 601 UNREACHABLE(); | 602 UNREACHABLE(); |
| 602 return NULL; | 603 return NULL; |
| 603 } | 604 } |
| 604 | 605 |
| 605 | 606 |
| 606 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { | 607 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { |
| 607 Object* holder = NULL; | 608 Heap* heap = IsSmi() |
| 608 if (IsSmi()) { | 609 ? Isolate::Current()->heap() |
| 609 Context* global_context = Isolate::Current()->context()->global_context(); | 610 : HeapObject::cast(this)->GetHeap(); |
| 610 holder = global_context->number_function()->instance_prototype(); | 611 Object* holder = this; |
| 611 } else { | |
| 612 HeapObject* heap_object = HeapObject::cast(this); | |
| 613 | 612 |
| 614 if (heap_object->IsJSObject()) { | 613 // Iterate up the prototype chain until an element is found or the null |
| 615 return JSObject::cast(this)->GetElementWithReceiver(receiver, index); | 614 // prototype is encountered. |
| 615 for (holder = this; |
| 616 holder != heap->null_value(); |
| 617 holder = holder->GetPrototype()) { |
| 618 if (holder->IsSmi()) { |
| 619 Context* global_context = Isolate::Current()->context()->global_context(); |
| 620 holder = global_context->number_function()->instance_prototype(); |
| 621 } else { |
| 622 HeapObject* heap_object = HeapObject::cast(holder); |
| 623 if (!heap_object->IsJSObject()) { |
| 624 Isolate* isolate = heap->isolate(); |
| 625 Context* global_context = isolate->context()->global_context(); |
| 626 if (heap_object->IsString()) { |
| 627 holder = global_context->string_function()->instance_prototype(); |
| 628 } else if (heap_object->IsHeapNumber()) { |
| 629 holder = global_context->number_function()->instance_prototype(); |
| 630 } else if (heap_object->IsBoolean()) { |
| 631 holder = global_context->boolean_function()->instance_prototype(); |
| 632 } else if (heap_object->IsJSProxy()) { |
| 633 return heap->undefined_value(); // For now... |
| 634 } else { |
| 635 // Undefined and null have no indexed properties. |
| 636 ASSERT(heap_object->IsUndefined() || heap_object->IsNull()); |
| 637 return heap->undefined_value(); |
| 638 } |
| 639 } |
| 616 } | 640 } |
| 617 Heap* heap = heap_object->GetHeap(); | |
| 618 Isolate* isolate = heap->isolate(); | |
| 619 | 641 |
| 620 Context* global_context = isolate->context()->global_context(); | 642 // Inline the case for JSObjects. Doing so significantly improves the |
| 621 if (heap_object->IsString()) { | 643 // performance of fetching elements where checking the prototype chain is |
| 622 holder = global_context->string_function()->instance_prototype(); | 644 // necessary. |
| 623 } else if (heap_object->IsHeapNumber()) { | 645 JSObject* js_object = JSObject::cast(holder); |
| 624 holder = global_context->number_function()->instance_prototype(); | 646 |
| 625 } else if (heap_object->IsBoolean()) { | 647 // Check access rights if needed. |
| 626 holder = global_context->boolean_function()->instance_prototype(); | 648 if (js_object->IsAccessCheckNeeded()) { |
| 627 } else if (heap_object->IsJSProxy()) { | 649 Isolate* isolate = heap->isolate(); |
| 628 return heap->undefined_value(); // For now... | 650 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) { |
| 629 } else { | 651 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET); |
| 630 // Undefined and null have no indexed properties. | 652 return heap->undefined_value(); |
| 631 ASSERT(heap_object->IsUndefined() || heap_object->IsNull()); | 653 } |
| 632 return heap->undefined_value(); | 654 } |
| 655 |
| 656 if (js_object->HasIndexedInterceptor()) { |
| 657 return js_object->GetElementWithInterceptor(receiver, index); |
| 658 } |
| 659 |
| 660 if (js_object->elements() != heap->empty_fixed_array()) { |
| 661 MaybeObject* result = js_object->GetElementsAccessor()->GetWithReceiver( |
| 662 js_object, |
| 663 receiver, |
| 664 index); |
| 665 if (result != heap->the_hole_value()) return result; |
| 633 } | 666 } |
| 634 } | 667 } |
| 635 | 668 |
| 636 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index); | 669 return heap->undefined_value(); |
| 637 } | 670 } |
| 638 | 671 |
| 639 | 672 |
| 640 Object* Object::GetPrototype() { | 673 Object* Object::GetPrototype() { |
| 641 if (IsSmi()) { | 674 if (IsSmi()) { |
| 642 Heap* heap = Isolate::Current()->heap(); | 675 Heap* heap = Isolate::Current()->heap(); |
| 643 Context* context = heap->isolate()->context()->global_context(); | 676 Context* context = heap->isolate()->context()->global_context(); |
| 644 return context->number_function()->instance_prototype(); | 677 return context->number_function()->instance_prototype(); |
| 645 } | 678 } |
| 646 | 679 |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 } | 997 } |
| 965 | 998 |
| 966 | 999 |
| 967 void JSObject::JSObjectShortPrint(StringStream* accumulator) { | 1000 void JSObject::JSObjectShortPrint(StringStream* accumulator) { |
| 968 switch (map()->instance_type()) { | 1001 switch (map()->instance_type()) { |
| 969 case JS_ARRAY_TYPE: { | 1002 case JS_ARRAY_TYPE: { |
| 970 double length = JSArray::cast(this)->length()->Number(); | 1003 double length = JSArray::cast(this)->length()->Number(); |
| 971 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length)); | 1004 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length)); |
| 972 break; | 1005 break; |
| 973 } | 1006 } |
| 1007 case JS_WEAK_MAP_TYPE: { |
| 1008 int elements = JSWeakMap::cast(this)->table()->NumberOfElements(); |
| 1009 accumulator->Add("<JS WeakMap[%d]>", elements); |
| 1010 break; |
| 1011 } |
| 974 case JS_REGEXP_TYPE: { | 1012 case JS_REGEXP_TYPE: { |
| 975 accumulator->Add("<JS RegExp>"); | 1013 accumulator->Add("<JS RegExp>"); |
| 976 break; | 1014 break; |
| 977 } | 1015 } |
| 978 case JS_FUNCTION_TYPE: { | 1016 case JS_FUNCTION_TYPE: { |
| 979 Object* fun_name = JSFunction::cast(this)->shared()->name(); | 1017 Object* fun_name = JSFunction::cast(this)->shared()->name(); |
| 980 bool printed = false; | 1018 bool printed = false; |
| 981 if (fun_name->IsString()) { | 1019 if (fun_name->IsString()) { |
| 982 String* str = String::cast(fun_name); | 1020 String* str = String::cast(fun_name); |
| 983 if (str->length() > 0) { | 1021 if (str->length() > 0) { |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1197 switch (type) { | 1235 switch (type) { |
| 1198 case FIXED_ARRAY_TYPE: | 1236 case FIXED_ARRAY_TYPE: |
| 1199 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); | 1237 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); |
| 1200 break; | 1238 break; |
| 1201 case FIXED_DOUBLE_ARRAY_TYPE: | 1239 case FIXED_DOUBLE_ARRAY_TYPE: |
| 1202 break; | 1240 break; |
| 1203 case JS_OBJECT_TYPE: | 1241 case JS_OBJECT_TYPE: |
| 1204 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: | 1242 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
| 1205 case JS_VALUE_TYPE: | 1243 case JS_VALUE_TYPE: |
| 1206 case JS_ARRAY_TYPE: | 1244 case JS_ARRAY_TYPE: |
| 1245 case JS_WEAK_MAP_TYPE: |
| 1207 case JS_REGEXP_TYPE: | 1246 case JS_REGEXP_TYPE: |
| 1208 case JS_GLOBAL_PROXY_TYPE: | 1247 case JS_GLOBAL_PROXY_TYPE: |
| 1209 case JS_GLOBAL_OBJECT_TYPE: | 1248 case JS_GLOBAL_OBJECT_TYPE: |
| 1210 case JS_BUILTINS_OBJECT_TYPE: | 1249 case JS_BUILTINS_OBJECT_TYPE: |
| 1211 case JS_MESSAGE_OBJECT_TYPE: | 1250 case JS_MESSAGE_OBJECT_TYPE: |
| 1212 JSObject::BodyDescriptor::IterateBody(this, object_size, v); | 1251 JSObject::BodyDescriptor::IterateBody(this, object_size, v); |
| 1213 break; | 1252 break; |
| 1214 case JS_FUNCTION_TYPE: | 1253 case JS_FUNCTION_TYPE: |
| 1215 reinterpret_cast<JSFunction*>(this) | 1254 reinterpret_cast<JSFunction*>(this) |
| 1216 ->JSFunctionIterateBody(object_size, v); | 1255 ->JSFunctionIterateBody(object_size, v); |
| (...skipping 1717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2934 if (has_double_elements) { | 2973 if (has_double_elements) { |
| 2935 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); | 2974 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); |
| 2936 if (double_array->is_the_hole(i)) { | 2975 if (double_array->is_the_hole(i)) { |
| 2937 value = GetIsolate()->heap()->the_hole_value(); | 2976 value = GetIsolate()->heap()->the_hole_value(); |
| 2938 } else { | 2977 } else { |
| 2939 // Objects must be allocated in the old object space, since the | 2978 // Objects must be allocated in the old object space, since the |
| 2940 // overall number of HeapNumbers needed for the conversion might | 2979 // overall number of HeapNumbers needed for the conversion might |
| 2941 // exceed the capacity of new space, and we would fail repeatedly | 2980 // exceed the capacity of new space, and we would fail repeatedly |
| 2942 // trying to convert the FixedDoubleArray. | 2981 // trying to convert the FixedDoubleArray. |
| 2943 MaybeObject* maybe_value_object = | 2982 MaybeObject* maybe_value_object = |
| 2944 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED); | 2983 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED); |
| 2945 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; | 2984 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
| 2946 } | 2985 } |
| 2947 } else { | 2986 } else { |
| 2948 ASSERT(old_map->has_fast_elements()); | 2987 ASSERT(old_map->has_fast_elements()); |
| 2949 value = FixedArray::cast(array)->get(i); | 2988 value = FixedArray::cast(array)->get(i); |
| 2950 } | 2989 } |
| 2951 PropertyDetails details = PropertyDetails(NONE, NORMAL); | 2990 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
| 2952 if (!value->IsTheHole()) { | 2991 if (!value->IsTheHole()) { |
| 2953 Object* result; | 2992 Object* result; |
| 2954 MaybeObject* maybe_result = | 2993 MaybeObject* maybe_result = |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3113 return *v8::Utils::OpenHandle(*result); | 3152 return *v8::Utils::OpenHandle(*result); |
| 3114 } | 3153 } |
| 3115 } | 3154 } |
| 3116 MaybeObject* raw_result = | 3155 MaybeObject* raw_result = |
| 3117 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); | 3156 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); |
| 3118 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3157 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 3119 return raw_result; | 3158 return raw_result; |
| 3120 } | 3159 } |
| 3121 | 3160 |
| 3122 | 3161 |
| 3123 MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index, | |
| 3124 DeleteMode mode) { | |
| 3125 ASSERT(!HasExternalArrayElements()); | |
| 3126 switch (GetElementsKind()) { | |
| 3127 case FAST_ELEMENTS: { | |
| 3128 Object* obj; | |
| 3129 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | |
| 3130 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 3131 } | |
| 3132 uint32_t length = IsJSArray() ? | |
| 3133 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | |
| 3134 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | |
| 3135 if (index < length) { | |
| 3136 FixedArray::cast(elements())->set_the_hole(index); | |
| 3137 } | |
| 3138 break; | |
| 3139 } | |
| 3140 case DICTIONARY_ELEMENTS: { | |
| 3141 NumberDictionary* dictionary = element_dictionary(); | |
| 3142 int entry = dictionary->FindEntry(index); | |
| 3143 if (entry != NumberDictionary::kNotFound) { | |
| 3144 Object* deleted = dictionary->DeleteProperty(entry, mode); | |
| 3145 if (deleted == GetHeap()->true_value()) { | |
| 3146 MaybeObject* maybe_elements = dictionary->Shrink(index); | |
| 3147 FixedArray* new_elements = NULL; | |
| 3148 if (!maybe_elements->To(&new_elements)) { | |
| 3149 return maybe_elements; | |
| 3150 } | |
| 3151 set_elements(new_elements); | |
| 3152 } | |
| 3153 return deleted; | |
| 3154 } | |
| 3155 break; | |
| 3156 } | |
| 3157 default: | |
| 3158 UNREACHABLE(); | |
| 3159 break; | |
| 3160 } | |
| 3161 return GetHeap()->true_value(); | |
| 3162 } | |
| 3163 | |
| 3164 | |
| 3165 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { | 3162 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { |
| 3166 Isolate* isolate = GetIsolate(); | 3163 Isolate* isolate = GetIsolate(); |
| 3167 Heap* heap = isolate->heap(); | 3164 Heap* heap = isolate->heap(); |
| 3168 // Make sure that the top context does not change when doing | 3165 // Make sure that the top context does not change when doing |
| 3169 // callbacks or interceptor calls. | 3166 // callbacks or interceptor calls. |
| 3170 AssertNoContextChange ncc; | 3167 AssertNoContextChange ncc; |
| 3171 HandleScope scope(isolate); | 3168 HandleScope scope(isolate); |
| 3172 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); | 3169 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); |
| 3173 if (interceptor->deleter()->IsUndefined()) return heap->false_value(); | 3170 if (interceptor->deleter()->IsUndefined()) return heap->false_value(); |
| 3174 v8::IndexedPropertyDeleter deleter = | 3171 v8::IndexedPropertyDeleter deleter = |
| 3175 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); | 3172 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); |
| 3176 Handle<JSObject> this_handle(this); | 3173 Handle<JSObject> this_handle(this); |
| 3177 LOG(isolate, | 3174 LOG(isolate, |
| 3178 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); | 3175 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); |
| 3179 CustomArguments args(isolate, interceptor->data(), this, this); | 3176 CustomArguments args(isolate, interceptor->data(), this, this); |
| 3180 v8::AccessorInfo info(args.end()); | 3177 v8::AccessorInfo info(args.end()); |
| 3181 v8::Handle<v8::Boolean> result; | 3178 v8::Handle<v8::Boolean> result; |
| 3182 { | 3179 { |
| 3183 // Leaving JavaScript. | 3180 // Leaving JavaScript. |
| 3184 VMState state(isolate, EXTERNAL); | 3181 VMState state(isolate, EXTERNAL); |
| 3185 result = deleter(index, info); | 3182 result = deleter(index, info); |
| 3186 } | 3183 } |
| 3187 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3184 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 3188 if (!result.IsEmpty()) { | 3185 if (!result.IsEmpty()) { |
| 3189 ASSERT(result->IsBoolean()); | 3186 ASSERT(result->IsBoolean()); |
| 3190 return *v8::Utils::OpenHandle(*result); | 3187 return *v8::Utils::OpenHandle(*result); |
| 3191 } | 3188 } |
| 3192 MaybeObject* raw_result = | 3189 MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle, |
| 3193 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); | 3190 index, |
| 3191 NORMAL_DELETION); |
| 3194 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3192 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 3195 return raw_result; | 3193 return raw_result; |
| 3196 } | 3194 } |
| 3197 | 3195 |
| 3198 | 3196 |
| 3199 MaybeObject* JSObject::DeleteFastElement(uint32_t index) { | |
| 3200 ASSERT(HasFastElements() || HasFastArgumentsElements()); | |
| 3201 Heap* heap = GetHeap(); | |
| 3202 FixedArray* backing_store = FixedArray::cast(elements()); | |
| 3203 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | |
| 3204 backing_store = FixedArray::cast(backing_store->get(1)); | |
| 3205 } else { | |
| 3206 Object* writable; | |
| 3207 MaybeObject* maybe = EnsureWritableFastElements(); | |
| 3208 if (!maybe->ToObject(&writable)) return maybe; | |
| 3209 backing_store = FixedArray::cast(writable); | |
| 3210 } | |
| 3211 uint32_t length = static_cast<uint32_t>( | |
| 3212 IsJSArray() | |
| 3213 ? Smi::cast(JSArray::cast(this)->length())->value() | |
| 3214 : backing_store->length()); | |
| 3215 if (index < length) { | |
| 3216 backing_store->set_the_hole(index); | |
| 3217 // If an old space backing store is larger than a certain size and | |
| 3218 // has too few used values, normalize it. | |
| 3219 // To avoid doing the check on every delete we require at least | |
| 3220 // one adjacent hole to the value being deleted. | |
| 3221 Object* hole = heap->the_hole_value(); | |
| 3222 const int kMinLengthForSparsenessCheck = 64; | |
| 3223 if (backing_store->length() >= kMinLengthForSparsenessCheck && | |
| 3224 !heap->InNewSpace(backing_store) && | |
| 3225 ((index > 0 && backing_store->get(index - 1) == hole) || | |
| 3226 (index + 1 < length && backing_store->get(index + 1) == hole))) { | |
| 3227 int num_used = 0; | |
| 3228 for (int i = 0; i < backing_store->length(); ++i) { | |
| 3229 if (backing_store->get(i) != hole) ++num_used; | |
| 3230 // Bail out early if more than 1/4 is used. | |
| 3231 if (4 * num_used > backing_store->length()) break; | |
| 3232 } | |
| 3233 if (4 * num_used <= backing_store->length()) { | |
| 3234 MaybeObject* result = NormalizeElements(); | |
| 3235 if (result->IsFailure()) return result; | |
| 3236 } | |
| 3237 } | |
| 3238 } | |
| 3239 return heap->true_value(); | |
| 3240 } | |
| 3241 | |
| 3242 | |
| 3243 MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index, | |
| 3244 DeleteMode mode) { | |
| 3245 Isolate* isolate = GetIsolate(); | |
| 3246 Heap* heap = isolate->heap(); | |
| 3247 FixedArray* backing_store = FixedArray::cast(elements()); | |
| 3248 bool is_arguments = | |
| 3249 (GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); | |
| 3250 if (is_arguments) { | |
| 3251 backing_store = FixedArray::cast(backing_store->get(1)); | |
| 3252 } | |
| 3253 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | |
| 3254 int entry = dictionary->FindEntry(index); | |
| 3255 if (entry != NumberDictionary::kNotFound) { | |
| 3256 Object* result = dictionary->DeleteProperty(entry, mode); | |
| 3257 if (result == heap->true_value()) { | |
| 3258 MaybeObject* maybe_elements = dictionary->Shrink(index); | |
| 3259 FixedArray* new_elements = NULL; | |
| 3260 if (!maybe_elements->To(&new_elements)) { | |
| 3261 return maybe_elements; | |
| 3262 } | |
| 3263 if (is_arguments) { | |
| 3264 FixedArray::cast(elements())->set(1, new_elements); | |
| 3265 } else { | |
| 3266 set_elements(new_elements); | |
| 3267 } | |
| 3268 } | |
| 3269 if (mode == STRICT_DELETION && result == heap->false_value()) { | |
| 3270 // In strict mode, attempting to delete a non-configurable property | |
| 3271 // throws an exception. | |
| 3272 HandleScope scope(isolate); | |
| 3273 Handle<Object> holder(this); | |
| 3274 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); | |
| 3275 Handle<Object> args[2] = { name, holder }; | |
| 3276 Handle<Object> error = | |
| 3277 isolate->factory()->NewTypeError("strict_delete_property", | |
| 3278 HandleVector(args, 2)); | |
| 3279 return isolate->Throw(*error); | |
| 3280 } | |
| 3281 } | |
| 3282 return heap->true_value(); | |
| 3283 } | |
| 3284 | |
| 3285 | |
| 3286 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { | 3197 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
| 3287 Isolate* isolate = GetIsolate(); | 3198 Isolate* isolate = GetIsolate(); |
| 3288 // Check access rights if needed. | 3199 // Check access rights if needed. |
| 3289 if (IsAccessCheckNeeded() && | 3200 if (IsAccessCheckNeeded() && |
| 3290 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { | 3201 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { |
| 3291 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); | 3202 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); |
| 3292 return isolate->heap()->false_value(); | 3203 return isolate->heap()->false_value(); |
| 3293 } | 3204 } |
| 3294 | 3205 |
| 3295 if (IsJSGlobalProxy()) { | 3206 if (IsJSGlobalProxy()) { |
| 3296 Object* proto = GetPrototype(); | 3207 Object* proto = GetPrototype(); |
| 3297 if (proto->IsNull()) return isolate->heap()->false_value(); | 3208 if (proto->IsNull()) return isolate->heap()->false_value(); |
| 3298 ASSERT(proto->IsJSGlobalObject()); | 3209 ASSERT(proto->IsJSGlobalObject()); |
| 3299 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); | 3210 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
| 3300 } | 3211 } |
| 3301 | 3212 |
| 3302 if (HasIndexedInterceptor()) { | 3213 if (HasIndexedInterceptor()) { |
| 3303 // Skip interceptor if forcing deletion. | 3214 // Skip interceptor if forcing deletion. |
| 3304 return (mode == FORCE_DELETION) | 3215 if (mode != FORCE_DELETION) { |
| 3305 ? DeleteElementPostInterceptor(index, FORCE_DELETION) | 3216 return DeleteElementWithInterceptor(index); |
| 3306 : DeleteElementWithInterceptor(index); | 3217 } |
| 3218 mode = JSReceiver::FORCE_DELETION; |
| 3307 } | 3219 } |
| 3308 | 3220 |
| 3309 switch (GetElementsKind()) { | 3221 return GetElementsAccessor()->Delete(this, index, mode); |
| 3310 case FAST_ELEMENTS: | |
| 3311 return DeleteFastElement(index); | |
| 3312 | |
| 3313 case DICTIONARY_ELEMENTS: | |
| 3314 return DeleteDictionaryElement(index, mode); | |
| 3315 | |
| 3316 case FAST_DOUBLE_ELEMENTS: { | |
| 3317 int length = IsJSArray() | |
| 3318 ? Smi::cast(JSArray::cast(this)->length())->value() | |
| 3319 : FixedDoubleArray::cast(elements())->length(); | |
| 3320 if (index < static_cast<uint32_t>(length)) { | |
| 3321 FixedDoubleArray::cast(elements())->set_the_hole(index); | |
| 3322 } | |
| 3323 break; | |
| 3324 } | |
| 3325 case EXTERNAL_PIXEL_ELEMENTS: | |
| 3326 case EXTERNAL_BYTE_ELEMENTS: | |
| 3327 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 3328 case EXTERNAL_SHORT_ELEMENTS: | |
| 3329 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 3330 case EXTERNAL_INT_ELEMENTS: | |
| 3331 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 3332 case EXTERNAL_FLOAT_ELEMENTS: | |
| 3333 case EXTERNAL_DOUBLE_ELEMENTS: | |
| 3334 // Pixel and external array elements cannot be deleted. Just | |
| 3335 // silently ignore here. | |
| 3336 break; | |
| 3337 | |
| 3338 case NON_STRICT_ARGUMENTS_ELEMENTS: { | |
| 3339 FixedArray* parameter_map = FixedArray::cast(elements()); | |
| 3340 uint32_t length = parameter_map->length(); | |
| 3341 Object* probe = | |
| 3342 index < (length - 2) ? parameter_map->get(index + 2) : NULL; | |
| 3343 if (probe != NULL && !probe->IsTheHole()) { | |
| 3344 // TODO(kmillikin): We could check if this was the last aliased | |
| 3345 // parameter, and revert to normal elements in that case. That | |
| 3346 // would enable GC of the context. | |
| 3347 parameter_map->set_the_hole(index + 2); | |
| 3348 } else { | |
| 3349 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 3350 if (arguments->IsDictionary()) { | |
| 3351 return DeleteDictionaryElement(index, mode); | |
| 3352 } else { | |
| 3353 return DeleteFastElement(index); | |
| 3354 } | |
| 3355 } | |
| 3356 break; | |
| 3357 } | |
| 3358 } | |
| 3359 return isolate->heap()->true_value(); | |
| 3360 } | 3222 } |
| 3361 | 3223 |
| 3362 | 3224 |
| 3363 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { | 3225 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { |
| 3364 if (IsJSProxy()) { | 3226 if (IsJSProxy()) { |
| 3365 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode); | 3227 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode); |
| 3366 } else { | 3228 } else { |
| 3367 return JSObject::cast(this)->DeleteProperty(name, mode); | 3229 return JSObject::cast(this)->DeleteProperty(name, mode); |
| 3368 } | 3230 } |
| 3369 } | 3231 } |
| (...skipping 1540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4910 // We cannot optimize if 'this' is empty, as other may have holes | 4772 // We cannot optimize if 'this' is empty, as other may have holes |
| 4911 // or non keys. | 4773 // or non keys. |
| 4912 if (len1 == 0) return this; | 4774 if (len1 == 0) return this; |
| 4913 | 4775 |
| 4914 // Compute how many elements are not in this. | 4776 // Compute how many elements are not in this. |
| 4915 int extra = 0; | 4777 int extra = 0; |
| 4916 Heap* heap = GetHeap(); | 4778 Heap* heap = GetHeap(); |
| 4917 Object* obj; | 4779 Object* obj; |
| 4918 for (int y = 0; y < len1; y++) { | 4780 for (int y = 0; y < len1; y++) { |
| 4919 if (!other->is_the_hole(y)) { | 4781 if (!other->is_the_hole(y)) { |
| 4920 MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y)); | 4782 MaybeObject* maybe_obj = heap->NumberFromDouble(other->get_scalar(y)); |
| 4921 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4783 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4922 if (!HasKey(this, obj)) extra++; | 4784 if (!HasKey(this, obj)) extra++; |
| 4923 } | 4785 } |
| 4924 } | 4786 } |
| 4925 | 4787 |
| 4926 if (extra == 0) return this; | 4788 if (extra == 0) return this; |
| 4927 | 4789 |
| 4928 // Allocate the result | 4790 // Allocate the result |
| 4929 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra); | 4791 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra); |
| 4930 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4792 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4931 } | 4793 } |
| 4932 // Fill in the content | 4794 // Fill in the content |
| 4933 FixedArray* result = FixedArray::cast(obj); | 4795 FixedArray* result = FixedArray::cast(obj); |
| 4934 { | 4796 { |
| 4935 // Limit the scope of the AssertNoAllocation | 4797 // Limit the scope of the AssertNoAllocation |
| 4936 AssertNoAllocation no_gc; | 4798 AssertNoAllocation no_gc; |
| 4937 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); | 4799 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
| 4938 for (int i = 0; i < len0; i++) { | 4800 for (int i = 0; i < len0; i++) { |
| 4939 Object* e = get(i); | 4801 Object* e = get(i); |
| 4940 ASSERT(e->IsString() || e->IsNumber()); | 4802 ASSERT(e->IsString() || e->IsNumber()); |
| 4941 result->set(i, e, mode); | 4803 result->set(i, e, mode); |
| 4942 } | 4804 } |
| 4943 } | 4805 } |
| 4944 | 4806 |
| 4945 // Fill in the extra keys. | 4807 // Fill in the extra keys. |
| 4946 int index = 0; | 4808 int index = 0; |
| 4947 for (int y = 0; y < len1; y++) { | 4809 for (int y = 0; y < len1; y++) { |
| 4948 if (!other->is_the_hole(y)) { | 4810 if (!other->is_the_hole(y)) { |
| 4949 MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y)); | 4811 MaybeObject* maybe_obj = heap->NumberFromDouble(other->get_scalar(y)); |
| 4950 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4812 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4951 if (!HasKey(this, obj)) { | 4813 if (!HasKey(this, obj)) { |
| 4952 result->set(len0 + index, obj); | 4814 result->set(len0 + index, obj); |
| 4953 index++; | 4815 index++; |
| 4954 } | 4816 } |
| 4955 } | 4817 } |
| 4956 } | 4818 } |
| 4957 ASSERT(extra == index); | 4819 ASSERT(extra == index); |
| 4958 return result; | 4820 return result; |
| 4959 } | 4821 } |
| (...skipping 2262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7222 #ifdef ENABLE_DISASSEMBLER | 7084 #ifdef ENABLE_DISASSEMBLER |
| 7223 | 7085 |
| 7224 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { | 7086 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { |
| 7225 disasm::NameConverter converter; | 7087 disasm::NameConverter converter; |
| 7226 int deopt_count = DeoptCount(); | 7088 int deopt_count = DeoptCount(); |
| 7227 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); | 7089 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); |
| 7228 if (0 == deopt_count) return; | 7090 if (0 == deopt_count) return; |
| 7229 | 7091 |
| 7230 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); | 7092 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); |
| 7231 for (int i = 0; i < deopt_count; i++) { | 7093 for (int i = 0; i < deopt_count; i++) { |
| 7232 int command_count = 0; | |
| 7233 PrintF(out, "%6d %6d %6d", | 7094 PrintF(out, "%6d %6d %6d", |
| 7234 i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); | 7095 i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); |
| 7096 |
| 7097 if (!FLAG_print_code_verbose) continue; |
| 7098 // Print details of the frame translation. |
| 7235 int translation_index = TranslationIndex(i)->value(); | 7099 int translation_index = TranslationIndex(i)->value(); |
| 7236 TranslationIterator iterator(TranslationByteArray(), translation_index); | 7100 TranslationIterator iterator(TranslationByteArray(), translation_index); |
| 7237 Translation::Opcode opcode = | 7101 Translation::Opcode opcode = |
| 7238 static_cast<Translation::Opcode>(iterator.Next()); | 7102 static_cast<Translation::Opcode>(iterator.Next()); |
| 7239 ASSERT(Translation::BEGIN == opcode); | 7103 ASSERT(Translation::BEGIN == opcode); |
| 7240 int frame_count = iterator.Next(); | 7104 int frame_count = iterator.Next(); |
| 7241 if (FLAG_print_code_verbose) { | 7105 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode), |
| 7242 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode), | 7106 frame_count); |
| 7243 frame_count); | |
| 7244 } | |
| 7245 | 7107 |
| 7246 for (int i = 0; i < frame_count; ++i) { | 7108 while (iterator.HasNext() && |
| 7247 opcode = static_cast<Translation::Opcode>(iterator.Next()); | 7109 Translation::BEGIN != |
| 7248 ASSERT(Translation::FRAME == opcode); | 7110 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) { |
| 7249 int ast_id = iterator.Next(); | 7111 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode)); |
| 7250 int function_id = iterator.Next(); | |
| 7251 JSFunction* function = | |
| 7252 JSFunction::cast(LiteralArray()->get(function_id)); | |
| 7253 unsigned height = iterator.Next(); | |
| 7254 if (FLAG_print_code_verbose) { | |
| 7255 PrintF(out, "%24s %s {ast_id=%d, function=", | |
| 7256 "", Translation::StringFor(opcode), ast_id); | |
| 7257 function->PrintName(out); | |
| 7258 PrintF(out, ", height=%u}\n", height); | |
| 7259 } | |
| 7260 | 7112 |
| 7261 // Size of translation is height plus all incoming arguments including | 7113 switch (opcode) { |
| 7262 // receiver. | 7114 case Translation::BEGIN: |
| 7263 int size = height + function->shared()->formal_parameter_count() + 1; | 7115 UNREACHABLE(); |
| 7264 command_count += size; | 7116 break; |
| 7265 for (int j = 0; j < size; ++j) { | 7117 |
| 7266 opcode = static_cast<Translation::Opcode>(iterator.Next()); | 7118 case Translation::FRAME: { |
| 7267 if (FLAG_print_code_verbose) { | 7119 int ast_id = iterator.Next(); |
| 7268 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode)); | 7120 int function_id = iterator.Next(); |
| 7121 JSFunction* function = |
| 7122 JSFunction::cast(LiteralArray()->get(function_id)); |
| 7123 unsigned height = iterator.Next(); |
| 7124 PrintF(out, "{ast_id=%d, \nfunction=", ast_id); |
| 7125 function->PrintName(out); |
| 7126 PrintF(out, ", height=%u}", height); |
| 7127 break; |
| 7269 } | 7128 } |
| 7270 | 7129 |
| 7271 if (opcode == Translation::DUPLICATE) { | 7130 case Translation::DUPLICATE: |
| 7272 opcode = static_cast<Translation::Opcode>(iterator.Next()); | 7131 break; |
| 7273 if (FLAG_print_code_verbose) { | 7132 |
| 7274 PrintF(out, "%s ", Translation::StringFor(opcode)); | 7133 case Translation::REGISTER: { |
| 7275 } | 7134 int reg_code = iterator.Next(); |
| 7276 --j; // Two commands share the same frame index. | 7135 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); |
| 7136 break; |
| 7277 } | 7137 } |
| 7278 | 7138 |
| 7279 switch (opcode) { | 7139 case Translation::INT32_REGISTER: { |
| 7280 case Translation::BEGIN: | 7140 int reg_code = iterator.Next(); |
| 7281 case Translation::FRAME: | 7141 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); |
| 7282 case Translation::DUPLICATE: | 7142 break; |
| 7283 UNREACHABLE(); | 7143 } |
| 7284 break; | |
| 7285 | 7144 |
| 7286 case Translation::REGISTER: { | 7145 case Translation::DOUBLE_REGISTER: { |
| 7287 int reg_code = iterator.Next(); | 7146 int reg_code = iterator.Next(); |
| 7288 if (FLAG_print_code_verbose) { | 7147 PrintF(out, "{input=%s}", |
| 7289 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); | 7148 DoubleRegister::AllocationIndexToString(reg_code)); |
| 7290 } | 7149 break; |
| 7291 break; | 7150 } |
| 7292 } | |
| 7293 | 7151 |
| 7294 case Translation::INT32_REGISTER: { | 7152 case Translation::STACK_SLOT: { |
| 7295 int reg_code = iterator.Next(); | 7153 int input_slot_index = iterator.Next(); |
| 7296 if (FLAG_print_code_verbose) { | 7154 PrintF(out, "{input=%d}", input_slot_index); |
| 7297 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); | 7155 break; |
| 7298 } | 7156 } |
| 7299 break; | |
| 7300 } | |
| 7301 | 7157 |
| 7302 case Translation::DOUBLE_REGISTER: { | 7158 case Translation::INT32_STACK_SLOT: { |
| 7303 int reg_code = iterator.Next(); | 7159 int input_slot_index = iterator.Next(); |
| 7304 if (FLAG_print_code_verbose) { | 7160 PrintF(out, "{input=%d}", input_slot_index); |
| 7305 PrintF(out, "{input=%s}", | 7161 break; |
| 7306 DoubleRegister::AllocationIndexToString(reg_code)); | 7162 } |
| 7307 } | |
| 7308 break; | |
| 7309 } | |
| 7310 | 7163 |
| 7311 case Translation::STACK_SLOT: { | 7164 case Translation::DOUBLE_STACK_SLOT: { |
| 7312 int input_slot_index = iterator.Next(); | 7165 int input_slot_index = iterator.Next(); |
| 7313 if (FLAG_print_code_verbose) { | 7166 PrintF(out, "{input=%d}", input_slot_index); |
| 7314 PrintF(out, "{input=%d}", input_slot_index); | 7167 break; |
| 7315 } | 7168 } |
| 7316 break; | |
| 7317 } | |
| 7318 | 7169 |
| 7319 case Translation::INT32_STACK_SLOT: { | 7170 case Translation::LITERAL: { |
| 7320 int input_slot_index = iterator.Next(); | 7171 unsigned literal_index = iterator.Next(); |
| 7321 if (FLAG_print_code_verbose) { | 7172 PrintF(out, "{literal_id=%u}", literal_index); |
| 7322 PrintF(out, "{input=%d}", input_slot_index); | 7173 break; |
| 7323 } | 7174 } |
| 7324 break; | |
| 7325 } | |
| 7326 | 7175 |
| 7327 case Translation::DOUBLE_STACK_SLOT: { | 7176 case Translation::ARGUMENTS_OBJECT: |
| 7328 int input_slot_index = iterator.Next(); | 7177 break; |
| 7329 if (FLAG_print_code_verbose) { | |
| 7330 PrintF(out, "{input=%d}", input_slot_index); | |
| 7331 } | |
| 7332 break; | |
| 7333 } | |
| 7334 | |
| 7335 case Translation::LITERAL: { | |
| 7336 unsigned literal_index = iterator.Next(); | |
| 7337 if (FLAG_print_code_verbose) { | |
| 7338 PrintF(out, "{literal_id=%u}", literal_index); | |
| 7339 } | |
| 7340 break; | |
| 7341 } | |
| 7342 | |
| 7343 case Translation::ARGUMENTS_OBJECT: | |
| 7344 break; | |
| 7345 } | |
| 7346 if (FLAG_print_code_verbose) PrintF(out, "\n"); | |
| 7347 } | 7178 } |
| 7179 PrintF(out, "\n"); |
| 7348 } | 7180 } |
| 7349 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count); | |
| 7350 } | 7181 } |
| 7351 } | 7182 } |
| 7352 | 7183 |
| 7353 | 7184 |
| 7354 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) { | 7185 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) { |
| 7355 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n", | 7186 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n", |
| 7356 this->DeoptPoints()); | 7187 this->DeoptPoints()); |
| 7357 if (this->DeoptPoints() == 0) return; | 7188 if (this->DeoptPoints() == 0) return; |
| 7358 | 7189 |
| 7359 PrintF("%6s %8s %s\n", "ast id", "pc", "state"); | 7190 PrintF("%6s %8s %s\n", "ast id", "pc", "state"); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7616 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 7447 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| 7617 // Fill out the new array with this content and array holes. | 7448 // Fill out the new array with this content and array holes. |
| 7618 for (uint32_t i = 0; i < old_length; i++) { | 7449 for (uint32_t i = 0; i < old_length; i++) { |
| 7619 if (!old_elements->is_the_hole(i)) { | 7450 if (!old_elements->is_the_hole(i)) { |
| 7620 Object* obj; | 7451 Object* obj; |
| 7621 // Objects must be allocated in the old object space, since the | 7452 // Objects must be allocated in the old object space, since the |
| 7622 // overall number of HeapNumbers needed for the conversion might | 7453 // overall number of HeapNumbers needed for the conversion might |
| 7623 // exceed the capacity of new space, and we would fail repeatedly | 7454 // exceed the capacity of new space, and we would fail repeatedly |
| 7624 // trying to convert the FixedDoubleArray. | 7455 // trying to convert the FixedDoubleArray. |
| 7625 MaybeObject* maybe_value_object = | 7456 MaybeObject* maybe_value_object = |
| 7626 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED); | 7457 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i), |
| 7458 TENURED); |
| 7627 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; | 7459 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; |
| 7628 // Force write barrier. It's not worth trying to exploit | 7460 // Force write barrier. It's not worth trying to exploit |
| 7629 // elems->GetWriteBarrierMode(), since it requires an | 7461 // elems->GetWriteBarrierMode(), since it requires an |
| 7630 // AssertNoAllocation stack object that would have to be positioned | 7462 // AssertNoAllocation stack object that would have to be positioned |
| 7631 // after the HeapNumber allocation anyway. | 7463 // after the HeapNumber allocation anyway. |
| 7632 new_elements->set(i, obj, UPDATE_WRITE_BARRIER); | 7464 new_elements->set(i, obj, UPDATE_WRITE_BARRIER); |
| 7633 } | 7465 } |
| 7634 } | 7466 } |
| 7635 set_map(new_map); | 7467 set_map(new_map); |
| 7636 set_elements(new_elements); | 7468 set_elements(new_elements); |
| (...skipping 1322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8959 { MaybeObject* maybe_len = | 8791 { MaybeObject* maybe_len = |
| 8960 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1); | 8792 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1); |
| 8961 if (!maybe_len->ToObject(&len)) return maybe_len; | 8793 if (!maybe_len->ToObject(&len)) return maybe_len; |
| 8962 } | 8794 } |
| 8963 set_length(len); | 8795 set_length(len); |
| 8964 } | 8796 } |
| 8965 return value; | 8797 return value; |
| 8966 } | 8798 } |
| 8967 | 8799 |
| 8968 | 8800 |
| 8969 MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver, | |
| 8970 uint32_t index) { | |
| 8971 // Get element works for both JSObject and JSArray since | |
| 8972 // JSArray::length cannot change. | |
| 8973 switch (GetElementsKind()) { | |
| 8974 case FAST_ELEMENTS: { | |
| 8975 FixedArray* elms = FixedArray::cast(elements()); | |
| 8976 if (index < static_cast<uint32_t>(elms->length())) { | |
| 8977 Object* value = elms->get(index); | |
| 8978 if (!value->IsTheHole()) return value; | |
| 8979 } | |
| 8980 break; | |
| 8981 } | |
| 8982 case FAST_DOUBLE_ELEMENTS: { | |
| 8983 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | |
| 8984 if (index < static_cast<uint32_t>(elms->length())) { | |
| 8985 if (!elms->is_the_hole(index)) { | |
| 8986 return GetHeap()->NumberFromDouble(elms->get(index)); | |
| 8987 } | |
| 8988 } | |
| 8989 break; | |
| 8990 } | |
| 8991 case EXTERNAL_PIXEL_ELEMENTS: | |
| 8992 case EXTERNAL_BYTE_ELEMENTS: | |
| 8993 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 8994 case EXTERNAL_SHORT_ELEMENTS: | |
| 8995 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 8996 case EXTERNAL_INT_ELEMENTS: | |
| 8997 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 8998 case EXTERNAL_FLOAT_ELEMENTS: | |
| 8999 case EXTERNAL_DOUBLE_ELEMENTS: { | |
| 9000 MaybeObject* maybe_value = GetExternalElement(index); | |
| 9001 Object* value; | |
| 9002 if (!maybe_value->ToObject(&value)) return maybe_value; | |
| 9003 if (!value->IsUndefined()) return value; | |
| 9004 break; | |
| 9005 } | |
| 9006 case DICTIONARY_ELEMENTS: { | |
| 9007 NumberDictionary* dictionary = element_dictionary(); | |
| 9008 int entry = dictionary->FindEntry(index); | |
| 9009 if (entry != NumberDictionary::kNotFound) { | |
| 9010 Object* element = dictionary->ValueAt(entry); | |
| 9011 PropertyDetails details = dictionary->DetailsAt(entry); | |
| 9012 if (details.type() == CALLBACKS) { | |
| 9013 return GetElementWithCallback(receiver, | |
| 9014 element, | |
| 9015 index, | |
| 9016 this); | |
| 9017 } | |
| 9018 return element; | |
| 9019 } | |
| 9020 break; | |
| 9021 } | |
| 9022 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
| 9023 UNIMPLEMENTED(); | |
| 9024 break; | |
| 9025 } | |
| 9026 | |
| 9027 // Continue searching via the prototype chain. | |
| 9028 Object* pt = GetPrototype(); | |
| 9029 if (pt->IsNull()) return GetHeap()->undefined_value(); | |
| 9030 return pt->GetElementWithReceiver(receiver, index); | |
| 9031 } | |
| 9032 | |
| 9033 | |
| 9034 MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, | 8801 MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, |
| 9035 uint32_t index) { | 8802 uint32_t index) { |
| 9036 Isolate* isolate = GetIsolate(); | 8803 Isolate* isolate = GetIsolate(); |
| 9037 // Make sure that the top context does not change when doing | 8804 // Make sure that the top context does not change when doing |
| 9038 // callbacks or interceptor calls. | 8805 // callbacks or interceptor calls. |
| 9039 AssertNoContextChange ncc; | 8806 AssertNoContextChange ncc; |
| 9040 HandleScope scope(isolate); | 8807 HandleScope scope(isolate); |
| 9041 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate); | 8808 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate); |
| 9042 Handle<Object> this_handle(receiver, isolate); | 8809 Handle<Object> this_handle(receiver, isolate); |
| 9043 Handle<JSObject> holder_handle(this, isolate); | 8810 Handle<JSObject> holder_handle(this, isolate); |
| 9044 if (!interceptor->getter()->IsUndefined()) { | 8811 if (!interceptor->getter()->IsUndefined()) { |
| 9045 v8::IndexedPropertyGetter getter = | 8812 v8::IndexedPropertyGetter getter = |
| 9046 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); | 8813 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); |
| 9047 LOG(isolate, | 8814 LOG(isolate, |
| 9048 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index)); | 8815 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index)); |
| 9049 CustomArguments args(isolate, interceptor->data(), receiver, this); | 8816 CustomArguments args(isolate, interceptor->data(), receiver, this); |
| 9050 v8::AccessorInfo info(args.end()); | 8817 v8::AccessorInfo info(args.end()); |
| 9051 v8::Handle<v8::Value> result; | 8818 v8::Handle<v8::Value> result; |
| 9052 { | 8819 { |
| 9053 // Leaving JavaScript. | 8820 // Leaving JavaScript. |
| 9054 VMState state(isolate, EXTERNAL); | 8821 VMState state(isolate, EXTERNAL); |
| 9055 result = getter(index, info); | 8822 result = getter(index, info); |
| 9056 } | 8823 } |
| 9057 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 8824 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 9058 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); | 8825 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); |
| 9059 } | 8826 } |
| 9060 | 8827 |
| 9061 MaybeObject* raw_result = | 8828 Heap* heap = holder_handle->GetHeap(); |
| 9062 holder_handle->GetElementPostInterceptor(*this_handle, index); | 8829 ElementsAccessor* handler = holder_handle->GetElementsAccessor(); |
| 8830 MaybeObject* raw_result = handler->GetWithReceiver(*holder_handle, |
| 8831 *this_handle, |
| 8832 index); |
| 8833 if (raw_result != heap->the_hole_value()) return raw_result; |
| 8834 |
| 9063 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 8835 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 9064 return raw_result; | 8836 |
| 8837 Object* pt = holder_handle->GetPrototype(); |
| 8838 if (pt == heap->null_value()) return heap->undefined_value(); |
| 8839 return pt->GetElementWithReceiver(*this_handle, index); |
| 9065 } | 8840 } |
| 9066 | 8841 |
| 9067 | 8842 |
| 9068 MaybeObject* JSObject::GetElementWithReceiver(Object* receiver, | |
| 9069 uint32_t index) { | |
| 9070 // Check access rights if needed. | |
| 9071 if (IsAccessCheckNeeded()) { | |
| 9072 Heap* heap = GetHeap(); | |
| 9073 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) { | |
| 9074 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET); | |
| 9075 return heap->undefined_value(); | |
| 9076 } | |
| 9077 } | |
| 9078 | |
| 9079 if (HasIndexedInterceptor()) { | |
| 9080 return GetElementWithInterceptor(receiver, index); | |
| 9081 } | |
| 9082 | |
| 9083 // Get element works for both JSObject and JSArray since | |
| 9084 // JSArray::length cannot change. | |
| 9085 switch (GetElementsKind()) { | |
| 9086 case FAST_ELEMENTS: { | |
| 9087 FixedArray* elms = FixedArray::cast(elements()); | |
| 9088 if (index < static_cast<uint32_t>(elms->length())) { | |
| 9089 Object* value = elms->get(index); | |
| 9090 if (!value->IsTheHole()) return value; | |
| 9091 } | |
| 9092 break; | |
| 9093 } | |
| 9094 case FAST_DOUBLE_ELEMENTS: { | |
| 9095 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | |
| 9096 if (index < static_cast<uint32_t>(elms->length())) { | |
| 9097 if (!elms->is_the_hole(index)) { | |
| 9098 double double_value = elms->get(index); | |
| 9099 return GetHeap()->NumberFromDouble(double_value); | |
| 9100 } | |
| 9101 } | |
| 9102 break; | |
| 9103 } | |
| 9104 case EXTERNAL_PIXEL_ELEMENTS: | |
| 9105 case EXTERNAL_BYTE_ELEMENTS: | |
| 9106 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 9107 case EXTERNAL_SHORT_ELEMENTS: | |
| 9108 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 9109 case EXTERNAL_INT_ELEMENTS: | |
| 9110 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 9111 case EXTERNAL_FLOAT_ELEMENTS: | |
| 9112 case EXTERNAL_DOUBLE_ELEMENTS: { | |
| 9113 MaybeObject* maybe_value = GetExternalElement(index); | |
| 9114 Object* value; | |
| 9115 if (!maybe_value->ToObject(&value)) return maybe_value; | |
| 9116 if (!value->IsUndefined()) return value; | |
| 9117 break; | |
| 9118 } | |
| 9119 case DICTIONARY_ELEMENTS: { | |
| 9120 NumberDictionary* dictionary = element_dictionary(); | |
| 9121 int entry = dictionary->FindEntry(index); | |
| 9122 if (entry != NumberDictionary::kNotFound) { | |
| 9123 Object* element = dictionary->ValueAt(entry); | |
| 9124 PropertyDetails details = dictionary->DetailsAt(entry); | |
| 9125 if (details.type() == CALLBACKS) { | |
| 9126 return GetElementWithCallback(receiver, | |
| 9127 element, | |
| 9128 index, | |
| 9129 this); | |
| 9130 } | |
| 9131 return element; | |
| 9132 } | |
| 9133 break; | |
| 9134 } | |
| 9135 case NON_STRICT_ARGUMENTS_ELEMENTS: { | |
| 9136 FixedArray* parameter_map = FixedArray::cast(elements()); | |
| 9137 uint32_t length = parameter_map->length(); | |
| 9138 Object* probe = | |
| 9139 (index < length - 2) ? parameter_map->get(index + 2) : NULL; | |
| 9140 if (probe != NULL && !probe->IsTheHole()) { | |
| 9141 Context* context = Context::cast(parameter_map->get(0)); | |
| 9142 int context_index = Smi::cast(probe)->value(); | |
| 9143 ASSERT(!context->get(context_index)->IsTheHole()); | |
| 9144 return context->get(context_index); | |
| 9145 } else { | |
| 9146 // Object is not mapped, defer to the arguments. | |
| 9147 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 9148 if (arguments->IsDictionary()) { | |
| 9149 NumberDictionary* dictionary = NumberDictionary::cast(arguments); | |
| 9150 int entry = dictionary->FindEntry(index); | |
| 9151 if (entry != NumberDictionary::kNotFound) { | |
| 9152 Object* element = dictionary->ValueAt(entry); | |
| 9153 PropertyDetails details = dictionary->DetailsAt(entry); | |
| 9154 if (details.type() == CALLBACKS) { | |
| 9155 return GetElementWithCallback(receiver, | |
| 9156 element, | |
| 9157 index, | |
| 9158 this); | |
| 9159 } | |
| 9160 return element; | |
| 9161 } | |
| 9162 } else if (index < static_cast<uint32_t>(arguments->length())) { | |
| 9163 Object* value = arguments->get(index); | |
| 9164 if (!value->IsTheHole()) return value; | |
| 9165 } | |
| 9166 } | |
| 9167 break; | |
| 9168 } | |
| 9169 } | |
| 9170 | |
| 9171 Object* pt = GetPrototype(); | |
| 9172 Heap* heap = GetHeap(); | |
| 9173 if (pt == heap->null_value()) return heap->undefined_value(); | |
| 9174 return pt->GetElementWithReceiver(receiver, index); | |
| 9175 } | |
| 9176 | |
| 9177 | |
| 9178 MaybeObject* JSObject::GetExternalElement(uint32_t index) { | |
| 9179 // Get element works for both JSObject and JSArray since | |
| 9180 // JSArray::length cannot change. | |
| 9181 switch (GetElementsKind()) { | |
| 9182 case EXTERNAL_PIXEL_ELEMENTS: { | |
| 9183 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); | |
| 9184 if (index < static_cast<uint32_t>(pixels->length())) { | |
| 9185 uint8_t value = pixels->get(index); | |
| 9186 return Smi::FromInt(value); | |
| 9187 } | |
| 9188 break; | |
| 9189 } | |
| 9190 case EXTERNAL_BYTE_ELEMENTS: { | |
| 9191 ExternalByteArray* array = ExternalByteArray::cast(elements()); | |
| 9192 if (index < static_cast<uint32_t>(array->length())) { | |
| 9193 int8_t value = array->get(index); | |
| 9194 return Smi::FromInt(value); | |
| 9195 } | |
| 9196 break; | |
| 9197 } | |
| 9198 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { | |
| 9199 ExternalUnsignedByteArray* array = | |
| 9200 ExternalUnsignedByteArray::cast(elements()); | |
| 9201 if (index < static_cast<uint32_t>(array->length())) { | |
| 9202 uint8_t value = array->get(index); | |
| 9203 return Smi::FromInt(value); | |
| 9204 } | |
| 9205 break; | |
| 9206 } | |
| 9207 case EXTERNAL_SHORT_ELEMENTS: { | |
| 9208 ExternalShortArray* array = ExternalShortArray::cast(elements()); | |
| 9209 if (index < static_cast<uint32_t>(array->length())) { | |
| 9210 int16_t value = array->get(index); | |
| 9211 return Smi::FromInt(value); | |
| 9212 } | |
| 9213 break; | |
| 9214 } | |
| 9215 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { | |
| 9216 ExternalUnsignedShortArray* array = | |
| 9217 ExternalUnsignedShortArray::cast(elements()); | |
| 9218 if (index < static_cast<uint32_t>(array->length())) { | |
| 9219 uint16_t value = array->get(index); | |
| 9220 return Smi::FromInt(value); | |
| 9221 } | |
| 9222 break; | |
| 9223 } | |
| 9224 case EXTERNAL_INT_ELEMENTS: { | |
| 9225 ExternalIntArray* array = ExternalIntArray::cast(elements()); | |
| 9226 if (index < static_cast<uint32_t>(array->length())) { | |
| 9227 int32_t value = array->get(index); | |
| 9228 return GetHeap()->NumberFromInt32(value); | |
| 9229 } | |
| 9230 break; | |
| 9231 } | |
| 9232 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { | |
| 9233 ExternalUnsignedIntArray* array = | |
| 9234 ExternalUnsignedIntArray::cast(elements()); | |
| 9235 if (index < static_cast<uint32_t>(array->length())) { | |
| 9236 uint32_t value = array->get(index); | |
| 9237 return GetHeap()->NumberFromUint32(value); | |
| 9238 } | |
| 9239 break; | |
| 9240 } | |
| 9241 case EXTERNAL_FLOAT_ELEMENTS: { | |
| 9242 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); | |
| 9243 if (index < static_cast<uint32_t>(array->length())) { | |
| 9244 float value = array->get(index); | |
| 9245 return GetHeap()->AllocateHeapNumber(value); | |
| 9246 } | |
| 9247 break; | |
| 9248 } | |
| 9249 case EXTERNAL_DOUBLE_ELEMENTS: { | |
| 9250 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); | |
| 9251 if (index < static_cast<uint32_t>(array->length())) { | |
| 9252 double value = array->get(index); | |
| 9253 return GetHeap()->AllocateHeapNumber(value); | |
| 9254 } | |
| 9255 break; | |
| 9256 } | |
| 9257 case FAST_DOUBLE_ELEMENTS: | |
| 9258 case FAST_ELEMENTS: | |
| 9259 case DICTIONARY_ELEMENTS: | |
| 9260 UNREACHABLE(); | |
| 9261 break; | |
| 9262 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
| 9263 UNIMPLEMENTED(); | |
| 9264 break; | |
| 9265 } | |
| 9266 return GetHeap()->undefined_value(); | |
| 9267 } | |
| 9268 | |
| 9269 | |
| 9270 bool JSObject::HasDenseElements() { | 8843 bool JSObject::HasDenseElements() { |
| 9271 int capacity = 0; | 8844 int capacity = 0; |
| 9272 int used = 0; | 8845 int used = 0; |
| 9273 GetElementsCapacityAndUsage(&capacity, &used); | 8846 GetElementsCapacityAndUsage(&capacity, &used); |
| 9274 return (capacity == 0) || (used > (capacity / 2)); | 8847 return (capacity == 0) || (used > (capacity / 2)); |
| 9275 } | 8848 } |
| 9276 | 8849 |
| 9277 | 8850 |
| 9278 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { | 8851 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
| 9279 *capacity = 0; | 8852 *capacity = 0; |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9770 // mirrors. | 9343 // mirrors. |
| 9771 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { | 9344 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { |
| 9772 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index)); | 9345 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index)); |
| 9773 if (HasFastProperties()) { | 9346 if (HasFastProperties()) { |
| 9774 DescriptorArray* descs = map()->instance_descriptors(); | 9347 DescriptorArray* descs = map()->instance_descriptors(); |
| 9775 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 9348 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 9776 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i)); | 9349 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i)); |
| 9777 } | 9350 } |
| 9778 ASSERT(storage->length() >= index); | 9351 ASSERT(storage->length() >= index); |
| 9779 } else { | 9352 } else { |
| 9780 property_dictionary()->CopyKeysTo(storage, StringDictionary::UNSORTED); | 9353 property_dictionary()->CopyKeysTo(storage, |
| 9354 index, |
| 9355 StringDictionary::UNSORTED); |
| 9781 } | 9356 } |
| 9782 } | 9357 } |
| 9783 | 9358 |
| 9784 | 9359 |
| 9785 int JSObject::NumberOfLocalElements(PropertyAttributes filter) { | 9360 int JSObject::NumberOfLocalElements(PropertyAttributes filter) { |
| 9786 return GetLocalElementKeys(NULL, filter); | 9361 return GetLocalElementKeys(NULL, filter); |
| 9787 } | 9362 } |
| 9788 | 9363 |
| 9789 | 9364 |
| 9790 int JSObject::NumberOfEnumElements() { | 9365 int JSObject::NumberOfEnumElements() { |
| (...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10519 int, JSObject::DeleteMode); | 10094 int, JSObject::DeleteMode); |
| 10520 | 10095 |
| 10521 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink( | 10096 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink( |
| 10522 String*); | 10097 String*); |
| 10523 | 10098 |
| 10524 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink( | 10099 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink( |
| 10525 uint32_t); | 10100 uint32_t); |
| 10526 | 10101 |
| 10527 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( | 10102 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( |
| 10528 FixedArray*, | 10103 FixedArray*, |
| 10104 int, |
| 10529 Dictionary<StringDictionaryShape, String*>::SortMode); | 10105 Dictionary<StringDictionaryShape, String*>::SortMode); |
| 10530 | 10106 |
| 10531 template int | 10107 template int |
| 10532 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( | 10108 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( |
| 10533 PropertyAttributes); | 10109 PropertyAttributes); |
| 10534 | 10110 |
| 10535 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( | 10111 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( |
| 10536 String*, Object*, PropertyDetails); | 10112 String*, Object*, PropertyDetails); |
| 10537 | 10113 |
| 10538 template MaybeObject* | 10114 template MaybeObject* |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10693 Object* new_array; | 10269 Object* new_array; |
| 10694 { MaybeObject* maybe_new_array = | 10270 { MaybeObject* maybe_new_array = |
| 10695 heap->AllocateFixedArray(dict->NumberOfElements(), tenure); | 10271 heap->AllocateFixedArray(dict->NumberOfElements(), tenure); |
| 10696 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; | 10272 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; |
| 10697 } | 10273 } |
| 10698 FixedArray* fast_elements = FixedArray::cast(new_array); | 10274 FixedArray* fast_elements = FixedArray::cast(new_array); |
| 10699 dict->CopyValuesTo(fast_elements); | 10275 dict->CopyValuesTo(fast_elements); |
| 10700 | 10276 |
| 10701 set_map(new_map); | 10277 set_map(new_map); |
| 10702 set_elements(fast_elements); | 10278 set_elements(fast_elements); |
| 10703 } else { | 10279 } else if (!HasFastDoubleElements()) { |
| 10704 Object* obj; | 10280 Object* obj; |
| 10705 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | 10281 { MaybeObject* maybe_obj = EnsureWritableFastElements(); |
| 10706 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 10282 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 10707 } | 10283 } |
| 10708 } | 10284 } |
| 10709 ASSERT(HasFastElements()); | 10285 ASSERT(HasFastElements() || HasFastDoubleElements()); |
| 10710 | 10286 |
| 10711 // Collect holes at the end, undefined before that and the rest at the | 10287 // Collect holes at the end, undefined before that and the rest at the |
| 10712 // start, and return the number of non-hole, non-undefined values. | 10288 // start, and return the number of non-hole, non-undefined values. |
| 10713 | 10289 |
| 10714 FixedArray* elements = FixedArray::cast(this->elements()); | 10290 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements()); |
| 10715 uint32_t elements_length = static_cast<uint32_t>(elements->length()); | 10291 uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); |
| 10716 if (limit > elements_length) { | 10292 if (limit > elements_length) { |
| 10717 limit = elements_length ; | 10293 limit = elements_length ; |
| 10718 } | 10294 } |
| 10719 if (limit == 0) { | 10295 if (limit == 0) { |
| 10720 return Smi::FromInt(0); | 10296 return Smi::FromInt(0); |
| 10721 } | 10297 } |
| 10722 | 10298 |
| 10723 HeapNumber* result_double = NULL; | 10299 HeapNumber* result_double = NULL; |
| 10724 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | 10300 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { |
| 10725 // Pessimistically allocate space for return value before | 10301 // Pessimistically allocate space for return value before |
| 10726 // we start mutating the array. | 10302 // we start mutating the array. |
| 10727 Object* new_double; | 10303 Object* new_double; |
| 10728 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0); | 10304 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0); |
| 10729 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; | 10305 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; |
| 10730 } | 10306 } |
| 10731 result_double = HeapNumber::cast(new_double); | 10307 result_double = HeapNumber::cast(new_double); |
| 10732 } | 10308 } |
| 10733 | 10309 |
| 10734 AssertNoAllocation no_alloc; | 10310 uint32_t result = 0; |
| 10311 if (elements_base->map() == heap->fixed_double_array_map()) { |
| 10312 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base); |
| 10313 // Split elements into defined and the_hole, in that order. |
| 10314 unsigned int holes = limit; |
| 10315 // Assume most arrays contain no holes and undefined values, so minimize the |
| 10316 // number of stores of non-undefined, non-the-hole values. |
| 10317 for (unsigned int i = 0; i < holes; i++) { |
| 10318 if (elements->is_the_hole(i)) { |
| 10319 holes--; |
| 10320 } else { |
| 10321 continue; |
| 10322 } |
| 10323 // Position i needs to be filled. |
| 10324 while (holes > i) { |
| 10325 if (elements->is_the_hole(holes)) { |
| 10326 holes--; |
| 10327 } else { |
| 10328 elements->set(i, elements->get_scalar(holes)); |
| 10329 break; |
| 10330 } |
| 10331 } |
| 10332 } |
| 10333 result = holes; |
| 10334 while (holes < limit) { |
| 10335 elements->set_the_hole(holes); |
| 10336 holes++; |
| 10337 } |
| 10338 } else { |
| 10339 FixedArray* elements = FixedArray::cast(elements_base); |
| 10340 AssertNoAllocation no_alloc; |
| 10735 | 10341 |
| 10736 // Split elements into defined, undefined and the_hole, in that order. | 10342 // Split elements into defined, undefined and the_hole, in that order. Only |
| 10737 // Only count locations for undefined and the hole, and fill them afterwards. | 10343 // count locations for undefined and the hole, and fill them afterwards. |
| 10738 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc); | 10344 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc); |
| 10739 unsigned int undefs = limit; | 10345 unsigned int undefs = limit; |
| 10740 unsigned int holes = limit; | 10346 unsigned int holes = limit; |
| 10741 // Assume most arrays contain no holes and undefined values, so minimize the | 10347 // Assume most arrays contain no holes and undefined values, so minimize the |
| 10742 // number of stores of non-undefined, non-the-hole values. | 10348 // number of stores of non-undefined, non-the-hole values. |
| 10743 for (unsigned int i = 0; i < undefs; i++) { | 10349 for (unsigned int i = 0; i < undefs; i++) { |
| 10744 Object* current = elements->get(i); | 10350 Object* current = elements->get(i); |
| 10745 if (current->IsTheHole()) { | |
| 10746 holes--; | |
| 10747 undefs--; | |
| 10748 } else if (current->IsUndefined()) { | |
| 10749 undefs--; | |
| 10750 } else { | |
| 10751 continue; | |
| 10752 } | |
| 10753 // Position i needs to be filled. | |
| 10754 while (undefs > i) { | |
| 10755 current = elements->get(undefs); | |
| 10756 if (current->IsTheHole()) { | 10351 if (current->IsTheHole()) { |
| 10757 holes--; | 10352 holes--; |
| 10758 undefs--; | 10353 undefs--; |
| 10759 } else if (current->IsUndefined()) { | 10354 } else if (current->IsUndefined()) { |
| 10760 undefs--; | 10355 undefs--; |
| 10761 } else { | 10356 } else { |
| 10762 elements->set(i, current, write_barrier); | 10357 continue; |
| 10763 break; | 10358 } |
| 10359 // Position i needs to be filled. |
| 10360 while (undefs > i) { |
| 10361 current = elements->get(undefs); |
| 10362 if (current->IsTheHole()) { |
| 10363 holes--; |
| 10364 undefs--; |
| 10365 } else if (current->IsUndefined()) { |
| 10366 undefs--; |
| 10367 } else { |
| 10368 elements->set(i, current, write_barrier); |
| 10369 break; |
| 10370 } |
| 10764 } | 10371 } |
| 10765 } | 10372 } |
| 10766 } | 10373 result = undefs; |
| 10767 uint32_t result = undefs; | 10374 while (undefs < holes) { |
| 10768 while (undefs < holes) { | 10375 elements->set_undefined(undefs); |
| 10769 elements->set_undefined(undefs); | 10376 undefs++; |
| 10770 undefs++; | 10377 } |
| 10771 } | 10378 while (holes < limit) { |
| 10772 while (holes < limit) { | 10379 elements->set_the_hole(holes); |
| 10773 elements->set_the_hole(holes); | 10380 holes++; |
| 10774 holes++; | 10381 } |
| 10775 } | 10382 } |
| 10776 | 10383 |
| 10777 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { | 10384 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { |
| 10778 return Smi::FromInt(static_cast<int>(result)); | 10385 return Smi::FromInt(static_cast<int>(result)); |
| 10779 } | 10386 } |
| 10780 ASSERT_NE(NULL, result_double); | 10387 ASSERT_NE(NULL, result_double); |
| 10781 result_double->set_value(static_cast<double>(result)); | 10388 result_double->set_value(static_cast<double>(result)); |
| 10782 return result_double; | 10389 return result_double; |
| 10783 } | 10390 } |
| 10784 | 10391 |
| (...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11617 } | 11224 } |
| 11618 } | 11225 } |
| 11619 storage->SortPairs(sort_array, sort_array->length()); | 11226 storage->SortPairs(sort_array, sort_array->length()); |
| 11620 ASSERT(storage->length() >= index); | 11227 ASSERT(storage->length() >= index); |
| 11621 } | 11228 } |
| 11622 | 11229 |
| 11623 | 11230 |
| 11624 template<typename Shape, typename Key> | 11231 template<typename Shape, typename Key> |
| 11625 void Dictionary<Shape, Key>::CopyKeysTo( | 11232 void Dictionary<Shape, Key>::CopyKeysTo( |
| 11626 FixedArray* storage, | 11233 FixedArray* storage, |
| 11234 int index, |
| 11627 typename Dictionary<Shape, Key>::SortMode sort_mode) { | 11235 typename Dictionary<Shape, Key>::SortMode sort_mode) { |
| 11628 ASSERT(storage->length() >= NumberOfElementsFilterAttributes( | 11236 ASSERT(storage->length() >= NumberOfElementsFilterAttributes( |
| 11629 static_cast<PropertyAttributes>(NONE))); | 11237 static_cast<PropertyAttributes>(NONE))); |
| 11630 int capacity = HashTable<Shape, Key>::Capacity(); | 11238 int capacity = HashTable<Shape, Key>::Capacity(); |
| 11631 int index = 0; | |
| 11632 for (int i = 0; i < capacity; i++) { | 11239 for (int i = 0; i < capacity; i++) { |
| 11633 Object* k = HashTable<Shape, Key>::KeyAt(i); | 11240 Object* k = HashTable<Shape, Key>::KeyAt(i); |
| 11634 if (HashTable<Shape, Key>::IsKey(k)) { | 11241 if (HashTable<Shape, Key>::IsKey(k)) { |
| 11635 PropertyDetails details = DetailsAt(i); | 11242 PropertyDetails details = DetailsAt(i); |
| 11636 if (details.IsDeleted()) continue; | 11243 if (details.IsDeleted()) continue; |
| 11637 storage->set(index++, k); | 11244 storage->set(index++, k); |
| 11638 } | 11245 } |
| 11639 } | 11246 } |
| 11640 if (sort_mode == Dictionary<Shape, Key>::SORTED) { | 11247 if (sort_mode == Dictionary<Shape, Key>::SORTED) { |
| 11641 storage->SortPairs(storage, index); | 11248 storage->SortPairs(storage, index); |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11842 } | 11449 } |
| 11843 | 11450 |
| 11844 | 11451 |
| 11845 void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) { | 11452 void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) { |
| 11846 set(EntryToIndex(entry), key); | 11453 set(EntryToIndex(entry), key); |
| 11847 set(EntryToIndex(entry) + 1, value); | 11454 set(EntryToIndex(entry) + 1, value); |
| 11848 ElementAdded(); | 11455 ElementAdded(); |
| 11849 } | 11456 } |
| 11850 | 11457 |
| 11851 | 11458 |
| 11852 void ObjectHashTable::RemoveEntry(int entry) { | 11459 void ObjectHashTable::RemoveEntry(int entry, Heap* heap) { |
| 11853 Object* null_value = GetHeap()->null_value(); | 11460 set_null(heap, EntryToIndex(entry)); |
| 11854 set(EntryToIndex(entry), null_value); | 11461 set_null(heap, EntryToIndex(entry) + 1); |
| 11855 set(EntryToIndex(entry) + 1, null_value); | |
| 11856 ElementRemoved(); | 11462 ElementRemoved(); |
| 11857 } | 11463 } |
| 11858 | 11464 |
| 11859 | 11465 |
| 11860 #ifdef ENABLE_DEBUGGER_SUPPORT | 11466 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 11861 // Check if there is a break point at this code position. | 11467 // Check if there is a break point at this code position. |
| 11862 bool DebugInfo::HasBreakPoint(int code_position) { | 11468 bool DebugInfo::HasBreakPoint(int code_position) { |
| 11863 // Get the break point info object for this code position. | 11469 // Get the break point info object for this code position. |
| 11864 Object* break_point_info = GetBreakPointInfo(code_position); | 11470 Object* break_point_info = GetBreakPointInfo(code_position); |
| 11865 | 11471 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12076 new_array->set(old_array->length(), *break_point_object); | 11682 new_array->set(old_array->length(), *break_point_object); |
| 12077 break_point_info->set_break_point_objects(*new_array); | 11683 break_point_info->set_break_point_objects(*new_array); |
| 12078 } | 11684 } |
| 12079 | 11685 |
| 12080 | 11686 |
| 12081 bool BreakPointInfo::HasBreakPointObject( | 11687 bool BreakPointInfo::HasBreakPointObject( |
| 12082 Handle<BreakPointInfo> break_point_info, | 11688 Handle<BreakPointInfo> break_point_info, |
| 12083 Handle<Object> break_point_object) { | 11689 Handle<Object> break_point_object) { |
| 12084 // No break point. | 11690 // No break point. |
| 12085 if (break_point_info->break_point_objects()->IsUndefined()) return false; | 11691 if (break_point_info->break_point_objects()->IsUndefined()) return false; |
| 12086 // Single beak point. | 11692 // Single break point. |
| 12087 if (!break_point_info->break_point_objects()->IsFixedArray()) { | 11693 if (!break_point_info->break_point_objects()->IsFixedArray()) { |
| 12088 return break_point_info->break_point_objects() == *break_point_object; | 11694 return break_point_info->break_point_objects() == *break_point_object; |
| 12089 } | 11695 } |
| 12090 // Multiple break points. | 11696 // Multiple break points. |
| 12091 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); | 11697 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); |
| 12092 for (int i = 0; i < array->length(); i++) { | 11698 for (int i = 0; i < array->length(); i++) { |
| 12093 if (array->get(i) == *break_point_object) { | 11699 if (array->get(i) == *break_point_object) { |
| 12094 return true; | 11700 return true; |
| 12095 } | 11701 } |
| 12096 } | 11702 } |
| 12097 return false; | 11703 return false; |
| 12098 } | 11704 } |
| 12099 | 11705 |
| 12100 | 11706 |
| 12101 // Get the number of break points. | 11707 // Get the number of break points. |
| 12102 int BreakPointInfo::GetBreakPointCount() { | 11708 int BreakPointInfo::GetBreakPointCount() { |
| 12103 // No break point. | 11709 // No break point. |
| 12104 if (break_point_objects()->IsUndefined()) return 0; | 11710 if (break_point_objects()->IsUndefined()) return 0; |
| 12105 // Single beak point. | 11711 // Single break point. |
| 12106 if (!break_point_objects()->IsFixedArray()) return 1; | 11712 if (!break_point_objects()->IsFixedArray()) return 1; |
| 12107 // Multiple break points. | 11713 // Multiple break points. |
| 12108 return FixedArray::cast(break_point_objects())->length(); | 11714 return FixedArray::cast(break_point_objects())->length(); |
| 12109 } | 11715 } |
| 12110 #endif | 11716 #endif |
| 12111 | 11717 |
| 12112 | 11718 |
| 12113 } } // namespace v8::internal | 11719 } } // namespace v8::internal |
| OLD | NEW |