Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 27636585b1c736aac37384ee1d82a5a8e22ef4d3..4d874219aae409e6673e1ac21fd70af9d7224b66 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -2220,10 +2220,14 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { |
} |
ASSERT(old_details.type() == CONSTANT || |
old_details.type() == FIELD); |
- Object* raw_value = old_details.type() == CONSTANT |
- ? old_descriptors->GetValue(i) |
- : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i)); |
- Handle<Object> value(raw_value, isolate); |
+ Handle<Object> value; |
+ if (old_details.type() == CONSTANT) { |
+ value = handle(old_descriptors->GetValue(i), isolate); |
+ } else { |
+ FieldIndex index = FieldIndex::ForDescriptor(*old_map, i); |
+ // TODO(ishell): avoid boxing if copying to unboxed double. |
+ value = RawFastBoxedPropertyAt(object, index); |
+ } |
if (!old_details.representation().IsDouble() && |
details.representation().IsDouble()) { |
if (old_details.representation().IsNone()) { |
@@ -2262,7 +2266,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { |
int limit = Min(inobject, number_of_fields); |
for (int i = 0; i < limit; i++) { |
FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); |
- object->FastPropertyAtPut(index, array->get(external + i)); |
+ object->FastPropertyAtPut(*new_map, index, array->get(external + i)); |
} |
Heap* heap = isolate->heap(); |
@@ -2396,10 +2400,11 @@ void Map::DeprecateTransitionTree() { |
// Invalidates a transition target at |key|, and installs |new_descriptors| over |
// the current instance_descriptors to ensure proper sharing of descriptor |
// arrays. |
-void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) { |
+void Map::DeprecateTarget(Handle<Name> key, |
+ Handle<DescriptorArray> new_descriptors) { |
if (HasTransitionArray()) { |
TransitionArray* transitions = this->transitions(); |
- int transition = transitions->Search(key); |
+ int transition = transitions->Search(*key); |
if (transition != TransitionArray::kNotFound) { |
transitions->GetTarget(transition)->DeprecateTransitionTree(); |
} |
@@ -2408,12 +2413,14 @@ void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) { |
// Don't overwrite the empty descriptor array. |
if (NumberOfOwnDescriptors() == 0) return; |
+ Handle<LayoutDescriptor> new_layout_descriptor = |
+ LayoutDescriptor::New(new_descriptors); |
DescriptorArray* to_replace = instance_descriptors(); |
Map* current = this; |
GetHeap()->incremental_marking()->RecordWrites(to_replace); |
while (current->instance_descriptors() == to_replace) { |
current->SetEnumLength(kInvalidEnumCacheSentinel); |
- current->set_instance_descriptors(new_descriptors); |
+ current->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); |
Object* next = current->GetBackPointer(); |
if (next->IsUndefined()) break; |
current = Map::cast(next); |
@@ -2494,7 +2501,7 @@ void Map::UpdateDescriptor(int descriptor_number, Descriptor* desc) { |
transitions->GetTarget(i)->UpdateDescriptor(descriptor_number, desc); |
} |
} |
- instance_descriptors()->Replace(descriptor_number, desc);; |
+ instance_descriptors()->Replace(descriptor_number, desc); |
} |
@@ -2744,7 +2751,9 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
int current_offset = 0; |
for (int i = 0; i < root_nof; ++i) { |
PropertyDetails old_details = old_descriptors->GetDetails(i); |
- if (old_details.type() == FIELD) current_offset++; |
+ if (old_details.type() == FIELD) { |
+ current_offset += old_details.field_width_in_words(); |
+ } |
Descriptor d(handle(old_descriptors->GetKey(i), isolate), |
handle(old_descriptors->GetValue(i), isolate), |
old_details); |
@@ -2782,11 +2791,10 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
target_field_type = GeneralizeFieldType( |
target_field_type, new_field_type, isolate); |
} |
- FieldDescriptor d(target_key, |
- current_offset++, |
- target_field_type, |
+ FieldDescriptor d(target_key, current_offset, target_field_type, |
target_details.attributes(), |
target_details.representation()); |
+ current_offset += d.GetDetails().field_width_in_words(); |
new_descriptors->Set(i, &d); |
} else { |
ASSERT_NE(FIELD, target_details.type()); |
@@ -2812,23 +2820,20 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
old_field_type = GeneralizeFieldType( |
old_field_type, new_field_type, isolate); |
} |
- FieldDescriptor d(old_key, |
- current_offset++, |
- old_field_type, |
- old_details.attributes(), |
- old_details.representation()); |
+ FieldDescriptor d(old_key, current_offset, old_field_type, |
+ old_details.attributes(), old_details.representation()); |
+ current_offset += d.GetDetails().field_width_in_words(); |
new_descriptors->Set(i, &d); |
} else { |
ASSERT(old_details.type() == CONSTANT || old_details.type() == CALLBACKS); |
if (modify_index == i && store_mode == FORCE_FIELD) { |
- FieldDescriptor d(old_key, |
- current_offset++, |
- GeneralizeFieldType( |
- old_descriptors->GetValue(i)->OptimalType( |
- isolate, old_details.representation()), |
- new_field_type, isolate), |
- old_details.attributes(), |
- old_details.representation()); |
+ FieldDescriptor d( |
+ old_key, current_offset, |
+ GeneralizeFieldType(old_descriptors->GetValue(i)->OptimalType( |
+ isolate, old_details.representation()), |
+ new_field_type, isolate), |
+ old_details.attributes(), old_details.representation()); |
+ current_offset += d.GetDetails().field_width_in_words(); |
new_descriptors->Set(i, &d); |
} else { |
ASSERT_NE(FIELD, old_details.type()); |
@@ -2851,7 +2856,7 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, |
ASSERT_NE(old_nof, split_nof); |
split_map->DeprecateTarget( |
- old_descriptors->GetKey(split_nof), *new_descriptors); |
+ handle(old_descriptors->GetKey(split_nof), isolate), new_descriptors); |
if (FLAG_trace_generalization) { |
PropertyDetails old_details = old_descriptors->GetDetails(modify_index); |
@@ -3129,8 +3134,13 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( |
descriptors, old_size, slack); |
+ Handle<LayoutDescriptor> new_layout_descriptor = |
+ LayoutDescriptor::New(new_descriptors); |
+ |
+ DisallowHeapAllocation no_allocation; |
+ |
if (old_size == 0) { |
- map->set_instance_descriptors(*new_descriptors); |
+ map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); |
return; |
} |
@@ -3152,10 +3162,10 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
current = walk_map->GetBackPointer()) { |
walk_map = Map::cast(current); |
if (walk_map->instance_descriptors() != *descriptors) break; |
- walk_map->set_instance_descriptors(*new_descriptors); |
+ walk_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); |
} |
- map->set_instance_descriptors(*new_descriptors); |
+ map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); |
} |
@@ -3470,10 +3480,12 @@ void JSObject::LookupOwnRealNamedProperty(Handle<Name> name, |
(result->holder() == this && result->IsFastPropertyType())); |
// Disallow caching for uninitialized constants. These can only |
// occur as fields. |
- if (result->IsField() && |
- result->IsReadOnly() && |
- RawFastPropertyAt(result->GetFieldIndex())->IsTheHole()) { |
- result->DisallowCaching(); |
+ if (result->IsField() && result->IsReadOnly()) { |
+ FieldIndex index = result->GetFieldIndex(); |
+ if (!map()->IsUnboxedDoubleField(index) && |
Toon Verwaest
2014/07/29 15:02:09
Unnecessary by now
Igor Sheludko
2014/10/30 14:23:44
Done.
|
+ RawFastPropertyAt(index)->IsTheHole()) { |
+ result->DisallowCaching(); |
+ } |
} |
return; |
} |
@@ -3988,9 +4000,13 @@ void JSObject::WriteToField(int descriptor, Object* value) { |
if (details.representation().IsDouble()) { |
// Nothing more to be done. |
if (value->IsUninitialized()) return; |
- HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index)); |
- ASSERT(box->IsMutableHeapNumber()); |
- box->set_value(value->Number()); |
+ if (map()->IsUnboxedDoubleField(index)) { |
+ FastDoublePropertyAtPut(index, value->Number()); |
+ } else { |
+ HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index)); |
+ ASSERT(box->IsMutableHeapNumber()); |
+ box->set_value(value->Number()); |
+ } |
} else { |
FastPropertyAtPut(index, value); |
} |
@@ -4656,8 +4672,7 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object, |
case FIELD: { |
Handle<Name> key(descs->GetKey(i)); |
FieldIndex index = FieldIndex::ForDescriptor(*map, i); |
- Handle<Object> value( |
- object->RawFastPropertyAt(index), isolate); |
+ Handle<Object> value(JSObject::RawFastBoxedPropertyAt(object, index)); |
if (details.representation().IsDouble()) { |
ASSERT(value->IsMutableHeapNumber()); |
Handle<HeapNumber> old = Handle<HeapNumber>::cast(value); |
@@ -4823,11 +4838,10 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object, |
int offset = current_offset - inobject_props; |
fields->set(offset, value); |
} |
- FieldDescriptor d(key, |
- current_offset++, |
- details.attributes(), |
+ FieldDescriptor d(key, current_offset, details.attributes(), |
// TODO(verwaest): value->OptimalRepresentation(); |
Representation::Tagged()); |
+ current_offset += d.GetDetails().field_width_in_words(); |
descriptors->Set(enumeration_index - 1, &d); |
} else if (type == CALLBACKS) { |
CallbacksDescriptor d(key, |
@@ -4843,8 +4857,11 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object, |
descriptors->Sort(); |
+ Handle<LayoutDescriptor> layout_descriptor = |
+ LayoutDescriptor::New(descriptors); |
+ |
DisallowHeapAllocation no_gc; |
- new_map->InitializeDescriptors(*descriptors); |
+ new_map->InitializeOwnDescriptors(*descriptors, *layout_descriptor); |
new_map->set_unused_property_fields(unused_property_fields); |
// Transform the object. |
@@ -5827,7 +5844,8 @@ Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, |
Representation representation, |
FieldIndex index) { |
Isolate* isolate = object->GetIsolate(); |
- Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); |
+ // TODO(ishell): unboxed double fields will be wrapped twice here. |
+ Handle<Object> raw_value(JSObject::RawFastBoxedPropertyAt(object, index)); |
return Object::WrapForRead(isolate, raw_value, representation); |
} |
@@ -5917,7 +5935,8 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( |
PropertyDetails details = descriptors->GetDetails(i); |
if (details.type() != FIELD) continue; |
FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i); |
- Handle<Object> value(object->RawFastPropertyAt(index), isolate); |
+ // TODO(ishell): avoid boxing if copying to unboxed double. |
+ Handle<Object> value = JSObject::RawFastBoxedPropertyAt(object, index); |
if (value->IsJSObject()) { |
ASSIGN_RETURN_ON_EXCEPTION( |
isolate, value, |
@@ -6160,16 +6179,17 @@ int Map::NumberOfDescribedProperties(DescriptorFlag which, |
int Map::NextFreePropertyIndex() { |
- int max_index = -1; |
+ int free_index = 0; |
int number_of_own_descriptors = NumberOfOwnDescriptors(); |
DescriptorArray* descs = instance_descriptors(); |
for (int i = 0; i < number_of_own_descriptors; i++) { |
- if (descs->GetType(i) == FIELD) { |
- int current_index = descs->GetFieldIndex(i); |
- if (current_index > max_index) max_index = current_index; |
+ PropertyDetails details = descs->GetDetails(i); |
+ if (details.type() == FIELD) { |
+ int candidate = details.field_index() + details.field_width_in_words(); |
+ if (candidate > free_index) free_index = candidate; |
} |
} |
- return max_index + 1; |
+ return free_index; |
} |
@@ -7008,17 +7028,27 @@ Object* JSObject::SlowReverseLookup(Object* value) { |
if (HasFastProperties()) { |
int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); |
DescriptorArray* descs = map()->instance_descriptors(); |
+ bool value_is_number = value->IsNumber(); |
for (int i = 0; i < number_of_own_descriptors; i++) { |
if (descs->GetType(i) == FIELD) { |
- Object* property = |
- RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i)); |
- if (descs->GetDetails(i).representation().IsDouble()) { |
- ASSERT(property->IsMutableHeapNumber()); |
- if (value->IsNumber() && property->Number() == value->Number()) { |
+ FieldIndex field_index = FieldIndex::ForDescriptor(map(), i); |
+ if (map()->IsUnboxedDoubleField(field_index)) { |
+ if (value_is_number) { |
+ double property = RawFastDoublePropertyAt(field_index); |
+ if (property == value->Number()) { |
+ return descs->GetKey(i); |
+ } |
+ } |
+ } else { |
+ Object* property = RawFastPropertyAt(field_index); |
+ if (field_index.is_double()) { |
+ ASSERT(property->IsMutableHeapNumber()); |
+ if (value_is_number && property->Number() == value->Number()) { |
+ return descs->GetKey(i); |
+ } |
+ } else if (property == value) { |
return descs->GetKey(i); |
} |
- } else if (property == value) { |
- return descs->GetKey(i); |
} |
} else if (descs->GetType(i) == CONSTANT) { |
if (descs->GetConstant(i) == value) { |
@@ -7169,12 +7199,15 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map, |
} |
} |
+ descriptors->Append(descriptor); |
+ Handle<LayoutDescriptor> layout_descriptor = |
+ LayoutDescriptor::New(descriptors); |
+ |
// Commit the state atomically. |
DisallowHeapAllocation no_gc; |
- descriptors->Append(descriptor); |
result->SetBackPointer(*map); |
- result->InitializeDescriptors(*descriptors); |
+ result->InitializeOwnDescriptors(*descriptors, *layout_descriptor); |
ASSERT(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1); |
@@ -7193,9 +7226,12 @@ Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map, |
ASSERT(descriptors->IsSortedNoDuplicates()); |
Handle<Map> result = CopyDropDescriptors(map); |
- result->InitializeDescriptors(*descriptors); |
if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) { |
+ Handle<LayoutDescriptor> layout_descriptor = |
+ LayoutDescriptor::New(descriptors); |
+ result->InitializeOwnDescriptors(*descriptors, *layout_descriptor); |
+ |
Handle<Name> name; |
CHECK(maybe_name.ToHandle(&name)); |
Handle<TransitionArray> transitions = TransitionArray::CopyInsert( |
@@ -7210,6 +7246,8 @@ Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map, |
descriptors->SetValue(i, HeapType::Any()); |
} |
} |
+ result->InitializeOwnDescriptors(*descriptors, |
+ LayoutDescriptor::FastPointerLayout()); |
} |
return result; |
@@ -7225,8 +7263,14 @@ Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map, |
Handle<Map> result = CopyDropDescriptors(map); |
- result->InitializeDescriptors(*descriptors); |
+ result->set_instance_descriptors(*descriptors); |
result->SetNumberOfOwnDescriptors(new_descriptor + 1); |
+ if (FLAG_unbox_double_fields) { |
+ Handle<LayoutDescriptor> layout_descriptor = |
+ LayoutDescriptor::New(descriptors); |
+ result->set_layout_descriptor(layout_descriptor->OptimizeFor(*result)); |
+ result->set_visitor_id(StaticVisitorBase::GetVisitorId(*result)); |
+ } |
int unused_property_fields = map->unused_property_fields(); |
if (descriptors->GetDetails(new_descriptor).type() == FIELD) { |
@@ -7273,10 +7317,14 @@ Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind, |
// transfer ownership to the new map. |
Handle<Map> new_map = CopyDropDescriptors(map); |
+ Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
+ Handle<LayoutDescriptor> layout_descriptor = |
+ LayoutDescriptor::New(descriptors); |
+ |
SetElementsTransitionMap(map, new_map); |
new_map->set_elements_kind(kind); |
- new_map->InitializeDescriptors(map->instance_descriptors()); |
+ new_map->InitializeOwnDescriptors(*descriptors, *layout_descriptor); |
new_map->SetBackPointer(*map); |
map->set_owns_descriptors(false); |
return new_map; |
@@ -7320,7 +7368,10 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) { |
new_map->set_is_observed(); |
if (map->owns_descriptors()) { |
- new_map->InitializeDescriptors(map->instance_descriptors()); |
Toon Verwaest
2014/07/29 15:02:09
This is overkill, set_instance_descriptors should
Igor Sheludko
2014/10/30 14:23:44
Done.
|
+ Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
+ Handle<LayoutDescriptor> layout_descriptor = |
+ LayoutDescriptor::New(descriptors); |
+ new_map->InitializeOwnDescriptors(*descriptors, *layout_descriptor); |
map->set_owns_descriptors(false); |
} |
@@ -8273,6 +8324,9 @@ Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate, |
Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size)); |
result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); |
+ if (FLAG_unbox_double_fields) { |
+ result->set(kLayoutDescriptorCacheIndex, *factory->undefined_value()); |
+ } |
result->set(kEnumCacheIndex, Smi::FromInt(0)); |
return Handle<DescriptorArray>::cast(result); |
} |
@@ -8304,8 +8358,7 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
} |
-void DescriptorArray::CopyFrom(int index, |
- DescriptorArray* src, |
+void DescriptorArray::CopyFrom(int index, DescriptorArray* src, |
const WhitenessWitness& witness) { |
Object* value = src->GetValue(index); |
PropertyDetails details = src->GetDetails(index); |
@@ -8375,6 +8428,66 @@ void DescriptorArray::Sort() { |
} |
+Handle<LayoutDescriptor> LayoutDescriptor::New( |
+ Handle<DescriptorArray> descriptors) { |
+ Isolate* isolate = descriptors->GetIsolate(); |
+ if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate); |
+ |
+ // Check cached layout descriptor in descriptors array. |
+ Object* cached = descriptors->cached_layout_descriptor(); |
+ if (cached != isolate->heap()->undefined_value()) { |
+ LayoutDescriptor* layout_descriptor = LayoutDescriptor::cast(cached); |
+ return handle(layout_descriptor, isolate); |
+ } |
+ |
+ int num_descriptors = descriptors->number_of_descriptors(); |
+ |
+ int layout_descriptor_length; |
+ |
+ const int kMaxWordsPerField = kDoubleSize / kPointerSize; |
+ |
+ if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) { |
+ // Even in the "worst" case (all fields are doubles) it would fit into |
+ // a Smi, so no need to calculate length. |
+ layout_descriptor_length = kSmiValueSize; |
+ |
+ } else { |
+ layout_descriptor_length = 0; |
+ |
+ for (int i = 0; i < num_descriptors; i++) { |
+ PropertyDetails details = descriptors->GetDetails(i); |
+ if (details.type() == FIELD) { |
+ if (layout_descriptor_length <= details.field_index()) { |
+ layout_descriptor_length = |
+ details.field_index() + details.field_width_in_words(); |
+ } |
+ } |
+ } |
+ } |
+ |
+ Handle<LayoutDescriptor> layout_descriptor_handle = |
+ LayoutDescriptor::New(isolate, layout_descriptor_length); |
+ |
+ DisallowHeapAllocation no_allocation; |
+ LayoutDescriptor* layout_descriptor = *layout_descriptor_handle; |
+ |
+ for (int i = 0; i < num_descriptors; i++) { |
+ PropertyDetails details = descriptors->GetDetails(i); |
+ if (details.type() == FIELD) { |
+ int field_index = details.field_index(); |
+ bool tagged = !details.representation().IsDouble(); |
+ layout_descriptor = layout_descriptor->SetTagged(field_index, tagged); |
+ if (details.field_width_in_words() > 1) { |
+ layout_descriptor = |
+ layout_descriptor->SetTagged(field_index + 1, tagged); |
+ } |
+ } |
+ } |
+ descriptors->set_cached_layout_descriptor(layout_descriptor); |
+ return handle(layout_descriptor, isolate); |
+} |
+ |
+ |
Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) { |
Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair(); |
copy->set_getter(pair->getter()); |