Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple devirtualization #9230

Merged
merged 2 commits into from Mar 2, 2017

Conversation

@AndyAyersMS
Copy link
Member

commented Jan 31, 2017

Devirtualize calls where the this object type at a call site
is a subtype of the type described at the call site. Currently learns
types from local and arg references and a subset of other operators.

Will devirtualize if either the class or method is final (sealed in C#),
or if the type is known exactly (eg from a newobj).

Devirtualization is run twice, once during importation, and again in a
limited way after inlinining. Calls devirtualized during importation are
are subsequently eligible for inlining. Calls devirtualized during inlining
currently cannot be inlined.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Jan 31, 2017

Marking no merge for now since this is work in progress.

This impacts ~267 methods in System.Private.CoreLib,. 453 sites are devirtualized. No hits in other assemblys in jit-diff, presumably because of R2R restrictions, though I have yet to dig in deeper. Simple jitted test cases show expected results.

Particular areas for review: implementation of the jit interface call and the fragile way that call related info is updated.

@jkotas, @JosephTremoulet PTAL
cc @dotnet/jit-contrib

Related issues: #1166, #8772


// If we have a virtual call, is the class of 'this' a subtype of
// the class of the method? If so perhaps we can devirtualize.
if ((call->gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_VTABLE)

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 1, 2017

Member

You should also do this for CORINFO_VIRTUALCALL_STUB. It is used for interface calls under JIT and fragile NGen, and for all virtual calls under R2R. Thus, you should see some hits for R2R once you do that.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 2, 2017

Author Member

Have this sort of working, and yes I'm seeing it kick in for R2R code.

}

// If the objClass is sealed (final), then we may be able to devirtualize.
const DWORD objClassAttribs = info.compCompHnd->getClassAttribs(objClass);

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 1, 2017

Member

It should be cheaper (less VM/EE calls) and cleaner to let the VM do all these checks that are pre-reqs for devirtualization.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 2, 2017

Author Member

Agreed. I'll refactor to consolidate stuff on the VM side after I get a bit more functionality in place.

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

Are you still planning to do this?

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Mar 1, 2017

Author Member

Thinking of leaving things as they are now -- a few checks (eg the one for __Canon) were moved to the VM side, but a number remain on the jit side -- notably the attribute checks for final/sealed methods and classes.

Seemed logical to me to keep the policy decisions on the jit side and have the VM deal with correctness/servicing, which more or less dictates the current setup. Otherwise the jit has to pass in a bit more state (for instance, is the type known exactly) and get back more state (whether the target is known exactly).

Some of the jit-side checks will be removed in future work, eg interface call devirtualization.

{
CORINFO_METHOD_HANDLE result;

JIT_TO_EE_TRANSITION();

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 1, 2017

Member

You do not need this if you just forwarding to other JIT/EE interface method.

CORINFO_CLASS_HANDLE implementingClass
);

CORINFO_METHOD_HANDLE resolveVirtualMethodExact(

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 1, 2017

Member

It would be useful to have some comments what these methods do. (In particular, what's the difference between them.)

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 2, 2017

Author Member

Sure. This is the shim layer header for SPMI, so I'll put something cursory here and something more detailed over in corinfo.h

// MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
_ASSERTE(pMT->IsRestored() && pMT->IsFullyLoaded());

MethodDesc* pMD = pMT->GetMethodDescForSlot(slot);

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 1, 2017

Member

For R2R, this will also need the version bubble check.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 2, 2017

Author Member

Are you saying the current approach (where the jit calls canInline on the resulting method handle) is insufficient?

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 2, 2017

Member

canInline should work, but it is too pessimistic check and makes the optimization order dependent because of the noinlining hint is cached. I do not think you should be using canInline to gate it.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 2, 2017

Author Member

Ah, right. I have comments about the unfortunate impact of the noinline hint; this would be a good way to get past it.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 3, 2017

Author Member

Seems like I can maybe use getMethodBeingCompiled() for this? Something like:

    // Allow devirtialization if jitting, or if prejitting and the
    // method being jitted and the devirtualized method are in the
    // same versioning bubble.
    if (!IsCompilingForNGen() || IsInSameVersionBubble(getMethodBeingCompiled(), pMD))
    {
        result = (CORINFO_METHOD_HANDLE) pMD;
    }

Otherwise I need to pass in another method handle.

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 3, 2017

Member

Yes, this should work.

JIT_TO_EE_TRANSITION();

result = resolveVirtualMethodExact(methodHnd, derivedClass);

This comment has been minimized.

Copy link
@briansull

briansull Feb 2, 2017

Contributor

Why do we have two methods here?

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 2, 2017

Author Member

I was matching jit interface changes from .Net Native. It looks like I may not need both versions.

This comment has been minimized.

Copy link
@davidwrighton

davidwrighton Feb 24, 2017

Member

On UTC the resolveVirtualMethod canonicalize's its result in most cases, but resolveVirtualMethodExact does not. This is used to handle the inlining of generic dictionary cell usage into the outer method. Given that RyuJit has a different model for handling shared generics that can't do the inlining anyways, this is probably ok. I would suggest only implementing the resolveVirtualMethod api, and not implementing resolveVirtualMethodExact. (This is simply done, as the implementation below is effectively the same as resolveVirtualMethod should be returning, but isn't quite the same as what resolveVirtualMethodExact would return in ProjectN.)

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 3, 2017

Could not repro release crossgen failure at b334a7f; wonder if I need to rebase to hit it...?

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 3, 2017

Failures in 56f702a are missing null checks; looks like at least some of the vcall stubs do implicit null checking, which will now need to be made explicit. Not sure if I should enable this for all the stub devirts or just a subset; for now I'll turn it on for all.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 4, 2017

Same tests failed again in 0d17370; serves me right for jumping to the conclusion that it was stub null checks at fault. Will debug locally this time...

return;
}

// Do we know anything about the type of the 'this'?

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 6, 2017

Contributor

Have you looked at what we do with (constrained) callvirt on value types? Not sure what shape those are in when they hit this code, but presumably they'd make the exact type easier to find...

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 6, 2017

Author Member

Yes, we will (always?) see an upstream Box and can work out the type from there.

However I will probably leave this as future work since it would also be nice to optimize away the boxing at the same time.

}

// Fetch attributes and do more vetting of the method. In general,
// if we can't inline, we won't devirtualize.

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 6, 2017

Contributor

Not clear how the comment relates to the code. Did you mean to check for some inline-blocking attributes here?

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 6, 2017

Author Member

This is a stale comment. I used to call canInline but have since moved the relevant checks to the VM side.


if (objClassIsFinal || derivedMethodIsFinal)
{
JITDUMP("!!! Inlining ok, no restrictions, final; can devirtualize\n");

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 6, 2017

Contributor

I'm confused again by the reference to inlining.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 6, 2017

Author Member

Also a stale comment.

}
#endif

// Need to update call info too. This is fragile

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 6, 2017

Contributor

Do you think we could run these checks upstream, at the point where we're calling getCallInfo today? Then the callInfo wouldn't be mutating on us, and importCall could set these other flags on the call node as usual.

In fact, since you're already intending to push a number of these checks over to the VM, I'm wondering if we could end up with an interface where getCallInfo just takes an additional parameter which is the most-derived "thisPtr" type that the jit can determine...

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 6, 2017

Author Member

This is one area I'm still experimenting with.

I don't like the idea of patching the call info or the various context handles, and it seems like the patching may get more complex when extending this to support shared generics.

But I am not sure we can anticipate all the info we might need early.

For instance, I'd like to call back into the devirtualization code during inlining or even later on during optimization, as we potentially learn more about types.

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 6, 2017

Contributor

Right now you have it coded up as

  1. (if we can) get an updated CORINFO_METHOD_HANDLE (else abort)
  2. update the GenTreeCall node to the new target (returned from 1) and flags (inferred from change to nonvirtual call)
  3. update the CORINFO_CALL_INFO

I think you might be happier to switch the second two:

  1. (if we can) get an updated CORINFO_METHOD_HANDLE (else abort)
  2. update the CORINFO_CALL_INFO
  3. update the GenTreeCall node to the new target (returned from 1) and flags (returned from 2)

because

  1. You can code the changes to the GenTreeCall as a function of the CORINFO_CALL_INFO, so you may be able to share that code with the importer upstream and optimizations downstream
  2. You can separate the concerns of determining what the new info/attributes should be (which would be the part computing the new CORINFO_CALL_INFO) and determining which fields on a GenTreeCall need to change in response to devirtualization (which could be pretty mechanical). Currently you have a mix of those things in your second and third steps.
  3. It would line up with the desire to move some of this to the VM side, since we're used to the VM populating the CORINFO_CALL_INFO

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 7, 2017

Author Member

Wanted to get the post-inline case implemented so whatever approach I finally settle on handles both importer and inliner variants smoothly.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 7, 2017

So with latest updates the jit can devirtualize based on actual return types. For example, in the "sealed default" pattern from #9276:

using System;

public class Base
{
    public virtual int Foo() { return 33; }
    static BaseSealed s_Default = new BaseSealed();
    public static Base Default => s_Default;
}

sealed class BaseSealed : Base {}

public class Test
{
    public static int Main()
    {
        Base b = Base.Default;
        int x = b.Foo();
        return (x == 33 ? 100 : -1);
    }
}

the jit will devirtualize the call to Foo in Main.

Inlining Foo is a bit trickier; my current thinking is that we should split trees in the importer at all virtual calls to make some of the logistics simpler later on.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 7, 2017

Thinking those ARM64 failures may be related to #9375.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 7, 2017

Latest change ends up triggering a lot of non-crossgen fatal R2R errors of the form:

Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)) while compiling method Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetBinderFactory

