001: /* RemovePopAnalyzer Copyright (C) 1999-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU General Public License
014: * along with this program; see the file COPYING. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: RemovePopAnalyzer.java.in,v 1.1.2.1 2002/05/28 17:34:17 hoenicke Exp $
018: */
019:
020: package jode.obfuscator.modules;
021:
022: import jode.bytecode.*;
023: import jode.obfuscator.*;
024: import jode.AssertError;
025: import jode.GlobalOptions;
026:
027: import java.util.ListIterator;
028:
029: public class RemovePopAnalyzer implements CodeTransformer, Opcodes {
030: public RemovePopAnalyzer() {
031: }
032:
033: public void transformCode(BytecodeInfo bytecode) {
034: int poppush[] = new int[2];
035: ListIterator iter = bytecode.getInstructions().listIterator();
036: next_pop: while (iter.hasNext()) {
037: Instruction popInstr = (Instruction) iter.next();
038: boolean isPop2 = false;
039: switch (popInstr.getOpcode()) {
040: case opc_nop: {
041: iter.remove();
042: continue;
043: }
044:
045: case opc_pop2:
046: isPop2 = true;
047: case opc_pop:
048: if (popInstr.getPreds() != null)
049: // Can't handle pop with multiple predecessors
050: continue next_pop;
051: Handler[] handlers = bytecode.getExceptionHandlers();
052: for (int i = 0; i < handlers.length; i++)
053: if (handlers[i].catcher == popInstr)
054: continue next_pop;
055:
056: // remove pop, we will insert it again if something
057: // bad happened.
058: iter.remove();
059:
060: // remember position of pop, so we can insert it again.
061: Instruction popPrevious = (Instruction) iter.previous();
062: Instruction instr = popPrevious;
063: int count = 0;
064: while (true) {
065: if (instr.getSuccs() != null
066: || instr.doesAlwaysJump()) {
067: instr = null;
068: break;
069: }
070: instr.getStackPopPush(poppush);
071:
072: if (count < poppush[1]) {
073: if (count == 0)
074: break;
075:
076: int opcode = instr.getOpcode();
077: /* If this is a dup and the instruction popped is the
078: * duplicated element, remove the dup and the pop
079: */
080: if (count <= 3
081: && opcode == (opc_dup + count - 1)) {
082: iter.remove();
083: if (!isPop2)
084: continue next_pop;
085:
086: // We have to consider a pop instead of a
087: // pop2 now.
088: popInstr = new Instruction(opc_pop);
089: isPop2 = false;
090: instr = (Instruction) iter.previous();
091: continue;
092: }
093:
094: if (isPop2 && count > 1 && count <= 4
095: && opcode == (opc_dup2 + count - 2)) {
096: iter.remove();
097: continue next_pop;
098: }
099: /* Otherwise popping is not possible */
100: instr = null;
101: break;
102: }
103: count += poppush[0] - poppush[1];
104: instr = (Instruction) iter.previous();
105: }
106:
107: if (instr == null) {
108: // We insert the pop at the previous position
109: while (iter.next() != popPrevious) {
110: }
111: if (!isPop2 && popPrevious.getOpcode() == opc_pop) {
112: // merge pop with popPrevious
113: iter.set(new Instruction(opc_pop2));
114: } else
115: iter.add(popInstr);
116: continue;
117: }
118: int opcode = instr.getOpcode();
119: switch (opcode) {
120: case opc_ldc2_w:
121: case opc_lload:
122: case opc_dload:
123: if (!isPop2)
124: throw new AssertError("pop on long");
125: iter.remove();
126: continue;
127: case opc_ldc:
128: case opc_iload:
129: case opc_fload:
130: case opc_aload:
131: case opc_dup:
132: case opc_new:
133: if (isPop2)
134: iter.set(new Instruction(opc_pop));
135: else
136: iter.remove();
137: continue;
138: case opc_iaload:
139: case opc_faload:
140: case opc_aaload:
141: case opc_baload:
142: case opc_caload:
143: case opc_saload:
144: case opc_iadd:
145: case opc_fadd:
146: case opc_isub:
147: case opc_fsub:
148: case opc_imul:
149: case opc_fmul:
150: case opc_idiv:
151: case opc_fdiv:
152: case opc_irem:
153: case opc_frem:
154: case opc_iand:
155: case opc_ior:
156: case opc_ixor:
157: case opc_ishl:
158: case opc_ishr:
159: case opc_iushr:
160: case opc_fcmpl:
161: case opc_fcmpg:
162: /* We have to pop one entry more. */
163: iter.next();
164: iter.add(popInstr);
165: iter.previous();
166: iter.previous();
167: iter.set(new Instruction(opc_pop));
168: continue;
169:
170: case opc_dup_x1:
171: iter.set(new Instruction(opc_swap));
172: iter.next();
173: if (isPop2)
174: iter.add(new Instruction(opc_pop));
175: continue;
176:
177: case opc_dup2:
178: if (isPop2) {
179: iter.remove();
180: continue;
181: }
182: break;
183: case opc_swap:
184: if (isPop2) {
185: iter.set(popInstr);
186: continue;
187: }
188: break;
189:
190: case opc_lneg:
191: case opc_dneg:
192: case opc_l2d:
193: case opc_d2l:
194: case opc_laload:
195: case opc_daload:
196: if (!isPop2)
197: throw new AssertError("pop on long");
198: /* fall through */
199: case opc_ineg:
200: case opc_fneg:
201: case opc_i2f:
202: case opc_f2i:
203: case opc_i2b:
204: case opc_i2c:
205: case opc_i2s:
206: case opc_newarray:
207: case opc_anewarray:
208: case opc_arraylength:
209: case opc_instanceof :
210: iter.set(popInstr);
211: continue;
212:
213: case opc_l2i:
214: case opc_l2f:
215: case opc_d2i:
216: case opc_d2f:
217: if (isPop2) {
218: iter.next();
219: iter.add(new Instruction(opc_pop));
220: iter.previous();
221: iter.previous();
222: }
223: iter.set(new Instruction(opc_pop2));
224: continue;
225:
226: case opc_ladd:
227: case opc_dadd:
228: case opc_lsub:
229: case opc_dsub:
230: case opc_lmul:
231: case opc_dmul:
232: case opc_ldiv:
233: case opc_ddiv:
234: case opc_lrem:
235: case opc_drem:
236: case opc_land:
237: case opc_lor:
238: case opc_lxor:
239: if (!isPop2)
240: throw new AssertError("pop on long");
241: iter.next();
242: iter.add(popInstr);
243: iter.previous();
244: iter.previous();
245: iter.set(new Instruction(opc_pop2));
246: continue;
247: case opc_lshl:
248: case opc_lshr:
249: case opc_lushr:
250: if (!isPop2)
251: throw new AssertError("pop on long");
252: iter.next();
253: iter.add(popInstr);
254: iter.previous();
255: iter.previous();
256: iter.set(new Instruction(opc_pop));
257: continue;
258:
259: case opc_i2l:
260: case opc_i2d:
261: case opc_f2l:
262: case opc_f2d:
263: if (!isPop2)
264: throw new AssertError("pop on long");
265: iter.set(new Instruction(opc_pop));
266: continue;
267:
268: case opc_lcmp:
269: case opc_dcmpl:
270: case opc_dcmpg:
271: iter.next();
272: iter.add(new Instruction(opc_pop2));
273: if (isPop2) {
274: iter.add(new Instruction(opc_pop));
275: iter.previous();
276: }
277: iter.previous();
278: iter.previous();
279: iter.set(new Instruction(opc_pop2));
280: continue;
281:
282: case opc_getstatic:
283: case opc_getfield: {
284: Reference ref = instr.getReference();
285: int size = TypeSignature.getTypeSize(ref.getType());
286: if (size == 2 && !isPop2)
287: throw new AssertError("pop on long");
288: if (opcode == opc_getfield)
289: size--;
290: switch (size) {
291: case 0:
292: iter.set(popInstr);
293: break;
294: case 1:
295: if (isPop2) {
296: iter.set(new Instruction(opc_pop));
297: break;
298: }
299: /* fall through */
300: case 2:
301: iter.remove();
302: }
303: continue;
304: }
305:
306: case opc_multianewarray: {
307: int dims = instr.getDimensions();
308: if (--dims > 0) {
309: iter.next();
310: while (dims-- > 0) {
311: iter.add(new Instruction(opc_pop));
312: iter.previous();
313: }
314: iter.previous();
315: }
316: iter.set(popInstr);
317: continue;
318: }
319:
320: case opc_invokevirtual:
321: case opc_invokespecial:
322: case opc_invokestatic:
323: case opc_invokeinterface:
324: if (TypeSignature.getReturnSize(instr
325: .getReference().getType()) != 1)
326: break;
327: /* fall through */
328: case opc_checkcast:
329: if (isPop2) {
330: /* This is/may be a double pop on a single value
331: * split it and continue with second half
332: */
333: iter.next();
334: iter.add(new Instruction(opc_pop));
335: iter.add(new Instruction(opc_pop));
336: iter.previous();
337: continue;
338: }
339: }
340: // append the pop behind the unresolvable opcode.
341: iter.next();
342: iter.add(popInstr);
343: continue;
344: }
345: }
346: }
347: }
|