Skip to content

Commit 6c31586

Browse files
committed
Add cyclic-metadata support to tuples.
I was going to put this off for awhile, but it turns out that a lot of my testcases are enums with multi-payload cases, which we currently compile as tuples, so they were all still hanging until this patch.
1 parent f22d02a commit 6c31586

File tree

12 files changed

+524
-288
lines changed

12 files changed

+524
-288
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,10 @@ struct TargetTupleTypeMetadata : public TargetMetadata<Runtime> {
18681868
OpaqueValue *findIn(OpaqueValue *tuple) const {
18691869
return (OpaqueValue*) (((char*) tuple) + Offset);
18701870
}
1871+
1872+
const TypeLayout *getTypeLayout() const {
1873+
return Type->getTypeLayout();
1874+
}
18711875
};
18721876

18731877
Element *getElements() {
@@ -4180,21 +4184,24 @@ swift_getForeignTypeMetadata(ForeignTypeMetadata *nonUnique);
41804184
/// \param proposedWitnesses - an optional proposed set of value witnesses.
41814185
/// This is useful when working with a non-dependent tuple type
41824186
/// where the entrypoint is just being used to unique the metadata.
4183-
SWIFT_RUNTIME_EXPORT
4184-
const TupleTypeMetadata *
4185-
swift_getTupleTypeMetadata(TupleTypeFlags flags,
4187+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
4188+
MetadataResponse
4189+
swift_getTupleTypeMetadata(MetadataRequest request,
4190+
TupleTypeFlags flags,
41864191
const Metadata * const *elements,
41874192
const char *labels,
41884193
const ValueWitnessTable *proposedWitnesses);
41894194

4190-
SWIFT_RUNTIME_EXPORT
4191-
const TupleTypeMetadata *
4192-
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,
41934199
const char *labels,
41944200
const ValueWitnessTable *proposedWitnesses);
4195-
SWIFT_RUNTIME_EXPORT
4196-
const TupleTypeMetadata *
4197-
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,
41984205
const Metadata *elt2, const char *labels,
41994206
const ValueWitnessTable *proposedWitnesses);
42004207

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)