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