Skip to content

Add swift_getTypeByMangledNameInContextInMetadataState such that we can #28337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,11 @@ class ASTContext final {
/// compiler for the target platform.
AvailabilityContext getSwift51Availability();

/// Get the runtime availability of
/// swift_getTypeByMangledNameInContextInMetadataState.
AvailabilityContext getTypesInAbstractMetadataStateAvailability();


//===--------------------------------------------------------------------===//
// Diagnostics Helper functions
//===--------------------------------------------------------------------===//
Expand Down
14 changes: 14 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,20 @@ FUNCTION(GetTypeByMangledNameInContext, swift_getTypeByMangledNameInContext,
ARGS(Int8PtrTy, SizeTy, TypeContextDescriptorPtrTy, Int8PtrPtrTy),
ATTRS(NoUnwind, ArgMemOnly))

// const Metadata *swift_getTypeByMangledNameInContextInMetadataState(
// size_t metadataState,
// const char *typeNameStart,
// size_t typeNameLength,
// const TargetContextDescriptor<InProcess> *context,
// const void * const *genericArgs)
FUNCTION(GetTypeByMangledNameInContextInMetadataState,
swift_getTypeByMangledNameInContextInMetadataState, SwiftCC,
GetTypesInAbstractMetadataStateAvailability,
RETURNS(TypeMetadataPtrTy),
ARGS(SizeTy, Int8PtrTy, SizeTy, TypeContextDescriptorPtrTy,
Int8PtrPtrTy),
ATTRS(NoUnwind, ArgMemOnly))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd also be good to add the swift_getTypeByMangledNameInEnvironmentInMetadataState variant, so we have it available for future use to instantiate metadata in generic environments that don't have an associated type context.


#undef RETURNS
#undef ARGS
#undef ATTRS
Expand Down
14 changes: 14 additions & 0 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,17 @@ AvailabilityContext ASTContext::getSwift51Availability() {
return AvailabilityContext::alwaysAvailable();
}
}

AvailabilityContext ASTContext::getTypesInAbstractMetadataStateAvailability() {
auto target = LangOpts.Target;

if (target.isMacOSX() ) {
return AvailabilityContext(
VersionRange::allGTE(llvm::VersionTuple(10, 99, 0)));
} else if (target.isiOS() || target.isWatchOS()) {
return AvailabilityContext(
VersionRange::allGTE(llvm::VersionTuple(9999, 0, 0)));
} else {
return AvailabilityContext::alwaysAvailable();
}
}
10 changes: 10 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,16 @@ namespace RuntimeConstants {
return RuntimeAvailability::AlwaysAvailable;
}

RuntimeAvailability
GetTypesInAbstractMetadataStateAvailability(ASTContext &context) {
auto featureAvailability =
context.getTypesInAbstractMetadataStateAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}

RuntimeAvailability DynamicReplacementAvailability(ASTContext &Context) {
auto featureAvailability = Context.getSwift51Availability();
if (!isDeploymentAvailabilityContainedIn(Context, featureAvailability)) {
Expand Down
77 changes: 52 additions & 25 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2156,16 +2156,29 @@ static bool shouldAccessByMangledName(IRGenModule &IGM, CanType type) {

}

static bool canIssueIncompleteMetadataRequests(IRGenModule &IGM) {
// We can only answer blocking complete metadata requests with the <=5.1
// runtime ABI entry points.
auto &context = IGM.getSwiftModule()->getASTContext();
auto deploymentAvailability =
AvailabilityContext::forDeploymentTarget(context);
return deploymentAvailability.isContainedIn(
context.getTypesInAbstractMetadataStateAvailability());
}

/// Emit a call to a type metadata accessor using a mangled name.
static MetadataResponse
emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type,
DynamicMetadataRequest request) {
// TODO: We can only answer blocking complete metadata requests with the
// <=5.1 runtime ABI entry points.
assert(request.isStaticallyBlockingComplete()
&& "can only form complete metadata by mangled name");

auto &IGM = IGF.IGM;

// We can only answer blocking complete metadata requests with the <=5.1
// runtime ABI entry points.
assert((request.isStaticallyBlockingComplete() ||
(request.isStaticallyAbstract() &&
canIssueIncompleteMetadataRequests(IGM))) &&
"can only form complete metadata by mangled name");

llvm::Constant *mangledString;
unsigned mangledStringSize;
std::tie(mangledString, mangledStringSize) =
Expand Down Expand Up @@ -2198,11 +2211,15 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type,
}

// Get or create a shared helper function to do the instantiation.
auto instantiationFnName =
request.isStaticallyAbstract()
? "__swift_instantiateConcreteTypeFromMangledNameAbstract"
: "__swift_instantiateConcreteTypeFromMangledName";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for implementing this, Arnold! I wonder whether, if we're targeting Swift >= 5.2, we could only emit __swift_instantiateConcreteTypeFromMangledNameAbstract and use it for all metadata requests. That would probably mean a couple more instructions at call sites to materialize the metadata request kind argument, though.

auto instantiationFn = cast<llvm::Function>(
IGM.getModule()
->getOrInsertFunction("__swift_instantiateConcreteTypeFromMangledName",
IGF.IGM.TypeMetadataPtrTy, cache->getType())
.getCallee());
IGM.getModule()
->getOrInsertFunction(instantiationFnName, IGF.IGM.TypeMetadataPtrTy,
cache->getType())
.getCallee());
if (instantiationFn->empty()) {
ApplyIRLinkage(IRLinkage::InternalLinkOnceODR)
.to(instantiationFn);
Expand All @@ -2212,7 +2229,7 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type,
llvm::Attribute::NoInline);
IGM.setHasFramePointer(instantiationFn, false);

