Le 29/07/2009 00:33, Attila Szegedi a écrit :
> Hi folks,
>
> I'm on vacation this and next week, which in practical terms means
> that I get to hack on things I love to hack on. So, I'm now working on
> the MOP equivalent that relies on invokedynamic. Both because I have
> time for it and also because I'm terrified I won't have anything
> interesting to report for this year's JVM Language Summit :-).
>
> I did encounter something that at first seemed like a problem, but now
> actually seems like an opportunity, and would like a confirmation I'm
> correct (or wrong, as the case may be).
>
> So, sometime in the past, bootstrap method signature was changed from
> "Object bootstrap(CallSite callSite, Object receiver, Object...
> arguments) to "CallSite bootstrap(Object caller, String methodName,
> MethodType type)". I was actually a bit terrified by this at first.
> See, the old signature actually allowed me to find the most suitable
> method to link based on the receiver (is it a POJO? Link to a POJO
> method handle? Is it a Ruby object? Link to a Ruby MH. Is it a Jython
> object? Link to a Jython MH, and so on). It basically allowed for a
> monomorphic inline cache if the final MH was also set as the target,
> actually composed in an appropriate guardWithTest() where test was
> "receiver instanceof x" and fallback was a MH that redid the whole
> linking process.
>
> Now I'm faced with the fact that I have none of this with the new
> bootstrap method signature, as all I have is the MethodType, which
> reflects the static types of arguments to a particular invokedynamic
> call site.
>
> Consider for a moment a scripting language that compiles to bytecode
> with invokedynamic. In quite a lot of cases, the static types of all
> arguments will simply be java.lang.Object, 'cause we can't know at the
> time we emit the bytecode what will the argument types be. Okay, we
> might be able - depending on the language - to discern a boolean here
> and a double there as the argument types, but that's pretty much as
> far as it gets. That's not much help in dispatch scheme that relies on
> receiver type.
>
> Then I realized that this actually made the bootstrap protocol much
> more flexible, and it should actually be viewed as an opportunity.
> Namely, my top-level composite "Dynamic Linker" (which is more or less
> what the MOP should be named with invokedynamic, or rather we could
> say that the DL is the means of implementing a MOP) could install a
> general-purpose MH that will intercept the first call, then dispatch
> to the appropriate language-specific linker based on the type of
> "this", and said linker (JRuby, Jython, Rhino, or POJO) then replaces
> the general-purpose MH as the target of the call site with a language-
> specific one plus a guard.
>
> Well, okay, I could go this direction and not even feel particularly
> bad about it, except that if I did this, then I'd force all languages
> into only having a monomorphic inline cache. Wait, you might ask,
> didn't the old signature of bootstrap methods actually force that
> anyway? Well, yes, it did, and that's exactly my point - since the new
> signature allows more flexibility in linkage, wouldn't it be blunt if
> I now took it away in an inter-language interop protocol? Actually,
> with this interop protocol, I could mandate CallSite subclasses that
> have any inline caching strategy - strictly monomorphic, monomorphic
> escalating into megamorphic, monomorphic evolving into polymorphic,
> then escalating into megamorphic, and so on. But no matter how I slice
> it it looks to me like the top-level dynamic linker that composes
> multiple language-specific linkers will impose inline caching strategy
> on the individual language linkers.
>
> I was entertaining the idea that it might be possible to go to the
> other extreme, and have the master linker get out of the way instead.
> Namely, it'd still install the general-purpose MH, but then let the
> language-specific linker (selected by the type of the actual receiver
> on the first call) install whatever call site it wishes, that can
> follow any inline caching strategy. So, if I have two language
> runtimes in my JVM, A and B, and A creates MIC call sites, and B
> creates PIC call sites, then the inline caching strategy of the call
> site will be determined by whichever object is the receiver of the
> first call at the site - if the object came from runtime A, it's a
> MIC; if it came from B, it's a PIC. Except, this wouldn't really work,
> as a PIC call site would actually be defeated by a later linker that
> installs a MIC. And anyway, we can't recreate the call site, we can
> just relink its target once it's created for the first time. So the
> behaviour would be very nondeterministic, and I don't like that, and
> to boot, this might actually not be possible under current operational
> semantics of dynamic call sites in the JVM.
>
> Either that, or different runtimes would need to know about a finite
> number of available call site types that are part of the protocol.
>
> Which actually brings a third option to the table - have few
> predefined inline caching strategies as part of the linker protocol,
> that all language runtimes would know about and be able to respect
> without stepping on each other's toes. Yes, it's a compromise, and at
> the moment and don't even see how viable it is, or what would it look
> like in technical implementation details, but it might work. It's also
> a good question who gets to decide which call site follows which
> caching strategy (gut feeling would be to say it's the language
> runtime of the caller class, of course).
>
> Or for now, just accept that a framework for inter-language linking
> will force the participating languages' linkages into a single inline
> caching strategy (monomoprhic, or optionally, monomorphic escalating
> to megamorphic). Does that sound acceptable at least to "big" dynalang
> stakeholders out there (JRuby, Jython, I'm looking at you. Rhino has
> no invokedynamic yet, but if it did, I could definitely live with a
> MIC). Do I worry too much about this?
>
> Hope this all made sense :-)
>
> Attila.
>    

Hi Attila,
in my opinion a MOP (Meta Object Protocol) imposes
that all receiver should have a method like getMOP()
that returns an object implementing the following interface:

public interface MOP {
    // return an (Object)Object
    public MethodHandle getMember(String member);
    // returns an (Object,String)Object
    public MethodHandle getMember();

    // returns an (Object)Object
    public MethodHandle getIndex(int[] index);
    // returns an (Object,int...)Object
    // i.e if indexDimension=2 returns (Object,int, int)Object
    public MethodHandle getIndex(int indexDimension);

    // returns an (Object)Object
    public MethodHandle convertTo(Class<?> anotherType);
    // returns an (Object,Class<?>)Object i.e a kind of dynamic cast
    public MethodHandle convertTo();

    // returns a MethodHandle such as mh.type == methodType
    public MethodHandle call(MethodType methodType);
    // returns a (Object, Object[])Object
    public MethodHandle call();

    // retruns a MethodHandle such as mh.type == methodType
    public MethodHandle methodCall(String name, MethodType methodType);
    // returns a (Object, Object[])Object
    public MethodHandle methodCall(String name);

    //etc.
}

All methods are paired because the former knows statically some
informations by example for getMember, getMember(String) is used
if the name of the member is statically known and the later getMember() 
is used
if the name of the member is only given at runtime.

a.m     => getMember("m")
a["m"] => getMember()

So the MOP linker is responsible for calling the MOP object corresponding to
the receiver using any cache it wants: MIC,  PIC, etc.

Given that, we will able to see how to do a better invalidation, i.e
if a MOP returns a method handle which is a guard,
and if this guard detects that an invariant of the runtime isn't an 
invariant
anymore, it will want to replace the current method handle by another one.
A real MOP should provide a way to do that.

A simple way to achieve that is to take another parameter providing
a way to invalidate a method handle and
a way to get the last method handle used (the one invalidated) if it exists.

public interface MOP {
    // return an (Object)Object
    public MethodHandle getMember(String member, MOPControl control);
    // returns an (Object,String)Object
    public MethodHandle getMember(MOPControl control);
    ...
}

public interface MOPControl {
   public MethodHandle getInvalidatorFallback();
   public MethodHandle getInvalidatedMethodHandle();
}

In that case, it will be used like this:

public class MyLanguageMOP implements MOP {
   public MethodHandle getMember(String member, MOPControl control) {
      // control.getInvalidatedMethodHandle() returns the last method handle
      // used or null, here I don't care but it will be usefull to 
implement PIC

     // this method handle will call MOP.getMember with the method handle
     // retruns by this method in case of invalidation
     MethodHandle invalidator = control.getInvalidatorFallback();

      // to get a field my language provide a method Object getField(String)
      return MethodHandles.guardWithTest(INVARIANT_TEST, GET_FIELD, 
invalidator);
   }

    private static final MethodHandle GET_FIELD =
      
MethodHandles.publicLookup().findVirtual(MyLanguageBaseObject.class, 
"getField",
        MethodType.make(Object.class, String.class));

    private static final MethodHandle INVARIANT_TEST = ...
}


There is also a case where the receiver doesn't have a method getMOP(),
in that case the MOP can consider it has a POJO and use a special POJOMOP
object for that. Or perhaps it can try to inject an interface with the 
method
getMOP() when interface injection will work.

What do you think about that ?

cheers,
Rémi

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "JVM 
Languages" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/jvm-languages?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to