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

Unified Diff: src/objects.cc

Issue 10697015: Separating transitions from descriptors. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Using WhitenessWitness in TransitionArray code. Created 8 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 57483177854d3928d838967bf9c8a98adc7f6a54..03f5e553a4bf65981fc10858d904a1499947224e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -416,8 +416,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
}
case HANDLER:
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
+ case TRANSITION:
case NONEXISTENT:
UNREACHABLE();
}
@@ -641,9 +640,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
return result->holder()->GetPropertyWithInterceptor(
recvr, name, attributes);
}
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- break;
+ case TRANSITION:
case NONEXISTENT:
UNREACHABLE();
break;
@@ -1492,20 +1489,19 @@ String* JSReceiver::constructor_name() {
MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
String* name,
- Object* value) {
- int index = new_map->PropertyIndexFor(name);
+ Object* value,
+ int field_index) {
if (map()->unused_property_fields() == 0) {
- ASSERT(map()->unused_property_fields() == 0);
int new_unused = new_map->unused_property_fields();
- Object* values;
+ FixedArray* values;
{ MaybeObject* maybe_values =
properties()->CopySize(properties()->length() + new_unused + 1);
- if (!maybe_values->ToObject(&values)) return maybe_values;
+ if (!maybe_values->To(&values)) return maybe_values;
}
- set_properties(FixedArray::cast(values));
+ set_properties(values);
}
set_map(new_map);
- return FastPropertyAtPut(index, value);
+ return FastPropertyAtPut(field_index, value);
}
@@ -1551,10 +1547,10 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// Allocate new instance descriptors with (name, index) added
FieldDescriptor new_field(name, index, attributes);
- Object* new_descriptors;
+ DescriptorArray* new_descriptors;
{ MaybeObject* maybe_new_descriptors =
- old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
- if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
+ old_descriptors->CopyInsert(&new_field);
+ if (!maybe_new_descriptors->To(&new_descriptors)) {
return maybe_new_descriptors;
}
}
@@ -1562,7 +1558,7 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// Only allow map transition if the object isn't the global object and there
// is not a transition for the name, or there's a transition for the name but
// it's unrelated to properties.
- int descriptor_index = old_descriptors->Search(name);
+ int descriptor_index = old_descriptors->SearchWithCache(name);
// Element transitions are stored in the descriptor for property "", which is
// not a identifier and should have forced a switch to slow properties above.
@@ -1580,14 +1576,13 @@ MaybeObject* JSObject::AddFastProperty(String* name,
if (!maybe_r->ToObject(&r)) return maybe_r;
}
Map* new_map = Map::cast(r);
+
+ TransitionArray* new_transitions = NULL;
if (allow_map_transition) {
- // Allocate new instance descriptors for the old map with map transition.
- MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
- Object* r;
- { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
- if (!maybe_r->ToObject(&r)) return maybe_r;
+ MaybeObject* maybe_new_transitions = map()->AddTransition(name, new_map);
+ if (!maybe_new_transitions->To(&new_transitions)) {
+ return maybe_new_transitions;
}
- old_descriptors = DescriptorArray::cast(r);
}
if (map()->unused_property_fields() == 0) {
@@ -1610,13 +1605,13 @@ MaybeObject* JSObject::AddFastProperty(String* name,
} else {
new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
}
- // We have now allocated all the necessary objects.
- // All the changes can be applied at once, so they are atomic.
+ // Apply all changes at once, so they are atomic.
if (allow_map_transition) {
- map()->set_instance_descriptors(old_descriptors);
+ MaybeObject* transition_added = map()->set_transitions(new_transitions);
+ if (transition_added->IsFailure()) return transition_added;
}
+ new_map->set_instance_descriptors(new_descriptors);
new_map->SetBackPointer(map());
- new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
set_map(new_map);
return FastPropertyAtPut(index, value);
}
@@ -1628,24 +1623,23 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
PropertyAttributes attributes) {
// Allocate new instance descriptors with (name, function) added
ConstantFunctionDescriptor d(name, function, attributes);
- Object* new_descriptors;
+ DescriptorArray* new_descriptors;
{ MaybeObject* maybe_new_descriptors =
- map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
- if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
+ map()->instance_descriptors()->CopyInsert(&d);
+ if (!maybe_new_descriptors->To(&new_descriptors)) {
return maybe_new_descriptors;
}
}
// Allocate a new map for the object.
- Object* new_map;
+ Map* new_map;
{ MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
- if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
}
- DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
- Map::cast(new_map)->set_instance_descriptors(descriptors);
+ new_map->set_instance_descriptors(new_descriptors);
Map* old_map = map();
- set_map(Map::cast(new_map));
+ set_map(new_map);
// If the old map is the global object map (from new Object()),
// then transitions are not added to it, so we are done.
@@ -1655,29 +1649,36 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
return function;
}
- // Do not add CONSTANT_TRANSITIONS to global objects
+ // Do not add constant transitions to global objects
if (IsGlobalObject()) {
return function;
}
- // Add a CONSTANT_TRANSITION descriptor to the old map,
- // so future assignments to this property on other objects
- // of the same type will create a normal field, not a constant function.
- // Don't do this for special properties, with non-trival attributes.
+ // Add a constant transition to the old map, so future assignments to this
+ // property on other objects of the same type will create a normal field, not
+ // a constant function. Don't do this for special properties, with non-trival
+ // attributes.
if (attributes != NONE) {
return function;
}
- ConstTransitionDescriptor mark(name, Map::cast(new_map));
- { MaybeObject* maybe_new_descriptors =
- old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
- if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
+
+ TransitionArray* new_transitions;
+ { MaybeObject* maybe_new_transitions =
+ old_map->AddTransition(name, new_map);
+ if (!maybe_new_transitions->To(&new_transitions)) {
// We have accomplished the main goal, so return success.
return function;
}
}
- old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
- Map::cast(new_map)->SetBackPointer(old_map);
+ { MaybeObject* transition_added = old_map->set_transitions(new_transitions);
+ // We have accomplished the main goal, so return success.
+ if (transition_added->IsFailure()) {
+ return function;
+ }
+ }
+
+ new_map->SetBackPointer(old_map);
return function;
}
@@ -1798,7 +1799,6 @@ MaybeObject* JSObject::ReplaceSlowProperty(String* name,
int new_enumeration_index = 0; // 0 means "Use the next available index."
if (old_index != -1) {
// All calls to ReplaceSlowProperty have had all transitions removed.
- ASSERT(!dictionary->ContainsTransition(old_index));
new_enumeration_index = dictionary->DetailsAt(old_index).index();
}
@@ -1813,33 +1813,40 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
PropertyAttributes attributes) {
Map* old_map = map();
Object* result;
+
{ MaybeObject* maybe_result =
ConvertDescriptorToField(name, new_value, attributes);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ if (!maybe_result->To(&result)) return maybe_result;
}
+
// If we get to this point we have succeeded - do not return failure
// after this point. Later stuff is optional.
if (!HasFastProperties()) {
return result;
}
+
// Do not add transitions to the map of "new Object()".
if (map() == GetIsolate()->context()->global_context()->
object_function()->map()) {
return result;
}
- MapTransitionDescriptor transition(name,
- map(),
- attributes);
- Object* new_descriptors;
- { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
- CopyInsert(&transition, KEEP_TRANSITIONS);
- if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
- return result; // Yes, return _result_.
+ TransitionArray* new_transitions;
+ { MaybeObject* maybe_new_transitions = old_map->AddTransition(name, map());
+ if (!maybe_new_transitions->To(&new_transitions)) {
+ // We have accomplished the main goal, so return success.
+ return result;
+ }
+ }
+
+ { MaybeObject* transition_added = old_map->set_transitions(new_transitions);
+ // Return success if failure since we accomplished the main goal. Otherwise
+ // also set backpointer.
+ if (!transition_added->IsFailure()) {
+ map()->SetBackPointer(old_map);
}
}
- old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
- map()->SetBackPointer(old_map);
+
return result;
}
@@ -1861,8 +1868,8 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name,
FieldDescriptor new_field(name, index, attributes);
// Make a new DescriptorArray replacing an entry with FieldDescriptor.
Object* descriptors_unchecked;
- { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
- CopyInsert(&new_field, REMOVE_TRANSITIONS);
+ { MaybeObject* maybe_descriptors_unchecked =
+ map()->instance_descriptors()->CopyInsert(&new_field);
if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
return maybe_descriptors_unchecked;
}
@@ -2156,9 +2163,7 @@ MaybeObject* JSObject::SetPropertyViaPrototypes(
return result.proxy()->SetPropertyViaPrototypesWithHandler(
this, name, value, attributes, strict_mode, done);
}
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- break;
+ case TRANSITION:
case NONEXISTENT:
UNREACHABLE();
break;
@@ -2177,33 +2182,44 @@ MaybeObject* JSObject::SetPropertyViaPrototypes(
}
-void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
- DescriptorArray* descriptors = map()->instance_descriptors();
+void Map::LookupDescriptor(JSObject* holder,
+ String* name,
+ LookupResult* result) {
+ DescriptorArray* descriptors = this->instance_descriptors();
int number = descriptors->SearchWithCache(name);
if (number != DescriptorArray::kNotFound) {
- result->DescriptorResult(this, descriptors->GetDetails(number), number);
+ result->DescriptorResult(holder, descriptors->GetDetails(number), number);
} else {
result->NotFound();
}
}
-void Map::LookupInDescriptors(JSObject* holder,
- String* name,
- LookupResult* result) {
- DescriptorArray* descriptors = instance_descriptors();
- DescriptorLookupCache* cache =
- GetHeap()->isolate()->descriptor_lookup_cache();
- int number = cache->Lookup(descriptors, name);
- if (number == DescriptorLookupCache::kAbsent) {
- number = descriptors->Search(name);
- cache->Update(descriptors, name, number);
- }
- if (number != DescriptorArray::kNotFound) {
- result->DescriptorResult(holder, descriptors->GetDetails(number), number);
- } else {
- result->NotFound();
+void Map::LookupTransition(JSObject* holder,
+ String* name,
+ LookupResult* result) {
+ if (HasTransitionArray()) {
+ TransitionArray* transition_array = transitions();
+ int number = transition_array->Search(name);
+ if (number != TransitionArray::kNotFound) {
+ return result->TransitionResult(holder, number);
+ }
}
+ result->NotFound();
+}
+
+
+void Map::LookupTransitionOrDescriptor(JSObject* holder,
+ String* name,
+ LookupResult* result) {
+ // AccessorPairs containing both a Descriptor and a Transition are shared
+ // between the DescriptorArray and the Transition array. This is why looking
+ // up the AccessorPair solely in the DescriptorArray works.
+ // TODO(verwaest) This should be implemented differently so the
+ // DescriptorArray is free of transitions; and so we can freely share it.
+ this->LookupDescriptor(holder, name, result);
+ if (result->IsFound()) return;
+ this->LookupTransition(holder, name, result);
}
@@ -2256,21 +2272,16 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
ASSERT(index <= to_index);
for (; index < to_index; ++index) {
- Map* next_map = current_map->elements_transition_map();
- if (next_map == NULL) {
- return current_map;
- }
- current_map = next_map;
+ if (!current_map->HasElementsTransition()) return current_map;
+ current_map = current_map->elements_transition_map();
}
- if (!IsFastElementsKind(to_kind)) {
+ if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
Map* next_map = current_map->elements_transition_map();
- if (next_map != NULL && next_map->elements_kind() == to_kind) {
- return next_map;
- }
- ASSERT(current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
- } else {
- ASSERT(current_map->elements_kind() == to_kind);
+ if (next_map->elements_kind() == to_kind) return next_map;
}
+ ASSERT(IsFastElementsKind(to_kind)
+ ? current_map->elements_kind() == to_kind
+ : current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
return current_map;
}
@@ -2283,7 +2294,7 @@ Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) {
- ASSERT(elements_transition_map() == NULL ||
+ ASSERT(!HasElementsTransition() ||
((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
IsExternalArrayElementsKind(
elements_transition_map()->elements_kind())) &&
@@ -2294,13 +2305,17 @@ MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) {
ASSERT(next_kind != elements_kind());
Map* next_map;
- MaybeObject* maybe_next_map =
- this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED);
- if (!maybe_next_map->To(&next_map)) return maybe_next_map;
+ { MaybeObject* maybe_next_map =
+ this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED);
+ if (!maybe_next_map->To(&next_map)) return maybe_next_map;
+ }
+
+ { MaybeObject* added_elements = this->set_elements_transition_map(next_map);
+ if (added_elements->IsFailure()) return added_elements;
+ }
next_map->set_elements_kind(next_kind);
next_map->SetBackPointer(this);
- this->set_elements_transition_map(next_map);
return next_map;
}
@@ -2346,22 +2361,6 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
}
-// If the map is using the empty descriptor array, install a new empty
-// descriptor array that will contain an element transition.
-// TODO(verwaest) Goes away once the descriptor array is immutable.
-static MaybeObject* EnsureMayContainTransitions(Map* map) {
- if (map->instance_descriptors()->MayContainTransitions()) return map;
- DescriptorArray* descriptor_array;
- MaybeObject* maybe_descriptor_array =
- DescriptorArray::Allocate(0, DescriptorArray::CANNOT_BE_SHARED);
- if (!maybe_descriptor_array->To(&descriptor_array)) {
- return maybe_descriptor_array;
- }
- map->set_instance_descriptors(descriptor_array);
- return map;
-}
-
-
MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
Map* start_map = map();
ElementsKind from_kind = start_map->elements_kind();
@@ -2396,7 +2395,6 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
return new_map;
}
- EnsureMayContainTransitions(start_map);
Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
if (closest_map->elements_kind() == to_kind) {
@@ -2418,41 +2416,40 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
}
if (HasFastProperties()) {
- LookupInDescriptor(name, result);
- if (result->IsFound()) {
- // A property, a map transition or a null descriptor was found.
- // We return all of these result types because
- // LocalLookupRealNamedProperty is used when setting properties
- // where map transitions and null descriptors are handled.
- ASSERT(result->holder() == this && result->IsFastPropertyType());
- // Disallow caching for uninitialized constants. These can only
- // occur as fields.
- if (result->IsField() &&
- result->IsReadOnly() &&
- FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
- result->DisallowCaching();
- }
- return;
+ map()->LookupTransitionOrDescriptor(this, name, result);
+ // A property or a map transition was found. We return all of these result
+ // types because LocalLookupRealNamedProperty is used when setting
+ // properties where map transitions are handled.
+ ASSERT(!result->IsFound() ||
+ (result->holder() == this && result->IsFastPropertyType()));
+ // Disallow caching for uninitialized constants. These can only
+ // occur as fields.
+ if (result->IsField() &&
+ result->IsReadOnly() &&
+ FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
+ result->DisallowCaching();
}
- } else {
- int entry = property_dictionary()->FindEntry(name);
- if (entry != StringDictionary::kNotFound) {
- Object* value = property_dictionary()->ValueAt(entry);
- if (IsGlobalObject()) {
- PropertyDetails d = property_dictionary()->DetailsAt(entry);
- if (d.IsDeleted()) {
- result->NotFound();
- return;
- }
- value = JSGlobalPropertyCell::cast(value)->value();
+ return;
+ }
+
+ int entry = property_dictionary()->FindEntry(name);
+ if (entry != StringDictionary::kNotFound) {
+ Object* value = property_dictionary()->ValueAt(entry);
+ if (IsGlobalObject()) {
+ PropertyDetails d = property_dictionary()->DetailsAt(entry);
+ if (d.IsDeleted()) {
+ result->NotFound();
+ return;
}
- // Make sure to disallow caching for uninitialized constants
- // found in the dictionary-mode objects.
- if (value->IsTheHole()) result->DisallowCaching();
- result->DictionaryResult(this, entry);
- return;
+ value = JSGlobalPropertyCell::cast(value)->value();
}
+ // Make sure to disallow caching for uninitialized constants
+ // found in the dictionary-mode objects.
+ if (value->IsTheHole()) result->DisallowCaching();
+ result->DictionaryResult(this, entry);
+ return;
}
+
result->NotFound();
}
@@ -2879,7 +2876,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
// Neither properties nor transitions found.
return AddProperty(name, value, attributes, strict_mode, store_mode);
}
- if (result->IsReadOnly() && result->IsProperty()) {
+ if (result->IsProperty() && result->IsReadOnly()) {
if (strict_mode == kStrictMode) {
Handle<JSObject> self(this);
Handle<String> hname(name);
@@ -2890,6 +2887,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
return value;
}
}
+
// This is a real property that is not read-only, or it is a
// transition or null descriptor and there are no setters in the prototypes.
switch (result->type()) {
@@ -2897,14 +2895,6 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
return SetNormalizedProperty(result, value);
case FIELD:
return FastPropertyAtPut(result->GetFieldIndex(), value);
- case MAP_TRANSITION:
- if (attributes == result->GetAttributes()) {
- // Only use map transition if the attributes match.
- return AddFastPropertyUsingMap(result->GetTransitionMap(),
- name,
- value);
- }
- return ConvertDescriptorToField(name, value, attributes);
case CONSTANT_FUNCTION:
// Only replace the function if necessary.
if (value == result->GetConstantFunction()) return value;
@@ -2913,10 +2903,6 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
return ConvertDescriptorToField(name, value, attributes);
case CALLBACKS: {
Object* callback_object = result->GetCallbackObject();
- if (callback_object->IsAccessorPair() &&
- !AccessorPair::cast(callback_object)->ContainsAccessor()) {
- return ConvertDescriptorToField(name, value, attributes);
- }
return SetPropertyWithCallback(callback_object,
name,
value,
@@ -2925,23 +2911,49 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
}
case INTERCEPTOR:
return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
- case CONSTANT_TRANSITION: {
+ case TRANSITION: {
+ Object* transition = result->GetTransitionValue();
+
+ if (transition->IsAccessorPair()) {
+ if (!AccessorPair::cast(transition)->ContainsAccessor()) {
+ return ConvertDescriptorToField(name, value, attributes);
+ }
+ return SetPropertyWithCallback(transition,
+ name,
+ value,
+ result->holder(),
+ strict_mode);
+ }
+
+ Map* transition_map = Map::cast(transition);
+ DescriptorArray* descriptors = transition_map->instance_descriptors();
+ int descriptor = descriptors->SearchWithCache(name);
+ PropertyDetails details = descriptors->GetDetails(descriptor);
+ ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION);
+
+ if (details.type() == FIELD) {
+ if (attributes == details.attributes()) {
+ int field_index = descriptors->GetFieldIndex(descriptor);
+ return AddFastPropertyUsingMap(transition_map,
+ name,
+ value,
+ field_index);
+ }
+ return ConvertDescriptorToField(name, value, attributes);
+ }
+
+ // Is transition to CONSTANT_FUNCTION.
+ Object* constant_function = descriptors->GetValue(descriptor);
// If the same constant function is being added we can simply
// transition to the target map.
- Map* target_map = result->GetTransitionMap();
- DescriptorArray* target_descriptors = target_map->instance_descriptors();
- int number = target_descriptors->SearchWithCache(name);
- ASSERT(number != DescriptorArray::kNotFound);
- ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
- JSFunction* function =
- JSFunction::cast(target_descriptors->GetValue(number));
- if (value == function) {
- set_map(target_map);
- return value;
+ if (constant_function == value) {
+ set_map(transition_map);
+ return this;
}
- // Otherwise, replace with a MAP_TRANSITION to a new map with a
- // FIELD, even if the value is a constant function.
- return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+ // Otherwise, replace with a map transition to a new map with a FIELD,
+ // even if the value is a constant function.
+ return ConvertDescriptorToFieldAndMapTransition(
+ name, value, attributes);
}
case HANDLER:
case NONEXISTENT:
@@ -3011,22 +3023,14 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
return AddProperty(name, value, attributes, kNonStrictMode);
}
- PropertyDetails details = PropertyDetails(attributes, NORMAL);
-
// Check of IsReadOnly removed from here in clone.
switch (result.type()) {
- case NORMAL:
+ case NORMAL: {
+ PropertyDetails details = PropertyDetails(attributes, NORMAL);
return SetNormalizedProperty(name, value, details);
+ }
case FIELD:
return FastPropertyAtPut(result.GetFieldIndex(), value);
- case MAP_TRANSITION:
- if (attributes == result.GetAttributes()) {
- // Only use map transition if the attributes match.
- return AddFastPropertyUsingMap(result.GetTransitionMap(),
- name,
- value);
- }
- return ConvertDescriptorToField(name, value, attributes);
case CONSTANT_FUNCTION:
// Only replace the function if necessary.
if (value == result.GetConstantFunction()) return value;
@@ -3037,10 +3041,34 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
case INTERCEPTOR:
// Override callback in clone
return ConvertDescriptorToField(name, value, attributes);
- case CONSTANT_TRANSITION:
- // Replace with a MAP_TRANSITION to a new map with a FIELD, even
- // if the value is a function.
+ case TRANSITION: {
+ Object* transition = result.GetTransitionValue();
+
+ if (transition->IsAccessorPair()) {
+ return ConvertDescriptorToField(name, value, attributes);
+ }
+
+ Map* transition_map = Map::cast(transition);
+ DescriptorArray* descriptors = transition_map->instance_descriptors();
+ int descriptor = descriptors->Search(name);
+ PropertyDetails details = descriptors->GetDetails(descriptor);
+ ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION);
+
+ if (details.type() == FIELD) {
+ if (attributes == details.attributes()) {
+ int field_index = descriptors->GetFieldIndex(descriptor);
+ return AddFastPropertyUsingMap(transition_map,
+ name,
+ value,
+ field_index);
+ }
+ return ConvertDescriptorToField(name, value, attributes);
+ }
+
+ // Was transition to CONSTANT_FUNCTION. Replace with a map transition to a
+ // new map with a FIELD, even if the value is a function.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+ }
case HANDLER:
case NONEXISTENT:
UNREACHABLE();
@@ -3164,7 +3192,8 @@ PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
case INTERCEPTOR:
return result->holder()->GetPropertyAttributeWithInterceptor(
JSObject::cast(receiver), name, continue_search);
- default:
+ case TRANSITION:
+ case NONEXISTENT:
UNREACHABLE();
}
}
@@ -3321,7 +3350,6 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
break;
}
case CALLBACKS: {
- if (!descs->IsProperty(i)) break;
Object* value = descs->GetCallbacksObject(i);
if (value->IsAccessorPair()) {
MaybeObject* maybe_copy =
@@ -3333,12 +3361,11 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
break;
}
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
case INTERCEPTOR:
break;
case HANDLER:
case NORMAL:
+ case TRANSITION:
case NONEXISTENT:
UNREACHABLE();
break;
@@ -3678,13 +3705,10 @@ MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
DescriptorArray* descriptors = this->map()->instance_descriptors();
if ((descriptors->number_of_descriptors() > 0) &&
(descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
- if (descriptors->GetType(0) == FIELD) {
- Object* hidden_store =
- this->FastPropertyAt(descriptors->GetFieldIndex(0));
- return StringDictionary::cast(hidden_store);
- } else {
- ASSERT(descriptors->GetType(0) == MAP_TRANSITION);
- }
+ ASSERT(descriptors->GetType(0) == FIELD);
+ Object* hidden_store =
+ this->FastPropertyAt(descriptors->GetFieldIndex(0));
+ return StringDictionary::cast(hidden_store);
}
} else {
PropertyAttributes attributes;
@@ -3727,12 +3751,9 @@ MaybeObject* JSObject::SetHiddenPropertiesDictionary(
DescriptorArray* descriptors = this->map()->instance_descriptors();
if ((descriptors->number_of_descriptors() > 0) &&
(descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
- if (descriptors->GetType(0) == FIELD) {
- this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
- return this;
- } else {
- ASSERT(descriptors->GetType(0) == MAP_TRANSITION);
- }
+ ASSERT(descriptors->GetType(0) == FIELD);
+ this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
+ return this;
}
}
MaybeObject* store_result =
@@ -4167,7 +4188,7 @@ int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
DescriptorArray* descs = instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
PropertyDetails details = descs->GetDetails(i);
- if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
+ if ((details.attributes() & filter) == 0) {
result++;
}
}
@@ -4373,7 +4394,7 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
MaybeObject* JSObject::CreateAccessorPairFor(String* name) {
LookupResult result(GetHeap()->isolate());
LocalLookupRealNamedProperty(name, &result);
- if (result.IsProperty() && result.IsCallbacks()) {
+ if (result.IsPropertyCallbacks()) {
// Note that the result can actually have IsDontDelete() == true when we
// e.g. have to fall back to the slow case while adding a setter after
// successfully reusing a map transition for a getter. Nevertheless, this is
@@ -4582,8 +4603,7 @@ static MaybeObject* CreateFreshAccessor(JSObject* obj,
CallbacksDescriptor callbacks_descr2(name, accessors2, attributes);
DescriptorArray* descriptors2;
{ MaybeObject* maybe_descriptors2 =
- map1->instance_descriptors()->CopyInsert(&callbacks_descr2,
- REMOVE_TRANSITIONS);
+ map1->instance_descriptors()->CopyInsert(&callbacks_descr2);
if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2;
}
@@ -4603,18 +4623,20 @@ static MaybeObject* CreateFreshAccessor(JSObject* obj,
// step 5: create a copy of the descriptors, incl. the new getter/setter pair
// with the transition
- CallbacksDescriptor callbacks_descr1(name, accessors1, attributes);
- DescriptorArray* descriptors1;
- { MaybeObject* maybe_descriptors1 =
- map1->instance_descriptors()->CopyInsert(&callbacks_descr1,
- KEEP_TRANSITIONS);
- if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1;
+ TransitionArray* new_transitions;
+ { MaybeObject* maybe_new_transitions = map1->AddTransition(name, accessors1);
+ if (!maybe_new_transitions->To(&new_transitions)) {
+ return maybe_new_transitions;
+ }
}
// step 6: everything went well so far, so we make our changes visible
- obj->set_map(map2);
- map1->set_instance_descriptors(descriptors1);
+ { MaybeObject* transition_added = map1->set_transitions(new_transitions);
+ if (transition_added->IsFailure()) return transition_added;
+ }
+
map2->SetBackPointer(map1);
+ obj->set_map(map2);
return obj;
}
@@ -4652,8 +4674,7 @@ static MaybeObject* NewCallbackTransition(JSObject* obj,
CallbacksDescriptor callbacks_descr3(name, accessors3, attributes);
DescriptorArray* descriptors3;
{ MaybeObject* maybe_descriptors3 =
- map2->instance_descriptors()->CopyInsert(&callbacks_descr3,
- REMOVE_TRANSITIONS);
+ map2->instance_descriptors()->CopyInsert(&callbacks_descr3);
if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3;
}
@@ -4664,10 +4685,20 @@ static MaybeObject* NewCallbackTransition(JSObject* obj,
}
map3->set_instance_descriptors(descriptors3);
- // step 4: everything went well so far, so we make our changes visible
+ // step 4: add a new transition to the new map
+ TransitionArray* new_transitions;
+ { MaybeObject* maybe_transitions = map2->AddTransition(name, accessors2);
+ if (!maybe_transitions->To(&new_transitions)) return maybe_transitions;
+ }
+
+ // step 5: everything went well so far, so we make our changes visible
+ { MaybeObject* transition_added = map2->set_transitions(new_transitions);
+ if (transition_added->IsFailure()) return transition_added;
+ }
+
+ map3->SetBackPointer(map2);
obj->set_map(map3);
accessors2->set(component, map3);
- map3->SetBackPointer(map2);
return obj;
}
@@ -4686,7 +4717,8 @@ MaybeObject* JSObject::DefineFastAccessor(String* name,
}
// If the property is not a JavaScript accessor, fall back to the slow case.
- if (result.type() != CALLBACKS) return GetHeap()->null_value();
+ if (!result.IsCallbacks()) return GetHeap()->null_value();
+
Object* callback_value = result.GetCallbackObject();
if (!callback_value->IsAccessorPair()) return GetHeap()->null_value();
AccessorPair* accessors = AccessorPair::cast(callback_value);
@@ -4699,7 +4731,6 @@ MaybeObject* JSObject::DefineFastAccessor(String* name,
return this;
}
- // When we re-add the same accessor again, there is nothing to do.
if (entry == accessor && result.GetAttributes() == attributes) return this;
// Only the other accessor has been set so far, create a new transition.
@@ -4741,9 +4772,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
// Try to flatten before operating on the string.
name->TryFlatten();
- if (!CanSetCallback(name)) {
- return isolate->heap()->undefined_value();
- }
+ if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
uint32_t index = 0;
bool is_element = name->AsArrayIndex(&index);
@@ -4843,7 +4872,7 @@ Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
JSObject::cast(obj)->LocalLookup(name, &result);
if (result.IsProperty()) {
if (result.IsReadOnly()) return heap->undefined_value();
- if (result.IsCallbacks()) {
+ if (result.IsPropertyCallbacks()) {
Object* obj = result.GetCallbackObject();
if (obj->IsAccessorPair()) {
return AccessorPair::cast(obj)->GetComponent(component);
@@ -4903,7 +4932,7 @@ MaybeObject* Map::CopyDropDescriptors() {
JSFunction* ctor = JSFunction::cast(constructor());
Object* descriptors;
{ MaybeObject* maybe_descriptors =
- ctor->initial_map()->instance_descriptors()->RemoveTransitions(
+ ctor->initial_map()->instance_descriptors()->Copy(
DescriptorArray::MAY_BE_SHARED);
if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
}
@@ -4966,7 +4995,7 @@ MaybeObject* Map::CopyDropTransitions(
}
Object* descriptors;
{ MaybeObject* maybe_descriptors =
- instance_descriptors()->RemoveTransitions(shared_mode);
+ instance_descriptors()->Copy(shared_mode);
if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
}
cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
@@ -5030,18 +5059,16 @@ void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
// field of the contens array while it is running.
class IntrusiveMapTransitionIterator {
public:
- explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
- : descriptor_array_(descriptor_array) { }
+ explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
+ : transition_array_(transition_array) { }
void Start() {
ASSERT(!IsIterating());
- if (descriptor_array_->MayContainTransitions())
- *DescriptorArrayHeader() = Smi::FromInt(0);
+ *TransitionArrayHeader() = Smi::FromInt(0);
}
bool IsIterating() {
- return descriptor_array_->MayContainTransitions() &&
- (*DescriptorArrayHeader())->IsSmi();
+ return (*TransitionArrayHeader())->IsSmi();
}
Map* Next() {
@@ -5051,66 +5078,51 @@ class IntrusiveMapTransitionIterator {
// next descriptor by adding 2 to the index. The exceptions are the
// CALLBACKS entries: An even index means we look at its getter, and an odd
// index means we look at its setter.
- int raw_index = Smi::cast(*DescriptorArrayHeader())->value();
+ int raw_index = Smi::cast(*TransitionArrayHeader())->value();
int index = raw_index / 2;
- int number_of_descriptors = descriptor_array_->number_of_descriptors();
- while (index < number_of_descriptors) {
- PropertyDetails details(descriptor_array_->GetDetails(index));
- switch (details.type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- // We definitely have a map transition.
- *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2);
- return static_cast<Map*>(descriptor_array_->GetValue(index));
- case CALLBACKS: {
- // We might have a map transition in a getter or in a setter.
- AccessorPair* accessors =
- static_cast<AccessorPair*>(descriptor_array_->GetValue(index));
- Object* accessor;
- if ((raw_index & 1) == 0) {
- accessor = accessors->setter();
- } else {
- ++index;
- accessor = accessors->getter();
- }
- ++raw_index;
- if (accessor->IsMap()) {
- *DescriptorArrayHeader() = Smi::FromInt(raw_index);
- return static_cast<Map*>(accessor);
- }
- break;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- // We definitely have no map transition.
- raw_index += 2;
- ++index;
- break;
- case NONEXISTENT:
- UNREACHABLE();
- break;
+ int number_of_transitions = transition_array_->number_of_transitions();
+ while (index < number_of_transitions) {
+ Object* value = transition_array_->GetValue(index);
+
+ if (value->IsMap()) {
+ *TransitionArrayHeader() = Smi::FromInt(raw_index + 2);
+ return static_cast<Map*>(value);
}
- }
- if (index == descriptor_array_->number_of_descriptors()) {
- Map* elements_transition = descriptor_array_->elements_transition_map();
- if (elements_transition != NULL) {
- *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2);
- return elements_transition;
+
+ ASSERT(value->IsAccessorPair());
+
+ // We might have a map transition in a getter or in a setter.
+ AccessorPair* accessors = static_cast<AccessorPair*>(value);
+ Object* accessor;
+ if ((raw_index & 1) == 0) {
+ accessor = accessors->setter();
+ } else {
+ ++index;
+ accessor = accessors->getter();
}
+ ++raw_index;
+ if (accessor->IsMap()) {
+ *TransitionArrayHeader() = Smi::FromInt(raw_index);
+ return static_cast<Map*>(accessor);
+ }
+ }
+
+ if (index == transition_array_->number_of_transitions() &&
+ transition_array_->HasElementsTransition()) {
+ Map* elements_transition = transition_array_->elements_transition();
+ *TransitionArrayHeader() = Smi::FromInt(raw_index + 2);
+ return elements_transition;
}
- *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map();
+ *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
return NULL;
}
private:
- Object** DescriptorArrayHeader() {
- return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset);
+ Object** TransitionArrayHeader() {
+ return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
}
- DescriptorArray* descriptor_array_;
+ TransitionArray* transition_array_;
};
@@ -5210,22 +5222,19 @@ class TraversableMap : public Map {
// Can either be Smi (no instance descriptors), or a descriptor array with the
// header overwritten as a Smi (thus iterating).
- DescriptorArray* MutatedInstanceDescriptors() {
- Object* object =
- *HeapObject::RawField(this, kInstanceDescriptorsOrBitField3Offset);
- if (object->IsSmi()) {
- return GetHeap()->empty_descriptor_array();
- } else {
- DescriptorArray* descriptor_array =
- static_cast<DescriptorArray*>(object);
- return descriptor_array;
- }
+ TransitionArray* MutatedTransitions() {
+ Object* object = *HeapObject::RawField(instance_descriptors(),
+ DescriptorArray::kTransitionsOffset);
+ TransitionArray* transition_array = static_cast<TransitionArray*>(object);
+ return transition_array;
}
// Start iterating over this map's children, possibly destroying a FixedArray
// map (see explanation above).
void ChildIteratorStart() {
- IntrusiveMapTransitionIterator(instance_descriptors()).Start();
+ if (HasTransitionArray()) {
+ IntrusiveMapTransitionIterator(transitions()).Start();
+ }
IntrusivePrototypeTransitionIterator(
unchecked_prototype_transitions()).Start();
}
@@ -5239,11 +5248,13 @@ class TraversableMap : public Map {
Map* next = proto_iterator.Next();
if (next != NULL) return static_cast<TraversableMap*>(next);
}
- IntrusiveMapTransitionIterator
- descriptor_iterator(MutatedInstanceDescriptors());
- if (descriptor_iterator.IsIterating()) {
- Map* next = descriptor_iterator.Next();
- if (next != NULL) return static_cast<TraversableMap*>(next);
+ if (HasTransitionArray()) {
+ IntrusiveMapTransitionIterator
+ transitions_iterator(MutatedTransitions());
+ if (transitions_iterator.IsIterating()) {
+ Map* next = transitions_iterator.Next();
+ if (next != NULL) return static_cast<TraversableMap*>(next);
+ }
}
return NULL;
}
@@ -5872,71 +5883,46 @@ MaybeObject* DescriptorArray::CopyFrom(int dst_index,
}
-MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
- TransitionFlag transition_flag) {
- // Transitions are only kept when inserting another transition.
- // This precondition is not required by this function's implementation, but
- // is currently required by the semantics of maps, so we check it.
- // Conversely, we filter after replacing, so replacing a transition and
- // removing all other transitions is not supported.
- bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
- ASSERT(remove_transitions == !descriptor->ContainsTransition());
-
+MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) {
// Ensure the key is a symbol.
{ MaybeObject* maybe_result = descriptor->KeyToSymbol();
if (maybe_result->IsFailure()) return maybe_result;
}
- int new_size = 0;
- for (int i = 0; i < number_of_descriptors(); i++) {
- if (remove_transitions && IsTransitionOnly(i)) continue;
- new_size++;
- }
+ int new_size = number_of_descriptors();
// If key is in descriptor, we replace it in-place when filtering.
// Count a null descriptor for key as inserted, not replaced.
- int index = Search(descriptor->GetKey());
+ int index = SearchWithCache(descriptor->GetKey());
const bool replacing = (index != kNotFound);
bool keep_enumeration_index = false;
- if (!replacing) {
- ++new_size;
- } else if (!IsTransitionOnly(index)) {
+ if (replacing) {
// We are replacing an existing descriptor. We keep the enumeration index
// of a visible property.
keep_enumeration_index = true;
- } else if (remove_transitions) {
- // Replaced descriptor has been counted as removed if it is a transition
- // that will be replaced. Adjust count in this case.
+ } else {
++new_size;
}
DescriptorArray* new_descriptors;
- { SharedMode mode = remove_transitions ? MAY_BE_SHARED : CANNOT_BE_SHARED;
- MaybeObject* maybe_result = Allocate(new_size, mode);
+ { MaybeObject* maybe_result = Allocate(new_size, MAY_BE_SHARED);
if (!maybe_result->To(&new_descriptors)) return maybe_result;
}
- DescriptorArray::WhitenessWitness witness(new_descriptors);
+ FixedArray::WhitenessWitness witness(new_descriptors);
// Set the enumeration index in the descriptors and set the enumeration index
// in the result.
int enumeration_index = NextEnumerationIndex();
- if (!descriptor->ContainsTransition()) {
- if (keep_enumeration_index) {
- descriptor->SetEnumerationIndex(GetDetails(index).index());
- } else {
- descriptor->SetEnumerationIndex(enumeration_index);
- ++enumeration_index;
- }
- }
- Map* old_elements_transition = elements_transition_map();
- if ((!remove_transitions) && (old_elements_transition != NULL)) {
- new_descriptors->set_elements_transition_map(old_elements_transition);
+ if (keep_enumeration_index) {
+ descriptor->SetEnumerationIndex(GetDetails(index).index());
+ } else {
+ descriptor->SetEnumerationIndex(enumeration_index);
+ ++enumeration_index;
}
new_descriptors->SetNextEnumerationIndex(enumeration_index);
- // Copy the descriptors, filtering out transitions and null descriptors,
- // and inserting or replacing a descriptor.
+ // Copy the descriptors, inserting or replacing a descriptor.
int to_index = 0;
int insertion_index = -1;
int from_index = 0;
@@ -5946,11 +5932,9 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
insertion_index = to_index++;
if (replacing) from_index++;
} else {
- if (!(remove_transitions && IsTransitionOnly(from_index))) {
- MaybeObject* copy_result =
- new_descriptors->CopyFrom(to_index++, this, from_index, witness);
- if (copy_result->IsFailure()) return copy_result;
- }
+ MaybeObject* copy_result =
+ new_descriptors->CopyFrom(to_index++, this, from_index, witness);
+ if (copy_result->IsFailure()) return copy_result;
from_index++;
}
}
@@ -5966,31 +5950,25 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
}
-MaybeObject* DescriptorArray::RemoveTransitions(SharedMode shared_mode) {
+MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
// Allocate the new descriptor array.
- int new_number_of_descriptors = 0;
- for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsProperty(i)) new_number_of_descriptors++;
- }
+ int number_of_descriptors = this->number_of_descriptors();
DescriptorArray* new_descriptors;
- { MaybeObject* maybe_result = Allocate(new_number_of_descriptors,
+ { MaybeObject* maybe_result = Allocate(number_of_descriptors,
shared_mode);
if (!maybe_result->To(&new_descriptors)) return maybe_result;
}
// Copy the content.
- DescriptorArray::WhitenessWitness witness(new_descriptors);
- int next_descriptor = 0;
- for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsProperty(i)) {
+ if (number_of_descriptors > 0) {
+ FixedArray::WhitenessWitness witness(new_descriptors);
+ for (int i = 0; i < number_of_descriptors; i++) {
MaybeObject* copy_result =
- new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
+ new_descriptors->CopyFrom(i, this, i, witness);
if (copy_result->IsFailure()) return copy_result;
}
}
- ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
-
return new_descriptors;
}
@@ -6057,43 +6035,6 @@ void DescriptorArray::Sort(const WhitenessWitness& witness) {
}
-int DescriptorArray::BinarySearch(String* name, int low, int high) {
- uint32_t hash = name->Hash();
- int limit = high;
-
- ASSERT(low <= high);
-
- while (low != high) {
- int mid = (low + high) / 2;
- String* mid_name = GetKey(mid);
- uint32_t mid_hash = mid_name->Hash();
-
- if (mid_hash >= hash) {
- high = mid;
- } else {
- low = mid + 1;
- }
- }
-
- for (; low <= limit && GetKey(low)->Hash() == hash; ++low) {
- if (GetKey(low)->Equals(name)) return low;
- }
-
- return kNotFound;
-}
-
-
-int DescriptorArray::LinearSearch(SearchMode mode, String* name, int len) {
- uint32_t hash = name->Hash();
- for (int number = 0; number < len; number++) {
- String* entry = GetKey(number);
- if (mode == EXPECT_SORTED && entry->Hash() > hash) break;
- if (name->Equals(entry)) return number;
- }
- return kNotFound;
-}
-
-
MaybeObject* AccessorPair::CopyWithoutTransitions() {
Heap* heap = GetHeap();
AccessorPair* copy;
@@ -7336,17 +7277,6 @@ void String::PrintOn(FILE* file) {
}
-// Clear a possible back pointer in case the transition leads to a dead map.
-// Return true in case a back pointer has been cleared and false otherwise.
-static bool ClearBackPointer(Heap* heap, Object* target) {
- ASSERT(target->IsMap());
- Map* map = Map::cast(target);
- if (Marking::MarkBitFrom(map).Get()) return false;
- map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
- return true;
-}
-
-
// This function should only be called from within the GC, since it uses
// IncrementLiveBytesFromGC. If called from anywhere else, this results in an
// inconsistent live-bytes count.
@@ -7387,118 +7317,100 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
}
-// If the descriptor describes a transition to a dead map, the back pointer
-// of this map is cleared and we return true. Otherwise we return false.
-static bool ClearNonLiveTransitionsFromDescriptor(Heap* heap,
- DescriptorArray* d,
- int descriptor_index) {
- // If the pair (value, details) is a map transition, check if the target is
- // live. If not, null the descriptor. Also drop the back pointer for that
- // map transition, so that this map is not reached again by following a back
- // pointer from that non-live map.
- PropertyDetails details(d->GetDetails(descriptor_index));
- switch (details.type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- return ClearBackPointer(heap, d->GetValue(descriptor_index));
- case CALLBACKS: {
- Object* object = d->GetValue(descriptor_index);
- if (object->IsAccessorPair()) {
- bool cleared = true;
- AccessorPair* accessors = AccessorPair::cast(object);
- Object* getter = accessors->getter();
- if (getter->IsMap()) {
- if (ClearBackPointer(heap, getter)) {
- accessors->set_getter(heap->the_hole_value());
- } else {
- cleared = false;
- }
- } else if (!getter->IsTheHole()) {
- cleared = false;
- }
- Object* setter = accessors->setter();
- if (setter->IsMap()) {
- if (ClearBackPointer(heap, setter)) {
- accessors->set_setter(heap->the_hole_value());
- } else {
- cleared = false;
- }
- } else if (!setter->IsTheHole()) {
- cleared = false;
- }
- return cleared;
- }
- return false;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- return false;
- case NONEXISTENT:
- break;
- }
- UNREACHABLE();
+// Clear a possible back pointer in case the transition leads to a dead map.
+// Return true in case a back pointer has been cleared and false otherwise.
+static bool ClearBackPointer(Heap* heap, Object* target) {
+ ASSERT(target->IsMap());
+ Map* map = Map::cast(target);
+ if (Marking::MarkBitFrom(map).Get()) return false;
+ map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
return true;
}
+static bool ClearAccessorComponent(Heap* heap,
+ AccessorPair* accessors,
+ AccessorComponent component) {
+ Object* component_value = accessors->get(component);
+ if (!component_value->IsMap()) return true;
+ if (ClearBackPointer(heap, component_value)) {
+ accessors->set(component, heap->the_hole_value());
+ return true;
+ }
+ return false;
+}
+
+
+static bool ClearNonLiveTransition(Heap* heap,
+ TransitionArray* t,
+ int transition_index) {
+ // If the value is a map, check if the target is live. If not, clear the
+ // transition. Also drop the back pointer for that map transition, so that
+ // this map is not reached again by following a back pointer from that
+ // non-live map.
+ Object* value = t->GetValue(transition_index);
+ if (value->IsMap()) {
+ return ClearBackPointer(heap, t->GetValue(transition_index));
+ }
+
+ ASSERT(value->IsAccessorPair());
+
+ AccessorPair* accessors = AccessorPair::cast(value);
+ bool getter = ClearAccessorComponent(heap, accessors, ACCESSOR_GETTER);
+ bool setter = ClearAccessorComponent(heap, accessors, ACCESSOR_SETTER);
+ return getter && setter;
+}
+
+
// TODO(mstarzinger): This method should be moved into MarkCompactCollector,
// because it cannot be called from outside the GC and we already have methods
// depending on the transitions layout in the GC anyways.
void Map::ClearNonLiveTransitions(Heap* heap) {
- Object* array = *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset);
- // If there are no descriptors to be cleared, return.
+ TransitionArray* t = transitions();
+ // If there are no transitions to be cleared, return.
// TODO(verwaest) Should be an assert, otherwise back pointers are not
// properly cleared.
- if (array->IsSmi()) return;
- DescriptorArray* d = DescriptorArray::cast(array);
+ if (t == NULL) return;
+
+ int transition_index = 0;
- int descriptor_index = 0;
// Compact all live descriptors to the left.
- for (int i = 0; i < d->number_of_descriptors(); ++i) {
- if (!ClearNonLiveTransitionsFromDescriptor(heap, d, i)) {
- if (i != descriptor_index) {
- String* key = d->GetKey(i);
- Object* value = d->GetValue(i);
- d->SetKeyUnchecked(heap, descriptor_index, key);
- d->SetDetailsUnchecked(descriptor_index, d->GetDetails(i).AsSmi());
- d->SetValueUnchecked(heap, descriptor_index, value);
+ for (int i = 0; i < t->number_of_transitions(); ++i) {
+ if (!ClearNonLiveTransition(heap, t, i)) {
+ if (i != transition_index) {
+ String* key = t->GetKey(i);
+ Object* value = t->GetValue(i);
+ t->SetKey(transition_index, key);
+ t->SetValue(transition_index, value);
MarkCompactCollector* collector = heap->mark_compact_collector();
- Object** key_slot = d->GetKeySlot(descriptor_index);
+ Object** key_slot = t->GetKeySlot(transition_index);
collector->RecordSlot(key_slot, key_slot, key);
- if (value->IsHeapObject()) {
- Object** value_slot = d->GetValueSlot(descriptor_index);
- collector->RecordSlot(value_slot, value_slot, value);
- }
+ Object** value_slot = t->GetValueSlot(transition_index);
+ collector->RecordSlot(value_slot, value_slot, value);
}
- descriptor_index++;
+ transition_index++;
}
}
- Map* elements_transition = d->elements_transition_map();
- if (elements_transition != NULL &&
- ClearBackPointer(heap, elements_transition)) {
- elements_transition = NULL;
- d->ClearElementsTransition();
+ if (t->HasElementsTransition() &&
+ ClearBackPointer(heap, t->elements_transition())) {
+ t->ClearElementsTransition();
} else {
- // If there are no descriptors to be cleared, return.
+ // If there are no transitions to be cleared, return.
// TODO(verwaest) Should be an assert, otherwise back pointers are not
// properly cleared.
- if (descriptor_index == d->number_of_descriptors()) return;
+ if (transition_index == t->number_of_transitions()) return;
}
- // If the final descriptor array does not contain any live descriptors, remove
- // the descriptor array from the map.
- if (descriptor_index == 0 && elements_transition == NULL) {
- ClearDescriptorArray();
- return;
+ // If the final transition array does not contain any live transitions, remove
+ // the transition array from the map.
+ if (transition_index == 0 && !t->HasElementsTransition()) {
+ return ClearTransitions();
}
- int trim = d->number_of_descriptors() - descriptor_index;
+ int trim = t->number_of_transitions() - transition_index;
if (trim > 0) {
- RightTrimFixedArray(heap, d, trim * DescriptorArray::kDescriptorSize);
+ RightTrimFixedArray(heap, t, trim * TransitionArray::kTransitionSize);
}
}
@@ -10693,10 +10605,10 @@ void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
+ ASSERT(storage->length() >= index + descs->number_of_descriptors());
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
+ storage->set(index + i, descs->GetKey(i));
}
- ASSERT(storage->length() >= index);
} else {
property_dictionary()->CopyKeysTo(storage,
index,
@@ -11324,32 +11236,6 @@ int StringDictionary::FindEntry(String* key) {
}
-bool StringDictionary::ContainsTransition(int entry) {
- switch (DetailsAt(entry).type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- return true;
- case CALLBACKS: {
- Object* value = ValueAt(entry);
- if (!value->IsAccessorPair()) return false;
- AccessorPair* accessors = AccessorPair::cast(value);
- return accessors->getter()->IsMap() || accessors->setter()->IsMap();
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- return false;
- case NONEXISTENT:
- UNREACHABLE();
- break;
- }
- UNREACHABLE(); // Keep the compiler happy.
- return false;
-}
-
-
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
ASSERT(NumberOfElements() < new_table->Capacity());
@@ -12786,7 +12672,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
}
}
- DescriptorArray::WhitenessWitness witness(descriptors);
+ FixedArray::WhitenessWitness witness(descriptors);
int inobject_props = obj->map()->inobject_properties();
int number_of_allocated_fields =
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698