Commit 48e5ec9e authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[runtime] Change FieldIndex encoding so it supports unaligned offsets and can load single words

Unaligned access is still unused, but will be necessary to load String-length
once we store it as an int32 next to the hash-field.

Bug: v8:7065
Change-Id: I7fa9364e062774c0a6b32e7f961031dcd30c564c
Reviewed-on: https://chromium-review.googlesource.com/763349
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49358}
parent c56cff23
...@@ -43,13 +43,12 @@ Handle<AccessorInfo> Accessors::MakeAccessor( ...@@ -43,13 +43,12 @@ Handle<AccessorInfo> Accessors::MakeAccessor(
return info; return info;
} }
static V8_INLINE bool CheckForName(Handle<Name> name, static V8_INLINE bool CheckForName(Handle<Name> name,
Handle<String> property_name, Handle<String> property_name, int offset,
int offset, FieldIndex::Encoding encoding,
int* object_offset) { FieldIndex* index) {
if (Name::Equals(name, property_name)) { if (Name::Equals(name, property_name)) {
*object_offset = offset; *index = FieldIndex::ForInObjectOffset(offset, encoding);
return true; return true;
} }
return false; return false;
...@@ -59,18 +58,17 @@ static V8_INLINE bool CheckForName(Handle<Name> name, ...@@ -59,18 +58,17 @@ static V8_INLINE bool CheckForName(Handle<Name> name,
// Returns true for properties that are accessors to object fields. // Returns true for properties that are accessors to object fields.
// If true, *object_offset contains offset of object field. // If true, *object_offset contains offset of object field.
bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name, bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
int* object_offset) { FieldIndex* index) {
Isolate* isolate = name->GetIsolate(); Isolate* isolate = name->GetIsolate();
switch (map->instance_type()) { switch (map->instance_type()) {
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
return return CheckForName(name, isolate->factory()->length_string(),
CheckForName(name, isolate->factory()->length_string(), JSArray::kLengthOffset, FieldIndex::kTagged, index);
JSArray::kLengthOffset, object_offset);
default: default:
if (map->instance_type() < FIRST_NONSTRING_TYPE) { if (map->instance_type() < FIRST_NONSTRING_TYPE) {
return CheckForName(name, isolate->factory()->length_string(), return CheckForName(name, isolate->factory()->length_string(),
String::kLengthOffset, object_offset); String::kLengthOffset, FieldIndex::kTagged, index);
} }
return false; return false;
......
...@@ -17,6 +17,7 @@ namespace internal { ...@@ -17,6 +17,7 @@ namespace internal {
class AccessorInfo; class AccessorInfo;
template <typename T> template <typename T>
class Handle; class Handle;
class FieldIndex;
// The list of accessor descriptors. This is a second-order macro // The list of accessor descriptors. This is a second-order macro
// taking a macro to be applied to all accessor descriptor names. // taking a macro to be applied to all accessor descriptor names.
...@@ -81,9 +82,9 @@ class Accessors : public AllStatic { ...@@ -81,9 +82,9 @@ class Accessors : public AllStatic {
static Handle<JSObject> FunctionGetArguments(Handle<JSFunction> object); static Handle<JSObject> FunctionGetArguments(Handle<JSFunction> object);
// Returns true for properties that are accessors to object fields. // Returns true for properties that are accessors to object fields.
// If true, *object_offset contains offset of object field. // If true, the matching FieldIndex is returned through |field_index|.
static bool IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name, static bool IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
int* object_offset); FieldIndex* field_index);
// Create an AccessorInfo. The setter is optional (can be nullptr). // Create an AccessorInfo. The setter is optional (can be nullptr).
// //
......
...@@ -360,8 +360,8 @@ bool AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -360,8 +360,8 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
if (details.kind() == kData) { if (details.kind() == kData) {
int index = descriptors->GetFieldIndex(number); int index = descriptors->GetFieldIndex(number);
Representation details_representation = details.representation(); Representation details_representation = details.representation();
FieldIndex field_index = FieldIndex::ForPropertyIndex( FieldIndex field_index =
*map, index, details_representation.IsDouble()); FieldIndex::ForPropertyIndex(*map, index, details_representation);
Type* field_type = Type::NonInternal(); Type* field_type = Type::NonInternal();
MachineRepresentation field_representation = MachineRepresentation field_representation =
MachineRepresentation::kTagged; MachineRepresentation::kTagged;
...@@ -600,9 +600,8 @@ bool AccessInfoFactory::ConsolidateElementLoad(MapHandles const& maps, ...@@ -600,9 +600,8 @@ bool AccessInfoFactory::ConsolidateElementLoad(MapHandles const& maps,
bool AccessInfoFactory::LookupSpecialFieldAccessor( bool AccessInfoFactory::LookupSpecialFieldAccessor(
Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
// Check for special JSObject field accessors. // Check for special JSObject field accessors.
int offset; FieldIndex field_index;
if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { if (Accessors::IsJSObjectFieldAccessor(map, name, &field_index)) {
FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
Type* field_type = Type::NonInternal(); Type* field_type = Type::NonInternal();
MachineRepresentation field_representation = MachineRepresentation::kTagged; MachineRepresentation field_representation = MachineRepresentation::kTagged;
if (map->IsStringMap()) { if (map->IsStringMap()) {
...@@ -656,8 +655,8 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name, ...@@ -656,8 +655,8 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
if (details.location() != kField) return false; if (details.location() != kField) return false;
int const index = details.field_index(); int const index = details.field_index();
Representation details_representation = details.representation(); Representation details_representation = details.representation();
FieldIndex field_index = FieldIndex::ForPropertyIndex( FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index,
*transition_map, index, details_representation.IsDouble()); details_representation);
Type* field_type = Type::NonInternal(); Type* field_type = Type::NonInternal();
MaybeHandle<Map> field_map; MaybeHandle<Map> field_map;
MachineRepresentation field_representation = MachineRepresentation::kTagged; MachineRepresentation field_representation = MachineRepresentation::kTagged;
......
...@@ -12,31 +12,33 @@ ...@@ -12,31 +12,33 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
inline FieldIndex FieldIndex::ForInObjectOffset(int offset, const Map* map) { inline FieldIndex FieldIndex::ForInObjectOffset(int offset, Encoding encoding,
DCHECK_EQ(offset % kPointerSize, 0); const Map* map) {
int index = offset / kPointerSize; DCHECK(map == nullptr || offset < map->instance_size());
DCHECK(map == nullptr || DCHECK(encoding == kWord32 ? (offset % kInt32Size) == 0
index < (map->GetInObjectPropertyOffset(0) / kPointerSize + : (offset % kPointerSize) == 0);
map->GetInObjectProperties())); return FieldIndex(true, offset, encoding, 0, 0);
return FieldIndex(true, index, false, 0, 0, true);
} }
inline FieldIndex FieldIndex::ForPropertyIndex(const Map* map, inline FieldIndex FieldIndex::ForPropertyIndex(const Map* map,
int property_index, int property_index,
bool is_double) { Representation representation) {
DCHECK(map->instance_type() >= FIRST_NONSTRING_TYPE); DCHECK(map->instance_type() >= FIRST_NONSTRING_TYPE);
int inobject_properties = map->GetInObjectProperties(); int inobject_properties = map->GetInObjectProperties();
bool is_inobject = property_index < inobject_properties; bool is_inobject = property_index < inobject_properties;
int first_inobject_offset; int first_inobject_offset;
int offset;
if (is_inobject) { if (is_inobject) {
first_inobject_offset = map->GetInObjectPropertyOffset(0); first_inobject_offset = map->GetInObjectPropertyOffset(0);
offset = map->GetInObjectPropertyOffset(property_index);
} else { } else {
first_inobject_offset = FixedArray::kHeaderSize; first_inobject_offset = FixedArray::kHeaderSize;
property_index -= inobject_properties; property_index -= inobject_properties;
offset = FixedArray::kHeaderSize + property_index * kPointerSize;
} }
return FieldIndex(is_inobject, Encoding encoding = FieldEncoding(representation);
property_index + first_inobject_offset / kPointerSize, return FieldIndex(is_inobject, offset, encoding, inobject_properties,
is_double, inobject_properties, first_inobject_offset); first_inobject_offset);
} }
// Takes an index as computed by GetLoadByFieldIndex and reconstructs a // Takes an index as computed by GetLoadByFieldIndex and reconstructs a
...@@ -45,21 +47,22 @@ inline FieldIndex FieldIndex::ForLoadByFieldIndex(const Map* map, ...@@ -45,21 +47,22 @@ inline FieldIndex FieldIndex::ForLoadByFieldIndex(const Map* map,
int orig_index) { int orig_index) {
int field_index = orig_index; int field_index = orig_index;
bool is_inobject = true; bool is_inobject = true;
bool is_double = field_index & 1;
int first_inobject_offset = 0; int first_inobject_offset = 0;
Encoding encoding = field_index & 1 ? kDouble : kTagged;
field_index >>= 1; field_index >>= 1;
int offset;
if (field_index < 0) { if (field_index < 0) {
first_inobject_offset = FixedArray::kHeaderSize;
field_index = -(field_index + 1); field_index = -(field_index + 1);
is_inobject = false; is_inobject = false;
first_inobject_offset = FixedArray::kHeaderSize; offset = FixedArray::kHeaderSize + field_index * kPointerSize;
field_index += FixedArray::kHeaderSize / kPointerSize;
} else { } else {
first_inobject_offset = map->GetInObjectPropertyOffset(0); first_inobject_offset = map->GetInObjectPropertyOffset(0);
field_index += JSObject::kHeaderSize / kPointerSize; offset = map->GetInObjectPropertyOffset(field_index);
} }
FieldIndex result(is_inobject, field_index, is_double, FieldIndex result(is_inobject, offset, encoding, map->GetInObjectProperties(),
map->GetInObjectProperties(), first_inobject_offset); first_inobject_offset);
DCHECK(result.GetLoadByFieldIndex() == orig_index); DCHECK_EQ(result.GetLoadByFieldIndex(), orig_index);
return result; return result;
} }
...@@ -90,12 +93,7 @@ inline FieldIndex FieldIndex::ForDescriptor(const Map* map, ...@@ -90,12 +93,7 @@ inline FieldIndex FieldIndex::ForDescriptor(const Map* map,
PropertyDetails details = PropertyDetails details =
map->instance_descriptors()->GetDetails(descriptor_index); map->instance_descriptors()->GetDetails(descriptor_index);
int field_index = details.field_index(); int field_index = details.field_index();
return ForPropertyIndex(map, field_index, return ForPropertyIndex(map, field_index, details.representation());
details.representation().IsDouble());
}
inline FieldIndex FieldIndex::FromFieldAccessStubKey(int key) {
return FieldIndex(key);
} }
} // namespace internal } // namespace internal
......
...@@ -19,14 +19,17 @@ class Map; ...@@ -19,14 +19,17 @@ class Map;
// index it was originally generated from. // index it was originally generated from.
class FieldIndex final { class FieldIndex final {
public: public:
enum Encoding { kTagged, kDouble, kWord32 };
FieldIndex() : bit_field_(0) {} FieldIndex() : bit_field_(0) {}
static FieldIndex ForPropertyIndex(const Map* map, int index, static FieldIndex ForPropertyIndex(
bool is_double = false); const Map* map, int index,
static FieldIndex ForInObjectOffset(int offset, const Map* map = nullptr); Representation representation = Representation::Tagged());
static FieldIndex ForInObjectOffset(int offset, Encoding encoding,
const Map* map = nullptr);
static FieldIndex ForDescriptor(const Map* map, int descriptor_index); static FieldIndex ForDescriptor(const Map* map, int descriptor_index);
static FieldIndex ForLoadByFieldIndex(const Map* map, int index); static FieldIndex ForLoadByFieldIndex(const Map* map, int index);
static FieldIndex FromFieldAccessStubKey(int key);
int GetLoadByFieldIndex() const; int GetLoadByFieldIndex() const;
...@@ -36,17 +39,14 @@ class FieldIndex final { ...@@ -36,17 +39,14 @@ class FieldIndex final {
bool is_hidden_field() const { return IsHiddenField::decode(bit_field_); } bool is_hidden_field() const { return IsHiddenField::decode(bit_field_); }
bool is_double() const { bool is_double() const { return EncodingBits::decode(bit_field_) == kDouble; }
return IsDoubleBits::decode(bit_field_);
}
int offset() const { int offset() const { return OffsetBits::decode(bit_field_); }
return index() * kPointerSize;
}
// Zero-indexed from beginning of the object. // Zero-indexed from beginning of the object.
int index() const { int index() const {
return IndexBits::decode(bit_field_); DCHECK_EQ(0, offset() % kPointerSize);
return offset() / kPointerSize;
} }
int outobject_array_index() const { int outobject_array_index() const {
...@@ -67,7 +67,7 @@ class FieldIndex final { ...@@ -67,7 +67,7 @@ class FieldIndex final {
int GetFieldAccessStubKey() const { int GetFieldAccessStubKey() const {
return bit_field_ & return bit_field_ &
(IsInObjectBits::kMask | IsDoubleBits::kMask | IndexBits::kMask); (IsInObjectBits::kMask | EncodingBits::kMask | OffsetBits::kMask);
} }
bool operator==(FieldIndex const& other) const { bool operator==(FieldIndex const& other) const {
...@@ -76,42 +76,59 @@ class FieldIndex final { ...@@ -76,42 +76,59 @@ class FieldIndex final {
bool operator!=(FieldIndex const& other) const { return !(*this == other); } bool operator!=(FieldIndex const& other) const { return !(*this == other); }
private: private:
FieldIndex(bool is_inobject, int local_index, bool is_double, FieldIndex(bool is_inobject, int offset, Encoding encoding,
int inobject_properties, int first_inobject_property_offset, int inobject_properties, int first_inobject_property_offset,
bool is_hidden = false) { bool is_hidden = false) {
DCHECK_EQ(first_inobject_property_offset & (kPointerSize - 1), 0); DCHECK_EQ(first_inobject_property_offset & (kPointerSize - 1), 0);
bit_field_ = IsInObjectBits::encode(is_inobject) | bit_field_ = IsInObjectBits::encode(is_inobject) |
IsDoubleBits::encode(is_double) | EncodingBits::encode(encoding) |
FirstInobjectPropertyOffsetBits::encode(first_inobject_property_offset) | FirstInobjectPropertyOffsetBits::encode(
IsHiddenField::encode(is_hidden) | first_inobject_property_offset) |
IndexBits::encode(local_index) | IsHiddenField::encode(is_hidden) | OffsetBits::encode(offset) |
InObjectPropertyBits::encode(inobject_properties); InObjectPropertyBits::encode(inobject_properties);
} }
explicit FieldIndex(int bit_field) : bit_field_(bit_field) {} static Encoding FieldEncoding(Representation representation) {
switch (representation.kind()) {
case Representation::kNone:
case Representation::kSmi:
case Representation::kHeapObject:
case Representation::kTagged:
return kTagged;
case Representation::kDouble:
return kDouble;
default:
break;
}
PrintF("%s\n", representation.Mnemonic());
UNREACHABLE();
return kTagged;
}
int first_inobject_property_offset() const { int first_inobject_property_offset() const {
DCHECK(!is_hidden_field()); DCHECK(!is_hidden_field());
return FirstInobjectPropertyOffsetBits::decode(bit_field_); return FirstInobjectPropertyOffsetBits::decode(bit_field_);
} }
static const int kIndexBitsSize = kDescriptorIndexBitCount + 1; static const int kOffsetBitsSize =
(kDescriptorIndexBitCount + 1 + kPointerSizeLog2);
// Index from beginning of object. // Index from beginning of object.
class IndexBits: public BitField<int, 0, kIndexBitsSize> {}; class OffsetBits : public BitField64<int, 0, kOffsetBitsSize> {};
class IsInObjectBits: public BitField<bool, IndexBits::kNext, 1> {}; class IsInObjectBits : public BitField64<bool, OffsetBits::kNext, 1> {};
class IsDoubleBits: public BitField<bool, IsInObjectBits::kNext, 1> {}; class EncodingBits : public BitField64<Encoding, IsInObjectBits::kNext, 2> {};
// Number of inobject properties. // Number of inobject properties.
class InObjectPropertyBits class InObjectPropertyBits
: public BitField<int, IsDoubleBits::kNext, kDescriptorIndexBitCount> {}; : public BitField64<int, EncodingBits::kNext, kDescriptorIndexBitCount> {
};
// Offset of first inobject property from beginning of object. // Offset of first inobject property from beginning of object.
class FirstInobjectPropertyOffsetBits class FirstInobjectPropertyOffsetBits
: public BitField<int, InObjectPropertyBits::kNext, 7> {}; : public BitField64<int, InObjectPropertyBits::kNext, 7> {};
class IsHiddenField class IsHiddenField
: public BitField<bool, FirstInobjectPropertyOffsetBits::kNext, 1> {}; : public BitField64<bool, FirstInobjectPropertyOffsetBits::kNext, 1> {};
STATIC_ASSERT(IsHiddenField::kNext <= 32); STATIC_ASSERT(IsHiddenField::kNext <= 64);
int bit_field_; uint64_t bit_field_;
}; };
} // namespace internal } // namespace internal
......
...@@ -711,7 +711,8 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -711,7 +711,8 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (receiver->IsString() && if (receiver->IsString() &&
*lookup->name() == isolate()->heap()->length_string()) { *lookup->name() == isolate()->heap()->length_string()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset,
FieldIndex::kTagged);
return LoadHandler::LoadField(isolate(), index); return LoadHandler::LoadField(isolate(), index);
} }
...@@ -768,11 +769,9 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -768,11 +769,9 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
// Use simple field loads for some well-known callback properties. // Use simple field loads for some well-known callback properties.
// The method will only return true for absolute truths based on the // The method will only return true for absolute truths based on the
// receiver maps. // receiver maps.
int object_offset; FieldIndex index;
if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), &index)) {
&object_offset)) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
return LoadHandler::LoadField(isolate(), index); return LoadHandler::LoadField(isolate(), index);
} }
if (holder->IsJSModuleNamespace()) { if (holder->IsJSModuleNamespace()) {
......
...@@ -778,11 +778,7 @@ FieldIndex LookupIterator::GetFieldIndex() const { ...@@ -778,11 +778,7 @@ FieldIndex LookupIterator::GetFieldIndex() const {
DCHECK(holder_->HasFastProperties()); DCHECK(holder_->HasFastProperties());
DCHECK_EQ(kField, property_details_.location()); DCHECK_EQ(kField, property_details_.location());
DCHECK(!IsElement()); DCHECK(!IsElement());
Map* holder_map = holder_->map(); return FieldIndex::ForDescriptor(holder_->map(), descriptor_number());
int index =
holder_map->instance_descriptors()->GetFieldIndex(descriptor_number());
bool is_double = representation().IsDouble();
return FieldIndex::ForPropertyIndex(holder_map, index, is_double);
} }
Handle<FieldType> LookupIterator::GetFieldType() const { Handle<FieldType> LookupIterator::GetFieldType() const {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment