• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<?xml version="1.0"?>
2<!--
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10    *
11    *   http://www.apache.org/licenses/LICENSE-2.0
12    *
13    * Unless required by applicable law or agreed to in writing,
14    * software distributed under the License is distributed on an
15    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16    * KIND, either express or implied.  See the License for the
17    * specific language governing permissions and limitations
18    * under the License.
19-->
20<document>
21  <properties>
22    <title>Appendix</title>
23  </properties>
24
25  <body>
26    <section name="Appendix">
27
28    <subsection name="HelloWorldBuilder">
29      <p>
30        The following program reads a name from the standard input and
31        prints a friendly "Hello". Since the <tt>readLine()</tt> method may
32        throw an <tt>IOException</tt> it is enclosed by a <tt>try-catch</tt>
33        clause.
34      </p>
35
36      <source>
37import java.io.*;
38
39public class HelloWorld {
40    public static void main(String[] argv) {
41        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
42        String name = null;
43
44        try {
45            System.out.print("Please enter your name&gt; ");
46            name = in.readLine();
47        } catch (IOException e) {
48            return;
49        }
50
51        System.out.println("Hello, " + name);
52    }
53}
54      </source>
55
56      <p>
57        We will sketch here how the above Java class can be created from the
58        scratch using the <font face="helvetica,arial">BCEL</font> API. For
59        ease of reading we will use textual signatures and not create them
60        dynamically. For example, the signature
61      </p>
62
63      <source>"(Ljava/lang/String;)Ljava/lang/StringBuffer;"</source>
64
65      <p>
66        actually be created with
67      </p>
68
69      <source>Type.getMethodSignature(Type.STRINGBUFFER, new Type[] { Type.STRING });</source>
70
71      <p><b>Initialization:</b>
72        First we create an empty class and an instruction list:
73      </p>
74
75      <source>
76ClassGen cg = new ClassGen("HelloWorld", "java.lang.Object",
77                            "&lt;generated&gt;", ACC_PUBLIC | ACC_SUPER, null);
78ConstantPoolGen cp = cg.getConstantPool(); // cg creates constant pool
79InstructionList il = new InstructionList();
80      </source>
81
82      <p>
83        We then create the main method, supplying the method's name and the
84        symbolic type signature encoded with <tt>Type</tt> objects.
85      </p>
86
87      <source>
88MethodGen  mg = new MethodGen(ACC_STATIC | ACC_PUBLIC, // access flags
89                              Type.VOID,               // return type
90                              new Type[] {             // argument types
91                              new ArrayType(Type.STRING, 1) },
92                              new String[] { "argv" }, // arg names
93                              "main", "HelloWorld",    // method, class
94                              il, cp);
95InstructionFactory factory = new InstructionFactory(cg);
96      </source>
97
98      <p>
99        We now define some often used types:
100      </p>
101
102      <source>
103ObjectType i_stream = new ObjectType("java.io.InputStream");
104ObjectType p_stream = new ObjectType("java.io.PrintStream");
105      </source>
106
107      <p><b>Create variables <tt>in</tt> and <tt>name</tt>:</b> We call
108        the constructors, i.e., execute
109        <tt>BufferedReader(InputStreamReader(System.in))</tt>. The reference
110        to the <tt>BufferedReader</tt> object stays on top of the stack and
111        is stored in the newly allocated <tt>in</tt> variable.
112      </p>
113
114      <source>
115il.append(factory.createNew("java.io.BufferedReader"));
116il.append(InstructionConstants.DUP); // Use predefined constant
117il.append(factory.createNew("java.io.InputStreamReader"));
118il.append(InstructionConstants.DUP);
119il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC));
120il.append(factory.createInvoke("java.io.InputStreamReader", "&lt;init&gt;",
121                                Type.VOID, new Type[] { i_stream },
122                                Constants.INVOKESPECIAL));
123il.append(factory.createInvoke("java.io.BufferedReader", "&lt;init&gt;", Type.VOID,
124                                new Type[] {new ObjectType("java.io.Reader")},
125                                Constants.INVOKESPECIAL));
126
127LocalVariableGen lg = mg.addLocalVariable("in",
128                        new ObjectType("java.io.BufferedReader"), null, null);
129int in = lg.getIndex();
130lg.setStart(il.append(new ASTORE(in))); // "i" valid from here
131      </source>
132
133      <p>
134        Create local variable <tt>name</tt> and  initialize it to <tt>null</tt>.
135      </p>
136
137      <source>
138lg = mg.addLocalVariable("name", Type.STRING, null, null);
139int name = lg.getIndex();
140il.append(InstructionConstants.ACONST_NULL);
141lg.setStart(il.append(new ASTORE(name))); // "name" valid from here
142      </source>
143
144      <p><b>Create try-catch block:</b> We remember the start of the
145        block, read a line from the standard input and store it into the
146        variable <tt>name</tt>.
147      </p>
148
149      <source>
150InstructionHandle try_start =
151  il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC));
152
153il.append(new PUSH(cp, "Please enter your name&gt; "));
154il.append(factory.createInvoke("java.io.PrintStream", "print", Type.VOID,
155                                new Type[] { Type.STRING },
156                                Constants.INVOKEVIRTUAL));
157il.append(new ALOAD(in));
158il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
159                                Type.STRING, Type.NO_ARGS,
160                                Constants.INVOKEVIRTUAL));
161il.append(new ASTORE(name));
162      </source>
163
164      <p>
165        Upon normal execution we jump behind exception handler, the target
166        address is not known yet.
167      </p>
168
169      <source>
170GOTO g = new GOTO(null);
171InstructionHandle try_end = il.append(g);
172      </source>
173
174      <p>
175        We add the exception handler which simply returns from the method.
176      </p>
177
178      <source>
179InstructionHandle handler = il.append(InstructionConstants.RETURN);
180mg.addExceptionHandler(try_start, try_end, handler, "java.io.IOException");
181      </source>
182
183      <p>
184        "Normal" code continues, now we can set the branch target of the <tt>GOTO</tt>.
185      </p>
186
187      <source>
188InstructionHandle ih =
189  il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC));
190g.setTarget(ih);
191      </source>
192
193      <p><b>Printing "Hello":</b>
194String concatenation compiles to <tt>StringBuffer</tt> operations.
195      </p>
196
197      <source>
198il.append(factory.createNew(Type.STRINGBUFFER));
199il.append(InstructionConstants.DUP);
200il.append(new PUSH(cp, "Hello, "));
201il.append(factory.createInvoke("java.lang.StringBuffer", "&lt;init&gt;",
202                                Type.VOID, new Type[] { Type.STRING },
203                                Constants.INVOKESPECIAL));
204il.append(new ALOAD(name));
205il.append(factory.createInvoke("java.lang.StringBuffer", "append",
206                                Type.STRINGBUFFER, new Type[] { Type.STRING },
207                                Constants.INVOKEVIRTUAL));
208il.append(factory.createInvoke("java.lang.StringBuffer", "toString",
209                                Type.STRING, Type.NO_ARGS,
210                                Constants.INVOKEVIRTUAL));
211
212il.append(factory.createInvoke("java.io.PrintStream", "println",
213                                Type.VOID, new Type[] { Type.STRING },
214                                Constants.INVOKEVIRTUAL));
215il.append(InstructionConstants.RETURN);
216      </source>
217
218
219      <p><b>Finalization:</b> Finally, we have to set the stack size,
220        which normally would have to be computed on the fly and add a
221        default constructor method to the class, which is empty in this
222        case.
223      </p>
224
225      <source>
226mg.setMaxStack();
227cg.addMethod(mg.getMethod());
228il.dispose(); // Allow instruction handles to be reused
229cg.addEmptyConstructor(ACC_PUBLIC);
230      </source>
231
232      <p>
233        Last but not least we dump the <tt>JavaClass</tt> object to a file.
234      </p>
235
236      <source>
237try {
238    cg.getJavaClass().dump("HelloWorld.class");
239} catch (IOException e) {
240    System.err.println(e);
241}
242      </source>
243
244    </subsection>
245
246    <subsection name="Peephole optimizer">
247      <p>
248        This class implements a simple peephole optimizer that removes any NOP
249        instructions from the given class.
250      </p>
251
252      <source>
253import java.io.*;
254
255import java.util.Iterator;
256import org.apache.bcel.classfile.*;
257import org.apache.bcel.generic.*;
258import org.apache.bcel.Repository;
259import org.apache.bcel.util.InstructionFinder;
260
261public class Peephole {
262
263    public static void main(String[] argv) {
264        try {
265            // Load the class from CLASSPATH.
266            JavaClass clazz  = Repository.lookupClass(argv[0]);
267            Method[] methods = clazz.getMethods();
268            ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
269
270            for (int i = 0; i &lt; methods.length; i++) {
271                if (!(methods[i].isAbstract() || methods[i].isNative())) {
272                    MethodGen mg = new MethodGen(methods[i], clazz.getClassName(), cp);
273                    Method stripped = removeNOPs(mg);
274
275                    if (stripped != null)      // Any NOPs stripped?
276                        methods[i] = stripped; // Overwrite with stripped method
277                  }
278            }
279
280            // Dump the class to "class name"_.class
281            clazz.setConstantPool(cp.getFinalConstantPool());
282            clazz.dump(clazz.getClassName() + "_.class");
283        } catch (Exception e) {
284            e.printStackTrace();
285        }
286    }
287
288    private static Method removeNOPs(MethodGen mg) {
289        InstructionList il = mg.getInstructionList();
290        InstructionFinder f = new InstructionFinder(il);
291        String pat = "NOP+"; // Find at least one NOP
292        InstructionHandle next = null;
293        int count = 0;
294
295        for (Iterator iter = f.search(pat); iter.hasNext();) {
296            InstructionHandle[] match = (InstructionHandle[]) iter.next();
297            InstructionHandle first = match[0];
298            InstructionHandle last  = match[match.length - 1];
299
300            // Some nasty Java compilers may add NOP at end of method.
301            if ((next = last.getNext()) == null) {
302                break;
303            }
304
305            count += match.length;
306
307            /**
308             * Delete NOPs and redirect any references to them to the following (non-nop) instruction.
309             */
310            try {
311                il.delete(first, last);
312            } catch (TargetLostException e) {
313                for (InstructionHandle target : e.getTargets()) {
314                    for (InstructionTargeter targeter = target.getTargeters()) {
315                        targeter.updateTarget(target, next);
316                    }
317                }
318            }
319        }
320
321        Method m = null;
322
323        if (count &gt; 0) {
324            System.out.println("Removed " + count + " NOP instructions from method " + mg.getName());
325            m = mg.getMethod();
326        }
327
328        il.dispose(); // Reuse instruction handles
329        return m;
330    }
331}
332      </source>
333    </subsection>
334
335    <subsection name="BCELifier">
336      <p>
337        If you want to learn how certain things are generated using BCEL you
338        can do the following: Write your program with the needed features in
339        Java and compile it as usual. Then use <tt>BCELifier</tt> to create
340        a class that creates that very input class using BCEL.<br/>
341        (Think about this sentence for a while, or just try it ...)
342      </p>
343    </subsection>
344
345    <subsection name="Constant pool UML diagram">
346
347      <p align="center">
348        <a name="Figure 8">
349          <img src="../images/constantpool.gif"/>
350          <br/>
351          Figure 8: UML diagram for constant pool classes
352        </a>
353      </p>
354    </subsection>
355
356    <subsection name="Verifier">
357
358      <h4>Running a console based verifier</h4>
359
360      <source>
361java org.apache.bcel.verifier.Verifier fully.qualified.class.Name
362      </source>
363
364      lets JustIce work standalone.
365      If you get a "java.lang.OutOfMemoryError", you should increase the
366      maximum Java heap space. A command like
367
368      <source>
369java -Xmx1887436800 org.apache.bcel.verifier.Verifier f.q.c.Name
370      </source>
371
372      will usually resolve the problem. The value above is suitable for
373      big server machines; if your machine starts swapping to disk, try
374      to lower the value.
375
376      <h4>Running a graphics based verifier</h4>
377
378      If you prefer a graphical application, you should use a command like
379
380      <source>
381java org.apache.bcel.verifier.GraphicalVerifier
382      </source>
383
384      to launch one. Again, you may have to resolve a memory issue depending
385      on the classes to verify.
386    </subsection>
387  </section>
388  </body>
389</document>