Class CallWeaver

java.lang.Object
kilim.analysis.CallWeaver

public class CallWeaver extends 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:
    • Field Summary

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

      Constructors
      Constructor
      Description
       
    • Method Summary

      Modifier and Type
      Method
      Description
      private int
      allocVar(int size)
       
      private void
      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 String
       
      (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
       
      (package private) final org.objectweb.asm.tree.MethodInsnNode
       
      (package private) int
      The total number consumed by the call, including its object reference
      (package private) int
       
      private String
       
      private String
       
      (package private) int
       
      (package private) boolean
      isSAM(org.objectweb.asm.tree.MethodInsnNode mi)
      Is the given method the sole abstract method (modulo woven variants).
      (package private) final boolean
       
      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 Details

      • methodWeaver

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

        The basic block that calls the pausable method
      • resumeLabel

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

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

        private ValInfoList valInfoList
      • varUsage

        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 String stateClassName
        The canoncial name of the state class responsible for storing the state (@see kilim.State)
      • numArgs

        int numArgs
        Memoized version of getNumArgs()
      • detector

        private Detector detector
    • Constructor Details

    • Method Details

      • 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 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 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 String createStateClass()
      • allocVar

        private int allocVar(int size)
      • releaseVar

        private void releaseVar(int var, int size)
      • getBasicBlock

        BasicBlock getBasicBlock()