Skip to content

Commit 4fccd2f

Browse files
committed
Reflection: Closure context layout
This adds various MetadataReader methods to support closure layout: - Reading generic arguments from metadata - Reading parent metadata - Reading capture descriptor from heap metadata To a large extent, this is not currently taken advantage of, because SILGen always wraps address-only captures in SIL box types. Tests are in the next patch.
1 parent c056b25 commit 4fccd2f

File tree

7 files changed

+331
-4
lines changed

7 files changed

+331
-4
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/Reflection/TypeRefBuilder.h"
2727

2828
#include <iostream>
29+
#include <set>
2930
#include <vector>
3031
#include <unordered_map>
3132

@@ -46,6 +47,8 @@ class ReflectionContext
4647
using super::getBuilder;
4748
using super::readIsaMask;
4849
using super::readTypeFromMetadata;
50+
using super::readParentFromMetadata;
51+
using super::readGenericArgFromMetadata;
4952
using super::readMetadataFromInstance;
5053
using typename super::StoredPointer;
5154

@@ -202,6 +205,225 @@ class ReflectionContext
202205
const TypeInfo *getTypeInfo(const TypeRef *TR) {
203206
return getBuilder().getTypeConverter().getTypeInfo(TR);
204207
}
208+
209+
private:
210+
const TypeInfo *getClosureContextInfo(StoredPointer Context,
211+
const ClosureContextInfo &Info) {
212+
RecordTypeInfoBuilder Builder(getBuilder().getTypeConverter(),
213+
RecordKind::ClosureContext);
214+
215+
auto Metadata = readMetadataFromInstance(Context);
216+
if (!Metadata.first)
217+
return nullptr;
218+
219+
// Calculate the offset of the first capture.
220+
// See GenHeap.cpp, buildPrivateMetadata().
221+
auto OffsetToFirstCapture =
222+
this->readOffsetToFirstCaptureFromMetadata(Metadata.second);
223+
if (!OffsetToFirstCapture.first)
224+
return nullptr;
225+
226+
// Initialize the builder.
227+
Builder.addField(OffsetToFirstCapture.second, sizeof(StoredPointer));
228+
229+
// FIXME: should be unordered_set but I'm too lazy to write a hash
230+
// functor
231+
std::set<std::pair<const TypeRef *, const MetadataSource *>> Done;
232+
GenericArgumentMap Subs;
233+
234+
ArrayRef<const TypeRef *> CaptureTypes = Info.CaptureTypes;
235+
236+
// Closure context element layout depends on the layout of the
237+
// captured types, but captured types might depend on element
238+
// layout (of previous elements). Use an iterative approach to
239+
// solve the problem.
240+
while (!CaptureTypes.empty()) {
241+
const TypeRef *OrigCaptureTR = CaptureTypes[0];
242+
const TypeRef *SubstCaptureTR = nullptr;
243+
244+
// If we have enough substitutions to make this captured value's
245+
// type concrete, or we know it's size anyway (because it is a
246+
// class reference or metatype, for example), go ahead and add
247+
// it to the layout.
248+
if (OrigCaptureTR->isConcreteAfterSubstitutions(Subs))
249+
SubstCaptureTR = OrigCaptureTR->subst(getBuilder(), Subs);
250+
else if (getBuilder().getTypeConverter().hasFixedSize(OrigCaptureTR))
251+
SubstCaptureTR = OrigCaptureTR;
252+
253+
if (SubstCaptureTR != nullptr) {
254+
Builder.addField("", SubstCaptureTR);
255+
if (Builder.isInvalid())
256+
return nullptr;
257+
258+
// Try the next capture type.
259+
CaptureTypes = CaptureTypes.slice(1);
260+
continue;
261+
}
262+
263+
// Ok, we do not have enough substitutions yet. Perhaps we have
264+
// enough elements figured out that we can pick off some
265+
// metadata sources though, and use those to derive some new
266+
// substitutions.
267+
bool Progress = false;
268+
for (auto Source : Info.MetadataSources) {
269+
// Don't read a source more than once.
270+
if (Done.count(Source))
271+
continue;
272+
273+
// If we don't have enough information to read this source
274+
// (because it is fulfilled by metadata from a capture at
275+
// at unknown offset), keep going.
276+
if (!isMetadataSourceReady(Source.second, Builder))
277+
continue;
278+
279+
auto Metadata = readMetadataSource(Context, Source.second, Builder);
280+
if (!Metadata.first)
281+
return nullptr;
282+
283+
auto *SubstTR = readTypeFromMetadata(Metadata.second);
284+
if (SubstTR == nullptr)
285+
return nullptr;
286+
287+
if (!TypeRef::deriveSubstitutions(Subs, Source.first, SubstTR))
288+
return nullptr;
289+
290+
Done.insert(Source);
291+
Progress = true;
292+
}
293+
294+
// If we failed to make any forward progress above, we're stuck
295+
// and cannot close out this layout.
296+
if (!Progress)
297+
return nullptr;
298+
}
299+
300+
// Ok, we have a complete picture now.
301+
return Builder.build();
302+
}
303+
304+
/// Checks if we have enough information to read the given metadata
305+
/// source.
306+
///
307+
/// \param Builder Used to obtain offsets of elements known so far.
308+
bool isMetadataSourceReady(const MetadataSource *MS,
309+
const RecordTypeInfoBuilder &Builder) {
310+
switch (MS->getKind()) {
311+
case MetadataSourceKind::ClosureBinding:
312+
return true;
313+
case MetadataSourceKind::ReferenceCapture: {
314+
unsigned Index = cast<ReferenceCaptureMetadataSource>(MS)->getIndex();
315+
return Index < Builder.getNumFields();
316+
}
317+
case MetadataSourceKind::MetadataCapture: {
318+
unsigned Index = cast<MetadataCaptureMetadataSource>(MS)->getIndex();
319+
return Index < Builder.getNumFields();
320+
}
321+
case MetadataSourceKind::GenericArgument: {
322+
auto Base = cast<GenericArgumentMetadataSource>(MS)->getSource();
323+
return isMetadataSourceReady(Base, Builder);
324+
}
325+
case MetadataSourceKind::Parent: {
326+
auto Base = cast<ParentMetadataSource>(MS)->getChild();
327+
return isMetadataSourceReady(Base, Builder);
328+
}
329+
case MetadataSourceKind::Self:
330+
case MetadataSourceKind::SelfWitnessTable:
331+
return true;
332+
}
333+
}
334+
335+
/// Read metadata for a captured generic type from a closure context.
336+
///
337+
/// \param Context The closure context in the remote process.
338+
///
339+
/// \param MS The metadata source, which must be "ready" as per the
340+
/// above.
341+
///
342+
/// \param Builder Used to obtain offsets of elements known so far.
343+
std::pair<bool, StoredPointer>
344+
readMetadataSource(StoredPointer Context,
345+
const MetadataSource *MS,
346+
const RecordTypeInfoBuilder &Builder) {
347+
switch (MS->getKind()) {
348+
case MetadataSourceKind::ClosureBinding: {
349+
unsigned Index = cast<ClosureBindingMetadataSource>(MS)->getIndex();
350+
351+
// Skip the context's isa pointer.
352+
//
353+
// Metadata bindings are stored consecutively at the beginning of the
354+
// closure context.
355+
unsigned Offset = ((sizeof(StoredPointer) == 4 ? 12 : 8) +
356+
sizeof(StoredPointer) * Index);
357+
358+
StoredPointer MetadataAddress;
359+
if (!getReader().readInteger(RemoteAddress(Context + Offset),
360+
&MetadataAddress))
361+
break;
362+
363+
return std::make_pair(true, MetadataAddress);
364+
}
365+
case MetadataSourceKind::ReferenceCapture: {
366+
unsigned Index = cast<ReferenceCaptureMetadataSource>(MS)->getIndex();
367+
368+
// We should already have enough type information to know the offset
369+
// of this capture in the context.
370+
unsigned CaptureOffset = Builder.getFieldOffset(Index);
371+
372+
StoredPointer CaptureAddress;
373+
if (!getReader().readInteger(RemoteAddress(Context + CaptureOffset),
374+
&CaptureAddress))
375+
break;
376+
377+
// Read the requested capture's isa pointer.
378+
return readMetadataFromInstance(CaptureAddress);
379+
}
380+
case MetadataSourceKind::MetadataCapture: {
381+
unsigned Index = cast<MetadataCaptureMetadataSource>(MS)->getIndex();
382+
383+
// We should already have enough type information to know the offset
384+
// of this capture in the context.
385+
unsigned CaptureOffset = Builder.getFieldOffset(Index);
386+
387+
StoredPointer CaptureAddress;
388+
if (!getReader().readInteger(RemoteAddress(Context + CaptureOffset),
389+
&CaptureAddress))
390+
break;
391+
392+
return std::make_pair(true, CaptureAddress);
393+
}
394+
case MetadataSourceKind::GenericArgument: {
395+
auto *GAMS = cast<GenericArgumentMetadataSource>(MS);
396+
auto Base = readMetadataSource(Context, GAMS->getSource(), Builder);
397+
if (!Base.first)
398+
break;
399+
400+
unsigned Index = GAMS->getIndex();
401+
auto Arg = readGenericArgFromMetadata(Base.second, Index);
402+
if (!Arg.first)
403+
break;
404+
405+
return Arg;
406+
}
407+
case MetadataSourceKind::Parent: {
408+
auto Base = readMetadataSource(Context,
409+
cast<ParentMetadataSource>(MS)->getChild(),
410+
Builder);
411+
if (!Base.first)
412+
break;
413+
414+
auto Parent = readParentFromMetadata(Base.second);
415+
if (!Parent.first)
416+
break;
417+
418+
return Parent;
419+
}
420+
case MetadataSourceKind::Self:
421+
case MetadataSourceKind::SelfWitnessTable:
422+
break;
423+
}
424+
425+
return std::make_pair(false, StoredPointer(0));
426+
}
205427
};
206428

