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