protected void fillSupers(ClassFile clazz) { String name = clazz.getName(); List<String> list = supers.get(name); if (list == null) { list = new ArrayList<>(); supers.put(name, list); } if (clazz.isInterface()) { Collections.addAll(list, clazz.getInterfaces()); } else { String superclass = clazz.getSuperclass(); if (superclass != null) { list.add(superclass); } } }
public BaseClassData(ClassFile file, ClassLoader loader, boolean replaceable) { className = file.getName(); this.replaceable = replaceable; internalName = Descriptor.toJvmName(file.getName()); this.loader = loader; superClassName = file.getSuperclass(); boolean finalMethod = false; Set<MethodData> meths = new HashSet<MethodData>(); for (Object o : file.getMethods()) { String methodClassName = className; MethodInfo m = (MethodInfo) o; MemberType type = MemberType.NORMAL; if ((m.getDescriptor().equals(Constants.ADDED_METHOD_DESCRIPTOR) && m.getName().equals(Constants.ADDED_METHOD_NAME)) || (m.getDescriptor().equals(Constants.ADDED_STATIC_METHOD_DESCRIPTOR) && m.getName().equals(Constants.ADDED_STATIC_METHOD_NAME)) || (m.getDescriptor().equals(Constants.ADDED_CONSTRUCTOR_DESCRIPTOR))) { type = MemberType.ADDED_SYSTEM; } else if (m.getAttribute(Constants.FINAL_METHOD_ATTRIBUTE) != null) { finalMethod = true; } MethodData md = new MethodData( m.getName(), m.getDescriptor(), methodClassName, type, m.getAccessFlags(), finalMethod); meths.add(md); } this.methods = Collections.unmodifiableSet(meths); Set<FieldData> fieldData = new HashSet<FieldData>(); for (Object o : file.getFields()) { FieldInfo m = (FieldInfo) o; MemberType mt = MemberType.NORMAL; fieldData.add(new FieldData(m, mt, className, m.getAccessFlags())); } this.fields = Collections.unmodifiableSet(fieldData); }
/** * When creates the delegate initializer code when the delegate is injected into a method. * * <p>super initializer method is called first, and then _initMH is called * * @param file * @param intializerMethodInfo * @param delegateParameterPosition * @return */ private Bytecode createDelegateInitializerCode( ClassFile file, MethodInformation intializerMethodInfo, int delegateParameterPosition) { Bytecode b = new Bytecode(file.getConstPool()); // we need to push all the pareters on the stack to call the corresponding // superclass arguments b.addAload(0); // load this int localVariables = 1; int actualDelegateParamterPosition = 0; for (int i = 0; i < intializerMethodInfo.getMethod().getParameterTypes().length; ++i) { if (i == delegateParameterPosition) { // figure out the actual position of the delegate in the local // variables actualDelegateParamterPosition = localVariables; } Class<?> type = intializerMethodInfo.getMethod().getParameterTypes()[i]; BytecodeUtils.addLoadInstruction( b, DescriptorUtils.classToStringRepresentation(type), localVariables); if (type == long.class || type == double.class) { localVariables = localVariables + 2; } else { localVariables++; } } b.addInvokespecial( file.getSuperclass(), intializerMethodInfo.getName(), intializerMethodInfo.getDescriptor()); // if this method returns a value it is now sitting on top of the stack // we will leave it there are return it later // now we need to call _initMH b.addAload(0); // load this b.addAload(actualDelegateParamterPosition); // load the delegate b.addInvokevirtual(file.getName(), "_initMH", "(Ljava/lang/Object;)V"); // return the object from the top of the stack that we got from calling // the superclass method earlier BytecodeUtils.addReturnInstruction(b, intializerMethodInfo.getReturnType()); b.setMaxLocals(localVariables); return b; }
/** Add a method to a class that simply delegates to the parent implementation of the method */ public static void addDelegatingMethod(ClassFile file, MethodData mData) throws BadBytecode, DuplicateMemberException { MethodInfo m = new MethodInfo(file.getConstPool(), mData.getMethodName(), mData.getDescriptor()); m.setAccessFlags(mData.getAccessFlags()); Bytecode code = new Bytecode(file.getConstPool()); String[] params = DescriptorUtils.descriptorStringToParameterArray(mData.getDescriptor()); code.add(Opcode.ALOAD_0); // push this int count = 1; // zero is the this pointer int maxLocals = 1; for (String p : params) { // int char short boolean byte if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) { // push integer 0 code.addIload(count); maxLocals++; } // long else if (p.equals("J")) { code.addLload(count); maxLocals += 2; count++; } // double else if (p.equals("D")) { code.addDload(count); maxLocals += 2; count++; } // float else if (p.equals("F")) { code.addFload(count); maxLocals++; } // arrays and reference types else { code.addAload(count); maxLocals++; } count++; } code.addInvokespecial(file.getSuperclass(), mData.getMethodName(), mData.getDescriptor()); String p = DescriptorUtils.getReturnTypeInJvmFormat(mData.getDescriptor()); // int char short boolean byte if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) { code.add(Opcode.IRETURN); } // long else if (p.equals("J")) { code.add(Opcode.LRETURN); } // double else if (p.equals("D")) { code.add(Opcode.DRETURN); } // float else if (p.equals("F")) { code.add(Opcode.FRETURN); } // void else if (p.equals("V")) { code.add(Opcode.RETURN); } // arrays and reference types else { code.add(Opcode.ARETURN); } CodeAttribute ca = code.toCodeAttribute(); ca.computeMaxStack(); ca.setMaxLocals(maxLocals); m.setCodeAttribute(ca); file.addMethod(m); }