/* * 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 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 lstAttribute = new VBStyleCollection(); int len = in.readUnsignedShort(); for(int i=0;i 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 collinstr = new VBStyleCollection(); int bytecode_version = classStruct.getBytecodeVersion(); for(int i=0;i operands = new ArrayList(); 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 lstHandlers = new ArrayList(); int exception_count = in.readUnsignedShort(); for(int i=0;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 getAttributes() { return attributes; } public StructClass getClassStruct() { return classStruct; } public boolean containsCode() { return containsCode; } }