Remove special case code for generalizing constants to fields.
R=bmeurer@chromium.org Review URL: https://chromiumcodereview.appspot.com/22911018 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16275 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e886eff3bf
commit
22942716db
@ -1143,12 +1143,12 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
result, factory->length_string(),
|
||||
factory->undefined_value(), DONT_ENUM,
|
||||
Object::FORCE_TAGGED, JSReceiver::FORCE_FIELD));
|
||||
Object::FORCE_TAGGED, FORCE_FIELD));
|
||||
CHECK_NOT_EMPTY_HANDLE(isolate,
|
||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
result, factory->callee_string(),
|
||||
factory->undefined_value(), DONT_ENUM,
|
||||
Object::FORCE_TAGGED, JSReceiver::FORCE_FIELD));
|
||||
Object::FORCE_TAGGED, FORCE_FIELD));
|
||||
|
||||
#ifdef DEBUG
|
||||
LookupResult lookup(isolate);
|
||||
|
@ -1615,7 +1615,8 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
||||
if (!value->FitsRepresentation(target_details.representation())) {
|
||||
Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
|
||||
Map::GeneralizeRepresentation(
|
||||
target, target->LastAdded(), value->OptimalRepresentation());
|
||||
target, target->LastAdded(),
|
||||
value->OptimalRepresentation(), FORCE_FIELD);
|
||||
// Lookup the transition again since the transition tree may have changed
|
||||
// entirely by the migration above.
|
||||
receiver->map()->LookupTransition(*holder, *name, lookup);
|
||||
|
@ -1569,7 +1569,7 @@ MaybeObject* JSObject::MigrateInstance() {
|
||||
// transition that matches the object. This achieves what is needed.
|
||||
Map* original_map = map();
|
||||
MaybeObject* maybe_result = GeneralizeFieldRepresentation(
|
||||
0, Representation::None());
|
||||
0, Representation::None(), ALLOW_AS_CONSTANT);
|
||||
JSObject* result;
|
||||
if (FLAG_trace_migration && maybe_result->To(&result)) {
|
||||
PrintInstanceMigration(stdout, original_map, result->map());
|
||||
@ -2361,6 +2361,7 @@ PropertyType DescriptorArray::GetType(int descriptor_number) {
|
||||
|
||||
|
||||
int DescriptorArray::GetFieldIndex(int descriptor_number) {
|
||||
ASSERT(GetDetails(descriptor_number).type() == FIELD);
|
||||
return GetDetails(descriptor_number).field_index();
|
||||
}
|
||||
|
||||
|
410
src/objects.cc
410
src/objects.cc
@ -1450,19 +1450,31 @@ void JSObject::PrintElementsTransition(
|
||||
|
||||
|
||||
void Map::PrintGeneralization(FILE* file,
|
||||
const char* reason,
|
||||
int modify_index,
|
||||
int split,
|
||||
int descriptors,
|
||||
bool constant_to_field,
|
||||
Representation old_representation,
|
||||
Representation new_representation) {
|
||||
PrintF(file, "[generalizing ");
|
||||
constructor_name()->PrintOn(file);
|
||||
PrintF(file, "] ");
|
||||
String::cast(instance_descriptors()->GetKey(modify_index))->PrintOn(file);
|
||||
PrintF(file, ":%s->%s (+%i maps) [",
|
||||
old_representation.Mnemonic(),
|
||||
new_representation.Mnemonic(),
|
||||
descriptors - split);
|
||||
if (constant_to_field) {
|
||||
PrintF(file, ":c->f");
|
||||
} else {
|
||||
PrintF(file, ":%s->%s",
|
||||
old_representation.Mnemonic(),
|
||||
new_representation.Mnemonic());
|
||||
}
|
||||
PrintF(file, " (");
|
||||
if (strlen(reason) > 0) {
|
||||
PrintF(file, "%s", reason);
|
||||
} else {
|
||||
PrintF(file, "+%i maps", descriptors - split);
|
||||
}
|
||||
PrintF(file, ") [");
|
||||
JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
|
||||
PrintF(file, "]\n");
|
||||
}
|
||||
@ -1988,7 +2000,7 @@ MaybeObject* JSObject::AddConstantProperty(
|
||||
ConstantDescriptor d(name, constant, attributes);
|
||||
|
||||
TransitionFlag flag =
|
||||
// Do not add transitions to global objects.
|
||||
// Do not add transitions to global objects.
|
||||
(IsGlobalObject() ||
|
||||
// Don't add transitions to special properties with non-trivial
|
||||
// attributes.
|
||||
@ -2190,55 +2202,6 @@ MaybeObject* JSObject::ReplaceSlowProperty(Name* name,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* JSObject::ConvertTransitionToMapTransition(
|
||||
int transition_index,
|
||||
Name* name,
|
||||
Object* new_value,
|
||||
PropertyAttributes attributes) {
|
||||
Map* old_map = map();
|
||||
Map* old_target = old_map->GetTransition(transition_index);
|
||||
Object* result;
|
||||
|
||||
MaybeObject* maybe_result = ConvertDescriptorToField(
|
||||
name, new_value, attributes, OMIT_TRANSITION_KEEP_REPRESENTATIONS);
|
||||
if (!maybe_result->To(&result)) return maybe_result;
|
||||
|
||||
if (!HasFastProperties()) return result;
|
||||
|
||||
// This method should only be used to convert existing transitions.
|
||||
Map* new_map = map();
|
||||
|
||||
// TODO(verwaest): From here on we lose existing map transitions, causing
|
||||
// invalid back pointers. This will change once we can store multiple
|
||||
// transitions with the same key.
|
||||
bool owned_descriptors = old_map->owns_descriptors();
|
||||
if (owned_descriptors ||
|
||||
old_target->instance_descriptors() == old_map->instance_descriptors()) {
|
||||
// Since the conversion above generated a new fast map with an additional
|
||||
// property which can be shared as well, install this descriptor pointer
|
||||
// along the entire chain of smaller maps.
|
||||
Map* map;
|
||||
DescriptorArray* new_descriptors = new_map->instance_descriptors();
|
||||
DescriptorArray* old_descriptors = old_map->instance_descriptors();
|
||||
for (Object* current = old_map;
|
||||
!current->IsUndefined();
|
||||
current = map->GetBackPointer()) {
|
||||
map = Map::cast(current);
|
||||
if (map->instance_descriptors() != old_descriptors) break;
|
||||
map->SetEnumLength(Map::kInvalidEnumCache);
|
||||
map->set_instance_descriptors(new_descriptors);
|
||||
}
|
||||
old_map->set_owns_descriptors(false);
|
||||
}
|
||||
|
||||
old_target->DeprecateTransitionTree();
|
||||
|
||||
old_map->SetTransition(transition_index, new_map);
|
||||
new_map->SetBackPointer(old_map);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
|
||||
Object* new_value,
|
||||
PropertyAttributes attributes,
|
||||
@ -2491,10 +2454,11 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) {
|
||||
|
||||
MaybeObject* JSObject::GeneralizeFieldRepresentation(
|
||||
int modify_index,
|
||||
Representation new_representation) {
|
||||
Representation new_representation,
|
||||
StoreMode store_mode) {
|
||||
Map* new_map;
|
||||
MaybeObject* maybe_new_map =
|
||||
map()->GeneralizeRepresentation(modify_index, new_representation);
|
||||
MaybeObject* maybe_new_map = map()->GeneralizeRepresentation(
|
||||
modify_index, new_representation, store_mode);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
if (map() == new_map) return this;
|
||||
|
||||
@ -2512,16 +2476,39 @@ int Map::NumberOfFields() {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Map::CopyGeneralizeAllRepresentations() {
|
||||
MaybeObject* Map::CopyGeneralizeAllRepresentations(
|
||||
int modify_index,
|
||||
StoreMode store_mode,
|
||||
const char* reason) {
|
||||
Map* new_map;
|
||||
MaybeObject* maybe_map = this->Copy();
|
||||
if (!maybe_map->To(&new_map)) return maybe_map;
|
||||
|
||||
new_map->instance_descriptors()->InitializeRepresentations(
|
||||
Representation::Tagged());
|
||||
DescriptorArray* descriptors = new_map->instance_descriptors();
|
||||
descriptors->InitializeRepresentations(Representation::Tagged());
|
||||
|
||||
// Unless the instance is being migrated, ensure that modify_index is a field.
|
||||
PropertyDetails details = descriptors->GetDetails(modify_index);
|
||||
if (store_mode == FORCE_FIELD && details.type() != FIELD) {
|
||||
FieldDescriptor d(descriptors->GetKey(modify_index),
|
||||
new_map->NumberOfFields(),
|
||||
details.attributes(),
|
||||
Representation::Tagged());
|
||||
d.SetSortedKeyIndex(details.pointer());
|
||||
descriptors->Set(modify_index, &d);
|
||||
int unused_property_fields = new_map->unused_property_fields() - 1;
|
||||
if (unused_property_fields < 0) {
|
||||
unused_property_fields += JSObject::kFieldsAdded;
|
||||
}
|
||||
new_map->set_unused_property_fields(unused_property_fields);
|
||||
}
|
||||
|
||||
if (FLAG_trace_generalization) {
|
||||
PrintF("failed generalization %p -> %p\n",
|
||||
static_cast<void*>(this), static_cast<void*>(new_map));
|
||||
PrintGeneralization(stdout, reason, modify_index,
|
||||
new_map->NumberOfOwnDescriptors(),
|
||||
new_map->NumberOfOwnDescriptors(),
|
||||
details.type() == CONSTANT && store_mode == FORCE_FIELD,
|
||||
Representation::Tagged(), Representation::Tagged());
|
||||
}
|
||||
return new_map;
|
||||
}
|
||||
@ -2666,7 +2653,8 @@ Map* Map::FindLastMatchMap(int verbatim,
|
||||
// - Otherwise, invalidate the outdated transition target from |updated|, and
|
||||
// replace its transition tree with a new branch for the updated descriptors.
|
||||
MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
||||
Representation new_representation) {
|
||||
Representation new_representation,
|
||||
StoreMode store_mode) {
|
||||
Map* old_map = this;
|
||||
DescriptorArray* old_descriptors = old_map->instance_descriptors();
|
||||
Representation old_representation =
|
||||
@ -2688,38 +2676,45 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
||||
|
||||
// Check the state of the root map.
|
||||
if (!old_map->EquivalentToForTransition(root_map)) {
|
||||
return CopyGeneralizeAllRepresentations();
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
modify_index, store_mode, "not equivalent");
|
||||
}
|
||||
|
||||
int verbatim = root_map->NumberOfOwnDescriptors();
|
||||
|
||||
if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
modify_index, store_mode, "root modification");
|
||||
}
|
||||
|
||||
Map* updated = root_map->FindUpdatedMap(
|
||||
verbatim, descriptors, old_descriptors);
|
||||
if (updated == NULL) return CopyGeneralizeAllRepresentations();
|
||||
if (updated == NULL) {
|
||||
return CopyGeneralizeAllRepresentations(
|
||||
modify_index, store_mode, "incompatible");
|
||||
}
|
||||
|
||||
DescriptorArray* updated_descriptors = updated->instance_descriptors();
|
||||
|
||||
int valid = updated->NumberOfOwnDescriptors();
|
||||
|
||||
// Directly change the map if the target map is more general. Ensure that the
|
||||
// target type of the modify_index is a FIELD, unless we are migrating.
|
||||
if (updated_descriptors->IsMoreGeneralThan(
|
||||
verbatim, valid, descriptors, old_descriptors)) {
|
||||
verbatim, valid, descriptors, old_descriptors) &&
|
||||
(store_mode == ALLOW_AS_CONSTANT ||
|
||||
updated_descriptors->GetDetails(modify_index).type() == FIELD)) {
|
||||
Representation updated_representation =
|
||||
updated_descriptors->GetDetails(modify_index).representation();
|
||||
if (new_representation.fits_into(updated_representation)) {
|
||||
if (FLAG_trace_generalization &&
|
||||
!(modify_index == 0 && new_representation.IsNone())) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
||||
PrintGeneralization(stdout, modify_index, descriptors, descriptors,
|
||||
old_details.representation(),
|
||||
updated_representation);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
if (new_representation.fits_into(updated_representation)) return updated;
|
||||
}
|
||||
|
||||
DescriptorArray* new_descriptors;
|
||||
MaybeObject* maybe_descriptors = updated_descriptors->Merge(
|
||||
verbatim, valid, descriptors, old_descriptors);
|
||||
verbatim, valid, descriptors, modify_index, store_mode, old_descriptors);
|
||||
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
|
||||
ASSERT(store_mode == ALLOW_AS_CONSTANT ||
|
||||
new_descriptors->GetDetails(modify_index).type() == FIELD);
|
||||
|
||||
old_representation =
|
||||
new_descriptors->GetDetails(modify_index).representation();
|
||||
@ -2741,10 +2736,12 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
||||
split_map->DeprecateTarget(
|
||||
old_descriptors->GetKey(descriptor), new_descriptors);
|
||||
|
||||
if (FLAG_trace_generalization &&
|
||||
!(modify_index == 0 && new_representation.IsNone())) {
|
||||
PrintGeneralization(stdout, modify_index, descriptor, descriptors,
|
||||
old_representation, updated_representation);
|
||||
if (FLAG_trace_generalization) {
|
||||
PrintGeneralization(
|
||||
stdout, "", modify_index, descriptor, descriptors,
|
||||
old_descriptors->GetDetails(modify_index).type() == CONSTANT &&
|
||||
store_mode == FORCE_FIELD,
|
||||
old_representation, updated_representation);
|
||||
}
|
||||
|
||||
Map* new_map = split_map;
|
||||
@ -3782,14 +3779,92 @@ Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) {
|
||||
|
||||
Handle<Map> Map::GeneralizeRepresentation(Handle<Map> map,
|
||||
int modify_index,
|
||||
Representation representation) {
|
||||
Representation representation,
|
||||
StoreMode store_mode) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
map->GetIsolate(),
|
||||
map->GeneralizeRepresentation(modify_index, representation),
|
||||
map->GeneralizeRepresentation(modify_index, representation, store_mode),
|
||||
Map);
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* SetPropertyUsingTransition(LookupResult* lookup,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes) {
|
||||
Map* transition_map = lookup->GetTransitionTarget();
|
||||
int descriptor = transition_map->LastAdded();
|
||||
|
||||
DescriptorArray* descriptors = transition_map->instance_descriptors();
|
||||
PropertyDetails details = descriptors->GetDetails(descriptor);
|
||||
|
||||
if (details.type() == CALLBACKS || attributes != details.attributes()) {
|
||||
return lookup->holder()->ConvertDescriptorToField(
|
||||
*name, *value, attributes);
|
||||
}
|
||||
|
||||
// Keep the target CONSTANT if the same value is stored.
|
||||
// TODO(verwaest): Also support keeping the placeholder
|
||||
// (value->IsUninitialized) as constant.
|
||||
if (details.type() == CONSTANT &&
|
||||
descriptors->GetValue(descriptor) == *value) {
|
||||
lookup->holder()->set_map(transition_map);
|
||||
return *value;
|
||||
}
|
||||
|
||||
Representation representation = details.representation();
|
||||
|
||||
if (!value->FitsRepresentation(representation) ||
|
||||
details.type() == CONSTANT) {
|
||||
MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
|
||||
descriptor, value->OptimalRepresentation(), FORCE_FIELD);
|
||||
if (!maybe_map->To(&transition_map)) return maybe_map;
|
||||
Object* back = transition_map->GetBackPointer();
|
||||
if (back->IsMap()) {
|
||||
MaybeObject* maybe_failure =
|
||||
lookup->holder()->MigrateToMap(Map::cast(back));
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
}
|
||||
descriptors = transition_map->instance_descriptors();
|
||||
representation = descriptors->GetDetails(descriptor).representation();
|
||||
}
|
||||
|
||||
int field_index = descriptors->GetFieldIndex(descriptor);
|
||||
return lookup->holder()->AddFastPropertyUsingMap(
|
||||
transition_map, *name, *value, field_index, representation);
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* SetPropertyToField(LookupResult* lookup,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value) {
|
||||
Representation representation = lookup->representation();
|
||||
if (!value->FitsRepresentation(representation) ||
|
||||
lookup->type() == CONSTANT) {
|
||||
MaybeObject* maybe_failure =
|
||||
lookup->holder()->GeneralizeFieldRepresentation(
|
||||
lookup->GetDescriptorIndex(),
|
||||
value->OptimalRepresentation(),
|
||||
FORCE_FIELD);
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
|
||||
int descriptor = lookup->GetDescriptorIndex();
|
||||
representation = desc->GetDetails(descriptor).representation();
|
||||
}
|
||||
|
||||
if (FLAG_track_double_fields && representation.IsDouble()) {
|
||||
HeapNumber* storage = HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
|
||||
lookup->GetFieldIndex().field_index()));
|
||||
storage->set_value(value->Number());
|
||||
return *value;
|
||||
}
|
||||
|
||||
lookup->holder()->FastPropertyAtPut(
|
||||
lookup->GetFieldIndex().field_index(), *value);
|
||||
return *value;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
|
||||
Name* name_raw,
|
||||
Object* value_raw,
|
||||
@ -3878,37 +3953,13 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
|
||||
case NORMAL:
|
||||
result = lookup->holder()->SetNormalizedProperty(lookup, *value);
|
||||
break;
|
||||
case FIELD: {
|
||||
Representation representation = lookup->representation();
|
||||
if (!value->FitsRepresentation(representation)) {
|
||||
MaybeObject* maybe_failure =
|
||||
lookup->holder()->GeneralizeFieldRepresentation(
|
||||
lookup->GetDescriptorIndex(), value->OptimalRepresentation());
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
|
||||
int descriptor = lookup->GetDescriptorIndex();
|
||||
representation = desc->GetDetails(descriptor).representation();
|
||||
}
|
||||
if (FLAG_track_double_fields && representation.IsDouble()) {
|
||||
HeapNumber* storage =
|
||||
HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
|
||||
lookup->GetFieldIndex().field_index()));
|
||||
storage->set_value(value->Number());
|
||||
result = *value;
|
||||
break;
|
||||
}
|
||||
lookup->holder()->FastPropertyAtPut(
|
||||
lookup->GetFieldIndex().field_index(), *value);
|
||||
result = *value;
|
||||
case FIELD:
|
||||
result = SetPropertyToField(lookup, name, value);
|
||||
break;
|
||||
}
|
||||
case CONSTANT:
|
||||
// Only replace the constant if necessary.
|
||||
if (*value == lookup->GetConstant()) return *value;
|
||||
// Preserve the attributes of this existing property.
|
||||
attributes = lookup->GetAttributes();
|
||||
result = lookup->holder()->ConvertDescriptorToField(
|
||||
*name, *value, attributes);
|
||||
result = SetPropertyToField(lookup, name, value);
|
||||
break;
|
||||
case CALLBACKS: {
|
||||
Object* callback_object = lookup->GetCallbackObject();
|
||||
@ -3920,55 +3971,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
|
||||
*name, *value, attributes, strict_mode);
|
||||
break;
|
||||
case TRANSITION: {
|
||||
Map* transition_map = lookup->GetTransitionTarget();
|
||||
int descriptor = transition_map->LastAdded();
|
||||
|
||||
DescriptorArray* descriptors = transition_map->instance_descriptors();
|
||||
PropertyDetails details = descriptors->GetDetails(descriptor);
|
||||
|
||||
if (details.type() == FIELD) {
|
||||
if (attributes == details.attributes()) {
|
||||
Representation representation = details.representation();
|
||||
if (!value->FitsRepresentation(representation)) {
|
||||
MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
|
||||
descriptor, value->OptimalRepresentation());
|
||||
if (!maybe_map->To(&transition_map)) return maybe_map;
|
||||
Object* back = transition_map->GetBackPointer();
|
||||
if (back->IsMap()) {
|
||||
MaybeObject* maybe_failure =
|
||||
lookup->holder()->MigrateToMap(Map::cast(back));
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
}
|
||||
DescriptorArray* desc = transition_map->instance_descriptors();
|
||||
int descriptor = transition_map->LastAdded();
|
||||
representation = desc->GetDetails(descriptor).representation();
|
||||
}
|
||||
int field_index = descriptors->GetFieldIndex(descriptor);
|
||||
result = lookup->holder()->AddFastPropertyUsingMap(
|
||||
transition_map, *name, *value, field_index, representation);
|
||||
} else {
|
||||
result = lookup->holder()->ConvertDescriptorToField(
|
||||
*name, *value, attributes);
|
||||
}
|
||||
} else if (details.type() == CALLBACKS) {
|
||||
result = lookup->holder()->ConvertDescriptorToField(
|
||||
*name, *value, attributes);
|
||||
} else {
|
||||
ASSERT(details.type() == CONSTANT);
|
||||
|
||||
Object* constant = descriptors->GetValue(descriptor);
|
||||
if (constant == *value) {
|
||||
// If the same constant function is being added we can simply
|
||||
// transition to the target map.
|
||||
lookup->holder()->set_map(transition_map);
|
||||
result = constant;
|
||||
} else {
|
||||
// Otherwise, replace with a map transition to a new map with a FIELD,
|
||||
// even if the value is a constant function.
|
||||
result = lookup->holder()->ConvertTransitionToMapTransition(
|
||||
lookup->GetTransitionIndex(), *name, *value, attributes);
|
||||
}
|
||||
}
|
||||
result = SetPropertyUsingTransition(lookup, name, value, attributes);
|
||||
break;
|
||||
}
|
||||
case HANDLER:
|
||||
@ -4088,87 +4091,24 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
result = self->SetNormalizedProperty(*name, *value, details);
|
||||
break;
|
||||
}
|
||||
case FIELD: {
|
||||
Representation representation = lookup.representation();
|
||||
Representation value_representation =
|
||||
value->OptimalRepresentation(value_type);
|
||||
if (value_representation.IsNone()) break;
|
||||
if (!value_representation.fits_into(representation)) {
|
||||
MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation(
|
||||
lookup.GetDescriptorIndex(), value_representation);
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
DescriptorArray* desc = self->map()->instance_descriptors();
|
||||
int descriptor = lookup.GetDescriptorIndex();
|
||||
representation = desc->GetDetails(descriptor).representation();
|
||||
}
|
||||
if (FLAG_track_double_fields && representation.IsDouble()) {
|
||||
HeapNumber* storage =
|
||||
HeapNumber::cast(self->RawFastPropertyAt(
|
||||
lookup.GetFieldIndex().field_index()));
|
||||
storage->set_value(value->Number());
|
||||
result = *value;
|
||||
break;
|
||||
}
|
||||
self->FastPropertyAtPut(lookup.GetFieldIndex().field_index(), *value);
|
||||
result = *value;
|
||||
case FIELD:
|
||||
if (value->IsUninitialized()) break;
|
||||
result = SetPropertyToField(&lookup, name, value);
|
||||
break;
|
||||
}
|
||||
case CONSTANT:
|
||||
// Only replace the function if necessary.
|
||||
if (*value != lookup.GetConstant()) {
|
||||
// Preserve the attributes of this existing property.
|
||||
attributes = lookup.GetAttributes();
|
||||
result = self->ConvertDescriptorToField(*name, *value, attributes);
|
||||
}
|
||||
// Only replace the constant if necessary.
|
||||
if (*value == lookup.GetConstant()) return *value;
|
||||
if (value->IsUninitialized()) break;
|
||||
result = SetPropertyToField(&lookup, name, value);
|
||||
break;
|
||||
case CALLBACKS:
|
||||
case INTERCEPTOR:
|
||||
// Override callback in clone
|
||||
result = self->ConvertDescriptorToField(*name, *value, attributes);
|
||||
break;
|
||||
case TRANSITION: {
|
||||
Map* transition_map = lookup.GetTransitionTarget();
|
||||
int descriptor = transition_map->LastAdded();
|
||||
|
||||
DescriptorArray* descriptors = transition_map->instance_descriptors();
|
||||
PropertyDetails details = descriptors->GetDetails(descriptor);
|
||||
|
||||
if (details.type() == FIELD) {
|
||||
if (attributes == details.attributes()) {
|
||||
Representation representation = details.representation();
|
||||
Representation value_representation =
|
||||
value->OptimalRepresentation(value_type);
|
||||
if (!value_representation.fits_into(representation)) {
|
||||
MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
|
||||
descriptor, value_representation);
|
||||
if (!maybe_map->To(&transition_map)) return maybe_map;
|
||||
Object* back = transition_map->GetBackPointer();
|
||||
if (back->IsMap()) {
|
||||
MaybeObject* maybe_failure = self->MigrateToMap(Map::cast(back));
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
}
|
||||
DescriptorArray* desc = transition_map->instance_descriptors();
|
||||
int descriptor = transition_map->LastAdded();
|
||||
representation = desc->GetDetails(descriptor).representation();
|
||||
}
|
||||
int field_index = descriptors->GetFieldIndex(descriptor);
|
||||
result = self->AddFastPropertyUsingMap(
|
||||
transition_map, *name, *value, field_index, representation);
|
||||
} else {
|
||||
result = self->ConvertDescriptorToField(*name, *value, attributes);
|
||||
}
|
||||
} else if (details.type() == CALLBACKS) {
|
||||
result = self->ConvertDescriptorToField(*name, *value, attributes);
|
||||
} else {
|
||||
ASSERT(details.type() == CONSTANT);
|
||||
|
||||
// Replace transition to CONSTANT FUNCTION with a map transition to a
|
||||
// new map with a FIELD, even if the value is a function.
|
||||
result = self->ConvertTransitionToMapTransition(
|
||||
lookup.GetTransitionIndex(), *name, *value, attributes);
|
||||
}
|
||||
case TRANSITION:
|
||||
result = SetPropertyUsingTransition(&lookup, name, value, attributes);
|
||||
break;
|
||||
}
|
||||
case HANDLER:
|
||||
case NONEXISTENT:
|
||||
UNREACHABLE();
|
||||
@ -6675,7 +6615,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
|
||||
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
|
||||
set_transitions(transitions);
|
||||
result->SetBackPointer(this);
|
||||
} else if (flag != OMIT_TRANSITION_KEEP_REPRESENTATIONS) {
|
||||
} else {
|
||||
descriptors->InitializeRepresentations(Representation::Tagged());
|
||||
}
|
||||
|
||||
@ -7803,6 +7743,8 @@ void DescriptorArray::CopyFrom(int dst_index,
|
||||
MaybeObject* DescriptorArray::Merge(int verbatim,
|
||||
int valid,
|
||||
int new_size,
|
||||
int modify_index,
|
||||
StoreMode store_mode,
|
||||
DescriptorArray* other) {
|
||||
ASSERT(verbatim <= valid);
|
||||
ASSERT(valid <= new_size);
|
||||
@ -7836,6 +7778,7 @@ MaybeObject* DescriptorArray::Merge(int verbatim,
|
||||
PropertyDetails other_details = other->GetDetails(descriptor);
|
||||
|
||||
if (details.type() == FIELD || other_details.type() == FIELD ||
|
||||
(store_mode == FORCE_FIELD && descriptor == modify_index) ||
|
||||
(details.type() == CONSTANT &&
|
||||
other_details.type() == CONSTANT &&
|
||||
GetValue(descriptor) != other->GetValue(descriptor))) {
|
||||
@ -7854,7 +7797,8 @@ MaybeObject* DescriptorArray::Merge(int verbatim,
|
||||
// |valid| -> |new_size|
|
||||
for (; descriptor < new_size; descriptor++) {
|
||||
PropertyDetails details = other->GetDetails(descriptor);
|
||||
if (details.type() == FIELD) {
|
||||
if (details.type() == FIELD ||
|
||||
(store_mode == FORCE_FIELD && descriptor == modify_index)) {
|
||||
Name* key = other->GetKey(descriptor);
|
||||
FieldDescriptor d(key,
|
||||
current_offset++,
|
||||
|
@ -232,6 +232,13 @@ static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) {
|
||||
enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
|
||||
|
||||
|
||||
// Indicates whether a value can be loaded as a constant.
|
||||
enum StoreMode {
|
||||
ALLOW_AS_CONSTANT,
|
||||
FORCE_FIELD
|
||||
};
|
||||
|
||||
|
||||
// PropertyNormalizationMode is used to specify whether to keep
|
||||
// inobject properties when normalizing properties of a JSObject.
|
||||
enum PropertyNormalizationMode {
|
||||
@ -258,7 +265,6 @@ enum CreationFlag {
|
||||
// Indicates whether transitions can be added to a source map or not.
|
||||
enum TransitionFlag {
|
||||
INSERT_TRANSITION,
|
||||
OMIT_TRANSITION_KEEP_REPRESENTATIONS,
|
||||
OMIT_TRANSITION
|
||||
};
|
||||
|
||||
@ -1926,12 +1932,6 @@ class JSReceiver: public HeapObject {
|
||||
CERTAINLY_NOT_STORE_FROM_KEYED
|
||||
};
|
||||
|
||||
// Indicates whether a value can be loaded as a constant.
|
||||
enum StoreMode {
|
||||
ALLOW_AS_CONSTANT,
|
||||
FORCE_FIELD
|
||||
};
|
||||
|
||||
// Internal properties (e.g. the hidden properties dictionary) might
|
||||
// be added even though the receiver is non-extensible.
|
||||
enum ExtensibilityCheck {
|
||||
@ -2522,13 +2522,6 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
|
||||
MUST_USE_RESULT MaybeObject* UpdateAllocationSite(ElementsKind to_kind);
|
||||
|
||||
// Replaces an existing transition with a transition to a map with a FIELD.
|
||||
MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition(
|
||||
int transition_index,
|
||||
Name* name,
|
||||
Object* new_value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Converts a descriptor of any other type to a real field, backed by the
|
||||
// properties array.
|
||||
MUST_USE_RESULT MaybeObject* ConvertDescriptorToField(
|
||||
@ -2540,7 +2533,8 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* MigrateToMap(Map* new_map);
|
||||
MUST_USE_RESULT MaybeObject* GeneralizeFieldRepresentation(
|
||||
int modify_index,
|
||||
Representation new_representation);
|
||||
Representation new_representation,
|
||||
StoreMode store_mode);
|
||||
|
||||
// Add a property to a fast-case object.
|
||||
MUST_USE_RESULT MaybeObject* AddFastProperty(
|
||||
@ -3190,6 +3184,8 @@ class DescriptorArray: public FixedArray {
|
||||
MUST_USE_RESULT MaybeObject* Merge(int verbatim,
|
||||
int valid,
|
||||
int new_size,
|
||||
int modify_index,
|
||||
StoreMode store_mode,
|
||||
DescriptorArray* other);
|
||||
|
||||
bool IsMoreGeneralThan(int verbatim,
|
||||
@ -5619,16 +5615,23 @@ class Map: public HeapObject {
|
||||
static Handle<Map> GeneralizeRepresentation(
|
||||
Handle<Map> map,
|
||||
int modify_index,
|
||||
Representation new_representation);
|
||||
Representation new_representation,
|
||||
StoreMode store_mode);
|
||||
MUST_USE_RESULT MaybeObject* GeneralizeRepresentation(
|
||||
int modify_index,
|
||||
Representation representation);
|
||||
MUST_USE_RESULT MaybeObject* CopyGeneralizeAllRepresentations();
|
||||
Representation representation,
|
||||
StoreMode store_mode);
|
||||
MUST_USE_RESULT MaybeObject* CopyGeneralizeAllRepresentations(
|
||||
int modify_index,
|
||||
StoreMode store_mode,
|
||||
const char* reason);
|
||||
|
||||
void PrintGeneralization(FILE* file,
|
||||
const char* reason,
|
||||
int modify_index,
|
||||
int split,
|
||||
int descriptors,
|
||||
bool constant_to_field,
|
||||
Representation old_representation,
|
||||
Representation new_representation);
|
||||
|
||||
|
@ -422,12 +422,10 @@ class LookupResult BASE_EMBEDDED {
|
||||
|
||||
PropertyIndex GetFieldIndex() {
|
||||
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
|
||||
ASSERT(IsField());
|
||||
return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
|
||||
}
|
||||
|
||||
int GetLocalFieldIndexFromMap(Map* map) {
|
||||
ASSERT(IsField());
|
||||
return GetFieldIndexFromMap(map) - map->inobject_properties();
|
||||
}
|
||||
|
||||
|
@ -290,9 +290,7 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
|
||||
}
|
||||
Handle<Object> result;
|
||||
uint32_t element_index = 0;
|
||||
JSReceiver::StoreMode mode = value->IsJSObject()
|
||||
? JSReceiver::FORCE_FIELD
|
||||
: JSReceiver::ALLOW_AS_CONSTANT;
|
||||
StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT;
|
||||
if (key->IsInternalizedString()) {
|
||||
if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
|
||||
// Array index as string (uint32).
|
||||
|
Loading…
Reference in New Issue
Block a user