Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Get exact class during devirtualization#45526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged

Conversation

@AndyAyersMS
Copy link
Member

If we devirtualize to a method on a generic class, try and obtain the
exact class. Pass this back to the jit to unblock some types of inlines.

Also refactor how information is passed during devirtualization in
anticipation of follow on work to devirtualize default interface methods.
Because there are now multiple inputs and outputs, convey everthing
using a struct.

Resolves#38477.

Rattenkrieg and EgorBo reacted with rocket emoji
If we devirtualize to a method on a generic class, try and obtain theexact class. Pass this back to the jit to unblock some types of inlines.Also refactor how information is passed during devirtualization inanticipation of follow on work to devirtualize default interface methods.Because there are now multiple inputs and outputs, convey everthingusing a struct.Resolvesdotnet#38477.
@Dotnet-GitSync-BotDotnet-GitSync-Bot added the area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labelDec 3, 2020
@AndyAyersMS
Copy link
MemberAuthor

@davidwrighton PTAL

cc @dotnet/jit-contrib@Rattenkrieg

bool allowDevirt =
IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
&&IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
&&IsInSameVersionBubble(pCallerAssembly, pExactMT->GetAssembly());
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Not sure if this change makes sense; for an instantiation which assembly is returned?

Assuming this does make sense, if the exact class would block devirt we might try checking again with the shared class...?

Copy link
Member

Choose a reason for hiding this comment

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

GetAssembly is not affected by instantiation, but this change loses track of the R2R protection. Instead of usingpExactMT should bepObjMT

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Ah, right. We need to check that the full inheritance chain is in the bubble.

@AndyAyersMS
Copy link
MemberAuthor

Not many hits here per PMI. Could be something else is still blocking optimization in places.