[&IGM, instantiationFn]{
[&IGM, instantiationFn, request]{
IRGenFunction subIGF(IGM, instantiationFn);

auto params = subIGF.collectParameters();
Expand Down Expand Up @@ -2279,15 +2296,26 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type,
auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase,
stringAddrOffset);
stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy);

auto call =
subIGF.Builder.CreateCall(IGM.getGetTypeByMangledNameInContextFn(),
{stringAddr,
size,
// TODO: Use mangled name lookup in generic
// contexts?
llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});

llvm::CallInst *call;
if (request.isStaticallyAbstract()) {
call = subIGF.Builder.CreateCall(
IGM.getGetTypeByMangledNameInContextInMetadataStateFn(),
{llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract),
stringAddr, size,
// TODO: Use mangled name lookup in generic
// contexts?
llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});
} else {
call = subIGF.Builder.CreateCall(
IGM.getGetTypeByMangledNameInContextFn(),
{stringAddr, size,
// TODO: Use mangled name lookup in generic
// contexts?
llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});
}
call->setDoesNotThrow();
call->setDoesNotAccessMemory();
call->setCallingConv(IGM.SwiftCC);
Expand Down Expand Up @@ -2339,14 +2367,13 @@ emitCallToTypeMetadataAccessFunction(IRGenFunction &IGF, CanType type,
// single access by mangled name instead, if we're asking for complete
// metadata.
//
// TODO: The getTypeByMangledNameInContext entry point in Swift <=5.1 can
// only answer requests for complete metadata. We could introduce new
// entry points that could answer all metadata requests.
if (request.isStaticallyBlockingComplete()
&& shouldAccessByMangledName(IGF.IGM, type)) {
if ((request.isStaticallyBlockingComplete() ||
(request.isStaticallyAbstract() &&
canIssueIncompleteMetadataRequests(IGF.IGM))) &&
shouldAccessByMangledName(IGF.IGM, type)) {
return emitMetadataAccessByMangledName(IGF, type, request);
}

llvm::Constant *accessor =
getOrCreateTypeMetadataAccessFunction(IGF.IGM, type);
llvm::CallInst *call = IGF.Builder.CreateCall(accessor, { request.get(IGF) });
Expand Down
40 changes: 40 additions & 0 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,26 @@ swift_getTypeByMangledNameInEnvironment(
}).getMetadata();
}

SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT
const Metadata * _Nullable
swift_getTypeByMangledNameInEnvironmentInMetadataState(
size_t metadataState,
const char *typeNameStart,
size_t typeNameLength,
const TargetGenericEnvironment<InProcess> *environment,
const void * const *genericArgs) {
llvm::StringRef typeName(typeNameStart, typeNameLength);
SubstGenericParametersFromMetadata substitutions(environment, genericArgs);
return swift_getTypeByMangledName((MetadataState)metadataState, typeName,
genericArgs,
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index);
},
[&substitutions](const Metadata *type, unsigned index) {
return substitutions.getWitnessTable(type, index);
}).getMetadata();
}

SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT
const Metadata * _Nullable
swift_getTypeByMangledNameInContext(
Expand All @@ -1708,6 +1728,26 @@ swift_getTypeByMangledNameInContext(
}).getMetadata();
}

SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT
const Metadata * _Nullable
swift_getTypeByMangledNameInContextInMetadataState(
size_t metadataState,
const char *typeNameStart,
size_t typeNameLength,
const TargetContextDescriptor<InProcess> *context,
const void * const *genericArgs) {
llvm::StringRef typeName(typeNameStart, typeNameLength);
SubstGenericParametersFromMetadata substitutions(context, genericArgs);
return swift_getTypeByMangledName((MetadataState)metadataState, typeName,
genericArgs,
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index);
},
[&substitutions](const Metadata *type, unsigned index) {
return substitutions.getWitnessTable(type, index);
}).getMetadata();
}

