Search in sources :

Example 1 with MONITORENTER

use of org.apache.bcel.generic.MONITORENTER 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);
}
Also used : MONITORENTER(org.apache.bcel.generic.MONITORENTER) InstructionHandle(org.apache.bcel.generic.InstructionHandle) MONITOREXIT(org.apache.bcel.generic.MONITOREXIT) HashSet(java.util.HashSet) CFGEdge(com.jopdesign.common.code.ControlFlowGraph.CFGEdge) Pair(com.jopdesign.common.graphutils.Pair) CFGNode(com.jopdesign.common.code.ControlFlowGraph.CFGNode) Stack(java.util.Stack) ContextCFG(com.jopdesign.common.code.SuperGraph.ContextCFG) SuperGraphEdge(com.jopdesign.common.code.SuperGraph.SuperGraphEdge)

Example 2 with MONITORENTER

use of org.apache.bcel.generic.MONITORENTER 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();
}
Also used : ALOAD(org.apache.bcel.generic.ALOAD) InstructionList(org.apache.bcel.generic.InstructionList) JavaClassFormatError(com.jopdesign.common.misc.JavaClassFormatError) Iterator(java.util.Iterator) MONITOREXIT(org.apache.bcel.generic.MONITOREXIT) InstructionFinder(org.apache.bcel.util.InstructionFinder) MethodCode(com.jopdesign.common.MethodCode) MONITORENTER(org.apache.bcel.generic.MONITORENTER) InstructionHandle(org.apache.bcel.generic.InstructionHandle)

Example 3 with MONITORENTER

use of org.apache.bcel.generic.MONITORENTER 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;
}
Also used : InstructionList(org.apache.bcel.generic.InstructionList) InstructionFinder(org.apache.bcel.util.InstructionFinder) MONITORENTER(org.apache.bcel.generic.MONITORENTER) MethodGen(org.apache.bcel.generic.MethodGen) InstructionHandle(org.apache.bcel.generic.InstructionHandle) ReferenceType(org.apache.bcel.generic.ReferenceType) PUTSTATIC(org.apache.bcel.generic.PUTSTATIC) Field(org.apache.bcel.classfile.Field) CPInstruction(org.apache.bcel.generic.CPInstruction) Iterator(java.util.Iterator) MONITOREXIT(org.apache.bcel.generic.MONITOREXIT) ACONST_NULL(org.apache.bcel.generic.ACONST_NULL) PUTFIELD(org.apache.bcel.generic.PUTFIELD) Method(org.apache.bcel.classfile.Method) INVOKESPECIAL(org.apache.bcel.generic.INVOKESPECIAL) NOP(org.apache.bcel.generic.NOP) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) GETFIELD(org.apache.bcel.generic.GETFIELD) ReferenceType(org.apache.bcel.generic.ReferenceType) Type(org.apache.bcel.generic.Type) BasicType(org.apache.bcel.generic.BasicType) ConstantNameAndType(org.apache.bcel.classfile.ConstantNameAndType) JavaClass(org.apache.bcel.classfile.JavaClass) FieldInstruction(org.apache.bcel.generic.FieldInstruction) GETSTATIC(org.apache.bcel.generic.GETSTATIC)

Example 4 with MONITORENTER

use of org.apache.bcel.generic.MONITORENTER in project jop by jop-devel.

the class WCETAnalysis method runBlockingTimeAnalysis.

