public class MethodModel
extends java.lang.Object
Modifier and Type | Class and Description |
---|---|
static class |
MethodModel.FakeLocalVariableTableEntry |
Modifier and Type | Field and Description |
---|---|
private ClassModel.ConstantPool.FieldEntry |
accessorVariableFieldEntry |
private java.util.Set<MethodModel> |
calledMethods |
(package private) Entrypoint |
entrypoint |
private ExpressionList |
expressionList |
private static java.util.logging.Logger |
logger |
private ClassModel.ClassModelMethod |
method |
private boolean |
methodIsGetter |
private boolean |
methodIsPrivateMemoryGetter |
private boolean |
methodIsSetter |
private boolean |
noCL |
private Instruction |
pcHead |
private Instruction |
pcTail
After we have folded the top level instructions this root list will contain a list of all of the 'root' instructions (stores/loops/conditionals)
We are going to build a linked list.
|
(package private) InstructionTransformer[] |
transformers |
private boolean |
usesByteWrites
True is an indication to use the byte addressable store pragma
|
private boolean |
usesDoubles
True is an indication to use the fp64 pragma
|
private boolean |
usesPutfield |
Constructor and Description |
---|
MethodModel(ClassModel.ClassModelMethod _method) |
MethodModel(ClassModel.ClassModelMethod _method,
Entrypoint _entrypoint) |
Modifier and Type | Method and Description |
---|---|
(package private) void |
applyTransformations(ExpressionList _expressionList,
Instruction _instruction,
Instruction _operandStart) |
void |
buildBranchGraphs(java.util.Map<java.lang.Integer,Instruction> pcMap)
Here we connect the branch nodes to the instruction that they branch to.
|
(package private) void |
checkForGetter(java.util.Map<java.lang.Integer,Instruction> pcMap)
Determine if this method is a getter and record the accessed field if so
|
void |
checkForRecursion(java.util.Set<MethodModel> transitiveCalledMethods) |
(package private) void |
checkForSetter(java.util.Map<java.lang.Integer,Instruction> pcMap)
Determine if this method is a setter and record the accessed field if so
|
java.util.Map<java.lang.Integer,Instruction> |
createListOfInstructions()
Create a linked list of instructions (from pcHead to pcTail).
|
void |
deoptimizeReverseBranches()
Javac optimizes some branches to avoid goto->goto, branch->goto etc.
|
(package private) void |
foldExpressions()
Try to fold the instructions into higher level structures.
|
ClassModel.ConstantPool.FieldEntry |
getAccessorVariableFieldEntry() |
java.util.Set<MethodModel> |
getCalledMethods() |
ClassModel.ConstantPool |
getConstantPool() |
Instruction |
getExprHead() |
ClassModel.LocalVariableInfo |
getLocalVariable(int _pc,
int _index) |
ClassModel.LocalVariableTableEntry<ClassModel.LocalVariableInfo> |
getLocalVariableTableEntry() |
ClassModel.ClassModelMethod |
getMethod() |
java.util.List<InstructionSet.MethodCall> |
getMethodCalls() |
java.lang.String |
getName() |
Instruction |
getPCHead() |
java.lang.String |
getReturnType() |
java.lang.String |
getSimpleName() |
private void |
init(ClassModel.ClassModelMethod _method) |
boolean |
isGetter() |
boolean |
isNoCL() |
boolean |
isPrivateMemoryGetter() |
boolean |
isSetter() |
boolean |
methodUsesPutfield() |
boolean |
requiresByteAddressableStorePragma() |
boolean |
requiresDoublePragma() |
private void |
setAccessorVariableFieldEntry(ClassModel.ConstantPool.FieldEntry field) |
void |
setRequiredPragmas(Instruction instruction)
Look at each instruction for use of long/double or byte writes which
require pragmas to be used in the OpenCL source
|
java.lang.String |
toString() |
void |
txFormDups(ExpressionList _expressionList,
Instruction _instruction)
DUP family of instructions break our stack unwind model (whereby we treat instructions like the oeprands they create/consume).
|
private static java.util.logging.Logger logger
private ExpressionList expressionList
private ClassModel.ClassModelMethod method
private boolean usesDoubles
private boolean usesByteWrites
private boolean methodIsGetter
private boolean methodIsSetter
private boolean methodIsPrivateMemoryGetter
private boolean usesPutfield
private ClassModel.ConstantPool.FieldEntry accessorVariableFieldEntry
private boolean noCL
private final java.util.Set<MethodModel> calledMethods
private Instruction pcTail
private Instruction pcHead
InstructionTransformer[] transformers
Entrypoint entrypoint
MethodModel(ClassModel.ClassModelMethod _method, Entrypoint _entrypoint) throws AparapiException
AparapiException
MethodModel(ClassModel.ClassModelMethod _method) throws AparapiException
AparapiException
public boolean isGetter()
public boolean isSetter()
public boolean methodUsesPutfield()
public boolean isNoCL()
public boolean isPrivateMemoryGetter()
public ClassModel.ClassModelMethod getMethod()
public ClassModel.ConstantPool.FieldEntry getAccessorVariableFieldEntry()
public java.util.Set<MethodModel> getCalledMethods()
public void checkForRecursion(java.util.Set<MethodModel> transitiveCalledMethods) throws AparapiException
AparapiException
public void setRequiredPragmas(Instruction instruction)
public boolean requiresDoublePragma()
public boolean requiresByteAddressableStorePragma()
public java.util.Map<java.lang.Integer,Instruction> createListOfInstructions() throws ClassParseException
ClassParseException
public void buildBranchGraphs(java.util.Map<java.lang.Integer,Instruction> pcMap)
Each branch node contains a 'target' field indended to reference the node that the branch targets. Each instruction also contain four seperate lists of branch nodes that reference it. These lists hold forwardConditional, forwardUnconditional, reverseConditional and revereseUnconditional branches that reference it.
So assuming that we had a branch node at pc offset 100 which represented 'goto 200'.
Following this call the branch node at pc offset 100 will have a 'target' field which actually references the instruction at pc offset 200, and the instruction at pc offset 200 will have the branch node (at 100) added to it's forwardUnconditional list.
InstructionSet.Branch#getTarget()
public void deoptimizeReverseBranches()
public void txFormDups(ExpressionList _expressionList, Instruction _instruction) throws ClassParseException
Here we replace DUP style instructions with a 'mock' instruction which 'clones' the effect of the instruction. This would be invalid to execute but is useful to replace the DUP with a 'pattern' which it simulates. This allows us to later apply transforms to represent the original code.
An example might be the bytecode for the following sequence.
Which results in the following bytecode
results[10]++;
return
First we need to know what the stack will look like before the dup2 is encountered.
Using our folding technique we represent the first two instructions inside ()
0: aload_0 // reference through 'this' to get
1: getfield // field 'results' which is an array of int
4: bipush 10 // push the array index
6: dup2 // dreaded dup2 we'll come back here
7: iaload // ignore for the moment.
8: iconst_1
9: iadd
10: iastore
11: return
getfield (aload_0 // result in the array field reference on stack
bipush 10 // the array index
dup2 // dreaded dup2 we'll come back here
The dup2
essentially copies the top two elements on the stack. So we emulate this by replacing the dup2 with clones of the instructions which would reinstate the same stack state.
So after the dup2
transform we end up with:-
getfield (aload_0) // result in the array field reference on stack
bipush 10 // the array index
{getfield (aload_0)} // result in the array field reference on stack
{bipush 10} // the array index
So carrying on lets look at the iaload
which consumes two operands (the index and the array field reference) and creates one (the result of an array access)
getfield (aload_0) // result in the array field reference on stack
bipush 10 // the array index
{getfield (aload_0)} // result in the array field reference on stack
{bipush 10} // the array index
iaload
So we now have
getfield (aload_0) // result in the array field reference on stack
bipush 10 // the array index
iaload ({getfield(aload_0), {bipush 10}) // results in the array element on the stack
iconst
iadd
And if you are following along the iadd
will fold the previous two stack entries essentially pushing the result of
results[10]+1 on the stack.
getfield (aload_0) // result in the array field reference on stack
bipush 10 // the array index
iadd (iaload ({getfield(aload_0), {bipush 10}, iconst_1) // push of results[10]+1
Then the final istore
instruction which consumes 3 stack operands (the field array reference, the index and the value to assign).
Which results in
istore (getfield (aload_0), bipush 10, iadd (iaload ({getfield(aload_0), {bipush 10}, iconst_1)) // results[10] = results[10+1]
Where results[10] = results[10+1] is the long-hand form of the results[10]++
and will be transformed by one of the 'inc' transforms to the more familiar form a little later.
_expressionList
- _instruction
- ClassParseException
void foldExpressions() throws ClassParseException
ClassParseException
void applyTransformations(ExpressionList _expressionList, Instruction _instruction, Instruction _operandStart) throws ClassParseException
ClassParseException
void checkForGetter(java.util.Map<java.lang.Integer,Instruction> pcMap) throws ClassParseException
ClassParseException
private void setAccessorVariableFieldEntry(ClassModel.ConstantPool.FieldEntry field)
void checkForSetter(java.util.Map<java.lang.Integer,Instruction> pcMap) throws ClassParseException
ClassParseException
private void init(ClassModel.ClassModelMethod _method) throws AparapiException
AparapiException
public ClassModel.LocalVariableTableEntry<ClassModel.LocalVariableInfo> getLocalVariableTableEntry()
public ClassModel.ConstantPool getConstantPool()
public ClassModel.LocalVariableInfo getLocalVariable(int _pc, int _index)
public java.lang.String getSimpleName()
public java.lang.String getName()
public java.lang.String getReturnType()
public java.util.List<InstructionSet.MethodCall> getMethodCalls()
public Instruction getPCHead()
public Instruction getExprHead()
public java.lang.String toString()
toString
in class java.lang.Object