Package kilim.analysis
Class CallWeaver
java.lang.Object
kilim.analysis.CallWeaver
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
FieldsModifier and TypeFieldDescription(package private) BasicBlockThe basic block that calls the pausable method(package private) org.objectweb.asm.tree.LabelNodeprivate Detectorprivate MethodWeaverThe parent method-weaver responsible for writing the whole method(package private) intMemoized version of getNumArgs()(package private) intnumber of local registers required.private org.objectweb.asm.tree.LabelNodeprivate StringThe canoncial name of the state class responsible for storing the state (@see kilim.State)private ValInfoList(package private) BitSetvarUsage[i] is true if the i-th var is taken. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate intallocVar(int size) private voidThe basic block's frame tells us the number of parameters in the stack and which local variables are needed later on.private voidWe 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 String(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) BasicBlock(package private) final org.objectweb.asm.tree.MethodInsnNode(package private) intThe total number consumed by the call, including its object reference(package private) intprivate Stringprivate String(package private) int(package private) booleanisSAM(org.objectweb.asm.tree.MethodInsnNode mi) Is the given method the sole abstract method (modulo woven variants).(package private) final booleanprivate voidloadConstant(org.objectweb.asm.MethodVisitor mv, Value v) private voidreleaseVar(int var, int size)
-
Field Details
-
methodWeaver
The parent method-weaver responsible for writing the whole method -
bb
BasicBlock bbThe basic block that calls the pausable method -
resumeLabel
private org.objectweb.asm.tree.LabelNode resumeLabel -
callLabel
org.objectweb.asm.tree.LabelNode callLabel -
valInfoList
-
varUsage
BitSet varUsagevarUsage[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 numVarsnumber of local registers required. -
stateClassName
The canoncial name of the state class responsible for storing the state (@see kilim.State) -
numArgs
int numArgsMemoized version of getNumArgs() -
detector
-
-
Constructor Details
-
CallWeaver
-
-
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
-
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
-
checkcast
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
-
createStateClass
-
allocVar
private int allocVar(int size) -
releaseVar
private void releaseVar(int var, int size) -
getBasicBlock
BasicBlock getBasicBlock()
-