Uh oh!
There was an error while loading. Please reload this page.
NativeAOT: devirtualize isinst/castclass for monomorphic cases - #80831
Conversation
ghost
commented
Jan 19, 2023
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch, @kunalspathak Issue DetailsCloses #80828 Luckily, we already have JIT-EE API to get exact list of implementations/subclasses for given type. interfaceIMyInterface{}// this interface has a single implementationclassProgram:IMyInterface{staticvoidMain(){Case1(newProgram());Case2(newProgram());}[MethodImpl(MethodImplOptions.NoInlining)]staticboolCase1(objecto)=>oisIMyInterface;[MethodImpl(MethodImplOptions.NoInlining)]staticIMyInterfaceCase2(objecto)=>(IMyInterface)o;}Previous NativeAOT codegen:; Method Program:Case1(System.Object):boolsubrsp,40movrdx,rcxlearcx,[(reloc)]call CORINFO_HELP_ISINSTANCEOFINTERFACEtestrax,rax setne almovzxrax,aladdrsp,40ret; Total bytes of code: 33; Method Program:Case2(System.Object):IMyInterfacesubrsp,40movrdx,rcxlearcx,[(reloc)]call CORINFO_HELP_CHKCASTINTERFACEnopaddrsp,40ret; Total bytes of code: 25New NativeAOT codegen:; Method Program:Case1(System.Object):booltestrcx,rcxje SHORT G_M13626_IG05learax,[(reloc)]cmp qword ptr [rcx],raxje SHORT G_M13626_IG05xorrcx,rcxG_M13626_IG05:xoreax,eaxtestrcx,rcx setne alret; Total bytes of code: 28; Method Program:Case2(System.Object):IMyInterfacesubrsp,40movrdx,rcxmovrax,rdxtestrax,raxje SHORT G_M12806_IG05learcx,[(reloc)]cmp qword ptr [rax],rcxje SHORT G_M12806_IG05movrcx, qword ptr [rsp+20H]call CORINFO_HELP_CHKCASTINTERFACE ;; this is used to throw InvalidCastException onlyG_M12806_IG05:nopaddrsp,40ret; Total bytes of code: 43
|
am11
commented
Jan 19, 2023
Is |
AndyAyersMS
commented
Jan 19, 2023
The code is bigger but should also be faster, since we will rarely need to call the helper (only if the cast will throw). Though I'm not quite sure why we're shuffling those registers about like we do... |
MichalStrehovsky
commented
Jan 19, 2023
Curious: if we had hot/cold splitting support in NativeAOT (#77583), would that place the |
| if (this->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && | ||
| ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_CHKCASTINTERFACE)) && | ||
| (info.compCompHnd->getExactClasses(pResolvedToken->hClass, 1, &actualImplCls) == 1) && | ||
| (actualImplCls != NO_CLASS_HANDLE) && impIsClassExact(actualImplCls)) |
There was a problem hiding this comment.
Is there any reason this optimization shouldn't kick in for any other potential EE that returns 1 from getExactClasses?
There was a problem hiding this comment.
@jakobbotsch purely throughput reasons - 2 ifs + non inlined call getExactClasses since I don't think it will be useful outside of NativeAOT anytime soon 🙂
There was a problem hiding this comment.
Seems a bit premature? If I remove the NAOT check and hack SPMI to always return 0 on replay of getExactClasses I see no significant TP differences. IMO, as the general rule (no need to change this now) we should not be sacrificing abstractions unless they have demonstrable impact.
There was a problem hiding this comment.
no strong opinion on that, will remove as part of some next PR
EgorBo
commented
Jan 19, 2023
It doesn't look like it's handled in hot/cold splitting now, but at least it's still considered as "cold" in jit |
Closes#80828
Luckily, we already have JIT-EE API to get exact list of implementations/subclasses for given type.
Previous NativeAOT codegen:
New NativeAOT codegen: