[Question] Can Virtual Stub Dispatch be "inlined"? #8819

Open
benaadams opened this Issue Jan 5, 2017 · 1 comment

Projects

None yet

2 participants

@benaadams
Contributor
benaadams commented Jan 5, 2017 edited

Investigation of dispatch costs

There are 3 states for an interface callsite

1. 0 attached methods : Unresolved  -> Lookup stub
2. 1 attached method  : Monomorphic -> Dispatch stub
3. N attached methods : Megamorphic -> Resolve stub

For a monomorphic interface call it always goes via a stub to do dispatch; which is roughly the same cost as 2 chained non-inlined direct calls:

                      Method |          Mean |     StdDev | Scaled |          RPS |
---------------------------- |-------------- |----------- |------- |------------- |
     -> InterfaceMonomorphic | 1,276.6333 ns | 16.6153 ns |   1.00 |   783,310.26 |
      InterfacePolymorphicX2 | 1,444.7386 ns | 25.2325 ns |   1.13 |   692,166.75 |
     InterfaceMegamorphicX33 | 1,428.9762 ns | 13.8861 ns |   1.12 |   699,801.72 |

InterfaceUnsafeCastConstTest |   830.3120 ns |  9.8983 ns |   0.65 | 1,204,366.58 |
  InterfaceUnsafeCastVarTest | 1,198.1936 ns | 16.6743 ns |   0.94 |   834,589.69 |

  -> DirectViaCastIndirected | 1,136.0911 ns | 19.6327 ns |   0.89 |   880,211.12 |
     DirectViaCastNotInlined |   679.2567 ns |  9.4285 ns |   0.53 | 1,472,197.44 |
        DirectViaCastInlined |   192.5118 ns |  5.2530 ns |   0.15 | 5,194,485.75 |

Which is in line with the BoTR Virtual Stub Dispatch where the call site; calls stub; which calls method
Figure 1

For 1 resolved type (monomorphic) it looks roughly like this (excuse the pseudo-code)

function CallInterface()
{
    VirtualStub dispatch = callsite_dispatch;
    dispatch.Invoke(obj.methodTable);
}

class DispatchStub : VirtualStub
{
    Type expectedMT;
    PCODE implTarget;
    PCODE failTarget;

    Invoke(MethodTable methodTable)
    {
        if (expectedMT == methodTable)
        {
             this->implTarget();
        }
        else
        {
            this->failTarget();
        }
    }
}

However if the LookupStub and ResolveStubs returned 0 as MT then the DispatchStub could be turned into a regular POCO and the call inlined?

function CallInterface()
{
    var dispatch = callsite_dispatch;
    var expectedMT = dispatch->expectedMT;
    if (expectedMT == 0 || expectedMT == obj.methodTable)
    {
         dispatch->implTarget();
    }
    else
    {
        dispatch->failTarget();
    }
}

class DispatchStub : VirtualStub
{
    Type expectedMT;
    PCODE implTarget;
    PCODE failTarget;
}
class LookupStub : VirtualStub
{
    Type expectedMT = 0;
    PCODE implTarget => Invoke();
    PCODE failTarget ...;
}
class ResolveStub : VirtualStub
{
    Type expectedMT = 0;
    PCODE implTarget => Invoke();
    PCODE failTarget ...;
}

Comparable examples

Inline caches in Smalltalk, Java, Javascript

Question

Would there be any benefit to this change?

@benaadams benaadams changed the title from [Question] Can Virtual Stub Dispatch be inlined? to [Question] Can Virtual Stub Dispatch be "inlined"? Jan 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment