git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@251 379699f6-c40d-0410-875b-85095c16579estable
parent
cf7ede858a
commit
2d01111d8f
@ -0,0 +1,157 @@ |
||||
/* jode.bytecode.GrowableConstantPool Copyright (C) 1998 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.bytecode; |
||||
import java.io.*; |
||||
import jode.Type; |
||||
import java.util.Hashtable; |
||||
|
||||
/** |
||||
* This class represent a constant pool, where new constants can be added to. |
||||
* |
||||
* @author Jochen Hoenicke |
||||
*/ |
||||
public class GrowableConstantPool extends ConstantPool { |
||||
Hashtable entryToIndex = new Hashtable(); |
||||
|
||||
public GrowableConstantPool () { |
||||
count = 1; |
||||
tags = new int[1]; |
||||
indices1 = new int[1]; |
||||
indices2 = new int[1]; |
||||
constants = new Object[1]; |
||||
} |
||||
|
||||
public final void grow(int wantedSize) { |
||||
if (tags.length < wantedSize) { |
||||
int newSize = Math.max(tags.length*2, wantedSize); |
||||
int[] tmpints = new int[newSize]; |
||||
System.arraycopy(tags, 0, tmpints, 0, count); |
||||
tags = tmpints; |
||||
tmpints = new int[newSize]; |
||||
System.arraycopy(indices1, 0, tmpints, 0, count); |
||||
indices1 = tmpints; |
||||
tmpints = new int[newSize]; |
||||
System.arraycopy(indices2, 0, tmpints, 0, count); |
||||
indices2 = tmpints; |
||||
Object[] tmpobjs = new Object[newSize]; |
||||
System.arraycopy(constants, 0, tmpobjs, 0, count); |
||||
constants = tmpobjs; |
||||
} |
||||
} |
||||
|
||||
public int putConstant(int tag, Object constant) { |
||||
String key = tag+"C"+constant; |
||||
Integer index = (Integer) entryToIndex.get(key); |
||||
if (index != null) |
||||
return index.intValue(); |
||||
int newIndex = count; |
||||
grow(count+1); |
||||
tags[newIndex] = tag; |
||||
constants[newIndex] = constant; |
||||
entryToIndex.put(key, new Integer(newIndex)); |
||||
count++; |
||||
if (tag == DOUBLE || tag == LONG) |
||||
count++; |
||||
return newIndex; |
||||
} |
||||
|
||||
public int putIndexed(int tag, int index1, int index2) { |
||||
String key = tag+"I"+index1+","+index2; |
||||
Integer index = (Integer) entryToIndex.get(key); |
||||
if (index != null) |
||||
return index.intValue(); |
||||
grow(count+1); |
||||
tags[count] = tag; |
||||
indices1[count] = index1; |
||||
indices2[count] = index2; |
||||
entryToIndex.put(key, new Integer(count)); |
||||
return count++; |
||||
} |
||||
|
||||
public final int putUTF(String utf) { |
||||
return putConstant(UTF8, utf); |
||||
} |
||||
|
||||
public int putClassRef(String name) { |
||||
return putIndexed(CLASS, putUTF(name.replace('.','/')), 0); |
||||
} |
||||
|
||||
public int putRef(int tag, String[] names) { |
||||
int classIndex = putClassRef(names[0]); |
||||
int nameIndex = putUTF(names[1]); |
||||
int typeIndex = putUTF(names[2]); |
||||
int nameTypeIndex = putIndexed(NAMEANDTYPE, nameIndex, typeIndex); |
||||
return putIndexed(tag, classIndex, nameTypeIndex); |
||||
} |
||||
|
||||
public int copyConstant(ConstantPool cp, int index) |
||||
throws ClassFormatException { |
||||
if (cp.tags[index] == STRING) |
||||
return putIndexed(STRING, |
||||
putUTF(cp.getUTF8(cp.indices1[index])), 0); |
||||
else |
||||
return putConstant(cp.tags[index], cp.constants[index]); |
||||
} |
||||
|
||||
public void write(DataOutputStream stream) |
||||
throws IOException { |
||||
stream.writeShort(count); |
||||
for (int i=1; i< count; i++) { |
||||
int tag = tags[i]; |
||||
stream.writeByte(tag); |
||||
switch (tag) { |
||||
case CLASS: |
||||
stream.writeShort(indices1[i]); |
||||
break; |
||||
case FIELDREF: |
||||
case METHODREF: |
||||
case INTERFACEMETHODREF: |
||||
stream.writeShort(indices1[i]); |
||||
stream.writeShort(indices2[i]); |
||||
break; |
||||
case STRING: |
||||
stream.writeShort(indices1[i]); |
||||
break; |
||||
case INTEGER: |
||||
stream.writeInt(((Integer)constants[i]).intValue()); |
||||
break; |
||||
case FLOAT: |
||||
stream.writeFloat(((Float)constants[i]).floatValue()); |
||||
break; |
||||
case LONG: |
||||
stream.writeLong(((Long)constants[i]).longValue()); |
||||
i++; |
||||
break; |
||||
case DOUBLE: |
||||
stream.writeDouble(((Double)constants[i]).doubleValue()); |
||||
i++; |
||||
break; |
||||
case NAMEANDTYPE: |
||||
stream.writeShort(indices1[i]); |
||||
stream.writeShort(indices2[i]); |
||||
break; |
||||
case UTF8: |
||||
stream.writeUTF((String)constants[i]); |
||||
break; |
||||
default: |
||||
throw new ClassFormatException("unknown constant tag"); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,673 @@ |
||||
/* |
||||
* Opcodes (c) 1998 Jochen Hoenicke |
||||
* |
||||
* You may distribute under the terms of the GNU General Public License. |
||||
* |
||||
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, |
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF |
||||
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE |
||||
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
||||
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" |
||||
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, |
||||
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||||
* |
||||
* $Id$ |
||||
*/ |
||||
|
||||
package jode.decompiler; |
||||
import jode.CodeAnalyzer; |
||||
import jode.LocalInfo; |
||||
import jode.Type; |
||||
import jode.MethodType; |
||||
import jode.flow.*; |
||||
import jode.bytecode.*; |
||||
import java.io.*; |
||||
import java.util.Vector; |
||||
|
||||
/** |
||||
* This is an abstract class which creates flow blocks for the |
||||
* opcodes in a byte stream. |
||||
*/ |
||||
public abstract class Opcodes implements jode.bytecode.Opcodes { |
||||
|
||||
private final static Type ALL_INT_TYPE = Type.tUInt; |
||||
private final static Type BOOL_INT_TYPE = Type.tBoolInt; |
||||
private final static Type INT_TYPE = Type.tInt; |
||||
private final static Type LONG_TYPE = Type.tLong; |
||||
private final static Type FLOAT_TYPE = Type.tFloat; |
||||
private final static Type DOUBLE_TYPE = Type.tDouble; |
||||
private final static Type OBJECT_TYPE = Type.tUObject; |
||||
private final static Type BOOLEAN_TYPE = Type.tBoolean; |
||||
private final static Type BYTEBOOL_TYPE = Type.tBoolByte; |
||||
private final static Type BYTE_TYPE = Type.tByte; |
||||
private final static Type CHAR_TYPE = Type.tChar; |
||||
private final static Type SHORT_TYPE = Type.tShort; |
||||
private final static Type VOID_TYPE = Type.tVoid; |
||||
|
||||
private final static Type types[][] = { |
||||
{BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }, |
||||
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE, |
||||
BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE }, |
||||
{ BYTE_TYPE, CHAR_TYPE, SHORT_TYPE }, |
||||
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE } |
||||
}; |
||||
|
||||
private static StructuredBlock createNormal(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
Expression instr) |
||||
{ |
||||
return new InstructionBlock(instr, new Jump(addr+length)); |
||||
} |
||||
|
||||
private static StructuredBlock createSpecial(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
int type, int stackcount, int param) |
||||
{ |
||||
return new SpecialBlock(type, stackcount, param, |
||||
new Jump(addr+length)); |
||||
} |
||||
|
||||
private static StructuredBlock createGoto(CodeAnalyzer ca, |
||||
int addr, int length, int destAddr) |
||||
{ |
||||
return new EmptyBlock(new Jump(destAddr)); |
||||
} |
||||
|
||||
private static StructuredBlock createJsr(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
int destAddr) |
||||
{ |
||||
return new JsrBlock(new Jump(addr+length), |
||||
new Jump(destAddr)); |
||||
} |
||||
|
||||
private static StructuredBlock createIfGoto(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
int destAddr, Expression instr) |
||||
{ |
||||
return new ConditionalBlock(instr, |
||||
new Jump(destAddr), |
||||
new Jump(addr+length)); |
||||
} |
||||
|
||||
private static StructuredBlock createSwitch(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
int[] cases, int[] dests) |
||||
{ |
||||
return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests); |
||||
} |
||||
|
||||
private static StructuredBlock createBlock(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
StructuredBlock block) |
||||
{ |
||||
return block; |
||||
} |
||||
|
||||
private static StructuredBlock createRet(CodeAnalyzer ca, |
||||
int addr, int length, |
||||
LocalInfo local) |
||||
{ |
||||
return new RetBlock(local); |
||||
} |
||||
|
||||
/** |
||||
* Read an opcode out of a data input stream and determine its size |
||||
* and its successors. |
||||
* @param addr The current address. |
||||
* @param stream The stream containing the java byte code. |
||||
* @return An array of ints; the first entry is the size of the |
||||
* instruction, the remaining are the successors. |
||||
*/ |
||||
public static int[] getSizeAndSuccs(int addr, DataInputStream stream) |
||||
throws IOException |
||||
{ |
||||
int opcode = stream.readUnsignedByte(); |
||||
switch (opcode) { |
||||
case opc_multianewarray: |
||||
stream.skip(3); |
||||
return new int[] { 4, addr+4 }; |
||||
case opc_invokeinterface: |
||||
stream.skip(4); |
||||
return new int[] { 5, addr+5 }; |
||||
|
||||
case opc_wide: { |
||||
switch (opcode = stream.readUnsignedByte()) { |
||||
case opc_iload: case opc_lload: |
||||
case opc_fload: case opc_dload: case opc_aload: |
||||
case opc_istore: case opc_lstore: |
||||
case opc_fstore: case opc_dstore: case opc_astore: |
||||
stream.skip(2); |
||||
return new int[] { 4, addr+4 }; |
||||
|
||||
case opc_iinc: |
||||
stream.skip(4); |
||||
return new int[] { 6, addr+6 }; |
||||
case opc_ret: |
||||
stream.skip(2); |
||||
return new int[] { 4 }; |
||||
default: |
||||
throw new ClassFormatError("Invalid wide opcode "+opcode); |
||||
} |
||||
} |
||||
case opc_ret: |
||||
stream.skip(1); |
||||
return new int[] { 2 }; |
||||
|
||||
case opc_jsr_w: |
||||
return new int[] { 5, addr + 5, addr + stream.readInt() }; |
||||
|
||||
case opc_goto: |
||||
return new int[] { 3, addr + stream.readShort() }; |
||||
case opc_goto_w: |
||||
return new int[] { 5, addr + stream.readInt() }; |
||||
|
||||
case opc_tableswitch: { |
||||
int length = 3-(addr % 4); |
||||
stream.skip(length); |
||||
int def = addr + stream.readInt(); |
||||
int low = stream.readInt(); |
||||
int high = stream.readInt(); |
||||
int[] dests = new int[high-low+3]; |
||||
for (int i=0; i+low <= high; i++) { |
||||
dests[i+1] = addr + stream.readInt(); |
||||
} |
||||
dests[dests.length-1] = def; |
||||
dests[0] = length + 13 + 4 * (high-low+1); |
||||
return dests; |
||||
} |
||||
case opc_lookupswitch: { |
||||
int length = 3-(addr % 4); |
||||
stream.skip(length); |
||||
int def = addr + stream.readInt(); |
||||
int npairs = stream.readInt(); |
||||
int[] dests = new int[npairs+2]; |
||||
for (int i=0; i < npairs; i++) { |
||||
int value = stream.readInt(); |
||||
dests[i+1] = addr + stream.readInt(); |
||||
} |
||||
dests[npairs+1] = def; |
||||
dests[0] = length + 9 + 8 * npairs; |
||||
return dests; |
||||
} |
||||
|
||||
case opc_ifnull: case opc_ifnonnull: |
||||
case opc_jsr: |
||||
return new int[] { 3, addr + 3, addr + stream.readShort() }; |
||||
|
||||
case opc_sipush: |
||||
case opc_ldc_w: |
||||
case opc_ldc2_w: |
||||
case opc_iinc: |
||||
case opc_getstatic: |
||||
case opc_getfield: |
||||
case opc_putstatic: |
||||
case opc_putfield: |
||||
case opc_invokevirtual: |
||||
case opc_invokespecial: |
||||
case opc_invokestatic: |
||||
case opc_new: |
||||
case opc_anewarray: |
||||
case opc_checkcast: |
||||
case opc_instanceof: |
||||
stream.skip(2); |
||||
return new int[] { 3, addr+3 }; |
||||
} |
||||
|
||||
if (opcode == opc_newarray |
||||
|| (opcode >= opc_bipush && opcode <= opc_aload) |
||||
|| (opcode >= opc_istore && opcode <= opc_astore)) { |
||||
stream.skip(1); |
||||
return new int[] { 2, addr+2 }; |
||||
} |
||||
|
||||
if (opcode == opc_athrow |
||||
|| opcode >= opc_ireturn && opcode <= opc_return) |
||||
return new int[] { 1 }; |
||||
if (opcode >= opc_ifeq && opcode <= opc_if_acmpne) |
||||
return new int[] { 3, addr + 3, addr + stream.readShort() }; |
||||
if (opcode == opc_xxxunusedxxx || opcode > opc_breakpoint) |
||||
throw new ClassFormatError("Invalid opcode "+opcode); |
||||
|
||||
return new int[] { 1, addr+1 }; |
||||
} |
||||
|
||||
/** |
||||
* Read an opcode out of a data input stream containing the bytecode. |
||||
* @param addr The current address. |
||||
* @param stream The stream containing the java byte code. |
||||
* @param ca The Code Analyzer |
||||
* (where further information can be get from). |
||||
* @return The FlowBlock representing this opcode |
||||
* or null if the stream is empty. |
||||
* @exception IOException if an read error occured. |
||||
* @exception ClassFormatError if an invalid opcode is detected. |
||||
*/ |
||||
public static StructuredBlock readOpcode(ConstantPool cpool, |
||||
int addr, DataInputStream stream, |
||||
CodeAnalyzer ca) |
||||
throws IOException, ClassFormatError |
||||
{ |
||||
int opcode = stream.readUnsignedByte(); |
||||
switch (opcode) { |
||||
case opc_nop: |
||||
return createBlock |
||||
(ca, addr, 1, new EmptyBlock(new Jump(addr+1))); |
||||
case opc_aconst_null: |
||||
return createNormal |
||||
(ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null")); |
||||
case opc_iconst_0: case opc_iconst_1: |
||||
return createNormal |
||||
(ca, addr, 1, new ConstOperator |
||||
(Type.tBoolInt, Integer.toString(opcode - opc_iconst_0))); |
||||
case opc_iconst_m1: case opc_iconst_2: |
||||
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: |
||||
return createNormal |
||||
(ca, addr, 1, new ConstOperator |
||||
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); |
||||
case opc_lconst_0: case opc_lconst_1: |
||||
return createNormal |
||||
(ca, addr, 1, new ConstOperator |
||||
(LONG_TYPE, |
||||
Integer.toString(opcode - opc_lconst_0))); |
||||
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: |
||||
return createNormal |
||||
(ca, addr, 1, new ConstOperator |
||||
(FLOAT_TYPE, |
||||
Integer.toString(opcode - opc_fconst_0) + ".0")); |
||||
case opc_dconst_0: case opc_dconst_1: |
||||
return createNormal |
||||
(ca, addr, 1, new ConstOperator |
||||
(DOUBLE_TYPE, |
||||
Integer.toString(opcode - opc_dconst_0) + ".0")); |
||||
case opc_bipush: |
||||
return createNormal |
||||
(ca, addr, 2, new ConstOperator |
||||
(ALL_INT_TYPE, Integer.toString(stream.readByte()))); |
||||
case opc_sipush: { |
||||
short value = stream.readShort(); |
||||
return createNormal |
||||
(ca, addr, 3, new ConstOperator |
||||
((value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) |
||||
/* yes javac codes -128 with sipush :-( */ |
||||
? Type.tRange(Type.tInt, Type.tChar) : ALL_INT_TYPE, |
||||
Integer.toString(value))); |
||||
} |
||||
case opc_ldc: { |
||||
int index = stream.readUnsignedByte(); |
||||
return createNormal |
||||
(ca, addr, 2, new ConstOperator |
||||
(cpool.getConstantType(index), |
||||
cpool.getConstantString(index))); |
||||
} |
||||
case opc_ldc_w: |
||||
case opc_ldc2_w: { |
||||
int index = stream.readUnsignedShort(); |
||||
return createNormal |
||||
(ca, addr, 3, new ConstOperator |
||||
(cpool.getConstantType(index), |
||||
cpool.getConstantString(index))); |
||||
} |
||||
case opc_iload: case opc_lload: |
||||
case opc_fload: case opc_dload: case opc_aload: |
||||
return createNormal |
||||
(ca, addr, 2, new LocalLoadOperator |
||||
(types[0][opcode-opc_iload], |
||||
ca.getLocalInfo(addr, stream.readUnsignedByte()))); |
||||
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: |
||||
case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: |
||||
case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: |
||||
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: |
||||
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: |
||||
return createNormal |
||||
(ca, addr, 1, new LocalLoadOperator |
||||
(types[0][(opcode-opc_iload_0)/4], |
||||
ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3))); |
||||
case opc_iaload: case opc_laload: |
||||
case opc_faload: case opc_daload: case opc_aaload: |
||||
case opc_baload: case opc_caload: case opc_saload: |
||||
return createNormal |
||||
(ca, addr, 1, new ArrayLoadOperator |
||||
(types[1][opcode - opc_iaload])); |
||||
case opc_istore: case opc_lstore: |
||||
case opc_fstore: case opc_dstore: case opc_astore: |
||||
return createNormal |
||||
(ca, addr, 2, new LocalStoreOperator |
||||
(types[0][opcode-opc_istore], |
||||
ca.getLocalInfo(addr+2, stream.readUnsignedByte()), |
||||
Operator.ASSIGN_OP)); |
||||
case opc_istore_0: case opc_istore_1: |
||||
case opc_istore_2: case opc_istore_3: |
||||
case opc_lstore_0: case opc_lstore_1: |
||||
case opc_lstore_2: case opc_lstore_3: |
||||
case opc_fstore_0: case opc_fstore_1: |
||||
case opc_fstore_2: case opc_fstore_3: |
||||
case opc_dstore_0: case opc_dstore_1: |
||||
case opc_dstore_2: case opc_dstore_3: |
||||
case opc_astore_0: case opc_astore_1: |
||||
case opc_astore_2: case opc_astore_3: |
||||
return createNormal |
||||
(ca, addr, 1, new LocalStoreOperator |
||||
(types[0][(opcode-opc_istore_0)/4], |
||||
ca.getLocalInfo(addr+1, (opcode-opc_istore_0) & 3), |
||||
Operator.ASSIGN_OP)); |
||||
case opc_iastore: case opc_lastore: |
||||
case opc_fastore: case opc_dastore: case opc_aastore: |
||||
case opc_bastore: case opc_castore: case opc_sastore: |
||||
return createNormal |
||||
(ca, addr, 1, new ArrayStoreOperator |
||||
(types[1][opcode - opc_iastore])); |
||||
case opc_pop: case opc_pop2: |
||||
return createSpecial |
||||
(ca, addr, 1, SpecialBlock.POP, opcode - opc_pop + 1, 0); |
||||
case opc_dup: case opc_dup_x1: case opc_dup_x2: |
||||
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: |
||||
return createSpecial |
||||
(ca, addr, 1, SpecialBlock.DUP, |
||||
(opcode - opc_dup)/3+1, (opcode - opc_dup)%3); |
||||
case opc_swap: |
||||
return createSpecial(ca, addr, 1, SpecialBlock.SWAP, 1, 0); |
||||
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: |
||||
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: |
||||
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: |
||||
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: |
||||
case opc_irem: case opc_lrem: case opc_frem: case opc_drem: |
||||
return createNormal |
||||
(ca, addr, 1, new BinaryOperator |
||||
(types[3][(opcode - opc_iadd)%4], |
||||
(opcode - opc_iadd)/4+Operator.ADD_OP)); |
||||
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: |
||||
return createNormal |
||||
(ca, addr, 1, new UnaryOperator |
||||
(types[3][opcode - opc_ineg], Operator.NEG_OP)); |
||||
case opc_ishl: case opc_lshl: |
||||
case opc_ishr: case opc_lshr: |
||||
case opc_iushr: case opc_lushr: |
||||
return createNormal |
||||
(ca, addr, 1, new ShiftOperator |
||||
(types[3][(opcode - opc_ishl)%2], |
||||
(opcode - opc_ishl)/2 + Operator.SHIFT_OP)); |
||||
case opc_iand: case opc_land: |
||||
case opc_ior : case opc_lor : |
||||
case opc_ixor: case opc_lxor: |
||||
return createNormal |
||||
(ca, addr, 1, new BinaryOperator |
||||
(types[0][(opcode - opc_iand)%2], |
||||
(opcode - opc_iand)/2 + Operator.AND_OP)); |
||||
case opc_iinc: { |
||||
int local = stream.readUnsignedByte(); |
||||
int value = stream.readByte(); |
||||
int operation = Operator.ADD_OP; |
||||
if (value < 0) { |
||||
value = -value; |
||||
operation = Operator.NEG_OP; |
||||
} |
||||
LocalInfo li = ca.getLocalInfo(addr, local); |
||||
li.setType(ALL_INT_TYPE); |
||||
return createNormal |
||||
(ca, addr, 3, new IIncOperator |
||||
(li, Integer.toString(value), |
||||
operation + Operator.OPASSIGN_OP)); |
||||
} |
||||
case opc_i2l: case opc_i2f: case opc_i2d: |
||||
case opc_l2i: case opc_l2f: case opc_l2d: |
||||
case opc_f2i: case opc_f2l: case opc_f2d: |
||||
case opc_d2i: case opc_d2l: case opc_d2f: { |
||||
int from = (opcode-opc_i2l)/3; |
||||
int to = (opcode-opc_i2l)%3; |
||||
if (to >= from) |
||||
to++; |
||||
return createNormal |
||||
(ca, addr, 1, new ConvertOperator(types[3][from], |
||||
types[3][to])); |
||||
} |
||||
case opc_i2b: case opc_i2c: case opc_i2s: |
||||
return createNormal |
||||
(ca, addr, 1, new ConvertOperator |
||||
(ALL_INT_TYPE, types[2][opcode-opc_i2b])); |
||||
case opc_lcmp: |
||||
case opc_fcmpl: case opc_fcmpg: |
||||
case opc_dcmpl: case opc_dcmpg: |
||||
return createNormal |
||||
(ca, addr, 1, new CompareToIntOperator |
||||
(types[3][(opcode-(opc_lcmp-3))/2], |
||||
(opcode-(opc_lcmp-3))%2)); |
||||
case opc_ifeq: case opc_ifne: |
||||
return createIfGoto |
||||
(ca, addr, 3, addr+stream.readShort(), |
||||
new CompareUnaryOperator |
||||
(BOOL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP))); |
||||
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: |
||||
return createIfGoto |
||||
(ca, addr, 3, addr+stream.readShort(), |
||||
new CompareUnaryOperator |
||||
(ALL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP))); |
||||
case opc_if_icmpeq: case opc_if_icmpne: |
||||
return createIfGoto |
||||
(ca, addr, 3, addr+stream.readShort(), |
||||
new CompareBinaryOperator |
||||
(Type.tBoolInt, |
||||
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); |
||||
case opc_if_icmplt: case opc_if_icmpge: |
||||
case opc_if_icmpgt: case opc_if_icmple: |
||||
return createIfGoto |
||||
(ca, addr, 3, addr+stream.readShort(), |
||||
new CompareBinaryOperator |
||||
(ALL_INT_TYPE, |
||||
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); |
||||
case opc_if_acmpeq: case opc_if_acmpne: |
||||
return createIfGoto |
||||
(ca, addr, 3, addr+stream.readShort(), |
||||
new CompareBinaryOperator |
||||
(OBJECT_TYPE, |
||||
opcode - (opc_if_acmpeq-Operator.COMPARE_OP))); |
||||
case opc_goto: |
||||
return createGoto |
||||
(ca, addr, 3, addr+stream.readShort()); |
||||
case opc_jsr: |
||||
return createJsr |
||||
(ca, addr, 3, addr+stream.readShort()); |
||||
case opc_ret: |
||||
return createRet |
||||
(ca, addr, 2, |
||||
ca.getLocalInfo(addr, stream.readUnsignedByte())); |
||||
case opc_tableswitch: { |
||||
int length = 3-(addr % 4); |
||||
stream.skip(length); |
||||
int def = addr + stream.readInt(); |
||||
int low = stream.readInt(); |
||||
int high = stream.readInt(); |
||||
int[] cases = new int[high-low+1]; |
||||
int[] dests = new int[high-low+2]; |
||||
for (int i=0; i+low <= high; i++) { |
||||
cases[i] = i+low; |
||||
dests[i] = addr + stream.readInt(); |
||||
} |
||||
dests[cases.length] = def; |
||||
length += 13 + 4 * cases.length; |
||||
return createSwitch |
||||
(ca, addr, length, cases, dests); |
||||
} |
||||
case opc_lookupswitch: { |
||||
int length = 3-(addr % 4); |
||||
stream.skip(length); |
||||
int def = addr + stream.readInt(); |
||||
int npairs = stream.readInt(); |
||||
int[] cases = new int[npairs]; |
||||
int[] dests = new int[npairs+1]; |
||||
for (int i=0; i < npairs; i++) { |
||||
cases[i] = stream.readInt(); |
||||
dests[i] = addr + stream.readInt(); |
||||
} |
||||
dests[npairs] = def; |
||||
length += 9 + 8 * npairs; |
||||
return createSwitch |
||||
(ca, addr, length, cases, dests); |
||||
} |
||||
case opc_ireturn: case opc_lreturn: |
||||
case opc_freturn: case opc_dreturn: case opc_areturn: { |
||||
/* Address -1 is interpreted as end of method */ |
||||
Type retType = Type.tSubType(ca.getMethod().getReturnType()); |
||||
return createBlock |
||||
(ca, addr, 1, new ReturnBlock(new NopOperator(retType))); |
||||
} |
||||
case opc_return: |
||||
return createBlock |
||||
(ca, addr, 1, new EmptyBlock(new Jump(-1))); |
||||
case opc_getstatic: |
||||
case opc_getfield: { |
||||
String[] ref = cpool.getRef(stream.readUnsignedShort()); |
||||
return createNormal |
||||
(ca, addr, 3, new GetFieldOperator |
||||
(ca, opcode == opc_getstatic, |
||||
Type.tClass(ref[0]), Type.tType(ref[2]), ref[1])); |
||||
} |
||||
case opc_putstatic: |
||||
case opc_putfield: { |
||||
String[] ref = cpool.getRef(stream.readUnsignedShort()); |
||||
return createNormal |
||||
(ca, addr, 3, new PutFieldOperator |
||||
(ca, opcode == opc_putstatic, |
||||
Type.tClass(ref[0]), Type.tType(ref[2]), ref[1])); |
||||
} |
||||
case opc_invokevirtual: |
||||
case opc_invokespecial: |
||||
case opc_invokestatic : |
||||
case opc_invokeinterface: { |
||||
String[] ref = cpool.getRef(stream.readUnsignedShort()); |
||||
StructuredBlock block = createNormal |
||||
(ca, addr, opcode == opc_invokeinterface ? 5 : 3, |
||||
new InvokeOperator |
||||
(ca, opcode == opc_invokespecial, |
||||
Type.tClass(ref[0]), |
||||
new MethodType(opcode == opc_invokestatic, ref[2]), |
||||
ref[1])); |
||||
if (opcode == opc_invokeinterface) |
||||
stream.readUnsignedShort(); |
||||
return block; |
||||
} |
||||
case opc_new: { |
||||
Type type = Type.tClassOrArray |
||||
(cpool.getClassName(stream.readUnsignedShort())); |
||||
type.useType(); |
||||
return createNormal(ca, addr, 3, new NewOperator(type)); |
||||
} |
||||
case opc_newarray: { |
||||
Type type; |
||||
switch (stream.readUnsignedByte()) { |
||||
case 4: type = Type.tBoolean; break; |
||||
case 5: type = Type.tChar ; break; |
||||
case 6: type = Type.tFloat ; break; |
||||
case 7: type = Type.tDouble ; break; |
||||
case 8: type = Type.tByte ; break; |
||||
case 9: type = Type.tShort ; break; |
||||
case 10: type = Type.tInt ; break; |
||||
case 11: type = Type.tLong ; break; |
||||
default: |
||||
throw new ClassFormatError("Invalid newarray operand"); |
||||
} |
||||
type.useType(); |
||||
return createNormal |
||||
(ca, addr, 2, new NewArrayOperator(Type.tArray(type), 1)); |
||||
} |
||||
case opc_anewarray: { |
||||
Type type = Type.tClassOrArray |
||||
(cpool.getClassName(stream.readUnsignedShort())); |
||||
type.useType(); |
||||
return createNormal |
||||
(ca, addr, 3, new NewArrayOperator(Type.tArray(type), 1)); |
||||
} |
||||
case opc_arraylength: |
||||
return createNormal |
||||
(ca, addr, 1, new ArrayLengthOperator()); |
||||
case opc_athrow: |
||||
return createBlock |
||||
(ca, addr, 1, |
||||
new ThrowBlock(new NopOperator(Type.tUObject))); |
||||
case opc_checkcast: { |
||||
Type type = Type.tClassOrArray |
||||
(cpool.getClassName(stream.readUnsignedShort())); |
||||
type.useType(); |
||||
return createNormal |
||||
(ca, addr, 3, new CheckCastOperator(type)); |
||||
} |
||||
case opc_instanceof: { |
||||
Type type = Type.tClassOrArray |
||||
(cpool.getClassName(stream.readUnsignedShort())); |
||||
type.useType(); |
||||
return createNormal |
||||
(ca, addr, 3, new InstanceOfOperator(type)); |
||||
} |
||||
case opc_monitorenter: |
||||
return createNormal(ca, addr, 1, |
||||
new MonitorEnterOperator()); |
||||
case opc_monitorexit: |
||||
return createNormal(ca, addr, 1, |
||||
new MonitorExitOperator()); |
||||
case opc_wide: { |
||||
switch (opcode=stream.readUnsignedByte()) { |
||||
case opc_iload: case opc_lload: |
||||
case opc_fload: case opc_dload: case opc_aload: |
||||
return createNormal |
||||
(ca, addr, 4, |
||||
new LocalLoadOperator |
||||
(types[0][opcode-opc_iload], |
||||
ca.getLocalInfo(addr, stream.readUnsignedShort()))); |
||||
case opc_istore: case opc_lstore: |
||||
case opc_fstore: case opc_dstore: case opc_astore: |
||||
return createNormal |
||||
(ca, addr, 4, |
||||
new LocalStoreOperator |
||||
(types[0][opcode-opc_istore], |
||||
ca.getLocalInfo(addr+4, stream.readUnsignedShort()), |
||||
Operator.ASSIGN_OP)); |
||||
case opc_iinc: { |
||||
int local = stream.readUnsignedShort(); |
||||
int value = stream.readShort(); |
||||
int operation = Operator.ADD_OP; |
||||
if (value < 0) { |
||||
value = -value; |
||||
operation = Operator.NEG_OP; |
||||
} |
||||
LocalInfo li = ca.getLocalInfo(addr, local); |
||||
li.setType(ALL_INT_TYPE); |
||||
return createNormal |
||||
(ca, addr, 6, new IIncOperator |
||||
(li, Integer.toString(value), |
||||
operation + Operator.OPASSIGN_OP)); |
||||
} |
||||
case opc_ret: |
||||
return createRet |
||||
(ca, addr, 4, |
||||
ca.getLocalInfo(addr, stream.readUnsignedShort())); |
||||
default: |
||||
throw new ClassFormatError("Invalid wide opcode "+opcode); |
||||
} |
||||
} |
||||
case opc_multianewarray: { |
||||
Type type = Type.tClassOrArray |
||||
(cpool.getClassName(stream.readUnsignedShort())); |
||||
int dimension = stream.readUnsignedByte(); |
||||
return createNormal |
||||
(ca, addr, 4, |
||||
new NewArrayOperator(type, dimension)); |
||||
} |
||||
case opc_ifnull: case opc_ifnonnull: |
||||
return createIfGoto |
||||
(ca, addr, 3, addr+stream.readShort(), |
||||
new CompareUnaryOperator |
||||
(OBJECT_TYPE, opcode - (opc_ifnull-Operator.COMPARE_OP))); |
||||
case opc_goto_w: |
||||
return createGoto |
||||
(ca, addr, 5, addr + stream.readInt()); |
||||
case opc_jsr_w: |
||||
return createJsr |
||||
(ca, addr, 5, addr+stream.readInt()); |
||||
default: |
||||
throw new ClassFormatError("Invalid opcode "+opcode); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue