Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 897c52ade6b9003b309307e939e9456267cd8e2e..9a9fa1c8664bac479264f1814fd68b13a34e3fed 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -1959,12 +1959,14 @@ static Handle<Object> NewStorageFor(Isolate* isolate, |
| static MaybeObject* CopyAddFieldDescriptor(Map* map, |
| Name* name, |
| - int index, |
| + int field_index, |
| + HeapType* field_type, |
| PropertyAttributes attributes, |
| Representation representation, |
| TransitionFlag flag) { |
| Map* new_map; |
| - FieldDescriptor new_field_desc(name, index, attributes, representation); |
| + FieldDescriptor new_field_desc(name, field_index, field_type, |
| + attributes, representation); |
| MaybeObject* maybe_map = map->CopyAddDescriptor(&new_field_desc, flag); |
| if (!maybe_map->To(&new_map)) return maybe_map; |
| int unused_property_fields = map->unused_property_fields() - 1; |
| @@ -1978,13 +1980,15 @@ static MaybeObject* CopyAddFieldDescriptor(Map* map, |
| static Handle<Map> CopyAddFieldDescriptor(Handle<Map> map, |
| Handle<Name> name, |
| - int index, |
| + int field_index, |
| + Handle<HeapType> field_type, |
| PropertyAttributes attributes, |
| Representation representation, |
| TransitionFlag flag) { |
| CALL_HEAP_FUNCTION(map->GetIsolate(), |
| CopyAddFieldDescriptor( |
| - *map, *name, index, attributes, representation, flag), |
| + *map, *name, field_index, *field_type, |
| + attributes, representation, flag), |
| Map); |
| } |
| @@ -2013,23 +2017,44 @@ void JSObject::AddFastProperty(Handle<JSObject> object, |
| } |
| // Compute the new index for new field. |
| - int index = object->map()->NextFreePropertyIndex(); |
| + int field_index = object->map()->NextFreePropertyIndex(); |
| - // Allocate new instance descriptors with (name, index) added |
| + // Compute the optimal representation for the new field. |
| if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED; |
| Representation representation = value->OptimalRepresentation(value_type); |
| + |
| + // Compute the type of the new field. |
| + Handle<HeapType> field_type = FLAG_track_field_types |
| + ? HeapType::OfCurrently(value, isolate) |
|
Toon Verwaest
2014/03/21 14:33:37
If it's FORCE_TAGGED we also shouldn't be tracking
Benedikt Meurer
2014/04/11 11:12:00
Done.
|
| + : HeapType::Any(isolate); |
| + if (FLAG_trace_track_field_types) { |
| +#ifdef OBJECT_PRINT |
| + PrintF("[Adding fast property "); |
| + name->Print(); |
| + PrintF(" to object "); |
| + object->ShortPrint(); |
| + PrintF(" with value "); |
| + value->ShortPrint(); |
| + PrintF(" and field type "); |
| + field_type->TypePrint(stdout); |
| + PrintF("]\n"); |
| +#endif |
| + } |
| + |
| + // Allocate new instance descriptors with (name, index) added |
| Handle<Map> new_map = CopyAddFieldDescriptor( |
| - handle(object->map()), name, index, attributes, representation, flag); |
| + handle(object->map()), name, field_index, |
| + field_type, attributes, representation, flag); |
| JSObject::MigrateToMap(object, new_map); |
| if (representation.IsDouble()) { |
| // Nothing more to be done. |
| if (value->IsUninitialized()) return; |
| - HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(index)); |
| + HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(field_index)); |
| box->set_value(value->Number()); |
| } else { |
| - object->FastPropertyAtPut(index, *value); |
| + object->FastPropertyAtPut(field_index, *value); |
| } |
| } |
| @@ -2460,9 +2485,11 @@ Handle<TransitionArray> Map::AddTransition(Handle<Map> map, |
| void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object, |
| int modify_index, |
| Representation new_representation, |
| + Handle<HeapType> new_field_type, |
| StoreMode store_mode) { |
| Handle<Map> new_map = Map::GeneralizeRepresentation( |
| - handle(object->map()), modify_index, new_representation, store_mode); |
| + handle(object->map()), modify_index, new_representation, |
| + new_field_type, store_mode); |
| if (object->map() == *new_map) return; |
| return MigrateToMap(object, new_map); |
| } |
| @@ -2486,13 +2513,20 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map, |
| Handle<Map> new_map = Copy(map); |
| DescriptorArray* descriptors = new_map->instance_descriptors(); |
| - descriptors->InitializeRepresentations(Representation::Tagged()); |
| + int length = descriptors->number_of_descriptors(); |
| + for (int i = 0; i < length; i++) { |
| + descriptors->SetRepresentation(i, Representation::Tagged()); |
| + if (descriptors->GetDetails(i).type() == FIELD) { |
| + descriptors->SetValue(i, HeapType::Any()); |
| + } |
| + } |
| // Unless the instance is being migrated, ensure that modify_index is a field. |
| PropertyDetails details = descriptors->GetDetails(modify_index); |
| if (store_mode == FORCE_FIELD && details.type() != FIELD) { |
| FieldDescriptor d(descriptors->GetKey(modify_index), |
| new_map->NumberOfFields(), |
| + HeapType::Any(), |
| attributes, |
| Representation::Tagged()); |
| d.SetSortedKeyIndex(details.pointer()); |
| @@ -2623,20 +2657,64 @@ Map* Map::FindLastMatchMap(int verbatim, |
| Map* next = transitions->GetTarget(transition); |
| DescriptorArray* next_descriptors = next->instance_descriptors(); |
| - if (next_descriptors->GetValue(i) != descriptors->GetValue(i)) break; |
| - |
| PropertyDetails details = descriptors->GetDetails(i); |
| PropertyDetails next_details = next_descriptors->GetDetails(i); |
| if (details.type() != next_details.type()) break; |
| if (details.attributes() != next_details.attributes()) break; |
| if (!details.representation().Equals(next_details.representation())) break; |
| + // TODO(bmeurer): Check descriptors is subtype of next_descriptors. |
| + if (next_details.type() != FIELD && |
| + next_descriptors->GetValue(i) != descriptors->GetValue(i)) break; |
| + |
| current = next; |
| } |
| return current; |
| } |
| +Map* Map::FindFieldOwner(int descriptor) { |
| + ASSERT(instance_descriptors()->GetDetails(descriptor).type() == FIELD); |
| + Map* result = this; |
| + while (true) { |
| + Object* back = result->GetBackPointer(); |
| + if (back->IsUndefined()) break; |
| + Map* parent = Map::cast(back); |
| + if (parent->NumberOfOwnDescriptors() <= descriptor) break; |
| + result = parent; |
| + } |
| + return result; |
| +} |
| + |
| + |
| +void Map::UpdateDescriptor(int descriptor_number, Descriptor* desc) { |
| + if (HasTransitionArray()) { |
| + TransitionArray* transitions = this->transitions(); |
| + for (int i = 0; i < transitions->number_of_transitions(); ++i) { |
| + transitions->GetTarget(i)->UpdateDescriptor(descriptor_number, desc); |
| + } |
| + } |
| + DescriptorArray* descriptors = instance_descriptors(); |
| + desc->SetSortedKeyIndex(descriptors->GetDetails(descriptor_number).pointer()); |
| + descriptors->Set(descriptor_number, desc); |
| +} |
| + |
| + |
| +void Map::UpdateFieldType(int descriptor, HeapType* field_type) { |
| + ASSERT(this == FindFieldOwner(descriptor)); |
| + DescriptorArray* descriptors = instance_descriptors(); |
| + PropertyDetails details = descriptors->GetDetails(descriptor); |
| + FieldDescriptor d(descriptors->GetKey(descriptor), |
| + descriptors->GetFieldIndex(descriptor), |
| + field_type, |
| + details.attributes(), |
| + details.representation()); |
| + UpdateDescriptor(descriptor, &d); |
| + dependent_code()->DeoptimizeDependentCodeGroup( |
| + GetIsolate(), DependentCode::kFieldTypeGroup); |
| +} |
| + |
| + |
| // Generalize the representation of the descriptor at |modify_index|. |
| // This method rewrites the transition tree to reflect the new change. To avoid |
| // high degrees over polymorphism, and to stabilize quickly, on every rewrite |
| @@ -2658,6 +2736,7 @@ Map* Map::FindLastMatchMap(int verbatim, |
| Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
| int modify_index, |
| Representation new_representation, |
| + Handle<HeapType> new_field_type, |
| StoreMode store_mode) { |
| Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); |
| PropertyDetails old_details = old_descriptors->GetDetails(modify_index); |
| @@ -2671,6 +2750,9 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
| !new_representation.IsNone() && |
| !new_representation.IsDouble()) { |
| old_descriptors->SetRepresentation(modify_index, new_representation); |
| + if (old_details.type() == FIELD) { |
|
Toon Verwaest
2014/03/21 14:33:37
Only if new_representation is heap_object right?
|
| + old_descriptors->SetValue(modify_index, *new_field_type); |
| + } |
| return old_map; |
| } |
| @@ -2726,6 +2808,16 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
| if (!updated_representation.Equals(old_representation)) { |
| new_descriptors->SetRepresentation(modify_index, updated_representation); |
| } |
| + if (new_descriptors->GetDetails(modify_index).type() == FIELD) { |
| + Handle<HeapType> field_type(new_descriptors->GetFieldType(modify_index), |
| + new_descriptors->GetIsolate()); |
| + if (!new_field_type->IsCurrently(field_type)) { |
| + if (!field_type->IsCurrently(new_field_type)) { |
| + new_field_type = HeapType::Any(updated->GetIsolate()); |
| + } |
| + new_descriptors->SetValue(modify_index, *new_field_type); |
|
Toon Verwaest
2014/03/21 14:33:37
Only if new_representation.IsHeapObject()
Benedikt Meurer
2014/04/11 11:12:00
No, we track types independent of the representati
|
| + } |
| + } |
| Handle<Map> split_map(root_map->FindLastMatchMap( |
| verbatim, descriptors, *new_descriptors)); |
| @@ -2760,13 +2852,13 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
| // Generalize the representation of all FIELD descriptors. |
| Handle<Map> Map::GeneralizeAllFieldRepresentations( |
| - Handle<Map> map, |
| - Representation new_representation) { |
| + Handle<Map> map) { |
| Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| - for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { |
| - PropertyDetails details = descriptors->GetDetails(i); |
| - if (details.type() == FIELD) { |
| - map = GeneralizeRepresentation(map, i, new_representation, FORCE_FIELD); |
| + for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) { |
| + if (descriptors->GetDetails(i).type() == FIELD) { |
| + map = GeneralizeRepresentation(map, i, Representation::Tagged(), |
| + HeapType::Any(map->GetIsolate()), |
| + FORCE_FIELD); |
| } |
| } |
| return map; |
| @@ -3845,7 +3937,9 @@ void JSObject::MigrateInstance(Handle<JSObject> object) { |
| // transition that matches the object. This achieves what is needed. |
| Handle<Map> original_map(object->map()); |
| GeneralizeFieldRepresentation( |
| - object, 0, Representation::None(), ALLOW_AS_CONSTANT); |
| + object, 0, Representation::None(), |
| + HeapType::None(object->GetIsolate()), |
| + ALLOW_AS_CONSTANT); |
| object->map()->set_migration_target(true); |
| if (FLAG_trace_migration) { |
| object->PrintInstanceMigration(stdout, *original_map, object->map()); |
| @@ -3891,11 +3985,39 @@ Handle<Object> JSObject::SetPropertyUsingTransition( |
| // Keep the target CONSTANT if the same value is stored. |
| // TODO(verwaest): Also support keeping the placeholder |
| // (value->IsUninitialized) as constant. |
| + Handle<HeapType> value_type = FLAG_track_field_types |
| + ? HeapType::OfCurrently(value, lookup->isolate()) |
| + : HeapType::Any(lookup->isolate()); |
| if (!value->FitsRepresentation(details.representation()) || |
| (details.type() == CONSTANT && |
| descriptors->GetValue(descriptor) != *value)) { |
| - transition_map = Map::GeneralizeRepresentation(transition_map, |
| - descriptor, value->OptimalRepresentation(), FORCE_FIELD); |
| + transition_map = Map::GeneralizeRepresentation( |
| + transition_map, descriptor, |
| + value->OptimalRepresentation(), |
| + value_type, FORCE_FIELD); |
| + } else if (details.type() == FIELD && |
| + details.representation().IsHeapObject()) { |
| + Handle<HeapType> field_type(descriptors->GetFieldType(descriptor), |
| + lookup->isolate()); |
| + if (!value_type->IsCurrently(field_type)) { |
| + if (!field_type->IsCurrently(value_type)) { |
| + value_type = HeapType::Any(lookup->isolate()); |
| + } |
| + if (FLAG_trace_track_field_types) { |
| +#ifdef OBJECT_PRINT |
| + PrintF("[Updating type of field "); |
| + name->Print(); |
| + PrintF(" in transition map "); |
| + transition_map->ShortPrint(); |
| + PrintF(": "); |
| + field_type->TypePrint(stdout); |
| + PrintF(" -> "); |
| + value_type->TypePrint(stdout); |
| + PrintF("]\n"); |
| +#endif |
| + } |
| + transition_map->UpdateFieldType(descriptor, *value_type); |
| + } |
| } |
| JSObject::MigrateToMap(object, transition_map); |
| @@ -3924,15 +4046,40 @@ static void SetPropertyToField(LookupResult* lookup, |
| Handle<Name> name, |
| Handle<Object> value) { |
| Representation representation = lookup->representation(); |
| + Handle<HeapType> value_type = FLAG_track_field_types |
| + ? HeapType::OfCurrently(value, lookup->isolate()) |
| + : HeapType::Any(lookup->isolate()); |
| if (!value->FitsRepresentation(representation) || |
| lookup->type() == CONSTANT) { |
| JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()), |
| lookup->GetDescriptorIndex(), |
| value->OptimalRepresentation(), |
| - FORCE_FIELD); |
| + value_type, FORCE_FIELD); |
| DescriptorArray* desc = lookup->holder()->map()->instance_descriptors(); |
| int descriptor = lookup->GetDescriptorIndex(); |
| representation = desc->GetDetails(descriptor).representation(); |
| + } else if (representation.IsHeapObject()) { |
| + Handle<HeapType> field_type(lookup->GetFieldType(), lookup->isolate()); |
| + if (!value_type->IsCurrently(field_type)) { |
| + if (!field_type->IsCurrently(value_type)) { |
| + value_type = HeapType::Any(lookup->isolate()); |
| + } |
| + if (FLAG_trace_track_field_types) { |
| +#ifdef OBJECT_PRINT |
| + PrintF("[Updating type of field "); |
| + name->Print(); |
| + PrintF(" in map "); |
| + lookup->GetFieldOwner()->ShortPrint(); |
| + PrintF(": "); |
| + field_type->TypePrint(stdout); |
| + PrintF(" -> "); |
| + value_type->TypePrint(stdout); |
| + PrintF("]\n"); |
| +#endif |
| + } |
| + lookup->GetFieldOwner()->UpdateFieldType( |
| + lookup->GetDescriptorIndex(), *value_type); |
| + } |
| } |
| if (representation.IsDouble()) { |
| @@ -3964,7 +4111,8 @@ static void ConvertAndSetLocalProperty(LookupResult* lookup, |
| int descriptor_index = lookup->GetDescriptorIndex(); |
| if (lookup->GetAttributes() == attributes) { |
| JSObject::GeneralizeFieldRepresentation( |
| - object, descriptor_index, Representation::Tagged(), FORCE_FIELD); |
| + object, descriptor_index, Representation::Tagged(), |
| + HeapType::Any(lookup->isolate()), FORCE_FIELD); |
| } else { |
| Handle<Map> old_map(object->map()); |
| Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map, |
| @@ -4960,8 +5108,6 @@ Object* JSObject::GetHiddenPropertiesHashTable() { |
| if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && |
| sorted_index < map()->NumberOfOwnDescriptors()) { |
| ASSERT(descriptors->GetType(sorted_index) == FIELD); |
| - ASSERT(descriptors->GetDetails(sorted_index).representation(). |
| - IsCompatibleForLoad(Representation::Tagged())); |
| return this->RawFastPropertyAt( |
| descriptors->GetFieldIndex(sorted_index)); |
| } else { |
| @@ -6866,7 +7012,13 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
| set_transitions(transitions); |
| result->SetBackPointer(this); |
| } else { |
| - descriptors->InitializeRepresentations(Representation::Tagged()); |
| + int length = descriptors->number_of_descriptors(); |
| + for (int i = 0; i < length; i++) { |
| + descriptors->SetRepresentation(i, Representation::Tagged()); |
| + if (descriptors->GetDetails(i).type() == FIELD) { |
| + descriptors->SetValue(i, HeapType::Any()); |
| + } |
| + } |
| } |
| return result; |
| @@ -7986,6 +8138,12 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
| } |
| +HeapType* DescriptorArray::GetFieldType(int descriptor_number) { |
| + ASSERT(GetDetails(descriptor_number).type() == FIELD); |
| + return HeapType::cast(GetValue(descriptor_number)); |
| +} |
| + |
| + |
| void DescriptorArray::CopyFrom(int dst_index, |
| DescriptorArray* src, |
| int src_index, |
| @@ -8065,8 +8223,24 @@ MaybeObject* DescriptorArray::Merge(int verbatim, |
| GetValue(descriptor) != other->GetValue(descriptor))) { |
| Representation representation = |
| details.representation().generalize(other_details.representation()); |
| + // TODO(bmeurer): Cleanup this crap! |
| + HeapType* field_type = HeapType::Any(); |
| + if (representation.IsHeapObject()) { |
| + Object* val = GetValue(descriptor); |
| + Object* other_val = other->GetValue(descriptor); |
| + if (details.type() == FIELD && other_details.type() == FIELD) { |
| + HeapType* type = HeapType::cast(val); |
| + HeapType* other_type = HeapType::cast(other_val); |
| + if (type->Is(other_type)) { |
| + field_type = other_type; |
| + } else if (other_type->Is(type)) { |
| + field_type = type; |
| + } |
| + } |
| + } |
| FieldDescriptor d(key, |
| current_offset++, |
| + field_type, |
| other_details.attributes(), |
| representation); |
| result->Set(descriptor, &d, witness); |
| @@ -8083,6 +8257,7 @@ MaybeObject* DescriptorArray::Merge(int verbatim, |
| Name* key = other->GetKey(descriptor); |
| FieldDescriptor d(key, |
| current_offset++, |
| + HeapType::cast(other->GetValue(descriptor)), |
| details.attributes(), |
| details.representation()); |
| result->Set(descriptor, &d, witness); |
| @@ -15726,6 +15901,7 @@ MaybeObject* NameDictionary::TransformPropertiesToFastFor( |
| } |
| FieldDescriptor d(key, |
| current_offset++, |
| + HeapType::Any(), |
| details.attributes(), |
| // TODO(verwaest): value->OptimalRepresentation(); |
| Representation::Tagged()); |