Lworld and calling convention

Karen Kinnear karen.kinnear at oracle.com
Thu Apr 19 13:27:59 UTC 2018


Roland, Frederic,

Ignoring -Xcomp - 

Do you have a sense of how often we have a method that is being compiled due
to profiling and the methods being inlined have never been interpreted or compiled?

What if the interpreter were to load all classes for the method signature as part of invocation?
Right now, any argument that is not null should already have the class loaded, so perhaps
this would not be a huge additional overhead for the first invocation of a method?

Or combine with Frederic’s proposal, and the interpreter would preload any classes in
the signature that are annotated as value types?

Then if the compiler were to check the methods it is inlining and if the signature classes have
not been loaded yet, then perform the uncommon trap - or stop inlining at that point.
Perhaps if the interpreter preloads then this becomes very rare?

One challenge I see with the javac annotation is that we still run the risk of a mismatch
between the caller and callee - if we have separate compilation and one thinks we have
a value type and the other does not.

If the caller thinks we have a value type - and we therefore preload the class, and it
is not, then ICCE - so not a problem.

If the caller thinks we have a value type and the class is a value type and the callee does not think so - 
is there a way to detect the mismatch and deopt?
Same issue if the caller thinks we do not have a value type and the callee thinks we do.

thanks,
Karen

> On Apr 18, 2018, at 3:38 PM, Frederic Parain <frederic.parain at oracle.com> wrote:
> 
> Roland,
> 
> Thank you for this summary.
> 
> Would it help to have javac to annotate which arguments are expected
> to be value classes? In this case:
>  - only classes of annotated arguments would be pre-loaded (no additional
>    pre-loading for old code)
>  - after pre-loading, if the class is a value class, the calling convention could
>    use scalarisation, otherwise argument is passed by reference
>  - arguments without the annotation would always be passed by reference
> 
> With this proposal, the calling convention would depend only on the
> information provided by javac, not on the value of the arguments being
> passed (passing null would not impact the determination of the calling
> convention).
> 
> However, I’m not sure it would solve the issue with method inlining if the
> method candidate for in-lining are not known before the compilation starts.
> 
> Fred
> 
> 
>> On Apr 5, 2018, at 11:53, Roland Westrelin <rwestrel at redhat.com> wrote:
>> 
>> 
>> I started to work on bringing the calling convention from MVT to the
>> Lworld.
>> 
>> The first problem I hit is that when adapters are generated, classes of
>> the method's signature may not have been loaded yet so it's impossible
>> to tell which argument is a value and which is not.
>> 
>> I then looked at what it would take to make adapter generation lazy. I
>> have a prototype that seems to allow for lazy generation but then the
>> question is what are the events that should trigger adapter generation?
>> 
>> Going from interpreter to compiled code (where the i2c is needed) is
>> fairly simple. We don't need the i2c until compiled code exists. We
>> already load the classes of the signature before we trigger the
>> compilation of the method so generating the adapters at that point would
>> be fine.
>> 
>> Going from compiled code to the interpreter seems much trickier. Let's
>> say we compile m(). The compiler will trim some untaken paths and inline
>> some methods so it's only possible to tell what call sites will be in
>> the compiled m() as it's being compiled or once it's compiled. There's
>> no guarantee that the classes of the signatures of these call sites are
>> loaded when the call sites are compiled because, in legacy code, null
>> may be passed for a value argument.
>> 
>> We can't load classes as we compile the method because the compiler
>> threads don't perform class loading.
>> 
>> If compiled method m() has a call site:
>> 
>> m2(v1, v2)
>> 
>> and v1 and v2 are values (from 2 different classes), that call site may
>> be compiled as:
>> 
>> m2(v1.f1, v1.f2, .., v2.f1, v2.f2, ..)
>> 
>> (passing fields) if when the call site was compiled, classes for v1 & v2
>> are loaded.
>> 
>> or:
>> 
>> m2(v1, v2.f1, v2.f2, ..)
>> 
>> (passing a reference to v1) if the class for v1 was not loaded when the
>> call site was compiled
>> 
>> or:
>> 
>> m2(v1.f1, v1.f2, .., v2)
>> 
>> if the class for v2 was not loaded when the call site was compiled
>> 
>> or:
>> 
>> m2(v1, v2)
>> 
>> if both classes were not loaded when the call site was compiled.
>> 
>> So for a single call site with 2 value arguments, there are 4 ways of
>> compiling the call site.
>> 
>> We could generate the adapters the first time the call in compiled
>> method m() is executed (at call resolution time) but then we need to
>> generate an adapter that matches how the call site was compiled. How do
>> we know which of the 4 ways of performing the call it is?
>> 
>> As code executes and classes get loaded, we might need several adapters
>> generated. Maybe some m2() call site was compiled as:
>> 
>> m2(v1, v2)
>> 
>> but then one class got loaded so another one got compiled as:
>> 
>> m2(v1, v2.f1, v2.f2, ..)
>> 
>> and then another one as:
>> 
>> m2(v1.f1, v1.f2, .., v2.f1, v2.f2, ..)
>> 
>> and we need 3 different c2i adapters.
>> 
>> Add to this, that we can't deoptimize at call resolution time because
>> compiled code only has debug info to resume execution after the call.
>> 
>> I see 2 ways forward with this. Either we eagerly load classes of
>> signatures so we can generate the adapters eagerly as is done
>> currently. Or we refuse to compile a call site for which the classes of
>> the signature are not loaded (replace the call with an uncommon trap and
>> trigger class loading?). In that case, we would sometime drop perfectly
>> good code.
>> 
>> Comments?
>> 
>> Roland.
>> 
> 




More information about the valhalla-dev mailing list