Grouping all map creation code.

- Now tunnel all descriptor changes through methods on the map
- Renamed CopyDropTransitions to regular Copy since we always "drop transitions" on copy anyway.
- Merged and moved elements transition map creation.

Review URL: https://chromiumcodereview.appspot.com/10780031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12105 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2012-07-17 13:50:19 +00:00
parent 1ab272ab36
commit d8c7a03a3a
10 changed files with 237 additions and 277 deletions

View File

@ -3234,7 +3234,7 @@ void v8::Object::TurnOnAccessCheck() {
i::Deoptimizer::DeoptimizeGlobalObject(*obj); i::Deoptimizer::DeoptimizeGlobalObject(*obj);
i::Handle<i::Map> new_map = i::Handle<i::Map> new_map =
isolate->factory()->CopyMapDropTransitions(i::Handle<i::Map>(obj->map())); isolate->factory()->CopyMap(i::Handle<i::Map>(obj->map()));
new_map->set_is_access_check_needed(true); new_map->set_is_access_check_needed(true);
obj->set_map(*new_map); obj->set_map(*new_map);
} }

View File

@ -317,7 +317,7 @@ static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
// object.__proto__ = proto; // object.__proto__ = proto;
Factory* factory = object->GetIsolate()->factory(); Factory* factory = object->GetIsolate()->factory();
Handle<Map> old_to_map = Handle<Map>(object->map()); Handle<Map> old_to_map = Handle<Map>(object->map());
Handle<Map> new_to_map = factory->CopyMapDropTransitions(old_to_map); Handle<Map> new_to_map = factory->CopyMap(old_to_map);
new_to_map->set_prototype(*proto); new_to_map->set_prototype(*proto);
object->set_map(*new_to_map); object->set_map(*new_to_map);
} }
@ -999,7 +999,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map)); initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
// RegExp prototype object is itself a RegExp. // RegExp prototype object is itself a RegExp.
Handle<Map> proto_map = factory->CopyMapDropTransitions(initial_map); Handle<Map> proto_map = factory->CopyMap(initial_map);
proto_map->set_prototype(global_context()->initial_object_prototype()); proto_map->set_prototype(global_context()->initial_object_prototype());
Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map); Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
@ -1101,7 +1101,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
elements->set(1, *array); elements->set(1, *array);
Handle<Map> old_map(global_context()->arguments_boilerplate()->map()); Handle<Map> old_map(global_context()->arguments_boilerplate()->map());
Handle<Map> new_map = factory->CopyMapDropTransitions(old_map); Handle<Map> new_map = factory->CopyMap(old_map);
new_map->set_pre_allocated_property_fields(2); new_map->set_pre_allocated_property_fields(2);
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map); Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
// Set elements kind after allocating the object because // Set elements kind after allocating the object because
@ -1630,8 +1630,7 @@ bool Genesis::InstallNatives() {
// through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT // through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT
// transition easy to trap. Moreover, they rarely are smi-only. // transition easy to trap. Moreover, they rarely are smi-only.
MaybeObject* maybe_map = MaybeObject* maybe_map =
array_function->initial_map()->CopyDropTransitions( array_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
DescriptorArray::MAY_BE_SHARED);
Map* new_map; Map* new_map;
if (!maybe_map->To(&new_map)) return false; if (!maybe_map->To(&new_map)) return false;
new_map->set_elements_kind(FAST_HOLEY_ELEMENTS); new_map->set_elements_kind(FAST_HOLEY_ELEMENTS);
@ -2247,7 +2246,7 @@ void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
// Transfer the prototype (new map is needed). // Transfer the prototype (new map is needed).
Handle<Map> old_to_map = Handle<Map>(to->map()); Handle<Map> old_to_map = Handle<Map>(to->map());
Handle<Map> new_to_map = factory->CopyMapDropTransitions(old_to_map); Handle<Map> new_to_map = factory->CopyMap(old_to_map);
new_to_map->set_prototype(from->map()->prototype()); new_to_map->set_prototype(from->map()->prototype());
to->set_map(*new_to_map); to->set_map(*new_to_map);
} }

View File

