Search in sources :

Example 1 with BaseClassData

use of org.fakereplace.data.BaseClassData in project fakereplace by fakereplace.

the class FieldReplacementTransformer method transform.

@Override
public boolean transform(ClassLoader loader, String className, Class<?> oldClass, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    if (oldClass == null || className == null) {
        return false;
    }
    BaseClassData data = ClassDataStore.instance().getBaseClassData(loader, Descriptor.toJvmName(file.getName()));
    Set<FieldData> fields = new LinkedHashSet<>();
    fields.addAll(data.getFields());
    ListIterator<?> it = file.getFields().listIterator();
    final Set<FieldData> toRemove = new HashSet<>();
    final Set<FieldProxyInfo> toAdd = new HashSet<>();
    while (it.hasNext()) {
        FieldInfo m = (FieldInfo) it.next();
        FieldData md = null;
        for (FieldData i : fields) {
            if (i.getName().equals(m.getName()) && i.getType().equals(m.getDescriptor()) && i.getAccessFlags() == m.getAccessFlags()) {
                try {
                    Field field = i.getField(oldClass);
                    AnnotationDataStore.recordFieldAnnotations(field, (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag));
                    // now revert the annotations:
                    m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), field));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                md = i;
                break;
            }
        }
        // This is a newly added field.
        if (md == null) {
            int fieldNo = addField(loader, m, toAdd, oldClass);
            Transformer.getManipulator().rewriteInstanceFieldAccess(fieldNo, m.getName(), m.getDescriptor(), file.getName(), loader);
            it.remove();
        } else {
            fields.remove(md);
        }
    }
    // TODO: rewrite classes that access them to throw a NoSuchFieldError
    for (FieldData md : fields) {
        if (md.getMemberType() == MemberType.NORMAL) {
            FieldInfo old = new FieldInfo(file.getConstPool(), md.getName(), md.getType());
            old.setAccessFlags(md.getAccessFlags());
            toRemove.add(md);
        }
    }
    // clear all the fields and re-add them in the correct order
    // turns out order is important
    file.getFields().clear();
    for (FieldData md : data.getFields()) {
        if (md.getMemberType() == MemberType.NORMAL) {
            try {
                Field field = md.getField(oldClass);
                FieldInfo old = new FieldInfo(file.getConstPool(), md.getName(), md.getType());
                old.setAccessFlags(md.getAccessFlags());
                file.addField(old);
                old.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), field));
            } catch (DuplicateMemberException | SecurityException | NoSuchFieldException e) {
                // this should not happen
                throw new RuntimeException(e);
            }
        }
    }
    ClassDataStore.instance().modifyCurrentData(loader, file.getName(), (builder) -> {
        for (FieldProxyInfo field : toAdd) {
            builder.addFakeField(field.fieldData, field.proxyName, field.modifiers);
        }
        for (FieldData field : toRemove) {
            builder.removeField(field);
        }
    });
    return true;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) FieldData(org.fakereplace.data.FieldData) Field(java.lang.reflect.Field) BaseClassData(org.fakereplace.data.BaseClassData) FieldInfo(javassist.bytecode.FieldInfo) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 2 with BaseClassData

use of org.fakereplace.data.BaseClassData in project fakereplace by fakereplace.

the class MethodReplacementTransformer method transform.

@Override
public boolean transform(ClassLoader loader, String className, Class<?> oldClass, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    if (oldClass == null || className == null) {
        return false;
    }
    final Set<MethodData> methodsToRemove = new HashSet<>();
    final Set<FakeMethod> methodsToAdd = new HashSet<>();
    final Set<FakeMethod> constructorsToAdd = new HashSet<>();
    BaseClassData data = ClassDataStore.instance().getBaseClassData(loader, className);
    // state for added static methods
    CodeAttribute staticCodeAttribute = null, virtualCodeAttribute = null, constructorCodeAttribute = null;
    try {
        // stick our added methods into the class file
        // we can't finalise the code yet because we will probably need
        // the add stuff to them
        MethodInfo virtMethod = new MethodInfo(file.getConstPool(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
        modifiedMethods.add(virtMethod);
        virtMethod.setAccessFlags(AccessFlag.PUBLIC);
        if (file.isInterface()) {
            virtMethod.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.ABSTRACT | AccessFlag.SYNTHETIC);
        } else {
            virtMethod.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.SYNTHETIC);
            Bytecode b = new Bytecode(file.getConstPool(), 0, 3);
            if (BuiltinClassData.skipInstrumentation(file.getSuperclass())) {
                b.addNew(NoSuchMethodError.class.getName());
                b.add(Opcode.DUP);
                b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
                b.add(Opcode.ATHROW);
            } else {
                b.add(Bytecode.ALOAD_0);
                b.add(Bytecode.ILOAD_1);
                b.add(Bytecode.ALOAD_2);
                b.addInvokespecial(file.getSuperclass(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
                b.add(Bytecode.ARETURN);
            }
            virtualCodeAttribute = b.toCodeAttribute();
            virtMethod.setCodeAttribute(virtualCodeAttribute);
            MethodInfo m = new MethodInfo(file.getConstPool(), Constants.ADDED_STATIC_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
            modifiedMethods.add(m);
            m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC | AccessFlag.SYNTHETIC);
            b = new Bytecode(file.getConstPool(), 0, 3);
            b.addNew(NoSuchMethodError.class.getName());
            b.add(Opcode.DUP);
            b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
            b.add(Opcode.ATHROW);
            staticCodeAttribute = b.toCodeAttribute();
            m.setCodeAttribute(staticCodeAttribute);
            file.addMethod(m);
            m = new MethodInfo(file.getConstPool(), "<init>", Constants.ADDED_CONSTRUCTOR_DESCRIPTOR);
            modifiedMethods.add(m);
            m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.SYNTHETIC);
            b = new Bytecode(file.getConstPool(), 0, 4);
            if (ManipulationUtils.addBogusConstructorCall(file, b)) {
                constructorCodeAttribute = b.toCodeAttribute();
                m.setCodeAttribute(constructorCodeAttribute);
                constructorCodeAttribute.setMaxLocals(6);
                file.addMethod(m);
            }
        }
        file.addMethod(virtMethod);
    } catch (DuplicateMemberException e) {
        e.printStackTrace();
    }
    Set<MethodData> methods = new HashSet<>();
    methods.addAll(data.getMethods());
    ListIterator<?> it = file.getMethods().listIterator();
    // IncompatibleClassChange exception will be thrown
    while (it.hasNext()) {
        MethodInfo m = (MethodInfo) it.next();
        MethodData md = null;
        boolean upgradedVisibility = false;
        for (MethodData i : methods) {
            if (i.getMethodName().equals(m.getName()) && i.getDescriptor().equals(m.getDescriptor())) {
                // depends on what has changed
                if (i.getAccessFlags() != m.getAccessFlags()) {
                    if (AccessFlagUtils.upgradeVisibility(m.getAccessFlags(), i.getAccessFlags())) {
                        upgradedVisibility = true;
                    } else if (AccessFlagUtils.downgradeVisibility(m.getAccessFlags(), i.getAccessFlags())) {
                    // ignore this, we don't need to do anything
                    } else {
                        // we can't handle this yet
                        continue;
                    }
                }
                m.setAccessFlags(i.getAccessFlags());
                // if it is the constructor
                if (m.getName().equals("<init>")) {
                    try {
                        Constructor<?> meth = i.getConstructor(oldClass);
                        AnnotationDataStore.recordConstructorAnnotations(meth, (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag));
                        AnnotationDataStore.recordConstructorParameterAnnotations(meth, (ParameterAnnotationsAttribute) m.getAttribute(ParameterAnnotationsAttribute.visibleTag));
                        // now revert the annotations:
                        m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
                        m.addAttribute(AnnotationReplacer.duplicateParameterAnnotationsAttribute(file.getConstPool(), meth));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                } else if (!m.getName().equals("<clinit>")) {
                    // we do not have to worry about them
                    try {
                        Method meth = i.getMethod(oldClass);
                        AnnotationDataStore.recordMethodAnnotations(meth, (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag));
                        AnnotationDataStore.recordMethodParameterAnnotations(meth, (ParameterAnnotationsAttribute) m.getAttribute(ParameterAnnotationsAttribute.visibleTag));
                        // now revert the annotations:
                        m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
                        m.addAttribute(AnnotationReplacer.duplicateParameterAnnotationsAttribute(file.getConstPool(), meth));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                md = i;
                break;
            }
        }
        // we do not need to deal with these
        if (m.getName().equals(Constants.ADDED_METHOD_NAME) || m.getName().equals(Constants.ADDED_STATIC_METHOD_NAME)) {
            break;
        }
        // so it is still in the original
        if (md == null || upgradedVisibility) {
            if ((m.getAccessFlags() & AccessFlag.STATIC) != 0) {
                Class<?> c = addMethod(file, loader, m, methodsToAdd, staticCodeAttribute, true, oldClass);
                if (c != null) {
                    classesToRetransform.add(c);
                }
            } else if ((m.getName().equals("<init>"))) {
                addConstructor(file, loader, m, constructorsToAdd, constructorCodeAttribute, oldClass);
            } else if (m.getName().equals("<clinit>")) {
            // nop, we can't change this, just ignore it
            } else {
                Class<?> c = addMethod(file, loader, m, methodsToAdd, virtualCodeAttribute, false, oldClass);
                if (c != null) {
                    classesToRetransform.add(c);
                }
            }
            if (!upgradedVisibility) {
                it.remove();
            }
        } else {
            methods.remove(md);
        }
        if (upgradedVisibility) {
            methods.remove(md);
        }
    }
    for (MethodData md : methods) {
        if (md.getType() == MemberType.NORMAL) {
            MethodInfo removedMethod = createRemovedMethod(file, md, oldClass, methodsToRemove);
            if (removedMethod != null) {
                modifiedMethods.add(removedMethod);
            }
        }
    }
    ClassDataStore.instance().modifyCurrentData(loader, className, (builder) -> {
        for (MethodData method : methodsToRemove) {
            builder.removeMethod(method);
        }
        for (FakeMethod fake : methodsToAdd) {
            ClassDataStore.instance().registerReplacedMethod(fake.proxyName, builder.addFakeMethod(fake.name, fake.descriptor, fake.proxyName, fake.accessFlags));
        }
        for (FakeMethod fake : constructorsToAdd) {
            ClassDataStore.instance().registerReplacedMethod(fake.proxyName, builder.addFakeConstructor(fake.name, fake.descriptor, fake.proxyName, fake.accessFlags, fake.methodCount));
        }
    });
    // the method declaration to propagate the call to the parent
    if (!file.isInterface()) {
        try {
            staticCodeAttribute.computeMaxStack();
            virtualCodeAttribute.computeMaxStack();
            if (constructorCodeAttribute != null) {
                constructorCodeAttribute.computeMaxStack();
            }
        } catch (BadBytecode e) {
            e.printStackTrace();
        }
    }
    return true;
}
Also used : DuplicateMemberException(javassist.bytecode.DuplicateMemberException) ParameterAnnotationsAttribute(javassist.bytecode.ParameterAnnotationsAttribute) ParameterAnnotationsAttribute(javassist.bytecode.ParameterAnnotationsAttribute) AnnotationsAttribute(javassist.bytecode.AnnotationsAttribute) Method(java.lang.reflect.Method) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) BadBytecode(javassist.bytecode.BadBytecode) BaseClassData(org.fakereplace.data.BaseClassData) CodeAttribute(javassist.bytecode.CodeAttribute) MethodData(org.fakereplace.data.MethodData) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) HashSet(java.util.HashSet)

Example 3 with BaseClassData

use of org.fakereplace.data.BaseClassData in project fakereplace by fakereplace.

the class Fakereplace method redefine.

public static void redefine(ClassDefinition[] classes, AddedClass[] addedData, boolean wait) {
    try {
        for (AddedClass i : addedData) {
            ClassFile cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(i.getData())));
            mainTransformer.addNewClass(new NewClassData(i.getClassName(), i.getLoader(), cf));
        }
        for (ClassDefinition i : classes) {
            ClassDataStore.instance().markClassReplaced(i.getDefinitionClass());
            BaseClassData baseClassData = ClassDataStore.instance().getBaseClassData(i.getDefinitionClass().getClassLoader(), i.getDefinitionClass().getName());
            if (baseClassData != null) {
                ClassDataStore.instance().saveClassData(i.getDefinitionClass().getClassLoader(), i.getDefinitionClass().getName(), new ClassDataBuilder(baseClassData));
            }
        }
        for (AddedClass c : addedData) {
            ClassLookupManager.addClassInfo(c.getClassName(), c.getLoader(), c.getData());
        }
        inst.redefineClasses(classes);
        clearJvmCaches();
        if (wait) {
            mainTransformer.waitForTasks();
        }
    } catch (Throwable e) {
        try {
            // dump the classes to /tmp so we can look at them
            for (ClassDefinition d : classes) {
                try {
                    ByteArrayInputStream bin = new ByteArrayInputStream(d.getDefinitionClassFile());
                    DataInputStream dis = new DataInputStream(bin);
                    final ClassFile file = new ClassFile(dis);
                    Transformer.getManipulator().transformClass(file, d.getDefinitionClass().getClassLoader(), true, new HashSet<>());
                    String dumpDir = AgentOptions.getOption(AgentOption.DUMP_DIR);
                    if (dumpDir != null) {
                        FileOutputStream s = new FileOutputStream(dumpDir + '/' + d.getDefinitionClass().getName() + "1.class");
                        DataOutputStream dos = new DataOutputStream(s);
                        file.write(dos);
                        dos.flush();
                        dos.close();
                        // s.write(d.getDefinitionClassFile());
                        s.close();
                    }
                } catch (IOException a) {
                    a.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        throw (new RuntimeException(e));
    }
}
Also used : ClassFile(javassist.bytecode.ClassFile) DataOutputStream(java.io.DataOutputStream) AddedClass(org.fakereplace.replacement.AddedClass) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream) ClassDefinition(java.lang.instrument.ClassDefinition) ClassDataBuilder(org.fakereplace.data.ClassDataBuilder) IOException(java.io.IOException) UnmodifiableClassException(java.lang.instrument.UnmodifiableClassException) BaseClassData(org.fakereplace.data.BaseClassData) ByteArrayInputStream(java.io.ByteArrayInputStream) NewClassData(org.fakereplace.api.NewClassData) FileOutputStream(java.io.FileOutputStream) HashSet(java.util.HashSet)

Example 4 with BaseClassData

use of org.fakereplace.data.BaseClassData in project fakereplace by fakereplace.

the class Transformer method transform.

public boolean transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    boolean modified = false;
    if (classBeingRedefined != null) {
        ClassDataStore.instance().markClassReplaced(classBeingRedefined);
    }
    // java/io namespace except for java/lang/reflect/Proxy
    if (BuiltinClassData.skipInstrumentation(className)) {
        if (classBeingRedefined != null && manipulator.transformClass(file, loader, false, modifiedMethods)) {
            modified = true;
        }
        return modified;
    }
    if (classBeingRedefined == null) {
        AnnotationsAttribute at = (AnnotationsAttribute) file.getAttribute(AnnotationsAttribute.invisibleTag);
        if (at != null) {
            // NoInstrument is used for testing or by integration modules
            Object an = at.getAnnotation(NoInstrument.class.getName());
            if (an != null) {
                return modified;
            }
        }
    }
    final boolean replaceable = Fakereplace.isClassReplaceable(className, loader);
    if (manipulator.transformClass(file, loader, replaceable, modifiedMethods)) {
        modified = true;
    }
    if (replaceable) {
        if ((AccessFlag.ENUM & file.getAccessFlags()) == 0 && (AccessFlag.ANNOTATION & file.getAccessFlags()) == 0) {
            modified = true;
            watcher.addClassFile(className, loader);
            if (file.isInterface()) {
                addAbstractMethodForInstrumentation(file);
            } else {
                addMethodForInstrumentation(file);
                addConstructorForInstrumentation(file);
                addStaticConstructorForInstrumentation(file);
            }
        }
        if (classBeingRedefined == null) {
            BaseClassData baseData = new BaseClassData(file, loader, replaceable);
            ClassDataStore.instance().saveClassData(loader, baseData.getInternalName(), baseData);
        }
    }
    // file.getSuperclass(), classfileBuffer);
    return modified;
}
Also used : NoInstrument(org.fakereplace.util.NoInstrument) BaseClassData(org.fakereplace.data.BaseClassData) AnnotationsAttribute(javassist.bytecode.AnnotationsAttribute)

Example 5 with BaseClassData

use of org.fakereplace.data.BaseClassData in project fakereplace by fakereplace.

the class FakeMethodCallManipulator method transformClass.

public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
    if (!Fakereplace.isRetransformationStarted()) {
        return false;
    }
    final Map<String, Set<Data>> knownFakeMethods = data.getManipulationData(loader);
    // methods that are known to need a rewrite to a generated static method
    final Map<Integer, Data> knownFakeMethodCallLocations = new HashMap<>();
    // methods that may need a rewrite to a generated static method
    final Map<Integer, AddedMethodInfo> potentialFakeMethodCallLocations = new HashMap<>();
    // first we need to scan the constant pool looking for
    // CONSTANT_method_info_ref structures
    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
        // we have a method call
        if (pool.getTag(i) == ConstPool.CONST_Methodref || pool.getTag(i) == ConstPool.CONST_InterfaceMethodref) {
            String className, methodDesc, methodName;
            if (pool.getTag(i) == ConstPool.CONST_Methodref) {
                className = pool.getMethodrefClassName(i);
                methodDesc = pool.getMethodrefType(i);
                methodName = pool.getMethodrefName(i);
            } else {
                className = pool.getInterfaceMethodrefClassName(i);
                methodDesc = pool.getInterfaceMethodrefType(i);
                methodName = pool.getInterfaceMethodrefName(i);
            }
            if (methodName.equals("<clinit>") || methodName.equals("<init>")) {
                continue;
            }
            boolean handled = false;
            if (knownFakeMethods.containsKey(className)) {
                for (Data data : knownFakeMethods.get(className)) {
                    if (methodName.equals(data.getMethodName()) && methodDesc.equals(data.getMethodDesc())) {
                        // store the location in the const pool of the method ref
                        knownFakeMethodCallLocations.put(i, data);
                        // we have found a method call
                        // now lets replace it
                        handled = true;
                        break;
                    }
                }
            }
            if (loader != null && !handled && !className.equals(file.getName()) && Fakereplace.isClassReplaceable(className, loader)) {
                // may be an added method
                // if the field does not actually exist yet we just assume it is about to come into existence
                // and rewrite it anyway
                BaseClassData data = ClassDataStore.instance().getBaseClassData(loader, className);
                if (data != null) {
                    boolean noClassData = false;
                    MethodData method = null;
                    try {
                        Class<?> mainClass = loader.loadClass(className);
                        Set<Class> allClasses = new HashSet<>();
                        addToAllClasses(mainClass, allClasses);
                        for (Class clazz : allClasses) {
                            data = ClassDataStore.instance().getBaseClassData(clazz.getClassLoader(), clazz.getName());
                            if (data == null) {
                                noClassData = true;
                                break;
                            }
                            method = data.getMethodOrConstructor(methodName, methodDesc);
                            if (method != null) {
                                break;
                            }
                        }
                    } catch (ClassNotFoundException e) {
                        noClassData = true;
                    }
                    if (!noClassData) {
                        if (method == null) {
                            // this is a new method
                            // lets deal with it
                            int methodNo = MethodIdentifierStore.instance().getMethodNumber(methodName, methodDesc);
                            potentialFakeMethodCallLocations.put(i, new AddedMethodInfo(methodNo, className, methodName, methodDesc));
                        } else if (!Modifier.isPublic(method.getAccessFlags())) {
                            boolean requiresVisibilityUpgrade = false;
                            if (Modifier.isPrivate(method.getAccessFlags())) {
                                requiresVisibilityUpgrade = true;
                            } else if (!Modifier.isProtected(method.getAccessFlags())) {
                                // we can't handle protected properly, because we need to know the class heirachy
                                // this is package local, so we check the package names
                                boolean thisDefault = !file.getName().contains(".");
                                boolean thatDefault = !className.contains(".");
                                if (thisDefault && !thatDefault) {
                                    requiresVisibilityUpgrade = true;
                                } else if (thatDefault && !thisDefault) {
                                    requiresVisibilityUpgrade = true;
                                } else if (!thatDefault) {
                                    String thatPackage = className.substring(0, className.lastIndexOf("."));
                                    String thisPackage = file.getName().substring(0, file.getName().lastIndexOf("."));
                                    if (!thisPackage.equals(thatPackage)) {
                                        requiresVisibilityUpgrade = true;
                                    }
                                }
                            }
                            if (requiresVisibilityUpgrade) {
                                int methodNo = MethodIdentifierStore.instance().getMethodNumber(methodName, methodDesc);
                                potentialFakeMethodCallLocations.put(i, new AddedMethodInfo(methodNo, className, methodName, methodDesc));
                            }
                        }
                    }
                }
            }
        }
    }
    // through the methods and replace instances of the call
    if (!knownFakeMethodCallLocations.isEmpty() || !potentialFakeMethodCallLocations.isEmpty()) {
        handleLambdas(file, knownFakeMethodCallLocations, pool);
        List<MethodInfo> methods = file.getMethods();
        for (MethodInfo m : methods) {
            try {
                // ignore abstract methods
                if (m.getCodeAttribute() == null) {
                    continue;
                }
                CodeIterator it = m.getCodeAttribute().iterator();
                while (it.hasNext()) {
                    // loop through the bytecode
                    int index = it.next();
                    int op = it.byteAt(index);
                    // if the bytecode is a method invocation
                    if (op == CodeIterator.INVOKEVIRTUAL || op == CodeIterator.INVOKESTATIC || op == CodeIterator.INVOKEINTERFACE || op == CodeIterator.INVOKESPECIAL) {
                        int val = it.s16bitAt(index + 1);
                        // replacing
                        if (potentialFakeMethodCallLocations.containsKey(val)) {
                            AddedMethodInfo methodInfo = potentialFakeMethodCallLocations.get(val);
                            Data data = new Data(methodInfo.className, methodInfo.name, methodInfo.desc, op == Opcode.INVOKESTATIC ? Type.STATIC : op == Opcode.INVOKEINTERFACE ? Type.INTERFACE : Type.VIRTUAL, loader, methodInfo.number, null);
                            handleFakeMethodCall(file, modifiedMethods, m, it, index, op, data);
                        } else if (knownFakeMethodCallLocations.containsKey(val)) {
                            Data data = knownFakeMethodCallLocations.get(val);
                            handleFakeMethodCall(file, modifiedMethods, m, it, index, op, data);
                        }
                    }
                }
                modifiedMethods.add(m);
                m.getCodeAttribute().computeMaxStack();
            } catch (Exception e) {
                log.error("Bad byte code transforming " + file.getName(), e);
                e.printStackTrace();
            }
        }
        return true;
    } else {
        return false;
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) MethodData(org.fakereplace.data.MethodData) BaseClassData(org.fakereplace.data.BaseClassData) BaseClassData(org.fakereplace.data.BaseClassData) CodeIterator(javassist.bytecode.CodeIterator) MethodData(org.fakereplace.data.MethodData) MethodInfo(javassist.bytecode.MethodInfo) HashSet(java.util.HashSet)

Aggregations

BaseClassData (org.fakereplace.data.BaseClassData)7 HashSet (java.util.HashSet)4 MethodInfo (javassist.bytecode.MethodInfo)4 IOException (java.io.IOException)3 HashMap (java.util.HashMap)3 Set (java.util.Set)3 Bytecode (javassist.bytecode.Bytecode)3 CodeIterator (javassist.bytecode.CodeIterator)3 ConstPool (javassist.bytecode.ConstPool)3 MethodData (org.fakereplace.data.MethodData)3 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)2 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)2 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)2 FieldData (org.fakereplace.data.FieldData)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 DataInputStream (java.io.DataInputStream)1 DataOutputStream (java.io.DataOutputStream)1 FileOutputStream (java.io.FileOutputStream)1 ClassDefinition (java.lang.instrument.ClassDefinition)1 UnmodifiableClassException (java.lang.instrument.UnmodifiableClassException)1