Search in sources :

Example 6 with JavaClassFormatError

use of com.jopdesign.common.misc.JavaClassFormatError in project jop by jop-devel.

the class AppInfo method findImplementations.

/**
     * Find all methods which might get invoked for a given invokesite.
     * This uses the callgraph returned by {@link #getCallGraph()} to lookup possible implementations.
     * Use callgraph thinning to make the result of this method more precise.
     * If the callgraph has not yet been built by {@link #buildCallGraph(boolean)}, this uses
     * {@link #findImplementations(MethodRef)} to resolve virtual invocations.
     *
     * @param cs the callstring to the the invocation, including the given invokesite. Must not be empty.
     * @return a list of possible implementations for the invocation including native methods, or an empty set if resolution fails or is not safe.
     */
public Set<MethodInfo> findImplementations(CallString cs) {
    if (cs.length() == 0) {
        throw new AssertionError("findImplementations() called with empty callstring!");
    }
    InvokeSite invokeSite = cs.top();
    // callgraph is at least one, else we will get incorrect results
    if (!invokeSite.isVirtual()) {
        Set<MethodInfo> methods = new LinkedHashSet<MethodInfo>();
        MethodInfo method = invokeSite.getInvokeeRef().getMethodInfo();
        if (method == null) {
            return methods;
        }
        if (method.isAbstract()) {
            throw new JavaClassFormatError("Invokespecial calls abstract method " + invokeSite.getInvokeeRef());
        }
        methods.add(method);
        return methods;
    }
    if (callGraph == null) {
        // we do not have a callgraph, so just use typegraph info
        return findImplementations(invokeSite.getInvokeeRef());
    }
    if (!callGraph.containsMethod(invokeSite.getInvoker())) {
        if (logger.isTraceEnabled()) {
            logger.trace("Could not find method " + invokeSite.getInvoker() + " in the callgraph, falling back to typegraph");
        }
        return findImplementations(invokeSite.getInvokeeRef());
    }
    return callGraph.findImplementations(cs);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) JavaClassFormatError(com.jopdesign.common.misc.JavaClassFormatError) InvokeSite(com.jopdesign.common.code.InvokeSite)

Example 7 with JavaClassFormatError

use of com.jopdesign.common.misc.JavaClassFormatError in project jop by jop-devel.

the class AppInfo method findImplementations.

/**
     * Find all methods which might get invoked for a given methodRef.
     * This does not use the callgraph to eliminate methods. If you want a more precise result,
     * use {@link #findImplementations(InvokeSite, CallString)} and use callgraph thinning first.
     * <p>
     * Note that this method is slightly different from {@link MethodInfo#getImplementations(boolean)}, since
     * it returns only methods for subclasses of the invokee class, not of the implementing class.
     * </p>
     * <p>To handle invocations of super-methods correctly, use {@link #findImplementations(InvokeSite)}
     * instead.</p>
     *
     * @see #findImplementations(InvokeSite)
     * @see MethodInfo#overrides(MethodRef, boolean)
     * @param invokee the method to resolve.
     * @return all possible implementations, including native methods.
     */
public Set<MethodInfo> findImplementations(final MethodRef invokee) {
    final Set<MethodInfo> methods = new LinkedHashSet<MethodInfo>();
    // 'method' may refer to an inherited MethodInfo or to an interface method if there is no implementation
    final MethodInfo method = invokee.getMethodInfo();
    if (method != null && (method.isStatic() || method.isPrivate())) {
        methods.add(method);
        return methods;
    }
    final String methodSig = invokee.getMethodSignature();
    final ClassInfo invokeeClass = invokee.getClassRef().getClassInfo();
    if (invokeeClass == null) {
        // ok, now, if the target class is unknown, there is not much we can do, so return an empty set
        logger.debug("Trying to find implementations of a method in an unknown class " + invokee.toString());
        return methods;
    }
    // Constructors are only called by invokespecial
    if ("<init>".equals(invokee.getName())) {
        MethodInfo init = invokee.getMethodInfo();
        if (init == null) {
            throw new JavaClassFormatError("Constructor not found: " + invokee);
        }
        if (init.isAbstract()) {
            throw new JavaClassFormatError("Found abstract constructor, this isn't right..: " + invokee);
        }
        methods.add(init);
        return methods;
    }
    boolean undefinedBaseMethod = false;
    // check if method is defined in the referenced class or in a superclass
    if (invokeeClass.getMethodInfo(methodSig) == null) {
        // method is inherited, add to implementations
        if (method != null && !method.isAbstract()) {
            methods.add(method);
        } else if (method == null) {
            // hm, invoke to an unknown method (maybe excluded or native), what should we do?
            if (invokeeClass.isFullyKnown(true)) {
                // .. or maybe the method has not been loaded somehow when the MethodRef was created (check!)
                throw new JavaClassFormatError("Method implementation not found in superclass: " + invokee.toString());
            } else {
                // maybe defined in excluded superclass, but we do not know for sure..
                // We *must* return an empty set, but lets try to continue for now and
                // handle it like an excluded class, and abort only if we find overriding methods
                logger.debug("Method implementation not found in incomplete superclass: " + invokee.toString());
                undefinedBaseMethod = true;
            }
        }
    }
    // now, we have a virtual call on our hands ..
    ClassVisitor visitor = new ClassVisitor() {

        public boolean visitClass(ClassInfo classInfo) {
            // Note: we also handle interface classes here, because they can contain <clinit> methods
            MethodInfo m;
            if (invokeeClass.isInterface() && !classInfo.isInterface()) {
                // If we invoke an interface method, we also need to find inherited methods in implementing
                // classes
                m = classInfo.getMethodInfoInherited(methodSig, true);
            } else {
                // If we do not invoke an interface method, 'method' is already the only possible inherited 
                // method; If the visited class is an interface, it does not inherit implementations.
                m = classInfo.getMethodInfo(methodSig);
            }
            if (m != null) {
                if (m.isPrivate() && !classInfo.equals(invokeeClass)) {
                    // found an overriding method which is private .. this is interesting..
                    logger.error("Found private method " + m.getMethodSignature() + " in " + classInfo.getClassName() + " overriding non-private method in " + invokee.getClassName());
                }
                if (!m.isAbstract() && (method == null || m.overrides(method, false))) {
                    methods.add(m);
                }
            }
            return true;
        }

        public void finishClass(ClassInfo classInfo) {
        }
    };
    ClassHierarchyTraverser traverser = new ClassHierarchyTraverser(visitor);
    traverser.setVisitSubclasses(true, true);
    traverser.traverseDown(invokeeClass);
    if (undefinedBaseMethod && methods.size() > 0) {
        // overriding methods, this we cannot handle for now
        throw new JavaClassFormatError("Found overriding methods for " + invokee + " but superclasses are undefined!");
    }
    return methods;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) JavaClassFormatError(com.jopdesign.common.misc.JavaClassFormatError) ClassHierarchyTraverser(com.jopdesign.common.graphutils.ClassHierarchyTraverser) CallString(com.jopdesign.common.code.CallString) ClassVisitor(com.jopdesign.common.graphutils.ClassVisitor)

Example 8 with JavaClassFormatError

use of com.jopdesign.common.misc.JavaClassFormatError 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 9 with JavaClassFormatError

use of com.jopdesign.common.misc.JavaClassFormatError in project jop by jop-devel.

the class InstructionInterpreter method getOutEdges.

private List<Edge> getOutEdges(InstructionHandle ih) {
    List<Edge> edges = new LinkedList<Edge>();
    Instruction instr = ih.getInstruction();
    if (instr instanceof BranchInstruction) {
        if (instr instanceof Select) {
            Select s = (Select) instr;
            InstructionHandle[] target = s.getTargets();
            for (InstructionHandle aTarget : target) {
                edges.add(new Edge(ih, aTarget, EdgeType.TRUE_EDGE));
            }
            edges.add(new Edge(ih, s.getTarget(), EdgeType.FALSE_EDGE));
        } else {
            BranchInstruction b = (BranchInstruction) instr;
            edges.add(new Edge(ih, b.getTarget(), EdgeType.TRUE_EDGE));
        }
    }
    // Check if we can fall through to the next instruction
    if (ih.getNext() != null && !(instr instanceof UnconditionalBranch || instr instanceof Select || instr instanceof ReturnInstruction)) {
        if (instr instanceof BranchInstruction) {
            edges.add(new Edge(ih, ih.getNext(), EdgeType.FALSE_EDGE));
        } else {
            edges.add(new Edge(ih, ih.getNext(), EdgeType.NORMAL_EDGE));
        }
    }
    if (instr instanceof ReturnInstruction) {
        edges.add(new Edge(ih, getExitInstruction(), EdgeType.EXIT_EDGE));
    }
    if (instr instanceof ATHROW) {
    // TODO should we handle this somehow? Insert edges to the exception handlers or to an return-by-exception
    //      exit instruction?
    // for now, just ignore them
    }
    //      but for now, we just ignore them too.. in a safe way :)
    if (instr instanceof RET || instr instanceof JSR || instr instanceof JSR_W) {
        throw new JavaClassFormatError("Unsupported instruction " + instr + " in " + methodInfo);
    }
    return edges;
}
Also used : RET(org.apache.bcel.generic.RET) UnconditionalBranch(org.apache.bcel.generic.UnconditionalBranch) BranchInstruction(org.apache.bcel.generic.BranchInstruction) JSR(org.apache.bcel.generic.JSR) ATHROW(org.apache.bcel.generic.ATHROW) BranchInstruction(org.apache.bcel.generic.BranchInstruction) Instruction(org.apache.bcel.generic.Instruction) ReturnInstruction(org.apache.bcel.generic.ReturnInstruction) LinkedList(java.util.LinkedList) InstructionHandle(org.apache.bcel.generic.InstructionHandle) ReturnInstruction(org.apache.bcel.generic.ReturnInstruction) JavaClassFormatError(com.jopdesign.common.misc.JavaClassFormatError) Select(org.apache.bcel.generic.Select) JSR_W(org.apache.bcel.generic.JSR_W)

Example 10 with JavaClassFormatError

use of com.jopdesign.common.misc.JavaClassFormatError in project jop by jop-devel.

the class InvokeSite method isSuperMethod.

/**
     * Check if this invokespecial is a super invoke. Does NOT check if the instruction is indeed an
     * special invoke, check this first!
     * See #isInvokeSuper() for more details.
     *
     * @param invokee the method referenced by the instruction.
     * @return true if this references to a super method
     */
private boolean isSuperMethod(MethodRef invokee) {
    // This is the class where the invoker method is defined (not the class of the object instance!)
    ClassInfo cls = invoker.getClassInfo();
    if (!cls.hasSuperFlag())
        return false;
    if ("<init>".equals(invokee.getName()))
        return false;
    // just to handle some special cases of unknown superclasses gracefully, without requiring a classInfo
    if (cls.getClassName().equals(invokee.getClassName())) {
        // this is an invoke within the same class, no super here
        return false;
    }
    if (cls.isRootClass()) {
        // trying to call a super-method of Object? Not likely, dude ..
        return false;
    }
    // do not need to check interfaces, since invokespecial must not call interface methods
    Ternary rs = cls.hasSuperClass(invokee.getClassName(), false);
    if (rs == Ternary.UNKNOWN) {
        if (invokee.getClassRef().getClassInfo() != null) {
            // class exists, but method does not exists, either an error or superclasses are missing
            throw new JavaClassFormatError("Invokespecial tries to call " + invokee + " but this method has not been found");
        }
        // invokespecial to an unknown class, we cannot handle this safely
        throw new JavaClassFormatError("Could not determine if invokespecial is a super invoke for " + invokee);
    }
    return rs == Ternary.TRUE;
}
Also used : Ternary(com.jopdesign.common.misc.Ternary) JavaClassFormatError(com.jopdesign.common.misc.JavaClassFormatError) ClassInfo(com.jopdesign.common.ClassInfo)

Aggregations

JavaClassFormatError (com.jopdesign.common.misc.JavaClassFormatError)16 ClassInfo (com.jopdesign.common.ClassInfo)4 MethodInfo (com.jopdesign.common.MethodInfo)3 Iterator (java.util.Iterator)3 LinkedList (java.util.LinkedList)3 InstructionHandle (org.apache.bcel.generic.InstructionHandle)3 AppInfo (com.jopdesign.common.AppInfo)2 CallString (com.jopdesign.common.code.CallString)2 ClassHierarchyTraverser (com.jopdesign.common.graphutils.ClassHierarchyTraverser)2 ClassVisitor (com.jopdesign.common.graphutils.ClassVisitor)2 ConstantMethodInfo (com.jopdesign.common.type.ConstantMethodInfo)2 MethodRef (com.jopdesign.common.type.MethodRef)2 LinkedHashSet (java.util.LinkedHashSet)2 ConstantClass (org.apache.bcel.classfile.ConstantClass)2 ConstantFieldref (org.apache.bcel.classfile.ConstantFieldref)2 ConstantInterfaceMethodref (org.apache.bcel.classfile.ConstantInterfaceMethodref)2 ConstantMethodref (org.apache.bcel.classfile.ConstantMethodref)2 ConstantNameAndType (org.apache.bcel.classfile.ConstantNameAndType)2 ConstantString (org.apache.bcel.classfile.ConstantString)2 ConstantPoolGen (org.apache.bcel.generic.ConstantPoolGen)2