You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
7.8 KiB
308 lines
7.8 KiB
/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
package jode.obfuscator.modules;
|
|
import jode.bytecode.*;
|
|
import jode.obfuscator.*;
|
|
import jode.AssertError;
|
|
import jode.GlobalOptions;
|
|
|
|
import @COLLECTIONS@.ListIterator;
|
|
|
|
public class RemovePopAnalyzer implements CodeTransformer, Opcodes {
|
|
public RemovePopAnalyzer() {
|
|
}
|
|
|
|
public void transformCode(BytecodeInfo bytecode) {
|
|
int poppush[] = new int[2];
|
|
ListIterator iter = bytecode.getInstructions().listIterator();
|
|
next_pop:
|
|
while (iter.hasNext()) {
|
|
Instruction popInstr = (Instruction) iter.next();
|
|
boolean isPop2 = false;
|
|
switch (popInstr.getOpcode()) {
|
|
case opc_nop: {
|
|
iter.remove();
|
|
continue;
|
|
}
|
|
|
|
case opc_pop2:
|
|
isPop2 = true;
|
|
case opc_pop:
|
|
if (popInstr.getPreds() != null)
|
|
// Can't handle pop with multiple predecessors
|
|
continue next_pop;
|
|
Handler[] handlers = bytecode.getExceptionHandlers();
|
|
for (int i=0; i < handlers.length; i++)
|
|
if (handlers[i].catcher == popInstr)
|
|
continue next_pop;
|
|
|
|
// remove pop, we will insert it again if something
|
|
// bad happened.
|
|
iter.remove();
|
|
|
|
// remember position of pop, so we can insert it again.
|
|
Instruction popPrevious = (Instruction) iter.previous();
|
|
Instruction instr = popPrevious;
|
|
int count = 0;
|
|
while (true) {
|
|
if (instr.getSuccs() != null
|
|
|| instr.doesAlwaysJump()) {
|
|
instr = null;
|
|
break;
|
|
}
|
|
instr.getStackPopPush(poppush);
|
|
|
|
if (count < poppush[1]) {
|
|
if (count == 0)
|
|
break;
|
|
|
|
int opcode = instr.getOpcode();
|
|
/* If this is a dup and the instruction popped is the
|
|
* duplicated element, remove the dup and the pop
|
|
*/
|
|
if (count <= 3 && opcode == (opc_dup + count - 1)) {
|
|
iter.remove();
|
|
if (!isPop2)
|
|
continue next_pop;
|
|
|
|
// We have to consider a pop instead of a
|
|
// pop2 now.
|
|
popInstr = new Instruction(opc_pop);
|
|
isPop2 = false;
|
|
instr = (Instruction) iter.previous();
|
|
continue;
|
|
}
|
|
|
|
if (isPop2
|
|
&& count > 1 && count <= 4
|
|
&& opcode == (opc_dup2 + count-2)) {
|
|
iter.remove();
|
|
continue next_pop;
|
|
}
|
|
/* Otherwise popping is not possible */
|
|
instr = null;
|
|
break;
|
|
}
|
|
count += poppush[0] - poppush[1];
|
|
instr = (Instruction) iter.previous();
|
|
}
|
|
|
|
if (instr == null) {
|
|
// We insert the pop at the previous position
|
|
while (iter.next() != popPrevious)
|
|
{}
|
|
if (!isPop2 && popPrevious.getOpcode() == opc_pop) {
|
|
// merge pop with popPrevious
|
|
iter.set(new Instruction(opc_pop2));
|
|
} else
|
|
iter.add(popInstr);
|
|
continue;
|
|
}
|
|
int opcode = instr.getOpcode();
|
|
switch (opcode) {
|
|
case opc_ldc2_w:
|
|
case opc_lload: case opc_dload:
|
|
if (!isPop2)
|
|
throw new AssertError("pop on long");
|
|
iter.remove();
|
|
continue;
|
|
case opc_ldc:
|
|
case opc_iload: case opc_fload: case opc_aload:
|
|
case opc_dup:
|
|
case opc_new:
|
|
if (isPop2)
|
|
iter.set(new Instruction(opc_pop));
|
|
else
|
|
iter.remove();
|
|
continue;
|
|
case opc_iaload: case opc_faload: case opc_aaload:
|
|
case opc_baload: case opc_caload: case opc_saload:
|
|
case opc_iadd: case opc_fadd:
|
|
case opc_isub: case opc_fsub:
|
|
case opc_imul: case opc_fmul:
|
|
case opc_idiv: case opc_fdiv:
|
|
case opc_irem: case opc_frem:
|
|
case opc_iand: case opc_ior : case opc_ixor:
|
|
case opc_ishl: case opc_ishr: case opc_iushr:
|
|
case opc_fcmpl: case opc_fcmpg:
|
|
/* We have to pop one entry more. */
|
|
iter.next();
|
|
iter.add(popInstr);
|
|
iter.previous();
|
|
iter.previous();
|
|
iter.set(new Instruction(opc_pop));
|
|
continue;
|
|
|
|
case opc_dup_x1:
|
|
iter.set(new Instruction(opc_swap));
|
|
iter.next();
|
|
if (isPop2)
|
|
iter.add(new Instruction(opc_pop));
|
|
continue;
|
|
|
|
case opc_dup2:
|
|
if (isPop2) {
|
|
iter.remove();
|
|
continue;
|
|
}
|
|
break;
|
|
case opc_swap:
|
|
if (isPop2) {
|
|
iter.set(popInstr);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case opc_lneg: case opc_dneg:
|
|
case opc_l2d: case opc_d2l:
|
|
case opc_laload: case opc_daload:
|
|
if (!isPop2)
|
|
throw new AssertError("pop on long");
|
|
/* fall through */
|
|
case opc_ineg: case opc_fneg:
|
|
case opc_i2f: case opc_f2i:
|
|
case opc_i2b: case opc_i2c: case opc_i2s:
|
|
case opc_newarray: case opc_anewarray:
|
|
case opc_arraylength:
|
|
case opc_instanceof:
|
|
iter.set(popInstr);
|
|
continue;
|
|
|
|
case opc_l2i: case opc_l2f:
|
|
case opc_d2i: case opc_d2f:
|
|
if (isPop2) {
|
|
iter.next();
|
|
iter.add(new Instruction(opc_pop));
|
|
iter.previous();
|
|
iter.previous();
|
|
}
|
|
iter.set(new Instruction(opc_pop2));
|
|
continue;
|
|
|
|
case opc_ladd: case opc_dadd:
|
|
case opc_lsub: case opc_dsub:
|
|
case opc_lmul: case opc_dmul:
|
|
case opc_ldiv: case opc_ddiv:
|
|
case opc_lrem: case opc_drem:
|
|
case opc_land: case opc_lor : case opc_lxor:
|
|
if (!isPop2)
|
|
throw new AssertError("pop on long");
|
|
iter.next();
|
|
iter.add(popInstr);
|
|
iter.previous();
|
|
iter.previous();
|
|
iter.set(new Instruction(opc_pop2));
|
|
continue;
|
|
case opc_lshl: case opc_lshr: case opc_lushr:
|
|
if (!isPop2)
|
|
throw new AssertError("pop on long");
|
|
iter.next();
|
|
iter.add(popInstr);
|
|
iter.previous();
|
|
iter.previous();
|
|
iter.set(new Instruction(opc_pop));
|
|
continue;
|
|
|
|
case opc_i2l: case opc_i2d:
|
|
case opc_f2l: case opc_f2d:
|
|
if (!isPop2)
|
|
throw new AssertError("pop on long");
|
|
iter.set(new Instruction(opc_pop));
|
|
continue;
|
|
|
|
case opc_lcmp:
|
|
case opc_dcmpl: case opc_dcmpg:
|
|
iter.next();
|
|
iter.add(new Instruction(opc_pop2));
|
|
if (isPop2) {
|
|
iter.add(new Instruction(opc_pop));
|
|
iter.previous();
|
|
}
|
|
iter.previous();
|
|
iter.previous();
|
|
iter.set(new Instruction(opc_pop2));
|
|
continue;
|
|
|
|
case opc_getstatic:
|
|
case opc_getfield: {
|
|
Reference ref = instr.getReference();
|
|
int size = TypeSignature.getTypeSize(ref.getType());
|
|
if (size == 2 && !isPop2)
|
|
throw new AssertError("pop on long");
|
|
if (opcode == opc_getfield)
|
|
size--;
|
|
switch (size) {
|
|
case 0:
|
|
iter.set(popInstr);
|
|
break;
|
|
case 1:
|
|
if (isPop2) {
|
|
iter.set(new Instruction(opc_pop));
|
|
break;
|
|
}
|
|
/* fall through */
|
|
case 2:
|
|
iter.remove();
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case opc_multianewarray: {
|
|
int dims = instr.getDimensions();
|
|
if (--dims > 0) {
|
|
iter.next();
|
|
while (dims-- > 0) {
|
|
iter.add(new Instruction(opc_pop));
|
|
iter.previous();
|
|
}
|
|
iter.previous();
|
|
}
|
|
iter.set(popInstr);
|
|
continue;
|
|
}
|
|
|
|
case opc_invokevirtual:
|
|
case opc_invokespecial:
|
|
case opc_invokestatic:
|
|
case opc_invokeinterface:
|
|
if (TypeSignature.getReturnSize
|
|
(instr.getReference().getType()) != 1)
|
|
break;
|
|
/* fall through */
|
|
case opc_checkcast:
|
|
if (isPop2) {
|
|
/* This is/may be a double pop on a single value
|
|
* split it and continue with second half
|
|
*/
|
|
iter.next();
|
|
iter.add(new Instruction(opc_pop));
|
|
iter.add(new Instruction(opc_pop));
|
|
iter.previous();
|
|
continue;
|
|
}
|
|
}
|
|
// append the pop behind the unresolvable opcode.
|
|
iter.next();
|
|
iter.add(popInstr);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|