KOPI | ||
---|---|---|
Prev | Chapter 1. Classfile Handling | Next |
License type: KOPI Classfile is distributed under the terms of the the GNU Lesser General Public License. Appendix A
This package contains the API to edit classfiles from within a Java program. If you want to read or write classfiles in a human readable form, you should use KSM and DIS which offer an interface to classfile.
Basically, this package contains three parts: one to read data from a file, one to create a consistant class from another program, and a third part to check the code of each function (compute stack and local variable usage, and optionnally optimize code) and then dump the class into a file.
You just have to create a ClassInfo from a file:
ClassInfo clazz = new ClassInfo(new RandomAccessFile(``AClass.class''), false);or with its full name and a class path using the provided class ClassPath:
ClassPath path = new ClassPath(``.''); ClassInfo clazz = path.getClassFile(``pack.AClass'', true); // rmq: the last parameter allows you // to load only the interface (skip code)Once you've read your class, you can access all the information you need from the provided API such as getName(), getSuperClass(), getMethods(), getSourceFile(). If you have loaded an entire class (not only the interface), you'll be able to change some information (the source file, the name, some modifiers...) and then to dump it to file again.
You can create a class from scratch and then add all the attributes and members you want. See KSM or KJC for a real example of usage.
You can edit your class using the provided API:
ClassInfo clazz = new ClassInfo(new File(``AClass.class''); clazz.setName(``BClass'');
After you have built or edited the instructions, you can check and optimize the code:
// obtained from any non empty method CodeInfo code = clazz.getMethods()[0]; // 2 is the number of optimization loop, 0 for none code.optimizeAndCheck(2)The main check is to ensure that the stack depth is correct for every branch in the program. We may add later some verifications made by the Java Verifier at runtime.
After you have built or edited a ClassInfo, you can dump it into a file with:
ClassInfo clazz = new ClassInfo(new File(``AClass.class''); clazz.setName(``BClass'') clazz.write(new DataOutputStream(new FileOutputStream(``BClass.class'');
This simple example sets all methods to be public in the class passed as argv[0] and writes this new class in a file argv[1]
/** * This simple example set all methods to * be public in the class passed as first * parameters and write this new class in a file argv[1] */ import at.dms.classfile.*; import java.io.*; public class Editor implements Constants { public static void main(String[] argv) throws at.dms.classfile.ClassFileFormatException, java.io.FileNotFoundException, java.io.IOException { DataInputStream is = new DataInputStream(new FileInputStream(argv[0])); ClassInfo clazz = new ClassInfo(is, false); MethodInfo[] method = clazz.getMethods(); for (int i = 0; i < method.length; i++) method[i].setModifiers(toPublic(method[i].getModifiers())); clazz.write(new DataOutputStream(new FileOutputStream(argv[1]))); } private static short toPublic(short modifiers) { return (short)((modifiers | ACC_PUBLIC) & ~(ACC_PROTECTED | ACC_PRIVATE)); } }
This is a list of non restrictive possible tools to build with this package:
Back end for compilers that generates code for the Java Virtual Machine
There are two fully implemented examples that come with KOPI suite:
KSM Kopi assembler
This is a small example to show how a ``high level'' assembly language is translated into Java bytecode. This example is very small (10 classes) and is a good starting point for learning how the classfile package works. KSM is composed of a parser that reads ``.ksm'' files and some subclasses of classfiles for handling assembler labels and jumps. KSM syntax is easy because you don't have to use the most optimized pseudo-instruction in your code, you can use generic instruction that classfile will optimize afterwards.
By example if you use ``push 1'' to push the constant one into the stack, classfile will translate this instruction to ``iconst_1'', which is smaller and faster. Another feature of KSM is that you don't have to compute the amount of stack used, or the number of local variables; the classfile package will do it for you.
KJC Kopi Java Compiler
This is a big example (160 classes) that shows how to use the classfile package as a back end for a compiler. Classfile was first designed as a part of KJC, but because this package may be used for other purposes, it has been separated from the compiler. That makes the code easy to handle and improve.
Optimizer for classfiles (obfuscators, code optimizers, ...).
It is also very easy to create a classfile optimizer. We will soon provide a minimalist code optimizer that can read every classfile provided and generates optimized versions in the destination directory. Our optimizer will be used only for testing purpose and won't do anything more than:
Unnecessary information removal (local vars, line numbers, source file attibutes).
Bytecode optimization (equivalent to -O2 of KJC).
But it would be very easy to transform it to a true obfuscator/optimizer by collecting used fields and methods and renaming every member of class to the smallest size possible.
5.3 Disassemblers
It is very easy to build a disassembler over KOPI classfile by accessing every information in the classfile with the provided API. An example of such a disassembler, DIS, is provided with the KOPI suite. It converts classfile in a syntax that is understood by KSM. That allows you to disassemble a classfile, modify some code, and then regenerate the classfiles. Our disassembler is very small also but powerful enough to disassemble every classfiles into KSM syntax. And, if you want to disassemble classfiles in another syntax, you just have to subclass the AssemblerPrettyPrinter.
Native recompilers to C
From the classfile assembler, it is all the same to generate Java byte code or C. The problem of such tools is to provide a gc and a window toolkit. but it should not be to difficult to create a tool that compiles natively command-line Java programs.
Cross reference tool
A useful tool based on the KOPI classfile may be a cross reference analyser.
This chapter explains which optimisations are provided by the bytecode optimizer. These optimizations are:
Unreachable code elimination.
Jump and peephole optimizations.
Unreachable code is simply removed from the CodeInfo. And nop instructions are removed if they are not targeted in a method.
This is the current list of peephole optimization performed by KJC:
Jumps to the following instruction.
goto L1 L1: ... => ...
Jumps to next instruction.
... ifeq L1 L1: ... => ... pop[2] ...
Jump to unconditional jumps.
... opc_goto L1 ... L1: goto L2 => ... goto L2 ... L1: goto L2
Goto to return instruction.
... goto L1 ... L1: ireturn => ... ireturn ... ireturn
Peephole optimizations.
iconst_0 ifeq L1 ... L1: ... => ... L1: ...or
iconst_[0, 1, null] if_icmpeq L1 ... L1: ... => ifeq L1 ... L1: ...
Prev | Home | Next |
Classfile Handling | Up | The KOPI Kopi Java Compiler |