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);
}
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;
}
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();
}
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;
}
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;
}
Aggregations