Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the way bytecode offsets are tracked. #389

Open
wants to merge 1 commit into
base: develop/1.11.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading