git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@2 379699f6-c40d-0410-875b-85095c16579estable
parent
1be1aaff37
commit
55a5ea33d9
@ -0,0 +1,18 @@ |
||||
package jode; |
||||
|
||||
public class Block extends Instruction { |
||||
Expression[] exprs; |
||||
|
||||
public Block(int addr, int length, Expression[] exprs) { |
||||
super(addr,length); |
||||
this.exprs = exprs; |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
for (int i=0; i< exprs.length; i++) |
||||
exprs[i].dumpSource(writer,ca); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,10 @@ |
||||
package jode; |
||||
|
||||
public class AssertError extends Error { |
||||
public AssertError() { |
||||
} |
||||
|
||||
public AssertError(String detail) { |
||||
super(detail); |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
import java.lang.reflect.Modifier; |
||||
|
||||
public class Decompiler { |
||||
public static void main(String[] params) { |
||||
JodeEnvironment env = new JodeEnvironment(); |
||||
for (int i=0; i<params.length; i++) { |
||||
env.doClass(params[i]); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,225 @@ |
||||
package jode; |
||||
import java.io.*; |
||||
import sun.tools.java.Type; |
||||
|
||||
public interface Opcodes { |
||||
public final static int NOP_OP = 0; |
||||
public final static int ACONST_NULL_OP = 1; |
||||
public final static int ICONST_M1_OP = 2; |
||||
public final static int ICONST_0_OP = 3; |
||||
public final static int ICONST_1_OP = 4; |
||||
public final static int ICONST_2_OP = 5; |
||||
public final static int ICONST_3_OP = 6; |
||||
public final static int ICONST_4_OP = 7; |
||||
public final static int ICONST_5_OP = 8; |
||||
public final static int LCONST_0_OP = 9; |
||||
public final static int LCONST_1_OP = 10; |
||||
public final static int FCONST_0_OP = 11; |
||||
public final static int FCONST_1_OP = 12; |
||||
public final static int FCONST_2_OP = 13; |
||||
public final static int DCONST_0_OP = 14; |
||||
public final static int DCONST_1_OP = 15; |
||||
public final static int BIPUSH_OP = 16; |
||||
public final static int SIPUSH_OP = 17; |
||||
public final static int LDC_OP = 18; |
||||
public final static int LDC_W_OP = 19; |
||||
public final static int LDC2_W_OP = 20; |
||||
public final static int ILOAD_OP = 21; |
||||
public final static int LLOAD_OP = 22; |
||||
public final static int FLOAD_OP = 23; |
||||
public final static int DLOAD_OP = 24; |
||||
public final static int ALOAD_OP = 25; |
||||
public final static int ILOAD_0_OP = 26; |
||||
public final static int ILOAD_1_OP = 27; |
||||
public final static int ILOAD_2_OP = 28; |
||||
public final static int ILOAD_3_OP = 29; |
||||
public final static int LLOAD_0_OP = 30; |
||||
public final static int LLOAD_1_OP = 31; |
||||
public final static int LLOAD_2_OP = 32; |
||||
public final static int LLOAD_3_OP = 33; |
||||
public final static int FLOAD_0_OP = 34; |
||||
public final static int FLOAD_1_OP = 35; |
||||
public final static int FLOAD_2_OP = 36; |
||||
public final static int FLOAD_3_OP = 37; |
||||
public final static int DLOAD_0_OP = 38; |
||||
public final static int DLOAD_1_OP = 39; |
||||
public final static int DLOAD_2_OP = 40; |
||||
public final static int DLOAD_3_OP = 41; |
||||
public final static int ALOAD_0_OP = 42; |
||||
public final static int ALOAD_1_OP = 43; |
||||
public final static int ALOAD_2_OP = 44; |
||||
public final static int ALOAD_3_OP = 45; |
||||
public final static int IALOAD_OP = 46; |
||||
public final static int LALOAD_OP = 47; |
||||
public final static int FALOAD_OP = 48; |
||||
public final static int DALOAD_OP = 49; |
||||
public final static int AALOAD_OP = 50; |
||||
public final static int BALOAD_OP = 51; |
||||
public final static int CALOAD_OP = 52; |
||||
public final static int SALOAD_OP = 53; |
||||
public final static int ISTORE_OP = 54; |
||||
public final static int LSTORE_OP = 55; |
||||
public final static int FSTORE_OP = 56; |
||||
public final static int DSTORE_OP = 57; |
||||
public final static int ASTORE_OP = 58; |
||||
public final static int ISTORE_0_OP = 59; |
||||
public final static int ISTORE_1_OP = 60; |
||||
public final static int ISTORE_2_OP = 61; |
||||
public final static int ISTORE_3_OP = 62; |
||||
public final static int LSTORE_0_OP = 63; |
||||
public final static int LSTORE_1_OP = 64; |
||||
public final static int LSTORE_2_OP = 65; |
||||
public final static int LSTORE_3_OP = 66; |
||||
public final static int FSTORE_0_OP = 67; |
||||
public final static int FSTORE_1_OP = 68; |
||||
public final static int FSTORE_2_OP = 69; |
||||
public final static int FSTORE_3_OP = 70; |
||||
public final static int DSTORE_0_OP = 71; |
||||
public final static int DSTORE_1_OP = 72; |
||||
public final static int DSTORE_2_OP = 73; |
||||
public final static int DSTORE_3_OP = 74; |
||||
public final static int ASTORE_0_OP = 75; |
||||
public final static int ASTORE_1_OP = 76; |
||||
public final static int ASTORE_2_OP = 77; |
||||
public final static int ASTORE_3_OP = 78; |
||||
public final static int IASTORE_OP = 79; |
||||
public final static int LASTORE_OP = 80; |
||||
public final static int FASTORE_OP = 81; |
||||
public final static int DASTORE_OP = 82; |
||||
public final static int AASTORE_OP = 83; |
||||
public final static int BASTORE_OP = 84; |
||||
public final static int CASTORE_OP = 85; |
||||
public final static int SASTORE_OP = 86; |
||||
public final static int POP_OP = 87; |
||||
public final static int POP2_OP = 88; |
||||
public final static int DUP_OP = 89; |
||||
public final static int DUP_X1_OP = 90; |
||||
public final static int DUP_X2_OP = 91; |
||||
public final static int DUP2_OP = 92; |
||||
public final static int DUP2_X1_OP = 93; |
||||
public final static int DUP2_X2_OP = 94; |
||||
public final static int SWAP_OP = 95; |
||||
public final static int IADD_OP = 96; |
||||
public final static int LADD_OP = 97; |
||||
public final static int FADD_OP = 98; |
||||
public final static int DADD_OP = 99; |
||||
public final static int ISUB_OP = 100; |
||||
public final static int LSUB_OP = 101; |
||||
public final static int FSUB_OP = 102; |
||||
public final static int DSUB_OP = 103; |
||||
public final static int IMUL_OP = 104; |
||||
public final static int LMUL_OP = 105; |
||||
public final static int FMUL_OP = 106; |
||||
public final static int DMUL_OP = 107; |
||||
public final static int IDIV_OP = 108; |
||||
public final static int LDIV_OP = 109; |
||||
public final static int FDIV_OP = 110; |
||||
public final static int DDIV_OP = 111; |
||||
public final static int IREM_OP = 112; |
||||
public final static int LREM_OP = 113; |
||||
public final static int FREM_OP = 114; |
||||
public final static int DREM_OP = 115; |
||||
public final static int INEG_OP = 116; |
||||
public final static int LNEG_OP = 117; |
||||
public final static int FNEG_OP = 118; |
||||
public final static int DNEG_OP = 119; |
||||
public final static int ISHL_OP = 120; |
||||
public final static int LSHL_OP = 121; |
||||
public final static int ISHR_OP = 122; |
||||
public final static int LSHR_OP = 123; |
||||
public final static int IUSHR_OP = 124; |
||||
public final static int LUSHR_OP = 125; |
||||
public final static int IAND_OP = 126; |
||||
public final static int LAND_OP = 127; |
||||
public final static int IOR_OP = 128; |
||||
public final static int LOR_OP = 129; |
||||
public final static int IXOR_OP = 130; |
||||
public final static int LXOR_OP = 131; |
||||
public final static int IINC_OP = 132; |
||||
public final static int I2L_OP = 133; |
||||
public final static int I2F_OP = 134; |
||||
public final static int I2D_OP = 135; |
||||
public final static int L2I_OP = 136; |
||||
public final static int L2F_OP = 137; |
||||
public final static int L2D_OP = 138; |
||||
public final static int F2I_OP = 139; |
||||
public final static int F2L_OP = 140; |
||||
public final static int F2D_OP = 141; |
||||
public final static int D2I_OP = 142; |
||||
public final static int D2L_OP = 143; |
||||
public final static int D2F_OP = 144; |
||||
public final static int I2B_OP = 145; |
||||
public final static int I2C_OP = 146; |
||||
public final static int I2S_OP = 147; |
||||
public final static int LCMP_OP = 148; |
||||
public final static int FCMPL_OP = 149; |
||||
public final static int FCMPG_OP = 150; |
||||
public final static int DCMPL_OP = 151; |
||||
public final static int DCMPG_OP = 152; |
||||
public final static int IFEQ_OP = 153; |
||||
public final static int IFNE_OP = 154; |
||||
public final static int IFLT_OP = 155; |
||||
public final static int IFGE_OP = 156; |
||||
public final static int IFGT_OP = 157; |
||||
public final static int IFLE_OP = 158; |
||||
public final static int IF_ICMPEQ_OP = 159; |
||||
public final static int IF_ICMPNE_OP = 160; |
||||
public final static int IF_ICMPLT_OP = 161; |
||||
public final static int IF_ICMPGE_OP = 162; |
||||
public final static int IF_ICMPGT_OP = 163; |
||||
public final static int IF_ICMPLE_OP = 164; |
||||
public final static int IF_ACMPEQ_OP = 165; |
||||
public final static int IF_ACMPNE_OP = 166; |
||||
public final static int GOTO_OP = 167; |
||||
public final static int JSR_OP = 168; |
||||
public final static int RET_OP = 169; |
||||
public final static int TABLESWITCH_OP = 170; |
||||
public final static int LOOKUPSWITCH_OP = 171; |
||||
public final static int IRETURN_OP = 172; |
||||
public final static int LRETURN_OP = 173; |
||||
public final static int FRETURN_OP = 174; |
||||
public final static int DRETURN_OP = 175; |
||||
public final static int ARETURN_OP = 176; |
||||
public final static int RETURN_OP = 177; |
||||
public final static int GETSTATIC_OP = 178; |
||||
public final static int PUTSTATIC_OP = 179; |
||||
public final static int GETFIELD_OP = 180; |
||||
public final static int PUTFIELD_OP = 181; |
||||
public final static int INVOKEVIRTUAL_OP = 182; |
||||
public final static int INVOKESPECIAL_OP = 183; |
||||
public final static int INVOKESTATIC_OP = 184; |
||||
public final static int INVOKEINTERFACE_OP = 185; |
||||
public final static int NEW_OP = 187; |
||||
public final static int NEWARRAY_OP = 188; |
||||
public final static int ANEWARRAY_OP = 189; |
||||
public final static int ARRAYLENGTH_OP = 190; |
||||
public final static int ATHROW_OP = 191; |
||||
public final static int CHECKCAST_OP = 192; |
||||
public final static int INSTANCEOF_OP = 193; |
||||
public final static int MONITORENTER_OP = 194; |
||||
public final static int MONITOREXIT_OP = 195; |
||||
public final static int WIDE_OP = 196; |
||||
public final static int MULTIANEWARRAY_OP = 197; |
||||
public final static int IFNULL_OP = 198; |
||||
public final static int IFNONNULL_OP = 199; |
||||
public final static int GOTO_W_OP = 200; |
||||
public final static int JSR_W_OP = 201; |
||||
|
||||
public final static Type ALL_INT_TYPE = UnknownType.tUInt; |
||||
public final static Type INT_TYPE = Type.tInt; |
||||
public final static Type LONG_TYPE = Type.tLong; |
||||
public final static Type FLOAT_TYPE = Type.tFloat; |
||||
public final static Type DOUBLE_TYPE = Type.tDouble; |
||||
public final static Type OBJECT_TYPE = UnknownType.tUObject; |
||||
public final static Type BOOLEAN_TYPE = Type.tBoolean; |
||||
public final static Type BYTE_TYPE = Type.tByte; |
||||
public final static Type CHAR_TYPE = Type.tChar; |
||||
public final static Type SHORT_TYPE = Type.tShort; |
||||
|
||||
|
||||
public final static Type types[][] = { |
||||
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }, |
||||
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE, |
||||
BYTE_TYPE, CHAR_TYPE, SHORT_TYPE } |
||||
}; |
||||
} |
@ -0,0 +1,6 @@ |
||||
package jode; |
||||
|
||||
public interface Analyzer { |
||||
public void analyze(); |
||||
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException; |
||||
} |
@ -0,0 +1,75 @@ |
||||
package jode; |
||||
import java.lang.reflect.Modifier; |
||||
import java.io.IOException; |
||||
import sun.tools.java.*; |
||||
|
||||
public class ClassAnalyzer implements Analyzer { |
||||
BinaryClass cdef; |
||||
JodeEnvironment env; |
||||
Analyzer fields[]; |
||||
|
||||
public ClassAnalyzer(BinaryClass bc, JodeEnvironment e) |
||||
{ |
||||
cdef = bc; |
||||
env = e; |
||||
} |
||||
|
||||
public void analyze() { |
||||
int numFields = 0, i=0; |
||||
|
||||
FieldDefinition f; |
||||
for (f= cdef.getInnerClassField(); f != null; f = f.getNextField()) |
||||
numFields++; |
||||
for (f= cdef.getFirstField(); f != null; f = f.getNextField()) |
||||
numFields++; |
||||
fields = new Analyzer[numFields]; |
||||
for (f= cdef.getInnerClassField(); f != null; f = f.getNextField()) { |
||||
System.err.println("analyzing inner: "+f.getName()); |
||||
fields[i] = new ClassAnalyzer((BinaryClass) f.getInnerClass(), env); |
||||
fields[i++].analyze(); |
||||
} |
||||
for (f= cdef.getFirstField(); f != null; f = f.getNextField()) { |
||||
if (f.getType().getTypeCode() == Constants.TC_METHOD) { |
||||
System.err.println("analyzing method: "+f.getName()); |
||||
fields[i] = new MethodAnalyzer(f, env); |
||||
} else { |
||||
System.err.println("analyzing field: "+f.getName()); |
||||
fields[i] = new FieldAnalyzer(f, env); |
||||
} |
||||
fields[i++].analyze(); |
||||
} |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer) throws IOException |
||||
{ |
||||
if (cdef.getSource() != null) |
||||
writer.println("/* Original source: "+cdef.getSource()+" */"); |
||||
String modif = Modifier.toString(cdef.getModifiers()); |
||||
if (modif.length() > 0) |
||||
writer.print(modif + " "); |
||||
writer.print((cdef.isInterface())?"interface ":"class "); |
||||
writer.println(env.getNickName(cdef.getName().toString())); |
||||
writer.tab(); |
||||
if (cdef.getSuperClass() != null) |
||||
writer.println("extends "+cdef.getSuperClass().getName().toString()); |
||||
ClassDeclaration interfaces[] = cdef.getInterfaces(); |
||||
if (interfaces.length > 0) { |
||||
writer.print("implements "); |
||||
for (int i=0; i < interfaces.length; i++) { |
||||
if (i > 0) |
||||
writer.print(", "); |
||||
writer.print(interfaces[i].getName().toString()); |
||||
} |
||||
} |
||||
writer.untab(); |
||||
writer.println(" {"); |
||||
writer.tab(); |
||||
|
||||
for (int i=0; i< fields.length; i++) |
||||
fields[i].dumpSource(writer); |
||||
writer.untab(); |
||||
writer.println("}"); |
||||
} |
||||
} |
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,37 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
import java.lang.reflect.Modifier; |
||||
|
||||
public class FieldAnalyzer implements Analyzer { |
||||
FieldDefinition fdef; |
||||
JodeEnvironment env; |
||||
|
||||
public FieldAnalyzer(FieldDefinition fd, JodeEnvironment e) |
||||
{ |
||||
fdef = fd; |
||||
env = e; |
||||
} |
||||
|
||||
public void analyze() { |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer) |
||||
throws java.io.IOException |
||||
{ |
||||
String modif = Modifier.toString(fdef.getModifiers()); |
||||
if (modif.length() > 0) |
||||
writer.print(modif+" "); |
||||
|
||||
writer.println(fdef.getType(). |
||||
typeString(fdef.getName().toString(), false, false)+";"); |
||||
// writer.tab();
|
||||
// if (attributes.length > 0) {
|
||||
// writer.println("/* Attributes: "+attributes.length+" */");
|
||||
// for (int i=0; i < attributes.length; i++)
|
||||
// attributes[i].dumpSource(writer);
|
||||
// }
|
||||
// writer.untab();
|
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,96 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
import sun.tools.util.*; |
||||
import java.util.*; |
||||
|
||||
public class JodeEnvironment extends LoadEnvironment { |
||||
Hashtable imports = new Hashtable(); |
||||
BinaryClass main; |
||||
Identifier pkg; |
||||
|
||||
boolean isVerbose = true; |
||||
|
||||
JodeEnvironment() { |
||||
super(null); |
||||
path = new ClassPath(System.getProperty("java.class.path")); |
||||
} |
||||
|
||||
public BinaryConstantPool getConstantPool() { |
||||
return main.getConstants(); |
||||
} |
||||
|
||||
public Object getConstant(int i) { |
||||
return main.getConstants().getConstant(i, this); |
||||
} |
||||
|
||||
public Type getConstantType(int i) |
||||
throws ClassFormatError |
||||
{ |
||||
int t = main.getConstants().getConstantType(i); |
||||
switch(t) { |
||||
case 3: return Type.tInt ; |
||||
case 4: return Type.tFloat ; |
||||
case 5: return Type.tLong ; |
||||
case 6: return Type.tDouble; |
||||
case 8: return Type.tString; |
||||
default: |
||||
throw new ClassFormatError("invalid constant type: "+t); |
||||
} |
||||
} |
||||
|
||||
public String getNickName(String string) { |
||||
return string; |
||||
} |
||||
|
||||
public ClassDefinition getClassDefinition() { |
||||
return main; |
||||
} |
||||
|
||||
public void dumpHeader(TabbedPrintWriter writer) |
||||
throws java.io.IOException |
||||
{ |
||||
writer.println("/* Decompiled by JoDe (Jochen's Decompiler) */"); |
||||
if (pkg != null && pkg != Constants.idNull) |
||||
writer.println("package "+pkg+";"); |
||||
Enumeration enum = imports.keys(); |
||||
while (enum.hasMoreElements()) { |
||||
Identifier packageName = (Identifier) enum.nextElement(); |
||||
Integer vote = (Integer) imports.get(packageName); |
||||
if (vote.intValue() > 3) |
||||
writer.println("import "+packageName+";"); |
||||
} |
||||
writer.println(""); |
||||
} |
||||
|
||||
public void error(String message) { |
||||
System.err.println(message); |
||||
} |
||||
|
||||
public void doClass(String className) |
||||
{ |
||||
try { |
||||
Identifier ident = Identifier.lookup(className); |
||||
error(ident.toString()); |
||||
if (!classExists(ident)) { |
||||
error("`"+ident+"' not found"); |
||||
return; |
||||
} |
||||
pkg = ident.getQualifier(); |
||||
main = (BinaryClass)getClassDefinition(ident); |
||||
ClassAnalyzer a = new ClassAnalyzer(main, this); |
||||
a.analyze(); |
||||
TabbedPrintWriter writer = |
||||
new TabbedPrintWriter(System.out, " "); |
||||
a.dumpSource(writer); |
||||
} catch (ClassNotFound e) { |
||||
error(e.toString()); |
||||
} catch (java.io.IOException e) { |
||||
error(e.toString()); |
||||
} |
||||
} |
||||
|
||||
protected int loadFileFlags() |
||||
{ |
||||
return 1; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class LocalInfo { |
||||
static int serialnr = 0; |
||||
Identifier name; |
||||
Type type; |
||||
|
||||
public LocalInfo() { |
||||
name = Identifier.lookup("__"+serialnr); |
||||
type = Type.tUnknown; |
||||
serialnr++; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,10 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
import sun.tools.java.Identifier; |
||||
|
||||
public interface LocalVariable { |
||||
public Identifier getName(int addr); |
||||
public Type getType(int addr); |
||||
public Type setType(int addr, Type type); |
||||
public void combine(int addr1, int addr2); |
||||
} |
@ -0,0 +1,44 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
import sun.tools.java.Identifier; |
||||
|
||||
public class LocalVariableHash implements LocalVariable { |
||||
Hashtable locals; |
||||
|
||||
private find(int addr) { |
||||
LocalInfo li = (LocalInfo) locals.get(new Integer(addr)); |
||||
if (li == null) { |
||||
li = new LocalInfo(); |
||||
locals.put(new Integer(addr), li); |
||||
} |
||||
return li; |
||||
} |
||||
|
||||
public Identifier getName(int addr) { |
||||
LocalInfo li = find(addr); |
||||
return li.name; |
||||
} |
||||
|
||||
public Type getType(int addr) { |
||||
LocalInfo li = find(addr); |
||||
return li.type; |
||||
} |
||||
|
||||
public Type setType(int addr, Type type) { |
||||
LocalInfo li = find(addr); |
||||
li.type = UnknownType.commonType(li.type, type); |
||||
return li.type; |
||||
} |
||||
|
||||
public void combine(int addr1, int addr2) { |
||||
LocalInfo li1 = find(addr1); |
||||
LocalInfo li2 = find(addr2); |
||||
li1.type = UnknownType.commonType(li1.type, li2.type); |
||||
Enumeration keys = locals.keys(); |
||||
while (keys.hasMoreElements()) { |
||||
Object key = keys.nextElement(); |
||||
if (locals.get(key) == li2) |
||||
locals.put(key, li1); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,82 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class LocalVariableRangeList implements LocalVariable { |
||||
|
||||
class MyLocalInfo extends LocalInfo { |
||||
int start; |
||||
int length; |
||||
MyLocalInfo next; |
||||
|
||||
MyLocalInfo(int s, int l, Identifier n, Type t) { |
||||
start = s; |
||||
length = l; |
||||
name = n; |
||||
type = t; |
||||
next = null; |
||||
} |
||||
} |
||||
|
||||
MyLocalInfo list = null; |
||||
int slot; |
||||
|
||||
LocalVariableRangeList(int slot) { |
||||
this.slot = slot; |
||||
} |
||||
|
||||
private void add(MyLocalInfo li) { |
||||
MyLocalInfo before = null; |
||||
MyLocalInfo after = list; |
||||
while (after != null && after.start < li.start) { |
||||
before = after; |
||||
after = after.next; |
||||
} |
||||
if (after != null && li.start + li.length > after.start) |
||||
throw new AssertError("non disjoint locals"); |
||||
li.next = after; |
||||
if (before == null) |
||||
list = li; |
||||
else |
||||
before.next = li; |
||||
} |
||||
|
||||
private LocalInfo find(int addr) { |
||||
MyLocalInfo li = list; |
||||
while (li != null && addr > li.start+li.length) |
||||
li = li.next; |
||||
if (li == null || li.start > addr) { |
||||
LocalInfo temp =new LocalInfo(); |
||||
return temp; |
||||
} |
||||
return li; |
||||
} |
||||
|
||||
public void addLocal(int start, int length, |
||||
Identifier name, Type type) { |
||||
MyLocalInfo li = new MyLocalInfo(start,length,name,type); |
||||
add (li); |
||||
} |
||||
|
||||
public Identifier getName(int addr) { |
||||
LocalInfo li = find(addr); |
||||
return li.name; |
||||
} |
||||
|
||||
public Type getType(int addr) { |
||||
LocalInfo li = find(addr); |
||||
return li.type; |
||||
} |
||||
|
||||
public LocalInfo getInfo(int addr) { |
||||
return find(addr); |
||||
} |
||||
|
||||
public Type setType(int addr, Type newType) { |
||||
LocalInfo li = find(addr); |
||||
return commonType(newType, li.type); |
||||
} |
||||
|
||||
public void combine(int addr1, int addr2) { |
||||
throw AssertError("combine called on RangeList"); |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
import java.io.*; |
||||
import java.util.Vector; |
||||
|
||||
public class LocalVariableTable { |
||||
Vector locals; |
||||
boolean readfromclass; |
||||
|
||||
public LocalVariableTable(int size) { |
||||
locals = new Vector(); |
||||
locals.setSize(size); |
||||
readfromclass = false; |
||||
} |
||||
|
||||
public boolean isReadFromClass() { |
||||
return readfromclass; |
||||
} |
||||
|
||||
public void read(JodeEnvironment env, DataInputStream stream) |
||||
throws IOException |
||||
{ |
||||
int count = stream.readUnsignedShort(); |
||||
for (int i=0; i<count; i++) { |
||||
int start = stream.readUnsignedShort(); |
||||
int length = stream.readUnsignedShort(); |
||||
int name_i = stream.readUnsignedShort(); |
||||
int desc_i = stream.readUnsignedShort(); |
||||
int slot = stream.readUnsignedShort(); |
||||
LocalVariableRangeList lv = |
||||
(LocalVariableRangeList)locals.elementAt(slot); |
||||
if (lv == null) { |
||||
lv = new LocalVariableRangeList(slot); |
||||
locals.setElementAt(lv, slot); |
||||
} |
||||
lv.addLocal(start, length, |
||||
Identifier.lookup((String) |
||||
env.getConstantPool(). |
||||
getValue(name_i)), |
||||
env.getConstantPool().getType(desc_i)); |
||||
} |
||||
readfromclass = true; |
||||
} |
||||
|
||||
public LocalVariable getLocal(int slot) |
||||
throws ArrayOutOfBoundsException |
||||
{ |
||||
LocalVariable lv = (LocalVariable)locals.elementAt(slot); |
||||
if (lv == null) { |
||||
lv = new LocalVariable(slot); |
||||
locals.setElementAt(lv, slot); |
||||
} |
||||
return lv; |
||||
} |
||||
} |
@ -0,0 +1,135 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
import java.lang.reflect.Modifier; |
||||
import java.io.*; |
||||
|
||||
public class MethodAnalyzer implements Analyzer, Constants { |
||||
FieldDefinition mdef; |
||||
JodeEnvironment env; |
||||
CodeAnalyzer code = null; |
||||
LocalVariableTable lvt; |
||||
|
||||
public MethodAnalyzer(FieldDefinition fd, JodeEnvironment e) |
||||
{ |
||||
mdef = fd; |
||||
env = e; |
||||
byte bytecode[] = ((BinaryField) mdef).getAttribute(Constants.idCode); |
||||
if (bytecode != null) { |
||||
BinaryCode bc = |
||||
new BinaryCode(bytecode, |
||||
env.getConstantPool(), |
||||
env); |
||||
lvt = new LocalVariableTable(bc.getMaxLocals()); |
||||
readLVT(bc); |
||||
code = new CodeAnalyzer(this, bc, env); |
||||
} |
||||
} |
||||
|
||||
public void readLVT(BinaryCode bc) { |
||||
BinaryAttribute attr = bc.getAttributes(); |
||||
while (attr != null) { |
||||
if (attr.getName() == idLocalVariableTable) { |
||||
DataInputStream stream = |
||||
new DataInputStream |
||||
(new ByteArrayInputStream(attr.getData())); |
||||
try { |
||||
lvt.read(env, stream); |
||||
} catch (IOException ex) { |
||||
throw new ClassFormatError(ex.toString()); |
||||
} |
||||
} |
||||
attr = attr.getNextAttribute(); |
||||
} |
||||
if (!lvt.isReadFromClass()) { |
||||
int offset = 0; |
||||
if (!mdef.isStatic()) { |
||||
LocalInfo li = lvt.getLocal(0); |
||||
li.name = "this"; |
||||
li.type = mdef.getClassDefinition().getType(); |
||||
offset++; |
||||
} |
||||
Type[] paramTypes = mdef.getType().getArgumentTypes(); |
||||
for (int i=0; i< paramTypes.length; i++) { |
||||
LocalInfo li = lvt.getLocal(offset+i); |
||||
li.type = paramTypes[i]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void analyze() |
||||
throws ClassFormatError |
||||
{ |
||||
code.analyze(); |
||||
} |
||||
|
||||
public LocalVariable getLocal(int i) { |
||||
return lvt.getLocal(i); |
||||
} |
||||
|
||||
public Identifier getLocalName(int i, int addr) { |
||||
Identifier name = lvt.getLocal(i).getName(addr); |
||||
if (name != null) |
||||
return name; |
||||
if (!mdef.isStatic() && i == 0) |
||||
return idThis; |
||||
return Identifier.lookup("local_"+i+"@"+addr); |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer) |
||||
throws java.io.IOException |
||||
{ |
||||
writer.println(""); |
||||
String modif = Modifier.toString(mdef.getModifiers()); |
||||
if (modif.length() > 0) |
||||
writer.print(modif+" "); |
||||
if (mdef.isInitializer()) { |
||||
writer.print(""); /* static block */ |
||||
} else { |
||||
if (mdef.isConstructor()) |
||||
writer.print(mdef.getClassDeclaration().getName().toString()); |
||||
else |
||||
writer.print(mdef.getType().getReturnType().toString()+" "+ |
||||
mdef.getName().toString()); |
||||
writer.print("("); |
||||
Type[] paramTypes = mdef.getType().getArgumentTypes(); |
||||
int offset = mdef.isStatic()?0:1; |
||||
for (int i=0; i<paramTypes.length; i++) { |
||||
if (i>0) |
||||
writer.print(", "); |
||||
writer.print(paramTypes[i]. |
||||
typeString(getLocalName(i+offset, 0).toString(), |
||||
false, false)); |
||||
} |
||||
writer.print(")"); |
||||
} |
||||
IdentifierToken[] exceptions = mdef.getExceptionIds(); |
||||
if (exceptions != null && exceptions.length > 0) { |
||||
writer.println(""); |
||||
writer.print("throws "); |
||||
for (int i= 0; i< exceptions.length; i++) { |
||||
if (exceptions[i] != null) { |
||||
if (i > 0) |
||||
writer.print(", "); |
||||
writer.print(exceptions[i].getName().toString()); |
||||
} |
||||
} |
||||
} |
||||
if (code != null) { |
||||
writer.println(" {"); |
||||
writer.tab(); |
||||
code.dumpSource(writer); |
||||
writer.untab(); |
||||
writer.println("}"); |
||||
} else |
||||
writer.println(";"); |
||||
} |
||||
|
||||
/* |
||||
public byte[] getAttribute(Identifier identifier) |
||||
{ |
||||
if (mdef instanceof BinaryField) |
||||
return ((BinaryField)mdef).getAttribute(identifier); |
||||
return null; |
||||
} |
||||
*/ |
||||
} |
@ -0,0 +1,42 @@ |
||||
package jode; |
||||
import java.io.*; |
||||
|
||||
public class TabbedPrintWriter { |
||||
boolean atbol; |
||||
String tabstr; |
||||
StringBuffer indent; |
||||
PrintWriter pw; |
||||
int verbosity=100; |
||||
|
||||
public TabbedPrintWriter (OutputStream os, String tabstr) { |
||||
pw = new PrintWriter(os); |
||||
this.tabstr=tabstr; |
||||
indent = new StringBuffer(); |
||||
atbol = true; |
||||
} |
||||
|
||||
public void tab() { |
||||
indent.append(tabstr); |
||||
} |
||||
|
||||
public void untab() { |
||||
indent.setLength(indent.length()-tabstr.length()); |
||||
} |
||||
|
||||
public void println(String str) throws java.io.IOException { |
||||
if (atbol) { |
||||
pw.print(indent); |
||||
} |
||||
pw.println(str); |
||||
pw.flush(); |
||||
atbol = true; |
||||
} |
||||
|
||||
public void print(String str) throws java.io.IOException { |
||||
if (atbol) { |
||||
pw.print(indent); |
||||
} |
||||
pw.print(str); |
||||
atbol = false; |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class ArrayLengthOperator extends Operator { |
||||
|
||||
Type arrayType; |
||||
|
||||
public ArrayLengthOperator(int addr, int length) { |
||||
super(addr,length, Type.tInt, 0); |
||||
arrayType = Type.tArray(UnknownType.tUnknown); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 1; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 900; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return arrayType; |
||||
} |
||||
|
||||
public void setOperandType(Type[] types) { |
||||
arrayType = UnknownType.commonType(arrayType,types[0]); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + ".length"; |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
import sun.tools.java.ArrayType; |
||||
|
||||
public class ArrayLoadOperator extends SimpleOperator { |
||||
String value; |
||||
|
||||
public ArrayLoadOperator(int addr, int length, Type type) { |
||||
super(addr,length, type, 0, 2); |
||||
operandTypes[0] = Type.tArray(type); |
||||
operandTypes[1] = UnknownType.tUIndex; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return (i==0)?950:0; |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type type) { |
||||
if (type != this.type) { |
||||
super.setType(type); |
||||
operandTypes[0] = Type.tArray(type); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public void setOperandType(Type[] t) { |
||||
super.setOperandType(t); |
||||
if (operandTypes[0] instanceof ArrayType) |
||||
type = operandTypes[0].getElementType(); |
||||
else |
||||
type = Type.tError; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0]+"["+operands[1]+"]"; |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
import sun.tools.java.ArrayType; |
||||
|
||||
public class ArrayStoreOperator extends StoreInstruction { |
||||
Type indexType; |
||||
|
||||
public ArrayStoreOperator(int addr, int length, Type type) { |
||||
super(addr,length, type); |
||||
indexType = UnknownType.tUIndex; |
||||
} |
||||
|
||||
public ArrayStoreOperator(int addr, int length, Type type, int operator) { |
||||
super(addr,length, type, operator); |
||||
indexType = UnknownType.tUIndex; |
||||
} |
||||
|
||||
public boolean matches(Operator loadop) { |
||||
return loadop instanceof ArrayLoadOperator; |
||||
} |
||||
|
||||
public int getLValueOperandCount() { |
||||
return 2; |
||||
} |
||||
|
||||
public int getLValueOperandPriority(int i) { |
||||
if (i == 0) |
||||
return 950; |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
public Type getLValueOperandType(int i) { |
||||
if (i == 0) |
||||
return Type.tArray(lvalueType); |
||||
else |
||||
return indexType; |
||||
} |
||||
|
||||
public void setLValueOperandType(Type[] t) { |
||||
indexType = UnknownType.commonType(indexType, t[1]); |
||||
Type arraytype = |
||||
UnknownType.commonType(t[0], Type.tArray(lvalueType)); |
||||
System.err.println("lvot: "+t[0]+","+Type.tArray(lvalueType)+ |
||||
" -> "+arraytype); |
||||
if (arraytype instanceof ArrayType) |
||||
lvalueType = arraytype.getElementType(); |
||||
else { |
||||
System.err.println("no array: "+arraytype); |
||||
lvalueType = Type.tError; |
||||
} |
||||
} |
||||
|
||||
public String getLValueString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0]+"["+operands[1]+"]"; |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class AssignOperator extends BinaryOperator { |
||||
StoreInstruction store; |
||||
|
||||
public AssignOperator(int addr, int length, int op, |
||||
StoreInstruction store) { |
||||
super(addr,length, store.getLValueType(), op); |
||||
this.store = store; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return store.getOperandCount(); |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return store.getOperandPriority(i); |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return store.getOperandType(i); |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type type) { |
||||
boolean result = store.setLValueType(type); |
||||
super.setType(store.getLValueType()); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Overload this method if the resulting type depends on the input types |
||||
*/ |
||||
public void setOperandType(Type[] inputTypes) { |
||||
store.setOperandType(inputTypes); |
||||
this.type = store.getLValueType(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return store.toString(ca, operands); |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class BinaryOperator extends Operator { |
||||
protected Type operandType; |
||||
|
||||
public BinaryOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, type, op); |
||||
operandType = type; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 2; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
switch (operator) { |
||||
case 1: case 2: |
||||
return 610; |
||||
case 3: case 4: case 5: |
||||
return 650; |
||||
case 6: case 7: case 8: |
||||
return 600; |
||||
case 9: |
||||
return 450; |
||||
case 10: |
||||
return 410; |
||||
case 11: |
||||
return 420; |
||||
case 12: case 13: case 14: case 15: case 16: case 17: |
||||
case 18: case 19: case 20: case 21: case 22: case 23: |
||||
return 100; |
||||
case LOG_OR_OP: |
||||
return 310; |
||||
case LOG_AND_OP: |
||||
return 350; |
||||
} |
||||
throw new RuntimeException("Illegal operator"); |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority() + i; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return operandType; |
||||
} |
||||
|
||||
public void setOperandType(Type[] inputTypes) { |
||||
operandType = UnknownType.commonType |
||||
(operandType, UnknownType.commonType(inputTypes[0], |
||||
inputTypes[1])); |
||||
type = operandType; |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type newType) { |
||||
operandType = UnknownType.commonType(operandType, newType); |
||||
if (type != operandType) { |
||||
type = operandType; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + " "+getOperatorString()+" "+ operands[1]; |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class CheckCastOperator extends SimpleOperator { |
||||
public CheckCastOperator(int addr, int length, Type type) { |
||||
super(addr,length, type, 0, 1); |
||||
operandTypes[0] = UnknownType.tSubClass(type); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 700; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "("+ca.getTypeString(type) + ")" + operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class CompareBinaryOperator extends SimpleOperator { |
||||
public CompareBinaryOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, Type.tBoolean, op, 2); |
||||
operandTypes[0] = operandTypes[1] = type; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
switch (getOperator()) { |
||||
case 26: |
||||
case 27: |
||||
return 500; |
||||
case 28: |
||||
case 29: |
||||
case 30: |
||||
case 31: |
||||
return 550; |
||||
} |
||||
throw new RuntimeException("Illegal operator"); |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority()+i; |
||||
} |
||||
|
||||
public void setOperandType(Type[] inputTypes) { |
||||
super.setOperandType(inputTypes); |
||||
Type operandType = |
||||
UnknownType.commonType(operandTypes[0],operandTypes[1]); |
||||
operandTypes[0] = operandTypes[1] = operandType; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + " "+opString[operator]+" "+operands[1]; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class CompareToIntOperator extends BinaryOperator { |
||||
public CompareToIntOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, Type.tInt, op); |
||||
operandType = type; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
switch (getOperator()) { |
||||
case 25: |
||||
case 26: |
||||
return 500; |
||||
case 27: |
||||
case 28: |
||||
case 29: |
||||
case 30: |
||||
return 550; |
||||
} |
||||
throw new RuntimeException("Illegal operator"); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + " "+opString[operator]+" "+operands[1]; |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class CompareUnaryOperator extends SimpleOperator { |
||||
public CompareUnaryOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, Type.tBoolean, op, 1); |
||||
operandTypes[0] = type; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
switch (getOperator()) { |
||||
case 26: |
||||
case 27: |
||||
return 500; |
||||
case 28: |
||||
case 29: |
||||
case 30: |
||||
case 31: |
||||
return 550; |
||||
} |
||||
throw new RuntimeException("Illegal operator"); |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
if (operandTypes[0] == Type.tBoolean) { |
||||
if (operator == 26) /* xx == false */ |
||||
return "! ("+operands[0]+")"; /*XXX Make operators */ |
||||
else if (operator == 27) /* xx != false */ |
||||
return operands[0]; |
||||
} |
||||
return operands[0] + " "+opString[operator]+" "+ |
||||
(UnknownType.isOfType(operandTypes[0], |
||||
UnknownType.tObject)?"null":"0"); |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class ConstOperator extends NoArgOperator { |
||||
String value; |
||||
|
||||
public ConstOperator(int addr, int length, Type type, String value) { |
||||
super(addr, length, type); |
||||
this.value = value; |
||||
} |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 1000; |
||||
} |
||||
|
||||
public String quoted(String str) { |
||||
StringBuffer result = new StringBuffer("\""); |
||||
for (int i=0; i< value.length(); i++) { |
||||
switch (value.charAt(i)) { |
||||
case '\t': |
||||
result.append("\\t"); |
||||
break; |
||||
case '\n': |
||||
result.append("\\n"); |
||||
break; |
||||
case '\\': |
||||
result.append("\\\\"); |
||||
break; |
||||
case '\"': |
||||
result.append("\\\""); |
||||
break; |
||||
default: |
||||
result.append(value.charAt(i)); |
||||
} |
||||
} |
||||
return result.append("\"").toString(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
if (type == Type.tString) |
||||
return quoted(value); |
||||
if (type == Type.tBoolean) { |
||||
if (value.equals("0")) |
||||
return "false"; |
||||
else if (value.equals("1")) |
||||
return "true"; |
||||
} |
||||
return value; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,45 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class ConstructorOperator extends Operator { |
||||
FieldDefinition field; |
||||
|
||||
public ConstructorOperator(int addr, int length, Type type, |
||||
FieldDefinition field) { |
||||
super(addr,length, type, 0); |
||||
this.field = field; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 1 + field.getType().getArgumentTypes().length; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
if (i == 0) |
||||
return 950; |
||||
return 0; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
if (i == 0) |
||||
return type; |
||||
return field.getType().getArgumentTypes()[i-1]; |
||||
} |
||||
|
||||
public void setOperandType(Type types[]) { |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
StringBuffer result = new StringBuffer(operands[0]).append("("); |
||||
for (int i=0; i < field.getType().getArgumentTypes().length; i++) { |
||||
if (i>0) |
||||
result.append(", "); |
||||
result.append(operands[i+1]); |
||||
} |
||||
return result.append(")").toString(); |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class ConvertOperator extends Operator { |
||||
Type from; |
||||
|
||||
public ConvertOperator(int addr, int length, Type from, Type to) { |
||||
super(addr,length, to, 0); |
||||
this.from = from; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 700; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 700; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 1; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return from; |
||||
} |
||||
|
||||
public void setOperandType(Type[] inputTypes) { |
||||
from = UnknownType.commonType(from, inputTypes[0]); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) |
||||
{ |
||||
return "("+ca.getTypeString(type)+") "+operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
package jode; |
||||
|
||||
public class DupOperator extends Instruction { |
||||
int count, depth; |
||||
|
||||
public DupOperator(int a, int l, int depth, int count) { |
||||
super(a,l); |
||||
this.count = count; |
||||
this.depth = depth; |
||||
} |
||||
|
||||
public int getCount(){ |
||||
return count; |
||||
} |
||||
|
||||
public int getDepth(){ |
||||
return depth; |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter tpw, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
tpw.println("dup"+count+"_x"+depth+";"); |
||||
} |
||||
} |
@ -0,0 +1,128 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class Expression extends Instruction { |
||||
Operator operator; |
||||
Expression[] subExpressions; |
||||
|
||||
protected Expression(int addr, int length) { |
||||
super(addr, length); |
||||
} |
||||
|
||||
public Expression(int addr, int length, Operator op, Expression[] sub) { |
||||
super(addr, length); |
||||
operator = op; |
||||
subExpressions = sub; |
||||
if (op.getOperandCount() > 0) { |
||||
Type types[] = new Type[subExpressions.length]; |
||||
for (int i=0; i < types.length; i++) { |
||||
types[i] = subExpressions[i].getType(); |
||||
} |
||||
operator.setOperandType(types); |
||||
updateSubTypes(); |
||||
} |
||||
} |
||||
|
||||
public Expression negate() { |
||||
if (operator.operator >= operator.COMPARE_OP && |
||||
operator.operator < operator.COMPARE_OP+6) { |
||||
operator.setOperator(operator.getOperator() ^ 1); |
||||
return this; |
||||
} else if (operator.operator == operator.LOG_AND_OP || |
||||
operator.operator == operator.LOG_OR_OP) { |
||||
operator.setOperator(operator.getOperator() ^ 1); |
||||
for (int i=0; i< subExpressions.length; i++) { |
||||
subExpressions[i] = subExpressions[i].negate(); |
||||
} |
||||
return this; |
||||
} else if (operator.operator == operator.LOG_NOT_OP) { |
||||
return subExpressions[0]; |
||||
} |
||||
|
||||
Operator negop = |
||||
new UnaryOperator(getAddr(), getLength(), |
||||
Type.tBoolean, Operator.LOG_NOT_OP); |
||||
Expression[] e = { this }; |
||||
return new Expression(getAddr(), getLength(), negop, e); |
||||
} |
||||
|
||||
public Operator getOperator() { |
||||
return operator; |
||||
} |
||||
|
||||
public Expression[] getSubExpressions() { |
||||
return subExpressions; |
||||
} |
||||
|
||||
public Type getType() { |
||||
return operator.getType(); |
||||
} |
||||
|
||||
public void updateSubTypes() { |
||||
for (int i=0; i < subExpressions.length; i++) { |
||||
subExpressions[i].setType(operator.getOperandType(i)); |
||||
} |
||||
} |
||||
|
||||
public void setType(Type type) { |
||||
if (operator.setType(type)) |
||||
updateSubTypes(); |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
return operator.getSuccessors(); |
||||
} |
||||
|
||||
public boolean isVoid() { |
||||
return operator.getType() == Type.tVoid; |
||||
} |
||||
|
||||
String toString(CodeAnalyzer ca, int minPriority) { |
||||
String[] expr = new String[subExpressions.length]; |
||||
for (int i=0; i<subExpressions.length; i++) { |
||||
expr[i] = subExpressions[i]. |
||||
toString(ca, operator.getOperandPriority(i)); |
||||
} |
||||
String result = operator.toString(ca, expr); |
||||
if (operator.getPriority() < minPriority) { |
||||
result = "("+result+")"; |
||||
} |
||||
if (operator.casts.indexOf("/*",0) >= 0 || |
||||
operator.casts.indexOf("<-",0) >= 0 && false) |
||||
result = "<"+operator.casts+" "+result+">"; |
||||
return result; |
||||
} |
||||
|
||||
public boolean equals(Expression expr) { |
||||
if (this == expr) |
||||
return true; |
||||
if (!operator.equals(expr.operator) || |
||||
subExpressions.length != expr.subExpressions.length) |
||||
return false; |
||||
for (int i=0; i<subExpressions.length; i++) { |
||||
if (subExpressions[i] != expr.subExpressions[i]) |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
if (writer.verbosity > 6) { |
||||
writer.print("< "+ |
||||
ca.getTypeString(operator.getType())+" "+ |
||||
operator.getClass().getName()+"("); |
||||
for (int i=0; i< subExpressions.length; i++) { |
||||
if (i>0) |
||||
writer.print(", "); |
||||
writer.print("("+ca.getTypeString(operator.getOperandType(i))+ |
||||
") "+ca.getTypeString(subExpressions[i].getType())); |
||||
} |
||||
writer.println(") >"); |
||||
} |
||||
if (!isVoid()) |
||||
writer.print("push "); |
||||
writer.println(toString(ca, 0)+";"); |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class GetFieldOperator extends Operator { |
||||
boolean staticFlag; |
||||
FieldDefinition field; |
||||
|
||||
public GetFieldOperator(int addr, int length, boolean staticFlag, |
||||
FieldDefinition field) { |
||||
super(addr, length, field.getType(), 0); |
||||
this.staticFlag = staticFlag; |
||||
this.field = field; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return staticFlag?0:1; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
if (staticFlag) { |
||||
/* shouldn't be called */ |
||||
throw new RuntimeException("Field is static"); |
||||
} |
||||
return 900; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
if (staticFlag) { |
||||
/* shouldn't be called */ |
||||
throw new RuntimeException("Field is static"); |
||||
} |
||||
return field.getClassDeclaration().getType(); |
||||
} |
||||
|
||||
public void setOperandType(Type types[]) { |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
String object; |
||||
if (staticFlag) { |
||||
if (field.getClassDefinition() == ca.getClassDefinition()) |
||||
return field.getName().toString(); |
||||
object = |
||||
ca.getTypeString(field.getClassDeclaration().getType()); |
||||
} else { |
||||
if (operands[0].equals("this")) |
||||
return field.getName().toString(); |
||||
object = operands[0]; |
||||
} |
||||
return object + "." + field.getName(); |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class GotoOperator extends JumpInstruction { |
||||
protected int destination; |
||||
|
||||
public GotoOperator(int addr, int length, int dest) { |
||||
super(addr,length); |
||||
this.destination = dest; |
||||
} |
||||
|
||||
public int getDestination() { |
||||
return destination; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
throw new AssertError("This operator has no operands"); |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
throw new AssertError("This operator has no operands"); |
||||
} |
||||
|
||||
public void setOperandType(Type types[]) { |
||||
throw new AssertError("This operator has no operands"); |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
int [] result = { destination }; |
||||
return result; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "goto addr_" + destination; |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class IfGotoOperator extends JumpInstruction { |
||||
protected int destination; |
||||
|
||||
public IfGotoOperator(int addr, int length, int dest) { |
||||
super(addr,length); |
||||
destination = dest; |
||||
} |
||||
|
||||
public int getDestination() { |
||||
return destination; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 1; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 200; /* force parentheses around assignments */ |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return Type.tBoolean; |
||||
} |
||||
|
||||
public void setOperandType(Type types[]) { |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
int [] result = { destination, getAddr() + getLength() }; |
||||
return result; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "if ("+operands[0]+") goto addr_" + destination; |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class IfThenElseOperator extends SimpleOperator { |
||||
public IfThenElseOperator(int addr, int length, Type type) { |
||||
super(addr,length, type, 0, 3); |
||||
operandTypes[0] = Type.tBoolean; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 3; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 200; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
switch (i) { |
||||
case 0: |
||||
return 201; |
||||
case 1: |
||||
return 0; |
||||
case 2: |
||||
return 200; |
||||
default: |
||||
throw new AssertError("ifthenelse with operand "+i); |
||||
} |
||||
} |
||||
|
||||
public void setOperandType(Type[] inputTypes) { |
||||
super.setOperandType(inputTypes); |
||||
Type operandType = |
||||
UnknownType.commonType(operandTypes[1],operandTypes[2]); |
||||
type = operandTypes[1] = operandTypes[2] = operandType; |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type newType) { |
||||
Type operandType = |
||||
UnknownType.commonType(operandTypes[1], newType); |
||||
if (type != operandType) { |
||||
type = operandTypes[1] = operandTypes[2] = operandType; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + " ? "+operands[1]+" : "+ operands[2]; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class InstanceOfOperator extends SimpleOperator { |
||||
Type classType; |
||||
|
||||
public InstanceOfOperator(int addr, int length, Type type) { |
||||
super(addr, length, Type.tBoolean, 0, 1); |
||||
this.operandTypes[0] = UnknownType.tSubClass(type); |
||||
this.classType = type; |
||||
} |
||||
public int getOperandCount() { |
||||
return 1; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 550; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + " instanceof "+ca.getTypeString(classType); |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
package jode; |
||||
|
||||
public abstract class Instruction { |
||||
int addr,length; |
||||
|
||||
Instruction(int a, int l) { |
||||
addr = a; |
||||
length = l; |
||||
} |
||||
|
||||
public int getAddr() { |
||||
return addr; |
||||
} |
||||
|
||||
public void setAddr(int addr) { |
||||
this.addr = addr; |
||||
} |
||||
|
||||
public int getLength() { |
||||
return length; |
||||
} |
||||
|
||||
public void setLength(int length) { |
||||
this.length = length; |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
int[] result = { addr + length }; |
||||
return result; |
||||
} |
||||
|
||||
public abstract void dumpSource(TabbedPrintWriter tpw, CodeAnalyzer ca) |
||||
throws java.io.IOException; |
||||
} |
@ -0,0 +1,110 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class InvokeOperator extends Operator { |
||||
boolean staticFlag; |
||||
boolean specialFlag; |
||||
FieldDefinition field; |
||||
|
||||
public InvokeOperator(int addr, int length, |
||||
boolean staticFlag, boolean specialFlag, |
||||
FieldDefinition field) { |
||||
super(addr,length, field.getType().getReturnType(), 0); |
||||
this.staticFlag = staticFlag; |
||||
this.specialFlag = specialFlag; |
||||
this.field = field; |
||||
} |
||||
|
||||
public FieldDefinition getField() { |
||||
return field; |
||||
} |
||||
|
||||
public Type getClassType() { |
||||
return field.getClassDeclaration().getType(); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return (staticFlag?0:1) + field.getType().getArgumentTypes().length; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
if (!staticFlag && i == 0) |
||||
return 950; |
||||
return 0; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
if (!staticFlag) { |
||||
if (i == 0) |
||||
return field.getClassDeclaration().getType(); |
||||
i--; |
||||
} |
||||
return field.getType().getArgumentTypes()[i]; |
||||
} |
||||
|
||||
public void setOperandType(Type types[]) { |
||||
} |
||||
|
||||
public boolean isConstructor() { |
||||
return field.isConstructor(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
String object; |
||||
int arg = 0; |
||||
if (staticFlag) { |
||||
if (field.getClassDefinition() == ca.getClassDefinition()) |
||||
object = ""; |
||||
else |
||||
object = ca. |
||||
getTypeString(field.getClassDeclaration().getType()); |
||||
} else { |
||||
if (operands[arg].equals("this")) { |
||||
if (specialFlag && |
||||
(field.getClassDeclaration() == |
||||
ca.getClassDefinition().getSuperClass() || |
||||
(field.getClassDeclaration().getName() == |
||||
Constants.idJavaLangObject && |
||||
ca.getClassDefinition().getSuperClass() == null))) |
||||
object = "super"; |
||||
else if (specialFlag) |
||||
object = "(("+ca.getTypeString |
||||
(field.getClassDeclaration().getType())+ |
||||
") this)"; |
||||
else |
||||
object = ""; |
||||
} else { |
||||
if (specialFlag) |
||||
object = "(("+ca.getTypeString |
||||
(field.getClassDeclaration().getType())+ |
||||
") "+operands[arg]+")"; |
||||
else |
||||
object = operands[arg]; |
||||
} |
||||
arg++; |
||||
} |
||||
String method; |
||||
if (isConstructor()) { |
||||
if (object.length() == 0) |
||||
method = "this"; |
||||
else |
||||
method = object; |
||||
} else { |
||||
if (object.length() == 0) |
||||
method = field.getName().toString(); |
||||
else |
||||
method = object+"."+field.getName().toString(); |
||||
} |
||||
StringBuffer params = new StringBuffer(); |
||||
for (int i=0; i < field.getType().getArgumentTypes().length; i++) { |
||||
if (i>0) |
||||
params.append(", "); |
||||
params.append(operands[arg++]); |
||||
} |
||||
return method+"("+params+")"; |
||||
} |
||||
} |
@ -0,0 +1,16 @@ |
||||
package jode; |
||||
|
||||
public class JsrOperator extends Instruction { |
||||
int destination; |
||||
|
||||
public JsrOperator(int addr, int length, int dest) { |
||||
super(addr,length); |
||||
this.destination = dest; |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
writer.println("jsr addr_"+destination+";"); |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public abstract class JumpInstruction extends Operator { |
||||
public JumpInstruction(int addr, int length) { |
||||
super(addr, length, Type.tVoid, 0); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 0; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class LoadOperator extends ConstOperator { |
||||
LocalVariable slot; |
||||
|
||||
public LoadOperator(int addr, int length, Type type, LocalVariable slot) { |
||||
super(addr,length, |
||||
UnknownType.commonType(type,slot.getType(addr)), ""); |
||||
this.slot = slot; |
||||
} |
||||
|
||||
public LocalVariable getSlot() { |
||||
return slot; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return slot.getName(getAddr()).toString(); |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
return (o instanceof LoadOperator && |
||||
((LoadOperator) o).slot == slot); |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class MonitorEnterOperator extends SimpleOperator { |
||||
public MonitorEnterOperator(int a, int l) { |
||||
super(a,l, Type.tVoid, 0, 1); |
||||
operandTypes[0] = Type.tObject; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 0; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "monitorenter "+operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class MonitorExitOperator extends SimpleOperator { |
||||
public MonitorExitOperator(int a, int l) { |
||||
super(a,l,Type.tVoid, 0, 1); |
||||
operandTypes[0] = Type.tObject; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 0; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return UnknownType.tObject; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "monitorexit "+operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class NewArrayOperator extends SimpleOperator { |
||||
Type baseType; |
||||
|
||||
public NewArrayOperator(int addr, int length, |
||||
Type baseType, int dimensions) { |
||||
super(addr, length, baseType, 0, dimensions); |
||||
this.baseType = baseType; |
||||
for (int i=0; i< dimensions; i++) { |
||||
this.type = Type.tArray(this.type); |
||||
operandTypes[i] = UnknownType.tUIndex; |
||||
} |
||||
} |
||||
|
||||
public NewArrayOperator(int addr, int length, Type baseType) { |
||||
this(addr, length, baseType, 1); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 900; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 0; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
StringBuffer result |
||||
= new StringBuffer("new ").append(ca.getTypeString(baseType)); |
||||
for (int i=0; i< getOperandCount(); i++) { |
||||
result.append("[").append(operands[i]).append("]"); |
||||
} |
||||
return result.toString(); |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class NewConstructorOperator extends NoArgOperator { |
||||
Expression constructor; |
||||
|
||||
public NewConstructorOperator(int addr, int length, Type type, |
||||
Expression expr) { |
||||
super(addr,length, type); |
||||
this.constructor = expr; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "new "+constructor.toString(ca, 0); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class NewOperator extends NoArgOperator { |
||||
|
||||
public NewOperator(int addr, int length, Type type) { |
||||
super(addr,length, type); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 950; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "new "+getType().toString(); |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public abstract class NoArgOperator extends Operator { |
||||
|
||||
public NoArgOperator(int addr, int length, Type type) { |
||||
super(addr, length, type, 0); |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
throw new AssertError("This operator has no operands"); |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
throw new AssertError("This operator has no operands"); |
||||
} |
||||
|
||||
public void setOperandType(Type[] types) { |
||||
throw new AssertError("This operator has no operands"); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,13 @@ |
||||
package jode; |
||||
|
||||
public class NopOperator extends Instruction { |
||||
public NopOperator(int a, int l) { |
||||
super(a,l); |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter tpw, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
tpw.println("nop;"); |
||||
} |
||||
} |
@ -0,0 +1,111 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public abstract class Operator extends Instruction { |
||||
public final static int ADD_OP = 1; |
||||
public final static int NEG_OP = 2; |
||||
public final static int SHIFT_OP = 6; |
||||
public final static int ASSIGN_OP = 12; |
||||
public final static int OPASSIGN_OP= 12; |
||||
public final static int INC_OP = 24; |
||||
public final static int COMPARE_OP = 26; /* must be even! */ |
||||
public final static int LOG_AND_OP = 32; /* must be even! */ |
||||
public final static int LOG_OR_OP = 33; |
||||
public final static int LOG_NOT_OP = 34; |
||||
static String opString[] = { |
||||
"", "+","-","*","/","%", "<<", ">>", ">>>", "&", "|", "^", |
||||
"=","+=","-=","*=","/=","%=", "<<=", ">>=", ">>>=", "&=", "|=", "^=", |
||||
"++", "--", |
||||
"==","!=","<",">=",">", "<=", "&&", "||", |
||||
"~", "!" |
||||
}; |
||||
|
||||
protected Type type; |
||||
protected int operator; |
||||
|
||||
String casts; |
||||
|
||||
Operator (int addr, int length, Type type, int op) { |
||||
super(addr,length); |
||||
this.type = type; |
||||
this.operator = op; |
||||
if (type == null) |
||||
throw new AssertError("type == null"); |
||||
casts = type.toString(); |
||||
} |
||||
|
||||
public int getOperator() { |
||||
return operator; |
||||
} |
||||
public void setOperator(int op) { |
||||
operator = op; |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type type) { |
||||
if (!UnknownType.isOfType(type, this.type)) { |
||||
casts = type.toString()+"/*invalid*/ <- " + casts; |
||||
} else if (type != this.type) { |
||||
casts = type.toString()+" <- " + casts; |
||||
} |
||||
this.type = type; |
||||
return false; |
||||
} |
||||
|
||||
public final Type getType() { |
||||
return type; |
||||
} |
||||
|
||||
public String getOperatorString() { |
||||
return opString[operator]; |
||||
} |
||||
|
||||
/** |
||||
* Get priority of the operator. |
||||
* Currently this priorities are known: |
||||
* <ul><li> 1000 constant |
||||
* </li><li> 950 new, .(field access), [] |
||||
* </li><li> 900 new[] |
||||
* </li><li> 800 ++,-- (post) |
||||
* </li><li> 700 ++,--(pre), +,-(unary), ~, !, cast |
||||
* </li><li> 650 *,/, % |
||||
* </li><li> 610 +,- |
||||
* </li><li> 600 <<, >>, >>> |
||||
* </li><li> 550 >, <, >=, <=, instanceof |
||||
* </li><li> 500 ==, != |
||||
* </li><li> 450 & |
||||
* </li><li> 420 ^ |
||||
* </li><li> 410 | |
||||
* </li><li> 350 && |
||||
* </li><li> 310 || |
||||
* </li><li> 200 ?: |
||||
* </li><li> 100 =, +=, -=, etc. |
||||
* </li></ul> |
||||
*/ |
||||
public abstract int getPriority(); |
||||
|
||||
/** |
||||
* Get minimum priority of the nth operand. |
||||
* @see getPriority |
||||
*/ |
||||
public abstract int getOperandPriority(int i); |
||||
public abstract Type getOperandType(int i); |
||||
public abstract int getOperandCount(); |
||||
public abstract void setOperandType(Type[] inputTypes); |
||||
public abstract String toString(CodeAnalyzer ca, String[] operands); |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
if (type == null) |
||||
throw new AssertError("type == null"); |
||||
String[] operands = new String[getOperandCount()]; |
||||
for (int i=0; i< operands.length; i++) { |
||||
operands[i] = "stack_"+(operands.length-i-1); |
||||
} |
||||
writer.println(toString(ca, operands)); |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class PopOperator extends SimpleOperator { |
||||
int count; |
||||
|
||||
public PopOperator(int a, int l, int count) { |
||||
super(a,l, Type.tVoid, 0, 1); |
||||
operandTypes[0] = UnknownType.tUnknown; |
||||
this.count = count; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 0; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class PostFixOperator extends SimpleOperator { |
||||
public PostFixOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, type, op, 1); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 800; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority(); |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type type) { |
||||
super.setType(type); |
||||
Type newOpType = UnknownType.commonType(type, operandTypes[0]); |
||||
if (newOpType != operandTypes[0]) { |
||||
operandTypes[0] = newOpType; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return operands[0] + getOperatorString(); |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
package jode; |
||||
import sun.tools.java.*; |
||||
|
||||
public class PutFieldOperator extends StoreInstruction { |
||||
boolean staticFlag; |
||||
FieldDefinition field; |
||||
|
||||
public PutFieldOperator(int addr, int length, boolean staticFlag, |
||||
FieldDefinition field) { |
||||
super(addr, length, field.getType()); |
||||
this.staticFlag = staticFlag; |
||||
this.field = field; |
||||
} |
||||
|
||||
public boolean matches(Operator loadop) { |
||||
return loadop instanceof GetFieldOperator && |
||||
((GetFieldOperator)loadop).field == field; |
||||
} |
||||
|
||||
public int getLValueOperandCount() { |
||||
return staticFlag?0:1; |
||||
} |
||||
|
||||
public int getLValueOperandPriority(int i) { |
||||
if (staticFlag) { |
||||
/* shouldn't be called */ |
||||
throw new RuntimeException("Field is static"); |
||||
} |
||||
return 900; |
||||
} |
||||
|
||||
public Type getLValueOperandType(int i) { |
||||
if (staticFlag) { |
||||
/* shouldn't be called */ |
||||
throw new AssertError("Field is static"); |
||||
} |
||||
return field.getClassDefinition().getType(); |
||||
} |
||||
|
||||
public void setLValueOperandType(Type[] t) { |
||||
if (staticFlag) { |
||||
/* shouldn't be called */ |
||||
throw new AssertError("Field is static"); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
public String getLValueString(CodeAnalyzer ca, String[] operands) { |
||||
String object; |
||||
if (staticFlag) { |
||||
if (field.getClassDefinition() == ca.getClassDefinition()) |
||||
return field.getName().toString(); |
||||
object = |
||||
ca.getTypeString(field.getClassDeclaration().getType())+"."; |
||||
} else { |
||||
if (operands[0].equals("this")) |
||||
return field.getName().toString(); |
||||
object = operands[0]; |
||||
} |
||||
return object + "." + field.getName(); |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
package jode; |
||||
|
||||
public class RetOperator extends Instruction { |
||||
int slot; |
||||
|
||||
public RetOperator(int addr, int length, int slot) { |
||||
super(addr,length); |
||||
this.slot = slot; |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
return new int[0]; |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
writer.println("ret;"); |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class ReturnOperator extends SimpleOperator { |
||||
public ReturnOperator(int addr, int length, Type type) { |
||||
super(addr,length, Type.tVoid, 0, (type == Type.tVoid)?0:1); |
||||
if (type != Type.tVoid) |
||||
operandTypes[0] = type; |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
return new int[0]; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 0; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
StringBuffer result = new StringBuffer("return"); |
||||
if (getOperandCount() != 0) |
||||
result.append(" ").append(operands[0]); |
||||
return result.toString(); |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
/** |
||||
* ShiftOpcodes are special, because their second operand is an UIndex |
||||
*/ |
||||
public class ShiftOperator extends BinaryOperator { |
||||
protected Type shiftType; |
||||
|
||||
public ShiftOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, type, op); |
||||
shiftType = UnknownType.tUIndex; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return (i==0)?operandType:shiftType; |
||||
} |
||||
|
||||
public void setOperandType(Type[] inputTypes) { |
||||
operandType = UnknownType.commonType(operandType, inputTypes[0]); |
||||
shiftType = UnknownType.commonType(shiftType, inputTypes[1]); |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public abstract class SimpleOperator extends Operator { |
||||
protected Type[] operandTypes; |
||||
|
||||
public SimpleOperator(int addr, int length, Type type, int operator, |
||||
int operandCount) { |
||||
super(addr, length, type, operator); |
||||
operandTypes = new Type[operandCount]; |
||||
for (int i=0; i< operandCount; i++) { |
||||
operandTypes[i] = type; |
||||
} |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return operandTypes.length; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return operandTypes[i]; |
||||
} |
||||
|
||||
public void setOperandType(Type[] t) { |
||||
for (int i=0; i< operandTypes.length; i++) { |
||||
if (UnknownType.commonType(operandTypes[i], t[i]) == Type.tError) |
||||
System.err.println("Error: "+operandTypes[i]+","+t[i]); |
||||
operandTypes[i] = UnknownType.commonType(operandTypes[i], t[i]); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,80 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public abstract class StoreInstruction extends Operator { |
||||
|
||||
public String lvCasts; |
||||
Type lvalueType; |
||||
|
||||
public StoreInstruction(int addr, int length, Type type) { |
||||
this (addr,length, type, ASSIGN_OP); |
||||
} |
||||
|
||||
public StoreInstruction(int addr, int length, Type type, int operator) { |
||||
super(addr,length, Type.tVoid, operator); |
||||
lvalueType = type; |
||||
lvCasts = lvalueType.toString(); |
||||
} |
||||
|
||||
public Type getLValueType() { |
||||
return lvalueType; |
||||
} |
||||
|
||||
public abstract boolean matches(Operator loadop); |
||||
public abstract int getLValueOperandCount(); |
||||
public abstract int getLValueOperandPriority(int i); |
||||
public abstract Type getLValueOperandType(int i); |
||||
public abstract void setLValueOperandType(Type [] t); |
||||
|
||||
/** |
||||
* Sets the type of the lvalue (and rvalue). |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setLValueType(Type type) { |
||||
if (!UnknownType.isOfType(type, this.lvalueType)) { |
||||
lvCasts = type.toString()+"/*invalid*/ <- " + lvCasts; |
||||
} else if (type != this.lvalueType) { |
||||
lvCasts = type.toString()+" <- " + lvCasts; |
||||
} |
||||
this.lvalueType = type; |
||||
return false; |
||||
} |
||||
|
||||
public abstract String getLValueString(CodeAnalyzer ca, String[] operands); |
||||
|
||||
public int getPriority() { |
||||
return 100; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
if (i == getLValueOperandCount()) |
||||
return 100; |
||||
else |
||||
return getLValueOperandPriority(i); |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
if (i == getLValueOperandCount()) |
||||
return getLValueType(); |
||||
else |
||||
return getLValueOperandType(i); |
||||
} |
||||
|
||||
public void setOperandType(Type[] t) { |
||||
if (getLValueOperandCount() > 0) |
||||
setLValueOperandType(t); |
||||
setLValueType |
||||
(UnknownType.commonType(lvalueType, t[getLValueOperandCount()])); |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 1 + getLValueOperandCount(); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) |
||||
{ |
||||
return "{"+lvCasts+" "+getLValueString(ca, operands) + "} "+ |
||||
getOperatorString() +" "+ |
||||
operands[getLValueOperandCount()]; |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class StoreOperator extends StoreInstruction { |
||||
LocalVariable slot; |
||||
|
||||
public StoreOperator(int addr, int length, Type type, |
||||
LocalVariable slot, int operator) { |
||||
super(addr,length, |
||||
UnknownType.commonType(type,slot.getType(addr+length)), |
||||
operator); |
||||
this.slot = slot; |
||||
} |
||||
|
||||
public LocalVariable getSlot() { |
||||
return slot; |
||||
} |
||||
|
||||
public boolean matches(Operator loadop) { |
||||
return loadop instanceof LoadOperator && |
||||
((LoadOperator)loadop).getSlot() == slot; |
||||
} |
||||
|
||||
public int getLValueOperandCount() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getLValueOperandPriority(int i) { |
||||
/* shouldn't be called */ |
||||
throw new RuntimeException("StoreOperator has no operands"); |
||||
} |
||||
|
||||
public Type getLValueOperandType(int i) { |
||||
/* shouldn't be called */ |
||||
throw new RuntimeException("StoreOperator has no operands"); |
||||
} |
||||
|
||||
public void setLValueOperandType(Type []t) { |
||||
/* shouldn't be called */ |
||||
throw new RuntimeException("StoreOperator has no operands"); |
||||
} |
||||
|
||||
public String getLValueString(CodeAnalyzer ca, String[] operands) { |
||||
return slot.getName(getAddr()+getLength()).toString(); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
package jode; |
||||
|
||||
public class SwapOperator extends Instruction { |
||||
public SwapOperator(int a, int l) { |
||||
super(a,l); |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
writer.println("swap;"); |
||||
} |
||||
} |
@ -0,0 +1,70 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class SwitchOperator extends JumpInstruction { |
||||
int[] cases; |
||||
int[] destinations; |
||||
Type operandType; |
||||
|
||||
public SwitchOperator(int addr, int length, int[] cases, int[] dests) { |
||||
super(addr,length); |
||||
this.cases = cases; |
||||
this.destinations = dests; |
||||
this.operandType = UnknownType.tUInt; |
||||
} |
||||
|
||||
public int[] getCases() { |
||||
return cases; |
||||
} |
||||
|
||||
public int[] getSuccessors() { |
||||
return destinations; |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 0; |
||||
} |
||||
|
||||
public int getOperandCount() { |
||||
return 1; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return 0; |
||||
} |
||||
|
||||
public Type getOperandType(int i) { |
||||
return operandType; |
||||
} |
||||
|
||||
public void setOperandType(Type types[]) { |
||||
operandType = UnknownType.commonType(operandType, types[0]); |
||||
} |
||||
|
||||
public boolean setType(Type t) { |
||||
super.setType(type); |
||||
if (type != operandType) { |
||||
operandType = type; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "switch ("+operands[0]+") "; |
||||
} |
||||
|
||||
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca) |
||||
throws java.io.IOException |
||||
{ |
||||
writer.println("switch(stack_0) {"); |
||||
writer.tab(); |
||||
for (int i=0; i< cases.length; i++) { |
||||
writer.println("case "+cases[i]+ |
||||
": goto addr_"+destinations[i]+";"); |
||||
} |
||||
writer.println("default: goto addr_"+destinations[cases.length]); |
||||
writer.untab(); |
||||
writer.println("}"); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class ThrowOperator extends ReturnOperator { |
||||
|
||||
public ThrowOperator(int addr, int length) { |
||||
super(addr,length, UnknownType.tUObject); |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return "throw " + operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class UnaryOperator extends SimpleOperator { |
||||
public UnaryOperator(int addr, int length, Type type, int op) { |
||||
super(addr,length, type, op, 1); |
||||
} |
||||
|
||||
public int getPriority() { |
||||
return 700; |
||||
} |
||||
|
||||
public int getOperandPriority(int i) { |
||||
return getPriority(); |
||||
} |
||||
|
||||
/** |
||||
* Sets the return type of this operator. |
||||
* @return true if the operand types changed |
||||
*/ |
||||
public boolean setType(Type type) { |
||||
super.setType(type); |
||||
Type newOpType = UnknownType.commonType(type, operandTypes[0]); |
||||
if (newOpType != operandTypes[0]) { |
||||
operandTypes[0] = newOpType; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public String toString(CodeAnalyzer ca, String[] operands) { |
||||
return getOperatorString() + operands[0]; |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
|
||||
public class UnknownSubType extends UnknownType { |
||||
Type elemType; |
||||
|
||||
public UnknownSubType(Type type) { |
||||
super(103, "<"); |
||||
elemType = type; |
||||
} |
||||
|
||||
public Type getElementType() |
||||
{ |
||||
return elemType; |
||||
} |
||||
|
||||
public String typeString(String string, boolean flag1, boolean flag2) |
||||
{ |
||||
return "<superclass of "+ |
||||
String.valueOf(elemType.typeString(string, flag1, flag2))+">"; |
||||
} |
||||
} |
@ -0,0 +1,204 @@ |
||||
package jode; |
||||
import sun.tools.java.Type; |
||||
import java.util.Hashtable; |
||||
|
||||
public class UnknownType extends Type { |
||||
static Hashtable subclasses = new Hashtable(); |
||||
|
||||
public static Type tUnknown = new UnknownType(100, "x"); |
||||
public static Type tUInt = new UnknownType(101, "i"); |
||||
public static Type tUIndex = new UnknownType(104, "["); |
||||
public static Type tUObject = new UnknownType(102, "*"); |
||||
public static Type tSubClass(Type type) { |
||||
Type subtype = (Type) subclasses.get(type); |
||||
if (subtype == null) { |
||||
subtype = new UnknownSubType(type); |
||||
subclasses.put(type, subtype); |
||||
} |
||||
return subtype; |
||||
} |
||||
|
||||
protected UnknownType(int i, String str) { |
||||
super (i, str); |
||||
} |
||||
|
||||
public int stackSize() |
||||
{ |
||||
return 1; |
||||
} |
||||
|
||||
public String typeString(String var, boolean flag1, boolean flag2) |
||||
{ |
||||
String typeStr; |
||||
switch (typeCode) { |
||||
case 100: typeStr="<unknown>"; break; |
||||
case 101: typeStr="<int>"; break; /*XXX*/ |
||||
case 102: typeStr="<Object>"; break; |
||||
case 104: typeStr="<arrindex>"; break; /*XXX*/ |
||||
default: |
||||
throw new RuntimeException("Wrong typeCode "+typeCode); |
||||
} |
||||
if (var.length() > 0) |
||||
return typeStr+" "+var; |
||||
return typeStr; |
||||
} |
||||
|
||||
public static Type commonType(Type t1, Type t2) { |
||||
if (t1 == t2 || t2 == tUnknown) |
||||
return t1; |
||||
|
||||
switch (t1.getTypeCode()) { |
||||
case 0: /* boolean*/ |
||||
case 1: /* byte */ |
||||
case 2: /* char */ |
||||
case 3: /* short */ |
||||
case 4: /* int */ |
||||
if (t2.getTypeCode() <= 4) { |
||||
if (t2.getTypeCode() > t1.getTypeCode()) |
||||
return t2; |
||||
else |
||||
return t1; |
||||
} |
||||
if (t2 == tUInt || t2 == tUIndex) |
||||
return t1; |
||||
break; |
||||
|
||||
case 5: /* long */ |
||||
case 6: /* float */ |
||||
case 7: /* double */ |
||||
case 8: /* null? */ |
||||
case 11: /* void */ |
||||
case 12: /* method */ |
||||
case 13: /* error */ |
||||
break; |
||||
|
||||
case 9: /* array */ |
||||
if (t2 == tUObject) |
||||
return t1; |
||||
if (t2.getTypeCode() == 9) /* array, array case */ |
||||
return tArray(commonType(t1.getElementType(), |
||||
t2.getElementType())); |
||||
break; |
||||
|
||||
case 10: /* class */ |
||||
if (t2 == tUObject) |
||||
return t1; |
||||
if (t2.getTypeCode() == 103) { |
||||
/* find suitable subclass of t2 */ |
||||
return t2; /*XXX*/ |
||||
} |
||||
if (t2.getTypeCode() == 10) { |
||||
return t1; /*XXX*/ |
||||
} |
||||
break; |
||||
|
||||
case 100: /* unknown */ |
||||
return t2; |
||||
|
||||
case 101: /* unknown int */ |
||||
if ((t2.getTypeCode() >= 0 && t2.getTypeCode() <= 4) || |
||||
t2 == tUIndex) |
||||
return t2; |
||||
break; |
||||
case 104: /* unknown index */ |
||||
if (t2.getTypeCode() >= 1 && t2.getTypeCode() <= 4) |
||||
return t2; |
||||
if (t2 == tUInt) |
||||
return t1; |
||||
break; |
||||
|
||||
case 102: /* unknown object */ |
||||
if (t2.getTypeCode() == 9 || t2.getTypeCode() == 10 || |
||||
t2.getTypeCode() == 103) |
||||
return t2; |
||||
break; |
||||
|
||||
case 103: /* unknown super class */ |
||||
if (t2.getTypeCode() == 10 || t2.getTypeCode() == 103) |
||||
return t2; /*XXX*/ |
||||
if (t2 == tUObject) |
||||
return t1; |
||||
break; |
||||
|
||||
default: |
||||
throw new AssertError("Wrong typeCode "+t1.getTypeCode()); |
||||
} |
||||
return tError; |
||||
} |
||||
|
||||
/** |
||||
* Check if t1 is a t2. |
||||
* @return true if t1 is a more specific type than t2, e.g. |
||||
* if t2 is a superclass of t1 |
||||
*/ |
||||
public static boolean isOfType(Type t1, Type t2) { |
||||
if ((t1 == t2 || t2 == tUnknown) && t1 != tError) |
||||
return true; |
||||
|
||||
switch (t1.getTypeCode()) { |
||||
case 0: /* boolean*/ |
||||
case 1: /* byte */ |
||||
case 2: /* char */ |
||||
case 3: /* short */ |
||||
case 4: /* int */ |
||||
|
||||
/* JavaC thinks, that this is okay. */ |
||||
if (t2.getTypeCode() >= 0 && t2.getTypeCode() <=4) |
||||
return true; |
||||
|
||||
/* fallthrough */ |
||||
case 104: /* unknown index */ |
||||
if (t2 == tUInt || t2 == tUIndex) |
||||
return true; |
||||
break; |
||||
|
||||
case 5: /* long */ |
||||
case 6: /* float */ |
||||
case 7: /* double */ |
||||
case 8: /* null? */ |
||||
case 11: /* void */ |
||||
case 12: /* method */ |
||||
case 13: /* error */ |
||||
case 100: /* unknown */ |
||||
case 101: /* unknown int */ |
||||
case 102: /* unknown object */ |
||||
break; |
||||
|
||||
case 9: /* array */ |
||||
if (t2 == tUObject) |
||||
return true; |
||||
if (t2.getTypeCode() == 9) /* array,array case */ |
||||
return isOfType(t1.getElementType(), t2.getElementType()); |
||||
break; |
||||
|
||||
case 10: /* class */ |
||||
if (t2 == tUObject) |
||||
return true; |
||||
if (t2.getTypeCode() == 103) |
||||
/* Always true because t2 may be an Object XXX I think not*/ |
||||
return true; |
||||
if (t2.getTypeCode() == 10) |
||||
/* true if t2 is a superclass of t1 */ |
||||
return true; /*XXX*/ |
||||
break; |
||||
|
||||
case 103: /* unknown super class */ |
||||
if (t2.getTypeCode() == 103) |
||||
/* Always true because t2 may be an Object XXX I think not*/ |
||||
return true; |
||||
|
||||
if (t2.getTypeCode() == 10) { |
||||
/* true if t2 is a real super class
|
||||
(or interface) of t1.getElementType() */ |
||||
return true; /*XXX*/ |
||||
} |
||||
if (t2 == tUObject) |
||||
return true; |
||||
break; |
||||
|
||||
default: |
||||
throw new AssertError("Wrong typeCode "+t1.getTypeCode()); |
||||
} |
||||
return false; |
||||
} |
||||
} |
Loading…
Reference in new issue