private void runBlockingTimeAnalysis(MethodInfo targetMethod) throws InvalidFlowFactException, LpSolveException, UnsupportedCacheModelException {
    GlobalAnalysis an = new GlobalAnalysis(wcetTool, ipetConfig);
    CacheCostCalculationMethod requestedCacheApprox = IPETConfig.getRequestedCacheApprox(config);
    /* Find all synchronized segments */
    Segment target = Segment.methodSegment(targetMethod, CallString.EMPTY, wcetTool, wcetTool.getCallstringLength(), wcetTool);
    ArrayList<SynchronizedBlockResult> sBlocks = new ArrayList<SynchronizedBlockResult>();
    for (ContextCFG ccfg : target.getCallGraphNodes()) {
        for (CFGNode cfgNode : ccfg.getCfg().vertexSet()) {
            if (cfgNode.getBasicBlock() == null)
                continue;
            for (InstructionHandle ih : cfgNode.getBasicBlock().getInstructions()) {
                if (ih.getInstruction() instanceof MONITORENTER) {
                    /* compute synchronized block WCET */
                    Segment synchronizedSegment = Segment.synchronizedSegment(ccfg, cfgNode, ih, wcetTool, wcetTool.getCallstringLength(), wcetTool);
                    wcet = an.computeWCET(targetMethod.getShortName(), synchronizedSegment, requestedCacheApprox);
                    sBlocks.add(new SynchronizedBlockResult(sBlocks.size(), synchronizedSegment, cfgNode, ih, wcet));
                }
            }
        }
    }
    /* check nested synchronized blocks */
    for (SynchronizedBlockResult sBlock : sBlocks) {
        for (SynchronizedBlockResult otherBlock : sBlocks) {
            if (sBlock == otherBlock)
                continue;
            for (SuperGraphEdge entryEdge : otherBlock.synchronizedSegment.getEntryEdges()) {
                if (sBlock.synchronizedSegment.includesEdge(entryEdge)) {
                    sBlock.nested.add(otherBlock);
                    break;
                }
            }
        }
    }
    System.out.println("=== Synchronized Blocks ===");
    for (SynchronizedBlockResult sBlock : sBlocks) {
        sBlock.dump(System.out);
    }
}
Also used : CacheCostCalculationMethod(com.jopdesign.wcet.ipet.IPETConfig.CacheCostCalculationMethod) CFGNode(com.jopdesign.common.code.ControlFlowGraph.CFGNode) GlobalAnalysis(com.jopdesign.wcet.analysis.GlobalAnalysis) ContextCFG(com.jopdesign.common.code.SuperGraph.ContextCFG) ArrayList(java.util.ArrayList) SuperGraphEdge(com.jopdesign.common.code.SuperGraph.SuperGraphEdge) MONITORENTER(org.apache.bcel.generic.MONITORENTER) Segment(com.jopdesign.common.code.Segment) InstructionHandle(org.apache.bcel.generic.InstructionHandle)

Aggregations

InstructionHandle (org.apache.bcel.generic.InstructionHandle)4 MONITORENTER (org.apache.bcel.generic.MONITORENTER)4 MONITOREXIT (org.apache.bcel.generic.MONITOREXIT)3 CFGNode (com.jopdesign.common.code.ControlFlowGraph.CFGNode)2 ContextCFG (com.jopdesign.common.code.SuperGraph.ContextCFG)2 SuperGraphEdge (com.jopdesign.common.code.SuperGraph.SuperGraphEdge)2 Iterator (java.util.Iterator)2 InstructionList (org.apache.bcel.generic.InstructionList)2 InstructionFinder (org.apache.bcel.util.InstructionFinder)2 MethodCode (com.jopdesign.common.MethodCode)1 CFGEdge (com.jopdesign.common.code.ControlFlowGraph.CFGEdge)1 Segment (com.jopdesign.common.code.Segment)1 Pair (com.jopdesign.common.graphutils.Pair)1 JavaClassFormatError (com.jopdesign.common.misc.JavaClassFormatError)1 GlobalAnalysis (com.jopdesign.wcet.analysis.GlobalAnalysis)1 CacheCostCalculationMethod (com.jopdesign.wcet.ipet.IPETConfig.CacheCostCalculationMethod)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 Stack (java.util.Stack)1 ConstantNameAndType (org.apache.bcel.classfile.ConstantNameAndType)1