suspect something is off either with the devirt update to R2R calls or the dependence tracking.

(Update: this was from a private change I never pushed to the fork, so disregard the details here. R2R methods are still failing to encode in some cases, see below).

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 7, 2017

Still working through this. Was thrown off by the fact that in R2R mode crossgen will throw/catch for "expected" failures.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 7, 2017

With the 68af9f2 changes we lose 68 methods in R2R images, running into the "Method entrypoint cannot be encoded" notimpl in ZapInfo::getFunctionEntryPoint. So presumably after devirt the entry point info is not getting updated properly and the jit incorrectly tries to make a direct call.

I haven't been able to find a way to re-invoke getCallInfo for the new call target without making things worse. Have tried consing up a resolved token using the class/method handles I already have, as well as trying to recreate the information needed to call resolveToken; both just lead to more problems.

@jkotas any ideas?

Assembly* pCallerAssembly = pCallerModule->GetAssembly();
Assembly* pDevirtAssembly = pDevirtModule->GetAssembly();

if (pCallerAssembly == pDevirtAssembly)

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 7, 2017

Member

This should be just (edited):

if (IsReadyToRunCompilation())
{
    Assembly * pCallerAssembly = m_pMethodBeingCompiled->GetModule()->GetAssembly();
    allowDevirt = IsInSameVersionBubble(pCallerAssembly , pDevirtModule->GetModule()->GetAssembly()) && 
                          IsInSameVersionBubble(pCallerAssembly , pMT->GetAssembly());
}
else
{
   allowDevirt = true;
}

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 8, 2017

