Skip to content

Commit 93c8784

Browse files
authored
Merge pull request #3475 from jckarter/id-as-any-silgen
Preliminary SILGen and runtime support for id-as-Any.
2 parents 86c97df + 02640fc commit 93c8784

File tree

7 files changed

+548
-103
lines changed

7 files changed

+548
-103
lines changed

include/swift/AST/KnownDecls.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ FUNC_DECL(ForceBridgeFromObjectiveCBridgeable,
6565
FUNC_DECL(ConditionallyBridgeFromObjectiveCBridgeable,
6666
"_conditionallyBridgeFromObjectiveC_bridgeable")
6767

68+
FUNC_DECL(BridgeAnythingToObjectiveC,
69+
"_bridgeAnythingToObjectiveC")
70+
6871
FUNC_DECL(DidEnterMain, "_stdlib_didEnterMain")
6972
FUNC_DECL(DiagnoseUnexpectedNilOptional, "_diagnoseUnexpectedNilOptional")
7073

lib/SILGen/SILGenBridging.cpp

Lines changed: 145 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ParameterList.h"
2121
#include "swift/Basic/Fallthrough.h"
2222
#include "swift/SIL/SILArgument.h"
23+
#include "swift/SIL/SILUndef.h"
2324
#include "swift/SIL/TypeLowering.h"
2425

2526
using namespace swift;
@@ -280,13 +281,26 @@ static void buildFuncToBlockInvokeBody(SILGenFunction &gen,
280281
funcParam.getType()));
281282
}
282283

284+
CanType resultType;
285+
SILValue indirectResult;
286+
287+
if (funcTy->getNumAllResults() == 0)
288+
resultType = TupleType::getEmpty(gen.SGM.getASTContext());
289+
else {
290+
auto result = funcTy->getSingleResult();
291+
resultType = result.getType();
292+
293+
auto &tl = gen.getTypeLowering(result.getSILType());
294+
if (tl.isAddressOnly()) {
295+
assert(result.getConvention() == ResultConvention::Indirect);
296+
assert(resultType->isAny() &&
297+
"Should not be trying to bridge anything except for Any here");
298+
}
299+
}
300+
283301
// Call the native function.
284-
assert(!funcTy->hasIndirectResults()
285-
&& "block thunking func with indirect result not supported");
286-
assert(funcTy->getNumDirectResults() <= 1
287-
&& "block thunking func with multiple results not supported");
288302
ManagedValue result = gen.emitMonomorphicApply(loc, fn, args,
289-
funcTy->getSILResult().getSwiftRValueType(),
303+
resultType,
290304
ApplyOptions::None,
291305
None, None)
292306
.getAsSingleValue(gen, loc);
@@ -437,16 +451,43 @@ static ManagedValue emitNativeToCBridgedNonoptionalValue(SILGenFunction &gen,
437451
return gen.emitNativeToBridgedError(loc, v, loweredBridgedTy);
438452
}
439453

440-
return v;
454+
// Fall back to dynamic Any-to-id bridging.
455+
// The destination type should be AnyObject in this case.
456+
//
457+
// TODO: Should only get here if -enable-id-as-any is active.
458+
assert(gen.getASTContext().LangOpts.EnableIdAsAny
459+
&& loweredBridgedTy->isEqual(
460+
gen.getASTContext().getProtocol(KnownProtocolKind::AnyObject)
461+
->getDeclaredType()));
462+
463+
// If the input argument is known to be an existential, save the runtime
464+
// some work by opening it.
465+
if (loweredNativeTy->isExistentialType()) {
466+
auto openedTy = ArchetypeType::getOpened(loweredNativeTy);
467+
468+
auto openedExistential = gen.emitOpenExistential(loc, v, openedTy,
469+
gen.getLoweredType(openedTy));
470+
v = openedExistential.Value;
471+
loweredNativeTy = openedTy;
472+
}
473+
474+
// Call into the stdlib intrinsic.
475+
if (auto bridgeAnything =
476+
gen.getASTContext().getBridgeAnythingToObjectiveC(nullptr)) {
477+
Substitution sub(loweredNativeTy, {});
478+
return gen.emitApplyOfLibraryIntrinsic(loc, bridgeAnything, sub, v,
479+
SGFContext())
480+
.getAsSingleValue(gen, loc);
481+
}
482+
483+
// Shouldn't get here unless the standard library is busted.
484+
return gen.emitUndef(loc, bridgedTy);
441485
}
442486

443487
static ManagedValue emitNativeToCBridgedValue(SILGenFunction &gen,
444488
SILLocation loc,
445489
ManagedValue v,
446490
SILType bridgedTy) {
447-
assert(v.getType().isLoadable(gen.F.getModule()) &&
448-
"Cannot bridge address-only types");
449-
450491
CanType loweredBridgedTy = bridgedTy.getSwiftRValueType();
451492
CanType loweredNativeTy = v.getType().getSwiftRValueType();
452493
if (loweredNativeTy == loweredBridgedTy)
@@ -472,9 +513,9 @@ static ManagedValue emitNativeToCBridgedValue(SILGenFunction &gen,
472513
}
473514

474515
ManagedValue SILGenFunction::emitNativeToBridgedValue(SILLocation loc,
475-
ManagedValue v,
476-
SILFunctionTypeRepresentation destRep,
477-
CanType loweredBridgedTy){
516+
ManagedValue v,
517+
SILFunctionTypeRepresentation destRep,
518+
CanType loweredBridgedTy){
478519
switch (getSILFunctionLanguage(destRep)) {
479520
case SILFunctionLanguage::Swift:
480521
// No additional bridging needed for native functions.
@@ -499,15 +540,29 @@ static void buildBlockToFuncThunkBody(SILGenFunction &gen,
499540

500541
SmallVector<ManagedValue, 4> args;
501542
SILBasicBlock *entry = &*gen.F.begin();
543+
544+
CanType resultType;
545+
SILValue indirectResult;
546+
547+
if (funcTy->getNumAllResults() == 0)
548+
resultType = TupleType::getEmpty(gen.SGM.getASTContext());
549+
else {
550+
auto result = funcTy->getSingleResult();
551+
resultType = result.getType();
552+
553+
auto &tl = gen.getTypeLowering(result.getSILType());
554+
if (tl.isAddressOnly()) {
555+
assert(result.getConvention() == ResultConvention::Indirect);
556+
557+
indirectResult = new (gen.SGM.M) SILArgument(entry, result.getSILType());
558+
}
559+
}
560+
502561
for (unsigned i : indices(funcTy->getParameters())) {
503562
auto &param = funcTy->getParameters()[i];
504563
auto &blockParam = blockTy->getParameters()[i];
505564

506565
auto &tl = gen.getTypeLowering(param.getSILType());
507-
assert((tl.isTrivial()
508-
? param.getConvention() == ParameterConvention::Direct_Unowned
509-
: param.getConvention() == ParameterConvention::Direct_Owned)
510-
&& "nonstandard conventions for native functions not implemented");
511566
SILValue v = new (gen.SGM.M) SILArgument(entry, param.getSILType());
512567
auto mv = gen.emitManagedRValueWithCleanup(v, tl);
513568
args.push_back(gen.emitNativeToBridgedValue(loc, mv,
@@ -522,26 +577,22 @@ static void buildBlockToFuncThunkBody(SILGenFunction &gen,
522577
ManagedValue block = gen.emitManagedRValueWithCleanup(blockV);
523578

524579
// Call the block.
525-
assert(!funcTy->hasIndirectResults()
526-
&& "block thunking func with indirect result not supported");
527580
ManagedValue result = gen.emitMonomorphicApply(loc, block, args,
528-
funcTy->getSILResult().getSwiftRValueType(),
529-
ApplyOptions::None,
530-
/*override CC*/ SILFunctionTypeRepresentation::Block,
531-
/*foreign error*/ None)
581+
resultType,
582+
ApplyOptions::None,
583+
/*override CC*/ SILFunctionTypeRepresentation::Block,
584+
/*foreign error*/ None)
532585
.getAsSingleValue(gen, loc);
533586

534587
// Return the result at +1.
535-
#ifndef NDEBUG
536-
for (auto result : funcTy->getDirectResults()) {
537-
assert((gen.getTypeLowering(result.getSILType()).isTrivial()
538-
? result.getConvention() == ResultConvention::Unowned
539-
: result.getConvention() == ResultConvention::Owned)
540-
&& "nonstandard conventions for return not implemented");
588+
auto r = result.forward(gen);
589+
590+
if (indirectResult) {
591+
gen.B.createCopyAddr(loc, r, indirectResult,
592+
IsTake, IsInitialization);
593+
r = gen.B.createTuple(loc, funcTy->getSILResult(), {});
541594
}
542-
#endif
543595

544-
auto r = result.forward(gen);
545596
scope.pop();
546597
gen.B.createReturn(loc, r);
547598
}
@@ -584,9 +635,6 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &gen,
584635
SILLocation loc,
585636
ManagedValue v,
586637
SILType nativeTy) {
587-
assert(nativeTy.isLoadable(gen.F.getModule()) &&
588-
"Cannot bridge address-only types");
589-
590638
CanType loweredNativeTy = nativeTy.getSwiftRValueType();
591639
CanType loweredBridgedTy = v.getType().getSwiftRValueType();
592640
if (loweredNativeTy == loweredBridgedTy)
@@ -640,8 +688,29 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &gen,
640688
}
641689

642690
// Bridge NSError to Error.
643-
if (loweredBridgedTy == gen.SGM.Types.getNSErrorType()) {
691+
if (loweredBridgedTy == gen.SGM.Types.getNSErrorType())
644692
return gen.emitBridgedToNativeError(loc, v);
693+
694+
// id-to-Any bridging.
695+
if (loweredNativeTy->isAny()) {
696+
assert(loweredBridgedTy->isEqual(
697+
gen.getASTContext().getProtocol(KnownProtocolKind::AnyObject)
698+
->getDeclaredType())
699+
&& "Any should bridge to AnyObject");
700+
701+
// Open the type of the reference and use it to build an Any.
702+
auto openedTy = ArchetypeType::getOpened(loweredBridgedTy);
703+
auto openedSILTy = SILType::getPrimitiveObjectType(openedTy);
704+
// TODO: Ever need to handle +0 values here?
705+
assert(v.hasCleanup());
706+
auto opened = gen.B.createOpenExistentialRef(loc, v.forward(gen),
707+
openedSILTy);
708+
auto result = gen.emitTemporaryAllocation(loc, nativeTy);
709+
auto resultVal = gen.B.createInitExistentialAddr(loc, result,
710+
openedTy, openedSILTy,
711+
{});
712+
gen.B.createStore(loc, opened, resultVal);
713+
return gen.emitManagedRValueWithCleanup(result);
645714
}
646715

647716
return v;
@@ -779,13 +848,9 @@ static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen,
779848
assert(foreignError && "couldn't find foreign error convention!");
780849
}
781850

782-
// Emit the indirect result arguments, if any.
783-
// FIXME: we're just assuming that these match up exactly?
784-
for (auto indirectResult : objcFnTy->getIndirectResults()) {
785-
SILType argTy = indirectResult.getSILType();
786-
auto arg = new (gen.F.getModule()) SILArgument(gen.F.begin(), argTy);
787-
args.push_back(arg);
788-
}
851+
// We don't know what to do with indirect results from the Objective-C side.
852+
assert(objcFnTy->getNumIndirectResults() == 0 &&
853+
"Objective-C methods cannot have indirect results");
789854

790855
// Emit the other arguments, taking ownership of arguments if necessary.
791856
auto inputs = objcFnTy->getParameters();
@@ -839,7 +904,13 @@ static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen,
839904
"didn't find foreign error slot");
840905

841906
// Bridge the input types.
842-
Scope scope(gen.Cleanups, CleanupLocation::get(loc));
907+
908+
// FIXME: We really want alloc_stacks to outlive this scope, because
909+
// bridging id-to-Any requires allocating an Any which gets passed to
910+
// the native entry point.
911+
912+
// Scope scope(gen.Cleanups, CleanupLocation::get(loc));
913+
843914
assert(bridgedArgs.size() == nativeInputs.size());
844915
for (unsigned i = 0, size = bridgedArgs.size(); i < size; ++i) {
845916
SILType argTy = swiftFnTy->getParameters()[i].getSILType();
@@ -864,28 +935,43 @@ static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen,
864935
void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
865936
assert(thunk.isForeign);
866937
SILDeclRef native = thunk.asForeign(false);
867-
938+
auto nativeInfo = getConstantInfo(native);
939+
auto subs = F.getForwardingSubstitutions();
940+
auto substTy = nativeInfo.SILFnType->substGenericArgs(
941+
SGM.M, SGM.M.getSwiftModule(), subs);
942+
SILType substSILTy = SILType::getPrimitiveObjectType(substTy);
943+
868944
auto loc = thunk.getAsRegularLocation();
869945
loc.markAutoGenerated();
870946
Scope scope(Cleanups, CleanupLocation::get(loc));
871947

872-
// Bridge the arguments.
948+
// If we are bridging a Swift method with an Any return value, create a
949+
// stack allocation to hold the result, since Any is address-only.
873950
SmallVector<SILValue, 4> args;
951+
952+
if (substTy->getNumIndirectResults() > 0) {
953+
SILResultInfo indirectResult = substTy->getSingleResult();
954+
assert(indirectResult.getType()->isAny() &&
955+
"Should not be trying to bridge anything except for Any here");
956+
args.push_back(emitTemporaryAllocation(loc, indirectResult.getSILType()));
957+
}
958+
959+
// Now, enter a cleanup used for bridging the arguments. Note that if we
960+
// have an indirect result, it must be outside of this scope, otherwise
961+
// we will deallocate it too early.
962+
Scope argScope(Cleanups, CleanupLocation::get(loc));
963+
964+
// Bridge the arguments.
874965
Optional<ForeignErrorConvention> foreignError;
875966
SILValue foreignErrorSlot;
876967
auto objcFnTy = emitObjCThunkArguments(*this, loc, thunk, args,
877968
foreignErrorSlot, foreignError);
878-
auto nativeInfo = getConstantInfo(native);
879969
auto swiftResultTy =
880970
F.mapTypeIntoContext(nativeInfo.SILFnType->getSILResult());
881971
auto objcResultTy = objcFnTy->getSILResult();
882972

883973
// Call the native entry point.
884974
SILValue nativeFn = emitGlobalFunctionRef(loc, native, nativeInfo);
885-
auto subs = F.getForwardingSubstitutions();
886-
auto substTy = nativeInfo.SILFnType->substGenericArgs(
887-
SGM.M, SGM.M.getSwiftModule(), subs);
888-
SILType substSILTy = SILType::getPrimitiveObjectType(substTy);
889975

890976
CanType bridgedResultType = objcResultTy.getSwiftRValueType();
891977

@@ -896,9 +982,14 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
896982
result = B.createApply(loc, nativeFn, substSILTy,
897983
swiftResultTy, subs, args);
898984

899-
// Leave the scope immediately. This isn't really necessary; it
900-
// just limits lifetimes a little bit more.
901-
scope.pop();
985+
if (substTy->hasIndirectResults()) {
986+
assert(substTy->getNumAllResults() == 1);
987+
result = args[0];
988+
}
989+
990+
// Leave the argument cleanup scope immediately. This isn't really
991+
// necessary; it just limits lifetimes a little bit more.
992+
argScope.pop();
902993

903994
// Now bridge the return value.
904995
result = emitBridgeReturnValue(*this, loc, result,
@@ -946,9 +1037,10 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
9461037
result = contBB->createBBArg(objcResultTy);
9471038

9481039
// Leave the scope now.
949-
scope.pop();
1040+
argScope.pop();
9501041
}
9511042

1043+
scope.pop();
9521044
B.createReturn(loc, result);
9531045
}
9541046

lib/SILGen/SILGenExpr.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3517,16 +3517,11 @@ ManagedValue SILGenFunction::emitRValueAsSingleValue(Expr *E, SGFContext C) {
35173517
return std::move(rv).getAsSingleValue(*this, E);
35183518
}
35193519

3520-
static ManagedValue emitUndef(SILGenFunction &gen, SILLocation loc,
3521-
const TypeLowering &undefTL) {
3522-
SILValue undef = SILUndef::get(undefTL.getLoweredType(), gen.SGM.M);
3523-
return gen.emitManagedRValueWithCleanup(undef, undefTL);
3524-
}
3525-
35263520
ManagedValue SILGenFunction::emitUndef(SILLocation loc, Type type) {
3527-
return ::emitUndef(*this, loc, getTypeLowering(type));
3521+
return emitUndef(loc, getLoweredType(type));
35283522
}
35293523

35303524
ManagedValue SILGenFunction::emitUndef(SILLocation loc, SILType type) {
3531-
return ::emitUndef(*this, loc, getTypeLowering(type));
3525+
SILValue undef = SILUndef::get(type, SGM.M);
3526+
return ManagedValue::forUnmanaged(undef);
35323527
}

stdlib/public/core/BridgeObjectiveC.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,35 @@ func _bridgeToObjectiveCUnconditionalAutorelease<T>(_ x: T) -> AnyObject
193193
@_silgen_name("_swift_bridgeNonVerbatimToObjectiveC")
194194
func _bridgeNonVerbatimToObjectiveC<T>(_ x: T) -> AnyObject?
195195

196+
/// Bridge an arbitrary value to an Objective-C object.
197+
///
198+
/// - If `T` is a class type, it is always bridged verbatim, the function
199+
/// returns `x`;
200+
///
201+
/// - otherwise, `T` conforms to `_ObjectiveCBridgeable`:
202+
/// + if `T._isBridgedToObjectiveC()` returns `false`, then
203+
/// we fall back to boxing (below);
204+
/// + otherwise, returns the result of `x._bridgeToObjectiveC()`;
205+
///
206+
/// - otherwise, we use **boxing** to bring the value into Objective-C.
207+
/// The value is wrapped in an instance of a private Objective-C class
208+
/// that is `id`-compatible and dynamically castable back to the type of
209+
/// the boxed value, but is otherwise opaque.
210+
///
211+
/// TODO: This should subsume `_bridgeToObjectiveC` above.
212+
/// COMPILER_INTRINSIC
213+
public func _bridgeAnythingToObjectiveC<T>(_ x: T) -> AnyObject {
214+
if _fastPath(_isClassOrObjCExistential(T.self)) {
215+
return unsafeBitCast(x, to: AnyObject.self)
216+
}
217+
return _bridgeAnythingNonVerbatimToObjectiveC(x)
218+
}
219+
220+
// TODO: This should subsume `_bridgeNonVerbatimToObjectiveC` above.
221+
/// COMPILER_INTRINSIC
222+
@_silgen_name("_swift_bridgeAnythingNonVerbatimToObjectiveC")
223+
public func _bridgeAnythingNonVerbatimToObjectiveC<T>(_ x: T) -> AnyObject
224+
196225
/// Convert `x` from its Objective-C representation to its Swift
197226
/// representation.
198227
///
@@ -523,4 +552,5 @@ extension AutoreleasingUnsafeMutablePointer {
523552
Builtin.unreachable()
524553
}
525554
}
555+
526556
#endif

0 commit comments

Comments
 (0)