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:
parent
1ab272ab36
commit
d8c7a03a3a
@ -3234,7 +3234,7 @@ void v8::Object::TurnOnAccessCheck() {
|
||||
i::Deoptimizer::DeoptimizeGlobalObject(*obj);
|
||||
|
||||
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);
|
||||
obj->set_map(*new_map);
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
|
||||
// object.__proto__ = proto;
|
||||
Factory* factory = object->GetIsolate()->factory();
|
||||
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);
|
||||
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));
|
||||
|
||||
// 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());
|
||||
Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
|
||||
proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
|
||||
@ -1101,7 +1101,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
elements->set(1, *array);
|
||||
|
||||
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);
|
||||
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
|
||||
// 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
|
||||
// transition easy to trap. Moreover, they rarely are smi-only.
|
||||
MaybeObject* maybe_map =
|
||||
array_function->initial_map()->CopyDropTransitions(
|
||||
DescriptorArray::MAY_BE_SHARED);
|
||||
array_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
Map* new_map;
|
||||
if (!maybe_map->To(&new_map)) return false;
|
||||
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).
|
||||
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());
|
||||
to->set_map(*new_to_map);
|
||||
}
|
||||
|
@ -496,10 +496,8 @@ Handle<Map> Factory::CopyMap(Handle<Map> src,
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
src->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED),
|
||||
Map);
|
||||
Handle<Map> Factory::CopyMap(Handle<Map> src) {
|
||||
CALL_HEAP_FUNCTION(isolate(), src->Copy(DescriptorArray::MAY_BE_SHARED), Map);
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,8 +227,7 @@ class Factory {
|
||||
// Copy the map adding more inobject properties if possible without
|
||||
// overflowing the instance size.
|
||||
Handle<Map> CopyMap(Handle<Map> map, int extra_inobject_props);
|
||||
|
||||
Handle<Map> CopyMapDropTransitions(Handle<Map> map);
|
||||
Handle<Map> CopyMap(Handle<Map> map);
|
||||
|
||||
Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
|
||||
ElementsKind elements_kind);
|
||||
|
@ -165,7 +165,7 @@ void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
|
||||
func->shared()->set_expected_nof_properties(nof);
|
||||
if (func->has_initial_map()) {
|
||||
Handle<Map> new_initial_map =
|
||||
func->GetIsolate()->factory()->CopyMapDropTransitions(
|
||||
func->GetIsolate()->factory()->CopyMap(
|
||||
Handle<Map>(func->initial_map()));
|
||||
new_initial_map->set_unused_property_fields(nof);
|
||||
func->set_initial_map(*new_initial_map);
|
||||
|
26
src/heap.cc
26
src/heap.cc
@ -3709,23 +3709,21 @@ MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
|
||||
// constructors.
|
||||
Map* new_map;
|
||||
ASSERT(object_function->has_initial_map());
|
||||
{ MaybeObject* maybe_map =
|
||||
object_function->initial_map()->CopyDropTransitions(
|
||||
DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_map->To<Map>(&new_map)) return maybe_map;
|
||||
}
|
||||
MaybeObject* maybe_map =
|
||||
object_function->initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_map->To(&new_map)) return maybe_map;
|
||||
|
||||
Object* prototype;
|
||||
{ MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
|
||||
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
|
||||
}
|
||||
MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
|
||||
if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
|
||||
|
||||
// When creating the prototype for the function we must set its
|
||||
// constructor to the function.
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result =
|
||||
JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
|
||||
constructor_symbol(), function, DONT_ENUM);
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
}
|
||||
MaybeObject* maybe_failure =
|
||||
JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
|
||||
constructor_symbol(), function, DONT_ENUM);
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
|
@ -3653,12 +3653,12 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
|
||||
ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
|
||||
(value->IsMap() && GetBackPointer()->IsUndefined()));
|
||||
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);
|
||||
CONDITIONAL_WRITE_BARRIER(
|
||||
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;
|
||||
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
|
||||
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;
|
||||
maps->set(next_kind, new_map);
|
||||
current_map = new_map;
|
||||
|
373
src/objects.cc
373
src/objects.cc
@ -513,9 +513,9 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
|
||||
// from the DontDelete cell without checking if it contains
|
||||
// the hole value.
|
||||
Map* new_map;
|
||||
{ MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
}
|
||||
MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
|
||||
set_map(new_map);
|
||||
}
|
||||
JSGlobalPropertyCell* cell =
|
||||
@ -1544,57 +1544,42 @@ MaybeObject* JSObject::AddFastProperty(String* name,
|
||||
return AddSlowProperty(name, value, attributes);
|
||||
}
|
||||
|
||||
DescriptorArray* old_descriptors = map()->instance_descriptors();
|
||||
// Compute the new index for new field.
|
||||
int index = map()->NextFreePropertyIndex();
|
||||
|
||||
// Allocate new instance descriptors with (name, index) added
|
||||
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() ||
|
||||
(index - map()->inobject_properties()) < properties()->length() ||
|
||||
map()->unused_property_fields() == 0);
|
||||
|
||||
// Allocate a new map for the object.
|
||||
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;
|
||||
}
|
||||
FixedArray* values = NULL;
|
||||
|
||||
if (map()->unused_property_fields() == 0) {
|
||||
// Make room for the new value
|
||||
FixedArray* values;
|
||||
MaybeObject* maybe_values =
|
||||
properties()->CopySize(properties()->length() + kFieldsAdded);
|
||||
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);
|
||||
new_map->set_unused_property_fields(kFieldsAdded - 1);
|
||||
} else {
|
||||
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);
|
||||
return FastPropertyAtPut(index, value);
|
||||
}
|
||||
@ -1607,48 +1592,24 @@ MaybeObject* JSObject::AddConstantFunctionProperty(
|
||||
// Allocate new instance descriptors with (name, function) added
|
||||
ConstantFunctionDescriptor d(name, function, attributes, 0);
|
||||
|
||||
DescriptorArray* new_descriptors;
|
||||
MaybeObject* maybe_new_descriptors =
|
||||
map()->instance_descriptors()->CopyAdd(&d);
|
||||
if (!maybe_new_descriptors->To(&new_descriptors)) {
|
||||
return maybe_new_descriptors;
|
||||
}
|
||||
Heap* heap = GetHeap();
|
||||
TransitionFlag flag =
|
||||
// Do not add transitions to the empty object map (map of "new Object()"),
|
||||
// nor to global objects.
|
||||
(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;
|
||||
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;
|
||||
|
||||
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);
|
||||
new_map->SetBackPointer(old_map);
|
||||
return function;
|
||||
}
|
||||
|
||||
@ -1819,15 +1780,10 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name,
|
||||
int index = map()->NextFreePropertyIndex();
|
||||
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.
|
||||
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;
|
||||
|
||||
// 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,
|
||||
ElementsKind to_kind) {
|
||||
ASSERT(IsFastElementsKind(map->elements_kind()));
|
||||
@ -2260,18 +2189,18 @@ static MaybeObject* AddMissingElementsTransitions(Map* map,
|
||||
Map* current_map = map;
|
||||
|
||||
for (; index < to_index; ++index) {
|
||||
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
|
||||
MaybeObject* maybe_next_map =
|
||||
current_map->CreateNextElementsTransition(next_kind);
|
||||
if (!maybe_next_map->To(¤t_map)) return maybe_next_map;
|
||||
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
|
||||
MaybeObject* maybe_next_map =
|
||||
current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
|
||||
if (!maybe_next_map->To(¤t_map)) return maybe_next_map;
|
||||
}
|
||||
|
||||
// In case we are exiting the fast elements kind system, just add the map in
|
||||
// the end.
|
||||
if (!IsFastElementsKind(to_kind)) {
|
||||
MaybeObject* maybe_next_map =
|
||||
current_map->CreateNextElementsTransition(to_kind);
|
||||
if (!maybe_next_map->To(¤t_map)) return maybe_next_map;
|
||||
MaybeObject* maybe_next_map =
|
||||
current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
|
||||
if (!maybe_next_map->To(¤t_map)) return maybe_next_map;
|
||||
}
|
||||
|
||||
ASSERT(current_map->elements_kind() == to_kind);
|
||||
@ -2312,13 +2241,7 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
|
||||
}
|
||||
|
||||
if (!allow_store_transition) {
|
||||
// Create a new free-floating map only if we are not allowed to store it.
|
||||
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;
|
||||
return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
|
||||
}
|
||||
|
||||
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
|
||||
// be extensible.
|
||||
Map* new_map;
|
||||
{ MaybeObject* maybe =
|
||||
map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe->To<Map>(&new_map)) return maybe;
|
||||
}
|
||||
MaybeObject* maybe = map()->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe->To(&new_map)) return maybe;
|
||||
|
||||
new_map->set_is_extensible(false);
|
||||
set_map(new_map);
|
||||
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,
|
||||
AccessorComponent component,
|
||||
Object* accessor,
|
||||
@ -4613,12 +4501,15 @@ MaybeObject* JSObject::DefineFastAccessor(String* name,
|
||||
if (!maybe_accessors->To(&accessors)) return maybe_accessors;
|
||||
accessors->set(component, accessor);
|
||||
|
||||
return NewCallbackTransition(this,
|
||||
name,
|
||||
component,
|
||||
accessor,
|
||||
attributes,
|
||||
accessors);
|
||||
CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
|
||||
|
||||
Map* new_map;
|
||||
MaybeObject* maybe_new_map =
|
||||
map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
|
||||
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() {
|
||||
Map* result;
|
||||
{ MaybeObject* maybe_result = RawCopy(instance_size());
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
}
|
||||
MaybeObject* maybe_result = RawCopy(instance_size());
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
|
||||
// Please note instance_type and instance_size are set when allocated.
|
||||
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;
|
||||
{ MaybeObject* maybe_result = CopyDropDescriptors();
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
}
|
||||
MaybeObject* maybe_result = CopyDropDescriptors();
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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() {
|
||||
if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
|
||||
|
||||
@ -4859,21 +4791,67 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
|
||||
ASSERT(constructor()->IsJSFunction());
|
||||
JSFunction* ctor = JSFunction::cast(constructor());
|
||||
DescriptorArray* descriptors;
|
||||
{ MaybeObject* maybe_descriptors =
|
||||
ctor->initial_map()->instance_descriptors()->Copy(
|
||||
DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
|
||||
}
|
||||
return CopyReplaceDescriptors(descriptors);
|
||||
MaybeObject* maybe_descriptors =
|
||||
ctor->initial_map()->instance_descriptors()->Copy(
|
||||
DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
|
||||
|
||||
return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Map::CopyDropTransitions(DescriptorArray::SharedMode shared_mode) {
|
||||
MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) {
|
||||
DescriptorArray* descriptors;
|
||||
{ MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
|
||||
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
|
||||
MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
|
||||
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) {
|
||||
// Ensure the key is a symbol.
|
||||
MaybeObject* maybe_result = descriptor->KeyToSymbol();
|
||||
@ -7466,11 +7433,10 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
|
||||
// replace it with a copy containing the new prototype.
|
||||
Map* 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;
|
||||
new_map->set_prototype(value);
|
||||
MaybeObject* maybe_object =
|
||||
set_initial_map_and_cache_transitions(new_map);
|
||||
MaybeObject* maybe_object = set_initial_map_and_cache_transitions(new_map);
|
||||
if (maybe_object->IsFailure()) return maybe_object;
|
||||
} else {
|
||||
// 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
|
||||
// different prototype.
|
||||
Map* new_map;
|
||||
{ MaybeObject* maybe_new_map =
|
||||
map()->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
}
|
||||
MaybeObject* maybe_new_map = map()->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
|
||||
Heap* heap = new_map->GetHeap();
|
||||
set_map(new_map);
|
||||
new_map->set_constructor(value);
|
||||
@ -8791,15 +8756,12 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
|
||||
|
||||
Map* new_map = map->GetPrototypeTransition(value);
|
||||
if (new_map == NULL) {
|
||||
{ MaybeObject* maybe_new_map =
|
||||
map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
}
|
||||
MaybeObject* maybe_new_map = map->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
|
||||
{ MaybeObject* maybe_new_cache =
|
||||
map->PutPrototypeTransition(value, new_map);
|
||||
if (maybe_new_cache->IsFailure()) return maybe_new_cache;
|
||||
}
|
||||
MaybeObject* maybe_new_cache =
|
||||
map->PutPrototypeTransition(value, new_map);
|
||||
if (maybe_new_cache->IsFailure()) return maybe_new_cache;
|
||||
|
||||
new_map->set_prototype(value);
|
||||
}
|
||||
@ -12576,7 +12538,8 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor(
|
||||
descriptors->Sort(witness);
|
||||
// Allocate 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;
|
||||
|
||||
new_map->set_unused_property_fields(unused_property_fields);
|
||||
|
@ -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.
|
||||
const int kVariableSizeSentinel = 0;
|
||||
|
||||
@ -2555,14 +2562,13 @@ class DescriptorArray: public FixedArray {
|
||||
int src_index,
|
||||
const WhitenessWitness&);
|
||||
|
||||
// Copy the descriptor array, insert a new descriptor and optionally
|
||||
// remove map transitions. If the descriptor is already present, it is
|
||||
// replaced. If a replaced descriptor is a real property (not a transition
|
||||
// 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);
|
||||
// Copy the descriptor array, inserting new descriptor. Its enumeration index
|
||||
// is automatically set to the size of the descriptor array to which it was
|
||||
// added first.
|
||||
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,
|
||||
int insertion_index);
|
||||
|
||||
@ -4917,15 +4923,23 @@ class Map: public HeapObject {
|
||||
MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors();
|
||||
MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
|
||||
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,
|
||||
NormalizedMapSharingMode sharing);
|
||||
|
||||
// Returns a copy of the map, with all transitions dropped from the
|
||||
// instance descriptors.
|
||||
MUST_USE_RESULT MaybeObject* CopyDropTransitions(
|
||||
DescriptorArray::SharedMode shared_mode);
|
||||
MUST_USE_RESULT MaybeObject* Copy(DescriptorArray::SharedMode shared_mode);
|
||||
|
||||
// Returns the property index for name (only valid for FAST MODE).
|
||||
int PropertyIndexFor(String* name);
|
||||
@ -4984,10 +4998,6 @@ class Map: public HeapObject {
|
||||
// allowed.
|
||||
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
|
||||
// elements_kind that's found in |candidates|, or null handle if no match is
|
||||
// found at all.
|
||||
|
@ -1293,14 +1293,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
|
||||
bool needs_access_checks = old_map->is_access_check_needed();
|
||||
if (needs_access_checks) {
|
||||
// Copy map so it won't interfere constructor's initial map.
|
||||
Object* new_map;
|
||||
{ MaybeObject* maybe_new_map =
|
||||
old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
|
||||
}
|
||||
Map* new_map;
|
||||
MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
|
||||
Map::cast(new_map)->set_is_access_check_needed(false);
|
||||
object->set_map(Map::cast(new_map));
|
||||
new_map->set_is_access_check_needed(false);
|
||||
object->set_map(new_map);
|
||||
}
|
||||
return isolate->heap()->ToBoolean(needs_access_checks);
|
||||
}
|
||||
@ -1312,14 +1310,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
|
||||
Map* old_map = object->map();
|
||||
if (!old_map->is_access_check_needed()) {
|
||||
// Copy map so it won't interfere constructor's initial map.
|
||||
Object* new_map;
|
||||
{ MaybeObject* maybe_new_map =
|
||||
old_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
|
||||
}
|
||||
Map* new_map;
|
||||
MaybeObject* maybe_new_map = old_map->Copy(DescriptorArray::MAY_BE_SHARED);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
|
||||
Map::cast(new_map)->set_is_access_check_needed(true);
|
||||
object->set_map(Map::cast(new_map));
|
||||
new_map->set_is_access_check_needed(true);
|
||||
object->set_map(new_map);
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
@ -2172,25 +2168,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
|
||||
if (function->HasFastProperties()) {
|
||||
// Construct a new field descriptor with updated attributes.
|
||||
DescriptorArray* instance_desc = function->map()->instance_descriptors();
|
||||
|
||||
int index = instance_desc->Search(name);
|
||||
ASSERT(index != DescriptorArray::kNotFound);
|
||||
PropertyDetails details = instance_desc->GetDetails(index);
|
||||
|
||||
CallbacksDescriptor new_desc(name,
|
||||
instance_desc->GetValue(index),
|
||||
static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
|
||||
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.
|
||||
Map* new_map;
|
||||
{ MaybeObject* maybe_map =
|
||||
function->map()->CopyReplaceDescriptors(new_descriptors);
|
||||
if (!maybe_map->To(&new_map)) return maybe_map;
|
||||
}
|
||||
MaybeObject* maybe_map =
|
||||
function->map()->CopyReplaceDescriptor(
|
||||
&new_desc, index, OMIT_TRANSITION);
|
||||
if (!maybe_map->To(&new_map)) return maybe_map;
|
||||
|
||||
function->set_map(new_map);
|
||||
} else { // Dictionary properties.
|
||||
// Directly manipulate the property details.
|
||||
@ -7829,8 +7823,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
|
||||
isolate->heap()->non_strict_arguments_elements_map());
|
||||
|
||||
Handle<Map> old_map(result->map());
|
||||
Handle<Map> new_map =
|
||||
isolate->factory()->CopyMapDropTransitions(old_map);
|
||||
Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
|
||||
new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
|
||||
|
||||
result->set_map(*new_map);
|
||||
|
Loading…
Reference in New Issue
Block a user