/// Demangle a mangled name, but don't allow symbolic references.
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
const Metadata *_Nullable
Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/conditional_conformances.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc.swift
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass.swift
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift --check-prefix=CHECK --check-prefix=%target-os

// Too many pointer-sized integers in the IR
// REQUIRES: PTRSIZE=64
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.99 -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=TYPEBYNAME

// Too many pointer-sized integers in the IR
// REQUIRES: PTRSIZE=64
// REQUIRES: OS=macosx

54 changes: 48 additions & 6 deletions test/Inputs/conditional_conformance_basic_conformances.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,19 @@ public func single_concrete() {
// CHECK-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont

// CHECK: cacheIsNull:
// CHECK-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255)
// CHECK-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// macosx-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255)
// macosx-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// macosx-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// ios-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255)
// ios-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// ios-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// tvos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255)
// tvos-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// tvos-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// watchos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMa"(i64 255)
// watchos-NEXT: [[Single_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// watchos-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// linux-gnu-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMD")

// CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* %conditional.requirement.buffer, i32 0, i32 0
// CHECK-NEXT: [[A_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0
Expand All @@ -100,6 +110,28 @@ public func single_concrete() {
// CHECK-NEXT: ret i8** [[T0]]
// CHECK-NEXT: }

// TYPEBYNAME-LABEL: define linkonce_odr hidden i8** @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGACyxGAA2P1A2A0G0RzlWl"()
// TYPEBYNAME-NEXT: entry:
// TYPEBYNAME-NEXT: %conditional.requirement.buffer = alloca [1 x i8**], align 8
// TYPEBYNAME-NEXT: [[CACHE:%.*]] = load i8**, i8*** @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGACyxGAA2P1A2A0G0RzlWL", align 8
// TYPEBYNAME-NEXT: [[IS_NULL:%.*]] = icmp eq i8** [[CACHE]], null
// TYPEBYNAME-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont

// TYPEBYNAME: cacheIsNull:
// TYPEBYNAME-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGMD")
// TYPEBYNAME-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [1 x i8**], [1 x i8**]* %conditional.requirement.buffer, i32 0, i32 0
// TYPEBYNAME-NEXT: [[A_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0
// TYPEBYNAME-NEXT: store i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$s42conditional_conformance_basic_conformances4IsP2VAA0F0AAWP", i32 0, i32 0), i8*** [[A_P2_PTR]], align 8

// TYPEBYNAME-NEXT: [[Single_P1:%.*]] = call i8** @swift_getWitnessTable
// TYPEBYNAME-NEXT: store atomic i8** [[Single_P1]], i8*** @"$s42conditional_conformance_basic_conformances6SingleVyAA4IsP2VGACyxGAA2P1A2A0G0RzlWL" release, align 8
// TYPEBYNAME-NEXT: br label %cont

// TYPEBYNAME: cont:
// TYPEBYNAME-NEXT: [[T0:%.*]] = phi i8** [ [[CACHE]], %entry ], [ [[Single_P1]], %cacheIsNull ]
// TYPEBYNAME-NEXT: ret i8** [[T0]]
// TYPEBYNAME-NEXT: }


public struct Double<B, C> {}
extension Double: P1 where B: P2, C: P3 {
Expand Down Expand Up @@ -218,9 +250,19 @@ public func double_concrete_concrete() {
// CHECK-NEXT: br i1 [[IS_NULL]], label %cacheIsNull, label %cont

// CHECK: cacheIsNull:
// CHECK-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255)
// CHECK-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// macosx-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255)
// macosx-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// macosx-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// ios-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255)
// ios-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// ios-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// tvos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255)
// tvos-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// tvos-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// watchos-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMa"(i64 255)
// watchos-NEXT: [[Double_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// watchos-NEXT: extractvalue %swift.metadata_response [[T0]], 1
// linux-gnu-NEXT: [[T0:%.*]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledNameAbstract({ i32, i32 }* @"$s42conditional_conformance_basic_conformances6DoubleVyAA4IsP2VAA0F2P3VGMD")

// CHECK-NEXT: [[CONDITIONAL_REQUIREMENTS:%.*]] = getelementptr inbounds [2 x i8**], [2 x i8**]* %conditional.requirement.buffer, i32 0, i32 0
// CHECK-NEXT: [[B_P2_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[CONDITIONAL_REQUIREMENTS]], i32 0
Expand Down
Loading