diff options
Diffstat (limited to 'src/org/jetbrains/java/decompiler/struct/StructMethod.java')
-rw-r--r-- | src/org/jetbrains/java/decompiler/struct/StructMethod.java | 560 |
1 files changed, 560 insertions, 0 deletions
diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java new file mode 100644 index 0000000..20fdae9 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java @@ -0,0 +1,560 @@ +/* + * Fernflower - The Analytical Java Decompiler + * http://www.reversed-java.com + * + * (C) 2008 - 2010, Stiver + * + * This software is NEITHER public domain NOR free software + * as per GNU License. See license.txt for more details. + * + * This software is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. + */ + +package org.jetbrains.java.decompiler.struct; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.code.ConstantsUtil; +import org.jetbrains.java.decompiler.code.ExceptionHandler; +import org.jetbrains.java.decompiler.code.ExceptionTable; +import org.jetbrains.java.decompiler.code.FullInstructionSequence; +import org.jetbrains.java.decompiler.code.Instruction; +import org.jetbrains.java.decompiler.code.InstructionSequence; +import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute; +import org.jetbrains.java.decompiler.struct.consts.ConstantPool; +import org.jetbrains.java.decompiler.util.DataInputFullStream; +import org.jetbrains.java.decompiler.util.VBStyleCollection; + +/* + method_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + attribute_info attributes[attributes_count]; + } +*/ + +public class StructMethod implements CodeConstants { + + // ***************************************************************************** + // public fields + // ***************************************************************************** + + public int name_index; + + public int descriptor_index; + + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private static final int[] opr_iconst = new int[] {-1,0,1,2,3,4,5}; + + private static final int[] opr_loadstore = new int[] {0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3}; + + private static final int[] opcs_load = new int[] {opc_iload,opc_lload,opc_fload,opc_dload,opc_aload}; + + private static final int[] opcs_store = new int[] {opc_istore,opc_lstore,opc_fstore,opc_dstore,opc_astore}; + + + private int accessFlags; + + private VBStyleCollection<StructGeneralAttribute, String> attributes; + + private int localVariables; + + private int maxStack; + + private String name; + + private String descriptor; + + private InstructionSequence seq; + + private boolean containsCode = false; + + private boolean own; + + private StructClass classStruct; + + + // lazy properties + private boolean lazy; + + private boolean expanded; + + private byte[] code_content; + + private int code_length = 0; + + private int code_fulllength = 0; + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + public StructMethod(DataInputFullStream in, boolean own, StructClass clstruct) throws IOException { + this(in, true, own, clstruct); + } + + public StructMethod(DataInputFullStream in, boolean lazy, boolean own, StructClass clstruct) throws IOException { + + this.own = own; + this.lazy = lazy; + this.expanded = !lazy; + this.classStruct = clstruct; + + accessFlags = in.readUnsignedShort(); + name_index = in.readUnsignedShort(); + descriptor_index = in.readUnsignedShort(); + + ConstantPool pool = clstruct.getPool(); + + initStrings(pool, clstruct.this_class); + + VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>(); + int len = in.readUnsignedShort(); + for(int i=0;i<len;i++) { + + int attr_nameindex = in.readUnsignedShort(); + String attrname = pool.getPrimitiveConstant(attr_nameindex).getString(); + + if(StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) { + if(!this.own) { + // skip code in foreign classes + in.skip(8); + in.skip(in.readInt()); + in.skip(8*in.readUnsignedShort()); + } else { + containsCode = true; + + in.skip(4); + + maxStack = in.readUnsignedShort(); + localVariables = in.readUnsignedShort(); + + if(lazy) { + code_length = in.readInt(); + + in.skip(code_length); + + int exc_length = in.readUnsignedShort(); + code_fulllength = code_length + exc_length*8+2; + + in.skip(exc_length*8); + + } else { + seq = parseBytecode(in, in.readInt(), pool); + } + } + + // code attributes + int length = in.readUnsignedShort(); + for (int j = 0; j < length; j++) { + int codeattr_nameindex = in.readUnsignedShort(); + String codeattrname = pool.getPrimitiveConstant(codeattr_nameindex).getString(); + + readAttribute(in, pool, lstAttribute, codeattr_nameindex, codeattrname); + } + } else { + readAttribute(in, pool, lstAttribute, attr_nameindex, attrname); + } + } + + attributes = lstAttribute; + } + + + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public void writeToStream(DataOutputStream out) throws IOException { + + out.writeShort(accessFlags); + out.writeShort(name_index); + out.writeShort(descriptor_index); + + out.writeShort(attributes.size()); + + for(StructGeneralAttribute attr: attributes) { + if(StructGeneralAttribute.ATTRIBUTE_CODE.equals(attr.getName())){ + out.writeShort(attr.getAttribute_name_index()); + + if(lazy && !expanded) { + out.writeInt(10+code_content.length); + out.writeShort(maxStack); + out.writeShort(localVariables); + out.writeInt(code_length); + out.write(code_content); + } else { + ByteArrayOutputStream codeout = new ByteArrayOutputStream(); + seq.writeCodeToStream(new DataOutputStream(codeout)); + + ByteArrayOutputStream excout = new ByteArrayOutputStream(); + seq.writeExceptionsToStream(new DataOutputStream(excout)); + + out.writeInt(10+codeout.size()+excout.size()); + + out.writeShort(maxStack); + out.writeShort(localVariables); + out.writeInt(codeout.size()); + codeout.writeTo(out); + excout.writeTo(out); + } + // no attributes + out.writeShort(0); + } else { + attr.writeToStream(out); + } + } + + } + + private void readAttribute(DataInputFullStream in, ConstantPool pool, VBStyleCollection<StructGeneralAttribute, String> lstAttribute, + int attr_nameindex, String attrname) throws IOException { + + StructGeneralAttribute attribute = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname); + + if(attribute != null) { + attrname = attribute.getName(); + + byte[] arr = new byte[in.readInt()]; + in.readFull(arr); + attribute.setInfo(arr); + + attribute.initContent(pool); + + if(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname) && + lstAttribute.containsKey(attrname)) { + // merge all variable tables + StructLocalVariableTableAttribute oldattr = (StructLocalVariableTableAttribute)lstAttribute.getWithKey(attrname); + oldattr.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); + } else { + lstAttribute.addWithKey(attribute, attribute.getName()); + } + } else { + in.skip(in.readInt()); + } + } + + private void initStrings(ConstantPool pool, int class_index) { + String[] values = pool.getClassElement(ConstantPool.METHOD, class_index, name_index, descriptor_index); + name = values[0]; + descriptor = values[1]; + } + + public void expandData() throws IOException { + if(containsCode && lazy && !expanded) { + + byte[] codearr = classStruct.getLoader().loadBytecode(this, code_fulllength); + + seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(codearr)), code_length, classStruct.getPool()); + expanded = true; + } + } + + public void releaseResources() throws IOException { + if(containsCode && lazy && expanded) { + seq = null; + expanded = false; + } + } + + // ***************************************************************************** + // private methods + // ***************************************************************************** + + private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException { + + VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>(); + + int bytecode_version = classStruct.getBytecodeVersion(); + + for(int i=0;i<length;) { + + int offset = i; + + int opcode = in.readUnsignedByte(); + int group = GROUP_GENERAL; + + boolean wide = (opcode == opc_wide); + + if(wide) { + i++; + opcode = in.readUnsignedByte(); + } + + List<Integer> operands = new ArrayList<Integer>(); + + if(opcode>=opc_iconst_m1 && opcode<=opc_iconst_5) { + operands.add(new Integer(opr_iconst[opcode-opc_iconst_m1])); + opcode = opc_bipush; + }else if(opcode>=opc_iload_0 && opcode<=opc_aload_3) { + operands.add(new Integer(opr_loadstore[opcode-opc_iload_0])); + opcode = opcs_load[(opcode-opc_iload_0)/4]; + }else if(opcode>=opc_istore_0 && opcode<=opc_astore_3) { + operands.add(new Integer(opr_loadstore[opcode-opc_istore_0])); + opcode = opcs_store[(opcode-opc_istore_0)/4]; + } else { + switch (opcode) { + case opc_bipush: + operands.add(new Integer(in.readByte())); + i++; + break; + case opc_ldc: + case opc_newarray: + operands.add(new Integer(in.readUnsignedByte())); + i++; + break; + case opc_sipush: + case opc_ifeq: + case opc_ifne: + case opc_iflt: + case opc_ifge: + case opc_ifgt: + case opc_ifle: + case opc_if_icmpeq: + case opc_if_icmpne: + case opc_if_icmplt: + case opc_if_icmpge: + case opc_if_icmpgt: + case opc_if_icmple: + case opc_if_acmpeq: + case opc_if_acmpne: + case opc_goto: + case opc_jsr: + case opc_ifnull: + case opc_ifnonnull: + if(opcode!=opc_sipush) { + group = GROUP_JUMP; + } + operands.add(new Integer(in.readShort())); + i+=2; + break; + case opc_ldc_w: + case opc_ldc2_w: + case opc_getstatic: + case opc_putstatic: + case opc_getfield: + case opc_putfield: + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + case opc_new: + case opc_anewarray: + case opc_checkcast: + case opc_instanceof: + operands.add(new Integer(in.readUnsignedShort())); + i+=2; + if(opcode>=opc_getstatic && opcode<=opc_putfield) { + group = GROUP_FIELDACCESS; + } else if(opcode>=opc_invokevirtual && opcode<=opc_invokestatic) { + group = GROUP_INVOCATION; + } + break; + case opc_invokedynamic: + if(classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before + operands.add(new Integer(in.readUnsignedShort())); + in.skip(2); + group = GROUP_INVOCATION; + i+=4; + } + break; + 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: + case opc_ret: + if(wide) { + operands.add(new Integer(in.readUnsignedShort())); + i+=2; + } else { + operands.add(new Integer(in.readUnsignedByte())); + i++; + } + if(opcode == opc_ret) { + group = GROUP_RETURN; + } + break; + case opc_iinc: + if (wide) { + operands.add(new Integer(in.readUnsignedShort())); + operands.add(new Integer(in.readShort())); + i+=4; + } else { + operands.add(new Integer(in.readUnsignedByte())); + operands.add(new Integer(in.readByte())); + i+=2; + } + break; + case opc_goto_w: + case opc_jsr_w: + opcode = opcode == opc_jsr_w?opc_jsr:opc_goto; + operands.add(new Integer(in.readInt())); + group = GROUP_JUMP; + i+=4; + break; + case opc_invokeinterface: + operands.add(new Integer(in.readUnsignedShort())); + operands.add(new Integer(in.readUnsignedByte())); + in.skip(1); + group = GROUP_INVOCATION; + i+=4; + break; + case opc_multianewarray: + operands.add(new Integer(in.readUnsignedShort())); + operands.add(new Integer(in.readUnsignedByte())); + i+=3; + break; + case opc_tableswitch: + in.skip((4-(i+1)%4)%4); + i+=((4-(i+1)%4)%4); // padding + operands.add(new Integer(in.readInt())); + i+=4; + int low = in.readInt(); + operands.add(new Integer(low)); + i+=4; + int high = in.readInt(); + operands.add(new Integer(high)); + i+=4; + + for(int j=0;j<high-low+1;j++) { + operands.add(new Integer(in.readInt())); + i+=4; + } + group = GROUP_SWITCH; + + break; + case opc_lookupswitch: + in.skip((4-(i+1)%4)%4); + i+=((4-(i+1)%4)%4); // padding + operands.add(new Integer(in.readInt())); + i+=4; + int npairs = in.readInt(); + operands.add(new Integer(npairs)); + i+=4; + + for(int j=0;j<npairs;j++) { + operands.add(new Integer(in.readInt())); + i+=4; + operands.add(new Integer(in.readInt())); + i+=4; + } + group = GROUP_SWITCH; + break; + case opc_ireturn: + case opc_lreturn: + case opc_freturn: + case opc_dreturn: + case opc_areturn: + case opc_return: + case opc_athrow: + group = GROUP_RETURN; + } + } + + int[] ops = new int[operands.size()]; + for(int j=0;j<operands.size();j++) { + ops[j] = ((Integer)operands.get(j)).intValue(); + } + + Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops); + + collinstr.addWithKey(instr, new Integer(offset)); + + i++; + } + + // initialize exception table + List<ExceptionHandler> lstHandlers = new ArrayList<ExceptionHandler>(); + + int exception_count = in.readUnsignedShort(); + for(int i=0;i<exception_count;i++) { + ExceptionHandler handler = new ExceptionHandler(); + handler.from = in.readUnsignedShort(); + handler.to = in.readUnsignedShort(); + handler.handler = in.readUnsignedShort(); + + int excclass = in.readUnsignedShort(); + handler.class_index = excclass; + if(excclass!=0) { + handler.exceptionClass = pool.getPrimitiveConstant(excclass).getString(); + } + + lstHandlers.add(handler); + } + + InstructionSequence seq = new FullInstructionSequence(collinstr, new ExceptionTable(lstHandlers)); + + // initialize instructions + int i = seq.length()-1; + seq.setPointer(i); + + while(i>=0) { + Instruction instr = seq.getInstr(i--); + if(instr.group!=GROUP_GENERAL) { + instr.initInstruction(seq); + } + seq.addToPointer(-1); + } + + return seq; + + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public InstructionSequence getInstructionSequence() { + return seq; + } + + public String getDescriptor() { + return descriptor; + } + + public String getName() { + return name; + } + + public int getAccessFlags() { + return accessFlags; + } + + public int getLocalVariables() { + return localVariables; + } + + public VBStyleCollection<StructGeneralAttribute, String> getAttributes() { + return attributes; + } + + public StructClass getClassStruct() { + return classStruct; + } + + public boolean containsCode() { + return containsCode; + } +} + + |