mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is to support dynamic function replacement of functions with opaque result type. This approach requires that all state is thrown away (that could contain the old returned type for an opaque type) between replacements. rdar://48887938
200 lines
7.7 KiB
C++
200 lines
7.7 KiB
C++
//===--- SILFunctionBuilder.cpp -------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/SIL/SILFunctionBuilder.h"
|
|
#include "swift/AST/Availability.h"
|
|
#include "swift/AST/Decl.h"
|
|
using namespace swift;
|
|
|
|
SILFunction *SILFunctionBuilder::getOrCreateFunction(
|
|
SILLocation loc, StringRef name, SILLinkage linkage,
|
|
CanSILFunctionType type, IsBare_t isBareSILFunction,
|
|
IsTransparent_t isTransparent, IsSerialized_t isSerialized,
|
|
IsDynamicallyReplaceable_t isDynamic, ProfileCounter entryCount,
|
|
IsThunk_t isThunk, SubclassScope subclassScope) {
|
|
assert(!type->isNoEscape() && "Function decls always have escaping types.");
|
|
if (auto fn = mod.lookUpFunction(name)) {
|
|
assert(fn->getLoweredFunctionType() == type);
|
|
assert(stripExternalFromLinkage(fn->getLinkage()) ==
|
|
stripExternalFromLinkage(linkage));
|
|
return fn;
|
|
}
|
|
|
|
auto fn = SILFunction::create(mod, linkage, name, type, nullptr, loc,
|
|
isBareSILFunction, isTransparent, isSerialized,
|
|
entryCount, isDynamic, isThunk, subclassScope);
|
|
fn->setDebugScope(new (mod) SILDebugScope(loc, fn));
|
|
return fn;
|
|
}
|
|
|
|
void SILFunctionBuilder::addFunctionAttributes(SILFunction *F,
|
|
DeclAttributes &Attrs,
|
|
SILModule &M,
|
|
SILDeclRef constant) {
|
|
|
|
for (auto *A : Attrs.getAttributes<SemanticsAttr>())
|
|
F->addSemanticsAttr(cast<SemanticsAttr>(A)->Value);
|
|
|
|
// Propagate @_specialize.
|
|
for (auto *A : Attrs.getAttributes<SpecializeAttr>()) {
|
|
auto *SA = cast<SpecializeAttr>(A);
|
|
auto kind =
|
|
SA->getSpecializationKind() == SpecializeAttr::SpecializationKind::Full
|
|
? SILSpecializeAttr::SpecializationKind::Full
|
|
: SILSpecializeAttr::SpecializationKind::Partial;
|
|
F->addSpecializeAttr(SILSpecializeAttr::create(M, SA->getRequirements(),
|
|
SA->isExported(), kind));
|
|
}
|
|
|
|
if (auto *OA = Attrs.getAttribute<OptimizeAttr>()) {
|
|
F->setOptimizationMode(OA->getMode());
|
|
}
|
|
|
|
// @_silgen_name and @_cdecl functions may be called from C code somewhere.
|
|
if (Attrs.hasAttribute<SILGenNameAttr>() || Attrs.hasAttribute<CDeclAttr>())
|
|
F->setHasCReferences(true);
|
|
|
|
// Propagate @_dynamicReplacement(for:).
|
|
if (constant.isNull())
|
|
return;
|
|
auto *decl = constant.getDecl();
|
|
|
|
// Only emit replacements for the objc entry point of objc methods.
|
|
if (decl->isObjC() &&
|
|
F->getLoweredFunctionType()->getExtInfo().getRepresentation() !=
|
|
SILFunctionTypeRepresentation::ObjCMethod)
|
|
return;
|
|
|
|
auto *replacedFuncAttr = Attrs.getAttribute<DynamicReplacementAttr>();
|
|
if (!replacedFuncAttr)
|
|
return;
|
|
|
|
auto *replacedDecl = replacedFuncAttr->getReplacedFunction();
|
|
assert(replacedDecl);
|
|
|
|
if (decl->isObjC()) {
|
|
F->setObjCReplacement(replacedDecl);
|
|
return;
|
|
}
|
|
|
|
if (!constant.canBeDynamicReplacement())
|
|
return;
|
|
|
|
SILDeclRef declRef(replacedDecl, constant.kind, false);
|
|
auto *replacedFunc =
|
|
getOrCreateFunction(replacedDecl, declRef, NotForDefinition);
|
|
|
|
assert(replacedFunc->getLoweredFunctionType() ==
|
|
F->getLoweredFunctionType() ||
|
|
replacedFunc->getLoweredFunctionType()->hasOpaqueArchetype());
|
|
|
|
F->setDynamicallyReplacedFunction(replacedFunc);
|
|
}
|
|
|
|
SILFunction *
|
|
SILFunctionBuilder::getOrCreateFunction(SILLocation loc, SILDeclRef constant,
|
|
ForDefinition_t forDefinition,
|
|
ProfileCounter entryCount) {
|
|
auto nameTmp = constant.mangle();
|
|
auto constantType = mod.Types.getConstantFunctionType(constant);
|
|
SILLinkage linkage = constant.getLinkage(forDefinition);
|
|
|
|
if (auto fn = mod.lookUpFunction(nameTmp)) {
|
|
assert(fn->getLoweredFunctionType() == constantType);
|
|
assert(fn->getLinkage() == linkage ||
|
|
(forDefinition == ForDefinition_t::NotForDefinition &&
|
|
fn->getLinkage() ==
|
|
constant.getLinkage(ForDefinition_t::ForDefinition)));
|
|
if (forDefinition) {
|
|
// In all the cases where getConstantLinkage returns something
|
|
// different for ForDefinition, it returns an available-externally
|
|
// linkage.
|
|
if (isAvailableExternally(fn->getLinkage())) {
|
|
fn->setLinkage(constant.getLinkage(ForDefinition));
|
|
}
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
IsTransparent_t IsTrans =
|
|
constant.isTransparent() ? IsTransparent : IsNotTransparent;
|
|
IsSerialized_t IsSer = constant.isSerialized();
|
|
|
|
EffectsKind EK = constant.hasEffectsAttribute()
|
|
? constant.getEffectsAttribute()
|
|
: EffectsKind::Unspecified;
|
|
|
|
Inline_t inlineStrategy = InlineDefault;
|
|
if (constant.isNoinline())
|
|
inlineStrategy = NoInline;
|
|
else if (constant.isAlwaysInline())
|
|
inlineStrategy = AlwaysInline;
|
|
|
|
StringRef name = mod.allocateCopy(nameTmp);
|
|
IsDynamicallyReplaceable_t IsDyn = IsNotDynamic;
|
|
if (constant.isDynamicallyReplaceable()) {
|
|
IsDyn = IsDynamic;
|
|
IsTrans = IsNotTransparent;
|
|
}
|
|
|
|
auto *F = SILFunction::create(mod, linkage, name, constantType, nullptr, None,
|
|
IsNotBare, IsTrans, IsSer, entryCount, IsDyn,
|
|
IsNotThunk, constant.getSubclassScope(),
|
|
inlineStrategy, EK);
|
|
F->setDebugScope(new (mod) SILDebugScope(loc, F));
|
|
|
|
F->setGlobalInit(constant.isGlobal());
|
|
if (constant.hasDecl()) {
|
|
auto decl = constant.getDecl();
|
|
|
|
if (constant.isForeign && decl->hasClangNode())
|
|
F->setClangNodeOwner(decl);
|
|
|
|
if (decl->isWeakImported(/*forModule=*/nullptr, availCtx))
|
|
F->setWeakLinked();
|
|
|
|
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
|
|
auto *storage = accessor->getStorage();
|
|
// Add attributes for e.g. computed properties.
|
|
addFunctionAttributes(F, storage->getAttrs(), mod);
|
|
}
|
|
addFunctionAttributes(F, decl->getAttrs(), mod, constant);
|
|
}
|
|
|
|
return F;
|
|
}
|
|
|
|
SILFunction *SILFunctionBuilder::getOrCreateSharedFunction(
|
|
SILLocation loc, StringRef name, CanSILFunctionType type,
|
|
IsBare_t isBareSILFunction, IsTransparent_t isTransparent,
|
|
IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk,
|
|
IsDynamicallyReplaceable_t isDynamic) {
|
|
return getOrCreateFunction(loc, name, SILLinkage::Shared, type,
|
|
isBareSILFunction, isTransparent, isSerialized,
|
|
isDynamic, entryCount, isThunk,
|
|
SubclassScope::NotApplicable);
|
|
}
|
|
|
|
SILFunction *SILFunctionBuilder::createFunction(
|
|
SILLinkage linkage, StringRef name, CanSILFunctionType loweredType,
|
|
GenericEnvironment *genericEnv, Optional<SILLocation> loc,
|
|
IsBare_t isBareSILFunction, IsTransparent_t isTrans,
|
|
IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic,
|
|
ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope subclassScope,
|
|
Inline_t inlineStrategy, EffectsKind EK, SILFunction *InsertBefore,
|
|
const SILDebugScope *DebugScope) {
|
|
return SILFunction::create(mod, linkage, name, loweredType, genericEnv, loc,
|
|
isBareSILFunction, isTrans, isSerialized,
|
|
entryCount, isDynamic, isThunk, subclassScope,
|
|
inlineStrategy, EK, InsertBefore, DebugScope);
|
|
}
|