KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jbet > InstrBlock


1 /*
2  * JBET - Java Binary Enhancement Tool
3  * Copyright (c) 2003 Networks Associates Technology, Inc.
4  *
5  * This software was developed under DARPA/SPAWAR contract
6  * N66001-00-C-8602 "SPMA" as part of the
7  * DARPA OASIS research program.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */

30
31 /* A block of JVM instructions, containing arbitrary code plus an exit
32    record (Block.ExitRec). The exit record specifies all control flow
33    behavior of the block, including exception handlers to jump to if an
34    instruction within the block throws an exception. Exit record is
35    defined in Block.
36
37    @author Andrew Reisse
38 */

39
40 package jbet;
41 import java.util.*;
42
43 public class InstrBlock extends Block
44 {
45     public Snippit code; // internal code
46
public DataFlow.ProcState pse; // ProcState at entry (may be same object as exit)
47
public DataFlow.ProcState psx; // ProcState at exit
48
public MethodInfo from; // original method
49
public boolean entry; // true if this block follows a replaced method call
50
public String JavaDoc handler; // if not null, type for which this block begins an exception handler
51

52     public InstrBlock ()
53     {
54     es = new ExitRec();
55     pse = null;
56     psx = null;
57     entry = false;
58     handler = null;
59     code = new Snippit();
60     }
61
62     public DataFlow.ProcState entry() { return pse; }
63     public DataFlow.ProcState exit () { return psx; }
64
65     public void printinfo (LineWriter out, boolean printcode)
66     {
67     if (from != null && from.block == this)
68         out.println ("block " + swval + " : " + from.cr.name() + "." + from.name + from.descriptor);
69     else
70         out.println ("block " + swval);
71
72     if (handler != null) {
73         out.println (" Exception handler for " + handler);
74     }
75
76     if ((enflags & En_jsr) != 0)
77         out.println (" Jsr target");
78
79     if (entry() != null) {
80         out.print (" Entry Stack :");
81         for (int i = 0; i < entry().stacklen; i++)
82         out.print (" " + i + ":" + entry().stack[i].toString());
83         out.println();
84
85         out.print (" Entry Locals:");
86         for (int i = 0; i < entry().locals.length; i++)
87         if (entry().locals[i] != null)
88             out.print (" " + i + ":" + entry().locals[i].toString());
89         out.println();
90     }
91
92     if (exit() != null) {
93         out.print (" Exit Stack :");
94         for (int i = 0; i < exit().stacklen; i++)
95         out.print (" " + i + ":" + exit().stack[i].toString());
96         out.println();
97
98         out.print (" Exit Locals:");
99         for (int i = 0; i < exit().locals.length; i++)
100         if (exit().locals[i] != null)
101             out.print (" " + i + ":" + exit().locals[i].toString());
102         out.println();
103     }
104
105     if (printcode) {
106         code.printCode (out, true);
107         es.print (out);
108     }
109     }
110
111     private static int marker = 0;
112
113     /* We don't want to have to check for null strings in exception records, so
114        use java/lang/Throwable (a super class of all exceptions) */

115
116     private static String JavaDoc catchtype (String JavaDoc s)
117     {
118     if (s == null)
119         return "java/lang/Throwable";
120     else
121         return s;
122     }
123
124     /** Split the input method into basic blocks and exit
125      * records. Method calls to classes in CALLCLASSES also split
126      * basic blocks. Other method calls are left as ordinary
127      * instructions, and do not split basic blocks.
128      *
129      * @param meth The method to split
130      * @param callclasses Classes for which method calls to should
131      * split basic blocks
132      * @return List of basic blocks (InstrBlock)
133      */

134
135     public static Vector FindBasicBlocks (final MethodInfo meth, final Hashtable callclasses) throws ClassFileException, DataFlowException
136     {
137         if (meth.code == null)
138       return null;
139
140     class _util {
141         ClassInfo getclass (Object JavaDoc name) throws ClassFileException
142         {
143         return (ClassInfo) callclasses.get (name);
144         }
145
146         // also includes NAME derived from a callclass
147
ClassInfo getanyclass (String JavaDoc name) throws ClassFileException
148         {
149         ClassInfo cr2 = (ClassInfo) callclasses.get (name);
150
151         if (cr2 == null)
152             for (Iterator e = callclasses.values().iterator(); e.hasNext();) {
153             ClassInfo cr3 = (ClassInfo) e.next();
154             if ((new Type ('L' + name + ';')).isa
155                 (new Type ('L' + cr3.thisClass + ';'))) {
156                 cr2 = cr3;
157                 break;
158             }
159             }
160
161         return cr2;
162         }
163
164         boolean hasclass (Object JavaDoc name)
165         {
166         return callclasses.get (name) != null;
167         }
168
169         /* Should we replace the method call referenced by instr. */
170         boolean replaceMethod (Instruction instr)
171         {
172         if (callclasses == null)
173             return false;
174
175         throw new GlobalException ("no callclasses supported");
176         }
177
178         /* subject to change soon */
179
180         boolean canThrow (Instruction instr)
181         {
182         int op = instr.opCode();
183
184         return (op == Instruction.OP_ATHROW ||
185             op == Instruction.OP_INVOKEVIRTUAL ||
186             op == Instruction.OP_INVOKESTATIC);
187         }
188     }
189     _util util = new _util();
190
191     Snippit s = meth.code;
192     InstrBlock sb = null;
193     Vector blocks = new Vector();
194     boolean leader = true;
195     Instruction next;
196     boolean[] jumps = new boolean[s.tail.pc() + 1];
197     DataFlow tr;
198
199     /* Run dataflow if no cached results available. */
200     if (meth.dataflow == null) {
201         tr = new DataFlow (meth);
202         tr.run();
203         meth.dataflow = tr;
204     } else
205         tr = (DataFlow) meth.dataflow;
206
207     Hashtable localHash = new Hashtable();
208     
209     for (Instruction instr = s.head; instr != null; instr = instr.next)
210     {
211         s.advanceLocals(instr, localHash);
212         if (instr.usesLocals()) {
213         LocalVarRec rec = (LocalVarRec)localHash.get
214             (new Integer JavaDoc(instr.lvtIndex()));
215         if (rec != null) {
216             instr.setLvname(rec.name);
217         }
218         }
219
220         // all targets of jumps start a new basic block
221
if (instr.usesBranch ()) {
222         if (instr.opCode () == Instruction.OP_LOOKUPSWITCH ||
223             instr.opCode () == Instruction.OP_TABLESWITCH)
224             {
225             BranchTarget[] sw = instr.switchArray ();
226             for (int i = 0; i < sw.length; i++)
227                 jumps[sw[i].instr.pc()] = true;
228             jumps[instr.branchTarget().instr.pc()] = true;
229             }
230         else
231             jumps[instr.branchTarget().instr.pc()] = true;
232         }
233     }
234
235     // exception handlers and ranges start a new basic block
236
for (int i = 0; i < s.exVector.size(); i++) {
237         jumps[s.exAt (i).handler.instr.pc()] = true;
238         jumps[s.exAt (i).start.instr.pc()] = true;
239         jumps[s.exAt (i).end.instr.next.pc()] = true;
240         s.exAt (i).marker = ++marker;
241     }
242
243     for (Instruction instr = s.head; instr != null; instr = next)
244     {
245
246         //skip unreachable code
247
if (instr.procState() == null) { next = instr.next; continue; }
248
249         // jump targets and jump fall-throughs start a new basic block
250

251         if (jumps[instr.pc()])
252         leader = true;
253
254         if (instr.prev != null) {
255         if (instr.prev.usesBranch () ||
256             instr.prev.isReturn () ||
257             instr.prev.opCode () == Instruction.OP_ATHROW)
258             leader = true;
259
260         // replaced method calls start a new basic block
261
if (util.replaceMethod (instr.prev))
262             leader = true;
263         }
264
265         instr.setBlockNumber (0); //debug
266

267         if (leader) {
268         /* find exception handlers that apply to this block. The exception
269            behavior is the same for the entire block because exception ranges split
270            blocks.
271         */

272
273           if (instr.prev != null /*&& util.canThrow (instr.prev)*/)
274             for (int x = 0; x < s.exVector.size(); x++) {
275             ExceptionRec exo = s.exAt (x);
276             for (Instruction exi = exo.start.instr; exi != exo.end.instr.next; exi = exi.next)
277                 if (exi == instr.prev) {
278                 if (sb.es.exceptions == null)
279                     sb.es.exceptions = new Vector();
280                 sb.es.exceptions.addElement
281                     (new ExcInfo (catchtype (exo.catchType), exo));
282                 }
283             }
284
285         /* setup block structure */
286         sb = new InstrBlock();
287         sb.from = meth;
288         blocks.addElement (sb);
289         sb.swval = blocks.size();
290         instr.setBlockNumber (blocks.size());
291         
292         for (int i = 0; i < s.exVector.size(); i++)
293             if (instr == s.exAt(i).handler.instr) {
294             ExceptionRec ex = s.exAt (i);
295             
296             ex.handler.block = sb;
297             
298             if (ex.catchType != null)
299                 sb.handler = ex.catchType;
300             else
301                 sb.handler = "java/lang/Throwable";
302             }
303         }
304
305         next = instr.next;
306         sb.code.push (instr.dup());
307         leader = false;
308     }
309
310     /* Change the jumps to point to blocks instead of instructions
311        and find the blocks that can follow this one. Convert the last
312        instruction in the block to an exit record.
313     */

314
315     for (int j = 0; j < blocks.size(); j++)
316     {
317         sb = (InstrBlock)blocks.elementAt (j);
318
319         // remove blocks that are never executed
320
if (sb.code.head.procState() == null) {
321         Jbet.warn.println ("block #B" + sb.swval + " head " + sb.code.head.pc() +
322                    " is unreachable");
323         sb.code.head = sb.code.tail = null;
324         continue;
325         }
326
327         // fix exception handlers
328
if (sb.es.exceptions != null)
329         for (int i = 0; i < sb.es.exceptions.size(); i++) {
330             ExcInfo ex = sb.es.exAt (i);
331             ex.handler = (InstrBlock) blocks.elementAt (ex.info.handler.instr.blockNumber()-1);
332         }
333
334         sb.pse = sb.code.head.procState();
335
336         for (Instruction instr = sb.code.head; instr != null; instr = instr.next)
337         {
338         if (instr.opCode() != Instruction.AOP_EXCMARKER) {
339             sb.psx = instr.procState().dup();
340             sb.psx.model (instr);
341         }
342
343         if (instr.usesBranch())
344             switch (instr.opCode ()) {
345             case Instruction.OP_LOOKUPSWITCH:
346             case Instruction.OP_TABLESWITCH:
347             {
348                 sb.code.remove (instr);
349                 instr = instr.dup();
350                 BranchTarget[] sw = instr.switchArray ();
351                 BranchTarget t = instr.branchTarget();
352                 if (t.instr.blockNumber() == 0)
353                 Jbet.error.println ("bad jump at " + instr.pc() + " to pc="
354                              + t.instr.pc());
355                 for (int i = 0; i < sw.length; i++) {
356                 if (sw[i].instr.blockNumber() == 0)
357                     Jbet.error.println ("bad jump at "+instr.pc()+" to pc="
358                              + sw[i].instr.pc());
359                 sw[i].block = (InstrBlock)blocks.elementAt
360                     (sw[i].instr.blockNumber()-1);
361                 sw[i].instr = null;
362                 }
363                 sb.es.op = instr.opCode ();
364                 sb.es.switches = sw;
365                 sb.es.swofs = instr.immediate ();
366                 sb.es.primary = (InstrBlock)blocks.elementAt (t.instr.blockNumber()-1);
367                 sb.es.stackuse = 1;
368             }
369             break;
370
371             case Instruction.OP_IFNULL:
372             case Instruction.OP_IFNONNULL:
373             case Instruction.OP_IFEQ:
374             case Instruction.OP_IFNE:
375             case Instruction.OP_IFLE:
376             case Instruction.OP_IFLT:
377             case Instruction.OP_IFGT:
378             case Instruction.OP_IFGE:
379             case Instruction.OP_IF_ACMPEQ:
380             case Instruction.OP_IF_ACMPNE:
381             case Instruction.OP_IF_ICMPEQ:
382             case Instruction.OP_IF_ICMPNE:
383             case Instruction.OP_IF_ICMPLE:
384             case Instruction.OP_IF_ICMPLT:
385             case Instruction.OP_IF_ICMPGT:
386             case Instruction.OP_IF_ICMPGE:
387             sb.es.savestack = false;
388
389             default:
390             {
391                 sb.es.stackuse = instr.stackUse();
392                 sb.code.remove (instr);
393                 BranchTarget t = instr.branchTarget();
394                 if (t.instr.blockNumber() == 0)
395                 Jbet.error.println ("bad jump at " + instr.pc() + " to pc="
396                             + t.instr.pc());
397                 sb.es.op = instr.opCode ();
398
399                 if (sb.es.op == Instruction.OP_GOTO || sb.es.op == Instruction.OP_GOTO_W) {
400                 sb.es.op = 0;
401                 sb.es.primary = (InstrBlock)blocks.elementAt (t.instr.blockNumber()-1);
402                 }
403                 else if (sb.es.op==Instruction.OP_JSR || sb.es.op==Instruction.OP_JSR_W) {
404                 sb.es.savestack = false;
405                 sb.es.ret = (InstrBlock)blocks.elementAt (j+1);
406
407                 InstrBlock jsrt = (InstrBlock)blocks.elementAt (t.instr.blockNumber()-1);
408                 sb.es.primary = jsrt;
409                 jsrt.enflags |= En_jsr;
410                 }
411                 else {
412                 sb.es.jump = (InstrBlock)blocks.elementAt (t.instr.blockNumber()-1);
413                 sb.es.primary = (InstrBlock)blocks.elementAt (j+1);
414                 }
415             }
416             break;
417         }
418         else if (instr.isReturn ()) {
419             sb.es.primary = null;
420             sb.es.op = instr.opCode ();
421             sb.code.remove (instr);
422             sb.es.savestack = false;
423             sb.es.stackuse = instr.stackUse();
424
425             break;
426         }
427         else if (instr.opCode () == Instruction.OP_RET) {
428             DataFlow.ProcState ps = instr.procState();
429             sb.es.op = Instruction.OP_RET;
430             sb.es.retlvt = instr.lvtIndex ();
431             sb.es.switches = new BranchTarget [ ps.ret_places.size() ];
432             for (int l = 0; l < sb.es.switches.length; l++) {
433             sb.es.switches[l] = new BranchTarget();
434             sb.es.switches[l].block = (InstrBlock)blocks.elementAt
435                 (((Instruction)ps.ret_places.elementAt(l)).blockNumber()-1);
436             }
437             sb.code.remove (instr);
438             break;
439         }
440         else if (instr.opCode () == Instruction.OP_ATHROW) {
441             sb.es.stackuse = instr.stackUse();
442             sb.es.op = Instruction.OP_ATHROW;
443             sb.es.savestack = false;
444             sb.es.primary = null;
445             sb.code.remove (instr);
446         }
447         else if (util.replaceMethod (instr)) {
448             boolean ok = false;
449             ClassInfo cr2 = util.getanyclass (instr.classRef());
450
451             if (cr2 == null)
452             Jbet.debug.println ("cr2 null: " + instr.classRef());
453             else
454             for (int k = 0; k < cr2.methods.size(); k++) {
455             MethodInfo cmi = cr2.methodAt (k);
456
457             if (instr.descriptor ().equals (cmi.descriptor) &&
458                 instr.elemName().equals (cmi.name)) {
459
460                 if (cmi.isNative()) {
461                 ok = true;
462                 break;
463                 }
464
465                 ok = true;
466                 sb.es.method = cmi;
467                 sb.es.mclass = cr2;
468                 sb.es.op = instr.opCode ();
469                 sb.es.primary = sb;
470                 sb.es.ret = (InstrBlock)blocks.elementAt (j+1);
471                 ((InstrBlock) sb.es.ret).entry = true;
472                 sb.es.savestack = false;
473
474                 // is this a super class initializer call?
475
//checkcons (sb, instr, true, sb.es.ret);
476

477                 sb.code.remove (instr);
478                 break;
479             }
480             }
481
482             if (!ok) {
483             /* checkcons here */
484             Jbet.error.println ("failed to replace method call " + instr.classRef() + "." +
485                         instr.elemName() + instr.descriptor());
486             }
487         }
488         }
489
490         // set primary if not already set
491
if (sb.es.primary == null && j != blocks.size()-1 && sb.es.op != Instruction.OP_RET &&
492         sb.es.op != Instruction.OP_ATHROW && sb.es.op != Instruction.OP_RETURN &&
493         sb.es.op != Instruction.OP_IRETURN && sb.es.op != Instruction.OP_FRETURN &&
494         sb.es.op != Instruction.OP_ARETURN && sb.es.op != Instruction.OP_LRETURN &&
495         sb.es.op != Instruction.OP_DRETURN)
496         sb.es.primary = (InstrBlock)blocks.elementAt (j+1);
497     }
498
499     return blocks;
500     }
501 }
502
Popular Tags