207429
} // end namespace reflection

include/swift/Reflection/TypeLowering.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ enum class RecordKind : unsigned {
5555
// A class instance layout, consisting of the stored properties of
5656
// one class, excluding superclasses.
5757
ClassInstance,
58+
59+
// A closure context instance layout, consisting of the captured values.
60+
// For now, captured values do not retain their names.
61+
ClosureContext,
5862
};
5963

6064
enum class ReferenceCounting : unsigned {
@@ -231,6 +235,14 @@ class RecordTypeInfoBuilder {
231235
unsigned addField(unsigned fieldSize, unsigned fieldAlignment);
232236
void addField(const std::string &Name, const TypeRef *TR);
233237
const RecordTypeInfo *build();
238+
239+
unsigned getNumFields() const {
240+
return Fields.size();
241+
}
242+
243+
unsigned getFieldOffset(unsigned Index) const {
244+
return Fields[Index].Offset;
245+
}
234246
};
235247

236248
}

include/swift/Remote/MetadataReader.h

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -733,13 +733,12 @@ class MetadataReader {
733733
return Builder.createForeignClassType(std::move(name));
734734
}
735735
case MetadataKind::HeapLocalVariable:
736-
return Builder.getUnnamedForeignClassType(); // FIXME?
737736
case MetadataKind::HeapGenericLocalVariable:
738-
return Builder.getUnnamedForeignClassType(); // FIXME?
739737
case MetadataKind::ErrorObject:
740-
return Builder.getUnnamedForeignClassType(); // FIXME?
738+
// Treat these all as Builtin.NativeObject for type lowering purposes.
739+
return Builder.createBuiltinType("Bo");
741740
case MetadataKind::Opaque:
742-
return Builder.getOpaqueType(); // FIXME?
741+
return Builder.getOpaqueType();
743742
}
744743
}
745744

