Search in sources :

Example 21 with ClassWriter

use of org.objectweb.asm.ClassWriter in project android_frameworks_base by AOSPA.

the class AsmGenerator method transform.

/**
     * Transforms a class.
     * <p/>
     * There are 3 kind of transformations:
     *
     * 1- For "mock" dependencies classes, we want to remove all code from methods and replace
     * by a stub. Native methods must be implemented with this stub too. Abstract methods are
     * left intact. Modified classes must be overridable (non-private, non-final).
     * Native methods must be made non-final, non-private.
     *
     * 2- For "keep" classes, we want to rewrite all native methods as indicated above.
     * If a class has native methods, it must also be made non-private, non-final.
     *
     * Note that unfortunately static methods cannot be changed to non-static (since static and
     * non-static are invoked differently.)
     */
byte[] transform(ClassReader cr, boolean stubNativesOnly) {
    boolean hasNativeMethods = hasNativeMethods(cr);
    // Get the class name, as an internal name (e.g. com/android/SomeClass$InnerClass)
    String className = cr.getClassName();
    String newName = transformName(className);
    // transformName returns its input argument if there's no need to rename the class
    if (!newName.equals(className)) {
        mRenameCount++;
        // This class is being renamed, so remove it from the list of classes not renamed.
        mClassesNotRenamed.remove(className);
    }
    mLog.debug("Transform %s%s%s%s", className, newName.equals(className) ? "" : " (renamed to " + newName + ")", hasNativeMethods ? " -- has natives" : "", stubNativesOnly ? " -- stub natives only" : "");
    // Rewrite the new class from scratch, without reusing the constant pool from the
    // original class reader.
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    ClassVisitor cv = cw;
    // FIXME Generify
    if ("android/content/res/Resources".equals(className)) {
        cv = new FieldInjectorAdapter(cv);
    }
    if (mReplaceMethodCallsClasses.contains(className)) {
        cv = new ReplaceMethodCallsAdapter(cv, className);
    }
    cv = new RefactorClassAdapter(cv, mRefactorClasses);
    if (!newName.equals(className)) {
        cv = new RenameClassAdapter(cv, className, newName);
    }
    String binaryNewName = newName.replace('/', '.');
    if (mInjectedMethodsMap.keySet().contains(binaryNewName)) {
        cv = new InjectMethodsAdapter(cv, mInjectedMethodsMap.get(binaryNewName));
    }
    cv = new TransformClassAdapter(mLog, mStubMethods, mDeleteReturns.get(className), newName, cv, stubNativesOnly);
    Set<String> delegateMethods = mDelegateMethods.get(className);
    if (delegateMethods != null && !delegateMethods.isEmpty()) {
        // known to have no native methods, just skip this step.
        if (hasNativeMethods || !(delegateMethods.size() == 1 && delegateMethods.contains(DelegateClassAdapter.ALL_NATIVES))) {
            cv = new DelegateClassAdapter(mLog, cv, className, delegateMethods);
        }
    }
    Set<String> promoteFields = mPromotedFields.get(className);
    if (promoteFields != null && !promoteFields.isEmpty()) {
        cv = new PromoteFieldClassAdapter(cv, promoteFields);
    }
    cr.accept(cv, 0);
    return cw.toByteArray();
}
Also used : ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter)

Example 22 with ClassWriter

use of org.objectweb.asm.ClassWriter in project asterixdb by apache.

the class CodeGenUtil method generateEvaluatorClassBinary.

/**
     * Generates the byte code for an evaluator class.
     *
     * @param originalEvaluatorClassName,
     *            the name of the original evaluator class.
     * @param suffixForGeneratedClass,
     *            the suffix for the generated class.
     * @param evalCounter,
     *            the counter for the generated class.
     * @param nameMappings,
     *            class names that needs to be rewritten in the generated byte code.
     * @param classLoader,
     *            a class loader that has the original evaluator factory class in its resource paths.
     * @param action,
     *            a user definition action for the generated byte code.
     * @throws IOException
     * @throws ClassNotFoundException
     */
