mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
45 lines
1.3 KiB
Swift
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")
|
|
}
|
|
}
|