Total bytes of delta: 357 (0.00% of base)    diff is a regression.Top file regressions (bytes):         146 : System.Security.Cryptography.X509Certificates.dasm (0.09% of base)         143 : System.ComponentModel.Composition.dasm (0.04% of base)          64 : System.Windows.Extensions.dasm (0.41% of base)          30 : FSharp.Core.dasm (0.00% of base)          22 : Microsoft.VisualBasic.Core.dasm (0.00% of base)           3 : System.Text.Json.dasm (0.00% of base)Top file improvements (bytes):         -36 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.00% of base)         -15 : Microsoft.CodeAnalysis.CSharp.dasm (-0.00% of base)8 total files with Code Size differences (2 improved, 6 regressed), 260 unchanged.Top method regressions (bytes):         132 ( 1.97% of base) : System.ComponentModel.Composition.dasm - ExportProvider:GetExportsCore(String):IEnumerable`1:this (14 methods)          64 (12.70% of base) : System.Windows.Extensions.dasm - X509Certificate2UI:SelectFromCollectionHelper(X509Certificate2Collection,String,String,int,long):X509Certificate2Collection          38 ( 3.71% of base) : System.Security.Cryptography.X509Certificates.dasm - ChainPal:BuildChain(bool,ICertificatePal,X509Certificate2Collection,OidCollection,OidCollection,int,int,X509Certificate2Collection,int,DateTime,TimeSpan,bool):ChainPal          36 ( 5.79% of base) : System.Security.Cryptography.X509Certificates.dasm - CertificatePal:FilterPFXStore(ReadOnlySpan`1,SafePasswordHandle,int):SafeCertContextHandle          32 (10.19% of base) : System.Security.Cryptography.X509Certificates.dasm - ChainPal:GetChainEngine(int,X509Certificate2Collection,bool):SafeChainEngineHandle          30 (16.39% of base) : FSharp.Core.dasm - StringModule:Concat(String,IEnumerable`1):String          30 ( 6.20% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:FindCore(int,long,Func`2):this          17 ( 2.60% of base) : System.Security.Cryptography.X509Certificates.dasm - StorePal:FromBlobOrFile(ReadOnlySpan`1,String,SafePasswordHandle,int):StorePal          15 (23.81% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:Dispose():this          15 (25.42% of base) : System.Security.Cryptography.X509Certificates.dasm - StorePal:Dispose():this          15 (20.55% of base) : System.Security.Cryptography.X509Certificates.dasm - StorePal:MoveTo(X509Certificate2Collection):this          11 ( 4.07% of base) : Microsoft.VisualBasic.Core.dasm - FileSystem:get_Drives():ReadOnlyCollection`1          11 ( 1.95% of base) : Microsoft.VisualBasic.Core.dasm - FileSystem:FindInFiles(String,String,bool,int,ref):ReadOnlyCollection`1          11 ( 2.22% of base) : System.ComponentModel.Composition.dasm - ExportProvider:GetExports(Type,Type,String):IEnumerable`1:this           3 ( 9.09% of base) : System.Text.Json.dasm - ObjectConverter:ReadWithQuotes(byref):Object:thisTop method improvements (bytes):         -52 (-5.65% of base) : System.Security.Cryptography.X509Certificates.dasm - CertificatePal:FromBlobOrFile(ReadOnlySpan`1,String,SafePasswordHandle,int):ICertificatePal         -21 (-23.33% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - EmbeddedTypesManager:VerifyNotFrozen():this         -15 (-1.51% of base) : Microsoft.CodeAnalysis.CSharp.dasm - PEModuleBuilder:ValidateReferencedAssembly(AssemblySymbol,AssemblyReference,DiagnosticBag):this         -15 (-1.20% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - PEModuleBuilder:ValidateReferencedAssembly(AssemblySymbol,AssemblyReference,DiagnosticBag):thisTop method regressions (percentages):          15 (25.42% of base) : System.Security.Cryptography.X509Certificates.dasm - StorePal:Dispose():this          15 (23.81% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:Dispose():this          15 (20.55% of base) : System.Security.Cryptography.X509Certificates.dasm - StorePal:MoveTo(X509Certificate2Collection):this          30 (16.39% of base) : FSharp.Core.dasm - StringModule:Concat(String,IEnumerable`1):String          64 (12.70% of base) : System.Windows.Extensions.dasm - X509Certificate2UI:SelectFromCollectionHelper(X509Certificate2Collection,String,String,int,long):X509Certificate2Collection          32 (10.19% of base) : System.Security.Cryptography.X509Certificates.dasm - ChainPal:GetChainEngine(int,X509Certificate2Collection,bool):SafeChainEngineHandle           3 ( 9.09% of base) : System.Text.Json.dasm - ObjectConverter:ReadWithQuotes(byref):Object:this          30 ( 6.20% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:FindCore(int,long,Func`2):this          36 ( 5.79% of base) : System.Security.Cryptography.X509Certificates.dasm - CertificatePal:FilterPFXStore(ReadOnlySpan`1,SafePasswordHandle,int):SafeCertContextHandle          11 ( 4.07% of base) : Microsoft.VisualBasic.Core.dasm - FileSystem:get_Drives():ReadOnlyCollection`1          38 ( 3.71% of base) : System.Security.Cryptography.X509Certificates.dasm - ChainPal:BuildChain(bool,ICertificatePal,X509Certificate2Collection,OidCollection,OidCollection,int,int,X509Certificate2Collection,int,DateTime,TimeSpan,bool):ChainPal          17 ( 2.60% of base) : System.Security.Cryptography.X509Certificates.dasm - StorePal:FromBlobOrFile(ReadOnlySpan`1,String,SafePasswordHandle,int):StorePal          11 ( 2.22% of base) : System.ComponentModel.Composition.dasm - ExportProvider:GetExports(Type,Type,String):IEnumerable`1:this         132 ( 1.97% of base) : System.ComponentModel.Composition.dasm - ExportProvider:GetExportsCore(String):IEnumerable`1:this (14 methods)          11 ( 1.95% of base) : Microsoft.VisualBasic.Core.dasm - FileSystem:FindInFiles(String,String,bool,int,ref):ReadOnlyCollection`1Top method improvements (percentages):         -21 (-23.33% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - EmbeddedTypesManager:VerifyNotFrozen():this         -52 (-5.65% of base) : System.Security.Cryptography.X509Certificates.dasm - CertificatePal:FromBlobOrFile(ReadOnlySpan`1,String,SafePasswordHandle,int):ICertificatePal         -15 (-1.51% of base) : Microsoft.CodeAnalysis.CSharp.dasm - PEModuleBuilder:ValidateReferencedAssembly(AssemblySymbol,AssemblyReference,DiagnosticBag):this         -15 (-1.20% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - PEModuleBuilder:ValidateReferencedAssembly(AssemblySymbol,AssemblyReference,DiagnosticBag):this19 total methods with Code Size differences (4 improved, 15 regressed), 258813 unchanged.

Fixes the case from#38477, we now produce:

; Assembly listing for method Program:Main():int; Emitting BLENDED_CODE for X64 CPU with AVX - Windows; optimized code; rsp based frame; partially interruptible; Final local variable assignments;;  V00 OutArgs      [V00    ] (  1,  1   )  lclBlk (32) [rsp+0x00]   "OutgoingArgSpace";* V01 tmp1         [V01,T00] (  0,  0   )     ref  ->  zero-ref    class-hnd exact "NewObj constructor temp";; Lcl frame size = 40G_M24375_IG01:subrsp,40;; bbWeight=1    PerfScore 0.25G_M24375_IG02:moveax,1;; bbWeight=1    PerfScore 0.25G_M24375_IG03:addrsp,40ret;; bbWeight=1    PerfScore 1.25; Total bytes of code 14, prolog size 4, PerfScore 3.15, instruction count 4 (MethodHash=d9b8a0c8) for method Program:Main():int

Also want to look into why the jit thinks it needs to create a frame.

@AndyAyersMS
Copy link
MemberAuthor

Also want to look into why the jit thinks it needs to create a frame.

This happens because there's a newobj that we dead code, but only after lower, so the jit still thinks the method is going to make a call, and so allocates 40 bytes (8 to align the SP, and 32 for the outgoing args area).

I'm surprised we don't eliminate dead code earlier, when we first build liveness. Seems like it might pay for itself in terms of TP.

@AndyAyersMS
Copy link
MemberAuthor

I'm surprised we don't eliminate dead code earlier, when we first build liveness.

And this happens because at that point there's a use for the newobj result -- a null check. So it appears to be alive.

***** BB01STMT00000 (IL 0x000...0x00A)N005 ( 16, 16) [000003] -AC-----R---              *  ASG       ref   N004 (  1,  1) [000002] D------N----              +--*  LCL_VAR   ref    V01 tmp1         N003 ( 16, 16) [000001] --C---------              \--*  CALL help ref    HELPER.CORINFO_HELP_NEWSFASTN002 (  2, 10) [000000] H----------- arg0 in rcx     \--*  CNS_INT(h) long   0x7ffab24525c8 token***** BB01STMT00007 (IL 0x005...  ???)N002 (  2,  2) [000028] ---X--------              *  NULLCHECK byte  N001 (  1,  1) [000006] ------------              \--*  LCL_VAR   ref    V01 tmp1         ***** BB01STMT00004 (IL 0x00E...0x00F)N002 (  2,  2) [000013] ------------              *  RETURN    int   N001 (  1,  1) [000012] ------------              \--*  CNS_INT   int    1

So why can't local assertion prop get rid of this nullcheck? Looks like it does not know the newobj can't produce a null result. Ironically the nullcheck produces a non-null assertion...

fgMorphTree BB01, STMT00000 (after)               [000003] -AC--+------              *  ASG       ref                  [000002] D----+-N----              +--*  LCL_VAR   ref    V01 tmp1                        [000001] --C--+------              \--*  CALL help ref    HELPER.CORINFO_HELP_NEWSFAST               [000000] H----+------ arg0 in rcx     \--*  CNS_INT(h) long   0x7ffab24525c8 tokenfgMorphTree BB01, STMT00007 (before)               [000028] ---X--------              *  NULLCHECK byte                 [000006] ------------              \--*  LCL_VAR   ref    V01 tmp1         GenTreeNode creates assertion:               [000028] ---X--------              *  NULLCHECK byte  In BB01 New Local Constant Assertion: V01 != null index=#01, mask=0000000000000001fgMorphTree BB01, STMT00003 (before)               [000011] ------------              *  NOP       void  fgMorphTree BB01, STMT00004 (before)               [000013] ------------              *  RETURN    int                  [000012] ------------              \--*  CNS_INT   int    1

//
publicCORINFO_METHOD_STRUCT_*devirtualizedMethod;
publicuint_requiresInstMethodTableArg;
publicboolrequiresInstMethodTableArg{get{return_requiresInstMethodTableArg!=0;}set{_requiresInstMethodTableArg=value?(byte)1:(byte)0;}}
Copy link
Contributor

Choose a reason for hiding this comment

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

There is some entropy wrt passing bool flags between managed and unmanaged code in this file. So far I seeuints andbytes used. You probably copied that pattern fromCORINFO_CALL_INFO above which uses WindowsBOOL on native side. Other structs defined incorinfo.h have fields declared as c++bool.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

I noticed --@davidwrighton can you comment on that?

Copy link
Member

Choose a reason for hiding this comment

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

Yes,bool isbyte in managed code andBOOL isuint in managed code. (And to be pedantic, VARIANT_BOOL is ushort in managed code, but just don't use that type.) Due to the various alignment rules in play the code as written will function correctly on our current set of platforms, but please change the field type to byte.

@Rattenkrieg is completely correct. In a perfect world we'd standardize on bool. In fact, I'd like to see us change our c++ headers so that they are compatible with a standard set of C++ headers instead of requiring the PAL headers, but that's a much larger change that I may attempt over the holidays.

// We must ensure thatpObjMT actually implements the
// interface corresponding to pBaseMD.
if (!pDerivedMT->CanCastToInterface(pBaseMT))
if (!pObjMT->CanCastToInterface(pBaseMT))
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps this PR could be a better place to introduce/evaluatethis change

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

We can do that by amending your PR, or as a subsequent PR.

Hopefully what I've done here sets things up so that change is more straightforward.

Rattenkrieg reacted with thumbs up emoji
@AndyAyersMS
Copy link
MemberAuthor

One test failure to investigate...

@Rattenkrieg
Copy link
Contributor

One test failure to investigate...

I guess this one

Regressions/coreclr/15650/interfacecctor/interfacecctor.sh [FAIL]

dotnet/coreclr#16340
I've also stumbled upon this. I don't have access to my home machine atm but I remember that resulting assembly was like

moveax,0      ; s_resultret

my guess that we should not inline constructor body when class has beforefieldinit.

@AndyAyersMS
Copy link
MemberAuthor

The bug was that we were failing to find the exact context because for DIMs the class can't be found by searching the inheritance chain. So the exact context was null and the context value 1 (created from null by MAKE_CLASSCONTEXT) has a special meaning which caused the jit to bypass the class init check.

Now when we have that case we will just use the class associated with the method...

@Rattenkrieg
Copy link
Contributor

@AndyAyersMS how did you managed to have jit diffs while having changes on vm side (coreclr.dll)? See very last line ofthis comment Do you run a patchedjit-diff like I do, or is there a way to link coreclr lib statically?

@AndyAyersMS
Copy link
MemberAuthor

I run jit-diffs twice, one for the base and one for the diff, and then jit-analyze to compare the two...

@AndyAyersMS
Copy link
MemberAuthor

AndyAyersMS commentedDec 3, 2020
edited
Loading

The bug was that we were failing to find the exact context

Likely need to make a matching fix in crossgen2...

[edit: actually I think crossgen2 is ok for now becauseFindMethodOnTypeWithMatchingTypicalMethod checks for the non-generic case up front, so it won't walk the hierarchy].

@AndyAyersMS
Copy link
MemberAuthor

Also want to look into why the jit thinks it needs to create a frame.
...
Looks like it does not know the newobj can't produce a null result

I have prototyped a fix where the jit will no longer create a partial frame (master...AndyAyersMS:NonNullNewAssertion). However, like many assertion prop changes, it also has a downside because it may eliminate other useful assertions. Overall jit-diff impact is small so probably not worth pursuing; per PMI:

16 total methods with Code Size differences (10 improved, 6 regressed), 258816 unchanged.

It might be more surgical to fix this problem by resetting the outgoing arg size accounting before running lower, but again that probably has minimal impact.

@AndyAyersMS
Copy link
MemberAuthor

@davidwrighton any chance you can look this over?

Copy link
Member

@davidwrightondavidwrighton left a comment

Choose a reason for hiding this comment

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

The R2R and bool changes are needed, but otherwise I like the change.

//
publicCORINFO_METHOD_STRUCT_*devirtualizedMethod;
publicuint_requiresInstMethodTableArg;
publicboolrequiresInstMethodTableArg{get{return_requiresInstMethodTableArg!=0;}set{_requiresInstMethodTableArg=value?(byte)1:(byte)0;}}
Copy link
Member

Choose a reason for hiding this comment

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

Yes,bool isbyte in managed code andBOOL isuint in managed code. (And to be pedantic, VARIANT_BOOL is ushort in managed code, but just don't use that type.) Due to the various alignment rules in play the code as written will function correctly on our current set of platforms, but please change the field type to byte.

@Rattenkrieg is completely correct. In a perfect world we'd standardize on bool. In fact, I'd like to see us change our c++ headers so that they are compatible with a standard set of C++ headers instead of requiring the PAL headers, but that's a much larger change that I may attempt over the holidays.

bool allowDevirt =
IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
&&IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
&&IsInSameVersionBubble(pCallerAssembly, pExactMT->GetAssembly());
Copy link
Member

Choose a reason for hiding this comment

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

GetAssembly is not affected by instantiation, but this change loses track of the R2R protection. Instead of usingpExactMT should bepObjMT

@AndyAyersMSAndyAyersMS merged commitea35f6a intodotnet:masterDec 5, 2020
@AndyAyersMSAndyAyersMS deleted the ExactContextAfterDevirt branchDecember 5, 2020 16:33
@ghostghost locked asresolvedand limited conversation to collaboratorsJan 4, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

@davidwrightondavidwrightondavidwrighton approved these changes

+1 more reviewer

@RattenkriegRattenkriegRattenkrieg left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

Archived in project

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Compute precise generic context after de-virtualization

4 participants

@AndyAyersMS@Rattenkrieg@davidwrighton@Dotnet-GitSync-Bot

[8]ページ先頭

©2009-2025 Movatter.jp