Skip to content

[6.0] IRGen: Properly adjust the closure type of a partial_apply of an objc_method #73850

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
14 changes: 14 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6536,6 +6536,20 @@ void IRGenSILFunction::visitEndUnpairedAccessInst(EndUnpairedAccessInst *i) {
}

void IRGenSILFunction::visitConvertFunctionInst(swift::ConvertFunctionInst *i) {
auto &lv = getLoweredValue(i->getOperand());
if (lv.kind == LoweredValue::Kind::ObjCMethod) {
// LoadableByAddress lowering will insert convert_function instructions to
// change the type of a partial_apply instruction involving a objc_method
// convention, to change the partial_apply's SIL type (rewriting large types
// to @in_guaranteed/@out). This is important for pointer authentication.

// The convert_function instruction will carry the desired SIL type.
// Here we just forward the objective-c method.
auto &objcMethod = lv.getObjCMethod();
setLoweredObjCMethod(i, objcMethod.getMethod());
return;
}

// This instruction is specified to be a no-op.
Explosion temp = getLoweredExplosion(i->getOperand());

Expand Down
38 changes: 28 additions & 10 deletions lib/IRGen/LoadableByAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ class LargeSILTypeMapper {
irgen::IRGenModule &IGM);
SmallVector<SILResultInfo, 2> getNewResults(GenericEnvironment *GenericEnv,
CanSILFunctionType fnType,
irgen::IRGenModule &Mod);
irgen::IRGenModule &Mod,
bool mustTransform = false);
CanSILFunctionType getNewSILFunctionType(GenericEnvironment *env,
CanSILFunctionType fnType,
irgen::IRGenModule &IGM);
irgen::IRGenModule &IGM,
bool mustTransform = false);
SILType getNewOptionalFunctionType(GenericEnvironment *GenericEnv,
SILType storageType,
irgen::IRGenModule &Mod);
Expand Down Expand Up @@ -240,8 +242,9 @@ bool LargeSILTypeMapper::newResultsDiffer(GenericEnvironment *GenericEnv,

static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
CanSILFunctionType loweredTy,
irgen::IRGenModule &Mod) {
if (!modifiableFunction(loweredTy)) {
irgen::IRGenModule &Mod,
bool mustTransform = false) {
if (!modifiableFunction(loweredTy) && !mustTransform) {
return false;
}
if (loweredTy->getNumResults() != 1) {
Expand All @@ -258,7 +261,8 @@ static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
SmallVector<SILResultInfo, 2>
LargeSILTypeMapper::getNewResults(GenericEnvironment *GenericEnv,
CanSILFunctionType fnType,
irgen::IRGenModule &Mod) {
irgen::IRGenModule &Mod,
bool mustTransform) {
// Get new SIL Function results - same as old results UNLESS:
// 1) Function type results might have a different signature
// 2) Large loadables are replaced by @out version
Expand All @@ -267,7 +271,7 @@ LargeSILTypeMapper::getNewResults(GenericEnvironment *GenericEnv,
for (auto result : origResults) {
SILType currResultTy = result.getSILStorageInterfaceType();
SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod);
if (modNonFuncTypeResultType(GenericEnv, fnType, Mod)) {
if (modNonFuncTypeResultType(GenericEnv, fnType, Mod, mustTransform)) {
// Case (2) Above
SILResultInfo newSILResultInfo(newSILType.getASTType(),
ResultConvention::Indirect);
Expand All @@ -287,8 +291,9 @@ LargeSILTypeMapper::getNewResults(GenericEnvironment *GenericEnv,
CanSILFunctionType
LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env,
CanSILFunctionType fnType,
irgen::IRGenModule &IGM) {
if (!modifiableFunction(fnType)) {
irgen::IRGenModule &IGM,
bool mustTransform) {
if (!modifiableFunction(fnType) && !mustTransform) {
return fnType;
}

Expand All @@ -300,7 +305,7 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env,

auto newParams = getNewParameters(env, fnType, IGM);
auto newYields = getNewYields(env, fnType, IGM);
auto newResults = getNewResults(env, fnType, IGM);
auto newResults = getNewResults(env, fnType, IGM, mustTransform);
auto newFnType = SILFunctionType::get(
fnType->getInvocationGenericSignature(),
fnType->getExtInfo(),
Expand Down Expand Up @@ -2621,7 +2626,20 @@ void LoadableByAddress::recreateSingleApply(
// Change the type of the Closure
auto partialApplyConvention = castedApply->getCalleeConvention();
auto resultIsolation = castedApply->getResultIsolation();

// We do need to update the closure's funtion type to match with the other
// uses inside of the binary. Pointer auth cares about the SIL function
// type.
if (callee->getType().castTo<SILFunctionType>()->getExtInfo().getRepresentation() ==
SILFunctionTypeRepresentation::ObjCMethod) {
CanSILFunctionType newFnType =
MapperCache.getNewSILFunctionType(
genEnv,
callee->getType().castTo<SILFunctionType>(), *currIRMod,
/*mustTransform*/ true);
SILType newType = SILType::getPrimitiveObjectType(newFnType);
callee = applyBuilder.createConvertFunction(castedApply->getLoc(),
callee, newType, false);
}
auto newApply = applyBuilder.createPartialApply(
castedApply->getLoc(), callee, applySite.getSubstitutionMap(), callArgs,
partialApplyConvention, resultIsolation, castedApply->isOnStack());
Expand Down
1 change: 1 addition & 0 deletions test/IRGen/Inputs/large_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct SamplesType {
void* AA;
};

struct SamplesType samples();

typedef struct _ContainedType {
unsigned int f1;
Expand Down
17 changes: 11 additions & 6 deletions test/IRGen/big_types_corner_cases.sil
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=simplification -I %S/Inputs/abi %s -emit-ir | %FileCheck %s
// RUN: %target-swift-frontend -sil-verify-none -Xllvm -sil-disable-pass=simplification -I %S/Inputs/abi %s -emit-ir | %FileCheck %s

// REQUIRES: CPU=x86_64
// REQUIRES: OS=macosx

sil_stage canonical
sil_stage lowered

import c_layout
import Builtin
import Swift
Expand Down Expand Up @@ -307,13 +308,17 @@ bb0(%0 : $AnyObject):
dynamic_method_br %2 : $@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self, #X.foo!foreign, bb1, bb2

bb1(%6 : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> BitfieldOne): // Preds: bb0
%addr = alloc_stack $BitfieldOne
strong_retain %2 : $@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self
%8 = partial_apply [callee_guaranteed] %6(%2) : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> BitfieldOne
%9 = apply %8() : $@callee_guaranteed () -> BitfieldOne
%cvt = convert_function %6 : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> BitfieldOne to $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> @out BitfieldOne
%8 = partial_apply [callee_guaranteed] %cvt(%2) : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> @out BitfieldOne
%9 = apply %8(%addr) : $@callee_guaranteed () -> @out BitfieldOne
%10 = init_enum_data_addr %4 : $*Optional<BitfieldOne>, #Optional.some!enumelt
store %9 to %10 : $*BitfieldOne
%val = load %addr : $*BitfieldOne
store %val to %10 : $*BitfieldOne
inject_enum_addr %4 : $*Optional<BitfieldOne>, #Optional.some!enumelt
strong_release %8 : $@callee_guaranteed () -> BitfieldOne
strong_release %8 : $@callee_guaranteed () -> @out BitfieldOne
dealloc_stack %addr : $*BitfieldOne
br bb3

bb2: // Preds: bb0
Expand Down
29 changes: 29 additions & 0 deletions test/IRGen/loadable_by_address_objc_method.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %target-swift-frontend -I %t -emit-ir %s -import-objc-header %S/Inputs/large_c.h | %FileCheck %s
// RUN: %target-swift-frontend -I %t -emit-ir %s -import-objc-header %S/Inputs/large_c.h -Xllvm -sil-print-after=loadable-address 2>&1 | %FileCheck %s --check-prefix=SIL

// REQUIRES: OS=ios && CPU=arm64e

import Foundation

@objc protocol P { @objc optional func testFunction(_ i: SamplesType) -> SamplesType }

class C: P { func testFunction(_ i: SamplesType) -> SamplesType { samples() } }

func test() {
_ = (C() as P).testFunction?(samples())
}

// Make sure the ptrauth discriminator at closure build and invocation time match.

// CHECK: @"$sTa.ptrauth" = private constant {{.*}} ptr @"$sTa"{{.*}} i64 55683 }, section "llvm.ptrauth"
// CHECK: define hidden swiftcc void @"$s31loadable_by_address_objc_method4testyyF"()
// CHECK: store {{.*}} @"$sTa.ptrauth"
// CHECK: call swiftcc void {{.*}}(ptr {{.*}}sret(%TSo11SamplesTypeV) {{.*}} [ "ptrauth"(i32 0, i64 55683) ]
// CHECK: }

test()


// SIL: sil hidden @$s31loadable_by_address_objc_method4testyyF : $@convention(thin) () -> () {
// SIL: [[C:%.*]] = convert_function {{.*}} : $@convention(objc_method) (SamplesType, @opened({{.*}}, any P) Self) -> SamplesType to $@convention(objc_method) (@in_guaranteed SamplesType, @opened({{.*}}, any P) Self) -> @out SamplesType
// SIL: partial_apply [callee_guaranteed] [[C]]({{.*}}) : $@convention(objc_method) (@in_guaranteed SamplesType, @opened({{.*}}, any P) Self) -> @out SamplesType