On Aug 12, 2016, at 2:56 PM, Michael Haupt <michael.ha...@oracle.com> wrote:
> Hi Mark,
>> Am 05.08.2016 um 12:13 schrieb Mark Roos <mr...@roos.com 
>> <mailto:mr...@roos.com>>:
>> Good to see this.
> thanks. :-)
>> What is the philosophy for code annotations, line numbers and stack maps? 
>> Would they be some form of constant entry? 
> I recall you had asked this question at JVMLS. I think it definitely makes 
> sense to add support for these. How would you think they should be 
> represented?
> Here are some thoughts.
> First, stack maps. Leave their generation to the bytecode generation 
> framework responsible for producing the bytecode array (whichever one that 
> may be), allow for easy extraction of the map from its generation result, and 
> for passing that on to the loadCode implementation. This will require a 
> library-level representation of stack maps (inspired by Sec. 4.7.4 of the JVM 
> Spec), unless the plain class file format for them is used - which may not be 
> desirable given the convenience attempts the API is making with the constants 
> array. To maintain convenience, stack map generation could be the 
> responsibility of the loadCode implementation. This would duplicate the work 
> of generating the map, which seems rather unwelcome.

I think the right answer will involve making the verification of IM bytecodes 
simpler.  For example, if there is no invokespecial, all the nasty rules for 
that instruction go away (along with those for "new").  Frame maps are designed 
to support one-pass checking of bytecodes.  There are restrictions we can put 
on IM bytecodes that will recover the ability to perform one-pass checking, 
with implicitly derived frame maps.  In a nutshell, the first type-state wins, 
and any other type-states (e.g., from backward branches) need to match.  This 
makes it very slightly harder to generate IM bytecodes (with sometimes an extra 
checkcast for merge points), but in exchange nobody needs to mess with frame 
maps (except maybe VM internals).

This does lead me to an extra thought:  I think IM's could be given the 
capability to have multiple entry points.  This would allow a number of 
interesting applications, starting with exception handling that appeals to a 
helper object, instead of a handler table and some special verifier rules.

Immediately beyond that, although now I'm being a Mission Creep, if an IM has 
multiple entry points for exception handling, it could also use these entry 
points for frame resumption, as described by Ron Pressler in a previous JVMLS, 
and Andrey Breslav this year.  (That leads to the question of how an IM can 
yield to an suspension point, a very good question.  And something that a 
helper object can help with.  And so on.  This might help us do fibers 
experiments more quickly.)

> Annotations can be passed as a map from annotation classes to lists of 
> values. Line numbers can be passed as an int array of pairs of numbers, where 
> even indices represent start PCs, and odd indices, line numbers.

> Adding to your list, a source file association can be represented as a URL or 
> String. (Cream on top: a multiline String containing the IM's actual source 
> code.)

I hope all that logic can be wrapped up in a helper object, to be executed only 
when needed.  I.e., load quickly *with no paperwork*, and have the helper 
object figure out what happened later on, if we get asked.

interface IsolatedMethod { // reflected view of raw IM
  // recovered arguments to Lookup.loadCode:
  Lookup lookup();
  String name();
  MethodType type();
  ByteSequence bytes();  // NOTE: R/O view; same type for CONSTANT_Bytes
  List<Object> constants();

  // this has to be stuck in somehow:
  //Inspector inspector();

  interface Inspector {  // helper for "paperwork"
    String sourceFile(IsolatedMethod m);
    String className(IsolatedMethod m);
    int mapLineNumber(IsolatedMethod m, int bci);
    List<LocalVariableInfo> mapLocalVariables(IsolatedMethod m, int bci);
    List<HandlerInfo> mapExceptionHandlers(IsolatedMethod m, int bci);
    List<Class> mapFrameState(IsolatedMethod m, int bci);
    //?MethodHandleInfo methodHandleInfo(IsolatedMethod m);

> As a further addition, exceptions can be passed as a simple array or list, 
> and an exception handler table can be passed as a tuple (not in the Valhalla 
> sense, yet) of an int array of triplets of numbers representing start, end, 
> and handler PCs and of a list or array of exception classes.

Yes, exception handling is the tricky part (along with verification).  Maybe we 
could use an Inspector to help extract the details:

interface Inspector { …
  int exceptionContinuationPoint(IsolatedMethod m, int bci, Class<? extends 
Throwable> exc);

The idea would be to call the IM inspector for a continuation point.  Of 
course, that thing might throw an exception, which makes the model muddy, 
though not impossible.  Verification of the CP could be lazy, or the CP's could 
be marked up front and checked during loadCode.

There's a fiber frame system struggling to emerge here.

— John
mlvm-dev mailing list

Reply via email to