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