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