| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 2252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2263 ASSERT(target_inobject < inobject_properties()); | 2263 ASSERT(target_inobject < inobject_properties()); |
| 2264 if (target_number_of_fields <= target_inobject) { | 2264 if (target_number_of_fields <= target_inobject) { |
| 2265 ASSERT(target_number_of_fields + target_unused == target_inobject); | 2265 ASSERT(target_number_of_fields + target_unused == target_inobject); |
| 2266 return false; | 2266 return false; |
| 2267 } | 2267 } |
| 2268 // Otherwise, properties will need to be moved to the backing store. | 2268 // Otherwise, properties will need to be moved to the backing store. |
| 2269 return true; | 2269 return true; |
| 2270 } | 2270 } |
| 2271 | 2271 |
| 2272 | 2272 |
| 2273 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { | |
| 2274 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), object->MigrateToMap(*new_map)); | |
| 2275 } | |
| 2276 | |
| 2277 | |
| 2278 // To migrate an instance to a map: | 2273 // To migrate an instance to a map: |
| 2279 // - First check whether the instance needs to be rewritten. If not, simply | 2274 // - First check whether the instance needs to be rewritten. If not, simply |
| 2280 // change the map. | 2275 // change the map. |
| 2281 // - Otherwise, allocate a fixed array large enough to hold all fields, in | 2276 // - Otherwise, allocate a fixed array large enough to hold all fields, in |
| 2282 // addition to unused space. | 2277 // addition to unused space. |
| 2283 // - Copy all existing properties in, in the following order: backing store | 2278 // - Copy all existing properties in, in the following order: backing store |
| 2284 // properties, unused fields, inobject properties. | 2279 // properties, unused fields, inobject properties. |
| 2285 // - If all allocation succeeded, commit the state atomically: | 2280 // - If all allocation succeeded, commit the state atomically: |
| 2286 // * Copy inobject properties from the backing store back into the object. | 2281 // * Copy inobject properties from the backing store back into the object. |
| 2287 // * Trim the difference in instance size of the object. This also cleanly | 2282 // * Trim the difference in instance size of the object. This also cleanly |
| 2288 // frees inobject properties that moved to the backing store. | 2283 // frees inobject properties that moved to the backing store. |
| 2289 // * If there are properties left in the backing store, trim of the space used | 2284 // * If there are properties left in the backing store, trim of the space used |
| 2290 // to temporarily store the inobject properties. | 2285 // to temporarily store the inobject properties. |
| 2291 // * If there are properties left in the backing store, install the backing | 2286 // * If there are properties left in the backing store, install the backing |
| 2292 // store. | 2287 // store. |
| 2293 MaybeObject* JSObject::MigrateToMap(Map* new_map) { | 2288 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { |
| 2294 Heap* heap = GetHeap(); | 2289 Isolate* isolate = object->GetIsolate(); |
| 2295 Map* old_map = map(); | 2290 Handle<Map> old_map(object->map()); |
| 2296 int number_of_fields = new_map->NumberOfFields(); | 2291 int number_of_fields = new_map->NumberOfFields(); |
| 2297 int inobject = new_map->inobject_properties(); | 2292 int inobject = new_map->inobject_properties(); |
| 2298 int unused = new_map->unused_property_fields(); | 2293 int unused = new_map->unused_property_fields(); |
| 2299 | 2294 |
| 2300 // Nothing to do if no functions were converted to fields. | 2295 // Nothing to do if no functions were converted to fields and no smis were |
| 2296 // converted to doubles. |
| 2301 if (!old_map->InstancesNeedRewriting( | 2297 if (!old_map->InstancesNeedRewriting( |
| 2302 new_map, number_of_fields, inobject, unused)) { | 2298 *new_map, number_of_fields, inobject, unused)) { |
| 2303 set_map(new_map); | 2299 object->set_map(*new_map); |
| 2304 return this; | 2300 return; |
| 2305 } | 2301 } |
| 2306 | 2302 |
| 2307 int total_size = number_of_fields + unused; | 2303 int total_size = number_of_fields + unused; |
| 2308 int external = total_size - inobject; | 2304 int external = total_size - inobject; |
| 2309 FixedArray* array; | 2305 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); |
| 2310 MaybeObject* maybe_array = heap->AllocateFixedArray(total_size); | |
| 2311 if (!maybe_array->To(&array)) return maybe_array; | |
| 2312 | 2306 |
| 2313 DescriptorArray* old_descriptors = old_map->instance_descriptors(); | 2307 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); |
| 2314 DescriptorArray* new_descriptors = new_map->instance_descriptors(); | 2308 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); |
| 2315 int descriptors = new_map->NumberOfOwnDescriptors(); | 2309 int descriptors = new_map->NumberOfOwnDescriptors(); |
| 2316 | 2310 |
| 2317 for (int i = 0; i < descriptors; i++) { | 2311 for (int i = 0; i < descriptors; i++) { |
| 2318 PropertyDetails details = new_descriptors->GetDetails(i); | 2312 PropertyDetails details = new_descriptors->GetDetails(i); |
| 2319 if (details.type() != FIELD) continue; | 2313 if (details.type() != FIELD) continue; |
| 2320 PropertyDetails old_details = old_descriptors->GetDetails(i); | 2314 PropertyDetails old_details = old_descriptors->GetDetails(i); |
| 2321 if (old_details.type() == CALLBACKS) { | 2315 if (old_details.type() == CALLBACKS) { |
| 2322 ASSERT(details.representation().IsTagged()); | 2316 ASSERT(details.representation().IsTagged()); |
| 2323 continue; | 2317 continue; |
| 2324 } | 2318 } |
| 2325 ASSERT(old_details.type() == CONSTANT || | 2319 ASSERT(old_details.type() == CONSTANT || |
| 2326 old_details.type() == FIELD); | 2320 old_details.type() == FIELD); |
| 2327 Object* value = old_details.type() == CONSTANT | 2321 Object* raw_value = old_details.type() == CONSTANT |
| 2328 ? old_descriptors->GetValue(i) | 2322 ? old_descriptors->GetValue(i) |
| 2329 : RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); | 2323 : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); |
| 2324 Handle<Object> value(raw_value, isolate); |
| 2330 if (FLAG_track_double_fields && | 2325 if (FLAG_track_double_fields && |
| 2331 !old_details.representation().IsDouble() && | 2326 !old_details.representation().IsDouble() && |
| 2332 details.representation().IsDouble()) { | 2327 details.representation().IsDouble()) { |
| 2333 if (old_details.representation().IsNone()) value = Smi::FromInt(0); | 2328 if (old_details.representation().IsNone()) { |
| 2334 // Objects must be allocated in the old object space, since the | 2329 value = handle(Smi::FromInt(0), isolate); |
| 2335 // overall number of HeapNumbers needed for the conversion might | 2330 } |
| 2336 // exceed the capacity of new space, and we would fail repeatedly | 2331 value = NewStorageFor(isolate, value, details.representation()); |
| 2337 // trying to migrate the instance. | |
| 2338 MaybeObject* maybe_storage = | |
| 2339 value->AllocateNewStorageFor(heap, details.representation(), TENURED); | |
| 2340 if (!maybe_storage->To(&value)) return maybe_storage; | |
| 2341 } | 2332 } |
| 2342 ASSERT(!(FLAG_track_double_fields && | 2333 ASSERT(!(FLAG_track_double_fields && |
| 2343 details.representation().IsDouble() && | 2334 details.representation().IsDouble() && |
| 2344 value->IsSmi())); | 2335 value->IsSmi())); |
| 2345 int target_index = new_descriptors->GetFieldIndex(i) - inobject; | 2336 int target_index = new_descriptors->GetFieldIndex(i) - inobject; |
| 2346 if (target_index < 0) target_index += total_size; | 2337 if (target_index < 0) target_index += total_size; |
| 2347 array->set(target_index, value); | 2338 array->set(target_index, *value); |
| 2348 } | 2339 } |
| 2349 | 2340 |
| 2350 // From here on we cannot fail anymore. | 2341 // From here on we cannot fail and we shouldn't GC anymore. |
| 2342 DisallowHeapAllocation no_allocation; |
| 2351 | 2343 |
| 2352 // Copy (real) inobject properties. If necessary, stop at number_of_fields to | 2344 // Copy (real) inobject properties. If necessary, stop at number_of_fields to |
| 2353 // avoid overwriting |one_pointer_filler_map|. | 2345 // avoid overwriting |one_pointer_filler_map|. |
| 2354 int limit = Min(inobject, number_of_fields); | 2346 int limit = Min(inobject, number_of_fields); |
| 2355 for (int i = 0; i < limit; i++) { | 2347 for (int i = 0; i < limit; i++) { |
| 2356 FastPropertyAtPut(i, array->get(external + i)); | 2348 object->FastPropertyAtPut(i, array->get(external + i)); |
| 2357 } | 2349 } |
| 2358 | 2350 |
| 2359 // Create filler object past the new instance size. | 2351 // Create filler object past the new instance size. |
| 2360 int new_instance_size = new_map->instance_size(); | 2352 int new_instance_size = new_map->instance_size(); |
| 2361 int instance_size_delta = old_map->instance_size() - new_instance_size; | 2353 int instance_size_delta = old_map->instance_size() - new_instance_size; |
| 2362 ASSERT(instance_size_delta >= 0); | 2354 ASSERT(instance_size_delta >= 0); |
| 2363 Address address = this->address() + new_instance_size; | 2355 Address address = object->address() + new_instance_size; |
| 2364 heap->CreateFillerObjectAt(address, instance_size_delta); | 2356 isolate->heap()->CreateFillerObjectAt(address, instance_size_delta); |
| 2365 | 2357 |
| 2366 // If there are properties in the new backing store, trim it to the correct | 2358 // If there are properties in the new backing store, trim it to the correct |
| 2367 // size and install the backing store into the object. | 2359 // size and install the backing store into the object. |
| 2368 if (external > 0) { | 2360 if (external > 0) { |
| 2369 RightTrimFixedArray<FROM_MUTATOR>(heap, array, inobject); | 2361 RightTrimFixedArray<FROM_MUTATOR>(isolate->heap(), *array, inobject); |
| 2370 set_properties(array); | 2362 object->set_properties(*array); |
| 2371 } | 2363 } |
| 2372 | 2364 |
| 2373 set_map(new_map); | 2365 object->set_map(*new_map); |
| 2374 | |
| 2375 return this; | |
| 2376 } | 2366 } |
| 2377 | 2367 |
| 2378 | 2368 |
| 2379 void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object, | 2369 void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object, |
| 2380 int modify_index, | 2370 int modify_index, |
| 2381 Representation new_representation, | 2371 Representation new_representation, |
| 2382 StoreMode store_mode) { | 2372 StoreMode store_mode) { |
| 2383 Handle<Map> new_map = Map::GeneralizeRepresentation( | 2373 Handle<Map> new_map = Map::GeneralizeRepresentation( |
| 2384 handle(object->map()), modify_index, new_representation, store_mode); | 2374 handle(object->map()), modify_index, new_representation, store_mode); |
| 2385 if (object->map() == *new_map) return; | 2375 if (object->map() == *new_map) return; |
| (...skipping 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3701 return Handle<Object>(); | 3691 return Handle<Object>(); |
| 3702 } | 3692 } |
| 3703 trap = Handle<Object>(derived); | 3693 trap = Handle<Object>(derived); |
| 3704 } | 3694 } |
| 3705 | 3695 |
| 3706 bool threw; | 3696 bool threw; |
| 3707 return Execution::Call(isolate, trap, handler, argc, argv, &threw); | 3697 return Execution::Call(isolate, trap, handler, argc, argv, &threw); |
| 3708 } | 3698 } |
| 3709 | 3699 |
| 3710 | 3700 |
| 3701 // TODO(mstarzinger): Temporary wrapper until handlified. |
| 3702 static Handle<Map> MapAsElementsKind(Handle<Map> map, ElementsKind kind) { |
| 3703 CALL_HEAP_FUNCTION(map->GetIsolate(), map->AsElementsKind(kind), Map); |
| 3704 } |
| 3705 |
| 3706 |
| 3711 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { | 3707 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { |
| 3712 CALL_HEAP_FUNCTION_VOID( | 3708 ASSERT(object->map()->inobject_properties() == map->inobject_properties()); |
| 3713 object->GetIsolate(), | 3709 ElementsKind obj_kind = object->map()->elements_kind(); |
| 3714 object->AllocateStorageForMap(*map)); | 3710 ElementsKind map_kind = map->elements_kind(); |
| 3711 if (map_kind != obj_kind) { |
| 3712 ElementsKind to_kind = map_kind; |
| 3713 if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) || |
| 3714 IsDictionaryElementsKind(obj_kind)) { |
| 3715 to_kind = obj_kind; |
| 3716 } |
| 3717 if (IsDictionaryElementsKind(to_kind)) { |
| 3718 NormalizeElements(object); |
| 3719 } else { |
| 3720 TransitionElementsKind(object, to_kind); |
| 3721 } |
| 3722 map = MapAsElementsKind(map, to_kind); |
| 3723 } |
| 3724 int total_size = |
| 3725 map->NumberOfOwnDescriptors() + map->unused_property_fields(); |
| 3726 int out_of_object = total_size - map->inobject_properties(); |
| 3727 if (out_of_object != object->properties()->length()) { |
| 3728 Isolate* isolate = object->GetIsolate(); |
| 3729 Handle<FixedArray> new_properties = isolate->factory()->CopySizeFixedArray( |
| 3730 handle(object->properties()), out_of_object); |
| 3731 object->set_properties(*new_properties); |
| 3732 } |
| 3733 object->set_map(*map); |
| 3715 } | 3734 } |
| 3716 | 3735 |
| 3717 | 3736 |
| 3718 void JSObject::MigrateInstance(Handle<JSObject> object) { | 3737 void JSObject::MigrateInstance(Handle<JSObject> object) { |
| 3719 // Converting any field to the most specific type will cause the | 3738 // Converting any field to the most specific type will cause the |
| 3720 // GeneralizeFieldRepresentation algorithm to create the most general existing | 3739 // GeneralizeFieldRepresentation algorithm to create the most general existing |
| 3721 // transition that matches the object. This achieves what is needed. | 3740 // transition that matches the object. This achieves what is needed. |
| 3722 Handle<Map> original_map(object->map()); | 3741 Handle<Map> original_map(object->map()); |
| 3723 GeneralizeFieldRepresentation( | 3742 GeneralizeFieldRepresentation( |
| 3724 object, 0, Representation::None(), ALLOW_AS_CONSTANT); | 3743 object, 0, Representation::None(), ALLOW_AS_CONSTANT); |
| 3725 if (FLAG_trace_migration) { | 3744 if (FLAG_trace_migration) { |
| 3726 object->PrintInstanceMigration(stdout, *original_map, object->map()); | 3745 object->PrintInstanceMigration(stdout, *original_map, object->map()); |
| 3727 } | 3746 } |
| 3728 } | 3747 } |
| 3729 | 3748 |
| 3730 | 3749 |
| 3731 Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) { | 3750 Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) { |
| 3732 MigrateInstance(object); | 3751 Map* new_map = object->map()->CurrentMapForDeprecated(); |
| 3752 if (new_map == NULL) return Handle<Object>(); |
| 3753 Handle<Map> original_map(object->map()); |
| 3754 JSObject::MigrateToMap(object, handle(new_map)); |
| 3755 if (FLAG_trace_migration) { |
| 3756 object->PrintInstanceMigration(stdout, *original_map, object->map()); |
| 3757 } |
| 3733 return object; | 3758 return object; |
| 3734 } | 3759 } |
| 3735 | 3760 |
| 3736 | 3761 |
| 3737 Handle<Object> JSObject::SetPropertyUsingTransition( | 3762 Handle<Object> JSObject::SetPropertyUsingTransition( |
| 3738 Handle<JSObject> object, | 3763 Handle<JSObject> object, |
| 3739 LookupResult* lookup, | 3764 LookupResult* lookup, |
| 3740 Handle<Name> name, | 3765 Handle<Name> name, |
| 3741 Handle<Object> value, | 3766 Handle<Object> value, |
| 3742 PropertyAttributes attributes) { | 3767 PropertyAttributes attributes) { |
| (...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4341 if (pt->IsJSProxy()) { | 4366 if (pt->IsJSProxy()) { |
| 4342 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. | 4367 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. |
| 4343 return JSProxy::cast(pt)->GetElementAttributeWithHandler(receiver, index); | 4368 return JSProxy::cast(pt)->GetElementAttributeWithHandler(receiver, index); |
| 4344 } | 4369 } |
| 4345 if (pt->IsNull()) return ABSENT; | 4370 if (pt->IsNull()) return ABSENT; |
| 4346 return JSObject::cast(pt)->GetElementAttributeWithReceiver( | 4371 return JSObject::cast(pt)->GetElementAttributeWithReceiver( |
| 4347 receiver, index, true); | 4372 receiver, index, true); |
| 4348 } | 4373 } |
| 4349 | 4374 |
| 4350 | 4375 |
| 4351 MaybeObject* NormalizedMapCache::Get(JSObject* obj, | 4376 Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache, |
| 4352 PropertyNormalizationMode mode) { | 4377 Handle<JSObject> obj, |
| 4353 Isolate* isolate = obj->GetIsolate(); | 4378 PropertyNormalizationMode mode) { |
| 4354 Map* fast = obj->map(); | 4379 Map* fast = obj->map(); |
| 4355 int index = fast->Hash() % kEntries; | 4380 int index = fast->Hash() % kEntries; |
| 4356 Object* result = get(index); | 4381 Object* result = cache->get(index); |
| 4357 if (result->IsMap() && | 4382 if (result->IsMap() && |
| 4358 Map::cast(result)->EquivalentToForNormalization(fast, mode)) { | 4383 Map::cast(result)->EquivalentToForNormalization(fast, mode)) { |
| 4359 #ifdef VERIFY_HEAP | 4384 #ifdef VERIFY_HEAP |
| 4360 if (FLAG_verify_heap) { | 4385 if (FLAG_verify_heap) { |
| 4361 Map::cast(result)->SharedMapVerify(); | 4386 Map::cast(result)->SharedMapVerify(); |
| 4362 } | 4387 } |
| 4363 #endif | 4388 #endif |
| 4364 #ifdef DEBUG | 4389 #ifdef DEBUG |
| 4365 if (FLAG_enable_slow_asserts) { | 4390 if (FLAG_enable_slow_asserts) { |
| 4366 // The cached map should match newly created normalized map bit-by-bit, | 4391 // The cached map should match newly created normalized map bit-by-bit, |
| 4367 // except for the code cache, which can contain some ics which can be | 4392 // except for the code cache, which can contain some ics which can be |
| 4368 // applied to the shared map. | 4393 // applied to the shared map. |
| 4369 Object* fresh; | 4394 Object* fresh; |
| 4370 MaybeObject* maybe_fresh = | 4395 MaybeObject* maybe_fresh = |
| 4371 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); | 4396 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
| 4372 if (maybe_fresh->ToObject(&fresh)) { | 4397 if (maybe_fresh->ToObject(&fresh)) { |
| 4373 ASSERT(memcmp(Map::cast(fresh)->address(), | 4398 ASSERT(memcmp(Map::cast(fresh)->address(), |
| 4374 Map::cast(result)->address(), | 4399 Map::cast(result)->address(), |
| 4375 Map::kCodeCacheOffset) == 0); | 4400 Map::kCodeCacheOffset) == 0); |
| 4376 STATIC_ASSERT(Map::kDependentCodeOffset == | 4401 STATIC_ASSERT(Map::kDependentCodeOffset == |
| 4377 Map::kCodeCacheOffset + kPointerSize); | 4402 Map::kCodeCacheOffset + kPointerSize); |
| 4378 int offset = Map::kDependentCodeOffset + kPointerSize; | 4403 int offset = Map::kDependentCodeOffset + kPointerSize; |
| 4379 ASSERT(memcmp(Map::cast(fresh)->address() + offset, | 4404 ASSERT(memcmp(Map::cast(fresh)->address() + offset, |
| 4380 Map::cast(result)->address() + offset, | 4405 Map::cast(result)->address() + offset, |
| 4381 Map::kSize - offset) == 0); | 4406 Map::kSize - offset) == 0); |
| 4382 } | 4407 } |
| 4383 } | 4408 } |
| 4384 #endif | 4409 #endif |
| 4385 return result; | 4410 return handle(Map::cast(result)); |
| 4386 } | 4411 } |
| 4387 | 4412 |
| 4388 { MaybeObject* maybe_result = | 4413 Isolate* isolate = cache->GetIsolate(); |
| 4389 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); | 4414 Handle<Map> map = Map::CopyNormalized(handle(fast), mode, |
| 4390 if (!maybe_result->ToObject(&result)) return maybe_result; | 4415 SHARED_NORMALIZED_MAP); |
| 4391 } | 4416 ASSERT(map->is_dictionary_map()); |
| 4392 ASSERT(Map::cast(result)->is_dictionary_map()); | 4417 cache->set(index, *map); |
| 4393 set(index, result); | |
| 4394 isolate->counters()->normalized_maps()->Increment(); | 4418 isolate->counters()->normalized_maps()->Increment(); |
| 4395 | 4419 |
| 4396 return result; | 4420 return map; |
| 4397 } | 4421 } |
| 4398 | 4422 |
| 4399 | 4423 |
| 4400 void NormalizedMapCache::Clear() { | 4424 void NormalizedMapCache::Clear() { |
| 4401 int entries = length(); | 4425 int entries = length(); |
| 4402 for (int i = 0; i != entries; i++) { | 4426 for (int i = 0; i != entries; i++) { |
| 4403 set_undefined(i); | 4427 set_undefined(i); |
| 4404 } | 4428 } |
| 4405 } | 4429 } |
| 4406 | 4430 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4419 receiver->GetIsolate()->counters()->normalized_maps()->Increment(); | 4443 receiver->GetIsolate()->counters()->normalized_maps()->Increment(); |
| 4420 receiver->set_map(*map); | 4444 receiver->set_map(*map); |
| 4421 } | 4445 } |
| 4422 Map::UpdateCodeCache(map, name, code); | 4446 Map::UpdateCodeCache(map, name, code); |
| 4423 } | 4447 } |
| 4424 | 4448 |
| 4425 | 4449 |
| 4426 void JSObject::NormalizeProperties(Handle<JSObject> object, | 4450 void JSObject::NormalizeProperties(Handle<JSObject> object, |
| 4427 PropertyNormalizationMode mode, | 4451 PropertyNormalizationMode mode, |
| 4428 int expected_additional_properties) { | 4452 int expected_additional_properties) { |
| 4429 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), | 4453 if (!object->HasFastProperties()) return; |
| 4430 object->NormalizeProperties( | |
| 4431 mode, expected_additional_properties)); | |
| 4432 } | |
| 4433 | |
| 4434 | |
| 4435 MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, | |
| 4436 int expected_additional_properties) { | |
| 4437 if (!HasFastProperties()) return this; | |
| 4438 | 4454 |
| 4439 // The global object is always normalized. | 4455 // The global object is always normalized. |
| 4440 ASSERT(!IsGlobalObject()); | 4456 ASSERT(!object->IsGlobalObject()); |
| 4441 // JSGlobalProxy must never be normalized | 4457 // JSGlobalProxy must never be normalized |
| 4442 ASSERT(!IsJSGlobalProxy()); | 4458 ASSERT(!object->IsJSGlobalProxy()); |
| 4443 | 4459 |
| 4444 Map* map_of_this = map(); | 4460 Isolate* isolate = object->GetIsolate(); |
| 4461 HandleScope scope(isolate); |
| 4462 Handle<Map> map(object->map()); |
| 4445 | 4463 |
| 4446 // Allocate new content. | 4464 // Allocate new content. |
| 4447 int real_size = map_of_this->NumberOfOwnDescriptors(); | 4465 int real_size = map->NumberOfOwnDescriptors(); |
| 4448 int property_count = real_size; | 4466 int property_count = real_size; |
| 4449 if (expected_additional_properties > 0) { | 4467 if (expected_additional_properties > 0) { |
| 4450 property_count += expected_additional_properties; | 4468 property_count += expected_additional_properties; |
| 4451 } else { | 4469 } else { |
| 4452 property_count += 2; // Make space for two more properties. | 4470 property_count += 2; // Make space for two more properties. |
| 4453 } | 4471 } |
| 4454 NameDictionary* dictionary; | 4472 Handle<NameDictionary> dictionary = |
| 4455 MaybeObject* maybe_dictionary = | 4473 isolate->factory()->NewNameDictionary(property_count); |
| 4456 NameDictionary::Allocate(GetHeap(), property_count); | |
| 4457 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
| 4458 | 4474 |
| 4459 DescriptorArray* descs = map_of_this->instance_descriptors(); | 4475 Handle<DescriptorArray> descs(map->instance_descriptors()); |
| 4460 for (int i = 0; i < real_size; i++) { | 4476 for (int i = 0; i < real_size; i++) { |
| 4461 PropertyDetails details = descs->GetDetails(i); | 4477 PropertyDetails details = descs->GetDetails(i); |
| 4462 switch (details.type()) { | 4478 switch (details.type()) { |
| 4463 case CONSTANT: { | 4479 case CONSTANT: { |
| 4480 Handle<Name> key(descs->GetKey(i)); |
| 4481 Handle<Object> value(descs->GetConstant(i), isolate); |
| 4464 PropertyDetails d = PropertyDetails( | 4482 PropertyDetails d = PropertyDetails( |
| 4465 details.attributes(), NORMAL, i + 1); | 4483 details.attributes(), NORMAL, i + 1); |
| 4466 Object* value = descs->GetConstant(i); | 4484 dictionary = NameDictionaryAdd(dictionary, key, value, d); |
| 4467 MaybeObject* maybe_dictionary = | |
| 4468 dictionary->Add(descs->GetKey(i), value, d); | |
| 4469 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
| 4470 break; | 4485 break; |
| 4471 } | 4486 } |
| 4472 case FIELD: { | 4487 case FIELD: { |
| 4488 Handle<Name> key(descs->GetKey(i)); |
| 4489 Handle<Object> value( |
| 4490 object->RawFastPropertyAt(descs->GetFieldIndex(i)), isolate); |
| 4473 PropertyDetails d = | 4491 PropertyDetails d = |
| 4474 PropertyDetails(details.attributes(), NORMAL, i + 1); | 4492 PropertyDetails(details.attributes(), NORMAL, i + 1); |
| 4475 Object* value = RawFastPropertyAt(descs->GetFieldIndex(i)); | 4493 dictionary = NameDictionaryAdd(dictionary, key, value, d); |
| 4476 MaybeObject* maybe_dictionary = | |
| 4477 dictionary->Add(descs->GetKey(i), value, d); | |
| 4478 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
| 4479 break; | 4494 break; |
| 4480 } | 4495 } |
| 4481 case CALLBACKS: { | 4496 case CALLBACKS: { |
| 4482 Object* value = descs->GetCallbacksObject(i); | 4497 Handle<Name> key(descs->GetKey(i)); |
| 4498 Handle<Object> value(descs->GetCallbacksObject(i), isolate); |
| 4483 PropertyDetails d = PropertyDetails( | 4499 PropertyDetails d = PropertyDetails( |
| 4484 details.attributes(), CALLBACKS, i + 1); | 4500 details.attributes(), CALLBACKS, i + 1); |
| 4485 MaybeObject* maybe_dictionary = | 4501 dictionary = NameDictionaryAdd(dictionary, key, value, d); |
| 4486 dictionary->Add(descs->GetKey(i), value, d); | |
| 4487 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
| 4488 break; | 4502 break; |
| 4489 } | 4503 } |
| 4490 case INTERCEPTOR: | 4504 case INTERCEPTOR: |
| 4491 break; | 4505 break; |
| 4492 case HANDLER: | 4506 case HANDLER: |
| 4493 case NORMAL: | 4507 case NORMAL: |
| 4494 case TRANSITION: | 4508 case TRANSITION: |
| 4495 case NONEXISTENT: | 4509 case NONEXISTENT: |
| 4496 UNREACHABLE(); | 4510 UNREACHABLE(); |
| 4497 break; | 4511 break; |
| 4498 } | 4512 } |
| 4499 } | 4513 } |
| 4500 | 4514 |
| 4501 Heap* current_heap = GetHeap(); | |
| 4502 | |
| 4503 // Copy the next enumeration index from instance descriptor. | 4515 // Copy the next enumeration index from instance descriptor. |
| 4504 dictionary->SetNextEnumerationIndex(real_size + 1); | 4516 dictionary->SetNextEnumerationIndex(real_size + 1); |
| 4505 | 4517 |
| 4506 Map* new_map; | 4518 Handle<NormalizedMapCache> cache( |
| 4507 MaybeObject* maybe_map = | 4519 isolate->context()->native_context()->normalized_map_cache()); |
| 4508 current_heap->isolate()->context()->native_context()-> | 4520 Handle<Map> new_map = NormalizedMapCache::Get(cache, object, mode); |
| 4509 normalized_map_cache()->Get(this, mode); | |
| 4510 if (!maybe_map->To(&new_map)) return maybe_map; | |
| 4511 ASSERT(new_map->is_dictionary_map()); | 4521 ASSERT(new_map->is_dictionary_map()); |
| 4512 | 4522 |
| 4513 // We have now successfully allocated all the necessary objects. | 4523 // From here on we cannot fail and we shouldn't GC anymore. |
| 4514 // Changes can now be made with the guarantee that all of them take effect. | 4524 DisallowHeapAllocation no_allocation; |
| 4515 | 4525 |
| 4516 // Resize the object in the heap if necessary. | 4526 // Resize the object in the heap if necessary. |
| 4517 int new_instance_size = new_map->instance_size(); | 4527 int new_instance_size = new_map->instance_size(); |
| 4518 int instance_size_delta = map_of_this->instance_size() - new_instance_size; | 4528 int instance_size_delta = map->instance_size() - new_instance_size; |
| 4519 ASSERT(instance_size_delta >= 0); | 4529 ASSERT(instance_size_delta >= 0); |
| 4520 current_heap->CreateFillerObjectAt(this->address() + new_instance_size, | 4530 isolate->heap()->CreateFillerObjectAt(object->address() + new_instance_size, |
| 4521 instance_size_delta); | 4531 instance_size_delta); |
| 4522 if (Marking::IsBlack(Marking::MarkBitFrom(this))) { | 4532 if (Marking::IsBlack(Marking::MarkBitFrom(*object))) { |
| 4523 MemoryChunk::IncrementLiveBytesFromMutator(this->address(), | 4533 MemoryChunk::IncrementLiveBytesFromMutator(object->address(), |
| 4524 -instance_size_delta); | 4534 -instance_size_delta); |
| 4525 } | 4535 } |
| 4526 | 4536 |
| 4527 set_map(new_map); | 4537 object->set_map(*new_map); |
| 4528 map_of_this->NotifyLeafMapLayoutChange(); | 4538 map->NotifyLeafMapLayoutChange(); |
| 4529 | 4539 |
| 4530 set_properties(dictionary); | 4540 object->set_properties(*dictionary); |
| 4531 | 4541 |
| 4532 current_heap->isolate()->counters()->props_to_dictionary()->Increment(); | 4542 isolate->counters()->props_to_dictionary()->Increment(); |
| 4533 | 4543 |
| 4534 #ifdef DEBUG | 4544 #ifdef DEBUG |
| 4535 if (FLAG_trace_normalization) { | 4545 if (FLAG_trace_normalization) { |
| 4536 PrintF("Object properties have been normalized:\n"); | 4546 PrintF("Object properties have been normalized:\n"); |
| 4537 Print(); | 4547 object->Print(); |
| 4538 } | 4548 } |
| 4539 #endif | 4549 #endif |
| 4540 return this; | |
| 4541 } | 4550 } |
| 4542 | 4551 |
| 4543 | 4552 |
| 4544 void JSObject::TransformToFastProperties(Handle<JSObject> object, | 4553 void JSObject::TransformToFastProperties(Handle<JSObject> object, |
| 4545 int unused_property_fields) { | 4554 int unused_property_fields) { |
| 4555 if (object->HasFastProperties()) return; |
| 4556 ASSERT(!object->IsGlobalObject()); |
| 4546 CALL_HEAP_FUNCTION_VOID( | 4557 CALL_HEAP_FUNCTION_VOID( |
| 4547 object->GetIsolate(), | 4558 object->GetIsolate(), |
| 4548 object->TransformToFastProperties(unused_property_fields)); | 4559 object->property_dictionary()->TransformPropertiesToFastFor( |
| 4560 *object, unused_property_fields)); |
| 4549 } | 4561 } |
| 4550 | 4562 |
| 4551 | 4563 |
| 4552 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { | |
| 4553 if (HasFastProperties()) return this; | |
| 4554 ASSERT(!IsGlobalObject()); | |
| 4555 return property_dictionary()-> | |
| 4556 TransformPropertiesToFastFor(this, unused_property_fields); | |
| 4557 } | |
| 4558 | |
| 4559 | |
| 4560 static MUST_USE_RESULT MaybeObject* CopyFastElementsToDictionary( | 4564 static MUST_USE_RESULT MaybeObject* CopyFastElementsToDictionary( |
| 4561 Isolate* isolate, | 4565 Isolate* isolate, |
| 4562 FixedArrayBase* array, | 4566 FixedArrayBase* array, |
| 4563 int length, | 4567 int length, |
| 4564 SeededNumberDictionary* dictionary) { | 4568 SeededNumberDictionary* dictionary) { |
| 4565 Heap* heap = isolate->heap(); | 4569 Heap* heap = isolate->heap(); |
| 4566 bool has_double_elements = array->IsFixedDoubleArray(); | 4570 bool has_double_elements = array->IsFixedDoubleArray(); |
| 4567 for (int i = 0; i < length; i++) { | 4571 for (int i = 0; i < length; i++) { |
| 4568 Object* value = NULL; | 4572 Object* value = NULL; |
| 4569 if (has_double_elements) { | 4573 if (has_double_elements) { |
| (...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5336 return JSObject::cast(context->extension())->ReferencesObject(obj); | 5340 return JSObject::cast(context->extension())->ReferencesObject(obj); |
| 5337 } | 5341 } |
| 5338 } | 5342 } |
| 5339 | 5343 |
| 5340 // No references to object. | 5344 // No references to object. |
| 5341 return false; | 5345 return false; |
| 5342 } | 5346 } |
| 5343 | 5347 |
| 5344 | 5348 |
| 5345 Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) { | 5349 Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) { |
| 5346 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object); | 5350 Isolate* isolate = object->GetIsolate(); |
| 5347 } | 5351 if (object->IsAccessCheckNeeded() && |
| 5348 | 5352 !isolate->MayNamedAccess(*object, |
| 5349 | |
| 5350 MaybeObject* JSObject::PreventExtensions() { | |
| 5351 Isolate* isolate = GetIsolate(); | |
| 5352 if (IsAccessCheckNeeded() && | |
| 5353 !isolate->MayNamedAccess(this, | |
| 5354 isolate->heap()->undefined_value(), | 5353 isolate->heap()->undefined_value(), |
| 5355 v8::ACCESS_KEYS)) { | 5354 v8::ACCESS_KEYS)) { |
| 5356 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); | 5355 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); |
| 5357 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 5356 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); |
| 5358 return isolate->heap()->false_value(); | 5357 return isolate->factory()->false_value(); |
| 5359 } | 5358 } |
| 5360 | 5359 |
| 5361 if (IsJSGlobalProxy()) { | 5360 if (object->IsJSGlobalProxy()) { |
| 5362 Object* proto = GetPrototype(); | 5361 Handle<Object> proto(object->GetPrototype(), isolate); |
| 5363 if (proto->IsNull()) return this; | 5362 if (proto->IsNull()) return object; |
| 5364 ASSERT(proto->IsJSGlobalObject()); | 5363 ASSERT(proto->IsJSGlobalObject()); |
| 5365 return JSObject::cast(proto)->PreventExtensions(); | 5364 return PreventExtensions(Handle<JSObject>::cast(proto)); |
| 5366 } | 5365 } |
| 5367 | 5366 |
| 5368 // It's not possible to seal objects with external array elements | 5367 // It's not possible to seal objects with external array elements |
| 5369 if (HasExternalArrayElements()) { | 5368 if (object->HasExternalArrayElements()) { |
| 5370 HandleScope scope(isolate); | |
| 5371 Handle<Object> object(this, isolate); | |
| 5372 Handle<Object> error = | 5369 Handle<Object> error = |
| 5373 isolate->factory()->NewTypeError( | 5370 isolate->factory()->NewTypeError( |
| 5374 "cant_prevent_ext_external_array_elements", | 5371 "cant_prevent_ext_external_array_elements", |
| 5375 HandleVector(&object, 1)); | 5372 HandleVector(&object, 1)); |
| 5376 return isolate->Throw(*error); | 5373 isolate->Throw(*error); |
| 5374 return Handle<Object>(); |
| 5377 } | 5375 } |
| 5378 | 5376 |
| 5379 // If there are fast elements we normalize. | 5377 // If there are fast elements we normalize. |
| 5380 SeededNumberDictionary* dictionary = NULL; | 5378 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); |
| 5381 { MaybeObject* maybe = NormalizeElements(); | 5379 ASSERT(object->HasDictionaryElements() || |
| 5382 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe; | 5380 object->HasDictionaryArgumentsElements()); |
| 5383 } | 5381 |
| 5384 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | |
| 5385 // Make sure that we never go back to fast case. | 5382 // Make sure that we never go back to fast case. |
| 5386 dictionary->set_requires_slow_elements(); | 5383 dictionary->set_requires_slow_elements(); |
| 5387 | 5384 |
| 5388 // Do a map transition, other objects with this map may still | 5385 // Do a map transition, other objects with this map may still |
| 5389 // be extensible. | 5386 // be extensible. |
| 5390 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. | 5387 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. |
| 5391 Map* new_map; | 5388 Handle<Map> new_map = Map::Copy(handle(object->map())); |
| 5392 MaybeObject* maybe = map()->Copy(); | |
| 5393 if (!maybe->To(&new_map)) return maybe; | |
| 5394 | 5389 |
| 5395 new_map->set_is_extensible(false); | 5390 new_map->set_is_extensible(false); |
| 5396 set_map(new_map); | 5391 object->set_map(*new_map); |
| 5397 ASSERT(!map()->is_extensible()); | 5392 ASSERT(!object->map()->is_extensible()); |
| 5398 return new_map; | 5393 return object; |
| 5399 } | 5394 } |
| 5400 | 5395 |
| 5401 | 5396 |
| 5402 template<typename Dictionary> | 5397 template<typename Dictionary> |
| 5403 static void FreezeDictionary(Dictionary* dictionary) { | 5398 static void FreezeDictionary(Dictionary* dictionary) { |
| 5404 int capacity = dictionary->Capacity(); | 5399 int capacity = dictionary->Capacity(); |
| 5405 for (int i = 0; i < capacity; i++) { | 5400 for (int i = 0; i < capacity; i++) { |
| 5406 Object* k = dictionary->KeyAt(i); | 5401 Object* k = dictionary->KeyAt(i); |
| 5407 if (dictionary->IsKey(k)) { | 5402 if (dictionary->IsKey(k)) { |
| 5408 PropertyDetails details = dictionary->DetailsAt(i); | 5403 PropertyDetails details = dictionary->DetailsAt(i); |
| (...skipping 7022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12431 } | 12426 } |
| 12432 } | 12427 } |
| 12433 } | 12428 } |
| 12434 // All possible cases have been handled above. Add a return to avoid the | 12429 // All possible cases have been handled above. Add a return to avoid the |
| 12435 // complaints from the compiler. | 12430 // complaints from the compiler. |
| 12436 UNREACHABLE(); | 12431 UNREACHABLE(); |
| 12437 return isolate->heap()->null_value(); | 12432 return isolate->heap()->null_value(); |
| 12438 } | 12433 } |
| 12439 | 12434 |
| 12440 | 12435 |
| 12441 Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object, | 12436 void JSObject::TransitionElementsKind(Handle<JSObject> object, |
| 12442 ElementsKind to_kind) { | 12437 ElementsKind to_kind) { |
| 12443 CALL_HEAP_FUNCTION(object->GetIsolate(), | 12438 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), |
| 12444 object->TransitionElementsKind(to_kind), | 12439 object->TransitionElementsKind(to_kind)); |
| 12445 Object); | |
| 12446 } | 12440 } |
| 12447 | 12441 |
| 12448 | 12442 |
| 12449 MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { | 12443 MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { |
| 12450 if (!FLAG_track_allocation_sites || !IsJSArray()) { | 12444 if (!FLAG_track_allocation_sites || !IsJSArray()) { |
| 12451 return this; | 12445 return this; |
| 12452 } | 12446 } |
| 12453 | 12447 |
| 12454 AllocationMemento* memento = AllocationMemento::FindForJSObject(this); | 12448 AllocationMemento* memento = AllocationMemento::FindForJSObject(this); |
| 12455 if (memento == NULL || !memento->IsValid()) { | 12449 if (memento == NULL || !memento->IsValid()) { |
| (...skipping 3652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16108 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16102 #define ERROR_MESSAGES_TEXTS(C, T) T, |
| 16109 static const char* error_messages_[] = { | 16103 static const char* error_messages_[] = { |
| 16110 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16104 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
| 16111 }; | 16105 }; |
| 16112 #undef ERROR_MESSAGES_TEXTS | 16106 #undef ERROR_MESSAGES_TEXTS |
| 16113 return error_messages_[reason]; | 16107 return error_messages_[reason]; |
| 16114 } | 16108 } |
| 16115 | 16109 |
| 16116 | 16110 |
| 16117 } } // namespace v8::internal | 16111 } } // namespace v8::internal |
| OLD | NEW |