use of org.apache.bcel.generic.MONITOREXIT in project jop by jop-devel.
the class Segment method synchronizedSegment.
/**
* Create an interprocedural segment for a synchronized block. Currently we do
* not split basic blocks here, so either you are happy with basic block granularity,
* or you split the basic block while loading.
* @param targetBlock The block containing the monitorenter instruction
* @param monitorEnter The monitor enter instruction
* @param callString The context for the method
* @param cfgProvider A control flow graph provider
* @param callStringLength Length of the callstrings
* @param infeasibles Information about infeasible edges (null if no information available)
*
* @return a segment representing executions of the synchronized block
*/
public static Segment synchronizedSegment(ContextCFG ccfg, CFGNode entryNode, InstructionHandle monitorEnter, CFGProvider cfgProvider, int callStringLength, InfeasibleEdgeProvider infeasibles) {
if (infeasibles == null) {
infeasibles = InfeasibleEdgeProvider.NO_INFEASIBLES;
}
ControlFlowGraph cfg = ccfg.getCfg();
SuperGraph superGraph = new SuperGraph(cfgProvider, cfg, ccfg.getCallString(), callStringLength, infeasibles);
ContextCFG rootMethod = superGraph.getRootNode();
/* lift entry edges */
Set<SuperGraphEdge> entryEdges = Iterators.addAll(new HashSet<SuperGraphEdge>(), superGraph.liftCFGEdges(rootMethod, cfg.incomingEdgesOf(entryNode)));
/* find exit blocks (might also be in the same block) */
/* monitorenter followed bei monitorexit in same block => segment only contains this block */
Set<CFGEdge> monitorExitEdges = new HashSet<CFGEdge>();
CFGNode currentNode = entryNode;
int currentNestingLevel = 1;
Iterator<InstructionHandle> insIter = currentNode.getBasicBlock().getInstructions().iterator();
while (insIter.hasNext()) {
if (insIter.next() == monitorEnter)
break;
}
Stack<Pair<CFGNode, Integer>> todo = new Stack<Pair<CFGNode, Integer>>();
Set<CFGNode> visited = new HashSet<CFGNode>();
do {
boolean isExit = false;
while (insIter.hasNext()) {
InstructionHandle ih = insIter.next();
if (ih.getInstruction() instanceof MONITOREXIT) {
/* blocks outgoing edges terminate segment */
currentNestingLevel--;
if (currentNestingLevel == 0) {
isExit = true;
// If monitorexit is not implemented in Java, the outgoing edges of the
// basic block that contains monitorexit end the synchronized block.
// In order to avoid imprecision, it is advisable that monitorexit is the
// last statement in the basic block.
// We also handle the case when monitorexit is implemented in Java. In this case,
// currentNode will be a SpecialInvokeNode, urrentNode's only
// successor will be the corresponding ReturnNode, and the outgoing edges of
// the ReturnNode are the exit edges for the synchronized segment.
CFGNode onlySuccessor = Iterators.fromSingleton(cfg.getSuccessors(currentNode));
if (onlySuccessor != null && onlySuccessor instanceof ControlFlowGraph.ReturnNode) {
Iterators.addAll(monitorExitEdges, cfg.outgoingEdgesOf(onlySuccessor));
} else {
Iterators.addAll(monitorExitEdges, cfg.outgoingEdgesOf(currentNode));
}
break;
}
} else if (ih.getInstruction() instanceof MONITORENTER) {
currentNestingLevel++;
}
}
if (!isExit) {
for (CFGNode node : cfg.getSuccessors(currentNode)) {
todo.add(new Pair<CFGNode, Integer>(node, currentNestingLevel));
}
}
currentNode = null;
while (!todo.isEmpty()) {
Pair<CFGNode, Integer> nextPair = todo.pop();
CFGNode nextNode = nextPair.first();
if (!visited.contains(nextNode)) {
visited.add(nextNode);
if (cfg.outgoingEdgesOf(nextNode).isEmpty()) {
throw new AssertionError("Found monitor-exit free path from monitorenter to the end of a function. In: " + cfg);
} else if (nextNode.getBasicBlock() == null) {
for (CFGNode node : cfg.getSuccessors(nextNode)) {
todo.add(new Pair<CFGNode, Integer>(node, nextPair.second()));
}
} else {
currentNode = nextNode;
currentNestingLevel = nextPair.second();
insIter = currentNode.getBasicBlock().getInstructions().iterator();
break;
}
}
}
} while (currentNode != null);
Set<SuperGraphEdge> exitEdges = Iterators.addAll(new HashSet<SuperGraphEdge>(), superGraph.liftCFGEdges(rootMethod, monitorExitEdges));
return new Segment(superGraph, entryEdges, exitEdges);
}
use of org.apache.bcel.generic.MONITOREXIT in project jop by jop-devel.
the class InsertSynchronized method synchronize.
private void synchronize(MethodInfo method) {
MethodCode mc = method.getCode();
InstructionList il = mc.getInstructionList();
InstructionFinder f;
// prepend monitorenter (reversed order of opcodes)
il.insert(new MONITORENTER());
if (method.isStatic()) {
// il.insert(new GET_CURRENT_CLASS());
throw new JavaClassFormatError("synchronized on static methods not yet supported");
} else {
il.insert(new ALOAD(0));
}
il.setPositions();
f = new InstructionFinder(il);
// find return instructions and insert monitorexit
String retInstr = "ReturnInstruction";
for (Iterator iterator = f.search(retInstr); iterator.hasNext(); ) {
InstructionHandle[] match = (InstructionHandle[]) iterator.next();
InstructionHandle ih = match[0];
// handle for inserted sequence
InstructionHandle newh;
if (method.isStatic()) {
// il.insert(ih, new GET_CURRENT_CLASS());
throw new JavaClassFormatError("synchronized on static methods not yet supported");
} else {
// TODO this could become a bug if JCopter ever reassigns local variable slots, then
// we could not be sure that slot 0 holds the this reference anymore.. To be on the safe side
// we should check if there is an xSTORE_0 somewhere in the code
newh = il.insert(ih, new ALOAD(0));
}
il.insert(ih, new MONITOREXIT());
// correct jumps
method.getCode().retarget(ih, newh);
}
il.setPositions();
method.compile();
}
use of org.apache.bcel.generic.MONITOREXIT in project jop by jop-devel.
the class ReplaceNativeAndCPIdx method replace.
private Method replace(Method method) {
MethodGen mg = new MethodGen(method, clazz.getClassName(), cpoolgen);
InstructionList il = mg.getInstructionList();
InstructionFinder f = new InstructionFinder(il);
String methodId = method.getName() + method.getSignature();
OldMethodInfo mi = getCli().getMethodInfo(methodId);
// find invokes first and replace call to Native by
// JOP native instructions.
String invokeStr = "InvokeInstruction";
for (Iterator i = f.search(invokeStr); i.hasNext(); ) {
InstructionHandle[] match = (InstructionHandle[]) i.next();
InstructionHandle first = match[0];
InvokeInstruction ii = (InvokeInstruction) first.getInstruction();
if (ii.getClassName(cpoolgen).equals(JOPizer.nativeClass)) {
short opid = (short) JopInstr.getNative(ii.getMethodName(cpoolgen));
if (opid == -1) {
System.err.println(method.getName() + ": cannot locate " + ii.getMethodName(cpoolgen) + ". Replacing with NOP.");
first.setInstruction(new NOP());
} else {
first.setInstruction(new NativeInstruction(opid, (short) 1));
((JOPizer) ai).outTxt.println("\t" + first.getPosition());
// then we remove pc+2 and pc+1 from the MGCI info
if (JOPizer.dumpMgci) {
il.setPositions();
int pc = first.getPosition();
// important: take the high one first
GCRTMethodInfo.removePC(pc + 2, mi);
GCRTMethodInfo.removePC(pc + 1, mi);
}
}
}
if (ii instanceof INVOKESPECIAL) {
// not an initializer
if (!ii.getMethodName(cpoolgen).equals("<init>")) {
// check if this is a super invoke
// TODO this is just a hack, use InvokeSite.isInvokeSuper() when this is ported to the new framework!
boolean isSuper = false;
String declaredType = ii.getClassName(cpoolgen);
JopClassInfo cls = getCli();
OldClassInfo superClass = cls.superClass;
while (superClass != null) {
if (superClass.clazz.getClassName().equals(declaredType)) {
isSuper = true;
break;
}
if ("java.lang.Object".equals(superClass.clazz.getClassName())) {
break;
}
superClass = superClass.superClass;
}
if (isSuper) {
Integer idx = ii.getIndex();
int new_index = getCli().cpoolUsed.indexOf(idx) + 1;
first.setInstruction(new JOPSYS_INVOKESUPER((short) new_index));
// System.err.println("invokesuper "+ii.getClassName(cpoolgen)+"."+ii.getMethodName(cpoolgen));
}
}
}
}
if (JOPizer.CACHE_INVAL) {
f = new InstructionFinder(il);
// find volatile reads and insert cache invalidation bytecode
String fieldInstr = "GETFIELD|GETSTATIC|PUTFIELD|PUTSTATIC";
for (Iterator i = f.search(fieldInstr); i.hasNext(); ) {
InstructionHandle[] match = (InstructionHandle[]) i.next();
InstructionHandle ih = match[0];
FieldInstruction fi = (FieldInstruction) ih.getInstruction();
JavaClass jc = JOPizer.jz.cliMap.get(fi.getClassName(cpoolgen)).clazz;
Field field = null;
while (field == null) {
Field[] fields = jc.getFields();
for (int k = 0; k < fields.length; k++) {
if (fields[k].getName().equals(fi.getFieldName(cpoolgen))) {
field = fields[k];
break;
}
}
if (field == null) {
try {
jc = jc.getSuperClass();
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new Error();
}
}
}
if (field.isVolatile()) {
if (field.getType().getSize() < 2) {
if (fi instanceof GETFIELD || fi instanceof GETSTATIC) {
ih.setInstruction(new InvalidateInstruction());
ih = il.append(ih, fi);
}
} else {
// this only works because we do not throw a
// NullPointerException for monitorenter/-exit!
ih.setInstruction(new ACONST_NULL());
ih = il.append(ih, new MONITORENTER());
ih = il.append(ih, fi);
ih = il.append(ih, new ACONST_NULL());
ih = il.append(ih, new MONITOREXIT());
}
}
}
}
f = new InstructionFinder(il);
// find instructions that access the constant pool
// and replace the index by the new value from ClassInfo
String cpInstr = "CPInstruction";
for (Iterator it = f.search(cpInstr); it.hasNext(); ) {
InstructionHandle[] match = (InstructionHandle[]) it.next();
InstructionHandle ih = match[0];
CPInstruction cpii = (CPInstruction) ih.getInstruction();
int index = cpii.getIndex();
// we have to grab the information before we change
// the CP index.
FieldInstruction fi = null;
Type ft = null;
if (cpii instanceof FieldInstruction) {
fi = (FieldInstruction) ih.getInstruction();
ft = fi.getFieldType(cpoolgen);
}
Integer idx = new Integer(index);
// pos is the new position in the reduced constant pool
// idx is the position in the 'original' unresolved cpool
int pos = getCli().cpoolUsed.indexOf(idx);
int new_index = pos + 1;
// and putfield and by address for getstatic and putstatic
if (cpii instanceof GETFIELD || cpii instanceof PUTFIELD || cpii instanceof GETSTATIC || cpii instanceof PUTSTATIC) {
// we use the offset instead of the CP index
new_index = getFieldOffset(cp, index);
} else {
if (pos == -1) {
System.out.println("Error: constant " + index + " " + cpoolgen.getConstant(index) + " not found");
System.out.println("new cpool: " + getCli().cpoolUsed);
System.out.println("original cpool: " + cpoolgen);
System.exit(-1);
}
}
// set new index, position starts at
// 1 as cp points to the length of the pool
cpii.setIndex(new_index);
if (cpii instanceof FieldInstruction) {
boolean isRef = ft instanceof ReferenceType;
boolean isLong = ft == BasicType.LONG || ft == BasicType.DOUBLE;
if (fi instanceof GETSTATIC) {
if (isRef) {
ih.setInstruction(new GETSTATIC_REF((short) new_index));
} else if (isLong) {
ih.setInstruction(new GETSTATIC_LONG((short) new_index));
}
} else if (fi instanceof PUTSTATIC) {
if (isRef) {
if (!com.jopdesign.build.JOPizer.USE_RTTM) {
ih.setInstruction(new PUTSTATIC_REF((short) new_index));
}
} else if (isLong) {
ih.setInstruction(new PUTSTATIC_LONG((short) new_index));
}
} else if (fi instanceof GETFIELD) {
if (isRef) {
ih.setInstruction(new GETFIELD_REF((short) new_index));
} else if (isLong) {
ih.setInstruction(new GETFIELD_LONG((short) new_index));
}
} else if (fi instanceof PUTFIELD) {
if (isRef) {
if (!com.jopdesign.build.JOPizer.USE_RTTM) {
ih.setInstruction(new PUTFIELD_REF((short) new_index));
}
} else if (isLong) {
ih.setInstruction(new PUTFIELD_LONG((short) new_index));
}
}
}
}
Method m = mg.getMethod();
il.dispose();
return m;
}
Aggregations