@@ -767,6 +766,68 @@ class MetadataReader {
767766
return {true, MetadataAddress & isaMaskValue};
768767
}
769768

769+
/// Read the parent type metadata from a nested nominal type metadata.
770+
std::pair<bool, StoredPointer>
771+
readParentFromMetadata(StoredPointer metadata) {
772+
auto Meta = readMetadata(metadata);
773+
if (!Meta)
774+
return std::make_pair(false, 0);
775+
776+
auto descriptorAddress = readAddressOfNominalTypeDescriptor(Meta);
777+
if (!descriptorAddress)
778+
return std::make_pair(false, 0);
779+
780+
// Read the nominal type descriptor.
781+
auto descriptor = readNominalTypeDescriptor(descriptorAddress);
782+
if (!descriptor)
783+
return std::make_pair(false, 0);
784+
785+
// Read the parent type if the type has one.
786+
if (descriptor->GenericParams.Flags.hasParent()) {
787+
StoredPointer parentAddress = getNominalParent(Meta, descriptor);
788+
if (!parentAddress)
789+
return std::make_pair(false, 0);
790+
return std::make_pair(true, parentAddress);
791+
}
792+
793+
return std::make_pair(false, 0);
794+
}
795+
796+
/// Read a single generic type argument from a bound generic type
797+
/// metadata.
798+
std::pair<bool, StoredPointer>
799+
readGenericArgFromMetadata(StoredPointer metadata, unsigned index) {
800+
auto Meta = readMetadata(metadata);
801+
if (!Meta)
802+
return std::make_pair(false, 0);
803+
804+
auto descriptorAddress = readAddressOfNominalTypeDescriptor(Meta);
805+
if (!descriptorAddress)
806+
return std::make_pair(false, 0);
807+
808+
// Read the nominal type descriptor.
809+
auto descriptor = readNominalTypeDescriptor(descriptorAddress);
810+
if (!descriptor)
811+
return std::make_pair(false, 0);
812+
813+
auto numGenericParams = descriptor->GenericParams.NumPrimaryParams;
814+
auto offsetToGenericArgs =
815+
sizeof(StoredPointer) * (descriptor->GenericParams.Offset);
816+
auto addressOfGenericArgAddress =
817+
Meta.getAddress() + offsetToGenericArgs +
818+
index * sizeof(StoredPointer);
819+
820+
if (index >= numGenericParams)
821+
return std::make_pair(false, 0);
822+
823+
StoredPointer genericArgAddress;
824+
if (!Reader->readInteger(RemoteAddress(addressOfGenericArgAddress),
825+
&genericArgAddress))
826+
return std::make_pair(false, 0);
827+
828+
return std::make_pair(true, genericArgAddress);
829+
}
830+
770831
/// Given the address of a nominal type descriptor, attempt to resolve
771832
/// its nominal type declaration.
772833
BuiltNominalTypeDecl readNominalTypeFromDescriptor(StoredPointer address) {
@@ -800,6 +861,28 @@ class MetadataReader {
800861
return true;
801862
}
802863

864+
/// Given a remote pointer to class metadata, attempt to read its superclass.
865+
std::pair<bool, StoredPointer>
866+
readOffsetToFirstCaptureFromMetadata(StoredPointer MetadataAddress) {
867+
auto meta = readMetadata(MetadataAddress);
868+
if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable)
869+
return std::make_pair(false, 0);
870+
871+
auto heapMeta = cast<TargetHeapLocalVariableMetadata<Runtime>>(meta);
872+
return std::make_pair(true, heapMeta->OffsetToFirstCapture);
873+
}
874+
875+
/// Given a remote pointer to class metadata, attempt to read its superclass.
876+
std::pair<bool, StoredPointer>
877+
readCaptureDescriptorFromMetadata(StoredPointer MetadataAddress) {
878+
auto meta = readMetadata(MetadataAddress);
879+
if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable)
880+
return std::make_pair(false, 0);
881+
882+
auto heapMeta = cast<TargetHeapLocalVariableMetadata<Runtime>>(meta);
883+
return std::make_pair(true, heapMeta->CaptureDescription);
884+
}
885+
803886
protected:
804887
template<typename Offset>
805888
StoredPointer resolveRelativeOffset(StoredPointer targetAddress) {

include/swift/Runtime/Metadata.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,10 @@ struct TargetHeapLocalVariableMetadata
17621762
using StoredPointer = typename Runtime::StoredPointer;
17631763
uint32_t OffsetToFirstCapture;
17641764
TargetPointer<Runtime, const char> CaptureDescription;
1765+
1766+
static bool classof(const TargetMetadata<Runtime> *metadata) {
1767+
return metadata->getKind() == MetadataKind::HeapLocalVariable;
1768+
}
17651769
};
17661770
using HeapLocalVariableMetadata
17671771
= TargetHeapLocalVariableMetadata<InProcess>;

0 commit comments

Comments
 (0)