Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(220)

Side by Side Diff: src/objects.cc

Issue 1697283002: [runtime] Turn MigrateFastTo* into static helpers (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/objects.h" 5 #include "src/objects.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 #include <iomanip> 8 #include <iomanip>
9 #include <sstream> 9 #include <sstream>
10 10
(...skipping 2794 matching lines...) Expand 10 before | Expand all | Expand 10 after
2805 if (new_map->prototype_info()->IsPrototypeInfo()) { 2805 if (new_map->prototype_info()->IsPrototypeInfo()) {
2806 // The new map isn't registered with its prototype yet; reflect this fact 2806 // The new map isn't registered with its prototype yet; reflect this fact
2807 // in the PrototypeInfo it just inherited from the old map. 2807 // in the PrototypeInfo it just inherited from the old map.
2808 PrototypeInfo::cast(new_map->prototype_info()) 2808 PrototypeInfo::cast(new_map->prototype_info())
2809 ->set_registry_slot(PrototypeInfo::UNREGISTERED); 2809 ->set_registry_slot(PrototypeInfo::UNREGISTERED);
2810 } 2810 }
2811 JSObject::LazyRegisterPrototypeUser(new_map, isolate); 2811 JSObject::LazyRegisterPrototypeUser(new_map, isolate);
2812 } 2812 }
2813 } 2813 }
2814 2814
2815 2815 namespace {
2816 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
2817 int expected_additional_properties) {
2818 if (object->map() == *new_map) return;
2819 // If this object is a prototype (the callee will check), invalidate any
2820 // prototype chains involving it.
2821 InvalidatePrototypeChains(object->map());
2822 Handle<Map> old_map(object->map());
2823
2824 // If the map was registered with its prototype before, ensure that it
2825 // registers with its new prototype now. This preserves the invariant that
2826 // when a map on a prototype chain is registered with its prototype, then
2827 // all prototypes further up the chain are also registered with their
2828 // respective prototypes.
2829 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
2830
2831 if (object->HasFastProperties()) {
2832 if (!new_map->is_dictionary_map()) {
2833 MigrateFastToFast(object, new_map);
2834 if (old_map->is_prototype_map()) {
2835 DCHECK(!old_map->is_stable());
2836 DCHECK(new_map->is_stable());
2837 // Clear out the old descriptor array to avoid problems to sharing
2838 // the descriptor array without using an explicit.
2839 old_map->InitializeDescriptors(
2840 old_map->GetHeap()->empty_descriptor_array(),
2841 LayoutDescriptor::FastPointerLayout());
2842 // Ensure that no transition was inserted for prototype migrations.
2843 DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
2844 old_map->raw_transitions()));
2845 DCHECK(new_map->GetBackPointer()->IsUndefined());
2846 }
2847 } else {
2848 MigrateFastToSlow(object, new_map, expected_additional_properties);
2849 }
2850 } else {
2851 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
2852 // must be used instead.
2853 CHECK(new_map->is_dictionary_map());
2854
2855 // Slow-to-slow migration is trivial.
2856 object->set_map(*new_map);
2857 }
2858
2859 // Careful: Don't allocate here!
2860 // For some callers of this method, |object| might be in an inconsistent
2861 // state now: the new map might have a new elements_kind, but the object's
2862 // elements pointer hasn't been updated yet. Callers will fix this, but in
2863 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
2864 // When adding code here, add a DisallowHeapAllocation too.
2865 }
2866
2867
2868 // To migrate a fast instance to a fast map: 2816 // To migrate a fast instance to a fast map:
2869 // - First check whether the instance needs to be rewritten. If not, simply 2817 // - First check whether the instance needs to be rewritten. If not, simply
2870 // change the map. 2818 // change the map.
2871 // - Otherwise, allocate a fixed array large enough to hold all fields, in 2819 // - Otherwise, allocate a fixed array large enough to hold all fields, in
2872 // addition to unused space. 2820 // addition to unused space.
2873 // - Copy all existing properties in, in the following order: backing store 2821 // - Copy all existing properties in, in the following order: backing store
2874 // properties, unused fields, inobject properties. 2822 // properties, unused fields, inobject properties.
2875 // - If all allocation succeeded, commit the state atomically: 2823 // - If all allocation succeeded, commit the state atomically:
2876 // * Copy inobject properties from the backing store back into the object. 2824 // * Copy inobject properties from the backing store back into the object.
2877 // * Trim the difference in instance size of the object. This also cleanly 2825 // * Trim the difference in instance size of the object. This also cleanly
2878 // frees inobject properties that moved to the backing store. 2826 // frees inobject properties that moved to the backing store.
2879 // * If there are properties left in the backing store, trim of the space used 2827 // * If there are properties left in the backing store, trim of the space used
2880 // to temporarily store the inobject properties. 2828 // to temporarily store the inobject properties.
2881 // * If there are properties left in the backing store, install the backing 2829 // * If there are properties left in the backing store, install the backing
2882 // store. 2830 // store.
2883 void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { 2831 void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
2884 Isolate* isolate = object->GetIsolate(); 2832 Isolate* isolate = object->GetIsolate();
2885 Handle<Map> old_map(object->map()); 2833 Handle<Map> old_map(object->map());
2886 // In case of a regular transition. 2834 // In case of a regular transition.
2887 if (new_map->GetBackPointer() == *old_map) { 2835 if (new_map->GetBackPointer() == *old_map) {
2888 // If the map does not add named properties, simply set the map. 2836 // If the map does not add named properties, simply set the map.
2889 if (old_map->NumberOfOwnDescriptors() == 2837 if (old_map->NumberOfOwnDescriptors() ==
2890 new_map->NumberOfOwnDescriptors()) { 2838 new_map->NumberOfOwnDescriptors()) {
2891 object->synchronized_set_map(*new_map); 2839 object->synchronized_set_map(*new_map);
2892 return; 2840 return;
2893 } 2841 }
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
3077 address + new_instance_size, instance_size_delta); 3025 address + new_instance_size, instance_size_delta);
3078 heap->AdjustLiveBytes(*object, -instance_size_delta, 3026 heap->AdjustLiveBytes(*object, -instance_size_delta,
3079 Heap::CONCURRENT_TO_SWEEPER); 3027 Heap::CONCURRENT_TO_SWEEPER);
3080 } 3028 }
3081 3029
3082 // We are storing the new map using release store after creating a filler for 3030 // We are storing the new map using release store after creating a filler for
3083 // the left-over space to avoid races with the sweeper thread. 3031 // the left-over space to avoid races with the sweeper thread.
3084 object->synchronized_set_map(*new_map); 3032 object->synchronized_set_map(*new_map);
3085 } 3033 }
3086 3034
3035 void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
3036 int expected_additional_properties) {
3037 // The global object is always normalized.
3038 DCHECK(!object->IsJSGlobalObject());
3039 // JSGlobalProxy must never be normalized
3040 DCHECK(!object->IsJSGlobalProxy());
3041
3042 Isolate* isolate = object->GetIsolate();
3043 HandleScope scope(isolate);
3044 Handle<Map> map(object->map());
3045
3046 // Allocate new content.
3047 int real_size = map->NumberOfOwnDescriptors();
3048 int property_count = real_size;
3049 if (expected_additional_properties > 0) {
3050 property_count += expected_additional_properties;
3051 } else {
3052 property_count += 2; // Make space for two more properties.
3053 }
3054 Handle<NameDictionary> dictionary =
3055 NameDictionary::New(isolate, property_count);
3056
3057 Handle<DescriptorArray> descs(map->instance_descriptors());
3058 for (int i = 0; i < real_size; i++) {
3059 PropertyDetails details = descs->GetDetails(i);
3060 Handle<Name> key(descs->GetKey(i));
3061 switch (details.type()) {
3062 case DATA_CONSTANT: {
3063 Handle<Object> value(descs->GetConstant(i), isolate);
3064 PropertyDetails d(details.attributes(), DATA, i + 1,
3065 PropertyCellType::kNoCell);
3066 dictionary = NameDictionary::Add(dictionary, key, value, d);
3067 break;
3068 }
3069 case DATA: {
3070 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3071 Handle<Object> value;
3072 if (object->IsUnboxedDoubleField(index)) {
3073 double old_value = object->RawFastDoublePropertyAt(index);
3074 value = isolate->factory()->NewHeapNumber(old_value);
3075 } else {
3076 value = handle(object->RawFastPropertyAt(index), isolate);
3077 if (details.representation().IsDouble()) {
3078 DCHECK(value->IsMutableHeapNumber());
3079 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
3080 value = isolate->factory()->NewHeapNumber(old->value());
3081 }
3082 }
3083 PropertyDetails d(details.attributes(), DATA, i + 1,
3084 PropertyCellType::kNoCell);
3085 dictionary = NameDictionary::Add(dictionary, key, value, d);
3086 break;
3087 }
3088 case ACCESSOR: {
3089 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3090 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
3091 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3092 PropertyCellType::kNoCell);
3093 dictionary = NameDictionary::Add(dictionary, key, value, d);
3094 break;
3095 }
3096 case ACCESSOR_CONSTANT: {
3097 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
3098 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
3099 PropertyCellType::kNoCell);
3100 dictionary = NameDictionary::Add(dictionary, key, value, d);
3101 break;
3102 }
3103 }
3104 }
3105
3106 // Copy the next enumeration index from instance descriptor.
3107 dictionary->SetNextEnumerationIndex(real_size + 1);
3108
3109 // From here on we cannot fail and we shouldn't GC anymore.
3110 DisallowHeapAllocation no_allocation;
3111
3112 // Resize the object in the heap if necessary.
3113 int new_instance_size = new_map->instance_size();
3114 int instance_size_delta = map->instance_size() - new_instance_size;
3115 DCHECK(instance_size_delta >= 0);
3116
3117 if (instance_size_delta > 0) {
3118 Heap* heap = isolate->heap();
3119 heap->CreateFillerObjectAt(object->address() + new_instance_size,
3120 instance_size_delta);
3121 heap->AdjustLiveBytes(*object, -instance_size_delta,
3122 Heap::CONCURRENT_TO_SWEEPER);
3123 }
3124
3125 // We are storing the new map using release store after creating a filler for
3126 // the left-over space to avoid races with the sweeper thread.
3127 object->synchronized_set_map(*new_map);
3128
3129 object->set_properties(*dictionary);
3130
3131 // Ensure that in-object space of slow-mode object does not contain random
3132 // garbage.
3133 int inobject_properties = new_map->GetInObjectProperties();
3134 for (int i = 0; i < inobject_properties; i++) {
3135 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
3136 object->RawFastPropertyAtPut(index, Smi::FromInt(0));
3137 }
3138
3139 isolate->counters()->props_to_dictionary()->Increment();
3140
3141 #ifdef DEBUG
3142 if (FLAG_trace_normalization) {
3143 OFStream os(stdout);
3144 os << "Object properties have been normalized:\n";
3145 object->Print(os);
3146 }
3147 #endif
3148 }
3149
3150 } // namespace
3151
3152 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
3153 int expected_additional_properties) {
3154 if (object->map() == *new_map) return;
3155 // If this object is a prototype (the callee will check), invalidate any
3156 // prototype chains involving it.
3157 InvalidatePrototypeChains(object->map());
3158 Handle<Map> old_map(object->map());
3159
3160 // If the map was registered with its prototype before, ensure that it
3161 // registers with its new prototype now. This preserves the invariant that
3162 // when a map on a prototype chain is registered with its prototype, then
3163 // all prototypes further up the chain are also registered with their
3164 // respective prototypes.
3165 UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
3166
3167 if (object->HasFastProperties()) {
3168 if (!new_map->is_dictionary_map()) {
3169 MigrateFastToFast(object, new_map);
3170 if (old_map->is_prototype_map()) {
3171 DCHECK(!old_map->is_stable());
3172 DCHECK(new_map->is_stable());
3173 // Clear out the old descriptor array to avoid problems to sharing
3174 // the descriptor array without using an explicit.
3175 old_map->InitializeDescriptors(
3176 old_map->GetHeap()->empty_descriptor_array(),
3177 LayoutDescriptor::FastPointerLayout());
3178 // Ensure that no transition was inserted for prototype migrations.
3179 DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
3180 old_map->raw_transitions()));
3181 DCHECK(new_map->GetBackPointer()->IsUndefined());
3182 }
3183 } else {
3184 MigrateFastToSlow(object, new_map, expected_additional_properties);
3185 }
3186 } else {
3187 // For slow-to-fast migrations JSObject::MigrateSlowToFast()
3188 // must be used instead.
3189 CHECK(new_map->is_dictionary_map());
3190
3191 // Slow-to-slow migration is trivial.
3192 object->set_map(*new_map);
3193 }
3194
3195 // Careful: Don't allocate here!
3196 // For some callers of this method, |object| might be in an inconsistent
3197 // state now: the new map might have a new elements_kind, but the object's
3198 // elements pointer hasn't been updated yet. Callers will fix this, but in
3199 // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
3200 // When adding code here, add a DisallowHeapAllocation too.
3201 }
3087 3202
3088 int Map::NumberOfFields() { 3203 int Map::NumberOfFields() {
3089 DescriptorArray* descriptors = instance_descriptors(); 3204 DescriptorArray* descriptors = instance_descriptors();
3090 int result = 0; 3205 int result = 0;
3091 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { 3206 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
3092 if (descriptors->GetDetails(i).location() == kField) result++; 3207 if (descriptors->GetDetails(i).location() == kField) result++;
3093 } 3208 }
3094 return result; 3209 return result;
3095 } 3210 }
3096 3211
(...skipping 2462 matching lines...) Expand 10 before | Expand all | Expand 10 after
5559 const char* reason) { 5674 const char* reason) {
5560 if (!object->HasFastProperties()) return; 5675 if (!object->HasFastProperties()) return;
5561 5676
5562 Handle<Map> map(object->map()); 5677 Handle<Map> map(object->map());
5563 Handle<Map> new_map = Map::Normalize(map, mode, reason); 5678 Handle<Map> new_map = Map::Normalize(map, mode, reason);
5564 5679
5565 MigrateToMap(object, new_map, expected_additional_properties); 5680 MigrateToMap(object, new_map, expected_additional_properties);
5566 } 5681 }
5567 5682
5568 5683
5569 void JSObject::MigrateFastToSlow(Handle<JSObject> object,
5570 Handle<Map> new_map,
5571 int expected_additional_properties) {
5572 // The global object is always normalized.
5573 DCHECK(!object->IsJSGlobalObject());
5574 // JSGlobalProxy must never be normalized
5575 DCHECK(!object->IsJSGlobalProxy());
5576
5577 Isolate* isolate = object->GetIsolate();
5578 HandleScope scope(isolate);
5579 Handle<Map> map(object->map());
5580
5581 // Allocate new content.
5582 int real_size = map->NumberOfOwnDescriptors();
5583 int property_count = real_size;
5584 if (expected_additional_properties > 0) {
5585 property_count += expected_additional_properties;
5586 } else {
5587 property_count += 2; // Make space for two more properties.
5588 }
5589 Handle<NameDictionary> dictionary =
5590 NameDictionary::New(isolate, property_count);
5591
5592 Handle<DescriptorArray> descs(map->instance_descriptors());
5593 for (int i = 0; i < real_size; i++) {
5594 PropertyDetails details = descs->GetDetails(i);
5595 Handle<Name> key(descs->GetKey(i));
5596 switch (details.type()) {
5597 case DATA_CONSTANT: {
5598 Handle<Object> value(descs->GetConstant(i), isolate);
5599 PropertyDetails d(details.attributes(), DATA, i + 1,
5600 PropertyCellType::kNoCell);
5601 dictionary = NameDictionary::Add(dictionary, key, value, d);
5602 break;
5603 }
5604 case DATA: {
5605 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
5606 Handle<Object> value;
5607 if (object->IsUnboxedDoubleField(index)) {
5608 double old_value = object->RawFastDoublePropertyAt(index);
5609 value = isolate->factory()->NewHeapNumber(old_value);
5610 } else {
5611 value = handle(object->RawFastPropertyAt(index), isolate);
5612 if (details.representation().IsDouble()) {
5613 DCHECK(value->IsMutableHeapNumber());
5614 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
5615 value = isolate->factory()->NewHeapNumber(old->value());
5616 }
5617 }
5618 PropertyDetails d(details.attributes(), DATA, i + 1,
5619 PropertyCellType::kNoCell);
5620 dictionary = NameDictionary::Add(dictionary, key, value, d);
5621 break;
5622 }
5623 case ACCESSOR: {
5624 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
5625 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
5626 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
5627 PropertyCellType::kNoCell);
5628 dictionary = NameDictionary::Add(dictionary, key, value, d);
5629 break;
5630 }
5631 case ACCESSOR_CONSTANT: {
5632 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
5633 PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
5634 PropertyCellType::kNoCell);
5635 dictionary = NameDictionary::Add(dictionary, key, value, d);
5636 break;
5637 }
5638 }
5639 }
5640
5641 // Copy the next enumeration index from instance descriptor.
5642 dictionary->SetNextEnumerationIndex(real_size + 1);
5643
5644 // From here on we cannot fail and we shouldn't GC anymore.
5645 DisallowHeapAllocation no_allocation;
5646
5647 // Resize the object in the heap if necessary.
5648 int new_instance_size = new_map->instance_size();
5649 int instance_size_delta = map->instance_size() - new_instance_size;
5650 DCHECK(instance_size_delta >= 0);
5651
5652 if (instance_size_delta > 0) {
5653 Heap* heap = isolate->heap();
5654 heap->CreateFillerObjectAt(object->address() + new_instance_size,
5655 instance_size_delta);
5656 heap->AdjustLiveBytes(*object, -instance_size_delta,
5657 Heap::CONCURRENT_TO_SWEEPER);
5658 }
5659
5660 // We are storing the new map using release store after creating a filler for
5661 // the left-over space to avoid races with the sweeper thread.
5662 object->synchronized_set_map(*new_map);
5663
5664 object->set_properties(*dictionary);
5665
5666 // Ensure that in-object space of slow-mode object does not contain random
5667 // garbage.
5668 int inobject_properties = new_map->GetInObjectProperties();
5669 for (int i = 0; i < inobject_properties; i++) {
5670 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
5671 object->RawFastPropertyAtPut(index, Smi::FromInt(0));
5672 }
5673
5674 isolate->counters()->props_to_dictionary()->Increment();
5675
5676 #ifdef DEBUG
5677 if (FLAG_trace_normalization) {
5678 OFStream os(stdout);
5679 os << "Object properties have been normalized:\n";
5680 object->Print(os);
5681 }
5682 #endif
5683 }
5684
5685
5686 void JSObject::MigrateSlowToFast(Handle<JSObject> object, 5684 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
5687 int unused_property_fields, 5685 int unused_property_fields,
5688 const char* reason) { 5686 const char* reason) {
5689 if (object->HasFastProperties()) return; 5687 if (object->HasFastProperties()) return;
5690 DCHECK(!object->IsJSGlobalObject()); 5688 DCHECK(!object->IsJSGlobalObject());
5691 Isolate* isolate = object->GetIsolate(); 5689 Isolate* isolate = object->GetIsolate();
5692 Factory* factory = isolate->factory(); 5690 Factory* factory = isolate->factory();
5693 Handle<NameDictionary> dictionary(object->property_dictionary()); 5691 Handle<NameDictionary> dictionary(object->property_dictionary());
5694 5692
5695 // Make sure we preserve dictionary representation if there are too many 5693 // Make sure we preserve dictionary representation if there are too many
(...skipping 14289 matching lines...) Expand 10 before | Expand all | Expand 10 after
19985 if (cell->value() != *new_value) { 19983 if (cell->value() != *new_value) {
19986 cell->set_value(*new_value); 19984 cell->set_value(*new_value);
19987 Isolate* isolate = cell->GetIsolate(); 19985 Isolate* isolate = cell->GetIsolate();
19988 cell->dependent_code()->DeoptimizeDependentCodeGroup( 19986 cell->dependent_code()->DeoptimizeDependentCodeGroup(
19989 isolate, DependentCode::kPropertyCellChangedGroup); 19987 isolate, DependentCode::kPropertyCellChangedGroup);
19990 } 19988 }
19991 } 19989 }
19992 19990
19993 } // namespace internal 19991 } // namespace internal
19994 } // namespace v8 19992 } // namespace v8
OLDNEW
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698