Skip to content

Commit

Permalink
Refactor the way bytecode offsets are tracked.
Browse files Browse the repository at this point in the history
* Split SimpleInstructionSequence and FullInstructionSequence
* Remove usages of VBStyleCollection
* Instructions now track their own bytecode offsets.
  • Loading branch information
Kroppeb committed May 4, 2024
1 parent fa6317a commit cbc4296
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 270 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
import org.jetbrains.java.decompiler.api.plugin.StatementWriter;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.code.Instruction;
import org.jetbrains.java.decompiler.code.InstructionSequence;
import org.jetbrains.java.decompiler.code.FullInstructionSequence;
import org.jetbrains.java.decompiler.main.*;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
Expand Down Expand Up @@ -1222,21 +1221,19 @@ public static void collectErrorLines(Throwable error, List<String> lines) {
private static void collectBytecode(MethodWrapper wrapper, List<String> lines) throws IOException {
ClassNode classNode = DecompilerContext.getContextProperty(DecompilerContext.CURRENT_CLASS_NODE);
StructMethod method = wrapper.methodStruct;
InstructionSequence instructions = method.getInstructionSequence();
FullInstructionSequence instructions = method.getInstructionSequence();
if (instructions == null) {
method.expandData(classNode.classStruct);
instructions = method.getInstructionSequence();
}
int lastOffset = instructions.getOffset(instructions.length() - 1);
int lastOffset = instructions.getLast().startOffset;
int digits = 8 - Integer.numberOfLeadingZeros(lastOffset) / 4;
ConstantPool pool = classNode.classStruct.getPool();
StructBootstrapMethodsAttribute bootstrap = classNode.classStruct.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);

for (int idx = 0; idx < instructions.length(); idx++) {
int offset = instructions.getOffset(idx);
Instruction instr = instructions.getInstr(idx);
for (var instr : instructions) {
StringBuilder sb = new StringBuilder();
String offHex = Integer.toHexString(offset);
String offHex = Integer.toHexString(instr.startOffset);
sb.append("0".repeat(Math.max(0, digits - offHex.length())));
sb.append(offHex).append(": ");
if (instr.wide) {
Expand All @@ -1261,7 +1258,7 @@ private static void collectBytecode(MethodWrapper wrapper, List<String> lines) t
}
case CodeConstants.GROUP_JUMP -> {
sb.append(' ');
int dest = offset + instr.operand(0);
int dest = instr.startOffset + instr.operand(0);
String destHex = Integer.toHexString(dest);
sb.append("0".repeat(Math.max(0, digits - destHex.length())));
sb.append(destHex);
Expand Down
24 changes: 9 additions & 15 deletions src/org/jetbrains/java/decompiler/code/ExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,15 @@

import org.jetbrains.java.decompiler.main.DecompilerContext;

public class ExceptionHandler {
public int from = 0;
public int to = 0;
public int handler = 0;

public int from_instr = 0;
public int to_instr = 0;
public int handler_instr = 0;

public String exceptionClass = null;

public record ExceptionHandler(
int from,
int to,
int handler,
String exceptionClass
) {
public String toString() {
String new_line_separator = DecompilerContext.getNewLineSeparator();
return "from: " + from + " to: " + to + " handler: " + handler + new_line_separator +
"from_instr: " + from_instr + " to_instr: " + to_instr + " handler_instr: " + handler_instr + new_line_separator +
"exceptionClass: " + exceptionClass + new_line_separator;
String newLineSeparator = DecompilerContext.getNewLineSeparator();
return "from instr: " + this.from + " to instr: " + this.to + " handler instr: " + handler +
newLineSeparator + "exception class: " + this.exceptionClass + newLineSeparator;
}
}
64 changes: 50 additions & 14 deletions src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,61 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.code;

import org.jetbrains.java.decompiler.util.collections.VBStyleCollection;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.util.TextUtil;

import java.util.*;

public class FullInstructionSequence extends InstructionSequence {

// *****************************************************************************
// constructors
// *****************************************************************************
public record FullInstructionSequence(
List<Instruction> instructions,
Map<Integer, Integer> offsetToIndex,
ExceptionTable exceptionTable
) implements Iterable<Instruction> {

public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
super(collinstr);
this.exceptionTable = extable;
public Instruction getInstr(int index) {
return this.instructions.get(index);
}

public int length() {
return this.instructions.size();
}

public boolean isEmpty() {
return this.instructions.isEmpty();
}

public int getIndexByRelOffset(Instruction instruction, int offset) {
int absoluteOffset = instruction.startOffset + offset;
return offsetToIndex.getOrDefault(absoluteOffset, -1);
}

@Override
public Iterator<Instruction> iterator() {
return this.instructions.iterator();
}

public String toString() {
return toString(0);
}

public String toString(int indent) {
String new_line_separator = DecompilerContext.getNewLineSeparator();

// translate raw exception handlers to instr
for (ExceptionHandler handler : extable.getHandlers()) {
handler.from_instr = this.getPointerByAbsOffset(handler.from);
int toIndex = this.getPointerByAbsOffset(handler.to);
handler.to_instr = toIndex == -1 ? this.collinstr.size() : toIndex;
handler.handler_instr = this.getPointerByAbsOffset(handler.handler);
StringBuilder buf = new StringBuilder();

for (var instr : this.instructions) {
buf.append(TextUtil.getIndentString(indent));
buf.append(instr.startOffset);
buf.append(": ");
buf.append(instr);
buf.append(new_line_separator);
}

return buf.toString();
}

public Instruction getLast() {
return this.instructions.get(this.instructions.size() - 1);
}
}
32 changes: 25 additions & 7 deletions src/org/jetbrains/java/decompiler/code/Instruction.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@
import static org.jetbrains.java.decompiler.code.CodeConstants.*;

public class Instruction implements CodeConstants {
public static Instruction create(int opcode, boolean wide, int group, BytecodeVersion bytecodeVersion, int[] operands, int length) {
public static Instruction create(
int opcode,
boolean wide,
int group,
BytecodeVersion bytecodeVersion,
int[] operands,
int startOffset,
int length
) {
if (opcode >= opc_ifeq && opcode <= opc_if_acmpne ||
opcode == opc_ifnull || opcode == opc_ifnonnull ||
opcode == opc_jsr || opcode == opc_jsr_w ||
opcode == opc_goto || opcode == opc_goto_w) {
return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands, length);
return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands, startOffset, length);
}
else if (opcode == opc_tableswitch || opcode == opc_lookupswitch) {
return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands, length);
return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands, startOffset, length);
}
else {
return new Instruction(opcode, group, wide, bytecodeVersion, operands, length);
return new Instruction(opcode, group, wide, bytecodeVersion, operands, startOffset, length);
}
}

Expand All @@ -32,20 +40,30 @@ public static boolean equals(Instruction i1, Instruction i2) {
public final int group;
public final boolean wide;
public final BytecodeVersion bytecodeVersion;
public final int startOffset;
public final int length;

protected final int[] operands;

public Instruction(int opcode, int group, boolean wide, BytecodeVersion bytecodeVersion, int[] operands, int length) {
public Instruction(
int opcode,
int group,
boolean wide,
BytecodeVersion bytecodeVersion,
int[] operands,
int startOffset,
int length
) {
this.opcode = opcode;
this.group = group;
this.wide = wide;
this.bytecodeVersion = bytecodeVersion;
this.operands = operands;
this.startOffset = startOffset;
this.length = length;
}

public void initInstruction(InstructionSequence seq) { }
public void initInstruction(FullInstructionSequence seq) { }

public int operandsCount() {
return operands == null ? 0 : operands.length;
Expand Down Expand Up @@ -85,6 +103,6 @@ public String toString() {
@Override
@SuppressWarnings("MethodDoesntCallSuperMethod")
public Instruction clone() {
return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone(), length);
return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone(), startOffset, length);
}
}
Loading

0 comments on commit cbc4296

Please sign in to comment.