mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[serialized_for_package] if Package CMO is enabled. The latter kind allows a function to be serialized even if it contains loadable types, if Package CMO is enabled. Renamed IsSerialized_t as SerializedKind_t. The tri-state serialization kind requires validating inlinability depending on the serialization kinds of callee vs caller; e.g. if the callee is [serialized_for_package], the caller must be _not_ [serialized]. Renamed `hasValidLinkageForFragileInline` as `canBeInlinedIntoCaller` that takes in its caller's SerializedKind as an argument. Another argument `assumeFragileCaller` is also added to ensure that the calle sites of this function know the caller is serialized unless it's called for SIL inlining optimization passes. The [serialized_for_package] attribute is allowed for SIL function, global var, v-table, and witness-table. Resolves rdar://128406520
427 lines
15 KiB
C++
427 lines
15 KiB
C++
//===--- SILLinkage.h - Defines the SILLinkage type -------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_SILLINKAGE_H
|
|
#define SWIFT_SIL_SILLINKAGE_H
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
// FIXME: Remove after fixmeWitnessHasLinkageThatNeedsToBePublic is removed.
|
|
#include "swift/SIL/SILDeclRef.h"
|
|
|
|
namespace swift {
|
|
|
|
class ValueDecl;
|
|
|
|
/// Linkage for a SIL object. This concept combines the notions
|
|
/// of symbol linkage and visibility.
|
|
///
|
|
/// Note that a Swift module is not the same thing as a SILModule.
|
|
/// A SILModule is just a collection of objects.
|
|
///
|
|
/// Semantic equivalence does not imply exact operational equivalence.
|
|
/// For example, a function definition might be semantically
|
|
/// equivalent to a second definition which uses a parameter that the
|
|
/// first does not, perhaps by reading a value out of it (and then
|
|
/// ignoring the result) or retaining it (and then releasing it
|
|
/// later).
|
|
enum class SILLinkage : uint8_t {
|
|
/// This object definition is visible to multiple Swift modules (and
|
|
/// thus potentially across linkage-unit boundaries). There are no
|
|
/// other object definitions with this name in the program.
|
|
///
|
|
/// Public functions must be definitions, i.e. must have a body, except the
|
|
/// body is emitted by clang.
|
|
Public,
|
|
|
|
/// This is a special linkage used for symbols which are treated
|
|
/// as public for the purposes of SIL serialization and optimization,
|
|
/// but do not have public entry points in the generated binary.
|
|
///
|
|
/// This linkage is used for @_alwaysEmitIntoClient functions.
|
|
///
|
|
/// There is no external variant of this linkage, because from other
|
|
/// translation units in the same module, this behaves identically
|
|
/// to the HiddenExternal linkage.
|
|
///
|
|
/// When deserialized, such declarations receive Shared linkage.
|
|
///
|
|
/// PublicNonABI functions must be definitions.
|
|
PublicNonABI,
|
|
|
|
/// Same as \c Public, except the definition is visible within a package
|
|
/// of modules.
|
|
Package,
|
|
|
|
/// Similar to \c PublicNonABI, this definition is used for symbols treated
|
|
/// as package but do not have package entry points in the generated binary.
|
|
/// It's used for default argument expressions and `@_alwaysEmitIntoClient`.
|
|
/// When deserialized, this will become \c Shared linkage.
|
|
PackageNonABI,
|
|
|
|
/// This object definition is visible only to the current Swift
|
|
/// module (and thus should not be visible across linkage-unit
|
|
/// boundaries). There are no other object definitions with this
|
|
/// name in the module.
|
|
///
|
|
/// Hidden functions must be definitions, i.e. must have a body, except the
|
|
/// body is emitted by clang.
|
|
Hidden,
|
|
|
|
/// This object definition is visible only within a single Swift
|
|
/// module. There may be other object definitions with this name in
|
|
/// the module; those definitions are all guaranteed to be
|
|
/// semantically equivalent to this one.
|
|
///
|
|
/// This linkage is used e.g. for thunks and for specialized functions.
|
|
///
|
|
/// Shared functions must be definitions, i.e. must have a body, except the
|
|
/// body is emitted by clang.
|
|
Shared,
|
|
|
|
/// This object definition is visible only within a single Swift
|
|
/// file.
|
|
///
|
|
/// Private functions must be definitions, i.e. must have a body, except the
|
|
/// body is emitted by clang.
|
|
Private,
|
|
|
|
/// A Public definition with the same name as this object will be
|
|
/// available to the current Swift module at runtime. If this
|
|
/// object is a definition, it is semantically equivalent to that
|
|
/// definition.
|
|
PublicExternal,
|
|
|
|
/// Similar to \c PublicExternal.
|
|
/// Used to reference a \c Package definition in a different module
|
|
/// within a package.
|
|
PackageExternal,
|
|
|
|
/// A Public or Hidden definition with the same name as this object
|
|
/// will be defined by the current Swift module at runtime.
|
|
///
|
|
/// This linkage is only used for non-whole-module compilations to refer to
|
|
/// functions in other files of the same module.
|
|
HiddenExternal,
|
|
|
|
/// The default linkage for a definition.
|
|
DefaultForDefinition = Public,
|
|
|
|
/// The default linkage for an external declaration.
|
|
DefaultForDeclaration = PublicExternal,
|
|
};
|
|
|
|
enum {
|
|
/// The number of bits required to store a SILLinkage value.
|
|
NumSILLinkageBits = 4
|
|
};
|
|
|
|
/// Related to linkage: flag if a function, global variable, vtable or witness
|
|
/// table is serialized.
|
|
///
|
|
/// Used, e.g. for @inlinable functions.
|
|
///
|
|
/// This flag serves for two purposes:
|
|
/// * Imposes restrictions for optimizations. For example, non-serialized functions
|
|
/// cannot be inlined into serialized functions, because that could expose
|
|
/// internal types/functions to client modules.
|
|
/// * Tells the serializer which functions (and tables) need to be serialized:
|
|
/// - all public functions with the IsSerialized flag and
|
|
/// - all IsSerialized shared functions which are referenced from such functions.
|
|
///
|
|
/// After the swiftmodule file is written, the IsSerialized flag is cleared from
|
|
/// all functions. This means that optimizations after the serialization point
|
|
/// are not limited anymore regarding serialized functions.
|
|
enum SerializedKind_t : uint8_t {
|
|
|
|
/// The function is not inlinable and will not be serialized.
|
|
IsNotSerialized,
|
|
|
|
/// The function (or table) will be serialized.
|
|
///
|
|
/// This flag is only valid for Public, PublicNonABI, PublicExternal,
|
|
/// HiddenExternal and Shared functions.
|
|
/// Functions with external linkage (PublicExternal, HiddenExternal) will not
|
|
/// be serialized, because they are available in a different module (from
|
|
/// which they were de-serialized).
|
|
///
|
|
/// Functions with Shared linkage will only be serialized if they are
|
|
/// referenced from another serialized function (or table).
|
|
///
|
|
/// This flag is removed from all functions after the serialization point in
|
|
/// the optimizer pipeline.
|
|
IsSerialized,
|
|
|
|
/// This flag is valid for all linkages applicable to IsSerialized as well as
|
|
/// Package, PackageNonABI, and PackageExternal, if package-wide
|
|
/// serialization is enabled with Package-CMO optimization.
|
|
///
|
|
/// The [serialized_for_package] attribute is used to indicate that a function
|
|
/// is serialized because of Package CMO, which allows loadable types in a
|
|
/// serialized function in a resiliently built module, which is otherwise illegal.
|
|
/// It's also used to determine during SIL deserialization whether loadable
|
|
/// types in a serialized function can be allowed in the client module that
|
|
/// imports the module built with Package CMO. If the client contains a [serialized]
|
|
/// function due to `@inlinable`, funtions with [serialized_for_package] from
|
|
/// the imported module are not allowed being inlined into the client function,
|
|
/// which is the correct behavior.
|
|
IsSerializedForPackage
|
|
};
|
|
|
|
/// The scope in which a subclassable class can be subclassed.
|
|
enum class SubclassScope : uint8_t {
|
|
/// This class can be subclassed in other modules.
|
|
External,
|
|
|
|
/// This class can only be subclassed in this module.
|
|
Internal,
|
|
|
|
/// This class is resilient so even public methods cannot be directly
|
|
/// referenced from outside the module.
|
|
Resilient,
|
|
|
|
/// There is no class to subclass, or it is final.
|
|
NotApplicable,
|
|
};
|
|
|
|
/// Strip external from public_external, hidden_external. Otherwise just return
|
|
/// the linkage.
|
|
inline SILLinkage stripExternalFromLinkage(SILLinkage linkage) {
|
|
switch (linkage) {
|
|
case SILLinkage::PublicExternal:
|
|
return SILLinkage::Public;
|
|
case SILLinkage::PackageExternal:
|
|
return SILLinkage::Package;
|
|
case SILLinkage::HiddenExternal:
|
|
return SILLinkage::Hidden;
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageNonABI:
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::Shared:
|
|
case SILLinkage::Private:
|
|
return linkage;
|
|
}
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
/// Add the 'external' attribute to \p linkage.
|
|
inline SILLinkage addExternalToLinkage(SILLinkage linkage) {
|
|
switch (linkage) {
|
|
case SILLinkage::Public:
|
|
return SILLinkage::PublicExternal;
|
|
case SILLinkage::Package:
|
|
return SILLinkage::PackageExternal;
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::PackageNonABI:
|
|
// An external reference to a public or package non-ABI function is only valid
|
|
// if the function was emitted in another translation unit of the
|
|
// same Swift module, so we treat it as hidden here.
|
|
return SILLinkage::HiddenExternal;
|
|
case SILLinkage::Hidden:
|
|
return SILLinkage::HiddenExternal;
|
|
case SILLinkage::Shared:
|
|
case SILLinkage::Private:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::HiddenExternal:
|
|
return linkage;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
/// Return whether the linkage indicates that an object has a
|
|
/// definition outside the current SILModule.
|
|
inline bool isAvailableExternally(SILLinkage linkage) {
|
|
switch (linkage) {
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageNonABI:
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::Shared:
|
|
case SILLinkage::Private:
|
|
return false;
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::HiddenExternal:
|
|
return true;
|
|
}
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
/// Return whether the given linkage indicates that an object's
|
|
/// definition might be required outside the current SILModule.
|
|
/// If \p is true then we are in whole-module compilation.
|
|
inline bool isPossiblyUsedExternally(SILLinkage linkage, bool wholeModule) {
|
|
switch (linkage) {
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageNonABI:
|
|
return true;
|
|
case SILLinkage::Hidden:
|
|
return !wholeModule;
|
|
case SILLinkage::Shared:
|
|
case SILLinkage::Private:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::HiddenExternal:
|
|
return false;
|
|
}
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
SILLinkage getDeclSILLinkage(const ValueDecl *decl);
|
|
|
|
inline bool hasPublicVisibility(SILLinkage linkage) {
|
|
switch (linkage) {
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PublicNonABI:
|
|
return true;
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::PackageNonABI:
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::Shared:
|
|
case SILLinkage::Private:
|
|
case SILLinkage::HiddenExternal:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
/// Opt in package linkage for visibility in case Package CMO is enabled.
|
|
/// Used in SIL verification and other checks that determine inlinability to
|
|
/// accomodate for the optimization.
|
|
inline bool hasPublicOrPackageVisibility(SILLinkage linkage, bool includePackage) {
|
|
switch (linkage) {
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PublicNonABI:
|
|
return true;
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::PackageNonABI:
|
|
return includePackage;
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::Shared:
|
|
case SILLinkage::Private:
|
|
case SILLinkage::HiddenExternal:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
inline bool hasSharedVisibility(SILLinkage linkage) {
|
|
switch (linkage) {
|
|
case SILLinkage::Shared:
|
|
return true;
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::PackageNonABI:
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::HiddenExternal:
|
|
case SILLinkage::Private:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
inline bool hasPrivateVisibility(SILLinkage linkage) {
|
|
switch (linkage) {
|
|
case SILLinkage::Private:
|
|
return true;
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::PackageNonABI:
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::HiddenExternal:
|
|
case SILLinkage::Shared:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled SILLinkage in switch.");
|
|
}
|
|
|
|
inline SILLinkage effectiveLinkageForClassMember(SILLinkage linkage,
|
|
SubclassScope scope) {
|
|
switch (scope) {
|
|
case SubclassScope::External:
|
|
switch (linkage) {
|
|
case SILLinkage::Hidden:
|
|
case SILLinkage::Private:
|
|
return SILLinkage::Public;
|
|
case SILLinkage::HiddenExternal:
|
|
return SILLinkage::PublicExternal;
|
|
case SILLinkage::Public:
|
|
case SILLinkage::PublicNonABI:
|
|
case SILLinkage::Package:
|
|
case SILLinkage::PackageNonABI:
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PackageExternal:
|
|
case SILLinkage::Shared:
|
|
break;
|
|
}
|
|
break;
|
|
case SubclassScope::Internal:
|
|
if (linkage == SILLinkage::Private)
|
|
return SILLinkage::Hidden;
|
|
break;
|
|
|
|
case SubclassScope::Resilient:
|
|
if (isAvailableExternally(linkage))
|
|
return SILLinkage::HiddenExternal;
|
|
return SILLinkage::Hidden;
|
|
|
|
case SubclassScope::NotApplicable:
|
|
break;
|
|
}
|
|
return linkage;
|
|
}
|
|
|
|
// FIXME: This should not be necessary, but it looks like visibility rules for
|
|
// extension members are slightly bogus, and so some protocol witness thunks
|
|
// need to be public.
|
|
//
|
|
// We allow a 'public' member of an extension to witness a public
|
|
// protocol requirement, even if the extended type is not public;
|
|
// then SILGen gives the member private linkage, ignoring the more
|
|
// visible access level it was given in the AST.
|
|
//
|
|
// Despite the FIXME above, this is still used to determine the linkage
|
|
// for witness thunks. In case package serialization is enabled, we need
|
|
// to take the package linkage into account so we can set a proper final
|
|
// linkage to the thunks in the witness table with a package linkage.
|
|
inline bool fixmeWitnessHasLinkageThatNeedsToBePublic(SILDeclRef witness,
|
|
bool isPackageVisible) {
|
|
auto witnessLinkage = witness.getLinkage(ForDefinition);
|
|
return !hasPublicOrPackageVisibility(witnessLinkage, isPackageVisible) &&
|
|
(!hasSharedVisibility(witnessLinkage) || !witness.isSerialized());
|
|
}
|
|
|
|
} // end swift namespace
|
|
|
|
#endif
|