On 09/08/2011 01:12 AM, John Rose wrote: > On Sep 7, 2011, at 3:28 PM, Rémi Forax wrote: > >> On 09/07/2011 10:38 PM, John Rose wrote: >>> Object l0, l1, l2, ...; >>> l0 = l1 = l2 = ... null; // these are required only for definite >>> assignment in the catch body >>> try { >>> ...do fast path... >>> if (...constraint violated...) throw new DeoptExc(...); >>> return ...fast result... >>> } catch (DeoptExc ex) { >>> Object[] display = { l0, l1, l2, ... }; >>> return backupInterpreter(ex, display); // N.B. could throw DeoptExc >>> to caller also >>> } >>> >>> This problem is that the eager initializations of the various locals slow >>> down the fast path. (Did I get it right Remi?) The register allocator >>> should push them down into the catch body, and maybe even into the static >>> debug info of the JVM. >> Locals is not the only problem, you have to track stack values too. > To clarify, I meant only JVM locals, which serve as virtual registers for the > application language locals, stacks, whatever. JVM stack elements are > guaranteed to be thrown away when a JVM exception is thrown, so they function > like virtual registers that are blown by deopt. events. > >> It's the combination of locals initialization, local variable creation >> for storing stack values > Yes, if there are logically stacked values that need tracking into slow > paths, they need to be spilled to JVM locals. The cost of this will be > reduced by good register allocations in the JIT. Ensuring this is part of > the tuning job. > >> and supplementary exception handlers >> (that's the main problem, or you have multiple handlers, >> or you have one handler and a constant) >> that slow down the fast path. > I think a single handler is going to be simpler all the way around. Thus, > the deopt. source location and value display map have to be stored somewhere > so they can be made a parameter to the handler. I think the exception object > is the most likely place to store it; TLS is also a candidate.
currently I'm thinking to use multiple exception handler entry points but only one common code. handler1: iconst_0 goto common_handler handler2: iconst_1 goto common_handler ... common_handler: swap pop // remove exception object aload spill1 aload spill2 ... invokedynamic foo (ILObject;LObject ...) > > To extend on your cute idea below, have the source location and value display > map be static parameters to the invokedynamic instruction which initiates > transfer to the slow path. That way everything is in the class file, but > lazily unpacked only if needed. There's little or no need to use executable > bytecode instructions (other than an indy at the throw point and an indy in > the local handler) to manage the deopt. transition. The actual bytecodes can > be devoted to executing the fast path code, and testing for type-state faults. for PHP.reboot I need the AST node corresponding to the operation that overflow, so I need a live value. But I can use one parameter of the method to transfer all AST nodes wrapped in one object bound to the current method. > > BTW, although one might think that the repertoire for static BSM arguments is > limited (string, class, int, long, MH, MT), note that the MH gives a hook to > open-ended constant formation. Just treat the MH as a thunk to be executed > to materialize a desired constant. but you can get live value unless you allow to insert live values to the constant pool when linking the class (another old dream). > >> Also, in the catch block you can use invokedynamic to avoid >> the object array creation at call site. > Yes, cute idea. Simplifying code on the slow path should make for faster > loading and startup. > > Or (putting on my Pack200 hat), invokedynamic is the ultimate code-stream > compressor. > > -- John Rémi _______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev