Skip to content

Commit b18af4f

Browse files
authored
Merge pull request #15671 from rjmccall/cyclic-metadata
Finish the first stage of incomplete type metadata support
2 parents 346bc52 + bd0613f commit b18af4f

File tree

14 files changed

+1045
-440
lines changed

14 files changed

+1045
-440
lines changed

include/swift/Runtime/Debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ struct RuntimeErrorDetails {
167167
uintptr_t framesToSkip;
168168

169169
// Address of some associated object (if there's any).
170-
void *memoryAddress;
170+
const void *memoryAddress;
171171

172172
// A structure describing an extra thread (and its stack) that is related.
173173
struct Thread {

include/swift/Runtime/Metadata.h

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -195,25 +195,45 @@ using Metadata = TargetMetadata<InProcess>;
195195
/// For performance, functions returning this type should use SWIFT_CC so
196196
/// that the components are returned as separate values.
197197
struct MetadataResponse {
198-
/// For metadata access functions, this is the requested metadata.
199-
///
200-
/// For metadata initialization functions, this is either null,
201-
/// indicating that initialization was successful, or a metadata on
202-
/// which initialization depends for further progress.
198+
/// The requested metadata.
203199
const Metadata *Value;
204200

205-
/// For metadata access functions, this is the current state of the
206-
/// metadata returned. Always use this instead of trying to inspect
207-
/// the metadata directly; an incomplete metadata may be getting
208-
/// initialized concurrently. This can generally be ignored if the
209-
/// metadata request was for abstract metadata or if the request is
210-
/// blocking.
211-
///
212-
/// For metadata initialization functions, this is the state that the
213-
/// given metadata needs to be in before initialization can continue.
201+
/// The current state of the metadata returned. Always use this
202+
/// instead of trying to inspect the metadata directly to see if it
203+
/// satisfies the request. An incomplete metadata may be getting
204+
/// initialized concurrently. But this can generally be ignored if
205+
/// the metadata request was for abstract metadata or if the request
206+
/// is blocking.
214207
MetadataState State;
215208
};
216-
using MetadataDependency = MetadataResponse;
209+
210+
/// A dependency on the metadata progress of other type, indicating that
211+
/// initialization of a metadata cannot progress until another metadata
212+
/// reaches a particular state.
213+
///
214+
/// For performance, functions returning this type should use SWIFT_CC so
215+
/// that the components are returned as separate values.
216+
struct MetadataDependency {
217+
/// Either null, indicating that initialization was successful, or
218+
/// a metadata on which initialization depends for further progress.
219+
const Metadata *Value;
220+
221+
/// The state that Metadata needs to be in before initialization
222+
/// can continue.
223+
MetadataState Requirement;
224+
225+
MetadataDependency() : Value(nullptr) {}
226+
MetadataDependency(const Metadata *metadata, MetadataState requirement)
227+
: Value(metadata), Requirement(requirement) {}
228+
229+
explicit operator bool() const { return Value != nullptr; }
230+
231+
bool operator==(MetadataDependency other) const {
232+
assert(Value && other.Value);
233+
return Value == other.Value &&
234+
Requirement == other.Requirement;
235+
}
236+
};
217237

218238
template <typename Runtime> struct TargetProtocolConformanceDescriptor;
219239

@@ -1848,6 +1868,10 @@ struct TargetTupleTypeMetadata : public TargetMetadata<Runtime> {
18481868
OpaqueValue *findIn(OpaqueValue *tuple) const {
18491869
return (OpaqueValue*) (((char*) tuple) + Offset);
18501870
}
1871+
1872+
const TypeLayout *getTypeLayout() const {
1873+
return Type->getTypeLayout();
1874+
}
18511875
};
18521876

18531877
Element *getElements() {
@@ -4160,21 +4184,24 @@ swift_getForeignTypeMetadata(ForeignTypeMetadata *nonUnique);
41604184
/// \param proposedWitnesses - an optional proposed set of value witnesses.
41614185
/// This is useful when working with a non-dependent tuple type
41624186
/// where the entrypoint is just being used to unique the metadata.
4163-
SWIFT_RUNTIME_EXPORT
4164-
const TupleTypeMetadata *
4165-
swift_getTupleTypeMetadata(TupleTypeFlags flags,
4187+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
4188+
MetadataResponse
4189+
swift_getTupleTypeMetadata(MetadataRequest request,
4190+
TupleTypeFlags flags,
41664191
const Metadata * const *elements,
41674192
const char *labels,
41684193
const ValueWitnessTable *proposedWitnesses);
41694194

4170-
SWIFT_RUNTIME_EXPORT
4171-
const TupleTypeMetadata *
4172-
swift_getTupleTypeMetadata2(const Metadata *elt0, const Metadata *elt1,
4195+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
4196+
MetadataResponse
4197+
swift_getTupleTypeMetadata2(MetadataRequest request,
4198+
const Metadata *elt0, const Metadata *elt1,
41734199
const char *labels,
41744200
const ValueWitnessTable *proposedWitnesses);
4175-
SWIFT_RUNTIME_EXPORT
4176-
const TupleTypeMetadata *
4177-
swift_getTupleTypeMetadata3(const Metadata *elt0, const Metadata *elt1,
4201+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
4202+
MetadataResponse
4203+
swift_getTupleTypeMetadata3(MetadataRequest request,
4204+
const Metadata *elt0, const Metadata *elt1,
41784205
const Metadata *elt2, const char *labels,
41794206
const ValueWitnessTable *proposedWitnesses);
41804207

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -869,31 +869,35 @@ FUNCTION(GetObjCClassFromMetadata, swift_getObjCClassFromMetadata, C_CC,
869869
ARGS(TypeMetadataPtrTy),
870870
ATTRS(NoUnwind, ReadNone))
871871

872-
// Metadata *swift_getTupleTypeMetadata(TupleTypeFlags flags,
873-
// Metadata * const *elts,
874-
// const char *labels,
875-
// value_witness_table_t *proposed);
876-
FUNCTION(GetTupleMetadata, swift_getTupleTypeMetadata, C_CC,
877-
RETURNS(TypeMetadataPtrTy),
878-
ARGS(SizeTy, TypeMetadataPtrTy->getPointerTo(0),
872+
// MetadataResponse swift_getTupleTypeMetadata(MetadataRequest request,
873+
// TupleTypeFlags flags,
874+
// Metadata * const *elts,
875+
// const char *labels,
876+
// value_witness_table_t *proposed);
877+
FUNCTION(GetTupleMetadata, swift_getTupleTypeMetadata, SwiftCC,
878+
RETURNS(TypeMetadataResponseTy),
879+
ARGS(SizeTy, SizeTy, TypeMetadataPtrTy->getPointerTo(0),
879880
Int8PtrTy, WitnessTablePtrTy),
880881
ATTRS(NoUnwind, ReadOnly))
881882

882-
// Metadata *swift_getTupleTypeMetadata2(Metadata *elt0, Metadata *elt1,
883-
// const char *labels,
884-
// value_witness_table_t *proposed);
885-
FUNCTION(GetTupleMetadata2, swift_getTupleTypeMetadata2, C_CC,
886-
RETURNS(TypeMetadataPtrTy),
887-
ARGS(TypeMetadataPtrTy, TypeMetadataPtrTy,
883+
// MetadataResponse swift_getTupleTypeMetadata2(MetadataRequest request,
884+
// Metadata *elt0, Metadata *elt1,
885+
// const char *labels,
886+
// value_witness_table_t *proposed);
887+
FUNCTION(GetTupleMetadata2, swift_getTupleTypeMetadata2, SwiftCC,
888+
RETURNS(TypeMetadataResponseTy),
889+
ARGS(SizeTy, TypeMetadataPtrTy, TypeMetadataPtrTy,
888890
Int8PtrTy, WitnessTablePtrTy),
889891
ATTRS(NoUnwind, ReadOnly))
890892

891-
// Metadata *swift_getTupleTypeMetadata3(Metadata *elt0, Metadata *elt1,
892-
// Metadata *elt2, const char *labels,
893-
// value_witness_table_t *proposed);
894-
FUNCTION(GetTupleMetadata3, swift_getTupleTypeMetadata3, C_CC,
895-
RETURNS(TypeMetadataPtrTy),
896-
ARGS(TypeMetadataPtrTy, TypeMetadataPtrTy, TypeMetadataPtrTy,
893+
// MetadataResponse swift_getTupleTypeMetadata3(MetadataRequest request,
894+
// Metadata *elt0, Metadata *elt1,
895+
// Metadata *elt2,
896+
// const char *labels,
897+
// value_witness_table_t *proposed);
898+
FUNCTION(GetTupleMetadata3, swift_getTupleTypeMetadata3, SwiftCC,
899+
RETURNS(TypeMetadataResponseTy),
900+
ARGS(SizeTy, TypeMetadataPtrTy, TypeMetadataPtrTy, TypeMetadataPtrTy,
897901
Int8PtrTy, WitnessTablePtrTy),
898902
ATTRS(NoUnwind, ReadOnly))
899903

lib/IRGen/MetadataRequest.cpp

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -688,21 +688,22 @@ static llvm::Constant *emitEmptyTupleTypeMetadataRef(IRGenModule &IGM) {
688688
/*Ty=*/nullptr, fullMetadata, indices);
689689
}
690690

691-
/// Note that the element request will always be of a
692-
/// canResponseStatusBeIgnored() kind.
693691
using GetElementMetadataFn =
694-
llvm::function_ref<llvm::Value *(CanType eltType,
695-
DynamicMetadataRequest eltRequest)>;
692+
llvm::function_ref<MetadataResponse(CanType eltType,
693+
DynamicMetadataRequest eltRequest)>;
696694

697695
static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
698696
CanTupleType type,
699697
DynamicMetadataRequest request,
700698
bool useLabels,
701-
GetElementMetadataFn getElementMetadata) {
702-
703-
// FIXME: at least propagate dependency failure here.
704-
// FIXME: allow abstract creation when the runtime supports that.
705-
DynamicMetadataRequest eltRequest = MetadataState::Complete;
699+
GetElementMetadataFn getMetadataRecursive) {
700+
auto getElementMetadata = [&](CanType type) {
701+
// Just request the elements to be abstract so that we can always build
702+
// the metadata.
703+
// TODO: if we have a collector, or if this is a blocking request, maybe
704+
// we should build a stronger request?
705+
return getMetadataRecursive(type, MetadataState::Abstract).getMetadata();
706+
};
706707

707708
switch (type->getNumElements()) {
708709
case 0:
@@ -712,42 +713,45 @@ static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
712713
case 1:
713714
// For metadata purposes, we consider a singleton tuple to be
714715
// isomorphic to its element type. ???
715-
return MetadataResponse::forComplete(
716-
getElementMetadata(type.getElementType(0), eltRequest));
716+
return getMetadataRecursive(type.getElementType(0), request);
717717

718718
case 2: {
719-
auto elt0Metadata = getElementMetadata(type.getElementType(0), eltRequest);
720-
auto elt1Metadata = getElementMetadata(type.getElementType(1), eltRequest);
719+
auto elt0Metadata = getElementMetadata(type.getElementType(0));
720+
auto elt1Metadata = getElementMetadata(type.getElementType(1));
721721

722722
llvm::Value *args[] = {
723+
request.get(IGF),
723724
elt0Metadata, elt1Metadata,
724725
getTupleLabelsString(IGF.IGM, type, useLabels),
725726
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
726727
};
727728

728729
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata2Fn(),
729730
args);
731+
call->setCallingConv(IGF.IGM.SwiftCC);
730732
call->setDoesNotThrow();
731733

732-
return MetadataResponse::forComplete(call);
734+
return MetadataResponse::handle(IGF, request, call);
733735
}
734736

735737
case 3: {
736-
auto elt0Metadata = getElementMetadata(type.getElementType(0), eltRequest);
737-
auto elt1Metadata = getElementMetadata(type.getElementType(1), eltRequest);
738-
auto elt2Metadata = getElementMetadata(type.getElementType(2), eltRequest);
738+
auto elt0Metadata = getElementMetadata(type.getElementType(0));
739+
auto elt1Metadata = getElementMetadata(type.getElementType(1));
740+
auto elt2Metadata = getElementMetadata(type.getElementType(2));
739741

740742
llvm::Value *args[] = {
743+
request.get(IGF),
741744
elt0Metadata, elt1Metadata, elt2Metadata,
742745
getTupleLabelsString(IGF.IGM, type, useLabels),
743746
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
744747
};
745748

746749
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata3Fn(),
747750
args);
751+
call->setCallingConv(IGF.IGM.SwiftCC);
748752
call->setDoesNotThrow();
749753

750-
return MetadataResponse::forComplete(call);
754+
return MetadataResponse::handle(IGF, request, call);
751755
}
752756
default:
753757
// TODO: use a caching entrypoint (with all information
@@ -764,7 +768,7 @@ static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
764768
IGF.IGM.getPointerSize() * elements.size());
765769
for (auto i : indices(elements)) {
766770
// Find the metadata pointer for this element.
767-
llvm::Value *eltMetadata = getElementMetadata(elements[i], eltRequest);
771+
llvm::Value *eltMetadata = getElementMetadata(elements[i]);
768772

769773
// GEP to the appropriate element and store.
770774
Address eltPtr = IGF.Builder.CreateStructGEP(buffer, i,
@@ -778,6 +782,7 @@ static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
778782
TupleTypeFlags flags =
779783
TupleTypeFlags().withNumElements(elements.size());
780784
llvm::Value *args[] = {
785+
request.get(IGF),
781786
llvm::ConstantInt::get(IGF.IGM.SizeTy, flags.getIntValue()),
782787
pointerToFirst,
783788
getTupleLabelsString(IGF.IGM, type, useLabels),
@@ -786,12 +791,13 @@ static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
786791

787792
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadataFn(),
788793
args);
794+
call->setCallingConv(IGF.IGM.SwiftCC);
789795
call->setDoesNotThrow();
790796

791797
IGF.Builder.CreateLifetimeEnd(buffer,
792798
IGF.IGM.getPointerSize() * elements.size());
793799

794-
return MetadataResponse::forComplete(call);
800+
return MetadataResponse::handle(IGF, request, call);
795801
}
796802
}
797803

@@ -882,8 +888,7 @@ namespace {
882888
auto response = emitTupleTypeMetadataRef(IGF, type, request,
883889
/*labels*/ true,
884890
[&](CanType eltType, DynamicMetadataRequest eltRequest) {
885-
assert(eltRequest.canResponseStatusBeIgnored());
886-
return IGF.emitTypeMetadataRef(eltType, eltRequest).getMetadata();
891+
return IGF.emitTypeMetadataRef(eltType, eltRequest);
887892
});
888893

889894
return setLocal(type, response);
@@ -1651,24 +1656,23 @@ irgen::emitInPlaceTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
16511656
/// construction of the metadata value just involves calling idempotent
16521657
/// metadata-construction functions. It is not used for the in-place
16531658
/// initialization of non-generic nominal type metadata.
1654-
static llvm::Value *
1659+
static MetadataResponse
16551660
emitTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
1661+
DynamicMetadataRequest request,
16561662
CanType type) {
16571663
assert(!type->hasArchetype() &&
16581664
"cannot emit metadata accessor for context-dependent type");
16591665

16601666
// We only take this path for non-generic nominal types.
16611667
auto typeDecl = type->getAnyNominal();
16621668
if (!typeDecl)
1663-
return emitDirectTypeMetadataRef(IGF, type, MetadataState::Complete)
1664-
.getMetadata();
1669+
return emitDirectTypeMetadataRef(IGF, type, request);
16651670

16661671
if (typeDecl->isGenericContext() &&
16671672
!(isa<ClassDecl>(typeDecl) &&
16681673
isa<ClangModuleUnit>(typeDecl->getModuleScopeContext()))) {
16691674
// This is a metadata accessor for a fully substituted generic type.
1670-
return emitDirectTypeMetadataRef(IGF, type, MetadataState::Complete)
1671-
.getMetadata();
1675+
return emitDirectTypeMetadataRef(IGF, type, request);
16721676
}
16731677

16741678
// We should never be emitting a metadata accessor for resilient nominal
@@ -1687,18 +1691,19 @@ emitTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
16871691
if (auto classDecl = dyn_cast<ClassDecl>(typeDecl)) {
16881692
// We emit a completely different pattern for foreign classes.
16891693
if (classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
1690-
return emitForeignTypeMetadataRef(IGF, type);
1694+
return MetadataResponse::forComplete(
1695+
emitForeignTypeMetadataRef(IGF, type));
16911696
}
16921697

16931698
// Classes that might not have Swift metadata use a different
16941699
// symbol name.
16951700
if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) {
1696-
return emitObjCMetadataRef(IGF, classDecl);
1701+
return MetadataResponse::forComplete(emitObjCMetadataRef(IGF, classDecl));
16971702
}
16981703

16991704
// Imported value types require foreign metadata uniquing.
17001705
} else if (isa<ClangModuleUnit>(typeDecl->getModuleScopeContext())) {
1701-
return emitForeignTypeMetadataRef(IGF, type);
1706+
return MetadataResponse::forComplete(emitForeignTypeMetadataRef(IGF, type));
17021707
}
17031708

17041709
// Okay, everything else is built from a Swift metadata object.
@@ -1707,7 +1712,7 @@ emitTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
17071712
// We should not be doing more serious work along this path.
17081713
assert(isTypeMetadataAccessTrivial(IGF.IGM, type));
17091714

1710-
return metadata;
1715+
return MetadataResponse::forComplete(metadata);
17111716
}
17121717

17131718
/// Get or create an accessor function to the given non-dependent type.
@@ -1762,10 +1767,7 @@ llvm::Function *irgen::getTypeMetadataAccessFunction(IRGenModule &IGM,
17621767
llvm::Constant *cacheVariable) {
17631768
// We should not be called with ForDefinition for nominal types
17641769
// that require in-place initialization.
1765-
// We should also not be called for types that require more interesting
1766-
// initialization that really requires the request/response machinery.
1767-
return MetadataResponse::forComplete(
1768-
emitTypeMetadataAccessFunctionBody(IGF, type));
1770+
return emitTypeMetadataAccessFunctionBody(IGF, request, type);
17691771
});
17701772
}
17711773

@@ -1959,8 +1961,10 @@ namespace {
19591961
auto response = emitTupleTypeMetadataRef(IGF, type, request,
19601962
/*labels*/ false,
19611963
[&](CanType eltType, DynamicMetadataRequest eltRequest) {
1962-
assert(eltRequest.canResponseStatusBeIgnored());
1963-
return visit(eltType, eltRequest);
1964+
// This use of 'forComplete' is technically questionable, but in
1965+
// this class we're always producing responses we can ignore, so
1966+
// it's okay.
1967+
return MetadataResponse::forComplete(visit(eltType, eltRequest));
19641968
});
19651969

19661970
return setLocal(type, response);

0 commit comments

Comments
 (0)