Author Member

Just to make sure I understand: this extra check is for the case where the class the jit initially identifies as the object type is a subclass of the class that introduces the method, right?

If so, I though I had that covered over on the jit side by mapping back from the devirtualized method to the introducing class, and passing the implementing class to resolveVirtual.

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 8, 2017

Member

this extra check is for the case where the class the jit initially identifies as the object type is a subclass of the class that introduces the method, right?

Right.

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 8, 2017

Member

I have not realized that it may be handled in the JIT side. It may be good idea to do the version bubble check defensively here anyway.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 8, 2017

Author Member

Agreed, will update.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 8, 2017

Author Member

Also just to be clear -- no version bubble checks for ngen?

This comment has been minimized.

Copy link
@jkotas

jkotas Feb 8, 2017

Member

Right. Fragile NGen is like JIT.

@jkotas

This comment has been minimized.

Copy link
Member

commented Feb 8, 2017

@jkotas any ideas?

You can remove the TODO+THROW from ZapInfo::getFunctionEntryPoint. It is possible it will just work because of the getFunctionFixedEntryPoint next to it does not have it.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 8, 2017

Removing the throw leads to an AV in ZapMethodEntryPointTable::GetMethodEntryPoint on since m_pImage->m_pMethodEntryPoints is null.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 10, 2017

@jkotas looks like for R2R it is happy if I reinvoke getCallInfo, this triggers a bunch of stuff on the zap side.
I have to fake up a resolved token but that doesn't seem all that tricky, at least for for non-shared cases.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 10, 2017

