summaryrefslogtreecommitdiff
path: root/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java')
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java392
1 files changed, 392 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java
new file mode 100644
index 000000000000..2b5249f59d5a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.code.*;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.jetbrains.java.decompiler.code.CodeConstants.*;
+
+/*
+ method_info {
+ u2 access_flags;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ attribute_info attributes[attributes_count];
+ }
+*/
+public class StructMethod extends StructMember {
+
+ private static final int[] opr_iconst = {-1, 0, 1, 2, 3, 4, 5};
+ private static final int[] opr_loadstore = {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 = {opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
+ private static final int[] opcs_store = {opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
+
+ private final StructClass classStruct;
+ private final String name;
+ private final String descriptor;
+
+ private boolean containsCode = false;
+ private int localVariables = 0;
+ private int codeLength = 0;
+ private int codeFullLength = 0;
+ private InstructionSequence seq;
+ private boolean expanded = false;
+ private VBStyleCollection<StructGeneralAttribute, String> codeAttributes;
+
+ public StructMethod(DataInputFullStream in, StructClass clStruct) throws IOException {
+ classStruct = clStruct;
+
+ accessFlags = in.readUnsignedShort();
+ int nameIndex = in.readUnsignedShort();
+ int descriptorIndex = in.readUnsignedShort();
+
+ ConstantPool pool = clStruct.getPool();
+ String[] values = pool.getClassElement(ConstantPool.METHOD, clStruct.qualifiedName, nameIndex, descriptorIndex);
+ name = values[0];
+ descriptor = values[1];
+
+ attributes = readAttributes(in, pool);
+ if (codeAttributes != null) {
+ attributes.addAllWithKey(codeAttributes);
+ codeAttributes = null;
+ }
+ }
+
+ @Override
+ protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
+ if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(name)) {
+ if (!classStruct.isOwn()) {
+ // skip code in foreign classes
+ in.discard(8);
+ in.discard(in.readInt());
+ in.discard(8 * in.readUnsignedShort());
+ }
+ else {
+ containsCode = true;
+ in.discard(6);
+ localVariables = in.readUnsignedShort();
+ codeLength = in.readInt();
+ in.discard(codeLength);
+ int excLength = in.readUnsignedShort();
+ in.discard(excLength * 8);
+ codeFullLength = codeLength + excLength * 8 + 2;
+ }
+
+ codeAttributes = readAttributes(in, pool);
+
+ return null;
+ }
+
+ return super.readAttribute(in, pool, name);
+ }
+
+ public void expandData() throws IOException {
+ if (containsCode && !expanded) {
+ byte[] code = classStruct.getLoader().loadBytecode(this, codeFullLength);
+ seq = parseBytecode(new DataInputFullStream(code), codeLength, classStruct.getPool());
+ expanded = true;
+ }
+ }
+
+ public void releaseResources() throws IOException {
+ if (containsCode && expanded) {
+ seq = null;
+ expanded = false;
+ }
+ }
+
+ @SuppressWarnings("AssignmentToForLoopParameter")
+ private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
+ VBStyleCollection<Instruction, Integer> instructions = 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.discard(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.discard(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.discard((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.discard((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] = operands.get(j).intValue();
+ }
+
+ Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
+
+ instructions.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(instructions, 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;
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescriptor() {
+ return descriptor;
+ }
+
+ public boolean containsCode() {
+ return containsCode;
+ }
+
+ public int getLocalVariables() {
+ return localVariables;
+ }
+
+ public InstructionSequence getInstructionSequence() {
+ return seq;
+ }
+}