Skip to content

Commit e2332a3

Browse files
committed
[NFC] Move ValueWitnessTable layout into its own file
I've also target-ified EnumValueWitnessTable while I was at it.
1 parent cb3818e commit e2332a3

File tree

3 files changed

+325
-287
lines changed

3 files changed

+325
-287
lines changed

include/swift/ABI/Metadata.h

Lines changed: 1 addition & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818
#define SWIFT_ABI_METADATA_H
1919

2020
#include <atomic>
21-
#include <cassert>
22-
#include <climits>
23-
#include <cstddef>
24-
#include <cstdint>
2521
#include <iterator>
2622
#include <string>
2723
#include <type_traits>
@@ -35,6 +31,7 @@
3531
#include "swift/ABI/System.h"
3632
#include "swift/ABI/TargetLayout.h"
3733
#include "swift/ABI/TrailingObjects.h"
34+
#include "swift/ABI/ValueWitnessTable.h"
3835
#include "swift/Basic/Malloc.h"
3936
#include "swift/Basic/FlaggedPointer.h"
4037
#include "swift/Basic/RelativePointer.h"
@@ -147,201 +144,6 @@ struct MetadataDependency {
147144

148145
template <typename Runtime> struct TargetProtocolConformanceDescriptor;
149146

150-
/// Storage for an arbitrary value. In C/C++ terms, this is an
151-
/// 'object', because it is rooted in memory.
152-
///
153-
/// The context dictates what type is actually stored in this object,
154-
/// and so this type is intentionally incomplete.
155-
///
156-
/// An object can be in one of two states:
157-
/// - An uninitialized object has a completely unspecified state.
158-
/// - An initialized object holds a valid value of the type.
159-
struct OpaqueValue;
160-
161-
/// A fixed-size buffer for local values. It is capable of owning
162-
/// (possibly in side-allocated memory) the storage necessary
163-
/// to hold a value of an arbitrary type. Because it is fixed-size,
164-
/// it can be allocated in places that must be agnostic to the
165-
/// actual type: for example, within objects of existential type,
166-
/// or for local variables in generic functions.
167-
///
168-
/// The context dictates its type, which ultimately means providing
169-
/// access to a value witness table by which the value can be
170-
/// accessed and manipulated.
171-
///
172-
/// A buffer can directly store three pointers and is pointer-aligned.
173-
/// Three pointers is a sweet spot for Swift, because it means we can
174-
/// store a structure containing a pointer, a size, and an owning
175-
/// object, which is a common pattern in code due to ARC. In a GC
176-
/// environment, this could be reduced to two pointers without much loss.
177-
///
178-
/// A buffer can be in one of three states:
179-
/// - An unallocated buffer has a completely unspecified state.
180-
/// - An allocated buffer has been initialized so that it
181-
/// owns uninitialized value storage for the stored type.
182-
/// - An initialized buffer is an allocated buffer whose value
183-
/// storage has been initialized.
184-
template <typename Runtime>
185-
struct TargetValueBuffer {
186-
TargetPointer<Runtime, void> PrivateData[NumWords_ValueBuffer];
187-
};
188-
using ValueBuffer = TargetValueBuffer<InProcess>;
189-
190-
/// Can a value with the given size and alignment be allocated inline?
191-
constexpr inline bool canBeInline(bool isBitwiseTakable, size_t size,
192-
size_t alignment) {
193-
return isBitwiseTakable && size <= sizeof(ValueBuffer) &&
194-
alignment <= alignof(ValueBuffer);
195-
}
196-
197-
template <class T>
198-
constexpr inline bool canBeInline(bool isBitwiseTakable) {
199-
return canBeInline(isBitwiseTakable, sizeof(T), alignof(T));
200-
}
201-
202-
template <typename Runtime> struct TargetValueWitnessTable;
203-
using ValueWitnessTable = TargetValueWitnessTable<InProcess>;
204-
205-
template <typename Runtime> class TargetValueWitnessTypes;
206-
using ValueWitnessTypes = TargetValueWitnessTypes<InProcess>;
207-
208-
template <typename Runtime>
209-
class TargetValueWitnessTypes {
210-
public:
211-
using StoredPointer = typename Runtime::StoredPointer;
212-
213-
// Note that, for now, we aren't strict about 'const'.
214-
#define WANT_ALL_VALUE_WITNESSES
215-
#define DATA_VALUE_WITNESS(lowerId, upperId, type)
216-
#define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \
217-
typedef returnType (*lowerId ## Unsigned) paramTypes; \
218-
typedef TargetSignedPointer<Runtime, lowerId ## Unsigned \
219-
__ptrauth_swift_value_witness_function_pointer( \
220-
SpecialPointerAuthDiscriminators::upperId)> lowerId;
221-
#define MUTABLE_VALUE_TYPE TargetPointer<Runtime, OpaqueValue>
222-
#define IMMUTABLE_VALUE_TYPE ConstTargetPointer<Runtime, OpaqueValue>
223-
#define MUTABLE_BUFFER_TYPE TargetPointer<Runtime, ValueBuffer>
224-
#define IMMUTABLE_BUFFER_TYPE ConstTargetPointer<Runtime, ValueBuffer>
225-
#define TYPE_TYPE ConstTargetPointer<Runtime, Metadata>
226-
#define SIZE_TYPE StoredSize
227-
#define INT_TYPE int
228-
#define UINT_TYPE unsigned
229-
#define VOID_TYPE void
230-
#include "swift/ABI/ValueWitness.def"
231-
232-
// Handle the data witnesses explicitly so we can use more specific
233-
// types for the flags enums.
234-
typedef size_t size;
235-
typedef size_t stride;
236-
typedef ValueWitnessFlags flags;
237-
typedef uint32_t extraInhabitantCount;
238-
};
239-
240-
struct TypeLayout;
241-
242-
/// A value-witness table. A value witness table is built around
243-
/// the requirements of some specific type. The information in
244-
/// a value-witness table is intended to be sufficient to lay out
245-
/// and manipulate values of an arbitrary type.
246-
template <typename Runtime> struct TargetValueWitnessTable {
247-
// For the meaning of all of these witnesses, consult the comments
248-
// on their associated typedefs, above.
249-
250-
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
251-
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
252-
typename TargetValueWitnessTypes<Runtime>::LOWER_ID LOWER_ID;
253-
#define FUNCTION_VALUE_WITNESS(LOWER_ID, UPPER_ID, RET, PARAMS) \
254-
typename TargetValueWitnessTypes<Runtime>::LOWER_ID LOWER_ID;
255-
256-
#include "swift/ABI/ValueWitness.def"
257-
258-
using StoredSize = typename Runtime::StoredSize;
259-
260-
/// Is the external type layout of this type incomplete?
261-
bool isIncomplete() const {
262-
return flags.isIncomplete();
263-
}
264-
265-
/// Would values of a type with the given layout requirements be
266-
/// allocated inline?
267-
static bool isValueInline(bool isBitwiseTakable, StoredSize size,
268-
StoredSize alignment) {
269-
return (isBitwiseTakable && size <= sizeof(TargetValueBuffer<Runtime>) &&
270-
alignment <= alignof(TargetValueBuffer<Runtime>));
271-
}
272-
273-
/// Are values of this type allocated inline?
274-
bool isValueInline() const {
275-
return flags.isInlineStorage();
276-
}
277-
278-
/// Is this type POD?
279-
bool isPOD() const {
280-
return flags.isPOD();
281-
}
282-
283-
/// Is this type bitwise-takable?
284-
bool isBitwiseTakable() const {
285-
return flags.isBitwiseTakable();
286-
}
287-
288-
/// Return the size of this type. Unlike in C, this has not been
289-
/// padded up to the alignment; that value is maintained as
290-
/// 'stride'.
291-
StoredSize getSize() const {
292-
return size;
293-
}
294-
295-
/// Return the stride of this type. This is the size rounded up to
296-
/// be a multiple of the alignment.
297-
StoredSize getStride() const {
298-
return stride;
299-
}
300-
301-
/// Return the alignment required by this type, in bytes.
302-
StoredSize getAlignment() const {
303-
return flags.getAlignment();
304-
}
305-
306-
/// The alignment mask of this type. An offset may be rounded up to
307-
/// the required alignment by adding this mask and masking by its
308-
/// bit-negation.
309-
///
310-
/// For example, if the type needs to be 8-byte aligned, the value
311-
/// of this witness is 0x7.
312-
StoredSize getAlignmentMask() const {
313-
return flags.getAlignmentMask();
314-
}
315-
316-
/// The number of extra inhabitants, that is, bit patterns that do not form
317-
/// valid values of the type, in this type's binary representation.
318-
unsigned getNumExtraInhabitants() const {
319-
return extraInhabitantCount;
320-
}
321-
322-
/// Assert that this value witness table is an enum value witness table
323-
/// and return it as such.
324-
///
325-
/// This has an awful name because it's supposed to be internal to
326-
/// this file. Code outside this file should use LLVM's cast/dyn_cast.
327-
/// We don't want to use those here because we need to avoid accidentally
328-
/// introducing ABI dependencies on LLVM structures.
329-
const struct EnumValueWitnessTable *_asEVWT() const;
330-
331-
/// Get the type layout record within this value witness table.
332-
const TypeLayout *getTypeLayout() const {
333-
return reinterpret_cast<const TypeLayout *>(&size);
334-
}
335-
336-
/// Check whether this metadata is complete.
337-
bool checkIsComplete() const;
338-
339-
/// "Publish" the layout of this type to other threads. All other stores
340-
/// to the value witness table (including its extended header) should have
341-
/// happened before this is called.
342-
void publishLayout(const TypeLayout &layout);
343-
};
344-
345147
/// The header before a metadata object which appears on all type
346148
/// metadata. Note that heap metadata are not necessarily type
347149
/// metadata, even for objects of a heap type: for example, objects of

0 commit comments

Comments
 (0)