Chromium Code Reviews| Index: src/objects-inl.h |
| diff --git a/src/objects-inl.h b/src/objects-inl.h |
| index c00ecddb565afc5529e44a840c594e9dcf59dfa4..80bb5b51b629f6431fcb1644b426e7f4505d58bb 100644 |
| --- a/src/objects-inl.h |
| +++ b/src/objects-inl.h |
| @@ -56,6 +56,14 @@ PropertyDetails PropertyDetails::AsDeleted() const { |
| } |
| +int PropertyDetails::field_width_in_words() const { |
| + DCHECK(type() == FIELD); |
| + if (!FLAG_unbox_double_fields) return 1; |
| + if (kDoubleSize == kPointerSize) return 1; |
| + return representation().IsDouble() ? kDoubleSize / kPointerSize : 1; |
| +} |
| + |
| + |
| #define TYPE_CHECKER(type, instancetype) \ |
| bool Object::Is##type() const { \ |
| return Object::IsHeapObject() && \ |
| @@ -704,6 +712,11 @@ bool Object::IsDescriptorArray() const { |
| } |
| +bool Object::IsLayoutDescriptor() const { |
| + return IsSmi() || IsFixedTypedArrayBase(); |
| +} |
| + |
| + |
| bool Object::IsTransitionArray() const { |
| return IsFixedArray(); |
| } |
| @@ -2062,10 +2075,25 @@ void JSObject::SetInternalField(int index, Smi* value) { |
| } |
| +bool JSObject::IsUnboxedDoubleField(FieldIndex index) { |
| + if (!FLAG_unbox_double_fields) return false; |
| + if (index.is_hidden_field() || !index.is_inobject()) return false; |
| + return !map()->layout_descriptor()->IsTagged(index.property_index()); |
| +} |
| + |
| + |
| +bool Map::IsUnboxedDoubleField(FieldIndex index) { |
| + if (!FLAG_unbox_double_fields) return false; |
| + if (index.is_hidden_field() || !index.is_inobject()) return false; |
| + return !layout_descriptor()->IsTagged(index.property_index()); |
| +} |
| + |
| + |
| // Access fast-case object properties at index. The use of these routines |
| // is needed to correctly distinguish between properties stored in-object and |
| // properties stored in the properties array. |
| Object* JSObject::RawFastPropertyAt(FieldIndex index) { |
| + DCHECK(!IsUnboxedDoubleField(index)); |
| if (index.is_inobject()) { |
| return READ_FIELD(this, index.offset()); |
| } else { |
| @@ -2074,7 +2102,13 @@ Object* JSObject::RawFastPropertyAt(FieldIndex index) { |
| } |
| -void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) { |
| +double JSObject::RawFastDoublePropertyAt(FieldIndex index) { |
| + DCHECK(IsUnboxedDoubleField(index)); |
| + return READ_DOUBLE_FIELD(this, index.offset()); |
| +} |
| + |
| + |
| +void JSObject::RawFastPropertyAtPut(FieldIndex index, Object* value) { |
| if (index.is_inobject()) { |
| int offset = index.offset(); |
| WRITE_FIELD(this, offset, value); |
| @@ -2085,6 +2119,21 @@ void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) { |
| } |
| +void JSObject::RawFastDoublePropertyAtPut(FieldIndex index, double value) { |
| + WRITE_DOUBLE_FIELD(this, index.offset(), value); |
| +} |
| + |
| + |
| +void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) { |
| + if (IsUnboxedDoubleField(index)) { |
| + DCHECK(value->IsMutableHeapNumber()); |
| + RawFastDoublePropertyAtPut(index, HeapNumber::cast(value)->value()); |
| + } else { |
| + RawFastPropertyAtPut(index, value); |
| + } |
| +} |
| + |
| + |
| int JSObject::GetInObjectPropertyOffset(int index) { |
| return map()->GetInObjectPropertyOffset(index); |
| } |
| @@ -3082,8 +3131,7 @@ void DescriptorArray::Set(int descriptor_number, |
| NoIncrementalWriteBarrierSet(this, |
| ToValueIndex(descriptor_number), |
| *desc->GetValue()); |
| - NoIncrementalWriteBarrierSet(this, |
| - ToDetailsIndex(descriptor_number), |
| + NoIncrementalWriteBarrierSet(this, ToDetailsIndex(descriptor_number), |
| desc->GetDetails().AsSmi()); |
| } |
| @@ -3138,6 +3186,176 @@ DescriptorArray::WhitenessWitness::~WhitenessWitness() { |
| } |
| +LayoutDescriptor* LayoutDescriptor::FromSmi(Smi* smi) { |
| + return LayoutDescriptor::cast(smi); |
| +} |
| + |
| + |
| +Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) { |
| + if (length <= kSmiValueSize) { |
| + // The whole bit vector fits into a smi. |
| + return handle(LayoutDescriptor::FromSmi(Smi::FromInt(0)), isolate); |
| + } |
| + |
| + length = (length + kNumberOfBits - 1) / kNumberOfBits; |
| + DCHECK(length > 0); |
| + |
|
Toon Verwaest
2014/10/31 16:23:41
Add a comment why this is a good idea (not wasting
Igor Sheludko
2014/11/03 12:47:23
Done.
|
| + if (SmiValuesAre32Bits() && (length & 1)) { |
| + ++length; // Make kPtrSize aligned |
| + } |
| + return Handle<LayoutDescriptor>::cast( |
| + isolate->factory()->NewFixedTypedArray(length, kExternalUint32Array)); |
| +} |
| + |
| + |
| +bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties, |
| + PropertyDetails details) { |
| + if (details.type() != FIELD || !details.representation().IsDouble()) { |
| + return false; |
| + } |
| + int field_index = details.field_index(); |
| + // We care only about in-object properties. |
| + if (field_index >= inobject_properties) { |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| + |
| +LayoutDescriptor* LayoutDescriptor::FastPointerLayout() { |
| + return LayoutDescriptor::FromSmi(Smi::FromInt(0)); |
| +} |
| + |
| + |
| +bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index, |
| + uint32_t* layout_mask) { |
| + if (field_index >= capacity()) return false; |
| + |
| + *layout_word_index = field_index / kNumberOfBits; |
| + CHECK((!IsSmi() && (*layout_word_index < length())) || |
| + (IsSmi() && (*layout_word_index < 1))); |
| + |
| + int layout_bit_index = field_index % kNumberOfBits; |
| + *layout_mask = static_cast<uint32_t>(1) << layout_bit_index; |
| + return true; |
| +} |
| + |
| + |
| +LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) { |
| + int layout_word_index; |
| + uint32_t layout_mask; |
| + |
| + if (!GetIndexes(field_index, &layout_word_index, &layout_mask)) { |
| + CHECK(!"Bad index"); |
| + return this; |
| + } |
| + |
| + if (IsSlowLayout()) { |
| + uint32_t value = get_scalar(layout_word_index); |
| + if (tagged) { |
| + value &= ~layout_mask; |
| + } else { |
| + value |= layout_mask; |
| + } |
| + set(layout_word_index, value); |
| + return this; |
| + } else { |
| + uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value()); |
| + if (tagged) { |
| + value &= ~layout_mask; |
| + } else { |
| + value |= layout_mask; |
| + } |
| + return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value))); |
| + } |
| +} |
| + |
| + |
| +bool LayoutDescriptor::IsTagged(int field_index) { |
| + if (IsFastPointerLayout()) return true; |
| + |
| + int layout_word_index; |
| + uint32_t layout_mask; |
| + |
| + if (!GetIndexes(field_index, &layout_word_index, &layout_mask)) { |
| + // All bits after Out of bounds queries |
| + return true; |
| + } |
| + |
| + if (IsSlowLayout()) { |
| + uint32_t value = get_scalar(layout_word_index); |
| + return (value & layout_mask) == 0; |
| + } else { |
| + uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value()); |
| + return (value & layout_mask) == 0; |
| + } |
| +} |
| + |
| + |
| +bool LayoutDescriptor::IsFastPointerLayout() { |
| + return IsSmi() && (Smi::cast(this)->value() == 0); |
| +} |
| + |
| + |
| +bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); } |
| + |
| + |
| +int LayoutDescriptor::capacity() { |
| + return IsSlowLayout() ? (length() * kNumberOfBits) : kSmiValueSize; |
| +} |
| + |
| + |
| +LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) { |
| + if (object->IsSmi()) { |
| + // Either fast mode or forwarding pointer. |
| + LayoutDescriptor* layout_desc = reinterpret_cast<LayoutDescriptor*>(object); |
| + return layout_desc; |
| + } |
| + |
| + // This is a mixed descriptor which is a fixed typed array. |
| + MapWord map_word = reinterpret_cast<HeapObject*>(object)->map_word(); |
| + if (map_word.IsForwardingAddress()) { |
| + // Mark-compact has already moved layout descriptor. |
| + object = map_word.ToForwardingAddress(); |
| + } |
| + return LayoutDescriptor::cast(object); |
| +} |
| + |
| + |
| +// InobjectPropertiesHelper is a helper class for querying whether inobject |
| +// property at offset is Double or not. |
| +InobjectPropertiesHelper::InobjectPropertiesHelper(Map* map) |
| + : all_fields_tagged_(true), |
| + header_size_(0), |
| + inobject_properties_count_(0), |
| + layout_descriptor_(LayoutDescriptor::FastPointerLayout()) { |
| + if (!FLAG_unbox_double_fields) return; |
| + |
| + layout_descriptor_ = map->layout_descriptor_gc_safe(); |
| + if (layout_descriptor_->IsFastPointerLayout()) { |
| + return; |
| + } |
| + |
| + int inobject_properties = map->inobject_properties(); |
| + DCHECK(inobject_properties > 0); |
| + header_size_ = map->instance_size() - (inobject_properties * kPointerSize); |
| + DCHECK(header_size_ >= 0); |
| + |
| + all_fields_tagged_ = false; |
| +} |
| + |
| + |
| +bool InobjectPropertiesHelper::IsTagged(int offset_in_bytes) { |
| + DCHECK(IsAligned(offset_in_bytes, kPointerSize)); |
| + if (all_fields_tagged_) return true; |
| + // Object headers do not contain non-tagged fields. |
| + if (offset_in_bytes < header_size_) return true; |
| + int field_index = (offset_in_bytes - header_size_) / kPointerSize; |
| + |
| + return layout_descriptor_->IsTagged(field_index); |
| +} |
| + |
| + |
| template<typename Derived, typename Shape, typename Key> |
| int HashTable<Derived, Shape, Key>::ComputeCapacity(int at_least_space_for) { |
| const int kMinCapacity = 32; |
| @@ -3258,6 +3476,7 @@ CAST_ACCESSOR(JSTypedArray) |
| CAST_ACCESSOR(JSValue) |
| CAST_ACCESSOR(JSWeakMap) |
| CAST_ACCESSOR(JSWeakSet) |
| +CAST_ACCESSOR(LayoutDescriptor) |
| CAST_ACCESSOR(Map) |
| CAST_ACCESSOR(MapCache) |
| CAST_ACCESSOR(Name) |
| @@ -5141,14 +5360,41 @@ static void EnsureHasTransitionArray(Handle<Map> map) { |
| } |
| -void Map::InitializeDescriptors(DescriptorArray* descriptors) { |
| +LayoutDescriptor* Map::layout_descriptor_gc_safe() { |
| + Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset); |
| + return LayoutDescriptor::cast_gc_safe(layout_desc); |
| +} |
| + |
| + |
| +void Map::UpdateDescriptors(DescriptorArray* descriptors, |
| + LayoutDescriptor* layout_desc) { |
| + set_instance_descriptors(descriptors); |
| + if (FLAG_unbox_double_fields) { |
| + if (layout_descriptor()->IsSlowLayout()) { |
| + set_layout_descriptor(layout_desc); |
| + } |
| + SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(this)); |
| + DCHECK(visitor_id() == StaticVisitorBase::GetVisitorId(this)); |
| + } |
| +} |
| + |
| + |
| +void Map::InitializeDescriptors(DescriptorArray* descriptors, |
| + LayoutDescriptor* layout_desc) { |
| int len = descriptors->number_of_descriptors(); |
| set_instance_descriptors(descriptors); |
| SetNumberOfOwnDescriptors(len); |
| + |
| + if (FLAG_unbox_double_fields) { |
| + set_layout_descriptor(layout_desc); |
| + SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(this)); |
| + set_visitor_id(StaticVisitorBase::GetVisitorId(this)); |
| + } |
| } |
| ACCESSORS(Map, instance_descriptors, DescriptorArray, kDescriptorsOffset) |
| +ACCESSORS(Map, layout_descriptor, LayoutDescriptor, kLayoutDecriptorOffset) |
| void Map::set_bit_field3(uint32_t bits) { |
| @@ -5164,12 +5410,27 @@ uint32_t Map::bit_field3() { |
| } |
| +Handle<LayoutDescriptor> Map::GetLayoutDescriptor() { |
| + LayoutDescriptor* layout_desc = FLAG_unbox_double_fields |
| + ? layout_descriptor() |
| + : LayoutDescriptor::FastPointerLayout(); |
| + return handle(layout_desc, GetIsolate()); |
| +} |
| + |
| + |
| void Map::AppendDescriptor(Descriptor* desc) { |
| DescriptorArray* descriptors = instance_descriptors(); |
| int number_of_own_descriptors = NumberOfOwnDescriptors(); |
| DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors); |
| descriptors->Append(desc); |
| SetNumberOfOwnDescriptors(number_of_own_descriptors + 1); |
| + |
| +// This function does not support appending double field descriptors and |
| +// it should never try to (otherwise, layout descriptor must be updated too). |
| +#ifdef DEBUG |
| + PropertyDetails details = desc->GetDetails(); |
| + CHECK(details.type() != FIELD || !details.representation().IsDouble()); |
| +#endif |
| } |
| @@ -7201,12 +7462,36 @@ void ExternalTwoByteString::ExternalTwoByteStringIterateBody() { |
| } |
| +static void IterateBodyUsingLayoutDescriptor(HeapObject* object, |
| + int start_offset, int end_offset, |
| + ObjectVisitor* v) { |
| + DCHECK(FLAG_unbox_double_fields); |
| + DCHECK(IsAligned(start_offset, kPointerSize) && |
| + IsAligned(end_offset, kPointerSize)); |
| + |
| + InobjectPropertiesHelper helper(object->map()); |
| + DCHECK(!helper.all_fields_tagged()); |
| + |
| + for (int offset = start_offset; offset < end_offset; offset += kPointerSize) { |
| + // Visit all tagged fields. |
| + if (helper.IsTagged(offset)) { |
| + v->VisitPointer(HeapObject::RawField(object, offset)); |
| + } |
| + } |
| +} |
| + |
| + |
| template<int start_offset, int end_offset, int size> |
| void FixedBodyDescriptor<start_offset, end_offset, size>::IterateBody( |
| HeapObject* obj, |
| ObjectVisitor* v) { |
| + if (!FLAG_unbox_double_fields || |
| + obj->map()->layout_descriptor()->IsFastPointerLayout()) { |
| v->VisitPointers(HeapObject::RawField(obj, start_offset), |
| HeapObject::RawField(obj, end_offset)); |
| + } else { |
| + IterateBodyUsingLayoutDescriptor(obj, start_offset, end_offset, v); |
| + } |
| } |
| @@ -7214,8 +7499,13 @@ template<int start_offset> |
| void FlexibleBodyDescriptor<start_offset>::IterateBody(HeapObject* obj, |
| int object_size, |
| ObjectVisitor* v) { |
| - v->VisitPointers(HeapObject::RawField(obj, start_offset), |
| - HeapObject::RawField(obj, object_size)); |
| + if (!FLAG_unbox_double_fields || |
| + obj->map()->layout_descriptor()->IsFastPointerLayout()) { |
| + v->VisitPointers(HeapObject::RawField(obj, start_offset), |
| + HeapObject::RawField(obj, object_size)); |
| + } else { |
| + IterateBodyUsingLayoutDescriptor(obj, start_offset, object_size, v); |
| + } |
| } |