[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-mlvm-dev
Subject:    [jvm-l] Stack value extractor in Java
From:       john.r.rose () oracle ! com (John Rose)
Date:       2010-11-06 20:24:34
Message-ID: F1BCB28A-D57E-40AA-9CA5-9E08F8E78168 () oracle ! com
[Download RAW message or body]

On Nov 6, 2010, at 11:38 AM, R?mi Forax wrote:

> I've wanted to write that several times, so before doing something else,
> I want to try to convince all VM hackers that they should stop doing
> what they currently do and starts to implement a way to export
> values from the VM stack into a Java object.
> ...

Yes, JVM languages should be able to do the "deoptimization trick".  It works great \
for the JVM itself.

Here is a bytecode shape that might make it possible to do so, without the API you \
mentioned:

myfn(a,b,c) {
  var i,j,k;  // init to null if needed
  try {
    entry point of my fn...
    ... more stuff ...
    ... if (bail out #1) throw makeDeopt("cookie #1");
    ... more stuff ...
    ... if (bail out #2) throw makeDeopt("cookie #2");
    ... more stuff ...
    return x;
  } catch (MyDeopt deopt) {
     return executeDeopt(deopt, new Object[]{ a, b, c, i, j, k });
  }
}

Here, the cookies passed into the deopts are simple constants.  This (probably) \
simplifies data movement, since the complicated bundling is done once, at the catch \
point.  The local variable values could also be bundled up as arguments to makeDeopt. \
The throws could be replaced by gotos, but JITs are more likely to optimize the code \
the way you want if you use a throw (which the JIT will probably guess as uncommon).

Would this work for you?

Another problem here is where the executeDeopt guy should go.

Probably you want to fake up some AST interpreter state that expresses the pending \
continuations (for enclosing expressions and callers of inlined functions).  Then the \
AST engine, after it digests the app. some more, can generate new bytecodes.

Another option would be to generate bytecodes with multiple entry points.  This \
cannot be directly expressed but could be encoded with a leading pseudo-BCI \
parameter, with a switch at the entry point.  Again, the above "i,j,k" structure \
would be needed.  And all the entry points would have to have a common functional \
type.

Here's an idea:  For each byte-compiled method, compile the normal optimized version, \
and also compile a "fallback" version which can be used in corner cases:

myfn(int bci, args[], locals[]) {
  var a=args[0], ...;
  var i=locals[0],j,k;  // init to null if locals = null
  try {
    switch (bci) {
    case 0:
    entry point of my fn...
    case 1:
    ... more stuff ...
    ... if (bail out #1) throw makeDeopt("cookie #1");
    case 2:
    ... more stuff ...
    ... if (bail out #2) throw makeDeopt("cookie #2");
    case 3:
    ... more stuff ...
    return x;
    }
  } catch (MyDeopt deopt) {
     return executeDeopt(deopt, new Object[]{ a, b, c, i, j, k });
  }
}

The fallback could be used for type misses and untaken paths.  It could also be used \
for continuations (if your language has those).  The advantage of a pre-compiled \
fallback would be that you would reuse your bytecode compilation analysis to improve \
more execution paths, not just the fastest.  If that doesn't matter, a AST-based \
fallback is perhaps easier to work with.

-- John


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic