-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathStructLayout.h
436 lines (357 loc) · 13.9 KB
/
StructLayout.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
//===--- StructLayout.h - Structure layout ----------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines some routines that are useful for performing
// structure layout.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_STRUCTLAYOUT_H
#define SWIFT_IRGEN_STRUCTLAYOUT_H
#include "llvm/ADT/ArrayRef.h"
#include "swift/Basic/ClusteredBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
#include "IRGen.h"
namespace llvm {
class Constant;
class StructType;
class Type;
class Value;
}
namespace swift {
namespace irgen {
class Address;
class IRGenFunction;
class IRGenModule;
class TypeInfo;
/// An algorithm for laying out a structure.
enum class LayoutStrategy {
/// Compute an optimal layout; there are no constraints at all.
Optimal,
/// The 'universal' strategy: all modules must agree on the layout.
Universal
};
/// The kind of object being laid out.
enum class LayoutKind {
/// A non-heap object does not require a heap header.
NonHeapObject,
/// A heap object is destined to be allocated on the heap and must
/// be emitted with the standard heap header.
HeapObject,
};
class NonFixedOffsetsImpl;
/// The type to pass around for non-fixed offsets.
typedef Optional<NonFixedOffsetsImpl*> NonFixedOffsets;
/// An abstract class for determining non-fixed offsets.
class NonFixedOffsetsImpl {
protected:
virtual ~NonFixedOffsetsImpl() = default;
public:
/// Return the offset (in bytes, as a size_t) of the element with
/// the given index.
virtual llvm::Value *getOffsetForIndex(IRGenFunction &IGF,
unsigned index) = 0;
operator NonFixedOffsets() { return NonFixedOffsets(this); }
};
/// An element layout is the layout for a single element of some sort
/// of aggregate structure.
class ElementLayout {
public:
enum class Kind {
/// The element is known to require no storage in the aggregate.
Empty,
/// The element can be positioned at a fixed offset within the
/// aggregate.
Fixed,
/// The element cannot be positioned at a fixed offset within the
/// aggregate.
NonFixed,
/// The element is an object lacking a fixed size but located at
/// offset zero. This is necessary because LLVM forbids even a
/// 'gep 0' on an unsized type.
InitialNonFixedSize
};
private:
enum : unsigned { IncompleteKind = 4 };
/// The swift type information for this element.
const TypeInfo *Type;
/// The offset in bytes from the start of the struct.
unsigned ByteOffset;
/// The index of this element, either in the LLVM struct (if fixed)
/// or in the non-fixed elements array (if non-fixed).
unsigned Index : 28;
/// Whether this element is known to be POD in the local resilience
/// domain.
unsigned IsPOD : 1;
/// The kind of layout performed for this element.
unsigned TheKind : 3;
explicit ElementLayout(const TypeInfo &type)
: Type(&type), TheKind(IncompleteKind) {}
bool isCompleted() const {
return (TheKind != IncompleteKind);
}
public:
static ElementLayout getIncomplete(const TypeInfo &type) {
return ElementLayout(type);
}
void completeFrom(const ElementLayout &other) {
assert(!isCompleted());
TheKind = other.TheKind;
IsPOD = other.IsPOD;
ByteOffset = other.ByteOffset;
Index = other.Index;
}
void completeEmpty(IsPOD_t isPOD, Size byteOffset) {
TheKind = unsigned(Kind::Empty);
IsPOD = unsigned(isPOD);
// We still want to give empty fields an offset for use by things like
// ObjC ivar emission. We use the first field in a class layout as the
// instanceStart.
ByteOffset = byteOffset.getValue();
Index = 0; // make a complete write of the bitfield
}
void completeInitialNonFixedSize(IsPOD_t isPOD) {
TheKind = unsigned(Kind::InitialNonFixedSize);
IsPOD = unsigned(isPOD);
Index = 0; // make a complete write of the bitfield
}
void completeFixed(IsPOD_t isPOD, Size byteOffset, unsigned structIndex) {
TheKind = unsigned(Kind::Fixed);
IsPOD = unsigned(isPOD);
ByteOffset = byteOffset.getValue();
Index = structIndex;
assert(getByteOffset() == byteOffset);
}
/// Complete this element layout with a non-fixed offset.
///
/// \param nonFixedElementIndex - the index into the elements array
void completeNonFixed(IsPOD_t isPOD, unsigned nonFixedElementIndex) {
TheKind = unsigned(Kind::NonFixed);
IsPOD = unsigned(isPOD);
Index = nonFixedElementIndex;
}
const TypeInfo &getType() const { return *Type; }
Kind getKind() const {
assert(isCompleted());
return Kind(TheKind);
}
/// Is this element known to be empty?
bool isEmpty() const {
return getKind() == Kind::Empty;
}
/// Is this element known to be POD?
IsPOD_t isPOD() const {
assert(isCompleted());
return IsPOD_t(IsPOD);
}
/// Given that this element has a fixed offset, return that offset in bytes.
Size getByteOffset() const {
assert(isCompleted() &&
(getKind() == Kind::Fixed || getKind() == Kind::Empty));
return Size(ByteOffset);
}
/// Given that this element has a fixed offset, return the index in
/// the LLVM struct.
unsigned getStructIndex() const {
assert(isCompleted() && getKind() == Kind::Fixed);
return Index;
}
/// Given that this element does not have a fixed offset, return its
/// index in the nonfixed-elements array.
unsigned getNonFixedElementIndex() const {
assert(isCompleted() && getKind() == Kind::NonFixed);
return Index;
}
Address project(IRGenFunction &IGF, Address addr,
NonFixedOffsets offsets,
const llvm::Twine &suffix = "") const;
};
/// A class for building a structure layout.
class StructLayoutBuilder {
protected:
IRGenModule &IGM;
private:
SmallVector<llvm::Type*, 8> StructFields;
Size CurSize = Size(0);
Alignment CurAlignment = Alignment(1);
SpareBitVector CurSpareBits;
unsigned NextNonFixedOffsetIndex = 0;
bool IsFixedLayout = true;
IsPOD_t IsKnownPOD = IsPOD;
IsBitwiseTakable_t IsKnownBitwiseTakable = IsBitwiseTakable;
IsFixedSize_t IsKnownAlwaysFixedSize = IsFixedSize;
public:
StructLayoutBuilder(IRGenModule &IGM) : IGM(IGM) {}
/// Add a swift heap header to the layout. This must be the first
/// call to the layout.
void addHeapHeader();
/// Add a number of fields to the layout. The field layouts need
/// only have the TypeInfo set; the rest will be filled out.
///
/// Returns true if the fields may have increased the storage
/// requirements of the layout.
bool addFields(llvm::MutableArrayRef<ElementLayout> fields,
LayoutStrategy strategy);
/// Return whether the layout is known to be empty.
bool empty() const { return IsFixedLayout && CurSize == Size(0); }
/// Return the current set of fields.
ArrayRef<llvm::Type *> getStructFields() const { return StructFields; }
/// Return whether the structure has a fixed-size layout.
bool isFixedLayout() const { return IsFixedLayout; }
/// Return whether the structure is known to be POD in the local
/// resilience scope.
IsPOD_t isPOD() const { return IsKnownPOD; }
/// Return whether the structure is known to be bitwise-takable in the local
/// resilience scope.
IsBitwiseTakable_t isBitwiseTakable() const {
return IsKnownBitwiseTakable;
}
/// Return whether the structure is known to be fixed-size in all
/// resilience scopes.
IsFixedSize_t isAlwaysFixedSize() const {
return IsKnownAlwaysFixedSize;
}
/// Return the size of the structure built so far.
Size getSize() const { return CurSize; }
/// Return the alignment of the structure built so far.
Alignment getAlignment() const { return CurAlignment; }
/// Return the spare bit mask of the structure built so far.
const SpareBitVector &getSpareBits() const { return CurSpareBits; }
/// Return the spare bit mask of the structure built so far.
SpareBitVector &getSpareBits() { return CurSpareBits; }
/// Build the current elements as a new anonymous struct type.
llvm::StructType *getAsAnonStruct() const;
/// Build the current elements as a new anonymous struct type.
void setAsBodyOfStruct(llvm::StructType *type) const;
private:
void addFixedSizeElement(ElementLayout &elt);
void addNonFixedSizeElement(ElementLayout &elt);
void addEmptyElement(ElementLayout &elt);
void addElementAtFixedOffset(ElementLayout &elt);
void addElementAtNonFixedOffset(ElementLayout &elt);
void addNonFixedSizeElementAtOffsetZero(ElementLayout &elt);
};
/// Apply layout attributes such as @_alignment to the layout properties of a
/// type, diagnosing any problems with them.
void applyLayoutAttributes(IRGenModule &IGM,
CanType ty,
bool isFixedLayout,
/*inout*/ Alignment &alignment);
/// A struct layout is the result of laying out a complete structure.
class StructLayout {
/// The statically-known minimum bound on the alignment.
Alignment MinimumAlign;
/// The statically-known minimum bound on the size.
Size MinimumSize;
/// The statically-known spare bit mask.
SpareBitVector SpareBits;
/// Whether this layout is fixed in size. If so, the size and
/// alignment are exact.
bool IsFixedLayout;
IsPOD_t IsKnownPOD;
IsBitwiseTakable_t IsKnownBitwiseTakable;
IsFixedSize_t IsKnownAlwaysFixedSize = IsFixedSize;
CanType ASTTy;
llvm::Type *Ty;
SmallVector<ElementLayout, 8> Elements;
public:
/// Create a structure layout.
///
/// \param strategy - how much leeway the algorithm has to rearrange
/// and combine the storage of fields
/// \param kind - the kind of layout to perform, including whether the
/// layout must include the reference-counting header
/// \param typeToFill - if present, must be an opaque type whose body
/// will be filled with this layout
StructLayout(IRGenModule &IGM, CanType astTy,
LayoutKind kind, LayoutStrategy strategy,
ArrayRef<const TypeInfo *> fields,
llvm::StructType *typeToFill = 0);
/// Create a structure layout from a builder.
StructLayout(const StructLayoutBuilder &builder,
CanType astTy,
llvm::Type *type,
ArrayRef<ElementLayout> elements)
: MinimumAlign(builder.getAlignment()),
MinimumSize(builder.getSize()),
SpareBits(builder.getSpareBits()),
IsFixedLayout(builder.isFixedLayout()),
IsKnownPOD(builder.isPOD()),
IsKnownBitwiseTakable(builder.isBitwiseTakable()),
IsKnownAlwaysFixedSize(builder.isAlwaysFixedSize()),
ASTTy(astTy),
Ty(type),
Elements(elements.begin(), elements.end()) {}
/// Return the element layouts. This is parallel to the fields
/// passed in the constructor.
ArrayRef<ElementLayout> getElements() const { return Elements; }
const ElementLayout &getElement(unsigned i) const { return Elements[i]; }
llvm::Type *getType() const { return Ty; }
Size getSize() const { return MinimumSize; }
Alignment getAlignment() const { return MinimumAlign; }
const SpareBitVector &getSpareBits() const { return SpareBits; }
SpareBitVector &getSpareBits() { return SpareBits; }
bool isKnownEmpty() const { return isFixedLayout() && MinimumSize.isZero(); }
IsPOD_t isPOD() const { return IsKnownPOD; }
IsBitwiseTakable_t isBitwiseTakable() const {
return IsKnownBitwiseTakable;
}
IsFixedSize_t isAlwaysFixedSize() const {
return IsKnownAlwaysFixedSize;
}
bool isFixedLayout() const { return IsFixedLayout; }
llvm::Constant *emitSize(IRGenModule &IGM) const;
llvm::Constant *emitAlignMask(IRGenModule &IGM) const;
/// Bitcast the given pointer to this type.
Address emitCastTo(IRGenFunction &IGF, llvm::Value *ptr,
const llvm::Twine &name = "") const;
};
Size getHeapHeaderSize(IRGenModule &IGM);
void addHeapHeaderToLayout(IRGenModule &IGM, Size &size, Alignment &align,
SmallVectorImpl<llvm::Type*> &fieldTypes);
/// Different policies for accessing a physical field.
enum class FieldAccess : uint8_t {
/// Instance variable offsets are constant.
ConstantDirect,
/// Instance variable offsets must be loaded from "direct offset"
/// global variables.
NonConstantDirect,
/// Instance variable offsets are kept in fields in metadata, but
/// the offsets of those fields within the metadata are constant.
ConstantIndirect,
/// Instance variable offsets are kept in fields in metadata, and
/// the offsets of those fields within the metadata must be loaded
/// from "indirect offset" global variables.
NonConstantIndirect
};
struct ClassLayout {
/// Lazily-initialized array of all fragile stored properties in the class
/// (including superclass stored properties).
ArrayRef<VarDecl*> AllStoredProperties;
/// Lazily-initialized array of all fragile stored properties inherited from
/// superclasses.
ArrayRef<VarDecl*> InheritedStoredProperties;
/// Lazily-initialized array of all field access methods.
ArrayRef<FieldAccess> AllFieldAccesses;
/// Does the class metadata require dynamic initialization.
bool MetadataRequiresDynamicInitialization;
unsigned getFieldIndex(VarDecl *field) const {
// FIXME: This is algorithmically terrible.
auto found = std::find(AllStoredProperties.begin(),
AllStoredProperties.end(), field);
assert(found != AllStoredProperties.end() && "didn't find field in type?!");
return found - AllStoredProperties.begin();
}
};
} // end namespace irgen
} // end namespace swift
#endif