mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[WIP] Emit nominal type access functions for imported types.
Emit nominal type access functions for imported types. These access functions work with non-unique metadata references, so they perform uniquing through the runtime on first access. Fixes rdar://problem/36430234.
This commit is contained in:
@@ -451,7 +451,7 @@ static bool hasRequiredTypeMetadataAccessFunction(NominalTypeDecl *typeDecl) {
|
||||
|
||||
case FormalLinkage::PublicNonUnique:
|
||||
case FormalLinkage::HiddenNonUnique:
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("bad formal linkage");
|
||||
|
||||
@@ -1340,7 +1340,10 @@ emitInPlaceTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
|
||||
CanNominalType type,
|
||||
llvm::Constant *cacheVariable,
|
||||
InPlaceMetadataInitializer &&initializer) {
|
||||
llvm::Constant *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false);
|
||||
llvm::Constant *metadata =
|
||||
IGF.IGM.requiresForeignTypeMetadata(type)
|
||||
? IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type)
|
||||
: IGF.IGM.getAddrOfTypeMetadata(type, false);
|
||||
|
||||
// We might not have interesting initialization to do.
|
||||
assert((cacheVariable == nullptr) ==
|
||||
@@ -4607,8 +4610,9 @@ static llvm::Value *
|
||||
emitInPlaceValueTypeMetadataInitialization(IRGenFunction &IGF,
|
||||
CanNominalType type,
|
||||
llvm::Value *metadata) {
|
||||
// All the value types are basically similar.
|
||||
assert(isa<StructType>(type) || isa<EnumType>(type));
|
||||
// All the value types are basically similar, as are foreign types.
|
||||
assert(isa<StructType>(type) || isa<EnumType>(type) ||
|
||||
IGF.IGM.requiresForeignTypeMetadata(type));
|
||||
|
||||
// Set up the value witness table if it's dependent.
|
||||
SILType loweredType = IGF.IGM.getLoweredType(AbstractionPattern(type), type);
|
||||
@@ -5081,6 +5085,22 @@ namespace {
|
||||
}
|
||||
|
||||
Size getOffsetOfAddressPoint() const { return AddressPoint; }
|
||||
|
||||
void createMetadataAccessFunction() {
|
||||
auto type = cast<NominalType>(asImpl().getTargetType());
|
||||
|
||||
(void) getTypeMetadataAccessFunction(IGM, type, ForDefinition,
|
||||
[&](IRGenFunction &IGF,
|
||||
llvm::Constant *cacheVariable) {
|
||||
return emitInPlaceTypeMetadataAccessFunctionBody(IGF, type,
|
||||
cacheVariable,
|
||||
[&](IRGenFunction &IGF, llvm::Value *candidate) {
|
||||
auto metadata = uniqueForeignTypeMetadataRef(IGF, candidate);
|
||||
return emitInPlaceValueTypeMetadataInitialization(IGF, type,
|
||||
metadata);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class ForeignClassMetadataBuilder;
|
||||
@@ -5140,8 +5160,17 @@ namespace {
|
||||
}
|
||||
|
||||
void addNominalTypeDescriptor() {
|
||||
auto descriptor = ClassNominalTypeDescriptorBuilder(this->IGM, Target).emit();
|
||||
B.add(descriptor);
|
||||
// FIXME: Go through getAddrOfNominalTypeDescriptor once it's no
|
||||
// longer required to define the nominal type descriptor.
|
||||
|
||||
auto entity = LinkEntity::forNominalTypeDescriptor(Target);
|
||||
auto descriptor =
|
||||
IGM.getAddrOfLLVMVariableOrGOTEquivalent(
|
||||
entity,
|
||||
IGM.getPointerAlignment(),
|
||||
IGM.ClassNominalTypeDescriptorTy);
|
||||
assert(!descriptor.isIndirect() && "Should be defined here");
|
||||
B.add(descriptor.getDirectValue());
|
||||
}
|
||||
|
||||
void noteStartOfSuperClass() { }
|
||||
@@ -5225,6 +5254,18 @@ namespace {
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
bool IRGenModule::requiresForeignTypeMetadata(CanType type) {
|
||||
if (NominalTypeDecl *nominal = type->getAnyNominal()) {
|
||||
if (auto *clas = dyn_cast<ClassDecl>(nominal)) {
|
||||
return clas->getForeignClassKind() == ClassDecl::ForeignKind::CFType;
|
||||
}
|
||||
|
||||
return isa<ClangModuleUnit>(nominal->getModuleScopeContext());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
|
||||
// What we save in GlobalVars is actually the offsetted value.
|
||||
@@ -5236,10 +5277,33 @@ IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
|
||||
ConstantInitBuilder builder(*this);
|
||||
auto init = builder.beginStruct();
|
||||
init.setPacked(true);
|
||||
|
||||
|
||||
// Local function to create the global variable for the foreign type
|
||||
// metadata candidate.
|
||||
Size addressPoint;
|
||||
llvm::Constant *result = nullptr;
|
||||
auto createCandidateVariable = [&] {
|
||||
auto definition = init.finishAndCreateFuture();
|
||||
|
||||
// Create the global variable.
|
||||
LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
|
||||
auto var =
|
||||
createVariable(*this, link, definition.getType(),
|
||||
getPointerAlignment());
|
||||
definition.installInGlobal(var);
|
||||
|
||||
// Apply the offset.
|
||||
result = llvm::ConstantExpr::getBitCast(var, Int8PtrTy);
|
||||
result = llvm::ConstantExpr::getInBoundsGetElementPtr(
|
||||
Int8Ty, result, getSize(addressPoint));
|
||||
result = llvm::ConstantExpr::getBitCast(result, TypeMetadataPtrTy);
|
||||
|
||||
// Only remember the offset.
|
||||
GlobalVars[entity] = result;
|
||||
};
|
||||
|
||||
// Compute the constant initializer and the offset of the type
|
||||
// metadata candidate within it.
|
||||
Size addressPoint;
|
||||
if (auto classType = dyn_cast<ClassType>(type)) {
|
||||
assert(!classType.getParent());
|
||||
auto classDecl = classType->getDecl();
|
||||
@@ -5248,6 +5312,11 @@ IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
|
||||
ForeignClassMetadataBuilder builder(*this, classDecl, init);
|
||||
builder.layout();
|
||||
addressPoint = builder.getOffsetOfAddressPoint();
|
||||
|
||||
ClassNominalTypeDescriptorBuilder(*this, classDecl).emit();
|
||||
|
||||
createCandidateVariable();
|
||||
maybeEmitNominalTypeMetadataAccessFunction(classDecl, builder);
|
||||
} else if (auto structType = dyn_cast<StructType>(type)) {
|
||||
auto structDecl = structType->getDecl();
|
||||
assert(isa<ClangModuleUnit>(structDecl->getModuleScopeContext()));
|
||||
@@ -5255,6 +5324,9 @@ IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
|
||||
ForeignStructMetadataBuilder builder(*this, structDecl, init);
|
||||
builder.layout();
|
||||
addressPoint = builder.getOffsetOfAddressPoint();
|
||||
|
||||
createCandidateVariable();
|
||||
maybeEmitNominalTypeMetadataAccessFunction(structDecl, builder);
|
||||
} else if (auto enumType = dyn_cast<EnumType>(type)) {
|
||||
auto enumDecl = enumType->getDecl();
|
||||
assert(enumDecl->hasClangNode());
|
||||
@@ -5262,31 +5334,15 @@ IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
|
||||
ForeignEnumMetadataBuilder builder(*this, enumDecl, init);
|
||||
builder.layout();
|
||||
addressPoint = builder.getOffsetOfAddressPoint();
|
||||
|
||||
createCandidateVariable();
|
||||
maybeEmitNominalTypeMetadataAccessFunction(enumDecl, builder);
|
||||
} else {
|
||||
llvm_unreachable("foreign metadata for unexpected type?!");
|
||||
}
|
||||
|
||||
auto definition = init.finishAndCreateFuture();
|
||||
|
||||
// Create the global variable.
|
||||
LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
|
||||
auto var =
|
||||
createVariable(*this, link, definition.getType(), getPointerAlignment());
|
||||
definition.installInGlobal(var);
|
||||
|
||||
// Apply the offset.
|
||||
llvm::Constant *result = var;
|
||||
result = llvm::ConstantExpr::getBitCast(result, Int8PtrTy);
|
||||
result = llvm::ConstantExpr::getInBoundsGetElementPtr(
|
||||
Int8Ty, result, getSize(addressPoint));
|
||||
result = llvm::ConstantExpr::getBitCast(result, TypeMetadataPtrTy);
|
||||
|
||||
// Only remember the offset.
|
||||
GlobalVars[entity] = result;
|
||||
|
||||
if (NominalTypeDecl *Nominal = type->getAnyNominal()) {
|
||||
if (NominalTypeDecl *Nominal = type->getAnyNominal())
|
||||
addLazyConformances(Nominal);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2104,17 +2104,10 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
|
||||
|
||||
// Trigger the lazy emission of the foreign type metadata.
|
||||
CanType conformingType = Conf->getType()->getCanonicalType();
|
||||
if (NominalTypeDecl *Nominal = conformingType->getAnyNominal()) {
|
||||
if (auto *clas = dyn_cast<ClassDecl>(Nominal)) {
|
||||
if (clas->isForeign())
|
||||
getAddrOfForeignTypeMetadataCandidate(conformingType);
|
||||
} else if (isa<ClangModuleUnit>(Nominal->getModuleScopeContext())) {
|
||||
getAddrOfForeignTypeMetadataCandidate(conformingType);
|
||||
}
|
||||
}
|
||||
if (requiresForeignTypeMetadata(conformingType))
|
||||
(void)getAddrOfForeignTypeMetadataCandidate(conformingType);
|
||||
}
|
||||
|
||||
|
||||
/// True if a function's signature in LLVM carries polymorphic parameters.
|
||||
/// Generic functions and protocol witnesses carry polymorphic parameters.
|
||||
bool irgen::hasPolymorphicParameters(CanSILFunctionType ty) {
|
||||
|
||||
@@ -305,6 +305,23 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
|
||||
NominalTypeDescriptorPtrTy
|
||||
= NominalTypeDescriptorTy->getPointerTo(DefaultAS);
|
||||
|
||||
ClassNominalTypeDescriptorTy =
|
||||
llvm::StructType::get(LLVMContext, {
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int32Ty,
|
||||
Int16Ty,
|
||||
Int16Ty,
|
||||
Int32Ty,
|
||||
}, /*packed=*/true);
|
||||
|
||||
MethodDescriptorStructTy
|
||||
= createStructType(*this, "swift.method_descriptor", {
|
||||
RelativeAddressTy,
|
||||
|
||||
@@ -500,6 +500,7 @@ public:
|
||||
llvm::PointerType *ProtocolConformanceDescriptorPtrTy;
|
||||
llvm::StructType *NominalTypeDescriptorTy;
|
||||
llvm::PointerType *NominalTypeDescriptorPtrTy;
|
||||
llvm::StructType *ClassNominalTypeDescriptorTy;
|
||||
llvm::StructType *MethodDescriptorStructTy; /// %swift.method_descriptor
|
||||
llvm::StructType *TypeMetadataRecordTy;
|
||||
llvm::PointerType *TypeMetadataRecordPtrTy;
|
||||
@@ -1080,6 +1081,10 @@ public:
|
||||
llvm::Constant *getAddrOfTypeMetadataLazyCacheVariable(CanType type,
|
||||
ForDefinition_t forDefinition);
|
||||
llvm::Constant *getAddrOfForeignTypeMetadataCandidate(CanType concreteType);
|
||||
|
||||
/// Determine whether the given type requires foreign type metadata.
|
||||
bool requiresForeignTypeMetadata(CanType type);
|
||||
|
||||
llvm::Constant *getAddrOfClassMetadataBaseOffset(ClassDecl *D,
|
||||
ForDefinition_t forDefinition);
|
||||
llvm::Constant *getAddrOfNominalTypeDescriptor(NominalTypeDecl *D,
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
|
||||
import StdlibUnittest
|
||||
import Foundation
|
||||
import CoreFoundation
|
||||
|
||||
let DemangleToMetadataTests = TestSuite("DemangleToMetadataObjC")
|
||||
|
||||
@objc class C : NSObject { }
|
||||
@objc enum E: Int { case a }
|
||||
@objc protocol P1 { }
|
||||
protocol P2 { }
|
||||
|
||||
DemangleToMetadataTests.test("@objc classes") {
|
||||
expectEqual(type(of: C()), _typeByMangledName("4main1CC")!)
|
||||
@@ -40,5 +42,31 @@ DemangleToMetadataTests.test("Classes that don't exist") {
|
||||
expectNil(_typeByMangledName("4main4BoomC"))
|
||||
}
|
||||
|
||||
// FIXME: Shouldn't need this?
|
||||
extension CFArray: P2 { }
|
||||
|
||||
DemangleToMetadataTests.test("CoreFoundation classes") {
|
||||
expectEqual(CFArray.self, _typeByMangledName("So10CFArrayRefa")!)
|
||||
}
|
||||
|
||||
DemangleToMetadataTests.test("Imported error types") {
|
||||
expectEqual(URLError.self, _typeByMangledName("10Foundation8URLErrorV")!)
|
||||
expectEqual(URLError.Code.self,
|
||||
_typeByMangledName("10Foundation8URLErrorV4CodeV")!)
|
||||
}
|
||||
|
||||
DemangleToMetadataTests.test("Imported swift_wrapper types") {
|
||||
expectEqual(URLFileResourceType.self,
|
||||
_typeByMangledName("So21NSURLFileResourceTypea")!)
|
||||
}
|
||||
|
||||
extension URLSessionTask.State: P2 { }
|
||||
|
||||
DemangleToMetadataTests.test("Imported enum types") {
|
||||
// FIXME: Should work
|
||||
// expectEqual(NSURLSessionTask.State.self,
|
||||
// _typeByMangledName("So21NSURLSessionTaskStateV")!)
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user