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 1957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1968 static Handle<Object> NewStorageFor(Isolate* isolate, | 1968 static Handle<Object> NewStorageFor(Isolate* isolate, |
1969 Handle<Object> object, | 1969 Handle<Object> object, |
1970 Representation representation) { | 1970 Representation representation) { |
1971 Heap* heap = isolate->heap(); | 1971 Heap* heap = isolate->heap(); |
1972 CALL_HEAP_FUNCTION(isolate, | 1972 CALL_HEAP_FUNCTION(isolate, |
1973 object->AllocateNewStorageFor(heap, representation), | 1973 object->AllocateNewStorageFor(heap, representation), |
1974 Object); | 1974 Object); |
1975 } | 1975 } |
1976 | 1976 |
1977 | 1977 |
1978 void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object, | |
1979 Handle<Map> new_map, | |
1980 Handle<Name> name, | |
1981 Handle<Object> value, | |
1982 int field_index, | |
1983 Representation representation) { | |
1984 Isolate* isolate = object->GetIsolate(); | |
1985 | |
1986 // This method is used to transition to a field. If we are transitioning to a | |
1987 // double field, allocate new storage. | |
1988 Handle<Object> storage = NewStorageFor(isolate, value, representation); | |
1989 | |
1990 if (object->map()->unused_property_fields() == 0) { | |
1991 int new_unused = new_map->unused_property_fields(); | |
1992 Handle<FixedArray> properties(object->properties()); | |
1993 Handle<FixedArray> values = isolate->factory()->CopySizeFixedArray( | |
1994 properties, properties->length() + new_unused + 1); | |
1995 object->set_properties(*values); | |
1996 } | |
1997 | |
1998 object->set_map(*new_map); | |
1999 object->FastPropertyAtPut(field_index, *storage); | |
2000 } | |
2001 | |
2002 | |
2003 static MaybeObject* CopyAddFieldDescriptor(Map* map, | 1978 static MaybeObject* CopyAddFieldDescriptor(Map* map, |
2004 Name* name, | 1979 Name* name, |
2005 int index, | 1980 int index, |
2006 PropertyAttributes attributes, | 1981 PropertyAttributes attributes, |
2007 Representation representation, | 1982 Representation representation, |
2008 TransitionFlag flag) { | 1983 TransitionFlag flag) { |
2009 Map* new_map; | 1984 Map* new_map; |
2010 FieldDescriptor new_field_desc(name, index, attributes, representation); | 1985 FieldDescriptor new_field_desc(name, index, attributes, representation); |
2011 MaybeObject* maybe_map = map->CopyAddDescriptor(&new_field_desc, flag); | 1986 MaybeObject* maybe_map = map->CopyAddDescriptor(&new_field_desc, flag); |
2012 if (!maybe_map->To(&new_map)) return maybe_map; | 1987 if (!maybe_map->To(&new_map)) return maybe_map; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2057 | 2032 |
2058 // Compute the new index for new field. | 2033 // Compute the new index for new field. |
2059 int index = object->map()->NextFreePropertyIndex(); | 2034 int index = object->map()->NextFreePropertyIndex(); |
2060 | 2035 |
2061 // Allocate new instance descriptors with (name, index) added | 2036 // Allocate new instance descriptors with (name, index) added |
2062 if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED; | 2037 if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED; |
2063 Representation representation = value->OptimalRepresentation(value_type); | 2038 Representation representation = value->OptimalRepresentation(value_type); |
2064 Handle<Map> new_map = CopyAddFieldDescriptor( | 2039 Handle<Map> new_map = CopyAddFieldDescriptor( |
2065 handle(object->map()), name, index, attributes, representation, flag); | 2040 handle(object->map()), name, index, attributes, representation, flag); |
2066 | 2041 |
2067 AddFastPropertyUsingMap(object, new_map, name, value, index, representation); | 2042 JSObject::MigrateToMap(object, new_map); |
| 2043 |
| 2044 if (representation.IsDouble()) { |
| 2045 // Nothing more to be done. |
| 2046 if (value->IsUninitialized()) return; |
| 2047 HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(index)); |
| 2048 box->set_value(value->Number()); |
| 2049 } else { |
| 2050 object->FastPropertyAtPut(index, *value); |
| 2051 } |
2068 } | 2052 } |
2069 | 2053 |
2070 | 2054 |
2071 static MaybeObject* CopyAddConstantDescriptor(Map* map, | 2055 static MaybeObject* CopyAddConstantDescriptor(Map* map, |
2072 Name* name, | 2056 Name* name, |
2073 Object* value, | 2057 Object* value, |
2074 PropertyAttributes attributes, | 2058 PropertyAttributes attributes, |
2075 TransitionFlag flag) { | 2059 TransitionFlag flag) { |
2076 ConstantDescriptor new_constant_desc(name, value, attributes); | 2060 ConstantDescriptor new_constant_desc(name, value, attributes); |
2077 return map->CopyAddDescriptor(&new_constant_desc, flag); | 2061 return map->CopyAddDescriptor(&new_constant_desc, flag); |
(...skipping 23 matching lines...) Expand all Loading... |
2101 // Don't add transitions to special properties with non-trivial | 2085 // Don't add transitions to special properties with non-trivial |
2102 // attributes. | 2086 // attributes. |
2103 attributes != NONE) | 2087 attributes != NONE) |
2104 ? OMIT_TRANSITION | 2088 ? OMIT_TRANSITION |
2105 : initial_flag; | 2089 : initial_flag; |
2106 | 2090 |
2107 // Allocate new instance descriptors with (name, constant) added. | 2091 // Allocate new instance descriptors with (name, constant) added. |
2108 Handle<Map> new_map = CopyAddConstantDescriptor( | 2092 Handle<Map> new_map = CopyAddConstantDescriptor( |
2109 handle(object->map()), name, constant, attributes, flag); | 2093 handle(object->map()), name, constant, attributes, flag); |
2110 | 2094 |
2111 object->set_map(*new_map); | 2095 JSObject::MigrateToMap(object, new_map); |
2112 } | 2096 } |
2113 | 2097 |
2114 | 2098 |
2115 void JSObject::AddSlowProperty(Handle<JSObject> object, | 2099 void JSObject::AddSlowProperty(Handle<JSObject> object, |
2116 Handle<Name> name, | 2100 Handle<Name> name, |
2117 Handle<Object> value, | 2101 Handle<Object> value, |
2118 PropertyAttributes attributes) { | 2102 PropertyAttributes attributes) { |
2119 ASSERT(!object->HasFastProperties()); | 2103 ASSERT(!object->HasFastProperties()); |
2120 Isolate* isolate = object->GetIsolate(); | 2104 Isolate* isolate = object->GetIsolate(); |
2121 Handle<NameDictionary> dict(object->property_dictionary()); | 2105 Handle<NameDictionary> dict(object->property_dictionary()); |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2411 object->set_map(*new_map); | 2395 object->set_map(*new_map); |
2412 return; | 2396 return; |
2413 } | 2397 } |
2414 | 2398 |
2415 int total_size = number_of_fields + unused; | 2399 int total_size = number_of_fields + unused; |
2416 int external = total_size - inobject; | 2400 int external = total_size - inobject; |
2417 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); | 2401 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); |
2418 | 2402 |
2419 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); | 2403 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); |
2420 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); | 2404 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); |
2421 int descriptors = new_map->NumberOfOwnDescriptors(); | 2405 int old_nof = old_map->NumberOfOwnDescriptors(); |
| 2406 int new_nof = new_map->NumberOfOwnDescriptors(); |
2422 | 2407 |
2423 for (int i = 0; i < descriptors; i++) { | 2408 // This method only supports generalizing instances to at least the same |
| 2409 // number of properties. |
| 2410 ASSERT(old_nof <= new_nof); |
| 2411 |
| 2412 for (int i = 0; i < old_nof; i++) { |
2424 PropertyDetails details = new_descriptors->GetDetails(i); | 2413 PropertyDetails details = new_descriptors->GetDetails(i); |
2425 if (details.type() != FIELD) continue; | 2414 if (details.type() != FIELD) continue; |
2426 PropertyDetails old_details = old_descriptors->GetDetails(i); | 2415 PropertyDetails old_details = old_descriptors->GetDetails(i); |
2427 if (old_details.type() == CALLBACKS) { | 2416 if (old_details.type() == CALLBACKS) { |
2428 ASSERT(details.representation().IsTagged()); | 2417 ASSERT(details.representation().IsTagged()); |
2429 continue; | 2418 continue; |
2430 } | 2419 } |
2431 ASSERT(old_details.type() == CONSTANT || | 2420 ASSERT(old_details.type() == CONSTANT || |
2432 old_details.type() == FIELD); | 2421 old_details.type() == FIELD); |
2433 Object* raw_value = old_details.type() == CONSTANT | 2422 Object* raw_value = old_details.type() == CONSTANT |
2434 ? old_descriptors->GetValue(i) | 2423 ? old_descriptors->GetValue(i) |
2435 : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); | 2424 : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); |
2436 Handle<Object> value(raw_value, isolate); | 2425 Handle<Object> value(raw_value, isolate); |
2437 if (!old_details.representation().IsDouble() && | 2426 if (!old_details.representation().IsDouble() && |
2438 details.representation().IsDouble()) { | 2427 details.representation().IsDouble()) { |
2439 if (old_details.representation().IsNone()) { | 2428 if (old_details.representation().IsNone()) { |
2440 value = handle(Smi::FromInt(0), isolate); | 2429 value = handle(Smi::FromInt(0), isolate); |
2441 } | 2430 } |
2442 value = NewStorageFor(isolate, value, details.representation()); | 2431 value = NewStorageFor(isolate, value, details.representation()); |
2443 } | 2432 } |
2444 ASSERT(!(details.representation().IsDouble() && value->IsSmi())); | 2433 ASSERT(!(details.representation().IsDouble() && value->IsSmi())); |
2445 int target_index = new_descriptors->GetFieldIndex(i) - inobject; | 2434 int target_index = new_descriptors->GetFieldIndex(i) - inobject; |
2446 if (target_index < 0) target_index += total_size; | 2435 if (target_index < 0) target_index += total_size; |
2447 array->set(target_index, *value); | 2436 array->set(target_index, *value); |
2448 } | 2437 } |
2449 | 2438 |
| 2439 for (int i = old_nof; i < new_nof; i++) { |
| 2440 PropertyDetails details = new_descriptors->GetDetails(i); |
| 2441 if (details.type() != FIELD) continue; |
| 2442 if (details.representation().IsDouble()) { |
| 2443 int target_index = new_descriptors->GetFieldIndex(i) - inobject; |
| 2444 if (target_index < 0) target_index += total_size; |
| 2445 Handle<Object> box = isolate->factory()->NewHeapNumber(0); |
| 2446 array->set(target_index, *box); |
| 2447 } |
| 2448 } |
| 2449 |
2450 // From here on we cannot fail and we shouldn't GC anymore. | 2450 // From here on we cannot fail and we shouldn't GC anymore. |
2451 DisallowHeapAllocation no_allocation; | 2451 DisallowHeapAllocation no_allocation; |
2452 | 2452 |
2453 // Copy (real) inobject properties. If necessary, stop at number_of_fields to | 2453 // Copy (real) inobject properties. If necessary, stop at number_of_fields to |
2454 // avoid overwriting |one_pointer_filler_map|. | 2454 // avoid overwriting |one_pointer_filler_map|. |
2455 int limit = Min(inobject, number_of_fields); | 2455 int limit = Min(inobject, number_of_fields); |
2456 for (int i = 0; i < limit; i++) { | 2456 for (int i = 0; i < limit; i++) { |
2457 object->FastPropertyAtPut(i, array->get(external + i)); | 2457 object->FastPropertyAtPut(i, array->get(external + i)); |
2458 } | 2458 } |
2459 | 2459 |
(...skipping 1392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3852 IsDictionaryElementsKind(obj_kind)) { | 3852 IsDictionaryElementsKind(obj_kind)) { |
3853 to_kind = obj_kind; | 3853 to_kind = obj_kind; |
3854 } | 3854 } |
3855 if (IsDictionaryElementsKind(to_kind)) { | 3855 if (IsDictionaryElementsKind(to_kind)) { |
3856 NormalizeElements(object); | 3856 NormalizeElements(object); |
3857 } else { | 3857 } else { |
3858 TransitionElementsKind(object, to_kind); | 3858 TransitionElementsKind(object, to_kind); |
3859 } | 3859 } |
3860 map = MapAsElementsKind(map, to_kind); | 3860 map = MapAsElementsKind(map, to_kind); |
3861 } | 3861 } |
3862 int total_size = | 3862 JSObject::MigrateToMap(object, map); |
3863 map->NumberOfOwnDescriptors() + map->unused_property_fields(); | |
3864 int out_of_object = total_size - map->inobject_properties(); | |
3865 if (out_of_object != object->properties()->length()) { | |
3866 Isolate* isolate = object->GetIsolate(); | |
3867 Handle<FixedArray> new_properties = isolate->factory()->CopySizeFixedArray( | |
3868 handle(object->properties()), out_of_object); | |
3869 object->set_properties(*new_properties); | |
3870 } | |
3871 object->set_map(*map); | |
3872 } | 3863 } |
3873 | 3864 |
3874 | 3865 |
3875 void JSObject::MigrateInstance(Handle<JSObject> object) { | 3866 void JSObject::MigrateInstance(Handle<JSObject> object) { |
3876 // Converting any field to the most specific type will cause the | 3867 // Converting any field to the most specific type will cause the |
3877 // GeneralizeFieldRepresentation algorithm to create the most general existing | 3868 // GeneralizeFieldRepresentation algorithm to create the most general existing |
3878 // transition that matches the object. This achieves what is needed. | 3869 // transition that matches the object. This achieves what is needed. |
3879 Handle<Map> original_map(object->map()); | 3870 Handle<Map> original_map(object->map()); |
3880 GeneralizeFieldRepresentation( | 3871 GeneralizeFieldRepresentation( |
3881 object, 0, Representation::None(), ALLOW_AS_CONSTANT); | 3872 object, 0, Representation::None(), ALLOW_AS_CONSTANT); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3917 return JSObject::AddProperty( | 3908 return JSObject::AddProperty( |
3918 object, name, value, attributes, kNonStrictMode, | 3909 object, name, value, attributes, kNonStrictMode, |
3919 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED, | 3910 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED, |
3920 JSReceiver::OMIT_EXTENSIBILITY_CHECK, | 3911 JSReceiver::OMIT_EXTENSIBILITY_CHECK, |
3921 JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION); | 3912 JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION); |
3922 } | 3913 } |
3923 | 3914 |
3924 // Keep the target CONSTANT if the same value is stored. | 3915 // Keep the target CONSTANT if the same value is stored. |
3925 // TODO(verwaest): Also support keeping the placeholder | 3916 // TODO(verwaest): Also support keeping the placeholder |
3926 // (value->IsUninitialized) as constant. | 3917 // (value->IsUninitialized) as constant. |
3927 if (details.type() == CONSTANT && | 3918 if (!value->FitsRepresentation(details.representation()) || |
3928 descriptors->GetValue(descriptor) == *value) { | 3919 (details.type() == CONSTANT && |
3929 object->set_map(*transition_map); | 3920 descriptors->GetValue(descriptor) != *value)) { |
3930 return value; | 3921 transition_map = Map::GeneralizeRepresentation(transition_map, |
| 3922 descriptor, value->OptimalRepresentation(), FORCE_FIELD); |
3931 } | 3923 } |
3932 | 3924 |
3933 Representation representation = details.representation(); | 3925 JSObject::MigrateToMap(object, transition_map); |
3934 | 3926 |
3935 if (!value->FitsRepresentation(representation) || | 3927 // Reload. |
3936 details.type() == CONSTANT) { | 3928 descriptors = transition_map->instance_descriptors(); |
3937 transition_map = Map::GeneralizeRepresentation(transition_map, | 3929 details = descriptors->GetDetails(descriptor); |
3938 descriptor, value->OptimalRepresentation(), FORCE_FIELD); | 3930 |
3939 Object* back = transition_map->GetBackPointer(); | 3931 if (details.type() != FIELD) return value; |
3940 if (back->IsMap()) { | 3932 |
3941 MigrateToMap(object, handle(Map::cast(back))); | 3933 int field_index = descriptors->GetFieldIndex(descriptor); |
3942 } | 3934 if (details.representation().IsDouble()) { |
3943 descriptors = transition_map->instance_descriptors(); | 3935 // Nothing more to be done. |
3944 representation = descriptors->GetDetails(descriptor).representation(); | 3936 if (value->IsUninitialized()) return value; |
| 3937 HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(field_index)); |
| 3938 box->set_value(value->Number()); |
| 3939 } else { |
| 3940 object->FastPropertyAtPut(field_index, *value); |
3945 } | 3941 } |
3946 | 3942 |
3947 int field_index = descriptors->GetFieldIndex(descriptor); | |
3948 AddFastPropertyUsingMap( | |
3949 object, transition_map, name, value, field_index, representation); | |
3950 return value; | 3943 return value; |
3951 } | 3944 } |
3952 | 3945 |
3953 | 3946 |
3954 static void SetPropertyToField(LookupResult* lookup, | 3947 static void SetPropertyToField(LookupResult* lookup, |
3955 Handle<Name> name, | 3948 Handle<Name> name, |
3956 Handle<Object> value) { | 3949 Handle<Object> value) { |
3957 Representation representation = lookup->representation(); | 3950 Representation representation = lookup->representation(); |
3958 if (!value->FitsRepresentation(representation) || | 3951 if (!value->FitsRepresentation(representation) || |
3959 lookup->type() == CONSTANT) { | 3952 lookup->type() == CONSTANT) { |
(...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4761 // Switch to using the dictionary as the backing storage for elements. | 4754 // Switch to using the dictionary as the backing storage for elements. |
4762 if (is_arguments) { | 4755 if (is_arguments) { |
4763 FixedArray::cast(elements())->set(1, dictionary); | 4756 FixedArray::cast(elements())->set(1, dictionary); |
4764 } else { | 4757 } else { |
4765 // Set the new map first to satify the elements type assert in | 4758 // Set the new map first to satify the elements type assert in |
4766 // set_elements(). | 4759 // set_elements(). |
4767 Map* new_map; | 4760 Map* new_map; |
4768 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), | 4761 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), |
4769 DICTIONARY_ELEMENTS); | 4762 DICTIONARY_ELEMENTS); |
4770 if (!maybe->To(&new_map)) return maybe; | 4763 if (!maybe->To(&new_map)) return maybe; |
| 4764 // TODO(verwaest): Replace by MigrateToMap. |
4771 set_map(new_map); | 4765 set_map(new_map); |
4772 set_elements(dictionary); | 4766 set_elements(dictionary); |
4773 } | 4767 } |
4774 | 4768 |
4775 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()-> | 4769 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()-> |
4776 Increment(); | 4770 Increment(); |
4777 | 4771 |
4778 #ifdef DEBUG | 4772 #ifdef DEBUG |
4779 if (FLAG_trace_normalization) { | 4773 if (FLAG_trace_normalization) { |
4780 PrintF("Object elements have been normalized:\n"); | 4774 PrintF("Object elements have been normalized:\n"); |
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5489 | 5483 |
5490 // Make sure that we never go back to fast case. | 5484 // Make sure that we never go back to fast case. |
5491 dictionary->set_requires_slow_elements(); | 5485 dictionary->set_requires_slow_elements(); |
5492 | 5486 |
5493 // Do a map transition, other objects with this map may still | 5487 // Do a map transition, other objects with this map may still |
5494 // be extensible. | 5488 // be extensible. |
5495 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. | 5489 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. |
5496 Handle<Map> new_map = Map::Copy(handle(object->map())); | 5490 Handle<Map> new_map = Map::Copy(handle(object->map())); |
5497 | 5491 |
5498 new_map->set_is_extensible(false); | 5492 new_map->set_is_extensible(false); |
5499 object->set_map(*new_map); | 5493 JSObject::MigrateToMap(object, new_map); |
5500 ASSERT(!object->map()->is_extensible()); | 5494 ASSERT(!object->map()->is_extensible()); |
5501 | 5495 |
5502 if (object->map()->is_observed()) { | 5496 if (object->map()->is_observed()) { |
5503 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(), | 5497 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(), |
5504 isolate->factory()->the_hole_value()); | 5498 isolate->factory()->the_hole_value()); |
5505 } | 5499 } |
5506 return object; | 5500 return object; |
5507 } | 5501 } |
5508 | 5502 |
5509 | 5503 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5582 // No existing elements, use a pre-allocated empty backing store | 5576 // No existing elements, use a pre-allocated empty backing store |
5583 new_element_dictionary = | 5577 new_element_dictionary = |
5584 isolate->factory()->empty_slow_element_dictionary(); | 5578 isolate->factory()->empty_slow_element_dictionary(); |
5585 } | 5579 } |
5586 } | 5580 } |
5587 | 5581 |
5588 LookupResult result(isolate); | 5582 LookupResult result(isolate); |
5589 Handle<Map> old_map(object->map()); | 5583 Handle<Map> old_map(object->map()); |
5590 old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result); | 5584 old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result); |
5591 if (result.IsTransition()) { | 5585 if (result.IsTransition()) { |
5592 Map* transition_map = result.GetTransitionTarget(); | 5586 Handle<Map> transition_map(result.GetTransitionTarget()); |
5593 ASSERT(transition_map->has_dictionary_elements()); | 5587 ASSERT(transition_map->has_dictionary_elements()); |
5594 ASSERT(transition_map->is_frozen()); | 5588 ASSERT(transition_map->is_frozen()); |
5595 ASSERT(!transition_map->is_extensible()); | 5589 ASSERT(!transition_map->is_extensible()); |
5596 object->set_map(transition_map); | 5590 JSObject::MigrateToMap(object, transition_map); |
5597 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) { | 5591 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) { |
5598 // Create a new descriptor array with fully-frozen properties | 5592 // Create a new descriptor array with fully-frozen properties |
5599 int num_descriptors = old_map->NumberOfOwnDescriptors(); | 5593 int num_descriptors = old_map->NumberOfOwnDescriptors(); |
5600 Handle<DescriptorArray> new_descriptors = | 5594 Handle<DescriptorArray> new_descriptors = |
5601 DescriptorArray::CopyUpToAddAttributes( | 5595 DescriptorArray::CopyUpToAddAttributes( |
5602 handle(old_map->instance_descriptors()), num_descriptors, FROZEN); | 5596 handle(old_map->instance_descriptors()), num_descriptors, FROZEN); |
5603 Handle<Map> new_map = Map::CopyReplaceDescriptors( | 5597 Handle<Map> new_map = Map::CopyReplaceDescriptors( |
5604 old_map, new_descriptors, INSERT_TRANSITION, | 5598 old_map, new_descriptors, INSERT_TRANSITION, |
5605 isolate->factory()->frozen_symbol()); | 5599 isolate->factory()->frozen_symbol()); |
5606 new_map->freeze(); | 5600 new_map->freeze(); |
5607 new_map->set_is_extensible(false); | 5601 new_map->set_is_extensible(false); |
5608 new_map->set_elements_kind(DICTIONARY_ELEMENTS); | 5602 new_map->set_elements_kind(DICTIONARY_ELEMENTS); |
5609 object->set_map(*new_map); | 5603 JSObject::MigrateToMap(object, new_map); |
5610 } else { | 5604 } else { |
5611 // Slow path: need to normalize properties for safety | 5605 // Slow path: need to normalize properties for safety |
5612 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); | 5606 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); |
5613 | 5607 |
5614 // Create a new map, since other objects with this map may be extensible. | 5608 // Create a new map, since other objects with this map may be extensible. |
5615 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. | 5609 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. |
5616 Handle<Map> new_map = Map::Copy(handle(object->map())); | 5610 Handle<Map> new_map = Map::Copy(handle(object->map())); |
5617 new_map->freeze(); | 5611 new_map->freeze(); |
5618 new_map->set_is_extensible(false); | 5612 new_map->set_is_extensible(false); |
5619 new_map->set_elements_kind(DICTIONARY_ELEMENTS); | 5613 new_map->set_elements_kind(DICTIONARY_ELEMENTS); |
5620 object->set_map(*new_map); | 5614 JSObject::MigrateToMap(object, new_map); |
5621 | 5615 |
5622 // Freeze dictionary-mode properties | 5616 // Freeze dictionary-mode properties |
5623 FreezeDictionary(object->property_dictionary()); | 5617 FreezeDictionary(object->property_dictionary()); |
5624 } | 5618 } |
5625 | 5619 |
5626 ASSERT(object->map()->has_dictionary_elements()); | 5620 ASSERT(object->map()->has_dictionary_elements()); |
5627 if (!new_element_dictionary.is_null()) { | 5621 if (!new_element_dictionary.is_null()) { |
5628 object->set_elements(*new_element_dictionary); | 5622 object->set_elements(*new_element_dictionary); |
5629 } | 5623 } |
5630 | 5624 |
(...skipping 23 matching lines...) Expand all Loading... |
5654 Handle<Map> new_map; | 5648 Handle<Map> new_map; |
5655 if (result.IsTransition()) { | 5649 if (result.IsTransition()) { |
5656 new_map = handle(result.GetTransitionTarget()); | 5650 new_map = handle(result.GetTransitionTarget()); |
5657 ASSERT(new_map->is_observed()); | 5651 ASSERT(new_map->is_observed()); |
5658 } else if (object->map()->CanHaveMoreTransitions()) { | 5652 } else if (object->map()->CanHaveMoreTransitions()) { |
5659 new_map = Map::CopyForObserved(handle(object->map())); | 5653 new_map = Map::CopyForObserved(handle(object->map())); |
5660 } else { | 5654 } else { |
5661 new_map = Map::Copy(handle(object->map())); | 5655 new_map = Map::Copy(handle(object->map())); |
5662 new_map->set_is_observed(); | 5656 new_map->set_is_observed(); |
5663 } | 5657 } |
5664 object->set_map(*new_map); | 5658 JSObject::MigrateToMap(object, new_map); |
5665 } | 5659 } |
5666 | 5660 |
5667 | 5661 |
5668 Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { | 5662 Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { |
5669 Isolate* isolate = object->GetIsolate(); | 5663 Isolate* isolate = object->GetIsolate(); |
5670 CALL_HEAP_FUNCTION(isolate, | 5664 CALL_HEAP_FUNCTION(isolate, |
5671 isolate->heap()->CopyJSObject(*object), JSObject); | 5665 isolate->heap()->CopyJSObject(*object), JSObject); |
5672 } | 5666 } |
5673 | 5667 |
5674 | 5668 |
(...skipping 709 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6384 object, name, getter, setter, attributes, access_control); | 6378 object, name, getter, setter, attributes, access_control); |
6385 } | 6379 } |
6386 | 6380 |
6387 if (is_observed) { | 6381 if (is_observed) { |
6388 const char* type = preexists ? "reconfigure" : "add"; | 6382 const char* type = preexists ? "reconfigure" : "add"; |
6389 EnqueueChangeRecord(object, type, name, old_value); | 6383 EnqueueChangeRecord(object, type, name, old_value); |
6390 } | 6384 } |
6391 } | 6385 } |
6392 | 6386 |
6393 | 6387 |
6394 static bool TryAccessorTransition(JSObject* self, | 6388 static bool TryAccessorTransition(Handle<JSObject> self, |
6395 Map* transitioned_map, | 6389 Handle<Map> transitioned_map, |
6396 int target_descriptor, | 6390 int target_descriptor, |
6397 AccessorComponent component, | 6391 AccessorComponent component, |
6398 Object* accessor, | 6392 Handle<Object> accessor, |
6399 PropertyAttributes attributes) { | 6393 PropertyAttributes attributes) { |
6400 DescriptorArray* descs = transitioned_map->instance_descriptors(); | 6394 DescriptorArray* descs = transitioned_map->instance_descriptors(); |
6401 PropertyDetails details = descs->GetDetails(target_descriptor); | 6395 PropertyDetails details = descs->GetDetails(target_descriptor); |
6402 | 6396 |
6403 // If the transition target was not callbacks, fall back to the slow case. | 6397 // If the transition target was not callbacks, fall back to the slow case. |
6404 if (details.type() != CALLBACKS) return false; | 6398 if (details.type() != CALLBACKS) return false; |
6405 Object* descriptor = descs->GetCallbacksObject(target_descriptor); | 6399 Object* descriptor = descs->GetCallbacksObject(target_descriptor); |
6406 if (!descriptor->IsAccessorPair()) return false; | 6400 if (!descriptor->IsAccessorPair()) return false; |
6407 | 6401 |
6408 Object* target_accessor = AccessorPair::cast(descriptor)->get(component); | 6402 Object* target_accessor = AccessorPair::cast(descriptor)->get(component); |
6409 PropertyAttributes target_attributes = details.attributes(); | 6403 PropertyAttributes target_attributes = details.attributes(); |
6410 | 6404 |
6411 // Reuse transition if adding same accessor with same attributes. | 6405 // Reuse transition if adding same accessor with same attributes. |
6412 if (target_accessor == accessor && target_attributes == attributes) { | 6406 if (target_accessor == *accessor && target_attributes == attributes) { |
6413 self->set_map(transitioned_map); | 6407 JSObject::MigrateToMap(self, transitioned_map); |
6414 return true; | 6408 return true; |
6415 } | 6409 } |
6416 | 6410 |
6417 // If either not the same accessor, or not the same attributes, fall back to | 6411 // If either not the same accessor, or not the same attributes, fall back to |
6418 // the slow case. | 6412 // the slow case. |
6419 return false; | 6413 return false; |
6420 } | 6414 } |
6421 | 6415 |
6422 | 6416 |
6423 static MaybeObject* CopyInsertDescriptor(Map* map, | 6417 static MaybeObject* CopyInsertDescriptor(Map* map, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6465 } | 6459 } |
6466 } else { | 6460 } else { |
6467 return false; | 6461 return false; |
6468 } | 6462 } |
6469 | 6463 |
6470 int descriptor_number = result.GetDescriptorIndex(); | 6464 int descriptor_number = result.GetDescriptorIndex(); |
6471 | 6465 |
6472 object->map()->LookupTransition(*object, *name, &result); | 6466 object->map()->LookupTransition(*object, *name, &result); |
6473 | 6467 |
6474 if (result.IsFound()) { | 6468 if (result.IsFound()) { |
6475 Map* target = result.GetTransitionTarget(); | 6469 Handle<Map> target(result.GetTransitionTarget()); |
6476 ASSERT(target->NumberOfOwnDescriptors() == | 6470 ASSERT(target->NumberOfOwnDescriptors() == |
6477 object->map()->NumberOfOwnDescriptors()); | 6471 object->map()->NumberOfOwnDescriptors()); |
6478 // This works since descriptors are sorted in order of addition. | 6472 // This works since descriptors are sorted in order of addition. |
6479 ASSERT(object->map()->instance_descriptors()-> | 6473 ASSERT(object->map()->instance_descriptors()-> |
6480 GetKey(descriptor_number) == *name); | 6474 GetKey(descriptor_number) == *name); |
6481 return TryAccessorTransition(*object, target, descriptor_number, | 6475 return TryAccessorTransition(object, target, descriptor_number, |
6482 component, *accessor, attributes); | 6476 component, accessor, attributes); |
6483 } | 6477 } |
6484 } else { | 6478 } else { |
6485 // If not, lookup a transition. | 6479 // If not, lookup a transition. |
6486 object->map()->LookupTransition(*object, *name, &result); | 6480 object->map()->LookupTransition(*object, *name, &result); |
6487 | 6481 |
6488 // If there is a transition, try to follow it. | 6482 // If there is a transition, try to follow it. |
6489 if (result.IsFound()) { | 6483 if (result.IsFound()) { |
6490 Map* target = result.GetTransitionTarget(); | 6484 Handle<Map> target(result.GetTransitionTarget()); |
6491 int descriptor_number = target->LastAdded(); | 6485 int descriptor_number = target->LastAdded(); |
6492 ASSERT(target->instance_descriptors()->GetKey(descriptor_number) | 6486 ASSERT(target->instance_descriptors()->GetKey(descriptor_number) |
6493 ->Equals(*name)); | 6487 ->Equals(*name)); |
6494 return TryAccessorTransition(*object, target, descriptor_number, | 6488 return TryAccessorTransition(object, target, descriptor_number, |
6495 component, *accessor, attributes); | 6489 component, accessor, attributes); |
6496 } | 6490 } |
6497 } | 6491 } |
6498 | 6492 |
6499 // If there is no transition yet, add a transition to the a new accessor pair | 6493 // If there is no transition yet, add a transition to the a new accessor pair |
6500 // containing the accessor. Allocate a new pair if there were no source | 6494 // containing the accessor. Allocate a new pair if there were no source |
6501 // accessors. Otherwise, copy the pair and modify the accessor. | 6495 // accessors. Otherwise, copy the pair and modify the accessor. |
6502 Handle<AccessorPair> accessors = source_accessors != NULL | 6496 Handle<AccessorPair> accessors = source_accessors != NULL |
6503 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors)) | 6497 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors)) |
6504 : isolate->factory()->NewAccessorPair(); | 6498 : isolate->factory()->NewAccessorPair(); |
6505 accessors->set(component, *accessor); | 6499 accessors->set(component, *accessor); |
6506 Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()), | 6500 Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()), |
6507 name, accessors, attributes); | 6501 name, accessors, attributes); |
6508 object->set_map(*new_map); | 6502 JSObject::MigrateToMap(object, new_map); |
6509 return true; | 6503 return true; |
6510 } | 6504 } |
6511 | 6505 |
6512 | 6506 |
6513 Handle<Object> JSObject::SetAccessor(Handle<JSObject> object, | 6507 Handle<Object> JSObject::SetAccessor(Handle<JSObject> object, |
6514 Handle<AccessorInfo> info) { | 6508 Handle<AccessorInfo> info) { |
6515 Isolate* isolate = object->GetIsolate(); | 6509 Isolate* isolate = object->GetIsolate(); |
6516 Factory* factory = isolate->factory(); | 6510 Factory* factory = isolate->factory(); |
6517 Handle<Name> name(Name::cast(info->name())); | 6511 Handle<Name> name(Name::cast(info->name())); |
6518 | 6512 |
(...skipping 3263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9782 // If the value is not a JSReceiver, store the value in the map's | 9776 // If the value is not a JSReceiver, store the value in the map's |
9783 // constructor field so it can be accessed. Also, set the prototype | 9777 // constructor field so it can be accessed. Also, set the prototype |
9784 // used for constructing objects to the original object prototype. | 9778 // used for constructing objects to the original object prototype. |
9785 // See ECMA-262 13.2.2. | 9779 // See ECMA-262 13.2.2. |
9786 if (!value->IsJSReceiver()) { | 9780 if (!value->IsJSReceiver()) { |
9787 // Copy the map so this does not affect unrelated functions. | 9781 // Copy the map so this does not affect unrelated functions. |
9788 // Remove map transitions because they point to maps with a | 9782 // Remove map transitions because they point to maps with a |
9789 // different prototype. | 9783 // different prototype. |
9790 Handle<Map> new_map = Map::Copy(handle(function->map())); | 9784 Handle<Map> new_map = Map::Copy(handle(function->map())); |
9791 | 9785 |
9792 function->set_map(*new_map); | 9786 JSObject::MigrateToMap(function, new_map); |
9793 new_map->set_constructor(*value); | 9787 new_map->set_constructor(*value); |
9794 new_map->set_non_instance_prototype(true); | 9788 new_map->set_non_instance_prototype(true); |
9795 Isolate* isolate = new_map->GetIsolate(); | 9789 Isolate* isolate = new_map->GetIsolate(); |
9796 construct_prototype = handle( | 9790 construct_prototype = handle( |
9797 isolate->context()->native_context()->initial_object_prototype(), | 9791 isolate->context()->native_context()->initial_object_prototype(), |
9798 isolate); | 9792 isolate); |
9799 } else { | 9793 } else { |
9800 function->map()->set_non_instance_prototype(false); | 9794 function->map()->set_non_instance_prototype(false); |
9801 } | 9795 } |
9802 | 9796 |
(...skipping 2053 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11856 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); | 11850 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); |
11857 } | 11851 } |
11858 | 11852 |
11859 Handle<Map> new_map = Map::GetPrototypeTransition(map, value); | 11853 Handle<Map> new_map = Map::GetPrototypeTransition(map, value); |
11860 if (new_map.is_null()) { | 11854 if (new_map.is_null()) { |
11861 new_map = Map::Copy(map); | 11855 new_map = Map::Copy(map); |
11862 Map::PutPrototypeTransition(map, value, new_map); | 11856 Map::PutPrototypeTransition(map, value, new_map); |
11863 new_map->set_prototype(*value); | 11857 new_map->set_prototype(*value); |
11864 } | 11858 } |
11865 ASSERT(new_map->prototype() == *value); | 11859 ASSERT(new_map->prototype() == *value); |
11866 real_receiver->set_map(*new_map); | 11860 JSObject::MigrateToMap(real_receiver, new_map); |
11867 | 11861 |
11868 if (!dictionary_elements_in_chain && | 11862 if (!dictionary_elements_in_chain && |
11869 new_map->DictionaryElementsInPrototypeChainOnly()) { | 11863 new_map->DictionaryElementsInPrototypeChainOnly()) { |
11870 // If the prototype chain didn't previously have element callbacks, then | 11864 // If the prototype chain didn't previously have element callbacks, then |
11871 // KeyedStoreICs need to be cleared to ensure any that involve this | 11865 // KeyedStoreICs need to be cleared to ensure any that involve this |
11872 // map go generic. | 11866 // map go generic. |
11873 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC); | 11867 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC); |
11874 } | 11868 } |
11875 | 11869 |
11876 heap->ClearInstanceofCache(); | 11870 heap->ClearInstanceofCache(); |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12197 return value; | 12191 return value; |
12198 } | 12192 } |
12199 // Change elements kind from Smi-only to generic FAST if necessary. | 12193 // Change elements kind from Smi-only to generic FAST if necessary. |
12200 if (object->HasFastSmiElements() && !value->IsSmi()) { | 12194 if (object->HasFastSmiElements() && !value->IsSmi()) { |
12201 ElementsKind kind = object->HasFastHoleyElements() | 12195 ElementsKind kind = object->HasFastHoleyElements() |
12202 ? FAST_HOLEY_ELEMENTS | 12196 ? FAST_HOLEY_ELEMENTS |
12203 : FAST_ELEMENTS; | 12197 : FAST_ELEMENTS; |
12204 | 12198 |
12205 UpdateAllocationSite(object, kind); | 12199 UpdateAllocationSite(object, kind); |
12206 Handle<Map> new_map = GetElementsTransitionMap(object, kind); | 12200 Handle<Map> new_map = GetElementsTransitionMap(object, kind); |
12207 object->set_map(*new_map); | 12201 JSObject::MigrateToMap(object, new_map); |
12208 ASSERT(IsFastObjectElementsKind(object->GetElementsKind())); | 12202 ASSERT(IsFastObjectElementsKind(object->GetElementsKind())); |
12209 } | 12203 } |
12210 // Increase backing store capacity if that's been decided previously. | 12204 // Increase backing store capacity if that's been decided previously. |
12211 if (new_capacity != capacity) { | 12205 if (new_capacity != capacity) { |
12212 SetFastElementsCapacitySmiMode smi_mode = | 12206 SetFastElementsCapacitySmiMode smi_mode = |
12213 value->IsSmi() && object->HasFastSmiElements() | 12207 value->IsSmi() && object->HasFastSmiElements() |
12214 ? kAllowSmiElements | 12208 ? kAllowSmiElements |
12215 : kDontAllowSmiElements; | 12209 : kDontAllowSmiElements; |
12216 Handle<FixedArray> new_elements = | 12210 Handle<FixedArray> new_elements = |
12217 SetFastElementsCapacityAndLength(object, new_capacity, array_length, | 12211 SetFastElementsCapacityAndLength(object, new_capacity, array_length, |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12886 (IsFastSmiOrObjectElementsKind(from_kind) && | 12880 (IsFastSmiOrObjectElementsKind(from_kind) && |
12887 IsFastSmiOrObjectElementsKind(to_kind)) || | 12881 IsFastSmiOrObjectElementsKind(to_kind)) || |
12888 (from_kind == FAST_DOUBLE_ELEMENTS && | 12882 (from_kind == FAST_DOUBLE_ELEMENTS && |
12889 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { | 12883 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { |
12890 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND); | 12884 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND); |
12891 // No change is needed to the elements() buffer, the transition | 12885 // No change is needed to the elements() buffer, the transition |
12892 // only requires a map change. | 12886 // only requires a map change. |
12893 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind); | 12887 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind); |
12894 Map* new_map; | 12888 Map* new_map; |
12895 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 12889 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
| 12890 // TODO(verwaest): Replace by MigrateToMap. |
12896 set_map(new_map); | 12891 set_map(new_map); |
12897 if (FLAG_trace_elements_transitions) { | 12892 if (FLAG_trace_elements_transitions) { |
12898 FixedArrayBase* elms = FixedArrayBase::cast(elements()); | 12893 FixedArrayBase* elms = FixedArrayBase::cast(elements()); |
12899 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms); | 12894 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms); |
12900 } | 12895 } |
12901 return this; | 12896 return this; |
12902 } | 12897 } |
12903 | 12898 |
12904 FixedArrayBase* elms = FixedArrayBase::cast(elements()); | 12899 FixedArrayBase* elms = FixedArrayBase::cast(elements()); |
12905 uint32_t capacity = static_cast<uint32_t>(elms->length()); | 12900 uint32_t capacity = static_cast<uint32_t>(elms->length()); |
(...skipping 3592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16498 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16493 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16499 static const char* error_messages_[] = { | 16494 static const char* error_messages_[] = { |
16500 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16495 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16501 }; | 16496 }; |
16502 #undef ERROR_MESSAGES_TEXTS | 16497 #undef ERROR_MESSAGES_TEXTS |
16503 return error_messages_[reason]; | 16498 return error_messages_[reason]; |
16504 } | 16499 } |
16505 | 16500 |
16506 | 16501 |
16507 } } // namespace v8::internal | 16502 } } // namespace v8::internal |
OLD | NEW |