[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: Jaroslav Sevcik <jarin@chromium.org> Cr-Commit-Position: refs/heads/master@{#49358}
This commit is contained in:
parent
c56cff2359
commit
48e5ec9ea6
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user