Package kilim.analysis
Class CallWeaver
- java.lang.Object
-
- kilim.analysis.CallWeaver
-
public class CallWeaver extends java.lang.ObjectThis 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.
-
-
Field Summary
Fields Modifier and Type Field Description (package private) BasicBlockbbThe basic block that calls the pausable method(package private) org.objectweb.asm.tree.LabelNodecallLabelprivate Detectordetectorprivate MethodWeavermethodWeaverThe parent method-weaver responsible for writing the whole method(package private) intnumArgsMemoized version of getNumArgs()(package private) intnumVarsnumber of local registers required.private org.objectweb.asm.tree.LabelNoderesumeLabelprivate java.lang.StringstateClassNameThe canoncial name of the state class responsible for storing the state (@see kilim.State)private ValInfoListvalInfoList(package private) java.util.BitSetvarUsagevarUsage[i] is true if the i-th var is taken.
-
Constructor Summary
Constructors Constructor Description CallWeaver(MethodWeaver mw, Detector d, BasicBlock aBB)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description private intallocVar(int size)private voidassignRegisters()The basic block's frame tells us the number of parameters in the stack and which local variables are needed later on.private voidcheckcast(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 necessaryprivate java.lang.StringcreateStateClass()(package private) voidgenCall(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) voidgenPostCall(org.objectweb.asm.MethodVisitor mv)After the pausable method call is over, we have four possibilities.private voidgenRestore(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode restoreLabel)Not yielding (resuming normally), but have stored state.(package private) voidgenRestoreEx(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode restoreLabel)private voidgenRestoreVars(org.objectweb.asm.MethodVisitor mv, int stateVar)(package private) voidgenRewind(org.objectweb.asm.MethodVisitor mv)The following template is produced in the method's prelude for each pausable method.private voidgenSave(org.objectweb.asm.MethodVisitor mv, org.objectweb.asm.tree.LabelNode saveLabel)Yielding, but state hasn't been captured yet.private voidgenUnwind(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) BasicBlockgetBasicBlock()(package private) org.objectweb.asm.tree.MethodInsnNodegetMethodInsn()(package private) intgetNumArgs()The total number consumed by the call, including its object reference(package private) intgetNumBottom()private java.lang.StringgetReceiverTypename()private java.lang.StringgetReturnType()(package private) intgetStackLen()(package private) booleanisSAM(org.objectweb.asm.tree.MethodInsnNode mi)Is the given method the sole abstract method (modulo woven variants).(package private) booleanisStaticCall()private voidloadConstant(org.objectweb.asm.MethodVisitor mv, Value v)private voidreleaseVar(int var, int size)
-
-
-
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
-
valInfoList
private ValInfoList valInfoList
-
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()
-
detector
private Detector detector
-
-
Constructor Detail
-
CallWeaver
public CallWeaver(MethodWeaver mw, Detector d, BasicBlock aBB)
-
-
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)
-
getBasicBlock
BasicBlock getBasicBlock()
-
-