@ -496,10 +496,8 @@ Handle<Map> Factory::CopyMap(Handle<Map> src,
} }
Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) { Handle<Map> Factory::CopyMap(Handle<Map> src) {
CALL_HEAP_FUNCTION(isolate(), CALL_HEAP_FUNCTION(isolate(), src->Copy(DescriptorArray::MAY_BE_SHARED), Map);
src->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED),
Map);
} }

View File

@ -227,8 +227,7 @@ class Factory {
// Copy the map adding more inobject properties if possible without // Copy the map adding more inobject properties if possible without
// overflowing the instance size. // overflowing the instance size.
Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props); Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props);
Handle<Map> CopyMap(Handle<Map> map);
Handle<Map> CopyMapDropTransitions(Handle<Map> map);
Handle<Map> GetElementsTransitionMap(Handle<JSObject> object, Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
ElementsKind elements_kind); ElementsKind elements_kind);

View File

@ -165,7 +165,7 @@ void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
func->shared()->set_expected_nof_properties(nof); func->shared()->set_expected_nof_properties(nof);
if (func->has_initial_map()) { if (func->has_initial_map()) {
Handle<Map> new_initial_map = Handle<Map> new_initial_map =
func->GetIsolate()->factory()->CopyMapDropTransitions( func->GetIsolate()->factory()->CopyMap(
Handle<Map>(func->initial_map())); Handle<Map>(func->initial_map()));
new_initial_map->set_unused_property_fields(nof); new_initial_map->set_unused_property_fields(nof);
func->set_initial_map(*new_initial_map); func->set_initial_map(*new_initial_map);

View File

@ -3709,23 +3709,21 @@ MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
// constructors. // constructors.
Map* new_map; Map* new_map;
ASSERT(object_function->has_initial_map()); ASSERT(object_function->has_initial_map());
{ MaybeObject* maybe_map = MaybeObject* maybe_map =
object_function->initial_map()->CopyDropTransitions( object_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
DescriptorArray::MAY_BE_SHARED); if (!maybe_map->To(&new_map)) return maybe_map;
if (!maybe_map->To<Map>(&new_map)) return maybe_map;
}
Object* prototype; Object* prototype;
{ MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map); MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
}
// When creating the prototype for the function we must set its // When creating the prototype for the function we must set its
// constructor to the function. // constructor to the function.
Object* result; MaybeObject* maybe_failure =
{ MaybeObject* maybe_result = JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes( constructor_symbol(), function, DONT_ENUM);
constructor_symbol(), function, DONT_ENUM); if (maybe_failure->IsFailure()) return maybe_failure;
if (!maybe_result->ToObject(&result)) return maybe_result;
}
return prototype; return prototype;
} }

View File

@ -3653,12 +3653,12 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) || ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
(value->IsMap() && GetBackPointer()->IsUndefined())); (value->IsMap() && GetBackPointer()->IsUndefined()));
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset); Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
if (object->IsMap()) { if (object->IsDescriptorArray()) {
DescriptorArray::cast(object)->set_back_pointer_storage(value);
} else {
WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value); WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value);
CONDITIONAL_WRITE_BARRIER( CONDITIONAL_WRITE_BARRIER(
GetHeap(), this, kInstanceDescriptorsOrBackPointerOffset, value, mode); GetHeap(), this, kInstanceDescriptorsOrBackPointerOffset, value, mode);
} else {
DescriptorArray::cast(object)->set_back_pointer_storage(value);
} }
} }
@ -4301,7 +4301,7 @@ MaybeObject* JSFunction::set_initial_map_and_cache_transitions(
Map* new_map; Map* new_map;
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
MaybeObject* maybe_new_map = MaybeObject* maybe_new_map =
current_map->CreateNextElementsTransition(next_kind); current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map;
maps->set(next_kind, new_map); maps->set(next_kind, new_map);
current_map = new_map; current_map = new_map;

View File

@ -513,9 +513,9 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
// from the DontDelete cell without checking if it contains // from the DontDelete cell without checking if it contains
// the hole value. // the hole value.
Map* new_map; Map* new_map;
{ MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map;
}
set_map(new_map); set_map(new_map);
} }
JSGlobalPropertyCell* cell = JSGlobalPropertyCell* cell =
@ -1544,57 +1544,42 @@ MaybeObject* JSObject::AddFastProperty(String* name,
return AddSlowProperty(name, value, attributes); return AddSlowProperty(name, value, attributes);
} }
DescriptorArray* old_descriptors = map()->instance_descriptors();
// Compute the new index for new field. // Compute the new index for new field.
int index = map()->NextFreePropertyIndex(); int index = map()->NextFreePropertyIndex();
// Allocate new instance descriptors with (name, index) added // Allocate new instance descriptors with (name, index) added
FieldDescriptor new_field(name, index, attributes, 0); FieldDescriptor new_field(name, index, attributes, 0);
DescriptorArray* new_descriptors;
MaybeObject* maybe_new_descriptors = old_descriptors->CopyAdd(&new_field);
if (!maybe_new_descriptors->To(&new_descriptors)) {
return maybe_new_descriptors;
}
// Only allow map transition if the object isn't the global object.
bool allow_map_transition = isolate->empty_object_map() != map();
ASSERT(index < map()->inobject_properties() || ASSERT(index < map()->inobject_properties() ||
(index - map()->inobject_properties()) < properties()->length() || (index - map()->inobject_properties()) < properties()->length() ||
map()->unused_property_fields() == 0); map()->unused_property_fields() == 0);
// Allocate a new map for the object. FixedArray* values = NULL;
Map* new_map;
MaybeObject* maybe_r = map()->CopyReplaceDescriptors(new_descriptors);
if (!maybe_r->To(&new_map)) return maybe_r;
TransitionArray* new_transitions = NULL;
if (allow_map_transition) {
MaybeObject* maybe_transitions = map()->AddTransition(name, new_map);
if (!maybe_transitions->To(&new_transitions)) return maybe_transitions;
}
if (map()->unused_property_fields() == 0) { if (map()->unused_property_fields() == 0) {
// Make room for the new value // Make room for the new value
FixedArray* values;
MaybeObject* maybe_values = MaybeObject* maybe_values =
properties()->CopySize(properties()->length() + kFieldsAdded); properties()->CopySize(properties()->length() + kFieldsAdded);
if (!maybe_values->To(&values)) return maybe_values; if (!maybe_values->To(&values)) return maybe_values;
}
// Only allow map transition if the object isn't the global object.
TransitionFlag flag = isolate->empty_object_map() != map()
? INSERT_TRANSITION
: OMIT_TRANSITION;
Map* new_map;
MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag);
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
if (map()->unused_property_fields() == 0) {
ASSERT(values != NULL);
set_properties(values); set_properties(values);
new_map->set_unused_property_fields(kFieldsAdded - 1); new_map->set_unused_property_fields(kFieldsAdded - 1);
} else { } else {
new_map->set_unused_property_fields(map()->unused_property_fields() - 1); new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
} }
// Apply all changes at once, so they are atomic.
if (allow_map_transition) {
MaybeObject* transition_added = map()->set_transitions(new_transitions);
if (transition_added->IsFailure()) return transition_added;
}
new_map->SetBackPointer(map());
set_map(new_map); set_map(new_map);
return FastPropertyAtPut(index, value); return FastPropertyAtPut(index, value);
} }
@ -1607,48 +1592,24 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
// Allocate new instance descriptors with (name, function) added // Allocate new instance descriptors with (name, function) added
ConstantFunctionDescriptor d(name, function, attributes, 0); ConstantFunctionDescriptor d(name, function, attributes, 0);
DescriptorArray* new_descriptors; Heap* heap = GetHeap();
MaybeObject* maybe_new_descriptors = TransitionFlag flag =
map()->instance_descriptors()->CopyAdd(&d); // Do not add transitions to the empty object map (map of "new Object()"),
if (!maybe_new_descriptors->To(&new_descriptors)) { // nor to global objects.
return maybe_new_descriptors; (map() == heap->isolate()->empty_object_map() || IsGlobalObject() ||
} // Don't add transitions to special properties with non-trivial
// attributes.
// TODO(verwaest): Once we support attribute changes, these transitions
// should be kept as well.
attributes != NONE)
? OMIT_TRANSITION
: INSERT_TRANSITION;
// Allocate a new map for the object.
Map* new_map; Map* new_map;
MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors(new_descriptors); MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag);
if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map;
Map* old_map = map();
Heap* heap = GetHeap();
// Do not add transitions to the empty object map (map of "new Object()"), nor
// to global objects.
if (old_map == heap->isolate()->empty_object_map() || IsGlobalObject()) {
set_map(new_map);
return function;
}
// Don't add transitions to special properties with non-trivial attributes.
// TODO(verwaest): Once we support attribute changes, these transitions should
// be kept as well.
if (attributes != NONE) {
set_map(new_map);
return function;
}
// 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.
TransitionArray* transitions;
MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
MaybeObject* transition_added = old_map->set_transitions(transitions);
if (transition_added->IsFailure()) return transition_added;
set_map(new_map); set_map(new_map);
new_map->SetBackPointer(old_map);
return function; return function;
} }
@ -1819,15 +1780,10 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name,
int index = map()->NextFreePropertyIndex(); int index = map()->NextFreePropertyIndex();
FieldDescriptor new_field(name, index, attributes, 0); FieldDescriptor new_field(name, index, attributes, 0);
// Make a new DescriptorArray replacing an entry with FieldDescriptor.
DescriptorArray* new_descriptors;
MaybeObject* maybe_descriptors =
map()->instance_descriptors()->CopyInsert(&new_field);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
// Make a new map for the object. // Make a new map for the object.
Map* new_map; Map* new_map;
MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors(new_descriptors); MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field,
OMIT_TRANSITION);
if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map;
// Make new properties array if necessary. // Make new properties array if necessary.
@ -2220,33 +2176,6 @@ Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
} }
MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) {
ASSERT(!HasElementsTransition() ||
((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
IsExternalArrayElementsKind(
elements_transition_map()->elements_kind())) &&
(next_kind == DICTIONARY_ELEMENTS ||
IsExternalArrayElementsKind(next_kind))));
ASSERT(!IsFastElementsKind(next_kind) ||
IsMoreGeneralElementsKindTransition(elements_kind(), 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* 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);
return next_map;
}
static MaybeObject* AddMissingElementsTransitions(Map* map, static MaybeObject* AddMissingElementsTransitions(Map* map,
ElementsKind to_kind) { ElementsKind to_kind) {
ASSERT(IsFastElementsKind(map->elements_kind())); ASSERT(IsFastElementsKind(map->elements_kind()));
@ -2260,18 +2189,18 @@ static MaybeObject* AddMissingElementsTransitions(Map* map,
Map* current_map = map; Map* current_map = map;
for (; index < to_index; ++index) { for (; index < to_index; ++index) {
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1); ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
MaybeObject* maybe_next_map = MaybeObject* maybe_next_map =
current_map->CreateNextElementsTransition(next_kind); current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
if (!maybe_next_map->To(&current_map)) return maybe_next_map; if (!maybe_next_map->To(&current_map)) return maybe_next_map;
} }
// In case we are exiting the fast elements kind system, just add the map in // In case we are exiting the fast elements kind system, just add the map in
// the end. // the end.
if (!IsFastElementsKind(to_kind)) { if (!IsFastElementsKind(to_kind)) {
MaybeObject* maybe_next_map = MaybeObject* maybe_next_map =
current_map->CreateNextElementsTransition(to_kind); current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
if (!maybe_next_map->To(&current_map)) return maybe_next_map; if (!maybe_next_map->To(&current_map)) return maybe_next_map;
} }
ASSERT(current_map->elements_kind() == to_kind); ASSERT(current_map->elements_kind() == to_kind);
@ -2312,13 +2241,7 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
} }
if (!allow_store_transition) { if (!allow_store_transition) {
// Create a new free-floating map only if we are not allowed to store it. return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
Map* new_map = NULL;
MaybeObject* maybe_new_map =
start_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
new_map->set_elements_kind(to_kind);
return new_map;
} }
Map* closest_map = FindClosestElementsTransition(start_map, to_kind); Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
@ -4062,10 +3985,9 @@ MaybeObject* JSObject::PreventExtensions() {
// Do a map transition, other objects with this map may still // Do a map transition, other objects with this map may still
// be extensible. // be extensible.
Map* new_map; Map* new_map;
{ MaybeObject* maybe = MaybeObject* maybe = map()->Copy(DescriptorArray::MAY_BE_SHARED);
map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); if (!maybe->To(&new_map)) return maybe;
if (!maybe->To<Map>(&new_map)) return maybe;
}
new_map->set_is_extensible(false); new_map->set_is_extensible(false);
set_map(new_map); set_map(new_map);
ASSERT(!map()->is_extensible()); ASSERT(!map()->is_extensible());
@ -4529,40 +4451,6 @@ static MaybeObject* TryAccessorTransition(JSObject* self,
} }
static MaybeObject* NewCallbackTransition(JSObject* obj,
String* name,
AccessorComponent component,
Object* accessor,
PropertyAttributes attributes,
AccessorPair* new_accessors) {
// step 1: create a copy of the descriptors, incl. the new getter/setter pair
Map* old_map = obj->map();
CallbacksDescriptor new_accessors_desc(name, new_accessors, attributes);
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors =
old_map->instance_descriptors()->CopyInsert(&new_accessors_desc);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
// step 2: create a new map with the new descriptors
Map* new_map;
MaybeObject* maybe_new_map = old_map->CopyReplaceDescriptors(descriptors);
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
// step 3: add a new transition to the new map
TransitionArray* transitions;
MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
// step 4: everything went well so far, so we make our changes visible
MaybeObject* transition_added = old_map->set_transitions(transitions);
if (transition_added->IsFailure()) return transition_added;
new_map->SetBackPointer(old_map);
obj->set_map(new_map);
return obj;
}
MaybeObject* JSObject::DefineFastAccessor(String* name, MaybeObject* JSObject::DefineFastAccessor(String* name,
AccessorComponent component, AccessorComponent component,
Object* accessor, Object* accessor,
@ -4613,12 +4501,15 @@ MaybeObject* JSObject::DefineFastAccessor(String* name,
if (!maybe_accessors->To(&accessors)) return maybe_accessors; if (!maybe_accessors->To(&accessors)) return maybe_accessors;
accessors->set(component, accessor); accessors->set(component, accessor);
return NewCallbackTransition(this, CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
name,
component, Map* new_map;
accessor, MaybeObject* maybe_new_map =
attributes, map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
accessors); if (!maybe_new_map->To(&new_map)) return maybe_new_map;
set_map(new_map);
return this;
} }
@ -4826,9 +4717,8 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
MaybeObject* Map::CopyDropDescriptors() { MaybeObject* Map::CopyDropDescriptors() {
Map* result; Map* result;
{ MaybeObject* maybe_result = RawCopy(instance_size()); MaybeObject* maybe_result = RawCopy(instance_size());
if (!maybe_result->To(&result)) return maybe_result; if (!maybe_result->To(&result)) return maybe_result;
}
// Please note instance_type and instance_size are set when allocated. // Please note instance_type and instance_size are set when allocated.
result->set_inobject_properties(inobject_properties()); result->set_inobject_properties(inobject_properties());
@ -4841,16 +4731,58 @@ MaybeObject* Map::CopyDropDescriptors() {
} }
MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors) { MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
String* name,
TransitionFlag flag) {
Map* result; Map* result;
{ MaybeObject* maybe_result = CopyDropDescriptors(); MaybeObject* maybe_result = CopyDropDescriptors();
if (!maybe_result->To(&result)) return maybe_result; if (!maybe_result->To(&result)) return maybe_result;
}
result->set_instance_descriptors(descriptors); result->set_instance_descriptors(descriptors);
if (flag == INSERT_TRANSITION) {
TransitionArray* transitions;
MaybeObject* maybe_transitions = AddTransition(name, result);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
MaybeObject* maybe_set = set_transitions(transitions);
if (maybe_set->IsFailure()) return maybe_set;
result->SetBackPointer(this);
}
return result; return result;
} }
MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
// Create a new free-floating map only if we are not allowed to store it.
Map* new_map = NULL;
MaybeObject* maybe_new_map = Copy(DescriptorArray::MAY_BE_SHARED);
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
new_map->set_elements_kind(kind);
if (flag == INSERT_TRANSITION) {
ASSERT(!HasElementsTransition() ||
((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
IsExternalArrayElementsKind(
elements_transition_map()->elements_kind())) &&
(kind == DICTIONARY_ELEMENTS ||
IsExternalArrayElementsKind(kind))));
ASSERT(!IsFastElementsKind(kind) ||
IsMoreGeneralElementsKindTransition(elements_kind(), kind));
ASSERT(kind != elements_kind());
MaybeObject* added_elements = set_elements_transition_map(new_map);
if (added_elements->IsFailure()) return added_elements;
new_map->SetBackPointer(this);
}
return new_map;
}
MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
if (pre_allocated_property_fields() == 0) return CopyDropDescriptors(); if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
@ -4859,21 +4791,67 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
ASSERT(constructor()->IsJSFunction()); ASSERT(constructor()->IsJSFunction());
JSFunction* ctor = JSFunction::cast(constructor()); JSFunction* ctor = JSFunction::cast(constructor());
DescriptorArray* descriptors; DescriptorArray* descriptors;
{ MaybeObject* maybe_descriptors = MaybeObject* maybe_descriptors =
ctor->initial_map()->instance_descriptors()->Copy( ctor->initial_map()->instance_descriptors()->Copy(
DescriptorArray::MAY_BE_SHARED); DescriptorArray::MAY_BE_SHARED);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
}
return CopyReplaceDescriptors(descriptors); return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
} }
MaybeObject* Map::CopyDropTransitions(DescriptorArray::SharedMode shared_mode) { MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) {
DescriptorArray* descriptors; DescriptorArray* descriptors;
{ MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode); MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
}
MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
TransitionFlag flag) {
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors = instance_descriptors()->CopyAdd(descriptor);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
}
MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor,
TransitionFlag flag) {
DescriptorArray* old_descriptors = instance_descriptors();
// Ensure the key is a symbol.
MaybeObject* maybe_result = descriptor->KeyToSymbol();
if (maybe_result->IsFailure()) return maybe_result;
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors;
// We replace the key if it is already present.
int index = old_descriptors->SearchWithCache(descriptor->GetKey());
if (index == DescriptorArray::kNotFound) {
maybe_descriptors = old_descriptors->CopyAdd(descriptor);
} else {
maybe_descriptors = old_descriptors->CopyReplace(descriptor, index);
} }
return CopyReplaceDescriptors(descriptors); if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
}
MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor,
int index,
TransitionFlag flag) {
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors =
instance_descriptors()->CopyReplace(descriptor, index);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
} }
@ -4885,6 +4863,7 @@ void Map::UpdateCodeCache(Handle<Map> map,
map->UpdateCodeCache(*name, *code)); map->UpdateCodeCache(*name, *code));
} }
MaybeObject* Map::UpdateCodeCache(String* name, Code* code) { MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache()); ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache());
@ -5738,18 +5717,6 @@ MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor,
} }
MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) {
// Ensure the key is a symbol.
MaybeObject* maybe_result = descriptor->KeyToSymbol();
if (maybe_result->IsFailure()) return maybe_result;
// We replace the key if it is already present.
int index = SearchWithCache(descriptor->GetKey());
if (index == kNotFound) return CopyAdd(descriptor);
return CopyReplace(descriptor, index);
}
MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) { MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) {
// Ensure the key is a symbol. // Ensure the key is a symbol.
MaybeObject* maybe_result = descriptor->KeyToSymbol(); MaybeObject* maybe_result = descriptor->KeyToSymbol();
@ -7466,11 +7433,10 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
// replace it with a copy containing the new prototype. // replace it with a copy containing the new prototype.
Map* new_map; Map* new_map;
MaybeObject* maybe_new_map = MaybeObject* maybe_new_map =
initial_map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map;
new_map->set_prototype(value); new_map->set_prototype(value);
MaybeObject* maybe_object = MaybeObject* maybe_object = set_initial_map_and_cache_transitions(new_map);
set_initial_map_and_cache_transitions(new_map);
if (maybe_object->IsFailure()) return maybe_object; if (maybe_object->IsFailure()) return maybe_object;
} else { } else {
// Put the value in the initial map field until an initial map is // Put the value in the initial map field until an initial map is
@ -7496,10 +7462,9 @@ MaybeObject* JSFunction::SetPrototype(Object* value) {
// Remove map transitions because they point to maps with a // Remove map transitions because they point to maps with a
// different prototype. // different prototype.
Map* new_map; Map* new_map;
{ MaybeObject* maybe_new_map = MaybeObject* maybe_new_map = map()->Copy(DescriptorArray::MAY_BE_SHARED);
map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); if (!maybe_new_map->To(&new_map)) return maybe_new_map;
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
}
Heap* heap = new_map->GetHeap(); Heap* heap = new_map->GetHeap();
set_map(new_map); set_map(new_map);
new_map->set_constructor(value); new_map->set_constructor(value);
@ -8791,15 +8756,12 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
Map* new_map = map->GetPrototypeTransition(value); Map* new_map = map->GetPrototypeTransition(value);
if (new_map == NULL) { if (new_map == NULL) {
{ MaybeObject* maybe_new_map = MaybeObject* maybe_new_map = map->Copy(DescriptorArray::MAY_BE_SHARED);
map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); if (!maybe_new_map->To(&new_map)) return maybe_new_map;
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
}
{ MaybeObject* maybe_new_cache = MaybeObject* maybe_new_cache =
map->PutPrototypeTransition(value, new_map); map->PutPrototypeTransition(value, new_map);
if (maybe_new_cache->IsFailure()) return maybe_new_cache; if (maybe_new_cache->IsFailure()) return maybe_new_cache;
}
new_map->set_prototype(value); new_map->set_prototype(value);
} }
@ -12576,7 +12538,8 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
descriptors->Sort(witness); descriptors->Sort(witness);
// Allocate new map. // Allocate new map.
Map* new_map; Map* new_map;
MaybeObject* maybe_new_map = obj->map()->CopyReplaceDescriptors(descriptors); MaybeObject* maybe_new_map =
obj->map()->CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map;
new_map->set_unused_property_fields(unused_property_fields); new_map->set_unused_property_fields(unused_property_fields);

View File

@ -178,6 +178,13 @@ enum SearchMode {
}; };
// Indicates whether transitions can be added to a source map or not.
enum TransitionFlag {
INSERT_TRANSITION,
OMIT_TRANSITION
};
// Instance size sentinel for objects of variable size. // Instance size sentinel for objects of variable size.
const int kVariableSizeSentinel = 0; const int kVariableSizeSentinel = 0;
@ -2555,14 +2562,13 @@ class DescriptorArray: public FixedArray {
int src_index, int src_index,
const WhitenessWitness&); const WhitenessWitness&);
// Copy the descriptor array, insert a new descriptor and optionally // Copy the descriptor array, inserting new descriptor. Its enumeration index
// remove map transitions. If the descriptor is already present, it is // is automatically set to the size of the descriptor array to which it was
// replaced. If a replaced descriptor is a real property (not a transition // added first.
// or null), its enumeration index is kept as is.
// If adding a real property, map transitions must be removed. If adding
// a transition, they must not be removed. All null descriptors are removed.
MUST_USE_RESULT MaybeObject* CopyInsert(Descriptor* descriptor);
MUST_USE_RESULT MaybeObject* CopyAdd(Descriptor* descriptor); MUST_USE_RESULT MaybeObject* CopyAdd(Descriptor* descriptor);
// Copy the descriptor array, replacing a descriptor. Its enumeration index is
// kept.
MUST_USE_RESULT MaybeObject* CopyReplace(Descriptor* descriptor, MUST_USE_RESULT MaybeObject* CopyReplace(Descriptor* descriptor,
int insertion_index); int insertion_index);
@ -4917,15 +4923,23 @@ class Map: public HeapObject {
MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors(); MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors();
MUST_USE_RESULT MaybeObject* CopyDropDescriptors(); MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors( MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors(
DescriptorArray* descriptors); DescriptorArray* descriptors, String* name, TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor,
TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyInsertDescriptor(Descriptor* descriptor,
TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyReplaceDescriptor(Descriptor* descriptor,
int index,
TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
TransitionFlag flag);
MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode, MUST_USE_RESULT MaybeObject* CopyNormalized(PropertyNormalizationMode mode,
NormalizedMapSharingMode sharing); NormalizedMapSharingMode sharing);
// Returns a copy of the map, with all transitions dropped from the // Returns a copy of the map, with all transitions dropped from the
// instance descriptors. // instance descriptors.
MUST_USE_RESULT MaybeObject* CopyDropTransitions( MUST_USE_RESULT MaybeObject* Copy(DescriptorArray::SharedMode shared_mode);
DescriptorArray::SharedMode shared_mode);
// Returns the property index for name (only valid for FAST MODE). // Returns the property index for name (only valid for FAST MODE).
int PropertyIndexFor(String* name); int PropertyIndexFor(String* name);
@ -4984,10 +4998,6 @@ class Map: public HeapObject {
// allowed. // allowed.
Map* LookupElementsTransitionMap(ElementsKind elements_kind); Map* LookupElementsTransitionMap(ElementsKind elements_kind);
// Adds a new transitions for changing the elements kind to |elements_kind|.
MUST_USE_RESULT MaybeObject* CreateNextElementsTransition(
ElementsKind elements_kind);
// Returns the transitioned map for this map with the most generic // Returns the transitioned map for this map with the most generic
// elements_kind that's found in |candidates|, or null handle if no match is // elements_kind that's found in |candidates|, or null handle if no match is
// found at all. // found at all.

View File

@ -1293,14 +1293,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
bool needs_access_checks = old_map->is_access_check_needed(); bool needs_access_checks = old_map->is_access_check_needed();
if (needs_access_checks) { if (needs_access_checks) {
// Copy map so it won't interfere constructor's initial map. // Copy map so it won't interfere constructor's initial map.
Object* new_map; Map* new_map;
{ MaybeObject* maybe_new_map = MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); if (!maybe_new_map->To(&new_map)) return maybe_new_map;
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
}
Map::cast(new_map)->set_is_access_check_needed(false); new_map->set_is_access_check_needed(false);
object->set_map(Map::cast(new_map)); object->set_map(new_map);
} }
return isolate->heap()->ToBoolean(needs_access_checks); return isolate->heap()->ToBoolean(needs_access_checks);
} }
@ -1312,14 +1310,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
Map* old_map = object->map(); Map* old_map = object->map();
if (!old_map->is_access_check_needed()) { if (!old_map->is_access_check_needed()) {
// Copy map so it won't interfere constructor's initial map. // Copy map so it won't interfere constructor's initial map.
Object* new_map; Map* new_map;
{ MaybeObject* maybe_new_map = MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); if (!maybe_new_map->To(&new_map)) return maybe_new_map;
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
}
Map::cast(new_map)->set_is_access_check_needed(true); new_map->set_is_access_check_needed(true);
object->set_map(Map::cast(new_map)); object->set_map(new_map);
} }
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
@ -2172,25 +2168,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
if (function->HasFastProperties()) { if (function->HasFastProperties()) {
// Construct a new field descriptor with updated attributes. // Construct a new field descriptor with updated attributes.
DescriptorArray* instance_desc = function->map()->instance_descriptors(); DescriptorArray* instance_desc = function->map()->instance_descriptors();
int index = instance_desc->Search(name); int index = instance_desc->Search(name);
ASSERT(index != DescriptorArray::kNotFound); ASSERT(index != DescriptorArray::kNotFound);
PropertyDetails details = instance_desc->GetDetails(index); PropertyDetails details = instance_desc->GetDetails(index);
CallbacksDescriptor new_desc(name, CallbacksDescriptor new_desc(name,
instance_desc->GetValue(index), instance_desc->GetValue(index),
static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
details.index()); details.index());
// Construct a new field descriptors array containing the new descriptor.
DescriptorArray* new_descriptors;
{ MaybeObject* maybe_descriptors =
instance_desc->CopyReplace(&new_desc, index);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
}
// Create a new map featuring the new field descriptors array. // Create a new map featuring the new field descriptors array.
Map* new_map; Map* new_map;
{ MaybeObject* maybe_map = MaybeObject* maybe_map =
function->map()->CopyReplaceDescriptors(new_descriptors); function->map()->CopyReplaceDescriptor(
if (!maybe_map->To(&new_map)) return maybe_map; &new_desc, index, OMIT_TRANSITION);
} if (!maybe_map->To(&new_map)) return maybe_map;
function->set_map(new_map); function->set_map(new_map);
} else { // Dictionary properties. } else { // Dictionary properties.
// Directly manipulate the property details. // Directly manipulate the property details.
@ -7829,8 +7823,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
isolate->heap()->non_strict_arguments_elements_map()); isolate->heap()->non_strict_arguments_elements_map());
Handle<Map> old_map(result->map()); Handle<Map> old_map(result->map());
Handle<Map> new_map = Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
isolate->factory()->CopyMapDropTransitions(old_map);
new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
result->set_map(*new_map); result->set_map(*new_map);