__ SmiTst(value);
DeoptimizeIf(eq, instr->environment());
- // We know now that value is not a smi, so we can omit the check below.
+ // We know that value is a smi now, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
} else if (representation.IsDouble()) {
} else if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = descriptors->GetFieldType(descriptor);
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, scratch1, field_type->AsClass(),
- miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
Label do_store, heap_number;
__ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = lookup->GetFieldType();
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, scratch1, field_type->AsClass(),
- miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
// Load the double storage.
if (index < 0) {
!instr->hydrogen()->value()->type().IsHeapObject()) {
DeoptimizeIfSmi(value, instr->environment());
- // We know now that value is not a smi, so we can omit the check below.
+ // We know that value is a smi now, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
} else if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = descriptors->GetFieldType(descriptor);
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, scratch1, field_type->AsClass(),
- miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
UseScratchRegisterScope temps(masm);
DoubleRegister temp_double = temps.AcquireD();
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = lookup->GetFieldType();
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, scratch1, field_type->AsClass(),
- miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
UseScratchRegisterScope temps(masm);
DoubleRegister temp_double = temps.AcquireD();
// We also need to make sure that the representation of all fields
// in the given object are general enough to hold a tagged value.
Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
- Handle<Map>::cast(MaterializeNextValue()));
+ Handle<Map>::cast(MaterializeNextValue()), Representation::Tagged());
switch (map->instance_type()) {
case HEAP_NUMBER_TYPE: {
// Reuse the HeapNumber value directly as it is already properly
Handle<Object> map_object = slot_refs_[current_slot_].GetValue(isolate);
Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
- Handle<Map>::cast(map_object));
+ Handle<Map>::cast(map_object), Representation::Tagged());
current_slot_++;
// TODO(jarin) this should be unified with the code in
// Deoptimizer::MaterializeNextHeapObject()
DEFINE_implication(track_double_fields, track_fields)
DEFINE_implication(track_heap_object_fields, track_fields)
DEFINE_implication(track_computed_fields, track_fields)
-DEFINE_bool(track_field_types, true, "track field types")
-DEFINE_implication(track_field_types, track_fields)
-DEFINE_implication(track_field_types, track_heap_object_fields)
DEFINE_bool(smi_binop, true, "support smi representation in binary operations")
// Flags for optimization types.
#ifdef VERIFY_HEAP
void Heap::Verify() {
CHECK(HasBeenSetUp());
- HandleScope scope(isolate());
store_buffer()->Verify();
void ReduceLoadNamedField(HLoadNamedField* instr) {
// Reduce a load of the map field when it is known to be a constant.
- if (!IsMapAccess(instr->access())) {
- // Check if we introduce a map here.
- if (!instr->map().IsNull()) {
- Insert(instr, instr, instr->map());
- }
- return;
- }
+ if (!IsMapAccess(instr->access())) return;
HValue* object = instr->object()->ActualValue();
MapSet maps = FindMaps(object);
object()->PrintNameTo(stream);
access_.PrintTo(stream);
- if (!map().IsNull()) {
- stream->Add(" (%p)", *map().handle());
- }
-
if (HasDependency()) {
stream->Add(" ");
dependency()->PrintNameTo(stream);
public:
DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*, HValue*,
HObjectAccess);
- DECLARE_INSTRUCTION_FACTORY_P4(HLoadNamedField, HValue*, HValue*,
- HObjectAccess, Handle<Map>);
HValue* object() { return OperandAt(0); }
HValue* dependency() {
return access_.representation();
}
- Unique<Map> map() const { return map_; }
-
virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
return !access().IsInobject() || access().offset() >= size;
protected:
virtual bool DataEquals(HValue* other) V8_OVERRIDE {
HLoadNamedField* b = HLoadNamedField::cast(other);
- return access_.Equals(b->access_) && map_ == b->map_;
+ return access_.Equals(b->access_);
}
private:
HLoadNamedField(HValue* object,
HValue* dependency,
- HObjectAccess access,
- Handle<Map> map = Handle<Map>::null())
- : access_(access), map_(map) {
+ HObjectAccess access) : access_(access) {
ASSERT(object != NULL);
SetOperandAt(0, object);
SetOperandAt(1, dependency != NULL ? dependency : object);
virtual bool IsDeletable() const V8_OVERRIDE { return true; }
HObjectAccess access_;
- Unique<Map> map_;
};
access = HObjectAccess::ForHeapNumberValue();
}
return New<HLoadNamedField>(
- checked_object, static_cast<HValue*>(NULL), access, info->field_map());
+ checked_object, static_cast<HValue*>(NULL), access);
}
value, STORE_TO_INITIALIZED_ENTRY);
}
} else {
- if (!info->field_map().is_null()) {
- ASSERT(field_access.representation().IsHeapObject());
- BuildCheckHeapObject(value);
- value = BuildCheckMap(value, info->field_map());
- }
-
// This is a normal store.
instr = New<HStoreNamedField>(
checked_object->ActualValue(), field_access, value,
}
if (info->access_.offset() != access_.offset()) return false;
if (info->access_.IsInobject() != access_.IsInobject()) return false;
- if (!field_map_.is_identical_to(info->field_map_)) {
- if (!IsLoad()) return false;
-
- // Throw away type information for merging polymorphic loads.
- field_map_ = info->field_map_ = Handle<Map>();
- }
info->GeneralizeRepresentation(r);
return true;
}
}
if (lookup_.IsField()) {
- // Construct the object field access.
access_ = HObjectAccess::ForField(map, &lookup_, name_);
-
- if (access_.representation().IsHeapObject()) {
- // Figure out the field type from the accessor map.
- HeapType* field_type = lookup_.GetFieldTypeFromMap(*map);
- if (field_type->IsClass()) {
- Handle<Map> field_map = field_type->AsClass();
- if (field_map->is_stable()) { // TODO(bmeurer)
- field_map_ = field_map;
- field_map_->AddDependentCompilationInfo(
- DependentCode::kPrototypeCheckGroup, top_info());
-
- // Add dependency on the map that introduced the field.
- Handle<Map> field_owner = handle(lookup_.GetFieldOwnerFromMap(*map));
- field_owner->AddDependentCompilationInfo(
- DependentCode::kFieldTypeGroup, top_info());
- }
- }
- }
} else if (lookup_.IsPropertyCallbacks()) {
Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate());
if (!callback->IsAccessorPair()) return false;
Handle<JSFunction> accessor() { return accessor_; }
Handle<Object> constant() { return constant_; }
Handle<Map> transition() { return handle(lookup_.GetTransitionTarget()); }
- Handle<Map> field_map() { return field_map_; }
HObjectAccess access() { return access_; }
private:
Type* ToType(Handle<Map> map) { return builder_->ToType(map); }
Isolate* isolate() { return lookup_.isolate(); }
- CompilationInfo* top_info() { return builder_->top_info(); }
CompilationInfo* current_info() { return builder_->current_info(); }
bool LoadResult(Handle<Map> map);
Handle<JSFunction> accessor_;
Handle<JSObject> api_holder_;
Handle<Object> constant_;
- Handle<Map> field_map_;
HObjectAccess access_;
};
__ test(value, Immediate(kSmiTagMask));
DeoptimizeIf(zero, instr->environment());
- // We know now that value is not a smi, so we can omit the check below.
+ // We know that value is a smi now, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
}
} else if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = descriptors->GetFieldType(descriptor);
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, field_type->AsClass(), miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
Label do_store, heap_number;
__ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = lookup->GetFieldType();
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, field_type->AsClass(), miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
// Load the double storage.
if (index < 0) {
ASSERT(!receiver->map()->is_deprecated());
if (!lookup->CanHoldValue(value)) {
Handle<Map> target(lookup->GetTransitionTarget());
- Representation field_representation = value->OptimalRepresentation();
- Handle<HeapType> field_type = value->OptimalType(
- lookup->isolate(), field_representation);
Map::GeneralizeRepresentation(
target, target->LastAdded(),
- field_representation, field_type, FORCE_FIELD);
+ 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);
if (value->IsSmi() && expected_representation.IsDouble()) {
value = factory()->NewHeapNumber(
Handle<Smi>::cast(value)->value());
- } else if (expected_representation.IsHeapObject() &&
- !target->instance_descriptors()->GetFieldType(
- descriptor)->NowContains(value)) {
- Handle<HeapType> value_type(value->OptimalType(
- isolate(), expected_representation));
- Map::GeneralizeFieldType(target, descriptor, value_type);
}
- ASSERT(target->instance_descriptors()->GetFieldType(
- descriptor)->NowContains(value));
properties.Add(value, zone());
map = target;
continue;
if (value->IsUninitialized()) continue;
if (r.IsSmi()) ASSERT(value->IsSmi());
if (r.IsHeapObject()) ASSERT(value->IsHeapObject());
- HeapType* field_type = descriptors->GetFieldType(i);
- if (field_type->IsClass()) {
- Map* map = *field_type->AsClass();
- CHECK(!map->is_stable() || HeapObject::cast(value)->map() == map);
- } else if (r.IsNone()) {
- CHECK(field_type->Is(HeapType::None()));
- } else {
- CHECK(HeapType::Any()->Is(field_type));
- }
}
}
}
String::cast(this)->IsTwoByteRepresentation();
}
-
bool Object::HasValidElements() {
// Dictionary is covered under FixedArray.
return IsFixedArray() || IsFixedDoubleArray() || IsExternalArray() ||
}
+void DescriptorArray::InitializeRepresentations(Representation representation) {
+ int length = number_of_descriptors();
+ for (int i = 0; i < length; i++) {
+ SetRepresentation(i, representation);
+ }
+}
+
+
Object** DescriptorArray::GetValueSlot(int descriptor_number) {
ASSERT(descriptor_number < number_of_descriptors());
return RawFieldOfElementAt(ToValueIndex(descriptor_number));
}
-void DescriptorArray::SetValue(int descriptor_index, Object* value) {
- set(ToValueIndex(descriptor_index), value);
-}
-
-
PropertyDetails DescriptorArray::GetDetails(int descriptor_number) {
ASSERT(descriptor_number < number_of_descriptors());
Object* details = get(ToDetailsIndex(descriptor_number));
}
-HeapType* DescriptorArray::GetFieldType(int descriptor_number) {
- ASSERT(GetDetails(descriptor_number).type() == FIELD);
- return HeapType::cast(GetValue(descriptor_number));
-}
-
-
Object* DescriptorArray::GetConstant(int descriptor_number) {
return GetValue(descriptor_number);
}
}
-Handle<HeapType> Object::OptimalType(Isolate* isolate,
- Representation representation) {
- if (!FLAG_track_field_types) return HeapType::Any(isolate);
- if (representation.IsNone()) return HeapType::None(isolate);
- if (representation.IsHeapObject() && IsHeapObject()) {
- // We can track only JavaScript objects with stable maps.
- Handle<Map> map(HeapObject::cast(this)->map(), isolate);
- if (map->is_stable() &&
- map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
- map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
- return HeapType::Class(map, isolate);
- }
- }
- return HeapType::Any(isolate);
-}
-
-
MaybeObject* Object::ToObject(Context* native_context) {
if (IsNumber()) {
return CreateJSValue(native_context->number_function(), this);
int descriptors,
bool constant_to_field,
Representation old_representation,
- Representation new_representation,
- HeapType* old_field_type,
- HeapType* new_field_type) {
+ Representation new_representation) {
PrintF(file, "[generalizing ");
constructor_name()->PrintOn(file);
PrintF(file, "] ");
} else {
PrintF(file, "{symbol %p}", static_cast<void*>(name));
}
- PrintF(file, ":");
if (constant_to_field) {
- PrintF(file, "c");
+ PrintF(file, ":c->f");
} else {
- PrintF(file, "%s", old_representation.Mnemonic());
- PrintF(file, "{");
- old_field_type->TypePrint(file, HeapType::SEMANTIC_DIM);
- PrintF(file, "}");
- }
- PrintF(file, "->%s", new_representation.Mnemonic());
- PrintF(file, "{");
- new_field_type->TypePrint(file, HeapType::SEMANTIC_DIM);
- PrintF(file, "}");
+ PrintF(file, ":%s->%s",
+ old_representation.Mnemonic(),
+ new_representation.Mnemonic());
+ }
PrintF(file, " (");
if (strlen(reason) > 0) {
PrintF(file, "%s", reason);
static Handle<Map> CopyAddFieldDescriptor(Handle<Map> map,
Handle<Name> name,
int index,
- Handle<HeapType> field_type,
PropertyAttributes attributes,
Representation representation,
TransitionFlag flag) {
- FieldDescriptor new_field_desc(name, index, field_type,
- attributes, representation);
+ FieldDescriptor new_field_desc(name, index, attributes, representation);
Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
int unused_property_fields = map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
// Compute the new index for new field.
int index = object->map()->NextFreePropertyIndex();
- // Compute the optimal representation for the new field.
+ // Allocate new instance descriptors with (name, index) added
if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED;
Representation representation = value->OptimalRepresentation(value_type);
-
Handle<Map> new_map = CopyAddFieldDescriptor(
- handle(object->map()), name, index,
- value->OptimalType(isolate, representation),
- attributes, representation, flag);
+ handle(object->map()), name, index, attributes, representation, flag);
JSObject::MigrateToMap(object, new_map);
void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
int modify_index,
Representation new_representation,
- Handle<HeapType> new_field_type,
StoreMode store_mode) {
Handle<Map> new_map = Map::GeneralizeRepresentation(
- handle(object->map()), modify_index, new_representation,
- new_field_type, store_mode);
+ handle(object->map()), modify_index, new_representation, store_mode);
if (object->map() == *new_map) return;
return MigrateToMap(object, new_map);
}
StoreMode store_mode,
PropertyAttributes attributes,
const char* reason) {
- Isolate* isolate = map->GetIsolate();
Handle<Map> new_map = Copy(map);
DescriptorArray* descriptors = new_map->instance_descriptors();
- int length = descriptors->number_of_descriptors();
- for (int i = 0; i < length; i++) {
- descriptors->SetRepresentation(i, Representation::Tagged());
- if (descriptors->GetDetails(i).type() == FIELD) {
- descriptors->SetValue(i, HeapType::Any());
- }
- }
+ 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(handle(descriptors->GetKey(modify_index), isolate),
+ FieldDescriptor d(handle(descriptors->GetKey(modify_index),
+ map->GetIsolate()),
new_map->NumberOfFields(),
attributes,
Representation::Tagged());
}
if (FLAG_trace_generalization) {
- HeapType* field_type = (details.type() == FIELD)
- ? map->instance_descriptors()->GetFieldType(modify_index)
- : NULL;
map->PrintGeneralization(stdout, reason, modify_index,
new_map->NumberOfOwnDescriptors(),
new_map->NumberOfOwnDescriptors(),
details.type() == CONSTANT && store_mode == FORCE_FIELD,
- details.representation(), Representation::Tagged(),
- field_type, HeapType::Any());
+ Representation::Tagged(), Representation::Tagged());
}
return new_map;
}
Map* Map::FindUpdatedMap(int verbatim,
int length,
DescriptorArray* descriptors) {
- DisallowHeapAllocation no_allocation;
-
// This can only be called on roots of transition trees.
ASSERT(GetBackPointer()->IsUndefined());
Map* Map::FindLastMatchMap(int verbatim,
int length,
DescriptorArray* descriptors) {
- DisallowHeapAllocation no_allocation;
-
// This can only be called on roots of transition trees.
ASSERT(GetBackPointer()->IsUndefined());
Map* next = transitions->GetTarget(transition);
DescriptorArray* next_descriptors = next->instance_descriptors();
+ if (next_descriptors->GetValue(i) != descriptors->GetValue(i)) break;
+
PropertyDetails details = descriptors->GetDetails(i);
PropertyDetails next_details = next_descriptors->GetDetails(i);
if (details.type() != next_details.type()) break;
if (details.attributes() != next_details.attributes()) break;
if (!details.representation().Equals(next_details.representation())) break;
- if (next_details.type() == FIELD) {
- if (!descriptors->GetFieldType(i)->NowIs(
- next_descriptors->GetFieldType(i))) break;
- } else {
- if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
- }
current = next;
}
}
-Map* Map::FindFieldOwner(int descriptor) {
- DisallowHeapAllocation no_allocation;
- ASSERT_EQ(FIELD, instance_descriptors()->GetDetails(descriptor).type());
- Map* result = this;
- while (true) {
- Object* back = result->GetBackPointer();
- if (back->IsUndefined()) break;
- Map* parent = Map::cast(back);
- if (parent->NumberOfOwnDescriptors() <= descriptor) break;
- result = parent;
- }
- return result;
-}
-
-
-void Map::UpdateDescriptor(int descriptor_number, Descriptor* desc) {
- DisallowHeapAllocation no_allocation;
- if (HasTransitionArray()) {
- TransitionArray* transitions = this->transitions();
- for (int i = 0; i < transitions->number_of_transitions(); ++i) {
- transitions->GetTarget(i)->UpdateDescriptor(descriptor_number, desc);
- }
- }
- instance_descriptors()->Replace(descriptor_number, desc);;
-}
-
-
-// static
-Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> old_field_type,
- Handle<HeapType> new_field_type,
- Isolate* isolate) {
- if (new_field_type->NowIs(old_field_type)) return old_field_type;
- if (old_field_type->NowIs(new_field_type)) return new_field_type;
- return HeapType::Any(isolate);
-}
-
-
-// static
-void Map::GeneralizeFieldType(Handle<Map> map,
- int modify_index,
- Handle<HeapType> new_field_type) {
- Isolate* isolate = map->GetIsolate();
- Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
- Handle<DescriptorArray> descriptors(
- field_owner->instance_descriptors(), isolate);
-
- // Check if we actually need to generalize the field type at all.
- Handle<HeapType> old_field_type(
- descriptors->GetFieldType(modify_index), isolate);
- if (new_field_type->NowIs(old_field_type)) {
- ASSERT(Map::GeneralizeFieldType(old_field_type,
- new_field_type,
- isolate)->NowIs(old_field_type));
- return;
- }
-
- // Determine the generalized new field type.
- new_field_type = Map::GeneralizeFieldType(
- old_field_type, new_field_type, isolate);
-
- PropertyDetails details = descriptors->GetDetails(modify_index);
- FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
- descriptors->GetFieldIndex(modify_index),
- new_field_type,
- details.attributes(),
- details.representation());
- field_owner->UpdateDescriptor(modify_index, &d);
- field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
- isolate, DependentCode::kFieldTypeGroup);
-
- if (FLAG_trace_generalization) {
- map->PrintGeneralization(
- stdout, "field type generalization",
- modify_index, map->NumberOfOwnDescriptors(),
- map->NumberOfOwnDescriptors(), false,
- details.representation(), details.representation(),
- *old_field_type, *new_field_type);
- }
-}
-
-
// Generalize the representation of the descriptor at |modify_index|.
// This method rewrites the transition tree to reflect the new change. To avoid
// high degrees over polymorphism, and to stabilize quickly, on every rewrite
Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
int modify_index,
Representation new_representation,
- Handle<HeapType> new_field_type,
StoreMode store_mode) {
Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
if (old_representation.IsNone() &&
!new_representation.IsNone() &&
!new_representation.IsDouble()) {
- ASSERT(old_details.type() == FIELD);
- ASSERT(old_descriptors->GetFieldType(modify_index)->NowIs(
- HeapType::None()));
- if (FLAG_trace_generalization) {
- old_map->PrintGeneralization(
- stdout, "uninitialized field",
- modify_index, old_map->NumberOfOwnDescriptors(),
- old_map->NumberOfOwnDescriptors(), false,
- old_representation, new_representation,
- old_descriptors->GetFieldType(modify_index), *new_field_type);
- }
old_descriptors->SetRepresentation(modify_index, new_representation);
- old_descriptors->SetValue(modify_index, *new_field_type);
- return old_map;
- }
-
- if (new_representation.Equals(old_representation) &&
- old_details.type() == FIELD) {
- Map::GeneralizeFieldType(old_map, modify_index, new_field_type);
return old_map;
}
+ int descriptors = old_map->NumberOfOwnDescriptors();
Handle<Map> root_map(old_map->FindRootMap());
// Check the state of the root map.
old_details.attributes(), "root modification");
}
- int descriptors = old_map->NumberOfOwnDescriptors();
Map* raw_updated = root_map->FindUpdatedMap(
verbatim, descriptors, *old_descriptors);
if (raw_updated == NULL) {
ASSERT(store_mode == ALLOW_AS_CONSTANT ||
new_descriptors->GetDetails(modify_index).type() == FIELD);
- Isolate* isolate = new_descriptors->GetIsolate();
old_representation =
new_descriptors->GetDetails(modify_index).representation();
Representation updated_representation =
if (!updated_representation.Equals(old_representation)) {
new_descriptors->SetRepresentation(modify_index, updated_representation);
}
- if (new_descriptors->GetDetails(modify_index).type() == FIELD) {
- Handle<HeapType> field_type(
- new_descriptors->GetFieldType(modify_index), isolate);
- new_field_type = Map::GeneralizeFieldType(
- field_type, new_field_type, isolate);
- new_descriptors->SetValue(modify_index, *new_field_type);
- }
Handle<Map> split_map(root_map->FindLastMatchMap(
verbatim, descriptors, *new_descriptors));
old_descriptors->GetKey(descriptor), *new_descriptors);
if (FLAG_trace_generalization) {
- PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
- PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
- Handle<HeapType> old_field_type = (old_details.type() == FIELD)
- ? handle(old_descriptors->GetFieldType(modify_index), isolate)
- : HeapType::Constant(handle(old_descriptors->GetValue(modify_index),
- isolate), isolate);
- Handle<HeapType> new_field_type = (new_details.type() == FIELD)
- ? handle(new_descriptors->GetFieldType(modify_index), isolate)
- : HeapType::Constant(handle(new_descriptors->GetValue(modify_index),
- isolate), isolate);
old_map->PrintGeneralization(
stdout, "", modify_index, descriptor, descriptors,
- old_details.type() == CONSTANT && store_mode == FORCE_FIELD,
- old_details.representation(), new_details.representation(),
- *old_field_type, *new_field_type);
+ old_descriptors->GetDetails(modify_index).type() == CONSTANT &&
+ store_mode == FORCE_FIELD,
+ old_representation, updated_representation);
}
// Add missing transitions.
// Generalize the representation of all FIELD descriptors.
Handle<Map> Map::GeneralizeAllFieldRepresentations(
- Handle<Map> map) {
+ Handle<Map> map,
+ Representation new_representation) {
Handle<DescriptorArray> descriptors(map->instance_descriptors());
- for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
- if (descriptors->GetDetails(i).type() == FIELD) {
- map = GeneralizeRepresentation(map, i, Representation::Tagged(),
- HeapType::Any(map->GetIsolate()),
- FORCE_FIELD);
+ for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (details.type() == FIELD) {
+ map = GeneralizeRepresentation(map, i, new_representation, FORCE_FIELD);
}
}
return map;
// transition that matches the object. This achieves what is needed.
Handle<Map> original_map(object->map());
GeneralizeFieldRepresentation(
- object, 0, Representation::None(),
- HeapType::None(object->GetIsolate()),
- ALLOW_AS_CONSTANT);
+ object, 0, Representation::None(), ALLOW_AS_CONSTANT);
object->map()->set_migration_target(true);
if (FLAG_trace_migration) {
object->PrintInstanceMigration(stdout, *original_map, object->map());
Handle<Map> transition_map(lookup->GetTransitionTarget());
int descriptor = transition_map->LastAdded();
- Handle<DescriptorArray> descriptors(transition_map->instance_descriptors());
+ DescriptorArray* descriptors = transition_map->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
if (details.type() == CALLBACKS || attributes != details.attributes()) {
// Keep the target CONSTANT if the same value is stored.
// TODO(verwaest): Also support keeping the placeholder
// (value->IsUninitialized) as constant.
- if (!lookup->CanHoldValue(value)) {
- Representation field_representation = value->OptimalRepresentation();
- Handle<HeapType> field_type = value->OptimalType(
- lookup->isolate(), field_representation);
- transition_map = Map::GeneralizeRepresentation(
- transition_map, descriptor,
- field_representation, field_type, FORCE_FIELD);
+ if (!lookup->CanHoldValue(value) ||
+ (details.type() == CONSTANT &&
+ descriptors->GetValue(descriptor) != *value)) {
+ transition_map = Map::GeneralizeRepresentation(transition_map,
+ descriptor, value->OptimalRepresentation(), FORCE_FIELD);
}
JSObject::MigrateToMap(object, transition_map);
// Reload.
- descriptors = handle(transition_map->instance_descriptors());
+ descriptors = transition_map->instance_descriptors();
details = descriptors->GetDetails(descriptor);
if (details.type() != FIELD) return value;
static void SetPropertyToField(LookupResult* lookup,
Handle<Object> value) {
Representation representation = lookup->representation();
- if (lookup->type() == CONSTANT || !lookup->CanHoldValue(value)) {
- Representation field_representation = value->OptimalRepresentation();
- Handle<HeapType> field_type = value->OptimalType(
- lookup->isolate(), field_representation);
+ if (!lookup->CanHoldValue(value) ||
+ lookup->type() == CONSTANT) {
JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
lookup->GetDescriptorIndex(),
- field_representation, field_type,
+ value->OptimalRepresentation(),
FORCE_FIELD);
DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
int descriptor = lookup->GetDescriptorIndex();
int descriptor_index = lookup->GetDescriptorIndex();
if (lookup->GetAttributes() == attributes) {
JSObject::GeneralizeFieldRepresentation(
- object, descriptor_index, Representation::Tagged(),
- HeapType::Any(lookup->isolate()), FORCE_FIELD);
+ object, descriptor_index, Representation::Tagged(), FORCE_FIELD);
} else {
Handle<Map> old_map(object->map());
Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
map->set_transitions(*transitions);
result->SetBackPointer(*map);
} else {
- int length = descriptors->number_of_descriptors();
- for (int i = 0; i < length; i++) {
- descriptors->SetRepresentation(i, Representation::Tagged());
- if (descriptors->GetDetails(i).type() == FIELD) {
- descriptors->SetValue(i, HeapType::Any());
- }
- }
+ descriptors->InitializeRepresentations(Representation::Tagged());
}
return result;
(left_details.type() == CONSTANT &&
right_details.type() == CONSTANT &&
left->GetValue(descriptor) != right->GetValue(descriptor))) {
- ASSERT(left_details.type() == CONSTANT || left_details.type() == FIELD);
- ASSERT(right_details.type() == CONSTANT || right_details.type() == FIELD);
Representation representation = left_details.representation().generalize(
right_details.representation());
- Handle<HeapType> left_type = (left_details.type() == FIELD)
- ? handle(left->GetFieldType(descriptor), isolate)
- : left->GetValue(descriptor)->OptimalType(isolate, representation);
- Handle<HeapType> right_type = (right_details.type() == FIELD)
- ? handle(right->GetFieldType(descriptor), isolate)
- : right->GetValue(descriptor)->OptimalType(isolate, representation);
- Handle<HeapType> field_type = Map::GeneralizeFieldType(
- left_type, right_type, isolate);
- FieldDescriptor d(handle(left->GetKey(descriptor), isolate),
+ FieldDescriptor d(handle(left->GetKey(descriptor)),
current_offset++,
- field_type,
right_details.attributes(),
representation);
result->Set(descriptor, &d);
} else {
- Descriptor d(handle(right->GetKey(descriptor), isolate),
- handle(right->GetValue(descriptor), isolate),
+ Descriptor d(handle(right->GetKey(descriptor)),
+ handle(right->GetValue(descriptor), right->GetIsolate()),
right_details);
result->Set(descriptor, &d);
}
// |valid| -> |new_size|
for (; descriptor < new_size; descriptor++) {
PropertyDetails right_details = right->GetDetails(descriptor);
- if (right_details.type() == FIELD) {
- FieldDescriptor d(handle(right->GetKey(descriptor), isolate),
+ if (right_details.type() == FIELD ||
+ (store_mode == FORCE_FIELD && descriptor == modify_index)) {
+ FieldDescriptor d(handle(right->GetKey(descriptor)),
current_offset++,
- handle(right->GetFieldType(descriptor), isolate),
right_details.attributes(),
right_details.representation());
result->Set(descriptor, &d);
- } else if (store_mode == FORCE_FIELD && descriptor == modify_index) {
- ASSERT_EQ(CONSTANT, right_details.type());
- Representation field_representation = right_details.representation();
- Handle<HeapType> field_type = right->GetValue(descriptor)->OptimalType(
- isolate, field_representation);
- FieldDescriptor d(handle(right->GetKey(descriptor), isolate),
- current_offset++,
- field_type,
- right_details.attributes(),
- field_representation);
- result->Set(descriptor, &d);
} else {
- Descriptor d(handle(right->GetKey(descriptor), isolate),
- handle(right->GetValue(descriptor), isolate),
+ Descriptor d(handle(right->GetKey(descriptor)),
+ handle(right->GetValue(descriptor), right->GetIsolate()),
right_details);
result->Set(descriptor, &d);
}
return true;
}
- Handle<HeapType> OptimalType(Isolate* isolate, Representation representation);
-
inline MaybeObject* AllocateNewStorageFor(Heap* heap,
Representation representation);
static void GeneralizeFieldRepresentation(Handle<JSObject> object,
int modify_index,
Representation new_representation,
- Handle<HeapType> new_field_type,
StoreMode store_mode);
// Convert the object to use the canonical dictionary
inline Name* GetKey(int descriptor_number);
inline Object** GetKeySlot(int descriptor_number);
inline Object* GetValue(int descriptor_number);
- inline void SetValue(int descriptor_number, Object* value);
inline Object** GetValueSlot(int descriptor_number);
inline Object** GetDescriptorStartSlot(int descriptor_number);
inline Object** GetDescriptorEndSlot(int descriptor_number);
inline PropertyDetails GetDetails(int descriptor_number);
inline PropertyType GetType(int descriptor_number);
inline int GetFieldIndex(int descriptor_number);
- inline HeapType* GetFieldType(int descriptor_number);
inline Object* GetConstant(int descriptor_number);
inline Object* GetCallbacksObject(int descriptor_number);
inline AccessorDescriptor* GetCallbacks(int descriptor_number);
inline Name* GetSortedKey(int descriptor_number);
inline int GetSortedKeyIndex(int descriptor_number);
inline void SetSortedKey(int pointer, int descriptor_number);
+ inline void InitializeRepresentations(Representation representation);
inline void SetRepresentation(int descriptor_number,
Representation representation);
// Group of code that depends on global property values in property cells
// not being changed.
kPropertyCellChangedGroup,
- // Group of code that omit run-time type checks for the field(s) introduced
- // by this map.
- kFieldTypeGroup,
// Group of code that depends on tenuring information in AllocationSites
// not being changed.
kAllocationSiteTenuringChangedGroup,
Map* FindRootMap();
Map* FindUpdatedMap(int verbatim, int length, DescriptorArray* descriptors);
Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors);
- Map* FindFieldOwner(int descriptor);
-
- void UpdateDescriptor(int descriptor_number, Descriptor* desc);
inline int GetInObjectPropertyOffset(int index);
int target_number_of_fields,
int target_inobject,
int target_unused);
- static Handle<Map> GeneralizeAllFieldRepresentations(Handle<Map> map);
- static Handle<HeapType> GeneralizeFieldType(Handle<HeapType> old_field_type,
- Handle<HeapType> new_field_type,
- Isolate* isolate)
- V8_WARN_UNUSED_RESULT;
- static void GeneralizeFieldType(Handle<Map> map,
- int modify_index,
- Handle<HeapType> new_field_type);
+ static Handle<Map> GeneralizeAllFieldRepresentations(
+ Handle<Map> map,
+ Representation new_representation);
static Handle<Map> GeneralizeRepresentation(
Handle<Map> map,
int modify_index,
Representation new_representation,
- Handle<HeapType> new_field_type,
StoreMode store_mode);
static Handle<Map> CopyGeneralizeAllRepresentations(
Handle<Map> map,
int descriptors,
bool constant_to_field,
Representation old_representation,
- Representation new_representation,
- HeapType* old_field_type,
- HeapType* new_field_type);
+ Representation new_representation);
// Returns the constructor name (the name (possibly, inferred name) of the
// function that was used to instantiate the object).
PrintF(out, " -cacheable = %s\n", IsCacheable() ? "true" : "false");
PrintF(out, " -attributes = %x\n", GetAttributes());
if (IsTransition()) {
- PrintF(out, " -transition target:\n");
- GetTransitionTarget()->Print(out);
- PrintF(out, "\n");
- }
- switch (type()) {
- case NORMAL:
- PrintF(out, " -type = normal\n");
- PrintF(out, " -entry = %d", GetDictionaryEntry());
- break;
- case CONSTANT:
- PrintF(out, " -type = constant\n");
- PrintF(out, " -value:\n");
- GetConstant()->Print(out);
- PrintF(out, "\n");
- break;
- case FIELD:
- PrintF(out, " -type = field\n");
- PrintF(out, " -index = %d\n", GetFieldIndex().field_index());
- PrintF(out, " -field type:\n");
- GetFieldType()->TypePrint(out);
- break;
- case CALLBACKS:
- PrintF(out, " -type = call backs\n");
- PrintF(out, " -callback object:\n");
- GetCallbackObject()->Print(out);
- break;
- case HANDLER:
- PrintF(out, " -type = lookup proxy\n");
- break;
- case INTERCEPTOR:
- PrintF(out, " -type = lookup interceptor\n");
- break;
- case NONEXISTENT:
- UNREACHABLE();
- break;
+ switch (type()) {
+ case FIELD:
+ PrintF(out, " -type = map transition\n");
+ PrintF(out, " -map:\n");
+ GetTransitionTarget()->Print(out);
+ PrintF(out, "\n");
+ break;
+ case CONSTANT:
+ PrintF(out, " -type = constant property transition\n");
+ PrintF(out, " -map:\n");
+ GetTransitionTarget()->Print(out);
+ PrintF(out, "\n");
+ break;
+ case CALLBACKS:
+ PrintF(out, " -type = callbacks transition\n");
+ PrintF(out, " -callback object:\n");
+ GetCallbackObject()->Print(out);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ } else {
+ switch (type()) {
+ case NORMAL:
+ PrintF(out, " -type = normal\n");
+ PrintF(out, " -entry = %d", GetDictionaryEntry());
+ break;
+ case CONSTANT:
+ PrintF(out, " -type = constant\n");
+ PrintF(out, " -value:\n");
+ GetConstant()->Print(out);
+ PrintF(out, "\n");
+ break;
+ case FIELD:
+ PrintF(out, " -type = field\n");
+ PrintF(out, " -index = %d", GetFieldIndex().field_index());
+ PrintF(out, "\n");
+ break;
+ case CALLBACKS:
+ PrintF(out, " -type = call backs\n");
+ PrintF(out, " -callback object:\n");
+ GetCallbackObject()->Print(out);
+ break;
+ case HANDLER:
+ PrintF(out, " -type = lookup proxy\n");
+ break;
+ case INTERCEPTOR:
+ PrintF(out, " -type = lookup interceptor\n");
+ break;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
+ }
}
}
#include "isolate.h"
#include "factory.h"
-#include "types.h"
namespace v8 {
namespace internal {
int field_index,
PropertyAttributes attributes,
Representation representation)
- : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
+ : Descriptor(key, handle(Smi::FromInt(0), key->GetIsolate()), attributes,
FIELD, representation, field_index) {}
- FieldDescriptor(Handle<Name> key,
- int field_index,
- Handle<HeapType> field_type,
- PropertyAttributes attributes,
- Representation representation)
- : Descriptor(key, field_type, attributes, FIELD,
- representation, field_index) { }
};
number_ = number;
}
- bool CanHoldValue(Handle<Object> value) const {
- switch (type()) {
- case NORMAL:
- return true;
- case FIELD:
- return value->FitsRepresentation(representation()) &&
- GetFieldType()->NowContains(value);
- case CONSTANT:
- ASSERT(GetConstant() != *value ||
- value->FitsRepresentation(representation()));
- return GetConstant() == *value;
- case CALLBACKS:
- case HANDLER:
- case INTERCEPTOR:
- return true;
- case NONEXISTENT:
- UNREACHABLE();
- }
- UNREACHABLE();
- return true;
+ bool CanHoldValue(Handle<Object> value) {
+ if (IsNormal()) return true;
+ return value->FitsRepresentation(details_.representation());
}
void TransitionResult(JSObject* holder, Map* target) {
return map->instance_descriptors()->GetFieldIndex(number_);
}
- HeapType* GetFieldType() const {
- ASSERT(type() == FIELD);
- if (lookup_type_ == DESCRIPTOR_TYPE) {
- return GetFieldTypeFromMap(holder()->map());
- }
- ASSERT(lookup_type_ == TRANSITION_TYPE);
- return GetFieldTypeFromMap(transition_);
- }
-
- HeapType* GetFieldTypeFromMap(Map* map) const {
- ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
- lookup_type_ == TRANSITION_TYPE);
- ASSERT(number_ < map->NumberOfOwnDescriptors());
- return map->instance_descriptors()->GetFieldType(number_);
- }
-
- Map* GetFieldOwner() const {
- return GetFieldOwnerFromMap(holder()->map());
- }
-
- Map* GetFieldOwnerFromMap(Map* map) const {
- ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
- ASSERT(number_ < map->NumberOfOwnDescriptors());
- return map->FindFieldOwner(number_);
- }
-
void Iterate(ObjectVisitor* visitor);
private:
Condition cc = masm()->CheckSmi(value);
DeoptimizeIf(cc, instr->environment());
- // We know now that value is not a smi, so we can omit the check below.
+ // We know that value is a smi now, so we can omit the check below.
check_needed = OMIT_SMI_CHECK;
}
}
} else if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = descriptors->GetFieldType(descriptor);
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, field_type->AsClass(), miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
Label do_store, heap_number;
__ AllocateHeapNumber(storage_reg, scratch1, slow);
if (representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (representation.IsHeapObject()) {
- HeapType* field_type = lookup->GetFieldType();
- if (field_type->IsClass()) {
- __ CheckMap(value_reg, field_type->AsClass(), miss_label, DO_SMI_CHECK);
- } else {
- ASSERT(HeapType::Any()->Is(field_type));
- __ JumpIfSmi(value_reg, miss_label);
- }
+ __ JumpIfSmi(value_reg, miss_label);
} else if (representation.IsDouble()) {
// Load the double storage.
if (index < 0) {
+++ /dev/null
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax --nostress-opt --track-field-types
-
-(function() {
- var o = { text: "Hello World!" };
- function A() {
- this.a = o;
- }
- function readA(x) {
- return x.a;
- }
- var a = new A();
- assertUnoptimized(readA);
- readA(a); readA(a); readA(a);
- %OptimizeFunctionOnNextCall(readA);
- assertEquals(readA(a), o);
- assertOptimized(readA);
-
- var b = new A();
- b.b = o;
- assertEquals(readA(b), o);
- assertUnoptimized(readA);
- %OptimizeFunctionOnNextCall(readA);
- assertEquals(readA(a), o);
- assertOptimized(readA);
- assertEquals(readA(a), o);
- assertEquals(readA(b), o);
- assertOptimized(readA);
-
- function readAFromB(x) {
- return x.a;
- }
- assertUnoptimized(readAFromB);
- readAFromB(b); readAFromB(b); readAFromB(b);
- %OptimizeFunctionOnNextCall(readAFromB);
- assertEquals(readAFromB(b), o);
- assertOptimized(readAFromB);
-
- var c = new A();
- c.c = o;
- assertOptimized(readA);
- assertOptimized(readAFromB);
- c.a = [1];
- assertUnoptimized(readA);
- assertUnoptimized(readAFromB);
- assertEquals(readA(a), o);
- assertEquals(readA(b), o);
- assertEquals(readA(c), [1]);
- assertEquals(readAFromB(b), o);
-
- %OptimizeFunctionOnNextCall(readA);
- assertEquals(readA(a), o);
- %OptimizeFunctionOnNextCall(readAFromB);
- assertEquals(readAFromB(b), o);
- assertOptimized(readA);
- a.a = [1];
- assertEquals(readA(a), [1]);
- assertEquals(readA(b), o);
- assertEquals(readA(c), [1]);
- assertOptimized(readA);
- b.a = [1];
- assertEquals(readA(a), [1]);
- assertEquals(readA(b), [1]);
- assertEquals(readA(c), [1]);
- assertOptimized(readA);
- assertOptimized(readAFromB);
-})();
-
-(function() {
- function A() { this.x = 0; }
- A.prototype = {y: 20};
- function B(o) { return o.a.y; }
- function C() { this.a = new A(); }
-
- B(new C());
- B(new C());
- %OptimizeFunctionOnNextCall(B);
- var c = new C();
- assertEquals(20, B(c));
- assertOptimized(B);
- c.a.y = 10;
- assertEquals(10, B(c));
- assertUnoptimized(B);
-
- var c = new C();
- %OptimizeFunctionOnNextCall(B);
- assertEquals(20, B(c));
- assertOptimized(B);
- c.a.y = 30;
- assertEquals(30, B(c));
- assertOptimized(B);
-})();
-
-(function() {
- var x = new Object();
- x.a = 1 + "Long string that results in a cons string";
- x = JSON.parse('{"a":"Short"}');
-})();
-
-(function() {
- var x = {y: {z: 1}};
- x.y.z = 1.1;
-})();