Snip from the latest jit-diff stats. It would be really nice if jit-diff would also report how many methods remained unchaged; I'm curious what % of methods this change impacts.

The 41 methods that get lost are still a concern. Looks like most of then now bail out in R2R with: Runtime method access checks not supported. Could be a bug in devirt, since overrides should be just as accessible as the base methods. Will dig in deeper...

Total bytes of diff: -30127 (-0.21 % of base)
    diff is an improvement.

Total byte diff includes -18436 bytes from reconciling methods
        Base had   41 unique methods,    18571 unique bytes
        Diff had    1 unique methods,      135 unique bytes
...
2051 total methods with size differences (1695 improved, 356 regressed).
@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 24, 2017

Rebased, squashed commits down again into two: one for runtime side and one for jit side.

Incorporate some feedback: remove the unused interface method, add the check for __Canon over to the runtime side and remove the overly general check on the jit side.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 25, 2017

Think I cleared up the problems that were causing loss of some R2R methods. No losses seen in the current jit-diff framework set.

@dotnet-bot test Windows_NT Checked r2r

@AndyAyersMS AndyAyersMS force-pushed the AndyAyersMS:SimpleDevirtualization branch from ac18d9a to 59136f8 Feb 28, 2017
@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2017

Pushed an update so the jit interface should be in final form for merging. New GUID and all.
Am going to remove the no merge tag and ask for one last round of review.

@JosephTremoulet PTAL
cc @dotnet/jit-contrib

FYI this will require a coordinated update for desktop. I'll get that ready and kick off desktop testing.

@AndyAyersMS AndyAyersMS force-pushed the AndyAyersMS:SimpleDevirtualization branch from 2328df3 to 40b1841 Feb 28, 2017
@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2017

Another forced update to fix formatting, polish the commit text, and remove an unused declaration.

@benaadams

This comment has been minimized.

Copy link
Collaborator

commented Feb 28, 2017

For example, in the "sealed default" pattern from #9276: ... the jit will devirtualize the call to Foo in Main.

@AndyAyersMS this still true at current iteration? i.e. is it worth reactivating that PR?

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2017

Yes, it will devirtualize (but not inline, yet) -- provided you use the property directly when you make calls.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2017

CentOS failure (log) was in a PAL test; added note to possibly related #8321. Will retry.

@dotnet-bot retest CentOS7.1 x64 Debug Build and Test

Copy link
Contributor

left a comment

Overall looks good, just a few questions/comments.

// If the parent of the GT_RET_EXPR is a virtual call,
// devirtualization is attempted. This should only succeed in the
// successful inline case, when the inlinee's return value
// expression provides a better type then the declared type of the

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

typo: then -> than

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 28, 2017

Author Member

Fixed and reworded some neighboring text....

lvaInitVarDsc(varDsc, varNum, strip(corInfoType), typeHnd, localsSig, &info.compMethodInfo->locals);

varDsc->lvPinned = ((corInfoType & CORINFO_TYPE_MOD_PINNED) != 0);
varDsc->lvOnFrame = true; // The final home for this local variable might be our local stack frame

if (strip(corInfoType) == CORINFO_TYPE_CLASS)

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

Does this get the same CORINFO_CLASS_HANDLE that the call to getArgType just above got and passed to lvaInitVarDsc? Is so, maybe move this logic down into lvaInitVarDsc?

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 28, 2017

Author Member

getArgType doesn't set the class handle for ref types. It is mainly used to establish the representation of the type and not the identity of a type.

@@ -550,6 +558,11 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)

lvaInitVarDsc(varDsc, varDscInfo->varNum, strip(corInfoType), typeHnd, argLst, &info.compMethodInfo->args);

if (strip(corInfoType) == CORINFO_TYPE_CLASS)

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

Same as above regarding moving this into lvaInitVarDsc

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 28, 2017

Author Member

Same reason as above here.

// Virtual calls in IL will always "invoke" the base class method.
//
// This transformation looks for evidence that the type of 'this'
// in the call is a final class or would invoke a final method, and

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

nit: or is exact

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 28, 2017

Author Member

Fixed

// if that and other safety checks pan out, modifies the call and
// the call info to create a direct call.
//
// This transformation is done in the importer and not in some

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

This paragraph reads like we only call this before inline, but the same method gets called for late devirtualization, right?

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 28, 2017

