DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. De-Virtualization in CoreCLR: Part II

De-Virtualization in CoreCLR: Part II

How can you actually allow CLR to handle various methods and calls depending on exactly what kind of call you are doing?

Oren Eini user avatar by
Oren Eini
·
May. 03, 17 · Tutorial
Like (0)
Save
Tweet
Share
2.47K Views

Join the DZone community and get the full member experience.

Join For Free

In my previous post, I discussed how the CLR is handling various method calls, depending on exactly what we are doing (interface dispatch, virtual method call, and struct method call).

That was all fun and games, but how can we actually practice this? Let's take a look at a generic method and how it is actually translated to machine code:

Run<IActor>( ... ) ;
/*
 sub         rsp,28h  
 mov         rcx,r8  
 mov         r11,7FFACA010020h  
 cmp         dword ptr [rcx],ecx  
 call        qword ptr [r11]  
 nop  
 add         rsp,28h  
 ret  
*/


Run<ActorStruct>(...);
/*
 sub         rsp,28h  
 mov         rcx,27AB5E33068h  
 mov         rcx,qword ptr [rcx]  
 call        00007FFACA160750  
 nop  
 add         rsp,28h  
 ret  
*/

In the case of an interface, we got through the standard virtual stub to dispatch the method. In the case of a struct, the JIT was smart enough to inline the generic call.

I’ll let that sink in for a second. Using a struct generic argument, we were able to inline the call.

Remember the previous post when we talked about the cost of method dispatch, in the number of instructions, in the number of memory jumps and references? We now have a way to replace those invocation costs with inlinable code.

When is this going to be useful? This technique is most beneficial when we are talking about code that is used a lot and is relatively small/efficient already, to the point where the cost of calling it is a large part of the execution time.

One situation that pops to mind that answer just this scenario is getting the hash code and equality checks in a dictionary. The number of such calls that we have is in the many billions per second, and the cost of indirection here is tremendous. We have our own dictionary implementation (with different default and design guideline than the default one), but one who is also meant to be used with this approach.

In other words, instead of passing an EqualityComparer instance, we use an EqualityComparer generic parameter. And that allows the JIT to tune us to the Nth degree, allow us to inline the hash/equals calls. That means that in a very hot code path, we can drastically reduce costs.

Data structure Dictionary (software) POST (HTTP) Execution (computing) Memory (storage engine) Interface (computing) Implementation Machine Common Language Runtime

Published at DZone with permission of Oren Eini, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Simulating and Troubleshooting StackOverflowError in Kotlin
  • Efficiently Computing Permissions at Scale: Our Engineering Approach
  • 5 Tips for Optimizing Your React App’s Performance
  • The Enterprise, the Database, the Problem, and the Solution

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: