Class CallWeaver


  • public class CallWeaver
    extends java.lang.Object
    This class produces all the code associated with a specific pausable method invocation. There are three distinct chunks of code.
  • Rewind: At the beginning of the method, right after the opening switch statement (switch fiber.pc), which is the "rewind" portion. This stage pushes in (mostly) dummy values on the stack and jumps to the next method invocation in the cycle.
  • Call: The actual call. We push fiber as the last argument to the pausable method (by calling fiber.down()), before making the call.
  • Post-call The bulk of the code produced by this object.
  • An explanation of some terms used in the code may be useful. Much of this code concerns itself with storing and retrieving values from/to the stack and the local variables. The stack consists of three logical parts:

       +--------------+----------------------+---------------+
       | Stack bottom | callee obj reference | args for call | (Top of stack)
       +--------------+----------------------+---------------+
     
    The callee's object reference and the arguments at the top of stack are consumed by the method invocation. If the call is static, there is no object reference, of course. The bottom of the stack (which may also be empty) refers to the part of the stack that is left over once the args are consumed. This is the part that we need to save if we have to yield.

    As for the local variables, we are interested in saving var 0 (the "this" pointer) and all other variables that the flow analysis has shown to be live-in, that is, is used downstream of the call. Typically, only about 30% of all available vars are actually used downstream, so we use the rest for temporary storage.

    See Also:
    genRewind(MethodVisitor), genCall(MethodVisitor), genPostCall(MethodVisitor)
    • Field Summary

      Fields 
      Modifier and Type Field Description
      (package private) BasicBlock bb
      The basic block that calls the pausable method
      (package private) org.objectweb.asm.tree.LabelNode callLabel  
      private Detector detector  
      private MethodWeaver methodWeaver
      The parent method-weaver responsible for writing the whole method
      (package private) int numArgs
      Memoized version of getNumArgs()
      (package private) int numVars
      number of local registers required.
      private org.objectweb.asm.tree.LabelNode resumeLabel  
      private java.lang.String stateClassName
      The canoncial name of the state class responsible for storing the state (@see kilim.State)
      private ValInfoList valInfoList  
      (package private) java.util.BitSet varUsage
      varUsage[i] is true if the i-th var is taken.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      private int allocVar​(int size)  
      private void assignRegisters()
      The basic block's frame tells us the number of parameters in the stack and which local variables are needed later on.
      private void checkcast​(org.objectweb.asm.MethodVisitor mv, Value v)
      We have loaded a value of one of the five VM types into the stack and we need to cast it to the value's type, if necessary
      private java.lang.String createStateClass()  
      (package private) void genCall​(org.objectweb.asm.MethodVisitor mv)
      Before we make the target call, we need to call fiber.down(), to update it on the depth of the stack.
      (package private) void genPostCall​(org.objectweb.asm.MethodVisitor mv)
      After the pausable method call is over, we have four possibilities.
      private void genRestore​(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode restoreLabel)
      Not yielding (resuming normally), but have stored state.
      (package private) void genRestoreEx​(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode restoreLabel)  
      private void genRestoreVars​(org.objectweb.asm.MethodVisitor mv, int stateVar)  
      (package private) void genRewind​(org.objectweb.asm.MethodVisitor mv)
      The following template is produced in the method's prelude for each pausable method.
      private void genSave​(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode saveLabel)
      Yielding, but state hasn't been captured yet.
      private void genUnwind​(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode unwindLabel)
      Code for the case where we are yielding, and we have state built up from a previous call.
      (package private) BasicBlock getBasicBlock()  
      (package private) org.objectweb.asm.tree.MethodInsnNode getMethodInsn()  
      (package private) int getNumArgs()
      The total number consumed by the call, including its object reference
      (package private) int getNumBottom()  
      private java.lang.String getReceiverTypename()  
      private java.lang.String getReturnType()  
      (package private) int getStackLen()  
      (package private) boolean isSAM​(org.objectweb.asm.tree.MethodInsnNode mi)
      Is the given method the sole abstract method (modulo woven variants).
      (package private) boolean isStaticCall()  
      private void loadConstant​(org.objectweb.asm.MethodVisitor mv, Value v)  
      private void releaseVar​(int var, int size)  
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • methodWeaver

        private MethodWeaver methodWeaver
        The parent method-weaver responsible for writing the whole method
      • bb

        BasicBlock bb
        The basic block that calls the pausable method
      • resumeLabel

        private org.objectweb.asm.tree.LabelNode resumeLabel
      • callLabel

        org.objectweb.asm.tree.LabelNode callLabel
      • varUsage

        java.util.BitSet varUsage
        varUsage[i] is true if the i-th var is taken. We don't touch the first maxLocals vars. It is used for minimizing usage of extra vars.
      • numVars

        int numVars
        number of local registers required.
      • stateClassName

        private java.lang.String stateClassName
        The canoncial name of the state class responsible for storing the state (@see kilim.State)
      • numArgs

        int numArgs
        Memoized version of getNumArgs()
    • Method Detail

      • assignRegisters

        private void assignRegisters()
        The basic block's frame tells us the number of parameters in the stack and which local variables are needed later on. If the method is pausable, we'll need the bottom part of the stack and the object reference from the top part of the stack to be able to resume it. We don't need to worry about the arguments, because they will be saved (if needed) in the _called_ method's state. The "this" arg (var0) is given special treatment. It is always saved in all states, so it doesn't count as "data".
      • getStackLen

        int getStackLen()
      • getNumArgs

        int getNumArgs()
        The total number consumed by the call, including its object reference
      • isStaticCall

        final boolean isStaticCall()
      • getMethodInsn

        final org.objectweb.asm.tree.MethodInsnNode getMethodInsn()
      • getNumBottom

        int getNumBottom()
      • genRewind

        void genRewind​(org.objectweb.asm.MethodVisitor mv)
         The following template is produced in the method's prelude for each
         pausable method. 
         F_REWIND: 
           for each bottom stack operand
              introduce a dummy constant of the appropriate type.
                 (iconst_0, aconst_null, etc.)
              if the call is not static, 
                 we need the called object's object reference
                 ask the next state in the fiber's list
           goto F_CALL: // jump to the invocation site.
         
        Parameters:
        mv -
      • genCall

        void genCall​(org.objectweb.asm.MethodVisitor mv)
        Before we make the target call, we need to call fiber.down(), to update it on the depth of the stack. genPostCall subsequently arranges to call fiber.up(). We also need to push the fiber as the last argument to the pausable method. We accomplish both of these objectives by having fiber.down() do its book-keeping and return fiber, which is left on the stack before the call is made.
                     
                    F_CALL: 
                       push fiber.down()
                       invoke[virtual|static] classname/method modifiedDesc 
         
        Parameters:
        mv -
      • isSAM

        boolean isSAM​(org.objectweb.asm.tree.MethodInsnNode mi)
        Is the given method the sole abstract method (modulo woven variants).
      • genPostCall

        void genPostCall​(org.objectweb.asm.MethodVisitor mv)
        After the pausable method call is over, we have four possibilities. The called method yielded, or it returned normally. Orthogonally, we have saved state or not. fiber.up() returns the combined status ? *
                             
         switch (fiber.up()) {
            default:
            0: goto RESUME; // Not yielding , no State --  resume normal operations
            1: goto RESTORE; // Not yielding, has State -- restore state before resuming
            2: goto SAVE; // Yielding, no state -- save state before unwinding stack
            3: goto UNWIND // Yielding, has state -- nothing to do but unwind.
         }
         SAVE:
             ...
             xRETURN
         UNWIND:
             ...
             xRETURN
         RESTORE:
             ...
             // fall through to RESUME
         RESUME:
             ... original code
         
        Parameters:
        mv -
      • genUnwind

        private void genUnwind​(org.objectweb.asm.MethodVisitor mv,
                               org.objectweb.asm.tree.LabelNode unwindLabel)
        Code for the case where we are yielding, and we have state built up from a previous call. There's nothing meaningful to do except keep the verifier happy. Pop the bottom stack, then return a dummy return value (if this method -- note: not the called method -- returns a value)
        Parameters:
        mv -
      • getReturnType

        private java.lang.String getReturnType()
      • genSave

        private void genSave​(org.objectweb.asm.MethodVisitor mv,
                             org.objectweb.asm.tree.LabelNode saveLabel)
        Yielding, but state hasn't been captured yet. We create a state object and save each object in valInfoList in its corresponding field. Note that we save each stack item into a scratch register before loading it into a field. The reason is that we need to get the State ref under the stack item before we can do a putfield. The alternative is to load the State item, then do a swap or a dup_x2;pop (depending on the value's category). We'll go with the earlier approach because stack manipulations don't seem to perform as well in the current crop of JVMs.
        Parameters:
        mv -
      • genRestore

        private void genRestore​(org.objectweb.asm.MethodVisitor mv,
                                org.objectweb.asm.tree.LabelNode restoreLabel)
        Not yielding (resuming normally), but have stored state. We need to restore from state before resuming. This is slightly more work than saving state, because we have to restore constants and duplicates too. Note that the return value (if any) has a real value, which is why it needs to be saved away before we can get access to the bottom elements to pop them out.
                   If there is anything at the bottom save return value in scratch register
                         pop unnecessary bottom stuff.
                  
                   load fiber.curState 
                   cast to specific state (if necessary) 
                   astore in scratch <stateVar>
                  
                  for each value in frame.var 
                       if val is constant or is in valInfoList, 
                           push constant or load field (appropriately) 
                  for each value in bottom stack
                         restore value similar to above 
                  restore return value if any from scratch register
         
      • genRestoreEx

        void genRestoreEx​(org.objectweb.asm.MethodVisitor mv,
                          org.objectweb.asm.tree.LabelNode restoreLabel)
      • genRestoreVars

        private void genRestoreVars​(org.objectweb.asm.MethodVisitor mv,
                                    int stateVar)
      • getReceiverTypename

        private java.lang.String getReceiverTypename()
      • checkcast

        private void checkcast​(org.objectweb.asm.MethodVisitor mv,
                               Value v)
        We have loaded a value of one of the five VM types into the stack and we need to cast it to the value's type, if necessary
        Parameters:
        mv -
        v -
      • loadConstant

        private void loadConstant​(org.objectweb.asm.MethodVisitor mv,
                                  Value v)
      • createStateClass

        private java.lang.String createStateClass()
      • allocVar

        private int allocVar​(int size)
      • releaseVar

        private void releaseVar​(int var,
                                int size)