Author Member

Yes, I need to update the comment.

}

// If the objClass is sealed (final), then we may be able to devirtualize.
const DWORD objClassAttribs = info.compCompHnd->getClassAttribs(objClass);

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

Are you still planning to do this?

// Virtual calls include an implicit null check, which we may
// now need to make explicit. Not sure yet if we can restrict
// this to just a subset or need to do it for all cases, so
// will do it for all unless we know the object is not null.

This comment has been minimized.

Copy link
@JosephTremoulet

JosephTremoulet Feb 28, 2017

Contributor

Supposing we could restrict this to a subset, would that be up in the code that's setting nullCheck, or down here? If it would be down here, maybe better to invert the sense of the bool and name it knownNotNull or something rather than nullCheck.

This comment has been minimized.

Copy link
@AndyAyersMS

AndyAyersMS Feb 28, 2017

Author Member

When I wrote this I was thinking there might be a locally identifiable subset of calls that would not need checks -- one that could be identified by just looking at the call and its properties. But I no longer believe this.

So, suppressing the check requires some sort of analysis of the 'obj' and doing anything nontrivial here seems risky since we are in the middle of importing.

The string case is trivial so we might as well keep it. I suppose we could also rely on newobj not returning null.

Inverting the sense of the bool looks like a good suggestion since the common case is that we will add a null check.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2017

Updated to address feedback.

Added a 4.6 compat stub (needed for clean desktop builds).

Removed the distribution table showing which operators lead to type loss. The information is stale and arguably should live somewhere else.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2017

Haven't hit any issues in desktop testing, though have only run a subset because the GUID/interface change makes getting the full test of tests running a challenge.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Mar 1, 2017

Waiting for builds with #9869 to make their way over to CoreFx before merging this. Believe they should be in the beta25101-02 build of CoreCLR.

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Mar 1, 2017

Actually, watching dotnet/corefx#16574

@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Mar 2, 2017

Local CoreFx changes with these changes look good.

@briansull

This comment has been minimized.

Copy link
Contributor

commented Mar 2, 2017

LGTM

AndyAyersMS added 2 commits Jan 30, 2017
Add new method to jit interface so the jit can determine what derived
method might be called for a given base method, derived class pair.

Implement support in the VM and in other places (zap, spmi).
Devirtualize calls where the this object type at a call site
is a subtype of the type described at the call site. Currently learns
types from local and arg references and a subset of other operators.

Will devirtualize if either the class or method is final (sealed in C#),
or if the type is known exactly (eg from a newobj).

Devirtualization is run twice, once during importation, and again in a
limited way after inlinining. Calls devirtualized during importation are
are subsequently eligible for inlining. Calls devirtualized during inlining
currently cannot be inlined.
@AndyAyersMS

This comment has been minimized.

Copy link
Member Author

commented Mar 2, 2017

Am going to push one more force update that will reorder things so the non-jit changes are back together in one commit and the jit changes in another.

@AndyAyersMS AndyAyersMS force-pushed the AndyAyersMS:SimpleDevirtualization branch from dd298a8 to 393ee92 Mar 2, 2017
@AndyAyersMS AndyAyersMS merged commit e0637ea into dotnet:master Mar 2, 2017
14 checks passed
14 checks passed
CentOS7.1 x64 Debug Build and Test Build finished.
Details
FreeBSD x64 Checked Build Build finished.
Details
Linux ARM Emulator Cross Debug Build Build finished.
Details
Linux ARM Emulator Cross Release Build Build finished.
Details
OSX x64 Checked Build and Test Build finished.
Details
Ubuntu x64 Checked Build and Test Build finished.
Details
Ubuntu x64 Formatting Build finished.
Details
Windows_NT arm Cross Debug Build Build finished.
Details
Windows_NT arm Cross Release Build Build finished.
Details
Windows_NT arm64 Cross Debug Build Build finished.
Details
Windows_NT x64 Debug Build and Test Build finished.
Details
Windows_NT x64 Formatting Build finished.
Details
Windows_NT x64 Release Priority 1 Build and Test Build finished.
Details
Windows_NT x86 Checked Build and Test Build finished.
Details
@AndyAyersMS AndyAyersMS referenced this pull request Mar 2, 2017
5 of 23 tasks complete
@karelz karelz modified the milestone: 2.0.0 Aug 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.