Skip to content

Class stub fixes and execution tests #23846

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
merged 8 commits into from
Apr 19, 2019
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
65 changes: 19 additions & 46 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2084,13 +2084,6 @@ TypeDecl *EquivalenceClass::lookupNestedType(
foundMembers);
for (auto member : foundMembers) {
if (auto type = dyn_cast<TypeDecl>(member)) {
// Resolve the signature of this type.
if (!type->hasInterfaceType()) {
type->getASTContext().getLazyResolver()->resolveDeclSignature(type);
if (!type->hasInterfaceType())
continue;
}

concreteDecls.push_back(type);
}
}
Expand Down Expand Up @@ -3812,25 +3805,31 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype(
return pa;
}

static Type getStructuralType(TypeDecl *typeDecl, LazyResolver *resolver) {
if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
// Resolve the underlying type, if we haven't done so yet.
if (!typealias->hasInterfaceType())
resolver->resolveDeclSignature(typealias);

return typealias->getUnderlyingTypeLoc().getType();
}

return typeDecl->getDeclaredInterfaceType();
}

static Type substituteConcreteType(GenericSignatureBuilder &builder,
PotentialArchetype *basePA,
TypeDecl *concreteDecl) {
assert(concreteDecl);

auto *proto = concreteDecl->getDeclContext()->getSelfProtocolDecl();

if (!concreteDecl->hasInterfaceType())
builder.getLazyResolver()->resolveDeclSignature(concreteDecl);

if (!concreteDecl->hasInterfaceType())
// Form an unsubstituted type referring to the given type declaration,
// for use in an inferred same-type requirement.
auto type = getStructuralType(concreteDecl, builder.getLazyResolver());
if (!type)
return Type();

// The protocol concrete type has an underlying type written in terms
// of the protocol's 'Self' type.
auto typealias = dyn_cast<TypeAliasDecl>(concreteDecl);
auto type = typealias ? typealias->getUnderlyingTypeLoc().getType()
: concreteDecl->getDeclaredInterfaceType();

Type parentType;
SubstitutionMap subMap;
if (proto) {
Expand All @@ -3855,7 +3854,7 @@ static Type substituteConcreteType(GenericSignatureBuilder &builder,
}

// If we had a typealias, form a sugared type.
if (typealias) {
if (auto *typealias = dyn_cast<TypeAliasDecl>(concreteDecl)) {
type = TypeAliasType::get(typealias, parentType, subMap, type);
}

Expand Down Expand Up @@ -4226,34 +4225,13 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
return result;
};

// Form an unsubstituted type referring to the given type declaration,
// for use in an inferred same-type requirement.
auto formUnsubstitutedType = [&](TypeDecl *typeDecl) -> Type {
if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
return DependentMemberType::get(
assocType->getProtocol()->getSelfInterfaceType(),
assocType);
}

// Resolve the underlying type, if we haven't done so yet.
if (!typeDecl->hasInterfaceType()) {
getLazyResolver()->resolveDeclSignature(typeDecl);
}

if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
return typealias->getUnderlyingTypeLoc().getType();
}

return typeDecl->getDeclaredInterfaceType();
};

// An inferred same-type requirement between the two type declarations
// within this protocol or a protocol it inherits.
auto addInferredSameTypeReq = [&](TypeDecl *first, TypeDecl *second) {
Type firstType = formUnsubstitutedType(first);
Type firstType = getStructuralType(first, getLazyResolver());
if (!firstType) return;

Type secondType = formUnsubstitutedType(second);
Type secondType = getStructuralType(second, getLazyResolver());
if (!secondType) return;

auto inferredSameTypeSource =
Expand Down Expand Up @@ -5170,11 +5148,6 @@ ConstraintResult GenericSignatureBuilder::addInheritedRequirements(
UnresolvedType type,
const RequirementSource *parentSource,
ModuleDecl *inferForModule) {
if (isa<AssociatedTypeDecl>(decl) &&
decl->hasInterfaceType() &&
decl->getInterfaceType()->is<ErrorType>())
return ConstraintResult::Resolved;

// Local function to get the source.
auto getFloatingSource = [&](const TypeRepr *typeRepr, bool forInferred) {
if (parentSource) {
Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/GenCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ FailableCastResult irgen::emitClassIdenticalCast(IRGenFunction &IGF,
llvm::Value *targetMetadata;
if ((targetMetadata =
tryEmitConstantHeapMetadataRef(IGF.IGM, toType.getASTType(),
/*allowUninitialized*/ false,
/*allowStub*/ false))) {
/*allowUninitialized*/ false))) {
// ok
} else {
targetMetadata
Expand Down
40 changes: 27 additions & 13 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,32 @@ namespace {
if (categoryCount > 0)
os << categoryCount;
}


llvm::Constant *getClassMetadataRef() {
auto *theClass = getClass();

if (theClass->hasClangNode())
return IGM.getAddrOfObjCClass(theClass, NotForDefinition);

// Note that getClassMetadataStrategy() will return
// ClassMetadataStrategy::Resilient if the class is
// from another resilience domain, even if inside that
// resilience domain the class has fixed metadata
// layout.
//
// Since a class only has a class stub if its class
// hierarchy crosses resilience domains, we use a
// slightly different query here.
if (theClass->checkAncestry(AncestryFlags::ResilientOther)) {
assert(IGM.Context.LangOpts.EnableObjCResilientClassStubs);
return IGM.getAddrOfObjCResilientClassStub(theClass, NotForDefinition,
TypeMetadataAddress::AddressPoint);
}

auto type = getSelfType(theClass).getASTType();
return tryEmitConstantHeapMetadataRef(IGM, type, /*allowUninit*/ true);
}

public:
llvm::Constant *emitCategory() {
assert(TheExtension && "can't emit category data for a class");
Expand All @@ -1205,18 +1230,7 @@ namespace {
// char const *name;
fields.add(IGM.getAddrOfGlobalString(CategoryName));
// const class_t *theClass;
if (getClass()->hasClangNode())
fields.add(IGM.getAddrOfObjCClass(getClass(), NotForDefinition));
else {
auto type = getSelfType(getClass()).getASTType();
llvm::Constant *metadata =
tryEmitConstantHeapMetadataRef(IGM, type,
/*allowUninit*/ true,
/*allowStub*/ true);
assert(metadata &&
"extended objc class doesn't have constant metadata?");
fields.add(metadata);
}
fields.add(getClassMetadataRef());
// const method_list_t *instanceMethods;
fields.add(buildInstanceMethodList());
// const method_list_t *classMethods;
Expand Down
16 changes: 15 additions & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,12 @@ void IRGenModule::emitGlobalLists() {
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// And categories on class stubs.
emitGlobalList(*this, ObjCCategoriesOnStubs, "objc_categories_stubs",
GetObjCSectionName("__objc_catlist2",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// Emit nonlazily realized class references in a second magic section to make
// sure they are realized by the Objective-C runtime before any instances
// are allocated.
Expand Down Expand Up @@ -3802,7 +3808,15 @@ void IRGenModule::emitExtension(ExtensionDecl *ext) {
"foreign types cannot have categories emitted");
llvm::Constant *category = emitCategoryData(*this, ext);
category = llvm::ConstantExpr::getBitCast(category, Int8PtrTy);
ObjCCategories.push_back(category);

auto *theClass = ext->getSelfClassDecl();

// Categories on class stubs are added to a separate list.
if (theClass->checkAncestry(AncestryFlags::ResilientOther))
ObjCCategoriesOnStubs.push_back(category);
else
ObjCCategories.push_back(category);

ObjCCategoryDecls.push_back(ext);
}
}
Expand Down
24 changes: 16 additions & 8 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,7 @@ namespace {
super::layout();
addVTable();
addOverrideTable();
addObjCResilientClassStubInfo();
}

void addIncompleteMetadataOrRelocationFunction() {
Expand Down Expand Up @@ -1632,6 +1633,20 @@ namespace {
// uint32_t FieldOffsetVectorOffset;
B.addInt32(getFieldVectorOffset() / IGM.getPointerSize());
}

void addObjCResilientClassStubInfo() {
if (IGM.getClassMetadataStrategy(getType()) !=
ClassMetadataStrategy::Resilient)
return;

if (!hasObjCResilientClassStub(IGM, getType()))
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is the first condition not part of what the second function checks? I could see if this is a definition-vs-use situation, but we're always at the definition site here, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For some reason I factored it so that hasObjCResilientClassStub() asserts the first condition here. I guess it makes sense to change it around.


B.addRelativeAddress(
IGM.getAddrOfObjCResilientClassStub(
getType(), NotForDefinition,
TypeMetadataAddress::AddressPoint));
}
};

class OpaqueTypeDescriptorBuilder
Expand Down Expand Up @@ -2634,8 +2649,7 @@ namespace {
Type type = Target->mapTypeIntoContext(Target->getSuperclass());
auto *metadata = tryEmitConstantHeapMetadataRef(
IGM, type->getCanonicalType(),
/*allowUninit*/ false,
/*allowStub*/ false);
/*allowUninit*/ false);
assert(metadata != nullptr);
B.add(metadata);
}
Expand Down Expand Up @@ -3231,12 +3245,6 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
classDecl, NotForDefinition,
TypeMetadataAddress::AddressPoint);
emitObjCClassSymbol(IGM, classDecl, stub);

// @_objc_non_lazy_realization is only for use by the standard
// library, and we cannot support it with Objective-C class
// stubs (which there are none of in the standard library).
assert(!classDecl->getAttrs().hasAttribute<ObjCNonLazyRealizationAttr>());
IGM.addObjCClass(stub, /*eagerInitialization=*/false);
}
}
break;
Expand Down
2 changes: 2 additions & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,8 @@ class IRGenModule {
SmallVector<llvm::WeakTrackingVH, 4> ObjCNonLazyClasses;
/// List of Objective-C categories, bitcast to i8*.
SmallVector<llvm::WeakTrackingVH, 4> ObjCCategories;
/// List of Objective-C categories on class stubs, bitcast to i8*.
SmallVector<llvm::WeakTrackingVH, 4> ObjCCategoriesOnStubs;
/// List of non-ObjC protocols described by this module.
SmallVector<ProtocolDecl *, 4> SwiftProtocols;
/// List of protocol conformances to generate descriptors for.
Expand Down
9 changes: 1 addition & 8 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,19 +517,12 @@ irgen::getRuntimeReifiedType(IRGenModule &IGM, CanType type) {
llvm::Constant *
irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
CanType type,
bool allowDynamicUninitialized,
bool allowStub) {
bool allowDynamicUninitialized) {
auto theDecl = type->getClassOrBoundGenericClass();
assert(theDecl && "emitting constant heap metadata ref for non-class type?");

switch (IGM.getClassMetadataStrategy(theDecl)) {
case ClassMetadataStrategy::Resilient:
if (allowStub && IGM.Context.LangOpts.EnableObjCResilientClassStubs) {
return IGM.getAddrOfObjCResilientClassStub(theDecl, NotForDefinition,
TypeMetadataAddress::AddressPoint);
}
return nullptr;

case ClassMetadataStrategy::Singleton:
if (!allowDynamicUninitialized)
return nullptr;
Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/MetadataRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,7 @@ CanType getRuntimeReifiedType(IRGenModule &IGM, CanType type);
/// by a constant.
llvm::Constant *tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
CanType type,
bool allowUninitialized,
bool allowStub);
bool allowUninitialized);

enum class MetadataValueType { ObjCClass, TypeMetadata };

Expand Down
29 changes: 21 additions & 8 deletions test/IRGen/class_update_callback_with_stub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -I %t %S/../Inputs/resilient_struct.swift
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-module-path %t/resilient_class.swiftmodule -enable-library-evolution %S/../Inputs/resilient_class.swift
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-module-path %t/resilient_objc_class.swiftmodule -enable-library-evolution %S/../Inputs/resilient_objc_class.swift
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -I %t -emit-ir -enable-library-evolution -enable-resilient-objc-class-stubs %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime -DINT=i%target-ptrsize
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -I %t -emit-ir -enable-library-evolution -enable-resilient-objc-class-stubs %s > %t/out
// RUN: %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime -DINT=i%target-ptrsize < %t/out
// RUN: %FileCheck %s --check-prefix=NEGATIVE < %t/out

import Foundation
import resilient_class
Expand Down Expand Up @@ -49,6 +51,8 @@ import resilient_objc_class
// CHECK-SAME: @"got.$s15resilient_class22ResilientOutsideParentCMn"
// CHECK-SAME: @"got.$s15resilient_class22ResilientOutsideParentCACycfCTq"
// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCACycfC"
// -- class stub
// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMt"
// CHECK-SAME: }>, section "__TEXT,__const", align 4


Expand Down Expand Up @@ -87,22 +91,27 @@ import resilient_objc_class
// CHECK-LABEL: @"_CATEGORY__TtC31class_update_callback_with_stub27FixedLayoutNSObjectSubclass_$_class_update_callback_with_stub" = private constant
// CHECK-SAME: @"$s31class_update_callback_with_stub27FixedLayoutNSObjectSubclassCMs"

// -- But not if the entire inheritance chain is in a single module

// -- The NSObject-derived class appears on the class list
// CHECK-LABEL: @"_CATEGORY__TtC15resilient_class22ResilientOutsideParent_$_class_update_callback_with_stub" = private constant
// CHECK-SAME: @"$s15resilient_class22ResilientOutsideParentCN"

// CHECK-LABEL: @objc_classes = internal global
// CHECK-SAME: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs"
// CHECK-SAME: @"$s31class_update_callback_with_stub27FixedLayoutNSObjectSubclassCMs"
// CHECK-SAME: , section "__DATA,__objc_classlist,regular,no_dead_strip"

// -- Class stubs do not appear in the class list

// NEGATIVE-NOT: @objc_classes =

// -- The category list

// CHECK-LABEL: @objc_categories = internal global
// CHECK-SAME: @"_CATEGORY__TtC15resilient_class22ResilientOutsideParent_$_class_update_callback_with_stub"
// CHECK-SAME: , section "__DATA,__objc_catlist,regular,no_dead_strip"

// CHECK-LABEL: @objc_categories_stubs = internal global
// CHECK-SAME: @"_CATEGORY__TtC31class_update_callback_with_stub17ResilientSubclass_$_class_update_callback_with_stub"
// CHECK-SAME: @"_CATEGORY__TtC31class_update_callback_with_stub25ResilientNSObjectSubclass_$_class_update_callback_with_stub"
// CHECK-SAME: @"_CATEGORY__TtC31class_update_callback_with_stub27FixedLayoutNSObjectSubclass_$_class_update_callback_with_stub"
// CHECK-SAME: , section "__DATA,__objc_catlist,regular,no_dead_strip"
// CHECK-SAME: , section "__DATA,__objc_catlist2,regular,no_dead_strip"


// -- Address point for class stubs
Expand Down Expand Up @@ -152,4 +161,8 @@ extension ResilientNSObjectSubclass {

extension FixedLayoutNSObjectSubclass {
@objc public func objcMethod() {}
}
}

extension ResilientOutsideParent {
@objc public func anObjcMethod() {}
}
2 changes: 1 addition & 1 deletion test/Interpreter/SDK/objc_getClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import resilient_objc_class
// Old OS versions do not have this hook.
let getClassHookMissing = {
nil == dlsym(UnsafeMutableRawPointer(bitPattern: -2),
"objc_setHook_getClass")
"objc_setHook_getClass")
}()

var testSuite = TestSuite("objc_getClass")
Expand Down
1 change: 0 additions & 1 deletion test/Interpreter/class_resilience.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
// RUN: %target-run %t/main2 %t/%target-library-name(resilient_struct_wmo) %t/%target-library-name(resilient_class_wmo) %t/%target-library-name(fixed_layout_class_wmo)

// REQUIRES: executable_test
// REQUIRES: rdar49026933

import StdlibUnittest

Expand Down
Loading