Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

JIT: after devirtualization try undoing box and invoking unboxed entry #14698

Merged
merged 2 commits into from
Oct 30, 2017

Conversation

AndyAyersMS
Copy link
Member

See commits for details.

As per usual I need to finish off the implementation for SPMI and prepare desktop for jit interface changes.

Also still looking at diffs.

@AndyAyersMS
Copy link
Member Author

@stephentoub, @jkotas, @briansull PTAL
cc @dotnet/jit-contrib

Diffs are a bit tricky to evaluate here since the changes to corelib have perturbed crossgen order and cut out a fair number of instantiations.

@stephentoub if you have some simple test cases for the new paths in AwaitUnsafeOnCompleted please send them my way. I've run all the CoreFx tests locally without issue.

@stephentoub
Copy link
Member

if you have some simple test cases

Thanks, Andy. You're looking for tests cases to run or test cases to see the asm for?

@AndyAyersMS
Copy link
Member Author

Runnable is probably better.

@AndyAyersMS
Copy link
Member Author

First commit only

The fact we use R2R for most of the jit-diffs assemblies is an inhibitor. So we only see diffs here in the core library.

Total bytes of diff: -495 (0.00 % of base)
    diff is an improvement.

Total byte diff includes 0 bytes from reconciling methods
        Base had    0 unique methods,        0 unique bytes
        Diff had    0 unique methods,        0 unique bytes

Top file improvements by size (bytes):
        -495 : System.Private.CoreLib.dasm (-0.01 % of base)

1 total files with size differences (1 improved, 0 regressed), 129 unchanged.

Top method improvements by size (bytes):
         -32 : System.Private.CoreLib.dasm - System.Convert:ToChar(struct):char (2 methods)
         -32 : System.Private.CoreLib.dasm - System.Convert:ToDateTime(long):struct (2 methods)
         -30 : System.Private.CoreLib.dasm - System.Convert:ToDateTime(int):struct (2 methods)
         -24 : System.Private.CoreLib.dasm - System.Convert:ToDateTime(char):struct (2 methods)
         -23 : System.Private.CoreLib.dasm - System.Convert:ToChar(float):char

30 total methods with size differences (30 improved, 0 regressed), 142993 unchanged.

Second commit only

Note most of the improvement here is from instantations of ArraySegment<byte> that crossgen no longer creates.

Total bytes of diff: -16246 (-0.07 % of base)
    diff is an improvement.

Total byte diff includes -16435 bytes from reconciling methods
        Base had  163 unique methods,    18623 unique bytes
        Diff had   19 unique methods,     2188 unique bytes

Top file improvements by size (bytes):
      -16246 : System.Private.CoreLib.dasm (-0.46 % of base)

1 total files with size differences (1 improved, 0 regressed), 129 unchanged.