private static void generateEvaluatorClassBinary(String originalEvaluatorClassName, String suffixForGeneratedClass, int evalCounter, List<Pair<String, String>> nameMappings, ClassLoader classLoader, ClassByteCodeAction action) throws IOException, ClassNotFoundException {
    // Convert class names.
    originalEvaluatorClassName = toInternalClassName(originalEvaluatorClassName);
    if (originalEvaluatorClassName.equals(OBJECT_CLASS_NAME)) {
        return;
    }
    String targetEvaluatorClassName = getGeneratedClassName(originalEvaluatorClassName, EVALUATOR + suffixForGeneratedClass, evalCounter);
    // Generates code for super classes except java.lang.Object.
    Class<?> evaluatorClass = CodeGenUtil.class.getClassLoader().loadClass(toJdkStandardName(originalEvaluatorClassName));
    generateEvaluatorClassBinary(evaluatorClass.getSuperclass().getName(), suffixForGeneratedClass, evalCounter, nameMappings, classLoader, action);
    // Adds name mapping.
    nameMappings.add(Pair.of(originalEvaluatorClassName, targetEvaluatorClassName));
    nameMappings.add(Pair.of(toJdkStandardName(originalEvaluatorClassName), toJdkStandardName(targetEvaluatorClassName)));
    ClassReader firstPassReader = new ClassReader(getResourceStream(originalEvaluatorClassName, classLoader));
    // Generates inner classes other than the evaluator.
    Set<String> excludedNames = new HashSet<>();
    for (Pair<String, String> entry : nameMappings) {
        excludedNames.add(entry.getKey());
    }
    generateNonEvalInnerClasses(firstPassReader, excludedNames, nameMappings, suffixForGeneratedClass, classLoader, action);
    // Injects missing-handling byte code.
    ClassWriter firstPassWriter = new ClassWriter(firstPassReader, 0);
    EvaluatorMissingCheckVisitor missingHandlingVisitor = new EvaluatorMissingCheckVisitor(firstPassWriter);
    firstPassReader.accept(missingHandlingVisitor, 0);
    ClassReader secondPassReader = new ClassReader(firstPassWriter.toByteArray());
    // Injects null-handling byte code and output the class binary.
    // Since we're going to add jump instructions, we have to let the ClassWriter to
    // automatically generate frames for JVM to verify the class.
    ClassWriter secondPassWriter = new ClassWriter(secondPassReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    RenameClassVisitor renamingVisitor = new RenameClassVisitor(secondPassWriter, nameMappings);
    EvaluatorNullCheckVisitor nullHandlingVisitor = new EvaluatorNullCheckVisitor(renamingVisitor, missingHandlingVisitor.getLastAddedLabel());
    secondPassReader.accept(nullHandlingVisitor, 0);
    action.runAction(targetEvaluatorClassName, secondPassWriter.toByteArray());
}
Also used : ClassReader(org.objectweb.asm.ClassReader) ClassWriter(org.objectweb.asm.ClassWriter) HashSet(java.util.HashSet)

Example 23 with ClassWriter

use of org.objectweb.asm.ClassWriter in project asterixdb by apache.

the class CodeGenUtil method generateEvaluatorFactoryClassBinary.

/**
     * Generates the byte code for an evaluator factory class.
     *
     * @param packagePrefix,
     *            the prefix of evaluators for code generation.
     * @param originalEvaluatorFactoryClassName,
     *            the original evaluator factory class name.
     * @param suffixForGeneratedClass,
     *            the suffix for the generated class.
     * @param factoryCounter,
     *            the counter for the generated class.
     * @param nameMappings,
     *            class names that needs to be rewritten in the generated byte code.
     * @param classLoader,
     *            a class loader that has the original evaluator factory class in its resource paths.
     * @param action,
     *            a user definition action for the generated byte code.
     * @throws IOException
     * @throws ClassNotFoundException
     */
private static void generateEvaluatorFactoryClassBinary(String packagePrefix, String originalEvaluatorFactoryClassName, String suffixForGeneratedClass, int factoryCounter, List<Pair<String, String>> nameMappings, ClassLoader classLoader, ClassByteCodeAction action) throws IOException, ClassNotFoundException {
    originalEvaluatorFactoryClassName = toInternalClassName(originalEvaluatorFactoryClassName);
    String targetEvaluatorFactoryClassName = getGeneratedClassName(originalEvaluatorFactoryClassName, EVALUATOR_FACTORY + suffixForGeneratedClass, factoryCounter);
    // Adds the old/new names of the evaluator factory into the mapping.
    nameMappings.add(Pair.of(originalEvaluatorFactoryClassName, targetEvaluatorFactoryClassName));
    nameMappings.add(Pair.of(toJdkStandardName(originalEvaluatorFactoryClassName), toJdkStandardName(targetEvaluatorFactoryClassName)));
    // Gathers the class names of the evaluators that are created in the evaluator factory.
    ClassReader reader = new ClassReader(getResourceStream(originalEvaluatorFactoryClassName, classLoader));
    GatherEvaluatorCreationVisitor evalCreationVisitor = new GatherEvaluatorCreationVisitor(toInternalClassName(packagePrefix));
    reader.accept(evalCreationVisitor, 0);
    Set<String> evaluatorClassNames = evalCreationVisitor.getCreatedEvaluatorClassNames();
    // Generates inner classes other than evaluators.
    generateNonEvalInnerClasses(reader, evaluatorClassNames, nameMappings, suffixForGeneratedClass, classLoader, action);
    // Generates code for all evaluators.
    int evalCounter = 0;
    for (String evaluateClassName : evaluatorClassNames) {
        generateEvaluatorClassBinary(evaluateClassName, suffixForGeneratedClass, evalCounter++, nameMappings, classLoader, action);
    }
    // Transforms the evaluator factory class and outputs the generated class binary.
    ClassWriter writer = new ClassWriter(reader, 0);
    RenameClassVisitor renamingVisitor = new RenameClassVisitor(writer, nameMappings);
    reader.accept(renamingVisitor, 0);
    action.runAction(targetEvaluatorFactoryClassName, writer.toByteArray());
}
Also used : ClassReader(org.objectweb.asm.ClassReader) ClassWriter(org.objectweb.asm.ClassWriter)

Example 24 with ClassWriter

use of org.objectweb.asm.ClassWriter in project asterixdb by apache.

the class CodeGenUtil method generateNonEvalInnerClasses.

/**
     * Generates non-evaluator(-factory) inner classes defined in either a function descriptor
     * or an evaluator factory.
     *
     * @param reader,
     *            the reader of the outer class.
     * @param evalClassNames,
     *            the names of evaluator/evaluator-factory classes that shouldn't be generated in this
     *            method.
     * @param nameMappings,
     *            class names that needs to be rewritten in the generated byte code.
     * @param classLoader,
     *            a class loader that has the original evaluator factory class in its resource paths.
     * @param action,
     *            a user definition action for the generated byte code.
     * @throws IOException
     */
private static void generateNonEvalInnerClasses(ClassReader reader, Set<String> evalClassNames, List<Pair<String, String>> nameMappings, String suffixForGeneratedClass, ClassLoader classLoader, ClassByteCodeAction action) throws IOException {
    // Gathers inner classes of the function descriptor.
    GatherInnerClassVisitor innerClassVisitor = new GatherInnerClassVisitor();
    reader.accept(innerClassVisitor, 0);
    Set<String> innerClassNames = innerClassVisitor.getInnerClassNames();
    innerClassNames.removeAll(evalClassNames);
    // Rewrites inner classes.
    int counter = 0;
    String suffix = INNER + suffixForGeneratedClass;
    for (String innerClassName : innerClassNames) {
        // adds name mapping.
        String targetInnerClassName = getGeneratedClassName(innerClassName, suffix, counter++);
        nameMappings.add(Pair.of(innerClassName, targetInnerClassName));
        nameMappings.add(Pair.of(toJdkStandardName(innerClassName), toJdkStandardName(targetInnerClassName)));
        // Renaming appearances of original class names.
        ClassReader innerClassReader = new ClassReader(getResourceStream(innerClassName, classLoader));
        ClassWriter writer = new ClassWriter(innerClassReader, 0);
        RenameClassVisitor renamingVisitor = new RenameClassVisitor(writer, nameMappings);
        innerClassReader.accept(renamingVisitor, 0);
        action.runAction(targetInnerClassName, writer.toByteArray());
    }
}
Also used : ClassReader(org.objectweb.asm.ClassReader) ClassWriter(org.objectweb.asm.ClassWriter)

Example 25 with ClassWriter

use of org.objectweb.asm.ClassWriter in project asterixdb by apache.

the class CodeGenUtil method generateScalarFunctionDescriptorBinary.

/**
     * Generates the byte code for a scalar function descriptor.
     *
     * @param packagePrefix,
     *            the prefix of evaluators for code generation.
     * @param originalFuncDescriptorClassName,
     *            the original class name of the function descriptor.
     * @param suffixForGeneratedClass,
     *            the suffix for the generated class.
     * @param action,
     *            the customized action for the generated class definition bytes.
     * @throws IOException
     * @throws ClassNotFoundException
     */
public static List<Pair<String, String>> generateScalarFunctionDescriptorBinary(String packagePrefix, String originalFuncDescriptorClassName, String suffixForGeneratedClass, ClassLoader classLoader, ClassByteCodeAction action) throws IOException, ClassNotFoundException {
    originalFuncDescriptorClassName = toInternalClassName(originalFuncDescriptorClassName);
    if (originalFuncDescriptorClassName.equals(DESCRIPTOR_SUPER_CLASS_NAME)) {
        return Collections.emptyList();
    }
    String targetFuncDescriptorClassName = getGeneratedFunctionDescriptorInternalClassName(originalFuncDescriptorClassName, suffixForGeneratedClass);
    // Adds the mapping of the old/new names of the function descriptor.
    List<Pair<String, String>> nameMappings = new ArrayList<>();
    // Generates code for super classes except java.lang.Object.
    Class<?> evaluatorClass = CodeGenUtil.class.getClassLoader().loadClass(toJdkStandardName(originalFuncDescriptorClassName));
    nameMappings.addAll(generateScalarFunctionDescriptorBinary(packagePrefix, evaluatorClass.getSuperclass().getName(), suffixForGeneratedClass, classLoader, action));
    nameMappings.add(Pair.of(originalFuncDescriptorClassName, targetFuncDescriptorClassName));
    nameMappings.add(Pair.of(toJdkStandardName(originalFuncDescriptorClassName), toJdkStandardName(targetFuncDescriptorClassName)));
    // Gathers evaluator factory classes that are created in the function descriptor.
    ClassReader reader = new ClassReader(getResourceStream(originalFuncDescriptorClassName, classLoader));
    GatherEvaluatorFactoryCreationVisitor evalFactoryCreationVisitor = new GatherEvaluatorFactoryCreationVisitor(toInternalClassName(packagePrefix));
    reader.accept(evalFactoryCreationVisitor, 0);
    Set<String> evaluatorFactoryClassNames = evalFactoryCreationVisitor.getCreatedEvaluatorFactoryClassNames();
    // Generates inner classes other than evaluator factories.
    generateNonEvalInnerClasses(reader, evaluatorFactoryClassNames, nameMappings, suffixForGeneratedClass, classLoader, action);
    // Generates evaluator factories that are created in the function descriptor.
    int evalFactoryCounter = 0;
    for (String evaluateFactoryClassName : evaluatorFactoryClassNames) {
        generateEvaluatorFactoryClassBinary(packagePrefix, evaluateFactoryClassName, suffixForGeneratedClass, evalFactoryCounter++, nameMappings, classLoader, action);
    }
    // Transforms the function descriptor class and outputs the generated class binary.
    ClassWriter writer = new ClassWriter(reader, 0);
    RenameClassVisitor renamingVisitor = new RenameClassVisitor(writer, nameMappings);
    reader.accept(renamingVisitor, 0);
    action.runAction(targetFuncDescriptorClassName, writer.toByteArray());
    return nameMappings;
}
Also used : ArrayList(java.util.ArrayList) ClassReader(org.objectweb.asm.ClassReader) ClassWriter(org.objectweb.asm.ClassWriter) Pair(org.apache.commons.lang3.tuple.Pair)

Aggregations

ClassWriter (org.objectweb.asm.ClassWriter)471 ClassReader (org.objectweb.asm.ClassReader)275 MethodVisitor (org.objectweb.asm.MethodVisitor)115 Test (org.junit.Test)94 ClassVisitor (org.objectweb.asm.ClassVisitor)82 ClassNode (org.objectweb.asm.tree.ClassNode)70 IOException (java.io.IOException)57 SemanticVersioningClassVisitor (org.apache.aries.versioning.utils.SemanticVersioningClassVisitor)52 Label (org.objectweb.asm.Label)51 HashSet (java.util.HashSet)37 Method (java.lang.reflect.Method)36 BinaryCompatibilityStatus (org.apache.aries.versioning.utils.BinaryCompatibilityStatus)32 Type (org.objectweb.asm.Type)30 File (java.io.File)27 InvocationTargetException (java.lang.reflect.InvocationTargetException)27 FieldVisitor (org.objectweb.asm.FieldVisitor)26 InputStream (java.io.InputStream)25 MethodNode (org.objectweb.asm.tree.MethodNode)25 OuterClass (com.android.tools.layoutlib.create.dataclass.OuterClass)23 InnerClass (com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass)23