Files
swift-mirror/test/SILGen/checked_cast_br_anyobject.swift
Michael Gottesman 8e5fb2164a [sil] Ban casting AnyObject with a guaranteed ownership forwarding checked_cast_br and fix up semantic-arc-opts given that.
The reason why I am doing this is that currently checked_cast_br of an AnyObject
may return a different value due to boxing. As an example, this can occur when
performing a checked_cast_br of a __SwiftValue(AnyHashable(Klass())).

To model this in SIL, I added to OwnershipForwardingMixin a bit of information
that states if the instruction directly forwards ownership with a default value
of true. In checked_cast_br's constructor though I specialize this behavior if
the source type is AnyObject and thus mark the checked_cast_br as not directly
forwarding its operand. If an OwnershipForwardingMixin directly forwards
ownership, one can assume that if it forwards ownership, it will always do so in
a way that ensures that each forwarded value is rc-identical to whatever result
it algebraically forwards ownership to. So in the context of checked_cast_br, it
means that the source value is rc-identical to the argument of the success and
default blocks.

I added a verifier check to CheckedCastBr that makes sure that it can never
forward guaranteed ownership and have a source type of AnyObject.

In SemanticARCOpts, I modified the code that builds extended live ranges of
owned values (*) to check if a OwnershipForwardingMixin is directly
forwarding. If it is not directly forwarding, then we treat the use just as an
unknown consuming use. This will then prevent us from converting such an owned
value to guaranteed appropriately in such a case.

I also in SILGen needed to change checked_cast_br emission in SILGenBuilder to
perform an ensurePlusOne on the input operand (converting it to +1 with an
appropriate cleanup) if the source type is an AnyObject. I found this via the
verifier check catching this behavior from SILGen when compiling libswift. This
just shows how important IR verification of invariants can be.

(*) For those unaware, SemanticARCOpts contains a model of an owned value and
all forwarding uses of it called an OwnershipLiveRange.

rdar://85710101
2021-11-29 15:39:00 -08:00

45 lines
1.3 KiB
Swift

// RUN: %target-swift-emit-silgen -module-name checked_cast_br_anyobject -parse-as-library -Xllvm -sil-full-demangle -enforce-exclusivity=checked %s
public struct BridgedSwiftObject {
var swiftMetatype : UnsafeRawPointer
var refCounts : Int64
}
public typealias SwiftObject = UnsafeMutablePointer<BridgedSwiftObject>
extension UnsafeMutablePointer where Pointee == BridgedSwiftObject {
init<T: AnyObject>(_ object: T) {
let ptr = Unmanaged.passUnretained(object).toOpaque()
self = ptr.bindMemory(to: BridgedSwiftObject.self, capacity: 1)
}
func getAs<T: AnyObject>(_ objectType: T.Type) -> T {
return Unmanaged<T>.fromOpaque(self).takeUnretainedValue()
}
}
extension Optional where Wrapped == UnsafeMutablePointer<BridgedSwiftObject> {
func getAs<T: AnyObject>(_ objectType: T.Type) -> T? {
if let pointer = self {
return Unmanaged<T>.fromOpaque(pointer).takeUnretainedValue()
}
return nil
}
}
public class Klass {}
public class Klass2 {}
// Make sure that we do not crash when emitting this code!
public func getValue(_ obj: UnsafeMutablePointer<BridgedSwiftObject>) -> AnyObject {
let v = obj.getAs(AnyObject.self)
switch v {
case let k as Klass:
return k
case let k as Klass2:
return k
default:
fatalError("unknown type")
}
}