Top method regessions by size (bytes):
         301 : System.Private.CoreLib.dasm - System.ValueTuple`2[__Canon,Boolean][System.__Canon,System.Boolean]:System.Collections.IStructuralComparable.CompareTo(ref,ref):int:this
         281 : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder`1[Int32][System.Int32]:SetResult(int):this
         259 : System.Private.CoreLib.dasm - System.ValueTuple`2[__Canon,Boolean][System.__Canon,System.Boolean]:ToString():ref:this
         229 : System.Private.CoreLib.dasm - System.ValueTuple`2[__Canon,Boolean][System.__Canon,System.Boolean]:System.IComparable.CompareTo(ref):int:this
         184 : System.Private.CoreLib.dasm - System.ValueTuple`2[__Canon,Boolean][System.__Canon,System.Boolean]:System.Collections.IStructuralEquatable.Equals(ref,ref):bool:this

Top method improvements by size (bytes):
        -840 : System.Private.CoreLib.dasm - System.Threading.Tasks.TaskFactory`1[ArraySegment`1][System.ArraySegment`1[System.Byte]]:FromAsyncImpl(ref,ref,ref,int,ref):ref
        -760 : System.Private.CoreLib.dasm - System.Threading.Tasks.TaskFactory`1[ArraySegment`1][System.ArraySegment`1[System.Byte]]:FromAsyncImpl(ref,ref,ref,ref,int):ref
        -608 : System.Private.CoreLib.dasm - System.Threading.Tasks.TaskFactory`1[ArraySegment`1][System.ArraySegment`1[System.Byte]]:FromAsyncCoreLogic(ref,ref,ref,ref,bool)
        -562 : System.Private.CoreLib.dasm - System.Threading.Tasks.TaskFactory`1[ArraySegment`1][System.ArraySegment`1[System.Byte]]:ContinueWhenAnyImpl(ref,ref,ref,int,struct,ref):ref
        -545 : System.Private.CoreLib.dasm - System.Threading.Tasks.TaskFactory`1[ArraySegment`1][System.ArraySegment`1[System.Byte]]:ContinueWhenAllImpl(ref,ref,ref,int,struct,ref):ref

186 total methods with size differences (164 improved, 22 regressed), 142674 unchanged.

Second commit only, common methods

If we filter out methods that exist only in base or diff we can see common method changes. The regression in SetResult is a crossgen inline order difference (see #14441). The AwaitUnsafeOnCompleted size increases are from manually inlining the catch-all case. The improvement in ContinueWith is that there is one fewer instantation.

Total bytes of diff: 189 (0.00 % of base)
    diff is a regression.

Top file regressions by size (bytes):
         189 : System.Private.CoreLib.dasm (0.01 % of base)

1 total files with size differences (0 improved, 1 regressed), 129 unchanged.

Top method regessions by size (bytes):
         281 : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder`1[Int32][System.Int32]:SetResult(int):this
          88 : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[VoidTaskResult][System.Threading.Tasks.VoidTaskResult]:AwaitUnsafeOnCompleted(byref,byref):this (9 methods)
          49 : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[__Canon][System.__Canon]:AwaitUnsafeOnCompleted(byref,byref):this (3 methods)

Top method improvements by size (bytes):
        -229 : System.Private.CoreLib.dasm - System.Threading.Tasks.Task`1[__Canon][System.__Canon]:ContinueWith(ref,ref,ref,struct,int):ref:this (6 methods)

Both commits together

Basically the sum of the two separately.

Total bytes of diff: -16741 (-0.07 % of base)
    diff is an improvement.

Total byte diff includes -16435 bytes from reconciling methods
        Base had  163 unique methods,    18623 unique bytes
        Diff had   19 unique methods,     2188 unique bytes

Top file improvements by size (bytes):
      -16741 : System.Private.CoreLib.dasm (-0.48 % of base)

Sample diffs (simple test case)

The jit can now undo the box for x, but not for y. If the method inlines then it is possible to undo other argument boxes, if the uses in the method body are simple.

[MethodImpl(MethodImplOptions.NoInlining)]
static int CompareTo<T>(T x, T y)
{
    if (x is IComparable)
    {
        return ((IComparable)x).CompareTo(y);
    }
    return -1;
}
-; Lcl frame size = 32
+; Lcl frame size = 48

 G_M19816_IG01:
-       57                   push     rdi
        56                   push     rsi
-       53                   push     rbx
-       4883EC20             sub      rsp, 32
-       8BF1                 mov      esi, ecx
-       8BFA                 mov      edi, edx
+       4883EC30             sub      rsp, 48
+       8BF2                 mov      esi, edx

 G_M19816_IG02:
-       48B950F8688CFD7F0000 mov      rcx, 0x7FFD8C68F850
-       E816B9825F           call     CORINFO_HELP_NEWSFAST
-       488BD8               mov      rbx, rax
-       897308               mov      dword ptr [rbx+8], esi
-       48B950F8688CFD7F0000 mov      rcx, 0x7FFD8C68F850
-       E801B9825F           call     CORINFO_HELP_NEWSFAST
+       894C2428             mov      dword ptr [rsp+28H], ecx
+       48B908CE698CFD7F0000 mov      rcx, 0x7FFD8C69CE08
+       E896BB825F           call     CORINFO_HELP_NEWSFAST
        488BD0               mov      rdx, rax
-       897A08               mov      dword ptr [rdx+8], edi
-       488BCB               mov      rcx, rbx
-       E85B2D245C           call     System.Int32:CompareTo(ref):int:this
+       897208               mov      dword ptr [rdx+8], esi
+       488D4C2428           lea      rcx, bword ptr [rsp+28H]
+       E816685A5C           call     System.Int32:CompareTo(ref):int:this
        90                   nop

 G_M19816_IG03:
-       4883C420             add      rsp, 32
-       5B                   pop      rbx
+       4883C430             add      rsp, 48
        5E                   pop      rsi
-       5F                   pop      rdi
        C3                   ret

-; Total bytes of code 70, prolog size 7 for method Ex:CompareTo(int,int):int
+; Total bytes of code 49, prolog size 5 for method Ex:CompareTo(int,int):int

Sample diffs (in changed part of AsyncTaskMethodBuilder)

Still working on it...

@AndyAyersMS
Copy link
Member Author

@dotnet-bot test Windows_NT x64 corefx_baseline

@AndyAyersMS AndyAyersMS added the * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) label Oct 25, 2017
@benaadams
Copy link
Member

In the sample test case; the frame size went up though there seems to be less in it - is that expected?

@benaadams
Copy link
Member

Due to using stack rather than heap?

@justinvp
Copy link

Does the optimization happen when the simple test case is written as below? I assume so, but just curious as the IL is slightly different between the two.

[MethodImpl(MethodImplOptions.NoInlining)]
static int CompareTo<T>(T x, T y)
{
    if (x is IComparable c)
    {
        return c.CompareTo(y);
    }
    return -1;
}

@AndyAyersMS
Copy link
Member Author

@benaadams Yes, there is a copy on the stack now instead of on the heap.

@AndyAyersMS
Copy link
Member Author

@justinvp no, not yet, it needs something like #14471 to capture the knowledge gained from a successful type test.

@justinvp
Copy link

@AndyAyersMS ah, ok. Thanks.

@AndyAyersMS
Copy link
Member Author

Cross-linking to #14178 which has some good discussion. Latest version here mostly cleans up the special casing via type equality. Could go further and remove the unsafe cast bits from the earlier checks too....

@AndyAyersMS
Copy link
Member Author

Actually in we might be able to get to @justinvp's example. Looks like we aren't as proficient about propagating types through dup as we could be. Let me look a bit more at this case.

@stephentoub
Copy link
Member

if you have some simple test cases

Here's a simple test case highlighting what I'm trying to accomplish. It's made up to stress the allocation costs.

Consider this code:

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        for (long i = 0; i < 1000; i++)
        {
            var atmb = new AsyncTaskMethodBuilder();
            var t = Method1(i, atmb.Task);
            atmb.SetResult();
            await t;
        }
    }

    static async Task<long> Method1(long i, Task t) => await Method2(i, t);
    static async Task<long> Method2(long i, Task t) => await Method3(i, t);
    static async Task<long> Method3(long i, Task t) => await Method4(i, t);
    static async Task<long> Method4(long i, Task t) => await Method5(i, t);
    static async Task<long> Method5(long i, Task t) => await Method6(i, t);
    static async Task<long> Method6(long i, Task t) => await Method7(i, t);
    static async Task<long> Method7(long i, Task t) { await t; return i; }
}

When I run an allocation profiler on it on core, I get:
image
but when I switch those Tasks to be ValueTasks:

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        Console.ReadLine();

        for (long i = 0; i < 1000; i++)
        {
            var atmb = new AsyncTaskMethodBuilder();
            var t = Method1(i, atmb.Task);
            atmb.SetResult();
            await t;
        }
    }

    static async ValueTask<long> Method1(long i, Task t) => await Method2(i, t);
    static async ValueTask<long> Method2(long i, Task t) => await Method3(i, t);
    static async ValueTask<long> Method3(long i, Task t) => await Method4(i, t);
    static async ValueTask<long> Method4(long i, Task t) => await Method5(i, t);
    static async ValueTask<long> Method5(long i, Task t) => await Method6(i, t);
    static async ValueTask<long> Method6(long i, Task t) => await Method7(i, t);
    static async ValueTask<long> Method7(long i, Task t) { await t; return i; }
}

I get:
image
Those Action delegates consuming 40% of the allocations are what this change should get rid of, as it'll recognize ValueTask<T>, regardless of the T, as something it knows how to deal with directly and can avoid going through the awaiter for (using the awaiter requires that we create the delegate). Of course, the key here (and where your changes are very welcome) is getting rid of the delegate while not incurring other boxing allocations while trying to do so 😄

@AndyAyersMS
Copy link
Member Author

Improving flow of types through dup helps a little but more is needed.

@AndyAyersMS
Copy link
Member Author

Sample diffs (in changed part of AsyncTaskMethodBuilder)

Codegen for instantiation that follows the new IValueTaskAwaiter branch. No boxing; the only allocation here is to potentially create a task.

Still working on verifying changes via an allocation profiler. Something about my somewhat ad-hoc test setup is getting in the way.

Inlines into 060044EF System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[Int64][System.Int64]:AwaitUnsafeOnCompleted(byref,byref):this
  [0 IL=0002 TR=000003 060044F0] [FAILED: too many il bytes] System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[Int64][System.Int64]:GetStateMachineBox(byref):ref:this
  [1 IL=0173 TR=000153 0600458A] [below ALWAYS_INLINE size] System.Runtime.CompilerServices.ValueTaskAwaiter`1[Int64][System.Int64]:GetTask():ref:this
    [2 IL=0006 TR=000178 060024E2] [profitable inline] System.Threading.Tasks.ValueTask`1[Int64][System.Int64]:AsTask():ref:this
      [3 IL=0016 TR=000210 060044FB] [aggressive inline attribute] System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[Int64][System.Int64]:GetTaskForResult(long):ref
        [4 IL=0663 TR=000413 06002254] [profitable inline] System.Threading.Tasks.Task`1[Int64][System.Int64]:.ctor(long):this
          [5 IL=0012 TR=000434 060022D1] [profitable inline] System.Threading.Tasks.Task:.ctor(bool,int,struct):this
            [6 IL=0001 TR=000448 06000102] [below ALWAYS_INLINE size] System.Object:.ctor():this
  [0 IL=0184 TR=000166 06004512] [FAILED: noinline per IL/cached result] System.Runtime.CompilerServices.TaskAwaiter:UnsafeOnCompletedInternal(ref,ref,bool)

G_M44580_IG01:
       57                   push     rdi
       56                   push     rsi
       53                   push     rbx
       4883EC40             sub      rsp, 64
       C5F877               vzeroupper 
       33C0                 xor      rax, rax
       4889442430           mov      qword ptr [rsp+30H], rax
       488BF2               mov      rsi, rdx

G_M44580_IG02:
       498BD0               mov      rdx, r8
       E804F4FFFF           call     System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[Int64][System.Int64]:GetStateMachineBox(byref):ref:this
       488BF8               mov      rdi, rax
       480FBE0E             movsx    rcx, byte  ptr [rsi]

G_M44580_IG03:
       C4E17A6F06           vmovdqu  xmm0, qword ptr [rsi]
       C4E17A7F442430       vmovdqu  qword ptr [rsp+30H], xmm0   // copy the awaiter locally instead of boxing

G_M44580_IG04:
       488B4C2430           mov      rcx, gword ptr [rsp+30H]    // from inlined AsTask/GetTaskForResult; check for task
       4885C9               test     rcx, rcx
       754D                 jne      SHORT G_M44580_IG08
       488B742438           mov      rsi, qword ptr [rsp+38H]    // if no task, see result is zero so we can use cache
       4885F6               test     rsi, rsi
       7523                 jne      SHORT G_M44580_IG06         // jump if we can't use cache

G_M44580_IG05:
       48B928303A3CFD7F0000 mov      rcx, 0x7FFD3C3A3028         // fetch cached task
       BAD4000000           mov      edx, 212
       E80966375F           call     CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS
       48B90029001075010000 mov      rcx, 0x17510002900
       488B19               mov      rbx, gword ptr [rcx]
       EB1D                 jmp      SHORT G_M44580_IG07

G_M44580_IG06:
       48B938C14B3CFD7F0000 mov      rcx, 0x7FFD3C4BC138          // cons up new task
       E8DBA2365F           call     CORINFO_HELP_NEWFAST
       C7403400000001       mov      dword ptr [rax+52], 0x1000000
       48897038             mov      qword ptr [rax+56], rsi
       488BD8               mov      rbx, rax

G_M44580_IG07:
       488BCB               mov      rcx, rbx

G_M44580_IG08:
       488BD7               mov      rdx, rdi
       41B801000000         mov      r8d, 1
       E8CC014257           call     System.Runtime.CompilerServices.TaskAwaiter:UnsafeOnCompletedInternal(ref,ref,bool)
       90                   nop      

G_M44580_IG09:
       4883C440             add      rsp, 64
       5B                   pop      rbx
       5E                   pop      rsi
       5F                   pop      rdi
       C3                   ret      

@AndyAyersMS AndyAyersMS changed the title JIT: after devirtualization try undoing box and invoking unboxed entry [WIP] JIT: after devirtualization try undoing box and invoking unboxed entry Oct 27, 2017
@AndyAyersMS AndyAyersMS removed the * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) label Oct 27, 2017
@AndyAyersMS
Copy link
Member Author

This is ready for review now...

GenTree* blkArg = copyDst->gtOp.gtOp1;
assert(blkArg->gtOper == GT_ADD);

// Todo: verify addends

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you wanted to add verification that you are adding +4/+8 here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, thanks for catching that. Added with the latest commit.

virtual CORINFO_METHOD_HANDLE getUnboxedEntry(
CORINFO_METHOD_HANDLE ftn,
bool* requiresInstMethodTableArg = NULL /* OUT */
) = 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh Good, a Jit Interface change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, need a new guid, don't I....

@benaadams
Copy link
Member

Still working on verifying changes via an allocation profiler. Something about my somewhat ad-hoc test setup is getting in the way.

If you use perfview adding .NETTasks:0:0 to the 'Additional Providers' textbox should drop the extra allocs from the ETW events #14178 (comment)

@AndyAyersMS
Copy link
Member Author

@benaadams thanks, problem is that I'm not seeing the expected allocations in perfview, and can't get VS's profiler to work at all. Going to try a release build with perfview. Maybe checked builds do odd things.

@benaadams
Copy link
Member

K, I was having issues because the ETW tracing causes it to take a different path; so you need to switch it off for Tasks

@AndyAyersMS
Copy link
Member Author

Coarse sampling seems to capture things as expected, if I modify the test to run a bit longer. Not sure why the per-allocation eventing doesn't do the same. At any rate, no actions here.

image

@AndyAyersMS
Copy link
Member Author

On ubuntu, GC/Scenarios/LeakWheel/leakwheel/leakwheel.sh failed. At first glance it doesn't look like this change could be the cause, and earlier PR legs passed. Seems like also this test may have some random behavior. So am going to retry.

@dotnet-bot retest Ubuntu x64 Checked Innerloop Build and Test

@AndyAyersMS
Copy link
Member Author

AndyAyersMS commented Oct 27, 2017

Ubuntu now seems to be stuck running JIT/superpmi/superpmicollect/superpmicollect.sh and has timed out.

@sandreenko can you look over the SPMI changes I've made here and see if you spot anything wrong?

I can try and repro but it may take a while. My local ubuntu box (which I dual boot with Win10) is offline stuck in "grub repair" after a Win10 update.

I'm going to modify the shim collector to pass a local for the optional arg and then only report it back if the caller wants it. That way the optional result is always recorded.

Copy link

@briansull briansull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Good,

@benaadams
Copy link
Member

benaadams commented Oct 28, 2017

Windows_NT arm64 Cross Checked Innerloop Build and Test

JIT\Performance\CodeQuality\Roslyn\CscBench
JIT\Methodical\VT\port_il_relhuge_gcref
JIT\Methodical\Arrays\huge_il_relhuge_struct

18:09:48 Output: TEST_CMD_LINE: JIT\Methodical\Arrays\huge_il_relhuge_struct> C:\Users\robox\arm64_ci\tests\tests\JIT\Methodical\Arrays\huge_il_relhuge_struct_il_relhuge_struct.cmd
18:09:48 BEGIN EXECUTION
18:09:48 "C:\Users\robox\arm64_ci\tests\tests\tests\Core_Root\corerun.exe" _il_relhuge_struct.exe
18:09:48 Creating 32-dimension array
18:09:48 0 1 40 1 80 2 120 1 160 1 200 2 240 1 280 1 320 2 360 1 400 1 440 2 480 1 520 1 560 2 600 1 640 1 680 2 720 1 760 1 800 2 840 1 880 1 920 2 960 1 1000 1 1040 2 1080 1 1120 1 1160 2 1200 1 1240 1
18:09:48 Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
18:09:48 at JitTest.Test.Main()
18:09:48 Expected: 100
18:09:48 Actual: 255
18:09:48 END EXECUTION - FAILED
18:09:48 FAILED

@jkotas
Copy link
Member

jkotas commented Oct 30, 2017

@jkotas can you look over the new jit interface method?

LGTM

@AndyAyersMS
Copy link
Member Author

Arm64 test failures are pervasive lately, so will ignore.

@jashook should we disable the two tests that are failing here?

@AndyAyersMS
Copy link
Member Author

AndyAyersMS commented Oct 30, 2017

@stephentoub look ok to you now?

@stephentoub
Copy link
Member

@stephentoub look ok to you now?

Yup, thanks for doing this. I noticed in the asm you shared there are opportunities to pare that down further, in the implementation of the {Configured}ValueTaskAwaiter.GetTask, but I can do that subsequently.

@benaadams
Copy link
Member

This may have regressed for #20936 (comment)

((IStateMachineBoxAwareAwaiter)awaiter).AwaitUnsafeOnCompleted(box)

@benaadams
Copy link
Member

stephentoub added a commit to stephentoub/coreclr that referenced this pull request Sep 8, 2019
Take advantage of dotnet#14698 to avoid boxing the TRest argument and improve devirtualization.
stephentoub added a commit to stephentoub/coreclr that referenced this pull request Sep 9, 2019
Take advantage of dotnet#14698 to avoid boxing the TRest argument and improve devirtualization.
stephentoub added a commit to stephentoub/coreclr that referenced this pull request Sep 9, 2019
Take advantage of dotnet#14698 to avoid boxing the TRest argument and improve devirtualization.
stephentoub added a commit to stephentoub/coreclr that referenced this pull request Sep 10, 2019
Take advantage of dotnet#14698 to avoid boxing the TRest argument and improve devirtualization.
stephentoub added a commit to stephentoub/coreclr that referenced this pull request Sep 10, 2019
Take advantage of dotnet#14698 to avoid boxing the TRest argument and improve devirtualization.
stephentoub added a commit to stephentoub/coreclr that referenced this pull request Sep 14, 2019
Take advantage of dotnet#14698 to avoid boxing the TRest argument and improve devirtualization.
stephentoub added a commit that referenced this pull request Sep 15, 2019
Take advantage of #14698 to avoid boxing the TRest argument and improve devirtualization.
Dotnet-GitSync-Bot pushed a commit to Dotnet-GitSync-Bot/corefx that referenced this pull request Sep 15, 2019
Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Dotnet-GitSync-Bot pushed a commit to Dotnet-GitSync-Bot/corert that referenced this pull request Sep 15, 2019
Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Dotnet-GitSync-Bot pushed a commit to Dotnet-GitSync-Bot/mono that referenced this pull request Sep 15, 2019
Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
danmoseley pushed a commit to dotnet/corefx that referenced this pull request Sep 15, 2019
Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
MichalStrehovsky pushed a commit to dotnet/corert that referenced this pull request Sep 15, 2019
Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
vargaz pushed a commit to mono/mono that referenced this pull request Sep 15, 2019
…) (#16844)

Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
8 participants