[swift-dev] Protocol Devirtualizer Pass

Arnold Schwaighofer aschwaighofer at apple.com
Wed Nov 29 13:40:18 CST 2017


The issue I raised is when we truly replace the type in an existing function:

====

protocol Proto :class {}
class SingleImpl : Proto {}
class User {
  func useProto(p: Proto) {}
}

If i understand you correctly your pass changes this program to:

class User {
  func useProto(p: SingleImpl) {}
}

One way in which this could be iffy is that we mangle type information
as part of the function name. So if you did not implement this as a function
specialization but a true replacement the mangled name no longer
agrees with the actual type.

// User.useProto(p:)
sil hidden @_T03Foo4UserC8useProtoyAA0D0_p1p_tF : $@convention(method)
(@owned Proto, @guaranteed User) -> () {

$ swift-macosx-x86_64/bin/swift-demangle _T03Foo4UserC8useProtoyAA0D0_p1p_tF

_T03Foo4UserC8useProtoyAA0D0_p1p_tF ---> Foo.User.useProto(p: Foo.Proto) -> ()

True replacement (note the class type in the signature):

sil hidden @_T03Foo4UserC8useProtoyAA0D0_p1p_tF : $@convention(method)
(@owned SingleImpl, @guaranteed User) -> () {}


(Function specialization is different in that it actually creates a
different function, of course the original function is still there in
e.g the vtable which is not what you want)

You would have to make sure to update the mangled names in all places
... I am not sure of what problems that could entail, maybe none as
long as your type is internal. I would bring up this idea on swift
dev.

====

But, it seems you are actually doing function signature specialization which does not suffer the issue above.

You will however still have the original function with the protocol in the v-table of User in my example.

I don’t know how important getting rid of those is for you …

> On Nov 29, 2017, at 11:30 AM, Raj Barik via swift-dev <swift-dev at swift.org> wrote:
> 
> Hi,
> 
> I am thinking about writing a Protocol Devirtualizer Pass that specializes functions that take Protocols as arguments to transform them with concrete types instead of protocol types when the concrete types can be determined statically by some compiler analysis. This is the first step of the transformation that I am proposing. My goal is to extend this to eliminate the original function implementation and also to remove the corresponding protocol type (by deleting it from the witness table), if possible. For simple cases, where the protocol is only used for mocking for example and that there is just one class that conforms to it, we should be able to eliminate the protocol altogether. This is the second and final step of the transformation. Does anyone see any issues with both these steps? Arnold from Apple pointed out that there might be demangling issues when the protocol is eliminated. Any ideas on how to fix the demangling issues? Moreover, would such a pass be helpful to Swift folks?
> 
> Original code:
> 
> 
> protocol SumProtocol: class {
>   func increment(i:Int)  -> Int
> }
> 
> internal class SumClass: SumProtocol {
>   var a:Int
>   init(base:Int) {
>     self.a = base
>   }
>   func increment(i:Int) -> Int {
>    self.a += i
>    return self.a
>   }
> }
> 
> @inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{
>  return a.increment(i:val)
> }
> 
> internal let magic:SumProtocol = SumClass(base:10)
> print("c=\(wrap_inc(a:magic,val:10))")
> 
> 
> After Step 1:
> 
> 
> protocol SumProtocol: class {
>   func increment(i:Int)  -> Int
> }
> 
> internal class SumClass: SumProtocol {
>   var a:Int
>   init(base:Int) {
>     self.a = base
>   }
>   func increment(i:Int) -> Int {
>    self.a += i
>    return self.a
>   }
> }
> 
> @inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{
>  return a.increment(i:val)
> }
> 
> @inline(never) internal func wrap_inc_1(a:SumClass, val:Int) -> Int{
>  return a.increment(i:val)
> }
> 
> internal let magic:SumClass = SumClass(base:10)
> print("c=\(wrap_inc_1(a:magic,val:10))")
> 
> 
> After Step 2:
> 
> internal class SumClass {
>   var a:Int
>   init(base:Int) {
>     self.a = base
>   }
>   func increment(i:Int) -> Int {
>    self.a += i
>    return self.a
>   }
> }
> 
> @inline(never) internal func wrap_inc(a:SumClass, val:Int) -> Int{
>  return a.increment(i:val)
> }
> 
> internal let magic:SumClass = SumClass(base:10)
> print("c=\(wrap_inc(a:magic,val:10))")
> 
> Any comments/thought on this transformation?
> 
> Best,
> Raj 
> _______________________________________________
> swift-dev mailing list
> swift-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20171129/4b8c126a/attachment.html>


More information about the swift-dev mailing list