Commit f1400e43 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] improve GC visitors

Summary of changes:

- GC visitors no longer rely on superclass visitors, but instead visit
  everything themselves. This enables generating better code.
- Try to match simple body descriptors to reduce the amount of generated
  code.
- Turn SizeFor(instance) into an AllocatedSize() method.
- Remove the special handling of resizable object sizes from Torque
  and instead overwrite AllocatedSize in classes that need special
  handling in C++.
- Split the visitor id lists depending on whether the class has pointer
  fields.
- Turn Torque-generated body descriptors into an .inc file to
  simplify includes.
- Fix generated size functions to properly align the size.
- Generate GC visitors (and C++ class definitions) for all string
  classes and FixedArray, WeakFixedArray, and WeakArrayList.
- Store generated instance types in Torque class types. This is only
  used to determine if a type has a single instance type in this CL.

Bug: v8:7793
Change-Id: I4d362e96b047c305bd6d065247734957b8958c42
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2110014
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67542}
parent 0d449054
......@@ -1211,7 +1211,7 @@ template("run_torque") {
"class-verifiers-tq.h",
"enum-verifiers-tq.cc",
"objects-printer-tq.cc",
"objects-body-descriptors-tq-inl.h",
"objects-body-descriptors-tq-inl.inc",
"class-definitions-tq.cc",
"class-definitions-tq-inl.h",
"class-definitions-tq.h",
......
......@@ -18,7 +18,6 @@
#include "src/objects/oddball.h"
#include "src/objects/ordered-hash-table.h"
#include "src/wasm/wasm-objects.h"
#include "torque-generated/objects-body-descriptors-tq-inl.h"
namespace v8 {
namespace internal {
......@@ -61,8 +60,6 @@ ResultType HeapVisitor<ResultType, ConcreteVisitor>::Visit(Map map,
return visitor->VisitStruct(map, object);
case kVisitFreeSpace:
return visitor->VisitFreeSpace(map, FreeSpace::cast(object));
case kVisitWeakArray:
return visitor->VisitWeakArray(map, object);
case kDataOnlyVisitorIdCount:
case kVisitorIdCount:
UNREACHABLE();
......@@ -169,19 +166,6 @@ ResultType HeapVisitor<ResultType, ConcreteVisitor>::VisitFreeSpace(
return static_cast<ResultType>(object.size());
}
template <typename ResultType, typename ConcreteVisitor>
ResultType HeapVisitor<ResultType, ConcreteVisitor>::VisitWeakArray(
Map map, HeapObject object) {
ConcreteVisitor* visitor = static_cast<ConcreteVisitor*>(this);
if (!visitor->ShouldVisit(object)) return ResultType();
int size = WeakArrayBodyDescriptor::SizeOf(map, object);
if (visitor->ShouldVisitMapPointer()) {
visitor->VisitMapPointer(object);
}
WeakArrayBodyDescriptor::IterateBody(map, object, size, visitor);
return size;
}
template <typename ConcreteVisitor>
int NewSpaceVisitor<ConcreteVisitor>::VisitNativeContext(Map map,
NativeContext object) {
......
......@@ -9,6 +9,7 @@
#include "src/objects/map.h"
#include "src/objects/objects.h"
#include "src/objects/visitors.h"
#include "torque-generated/field-offsets-tq.h"
namespace v8 {
namespace internal {
......@@ -21,7 +22,6 @@ namespace internal {
V(Cell) \
V(Code) \
V(CodeDataContainer) \
V(ConsString) \
V(Context) \
V(CoverageInfo) \
V(DataHandler) \
......@@ -31,7 +31,6 @@ namespace internal {
V(FeedbackCell) \
V(FeedbackMetadata) \
V(FeedbackVector) \
V(FixedArray) \
V(FixedDoubleArray) \
V(JSArrayBuffer) \
V(JSDataView) \
......@@ -48,17 +47,13 @@ namespace internal {
V(PropertyArray) \
V(PropertyCell) \
V(PrototypeInfo) \
V(SeqOneByteString) \
V(SeqTwoByteString) \
V(SharedFunctionInfo) \
V(SlicedString) \
V(SmallOrderedHashMap) \
V(SmallOrderedHashSet) \
V(SmallOrderedNameDictionary) \
V(SourceTextModule) \
V(Symbol) \
V(SyntheticModule) \
V(ThinString) \
V(TransitionArray) \
V(UncompiledDataWithoutPreparseData) \
V(UncompiledDataWithPreparseData) \
......@@ -113,7 +108,6 @@ class HeapVisitor : public ObjectVisitor {
V8_INLINE ResultType VisitJSApiObject(Map map, JSObject object);
V8_INLINE ResultType VisitStruct(Map map, HeapObject object);
V8_INLINE ResultType VisitFreeSpace(Map map, FreeSpace object);
V8_INLINE ResultType VisitWeakArray(Map map, HeapObject object);
template <typename T>
static V8_INLINE T Cast(HeapObject object);
......
......@@ -195,6 +195,19 @@ void FixedArray::CopyElements(Isolate* isolate, int dst_index, FixedArray src,
isolate->heap()->CopyRange(*this, dst_slot, src_slot, len, mode);
}
// Due to left- and right-trimming, concurrent visitors need to read the length
// with acquire semantics.
// TODO(ulan): Acquire should not be needed anymore.
inline int FixedArray::AllocatedSize() {
return SizeFor(synchronized_length());
}
inline int WeakFixedArray::AllocatedSize() {
return SizeFor(synchronized_length());
}
inline int WeakArrayList::AllocatedSize() {
return SizeFor(synchronized_capacity());
}
// Perform a binary search in a fixed array.
template <SearchMode search_mode, typename T>
int BinarySearch(T* array, Name name, int valid_entries,
......
......@@ -7,6 +7,7 @@
#include "src/handles/maybe-handles.h"
#include "src/objects/instance-type.h"
#include "src/objects/objects.h"
#include "src/objects/smi.h"
#include "torque-generated/class-definitions-tq.h"
......@@ -15,8 +16,6 @@
namespace v8 {
namespace internal {
using WeakArrayBodyDescriptor =
FlexibleWeakBodyDescriptor<HeapObject::kHeaderSize>;
#define FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(V) \
V(BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE) \
......@@ -182,7 +181,9 @@ class FixedArray
// Dispatched behavior.
DECL_PRINTER(FixedArray)
using BodyDescriptor = FlexibleBodyDescriptor<kHeaderSize>;
int AllocatedSize();
class BodyDescriptor;
static constexpr int kObjectsOffset = kHeaderSize;
......@@ -280,16 +281,19 @@ class WeakFixedArray
DECL_PRINTER(WeakFixedArray)
DECL_VERIFIER(WeakFixedArray)
using BodyDescriptor = WeakArrayBodyDescriptor;
class BodyDescriptor;
static const int kMaxLength =
(FixedArray::kMaxSize - kHeaderSize) / kTaggedSize;
static_assert(Internals::IsValidSmi(kMaxLength),
"WeakFixedArray maxLength not a Smi");
int AllocatedSize();
protected:
static int OffsetOfElementAt(int index) {
return kHeaderSize + index * kTaggedSize;
STATIC_ASSERT(kObjectsOffset == SizeFor(0));
return SizeFor(index);
}
private:
......@@ -360,8 +364,9 @@ class WeakArrayList
// Get and set the capacity using acquire loads and release stores.
DECL_SYNCHRONIZED_INT_ACCESSORS(capacity)
int AllocatedSize();
using BodyDescriptor = WeakArrayBodyDescriptor;
class BodyDescriptor;
static const int kMaxCapacity =
(FixedArray::kMaxSize - kHeaderSize) / kTaggedSize;
......
......@@ -9,6 +9,7 @@ extern class FixedArrayBase extends HeapObject {
const length: Smi;
}
@generateBodyDescriptor
@generateCppClass
extern class FixedArray extends FixedArrayBase {
objects[length]: Object;
......@@ -21,6 +22,7 @@ extern class FixedDoubleArray extends FixedArrayBase {
floats[length]: float64_or_hole;
}
@generateBodyDescriptor
@generateCppClass
extern class WeakFixedArray extends HeapObject {
const length: Smi;
......@@ -41,6 +43,7 @@ extern class ArrayList extends FixedArray {
extern class TemplateList extends FixedArray {
}
@generateBodyDescriptor
@generateCppClass
extern class WeakArrayList extends HeapObject {
const capacity: Smi;
......
......@@ -142,7 +142,6 @@ VisitorId Map::GetVisitorId(Map map) {
case EMBEDDER_DATA_ARRAY_TYPE:
return kVisitEmbedderDataArray;
case FIXED_ARRAY_TYPE:
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
case HASH_TABLE_TYPE:
......@@ -175,10 +174,6 @@ VisitorId Map::GetVisitorId(Map map) {
case EPHEMERON_HASH_TABLE_TYPE:
return kVisitEphemeronHashTable;
case WEAK_FIXED_ARRAY_TYPE:
case WEAK_ARRAY_LIST_TYPE:
return kVisitWeakArray;
case FIXED_DOUBLE_ARRAY_TYPE:
return kVisitFixedDoubleArray;
......@@ -373,7 +368,7 @@ VisitorId Map::GetVisitorId(Map map) {
#define MAKE_TQ_CASE(TYPE, Name) \
case TYPE: \
return kVisit##Name;
TORQUE_BODY_DESCRIPTOR_LIST(MAKE_TQ_CASE)
TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(MAKE_TQ_CASE)
#undef MAKE_TQ_CASE
default:
......
......@@ -28,9 +28,7 @@ enum InstanceType : uint16_t;
V(CoverageInfo) \
V(DataObject) \
V(FeedbackMetadata) \
V(FixedDoubleArray) \
V(SeqOneByteString) \
V(SeqTwoByteString)
V(FixedDoubleArray)
#define POINTER_VISITOR_ID_LIST(V) \
V(AllocationSite) \
......@@ -38,7 +36,6 @@ enum InstanceType : uint16_t;
V(Cell) \
V(Code) \
V(CodeDataContainer) \
V(ConsString) \
V(Context) \
V(DataHandler) \
V(DescriptorArray) \
......@@ -46,7 +43,6 @@ enum InstanceType : uint16_t;
V(EphemeronHashTable) \
V(FeedbackCell) \
V(FeedbackVector) \
V(FixedArray) \
V(FreeSpace) \
V(JSApiObject) \
V(JSArrayBuffer) \
......@@ -66,7 +62,6 @@ enum InstanceType : uint16_t;
V(PrototypeInfo) \
V(SharedFunctionInfo) \
V(ShortcutCandidate) \
V(SlicedString) \
V(SmallOrderedHashMap) \
V(SmallOrderedHashSet) \
V(SmallOrderedNameDictionary) \
......@@ -74,7 +69,6 @@ enum InstanceType : uint16_t;
V(Struct) \
V(Symbol) \
V(SyntheticModule) \
V(ThinString) \
V(TransitionArray) \
V(UncompiledDataWithoutPreparseData) \
V(UncompiledDataWithPreparseData) \
......@@ -82,15 +76,11 @@ enum InstanceType : uint16_t;
V(WasmIndirectFunctionTable) \
V(WasmInstanceObject) \
V(WasmStruct) \
V(WeakArray) \
V(WeakCell)
#define TORQUE_OBJECT_BODY_TO_VISITOR_ID_LIST_ADAPTER(V, TYPE, TypeName) \
V(TypeName)
#define TORQUE_VISITOR_ID_LIST(V) \
TORQUE_BODY_DESCRIPTOR_LIST_GENERATOR( \
TORQUE_OBJECT_BODY_TO_VISITOR_ID_LIST_ADAPTER, V)
#define TORQUE_VISITOR_ID_LIST(V) \
TORQUE_DATA_ONLY_VISITOR_ID_LIST(V) \
TORQUE_POINTER_VISITOR_ID_LIST(V)
// Objects with the same visitor id are processed in the same way by
// the heap visitors. The visitor ids for data only objects must precede
......@@ -98,9 +88,11 @@ enum InstanceType : uint16_t;
// of whether an object contains only data or may contain pointers.
enum VisitorId {
#define VISITOR_ID_ENUM_DECL(id) kVisit##id,
DATA_ONLY_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL) kDataOnlyVisitorIdCount,
DATA_ONLY_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
TORQUE_DATA_ONLY_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
kDataOnlyVisitorIdCount,
POINTER_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
TORQUE_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
TORQUE_POINTER_VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
#undef VISITOR_ID_ENUM_DECL
kVisitorIdCount
};
......
......@@ -24,6 +24,9 @@
#include "src/objects/transitions.h"
#include "src/wasm/wasm-objects-inl.h"
#include "torque-generated/class-definitions-tq-inl.h"
#include "torque-generated/internal-class-definitions-tq-inl.h"
namespace v8 {
namespace internal {
......@@ -681,34 +684,6 @@ class Code::BodyDescriptor final : public BodyDescriptorBase {
}
};
class SeqOneByteString::BodyDescriptor final : public BodyDescriptorBase {
public:
static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
template <typename ObjectVisitor>
static inline void IterateBody(Map map, HeapObject obj, int object_size,
ObjectVisitor* v) {}
static inline int SizeOf(Map map, HeapObject obj) {
SeqOneByteString string = SeqOneByteString::cast(obj);
return SeqOneByteString::SizeFor(string.synchronized_length());
}
};
class SeqTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
public:
static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
template <typename ObjectVisitor>
static inline void IterateBody(Map map, HeapObject obj, int object_size,
ObjectVisitor* v) {}
static inline int SizeOf(Map map, HeapObject obj) {
SeqTwoByteString string = SeqTwoByteString::cast(obj);
return SeqTwoByteString::SizeFor(string.synchronized_length());
}
};
class WasmInstanceObject::BodyDescriptor final : public BodyDescriptorBase {
public:
static bool IsValidSlot(Map map, HeapObject obj, int offset) {
......@@ -923,7 +898,6 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case EMBEDDER_DATA_ARRAY_TYPE:
return Op::template apply<EmbedderDataArray::BodyDescriptor>(p1, p2, p3,
p4);
case FIXED_ARRAY_TYPE:
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
case HASH_TABLE_TYPE:
......@@ -953,10 +927,6 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
return Op::template apply<Context::BodyDescriptor>(p1, p2, p3, p4);
case NATIVE_CONTEXT_TYPE:
return Op::template apply<NativeContext::BodyDescriptor>(p1, p2, p3, p4);
case WEAK_FIXED_ARRAY_TYPE:
return Op::template apply<WeakFixedArray::BodyDescriptor>(p1, p2, p3, p4);
case WEAK_ARRAY_LIST_TYPE:
return Op::template apply<WeakArrayList::BodyDescriptor>(p1, p2, p3, p4);
case FIXED_DOUBLE_ARRAY_TYPE:
return ReturnType();
case FEEDBACK_METADATA_TYPE:
......@@ -1129,10 +1099,12 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case SYNTHETIC_MODULE_TYPE:
return Op::template apply<SyntheticModule::BodyDescriptor>(p1, p2, p3,
p4);
// TODO(tebbi): Avoid duplicated cases when the body descriptors are identical.
#define MAKE_TORQUE_BODY_DESCRIPTOR_APPLY(TYPE, TypeName) \
case TYPE: \
return Op::template apply<TypeName::BodyDescriptor>(p1, p2, p3, p4);
TORQUE_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_BODY_DESCRIPTOR_APPLY)
TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(
MAKE_TORQUE_BODY_DESCRIPTOR_APPLY)
#undef MAKE_TORQUE_BODY_DESCRIPTOR_APPLY
default:
......@@ -1193,6 +1165,8 @@ class EphemeronHashTable::BodyDescriptor final : public BodyDescriptorBase {
}
};
#include "torque-generated/objects-body-descriptors-tq-inl.inc"
} // namespace internal
} // namespace v8
......
......@@ -74,15 +74,14 @@ class BodyDescriptorBase {
ObjectVisitor* v);
};
// This class describes a body of an object of a fixed size
// in which all pointer fields are located in the [start_offset, end_offset)
// interval.
template <int start_offset, int end_offset, int size>
class FixedBodyDescriptor final : public BodyDescriptorBase {
// This class describes a body of an object in which all pointer fields are
// located in the [start_offset, end_offset) interval.
// All pointers have to be strong.
template <int start_offset, int end_offset>
class FixedRangeBodyDescriptor : public BodyDescriptorBase {
public:
static const int kStartOffset = start_offset;
static const int kEndOffset = end_offset;
static const int kSize = size;
static bool IsValidSlot(Map map, HeapObject obj, int offset) {
return offset >= kStartOffset && offset < kEndOffset;
......@@ -99,14 +98,30 @@ class FixedBodyDescriptor final : public BodyDescriptorBase {
IterateBody(map, obj, v);
}
static inline int SizeOf(Map map, HeapObject object) { return kSize; }
private:
static inline int SizeOf(Map map, HeapObject object) {
// Has to be implemented by the subclass.
UNREACHABLE();
}
};
// This class describes a body of an object of a variable size
// in which all pointer fields are located in the [start_offset, object_size)
// This class describes a body of an object of a fixed size
// in which all pointer fields are located in the [start_offset, end_offset)
// interval.
// All pointers have to be strong.
template <int start_offset, int end_offset, int size>
class FixedBodyDescriptor
: public FixedRangeBodyDescriptor<start_offset, end_offset> {
public:
static const int kSize = size;
static inline int SizeOf(Map map, HeapObject object) { return kSize; }
};
// This class describes a body of an object in which all pointer fields are
// located in the [start_offset, object_size) interval.
// All pointers have to be strong.
template <int start_offset>
class FlexibleBodyDescriptor final : public BodyDescriptorBase {
class SuffixRangeBodyDescriptor : public BodyDescriptorBase {
public:
static const int kStartOffset = start_offset;
......@@ -120,13 +135,30 @@ class FlexibleBodyDescriptor final : public BodyDescriptorBase {
IteratePointers(obj, start_offset, object_size, v);
}
private:
static inline int SizeOf(Map map, HeapObject object) {
// Has to be implemented by the subclass.
UNREACHABLE();
}
};
// This class describes a body of an object of a variable size
// in which all pointer fields are located in the [start_offset, object_size)
// interval.
// All pointers have to be strong.
template <int start_offset>
class FlexibleBodyDescriptor : public SuffixRangeBodyDescriptor<start_offset> {
public:
static inline int SizeOf(Map map, HeapObject object);
};
using StructBodyDescriptor = FlexibleBodyDescriptor<HeapObject::kHeaderSize>;
// This class describes a body of an object in which all pointer fields are
// located in the [start_offset, object_size) interval.
// Pointers may be strong or may be MaybeObject-style weak pointers.
template <int start_offset>
class FlexibleWeakBodyDescriptor final : public BodyDescriptorBase {
class SuffixRangeWeakBodyDescriptor : public BodyDescriptorBase {
public:
static const int kStartOffset = start_offset;
......@@ -140,9 +172,40 @@ class FlexibleWeakBodyDescriptor final : public BodyDescriptorBase {
IterateMaybeWeakPointers(obj, start_offset, object_size, v);
}
private:
static inline int SizeOf(Map map, HeapObject object) {
// Has to be implemented by the subclass.
UNREACHABLE();
}
};
// This class describes a body of an object of a variable size
// in which all pointer fields are located in the [start_offset, object_size)
// interval.
// Pointers may be strong or may be MaybeObject-style weak pointers.
template <int start_offset>
class FlexibleWeakBodyDescriptor
: public SuffixRangeWeakBodyDescriptor<start_offset> {
public:
static inline int SizeOf(Map map, HeapObject object);
};
// This class describes a body of an object without any pointers.
class DataOnlyBodyDescriptor : public BodyDescriptorBase {
public:
static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
template <typename ObjectVisitor>
static inline void IterateBody(Map map, HeapObject obj, int object_size,
ObjectVisitor* v) {}
private:
static inline int SizeOf(Map map, HeapObject object) {
// Has to be implemented by the subclass.
UNREACHABLE();
}
};
// This class describes a body of an object which has a parent class that also
// has a body descriptor. This represents a union of the parent's body
// descriptor, and a new descriptor for the child -- so, both parent and child's
......@@ -180,10 +243,6 @@ class SubclassBodyDescriptor final : public BodyDescriptorBase {
}
};
#define TORQUE_BODY_DESCRIPTOR_LIST_ADAPTER(V, TYPE, TypeName) V(TYPE, TypeName)
#define TORQUE_BODY_DESCRIPTOR_LIST(V) \
TORQUE_BODY_DESCRIPTOR_LIST_GENERATOR(TORQUE_BODY_DESCRIPTOR_LIST_ADAPTER, V)
} // namespace internal
} // namespace v8
......
......@@ -126,7 +126,6 @@
#include "torque-generated/class-definitions-tq-inl.h"
#include "torque-generated/internal-class-definitions-tq-inl.h"
#include "torque-generated/objects-body-descriptors-tq-inl.h"
namespace v8 {
namespace internal {
......@@ -2278,12 +2277,11 @@ int HeapObject::SizeFromMap(Map map) const {
PreparseData data = PreparseData::unchecked_cast(*this);
return PreparseData::SizeFor(data.data_length(), data.children_length());
}
#define MAKE_TORQUE_SIZE_FOR(TYPE, TypeName) \
if (instance_type == TYPE) { \
TypeName instance = TypeName::unchecked_cast(*this); \
return TypeName::SizeFor(instance); \
#define MAKE_TORQUE_SIZE_FOR(TYPE, TypeName) \
if (instance_type == TYPE) { \
return TypeName::unchecked_cast(*this).AllocatedSize(); \
}
TORQUE_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_SIZE_FOR)
TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(MAKE_TORQUE_SIZE_FOR)
#undef MAKE_TORQUE_SIZE_FOR
if (instance_type == CODE_TYPE) {
......
......@@ -569,12 +569,13 @@ void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
WriteField<uint16_t>(kHeaderSize + index * kShortSize, value);
}
int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
return SizeFor(length());
// Due to ThinString rewriting, concurrent visitors need to read the length with
// acquire semantics.
inline int SeqOneByteString::AllocatedSize() {
return SizeFor(synchronized_length());
}
int SeqOneByteString::SeqOneByteStringSize(InstanceType instance_type) {
return SizeFor(length());
inline int SeqTwoByteString::AllocatedSize() {
return SizeFor(synchronized_length());
}
void SlicedString::set_parent(String parent, WriteBarrierMode mode) {
......
......@@ -558,16 +558,13 @@ class SeqOneByteString
// instance.
inline int SeqOneByteStringSize(InstanceType instance_type);
// Computes the size for an OneByteString instance of a given length.
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length * kCharSize);
}
// Maximal memory usage for a single sequential one-byte string.
static const int kMaxCharsSize = kMaxLength;
static const int kMaxSize = OBJECT_POINTER_ALIGN(kMaxCharsSize + kHeaderSize);
STATIC_ASSERT((kMaxSize - kHeaderSize) >= String::kMaxLength);
int AllocatedSize();
class BodyDescriptor;
TQ_OBJECT_CONSTRUCTORS(SeqOneByteString)
......@@ -599,17 +596,14 @@ class SeqTwoByteString
// instance.
inline int SeqTwoByteStringSize(InstanceType instance_type);
// Computes the size for a TwoByteString instance of a given length.
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length * kShortSize);
}
// Maximal memory usage for a single sequential two-byte string.
static const int kMaxCharsSize = kMaxLength * 2;
static const int kMaxSize = OBJECT_POINTER_ALIGN(kMaxCharsSize + kHeaderSize);
STATIC_ASSERT(static_cast<int>((kMaxSize - kHeaderSize) / sizeof(uint16_t)) >=
String::kMaxLength);
int AllocatedSize();
class BodyDescriptor;
TQ_OBJECT_CONSTRUCTORS(SeqTwoByteString)
......@@ -639,7 +633,7 @@ class ConsString : public TorqueGeneratedConsString<ConsString, String> {
// Minimum length for a cons string.
static const int kMinLength = 13;
using BodyDescriptor = FixedBodyDescriptor<kFirstOffset, kSize, kSize>;
class BodyDescriptor;
DECL_VERIFIER(ConsString)
......@@ -661,7 +655,7 @@ class ThinString : public TorqueGeneratedThinString<ThinString, String> {
DECL_VERIFIER(ThinString)
using BodyDescriptor = FixedBodyDescriptor<kActualOffset, kSize, kSize>;
class BodyDescriptor;
TQ_OBJECT_CONSTRUCTORS(ThinString)
};
......@@ -688,7 +682,7 @@ class SlicedString : public TorqueGeneratedSlicedString<SlicedString, String> {
// Minimum length for a sliced string.
static const int kMinLength = 13;
using BodyDescriptor = FixedBodyDescriptor<kParentOffset, kSize, kSize>;
class BodyDescriptor;
DECL_VERIFIER(SlicedString)
......
......@@ -10,12 +10,14 @@ extern class String extends Name {
}
@generateCppClass
@generateBodyDescriptor
extern class ConsString extends String {
first: String;
second: String;
}
@abstract
@generateBodyDescriptor
extern class ExternalString extends String {
resource: RawPtr;
resource_data: RawPtr;
......@@ -28,27 +30,30 @@ extern class ExternalTwoByteString extends ExternalString {}
extern class InternalizedString extends String {
}
// TODO(v8:8983): Add declaration for variable-sized region.
@abstract
@generateCppClass
extern class SeqString extends String {
}
@generateCppClass
@generateBodyDescriptor
extern class SeqOneByteString extends SeqString {
chars[length]: char8;
}
@generateCppClass
@generateBodyDescriptor
extern class SeqTwoByteString extends SeqString {
chars[length]: char16;
}
@generateCppClass
@generateBodyDescriptor
extern class SlicedString extends String {
parent: String;
offset: Smi;
}
@generateCppClass
@generateBodyDescriptor
extern class ThinString extends String {
actual: String;
}
......
......@@ -127,7 +127,6 @@ enum class ClassFlag {
kIsShape = 1 << 5,
kHasSameInstanceTypeAsParent = 1 << 6,
kGenerateCppClassDefinitions = 1 << 7,
kHasIndexedField = 1 << 8,
kHighestInstanceTypeWithinParent = 1 << 9,
kLowestInstanceTypeWithinParent = 1 << 10,
kUndefinedLayout = 1 << 11,
......
......@@ -67,6 +67,14 @@ class GlobalContext : public ContextualClass<GlobalContext> {
return Get().generated_per_file_[file];
}
static void SetInstanceTypesInitialized() {
DCHECK(!Get().instance_types_initialized_);
Get().instance_types_initialized_ = true;
}
static bool IsInstanceTypesInitialized() {
return Get().instance_types_initialized_;
}
private:
bool collect_language_server_data_;
bool force_assert_statements_;
......@@ -76,6 +84,7 @@ class GlobalContext : public ContextualClass<GlobalContext> {
std::set<std::string> cpp_includes_;
std::map<SourceId, PerFileStreams> generated_per_file_;
std::map<std::string, size_t> fresh_ids_;
bool instance_types_initialized_ = false;
friend class LanguageServerData;
};
......
This diff is collapsed.
......@@ -256,6 +256,9 @@ int SolveInstanceTypeConstraints(
root->start = root->value;
}
root->num_values = root->end - root->start + 1;
root->type->InitializeInstanceTypes(
root->value == -1 ? base::Optional<int>{} : root->value,
std::make_pair(root->start, root->end));
if (root->num_values > 0) {
destination->push_back(std::move(root));
......@@ -485,6 +488,8 @@ void ImplementationVisitor::GenerateInstanceTypes(
}
std::string output_header_path = output_directory + "/" + file_name;
WriteFile(output_header_path, header.str());
GlobalContext::SetInstanceTypesInitialized();
}
} // namespace torque
......
......@@ -73,6 +73,7 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
ImplementationVisitor implementation_visitor;
implementation_visitor.SetDryRun(output_directory.length() == 0);
implementation_visitor.GenerateInstanceTypes(output_directory);
implementation_visitor.BeginCSAFiles();
implementation_visitor.VisitAllDeclarables();
......@@ -91,7 +92,6 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
implementation_visitor.GenerateBodyDescriptors(output_directory);
implementation_visitor.GenerateExportedMacrosAssembler(output_directory);
implementation_visitor.GenerateCSATypes(output_directory);
implementation_visitor.GenerateInstanceTypes(output_directory);
implementation_visitor.EndCSAFiles();
implementation_visitor.GenerateImplementation(output_directory);
......
......@@ -4,6 +4,7 @@
#include <iostream>
#include "src/base/optional.h"
#include "src/torque/types.h"
#include "src/base/bits.h"
......@@ -528,6 +529,121 @@ std::vector<Field> ClassType::ComputeAllFields() const {
return all_fields;
}
std::vector<Field> ClassType::ComputeHeaderFields() const {
std::vector<Field> result;
for (Field& field : ComputeAllFields()) {
if (field.index) break;
DCHECK(*field.offset < header_size());
result.push_back(std::move(field));
}
return result;
}
std::vector<Field> ClassType::ComputeArrayFields() const {
std::vector<Field> result;
for (Field& field : ComputeAllFields()) {
if (!field.index) {
DCHECK(*field.offset < header_size());
continue;
}
result.push_back(std::move(field));
}
return result;
}
void ClassType::InitializeInstanceTypes(
base::Optional<int> own, base::Optional<std::pair<int, int>> range) const {
DCHECK(!own_instance_type_.has_value());
DCHECK(!instance_type_range_.has_value());
own_instance_type_ = own;
instance_type_range_ = range;
}
base::Optional<int> ClassType::OwnInstanceType() const {
DCHECK(GlobalContext::IsInstanceTypesInitialized());
return own_instance_type_;
}
base::Optional<std::pair<int, int>> ClassType::InstanceTypeRange() const {
DCHECK(GlobalContext::IsInstanceTypesInitialized());
return instance_type_range_;
}
namespace {
void ComputeSlotKindsHelper(std::vector<ObjectSlotKind>* slots,
size_t start_offset,
const std::vector<Field>& fields) {
size_t offset = start_offset;
for (const Field& field : fields) {
size_t field_size = std::get<0>(field.GetFieldSizeInformation());
size_t slot_index = offset / TargetArchitecture::TaggedSize();
// Rounding-up division to find the number of slots occupied by all the
// fields up to and including the current one.
size_t used_slots =
(offset + field_size + TargetArchitecture::TaggedSize() - 1) /
TargetArchitecture::TaggedSize();
while (used_slots > slots->size()) {
slots->push_back(ObjectSlotKind::kNoPointer);
}
const Type* type = field.name_and_type.type;
if (auto struct_type = type->StructSupertype()) {
ComputeSlotKindsHelper(slots, offset, (*struct_type)->fields());
} else {
ObjectSlotKind kind;
if (type->IsSubtypeOf(TypeOracle::GetObjectType())) {
if (field.is_weak) {
kind = ObjectSlotKind::kCustomWeakPointer;
} else {
kind = ObjectSlotKind::kStrongPointer;
}
} else if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
DCHECK(!field.is_weak);
kind = ObjectSlotKind::kMaybeObjectPointer;
} else {
kind = ObjectSlotKind::kNoPointer;
}
DCHECK(slots->at(slot_index) == ObjectSlotKind::kNoPointer);
slots->at(slot_index) = kind;
}
offset += field_size;
}
}
} // namespace
std::vector<ObjectSlotKind> ClassType::ComputeHeaderSlotKinds() const {
std::vector<ObjectSlotKind> result;
std::vector<Field> header_fields = ComputeHeaderFields();
ComputeSlotKindsHelper(&result, 0, header_fields);
DCHECK_EQ(std::ceil(double{header_size()} / TargetArchitecture::TaggedSize()),
result.size());
return result;
}
base::Optional<ObjectSlotKind> ClassType::ComputeArraySlotKind() const {
std::vector<ObjectSlotKind> kinds;
ComputeSlotKindsHelper(&kinds, 0, ComputeArrayFields());
if (kinds.empty()) return base::nullopt;
std::sort(kinds.begin(), kinds.end());
if (kinds.front() == kinds.back()) return {kinds.front()};
if (kinds.front() == ObjectSlotKind::kStrongPointer &&
kinds.back() == ObjectSlotKind::kMaybeObjectPointer) {
return ObjectSlotKind::kMaybeObjectPointer;
}
Error("Array fields mix types with different GC visitation requirements.")
.Throw();
}
bool ClassType::HasNoPointerSlots() const {
for (ObjectSlotKind slot : ComputeHeaderSlotKinds()) {
if (slot != ObjectSlotKind::kNoPointer) return false;
}
if (auto slot = ComputeArraySlotKind()) {
if (*slot != ObjectSlotKind::kNoPointer) return false;
}
return true;
}
void ClassType::GenerateAccessors() {
// For each field, construct AST snippets that implement a CSA accessor
// function. The implementation iterator will turn the snippets into code.
......
......@@ -611,6 +611,23 @@ class StructType final : public AggregateType {
class TypeAlias;
enum class ObjectSlotKind : uint8_t {
kNoPointer,
kStrongPointer,
kMaybeObjectPointer,
kCustomWeakPointer
};
inline base::Optional<ObjectSlotKind> Combine(ObjectSlotKind a,
ObjectSlotKind b) {
if (a == b) return {a};
if (std::min(a, b) == ObjectSlotKind::kStrongPointer &&
std::max(a, b) == ObjectSlotKind::kMaybeObjectPointer) {
return {ObjectSlotKind::kMaybeObjectPointer};
}
return base::nullopt;
}
class ClassType final : public AggregateType {
public:
DECLARE_TYPE_BOILERPLATE(ClassType)
......@@ -627,6 +644,7 @@ class ClassType final : public AggregateType {
(!HasUndefinedLayout() && !IsShape()));
}
bool ShouldGenerateBodyDescriptor() const {
if (IsAbstract()) return false;
return flags_ & ClassFlag::kGenerateBodyDescriptor || !IsExtern();
}
bool IsTransient() const override { return flags_ & ClassFlag::kTransient; }
......@@ -661,6 +679,14 @@ class ClassType final : public AggregateType {
void Finalize() const override;
std::vector<Field> ComputeAllFields() const;
std::vector<Field> ComputeHeaderFields() const;
std::vector<Field> ComputeArrayFields() const;
// The slots of an object are the tagged pointer sized offsets in an object
// that may or may not require GC visiting. These helper functions determine
// what kind of GC visiting the individual slots require.
std::vector<ObjectSlotKind> ComputeHeaderSlotKinds() const;
base::Optional<ObjectSlotKind> ComputeArraySlotKind() const;
bool HasNoPointerSlots() const;
const InstanceTypeConstraints& GetInstanceTypeConstraints() const {
return decl_->instance_type_constraints;
......@@ -676,6 +702,14 @@ class ClassType final : public AggregateType {
}
SourcePosition GetPosition() const { return decl_->pos; }
// TODO(tebbi): We should no longer pass around types as const pointers, so
// that we can avoid mutable fields and const initializers for
// late-initialized portions of types like this one.
void InitializeInstanceTypes(base::Optional<int> own,
base::Optional<std::pair<int, int>> range) const;
base::Optional<int> OwnInstanceType() const;
base::Optional<std::pair<int, int>> InstanceTypeRange() const;
private:
friend class TypeOracle;
friend class TypeVisitor;
......@@ -689,6 +723,8 @@ class ClassType final : public AggregateType {
const std::string generates_;
const ClassDeclaration* decl_;
const TypeAlias* alias_;
mutable base::Optional<int> own_instance_type_;
mutable base::Optional<std::pair<int, int>> instance_type_range_;
};
inline std::ostream& operator<<(std::ostream& os, const Type& t) {
......
......@@ -1144,6 +1144,14 @@ namespace test {
b: HeapObject;
}
@abstract
class AbstractInternalClass extends HeapObject {
}
class AbstractInternalClassSubclass1 extends AbstractInternalClass {}
class AbstractInternalClassSubclass2 extends AbstractInternalClass {}
class InternalClassWithSmiElements extends FixedArrayBase {
data: Smi;
object: Oddball;
......
This diff is collapsed.
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