private Type mergeClasses(Type type) throws NotFoundException { CtClass superClass = findCommonSuperClass(this.clazz, type.clazz); // If its Object, then try and find a common interface(s) if (superClass.getSuperclass() == null) { Map interfaces = findCommonInterfaces(type); if (interfaces.size() == 1) return new Type((CtClass) interfaces.values().iterator().next()); if (interfaces.size() > 1) return new MultiType(interfaces); // Only Object is in common return new Type(superClass); } // Check for a common interface that is not on the found supertype Map commonDeclared = findExclusiveDeclaredInterfaces(type, superClass); if (commonDeclared.size() > 0) { return new MultiType(commonDeclared, new Type(superClass)); } return new Type(superClass); }
private Type createArray(Type rootComponent, int dims) { if (rootComponent instanceof MultiType) return new MultiArrayType((MultiType) rootComponent, dims); String name = arrayName(rootComponent.clazz.getName(), dims); Type type; try { type = Type.get(getClassPool(rootComponent).get(name)); } catch (NotFoundException e) { throw new RuntimeException(e); } return type; }
private Type mergeArray(Type type) { Type typeRoot = getRootComponent(type); Type thisRoot = getRootComponent(this); int typeDims = type.getDimensions(); int thisDims = this.getDimensions(); // Array commponents can be merged when the dimensions are equal if (typeDims == thisDims) { Type mergedComponent = thisRoot.merge(typeRoot); // If the components can not be merged (a primitive component mixed with a different type) // then Object is the common type. if (mergedComponent == Type.BOGUS) return Type.OBJECT; return createArray(mergedComponent, thisDims); } Type targetRoot; int targetDims; if (typeDims < thisDims) { targetRoot = typeRoot; targetDims = typeDims; } else { targetRoot = thisRoot; targetDims = thisDims; } // Special case, arrays are cloneable and serializable, so prefer them when dimensions differ if (eq(CLONEABLE.clazz, targetRoot.clazz) || eq(SERIALIZABLE.clazz, targetRoot.clazz)) return createArray(targetRoot, targetDims); return createArray(OBJECT, targetDims); }
private Map findCommonInterfaces(Type type) { Map typeMap = getAllInterfaces(type.clazz, null); Map thisMap = getAllInterfaces(this.clazz, null); return findCommonInterfaces(typeMap, thisMap); }
private Map findExclusiveDeclaredInterfaces(Type type, CtClass exclude) { Map typeMap = getDeclaredInterfaces(type.clazz, null); Map thisMap = getDeclaredInterfaces(this.clazz, null); Map excludeMap = getAllInterfaces(exclude, null); Iterator i = excludeMap.keySet().iterator(); while (i.hasNext()) { Object intf = i.next(); typeMap.remove(intf); thisMap.remove(intf); } return findCommonInterfaces(typeMap, thisMap); }
/** * Merges all types on the stack of this frame instance with that of the specified frame. * The local variable table is left untouched. * * @param frame the frame to merge the stack from * @return true if any changes where made */ public boolean mergeStack(Frame frame) { boolean changed = false; if (top != frame.top) throw new RuntimeException("Operand stacks could not be merged, they are different sizes!"); for (int i = 0; i < top; i++) { if (stack[i] != null) { Type prev = stack[i]; Type merged = prev.merge(frame.stack[i]); if (merged == Type.BOGUS) throw new RuntimeException("Operand stacks could not be merged due to differing primitive types: pos = " + i); stack[i] = merged; // always replace the instance in case a multi-interface type changes to a normal Type if ((! merged.equals(prev)) || merged.popChanged()) { changed = true; } } } return changed; }
public boolean isAssignableTo(Type type) { if (resolved != null) return type.isAssignableFrom(resolved); if (Type.OBJECT.equals(type)) return true; if (potentialClass != null && !type.isAssignableFrom(potentialClass)) potentialClass = null; Map map = mergeMultiAndSingle(this, type); if (map.size() == 1 && potentialClass == null) { // Update previous merge paths to the same resolved type resolved = Type.get((CtClass)map.values().iterator().next()); propogateResolved(); return true; } // Keep all previous merge paths up to date if (map.size() >= 1) { interfaces = map; propogateState(); return true; } if (potentialClass != null) { resolved = potentialClass; propogateResolved(); return true; } return false; }
return resolved.merge(type); Type mergePotential = potentialClass.merge(type); if (! mergePotential.equals(potentialClass) || mergePotential.popChanged()) { potentialClass = Type.OBJECT.equals(mergePotential) ? null : mergePotential; changed = true; resolved = Type.get((CtClass) merged.values().iterator().next()); } else if (potentialClass != null){ resolved = potentialClass;
Type type1 = frame.pop(); Type type2 = frame.pop(); if (type1.getSize() == 2 || type2.getSize() == 2) throw new BadBytecode("Swap can not be used with category 2 values, pos = " + pos); frame.push(type1); try { CtClass returnType = Descriptor.getReturnType(method.getDescriptor(), classPool); verifyAssignable(Type.get(returnType), simplePop(frame)); } catch (NotFoundException e) { throw new RuntimeException(e); case ARRAYLENGTH: { Type array = simplePop(frame); if (! array.isArray() && array != Type.UNINIT) throw new BadBytecode("Array length passed a non-array [pos = " + pos + "]: " + array); frame.push(Type.INTEGER);
/** * Obtain the Type for a given class. If the class is a primitive, * the the unique type instance for the primitive will be returned. * Otherwise a new Type instance representing the class is returned. * * @param clazz The java class * @return a type instance for this class */ public static Type get(CtClass clazz) { Type type = (Type)prims.get(clazz); return type != null ? type : new Type(clazz); }
private Type getType(String name) throws BadBytecode { try { return Type.get(classPool.get(name)); } catch (NotFoundException e) { throw new BadBytecode("Could not find class [pos = " + lastPos + "]: " + name); } }
public boolean equals(Object o) { if (! (o instanceof Type)) return false; return o.getClass() == getClass() && eq(clazz, ((Type)o).clazz); }
private Frame firstFrame(MethodInfo method, int maxLocals, int maxStack) { int pos = 0; Frame first = new Frame(maxLocals, maxStack); if ((method.getAccessFlags() & AccessFlag.STATIC) == 0) { first.setLocal(pos++, Type.get(clazz)); } CtClass[] parameters; try { parameters = Descriptor.getParameterTypes(method.getDescriptor(), clazz.getClassPool()); } catch (NotFoundException e) { throw new RuntimeException(e); } for (int i = 0; i < parameters.length; i++) { Type type = zeroExtend(Type.get(parameters[i])); first.setLocal(pos++, type); if (type.getSize() == 2) first.setLocal(pos++, Type.TOP); } return first; }
public boolean equals(Object o) { if (! (o instanceof MultiType)) return false; MultiType multi = (MultiType) o; if (resolved != null) return resolved.equals(multi.resolved); else if (multi.resolved != null) return false; return interfaces.keySet().equals(multi.interfaces.keySet()); }
Map getAllInterfaces(CtClass clazz, Map map) { if (map == null) map = new HashMap(); if (clazz.isInterface()) map.put(clazz.getName(), clazz); do { try { CtClass[] interfaces = clazz.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { CtClass intf = interfaces[i]; map.put(intf.getName(), intf); getAllInterfaces(intf, map); } clazz = clazz.getSuperclass(); } catch (NotFoundException e) { throw new RuntimeException(e); } } while (clazz != null); return map; }
/** * Merges all types on the stack and local variable table of this frame with that of the specified * type. * * @param frame the frame to merge with * @return true if any changes to this frame where made by this merge */ public boolean merge(Frame frame) { boolean changed = false; // Local variable table for (int i = 0; i < locals.length; i++) { if (locals[i] != null) { Type prev = locals[i]; Type merged = prev.merge(frame.locals[i]); // always replace the instance in case a multi-interface type changes to a normal Type locals[i] = merged; if (! merged.equals(prev) || merged.popChanged()) { changed = true; } } else if (frame.locals[i] != null) { locals[i] = frame.locals[i]; changed = true; } } changed |= mergeStack(frame); return changed; }
private Map<String,CtClass> findExclusiveDeclaredInterfaces(Type type, CtClass exclude) { Map<String,CtClass> typeMap = getDeclaredInterfaces(type.clazz, null); Map<String,CtClass> thisMap = getDeclaredInterfaces(this.clazz, null); Map<String,CtClass> excludeMap = getAllInterfaces(exclude, null); for (String intf:excludeMap.keySet()) { typeMap.remove(intf); thisMap.remove(intf); } return findCommonInterfaces(typeMap, thisMap); }
public boolean isAssignableTo(Type type) { if (resolved != null) return type.isAssignableFrom(resolved); if (Type.OBJECT.equals(type)) return true; if (potentialClass != null && !type.isAssignableFrom(potentialClass)) potentialClass = null; Map<String,CtClass> map = mergeMultiAndSingle(this, type); if (map.size() == 1 && potentialClass == null) { // Update previous merge paths to the same resolved type resolved = Type.get(map.values().iterator().next()); propogateResolved(); return true; } // Keep all previous merge paths up to date if (map.size() >= 1) { interfaces = map; propogateState(); return true; } if (potentialClass != null) { resolved = potentialClass; propogateResolved(); return true; } return false; }
return resolved.merge(type); Type mergePotential = potentialClass.merge(type); if (! mergePotential.equals(potentialClass) || mergePotential.popChanged()) { potentialClass = Type.OBJECT.equals(mergePotential) ? null : mergePotential; changed = true; resolved = Type.get(merged.values().iterator().next()); else if (potentialClass != null) resolved = potentialClass;
private Map<String,CtClass> findCommonInterfaces(Type type) { Map<String,CtClass> typeMap = getAllInterfaces(type.clazz, null); Map<String,CtClass> thisMap = getAllInterfaces(this.clazz, null); return findCommonInterfaces(typeMap, thisMap); }