[java-decompiler] Patch 0005 from ForgeFlower. Convert Exprent.bytecode to a BitMap.

GitOrigin-RevId: 41773788603b20705312f4d6d0a160bfdb1cfc1d
This commit is contained in:
LexManos
2024-10-10 09:55:48 +00:00
committed by intellij-monorepo-bot
parent e6a7029c9e
commit 8407b652c7
81 changed files with 2054 additions and 682 deletions
@@ -4,18 +4,18 @@ package org.jetbrains.java.decompiler.code;
import org.jetbrains.java.decompiler.util.TextUtil;
public class Instruction {
public static Instruction create(int opcode, boolean wide, int group, int bytecodeVersion, int[] operands) {
public static Instruction create(int opcode, boolean wide, int group, int bytecodeVersion, int[] operands, int length) {
if (opcode >= CodeConstants.opc_ifeq && opcode <= CodeConstants.opc_if_acmpne ||
opcode == CodeConstants.opc_ifnull || opcode == CodeConstants.opc_ifnonnull ||
opcode == CodeConstants.opc_jsr || opcode == CodeConstants.opc_jsr_w ||
opcode == CodeConstants.opc_goto || opcode == CodeConstants.opc_goto_w) {
return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands);
return new JumpInstruction(opcode, group, wide, bytecodeVersion, operands, length);
}
else if (opcode == CodeConstants.opc_tableswitch || opcode == CodeConstants.opc_lookupswitch) {
return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands);
return new SwitchInstruction(opcode, group, wide, bytecodeVersion, operands, length);
}
else {
return new Instruction(opcode, group, wide, bytecodeVersion, operands);
return new Instruction(opcode, group, wide, bytecodeVersion, operands, length);
}
}
@@ -31,15 +31,17 @@ public class Instruction {
public final int group;
public final boolean wide;
public final int bytecodeVersion;
public final int length;
protected final int[] operands;
public Instruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
public Instruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands, int length) {
this.opcode = opcode;
this.group = group;
this.wide = wide;
this.bytecodeVersion = bytecodeVersion;
this.operands = operands;
this.length = length;
}
public void initInstruction(InstructionSequence seq) { }
@@ -82,6 +84,6 @@ public class Instruction {
@Override
@SuppressWarnings("MethodDoesntCallSuperMethod")
public Instruction clone() {
return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone());
return create(opcode, wide, group, bytecodeVersion, operands == null ? null : operands.clone(), length);
}
}
@@ -4,8 +4,8 @@ package org.jetbrains.java.decompiler.code;
public class JumpInstruction extends Instruction {
public int destination;
public JumpInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
super(opcode, group, wide, bytecodeVersion, operands);
public JumpInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands, int length) {
super(opcode, group, wide, bytecodeVersion, operands, length);
}
@Override
@@ -6,8 +6,8 @@ public class SwitchInstruction extends Instruction {
private int[] values;
private int defaultDestination;
public SwitchInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands) {
super(opcode, group, wide, bytecodeVersion, operands);
public SwitchInstruction(int opcode, int group, boolean wide, int bytecodeVersion, int[] operands, int length) {
super(opcode, group, wide, bytecodeVersion, operands, length);
}
@Override
@@ -58,4 +58,4 @@ public class SwitchInstruction extends Instruction {
copy.values = values.clone();
return copy;
}
}
}
@@ -149,4 +149,19 @@ public class BasicBlock implements IGraphNode {
public String toString() {
return id + ":" + DecompilerContext.getNewLineSeparator() + seq.toString(0);
}
public int getStartInstruction() {
if (seq.isEmpty()) {
return 0;
}
return originalOffsets.get(0);
}
public int getEndInstruction() {
if (seq.isEmpty()) {
return 0;
}
int end = seq.getLastInstr().length;
return end + originalOffsets.get(size() -1);
}
}
@@ -31,10 +31,10 @@ public class BytecodeMappingTracer {
mapping.putIfAbsent(bytecode_offset, currentSourceLine);
}
public void addMapping(Set<Integer> bytecode_offsets) {
public void addMapping(BitSet bytecode_offsets) {
if (bytecode_offsets != null) {
for (Integer bytecode_offset : bytecode_offsets) {
addMapping(bytecode_offset);
for (int i = bytecode_offsets.nextSetBit(0); i >= 0; i = bytecode_offsets.nextSetBit(i+1)) {
addMapping(i);
}
}
}
@@ -533,7 +533,7 @@ public class NestedClassProcessor {
if (mapParamsToNewVars.containsKey(varIndex)) {
VarVersionPair newVar = mapParamsToNewVars.get(varIndex);
method.varproc.getExternalVars().add(newVar);
return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc);
return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode);
}
}
else if (exprent.type == Exprent.EXPRENT_FIELD) {
@@ -544,7 +544,7 @@ public class NestedClassProcessor {
// mapFieldsToNewVars.containsKey(key)) {
VarVersionPair newVar = mapFieldsToNewVars.get(key);
method.varproc.getExternalVars().add(newVar);
return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc);
return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode);
}
}
@@ -11,8 +11,8 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
import java.util.Set;
public final class ConcatenationHelper {
@@ -125,7 +125,7 @@ public final class ConcatenationHelper {
return createConcatExprent(lstOperands, expr.bytecode);
}
private static Exprent createConcatExprent(List<Exprent> lstOperands, Set<Integer> bytecode) {
private static Exprent createConcatExprent(List<Exprent> lstOperands, BitSet bytecode) {
// build exprent to return
Exprent func = lstOperands.get(0);
@@ -271,7 +271,15 @@ public class ExprProcessor {
for (int i = 0; i < seq.length(); i++) {
Instruction instr = seq.getInstr(i);
Integer offset = block.getOriginalOffset(i);
Set<Integer> offsets = offset >= 0 ? Set.of(offset) : null;
BitSet offsets = null;
if (offset >= 0) {
offsets = new BitSet();
offsets.set(offset);
int end_offset = block.getOriginalOffset(i+1);
if (end_offset > offset) {
offsets.set(offset, end_offset);
}
}
switch (instr.opcode) {
case CodeConstants.opc_aconst_null:
@@ -312,7 +320,7 @@ public class ExprProcessor {
case CodeConstants.opc_fload:
case CodeConstants.opc_dload:
case CodeConstants.opc_aload:
pushEx(stack, exprList, new VarExprent(instr.operand(0), varTypes[instr.opcode - CodeConstants.opc_iload], varProcessor, offset));
pushEx(stack, exprList, new VarExprent(instr.operand(0), varTypes[instr.opcode - CodeConstants.opc_iload], varProcessor, offsets));
break;
case CodeConstants.opc_iaload:
case CodeConstants.opc_laload:
@@ -335,7 +343,10 @@ public class ExprProcessor {
case CodeConstants.opc_astore: {
Exprent value = stack.pop();
int varIndex = instr.operand(0);
VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - CodeConstants.opc_istore], varProcessor, nextMeaningfulOffset(block, i));
if (offsets != null) { //TODO: Figure out why this nulls in some cases
offsets.set(offset, offset + instr.length);
}
VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - CodeConstants.opc_istore], varProcessor, offsets);
exprList.add(new AssignmentExprent(left, value, offsets));
break;
}
@@ -397,7 +408,7 @@ public class ExprProcessor {
pushEx(stack, exprList, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack, offsets));
break;
case CodeConstants.opc_iinc: {
VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor);
VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor, offsets);
int type = instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD;
List<Exprent> operands = Arrays.asList(varExpr.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null));
exprList.add(new AssignmentExprent(varExpr, new FunctionExprent(type, operands, offsets), offsets));
@@ -304,6 +304,7 @@ public class FinallyProcessor {
}
}
final int storeLength = var <= 3 ? 1 : var <= 128 ? 2 : 4;
// disable semaphore at statement exit points
for (BasicBlock block : setTry) {
for (BasicBlock dest : block.getSuccessors()) {
@@ -311,8 +312,8 @@ public class FinallyProcessor {
if (dest != graph.getLast() && !setCopy.contains(dest)) {
// disable semaphore
SimpleInstructionSequence seq = new SimpleInstructionSequence();
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{0}), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{0}, 1), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}, storeLength), -1);
// build a separate block
BasicBlock newBlock = new BasicBlock(++graph.last_id, seq);
@@ -331,11 +332,11 @@ public class FinallyProcessor {
}
// enable semaphore at the statement entrance
BasicBlock newHead = createHeadBlock(graph, 1, var, bytecodeVersion);
BasicBlock newHead = createHeadBlock(graph, 1, var, bytecodeVersion, storeLength);
insertBlockBefore(graph, head, newHead);
// initialize semaphore with false
BasicBlock newHeadInit = createHeadBlock(graph, 0, var, bytecodeVersion);
BasicBlock newHeadInit = createHeadBlock(graph, 0, var, bytecodeVersion, storeLength);
insertBlockBefore(graph, newHead, newHeadInit);
setCopy.add(newHead);
@@ -352,10 +353,10 @@ public class FinallyProcessor {
}
@NotNull
private static BasicBlock createHeadBlock(ControlFlowGraph graph, int value, int var, int bytecodeVersion) {
private static BasicBlock createHeadBlock(ControlFlowGraph graph, int value, int var, int bytecodeVersion, int storeLength) {
SimpleInstructionSequence seq = new SimpleInstructionSequence();
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{value}), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{value}, 1), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecodeVersion, new int[]{var}, storeLength), -1);
return new BasicBlock(++graph.last_id, seq);
}
@@ -92,6 +92,12 @@ public final class MergeHelper {
if (ifedge.getType() == EdgeType.BREAK) {
ifexpr.negateIf();
}
if (stat.getConditionExprent() != null) {
ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode);
}
ifexpr.getCondition().addBytecodeOffsets(lastif.getHeadexprent().bytecode);
stat.setConditionExprent(ifexpr.getCondition());
lastif.getFirst().removeSuccessor(ifedge);
lastif.removeSuccessor(elseedge);
@@ -146,6 +152,12 @@ public final class MergeHelper {
// negate condition (while header)
IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy();
ifexpr.negateIf();
if (stat.getConditionExprent() != null) {
ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode);
}
ifexpr.getCondition().addBytecodeOffsets(firstif.getHeadexprent().bytecode);
stat.setConditionExprent(ifexpr.getCondition());
// remove edges
@@ -184,7 +196,12 @@ public final class MergeHelper {
stat.setLoopType(LoopType.WHILE);
// no need to negate the while condition
stat.setConditionExprent(((IfExprent)firstif.getHeadexprent().copy()).getCondition());
IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy();
if (stat.getConditionExprent() != null) {
ifexpr.getCondition().addBytecodeOffsets(stat.getConditionExprent().bytecode);
}
ifexpr.getCondition().addBytecodeOffsets(firstif.getHeadexprent().bytecode);
stat.setConditionExprent(ifexpr.getCondition());
// remove edges
StatEdge ifedge = firstif.getIfEdge();
@@ -336,9 +353,17 @@ public final class MergeHelper {
stat.setLoopType(LoopType.FOR);
if (hasinit) {
stat.setInitExprent(preData.getExprents().remove(preData.getExprents().size() - 1));
Exprent exp = preData.getExprents().remove(preData.getExprents().size() - 1);
if (stat.getInitExprent() != null) {
exp.addBytecodeOffsets(stat.getInitExprent().bytecode);
}
stat.setInitExprent(exp);
}
stat.setIncExprent(lastData.getExprents().remove(lastData.getExprents().size() - 1));
Exprent exp = lastData.getExprents().remove(lastData.getExprents().size() - 1);
if (stat.getIncExprent() != null) {
exp.addBytecodeOffsets(stat.getIncExprent().bytecode);
}
stat.setIncExprent(exp);
}
if (lastData.getExprents().isEmpty()) {
@@ -641,7 +641,7 @@ public class SimplifyExprentsHelper {
if (stat.type == StatementType.IF && stat.getExprents() == null) {
IfStatement statement = (IfStatement)stat;
Exprent ifHeadExpr = statement.getHeadexprent();
Set<Integer> ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode);
BitSet ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode);
if (statement.iftype == IfStatement.IFTYPE_IFELSE) {
Statement ifStatement = statement.getIfstat();
@@ -18,8 +18,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
@@ -367,6 +365,7 @@ public class StackVarsProcessor {
}
}
/* This workaround isn't needed with Forge's cleanups.
//workaround to preserve variable names
AssignmentExprent assignmentExprent = (AssignmentExprent)exprent;
if (assignmentExprent.getRight() instanceof VarExprent && assignmentExprent.getLeft() instanceof VarExprent leftExp) {
@@ -380,6 +379,7 @@ public class StackVarsProcessor {
}
}
}
*/
if (isSelfReference && vernotreplaced) {
return new int[]{-1, changed};
@@ -495,8 +495,8 @@ public final class ExceptionDeobfuscator {
for (ExceptionRangeCFG range : ranges) {
// add some dummy instructions to prevent optimizing away the empty block
SimpleInstructionSequence seq = new SimpleInstructionSequence();
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_pop, false, CodeConstants.GROUP_GENERAL, bytecode_version, null), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}, 1), -1);
seq.addInstruction(Instruction.create(CodeConstants.opc_pop, false, CodeConstants.GROUP_GENERAL, bytecode_version, null, 1), -1);
BasicBlock dummyBlock = new BasicBlock(++graph.last_id, seq);
@@ -6,6 +6,7 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.BitSet;
import java.util.List;
import java.util.Objects;
@@ -97,4 +98,10 @@ public class AnnotationExprent extends Exprent {
parNames.equals(ann.parNames) &&
parValues.equals(ann.parValues);
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, parValues);
measureBytecode(values);
}
}
@@ -14,7 +14,7 @@ public class ArrayExprent extends Exprent {
private Exprent index;
private final VarType hardType;
public ArrayExprent(Exprent array, Exprent index, VarType hardType, Set<Integer> bytecodeOffsets) {
public ArrayExprent(Exprent array, Exprent index, VarType hardType, BitSet bytecodeOffsets) {
super(EXPRENT_ARRAY);
this.array = array;
this.index = index;
@@ -105,4 +105,11 @@ public class ArrayExprent extends Exprent {
public Exprent getIndex() {
return index;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, array);
measureBytecode(values, index);
measureBytecode(values);
}
}
@@ -3,9 +3,10 @@
*/
package org.jetbrains.java.decompiler.modules.decompiler.exps;
import org.jetbrains.java.decompiler.util.TextBuffer;
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.BitSet;
import java.util.List;
public class AssertExprent extends Exprent {
@@ -39,4 +40,10 @@ public class AssertExprent extends Exprent {
return buffer;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, parameters);
measureBytecode(values);
}
}
@@ -36,7 +36,7 @@ public class AssignmentExprent extends Exprent {
private Exprent right;
private int condType = CONDITION_NONE;
public AssignmentExprent(Exprent left, Exprent right, Set<Integer> bytecodeOffsets) {
public AssignmentExprent(Exprent left, Exprent right, BitSet bytecodeOffsets) {
super(EXPRENT_ASSIGNMENT);
this.left = left;
this.right = right;
@@ -165,6 +165,13 @@ public class AssignmentExprent extends Exprent {
condType == as.getCondType();
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, left);
measureBytecode(values, right);
measureBytecode(values);
}
// *****************************************************************************
// getter and setter methods
// *****************************************************************************
@@ -52,20 +52,20 @@ public class ConstExprent extends Exprent {
private final Object value;
private final boolean boolPermitted;
public ConstExprent(int val, boolean boolPermitted, Set<Integer> bytecodeOffsets) {
public ConstExprent(int val, boolean boolPermitted, BitSet bytecodeOffsets) {
this(guessType(val, boolPermitted), val, boolPermitted, bytecodeOffsets);
}
public ConstExprent(VarType constType, Object value, Set<Integer> bytecodeOffsets) {
public ConstExprent(VarType constType, Object value, BitSet bytecodeOffsets) {
this(constType, value, false, bytecodeOffsets);
}
public ConstExprent(VarType constType, Object value, Set<Integer> bytecodeOffsets, StructMember parent) {
public ConstExprent(VarType constType, Object value, BitSet bytecodeOffsets, StructMember parent) {
this(constType, value, bytecodeOffsets);
this.parent = parent;
}
private ConstExprent(VarType constType, Object value, boolean boolPermitted, Set<Integer> bytecodeOffsets) {
private ConstExprent(VarType constType, Object value, boolean boolPermitted, BitSet bytecodeOffsets) {
super(EXPRENT_CONST);
this.constType = constType;
this.value = value;
@@ -500,6 +500,11 @@ public class ConstExprent extends Exprent {
return boolPermitted;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values);
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -16,9 +16,9 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class ExitExprent extends Exprent {
@@ -29,7 +29,7 @@ public class ExitExprent extends Exprent {
private Exprent value;
private final VarType retType;
public ExitExprent(int exitType, Exprent value, VarType retType, Set<Integer> bytecodeOffsets) {
public ExitExprent(int exitType, Exprent value, VarType retType, BitSet bytecodeOffsets) {
super(EXPRENT_EXIT);
this.exitType = exitType;
this.value = value;
@@ -140,6 +140,13 @@ public class ExitExprent extends Exprent {
return retType;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, value);
measureBytecode(values);
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -16,7 +16,7 @@ import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.*;
import java.util.Map.Entry;
public class Exprent implements IMatchable {
public abstract class Exprent implements IMatchable {
public static final int MULTIPLE_USES = 1;
public static final int SIDE_EFFECTS_FREE = 2;
public static final int BOTH_FLAGS = 3;
@@ -38,7 +38,7 @@ public class Exprent implements IMatchable {
public final int type;
public final int id;
public Set<Integer> bytecode = null; // offsets of bytecode instructions decompiled to this exprent
public BitSet bytecode = null; // offsets of bytecode instructions decompiled to this exprent
public Exprent(int type) {
this.type = type;
@@ -115,14 +115,31 @@ public class Exprent implements IMatchable {
public void replaceExprent(Exprent oldExpr, Exprent newExpr) { }
public void addBytecodeOffsets(Collection<Integer> bytecodeOffsets) {
if (bytecodeOffsets != null && !bytecodeOffsets.isEmpty()) {
public void addBytecodeOffsets(BitSet bytecodeOffsets) {
if (bytecodeOffsets != null) {
if (bytecode == null) {
bytecode = new HashSet<>(bytecodeOffsets);
}
else {
bytecode.addAll(bytecodeOffsets);
bytecode = new BitSet();
}
bytecode.or(bytecodeOffsets);
}
}
public abstract void getBytecodeRange(BitSet values);
protected void measureBytecode(BitSet values) {
if (bytecode != null)
values.or(bytecode);
}
protected static void measureBytecode(BitSet values, Exprent exprent) {
if (exprent != null)
exprent.getBytecodeRange(values);
}
protected static void measureBytecode(BitSet values, List<? extends Exprent> list) {
if (list != null && !list.isEmpty()) {
for (Exprent e : list)
e.getBytecodeRange(values);
}
}
@@ -19,9 +19,9 @@ import org.jetbrains.java.decompiler.util.TextBuffer;
import org.jetbrains.java.decompiler.util.TextUtil;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class FieldExprent extends Exprent {
private final String name;
@@ -30,11 +30,11 @@ public class FieldExprent extends Exprent {
private Exprent instance;
private final FieldDescriptor descriptor;
public FieldExprent(LinkConstant cn, Exprent instance, Set<Integer> bytecodeOffsets) {
public FieldExprent(LinkConstant cn, Exprent instance, BitSet bytecodeOffsets) {
this(cn.elementName, cn.className, instance == null, instance, FieldDescriptor.parseDescriptor(cn.descriptor), bytecodeOffsets);
}
public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, Set<Integer> bytecodeOffsets) {
public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, BitSet bytecodeOffsets) {
super(EXPRENT_FIELD);
this.name = name;
this.classname = classname;
@@ -182,6 +182,12 @@ public class FieldExprent extends Exprent {
return name;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, instance);
measureBytecode(values);
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -184,7 +184,7 @@ public class FunctionExprent extends Exprent {
private VarType implicitType;
private final List<Exprent> lstOperands;
public FunctionExprent(int funcType, ListStack<Exprent> stack, Set<Integer> bytecodeOffsets) {
public FunctionExprent(int funcType, ListStack<Exprent> stack, BitSet bytecodeOffsets) {
this(funcType, new ArrayList<>(), bytecodeOffsets);
if (funcType >= FUNCTION_BIT_NOT && funcType <= FUNCTION_PPI && funcType != FUNCTION_CAST && funcType != FUNCTION_INSTANCEOF) {
@@ -200,7 +200,7 @@ public class FunctionExprent extends Exprent {
}
}
public FunctionExprent(int funcType, List<Exprent> operands, Set<Integer> bytecodeOffsets) {
public FunctionExprent(int funcType, List<Exprent> operands, BitSet bytecodeOffsets) {
super(EXPRENT_FUNCTION);
this.funcType = funcType;
this.lstOperands = operands;
@@ -208,7 +208,7 @@ public class FunctionExprent extends Exprent {
addBytecodeOffsets(bytecodeOffsets);
}
public FunctionExprent(int funcType, Exprent operand, Set<Integer> bytecodeOffsets) {
public FunctionExprent(int funcType, Exprent operand, BitSet bytecodeOffsets) {
this(funcType, new ArrayList<>(1), bytecodeOffsets);
lstOperands.add(operand);
}
@@ -563,6 +563,12 @@ public class FunctionExprent extends Exprent {
this.implicitType = implicitType;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, lstOperands);
measureBytecode(values);
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -9,9 +9,9 @@ import org.jetbrains.java.decompiler.util.ListStack;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class IfExprent extends Exprent {
@@ -64,7 +64,7 @@ public class IfExprent extends Exprent {
private Exprent condition;
public IfExprent(int ifType, ListStack<Exprent> stack, Set<Integer> bytecodeOffsets) {
public IfExprent(int ifType, ListStack<Exprent> stack, BitSet bytecodeOffsets) {
this(null, bytecodeOffsets);
if (ifType <= IF_LE) {
@@ -82,7 +82,7 @@ public class IfExprent extends Exprent {
}
}
private IfExprent(Exprent condition, Set<Integer> bytecodeOffsets) {
private IfExprent(Exprent condition, BitSet bytecodeOffsets) {
super(EXPRENT_IF);
this.condition = condition;
@@ -134,4 +134,10 @@ public class IfExprent extends Exprent {
public void setCondition(Exprent condition) {
this.condition = condition;
}
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, condition);
measureBytecode(values);
}
}
@@ -65,7 +65,7 @@ public class InvocationExprent extends Exprent {
LinkConstant cn,
List<PooledConstant> bootstrapArguments,
ListStack<? extends Exprent> stack,
Set<Integer> bytecodeOffsets) {
BitSet bytecodeOffsets) {
this();
name = cn.elementName;
@@ -612,6 +612,13 @@ public class InvocationExprent extends Exprent {
return bootstrapArguments;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, parameters);
measureBytecode(values, instance);
measureBytecode(values);
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -7,9 +7,9 @@ import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class MonitorExprent extends Exprent {
@@ -19,7 +19,7 @@ public class MonitorExprent extends Exprent {
private final int monType;
private Exprent value;
public MonitorExprent(int monType, Exprent value, Set<Integer> bytecodeOffsets) {
public MonitorExprent(int monType, Exprent value, BitSet bytecodeOffsets) {
super(EXPRENT_MONITOR);
this.monType = monType;
this.value = value;
@@ -74,4 +74,10 @@ public class MonitorExprent extends Exprent {
public Exprent getValue() {
return value;
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, value);
measureBytecode(values);
}
}
@@ -31,11 +31,11 @@ public class NewExprent extends Exprent {
private boolean lambda;
private boolean enumConst;
public NewExprent(VarType newType, ListStack<Exprent> stack, int arrayDim, Set<Integer> bytecodeOffsets) {
public NewExprent(VarType newType, ListStack<Exprent> stack, int arrayDim, BitSet bytecodeOffsets) {
this(newType, getDimensions(arrayDim, stack), bytecodeOffsets);
}
public NewExprent(VarType newType, List<Exprent> lstDims, Set<Integer> bytecodeOffsets) {
public NewExprent(VarType newType, List<Exprent> lstDims, BitSet bytecodeOffsets) {
super(EXPRENT_NEW);
this.newType = newType;
this.lstDims = lstDims;
@@ -435,6 +435,14 @@ public class NewExprent extends Exprent {
Objects.equals(lstArrayElements, ne.lstArrayElements);
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values, lstArrayElements);
measureBytecode(values, lstDims);
measureBytecode(values, constructor);
measureBytecode(values);
}
public InvocationExprent getConstructor() {
return constructor;
}
@@ -11,9 +11,9 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static org.jetbrains.java.decompiler.modules.decompiler.SwitchPatternHelper.isBootstrapSwitch;
@@ -22,7 +22,7 @@ public class SwitchExprent extends Exprent {
private Exprent value;
private List<List<Exprent>> caseValues = new ArrayList<>();
public SwitchExprent(Exprent value, Set<Integer> bytecodeOffsets) {
public SwitchExprent(Exprent value, BitSet bytecodeOffsets) {
super(EXPRENT_SWITCH);
this.value = value;
@@ -124,6 +124,22 @@ public class SwitchExprent extends Exprent {
return Objects.equals(value, sw.getValue());
}
@Override
public void getBytecodeRange(BitSet values) {
if (caseValues != null && !caseValues.isEmpty()) {
for (List<Exprent> l : caseValues) {
if (l != null && !l.isEmpty()) {
for (Exprent e : l) {
if (e != null)
e.getBytecodeRange(values);
}
}
}
}
measureBytecode(values, value);
measureBytecode(values);
}
public Exprent getValue() {
return value;
}
@@ -25,10 +25,7 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.TextBuffer;
import org.jetbrains.java.decompiler.util.TextUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
public class VarExprent extends Exprent {
public static final int STACK_BASE = 10000;
@@ -38,21 +35,20 @@ public class VarExprent extends Exprent {
private VarType varType;
private boolean definition = false;
private final VarProcessor processor;
private final int visibleOffset;
private int version = 0;
private boolean classDef = false;
private boolean stack = false;
public VarExprent(int index, VarType varType, VarProcessor processor) {
this(index, varType, processor, -1);
this(index, varType, processor, null);
}
public VarExprent(int index, VarType varType, VarProcessor processor, int visibleOffset) {
public VarExprent(int index, VarType varType, VarProcessor processor, BitSet bytecode) {
super(EXPRENT_VAR);
this.index = index;
this.varType = varType;
this.processor = processor;
this.visibleOffset = visibleOffset;
this.addBytecodeOffsets(bytecode);
}
@Override
@@ -72,7 +68,7 @@ public class VarExprent extends Exprent {
@Override
public Exprent copy() {
VarExprent var = new VarExprent(index, getVarType(), processor, visibleOffset);
VarExprent var = new VarExprent(index, getVarType(), processor, bytecode);
var.setDefinition(definition);
var.setVersion(version);
var.setClassDef(classDef);
@@ -113,7 +109,7 @@ public class VarExprent extends Exprent {
}
public int getVisibleOffset() {
return visibleOffset;
return bytecode == null ? -1 : bytecode.length();
}
@NotNull
@@ -130,7 +126,7 @@ public class VarExprent extends Exprent {
if (attr != null && processor != null) {
Integer origIndex = processor.getVarOriginalIndex(index);
if (origIndex != null) {
String name = attr.getName(origIndex, visibleOffset);
String name = attr.getName(origIndex, bytecode == null ? -1 : bytecode.nextSetBit(0));
if (name != null && TextUtil.isValidIdentifier(name, method.getBytecodeVersion())) {
return name;
}
@@ -147,6 +143,7 @@ public class VarExprent extends Exprent {
if (processor != null) {
originalIndex = processor.getVarOriginalIndex(index);
}
int visibleOffset = bytecode == null ? -1 : bytecode.length();
if (originalIndex != null) {
// first try from signature
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
@@ -195,6 +192,11 @@ public class VarExprent extends Exprent {
Objects.equals(getVarType(), ve.getVarType()); // FIXME: varType comparison redundant?
}
@Override
public void getBytecodeRange(BitSet values) {
measureBytecode(values);
}
public int getIndex() {
return index;
}
@@ -9,6 +9,7 @@ import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.util.StartEndPair;
import org.jetbrains.java.decompiler.util.TextBuffer;
public class BasicBlockStatement extends Statement {
@@ -58,4 +59,13 @@ public class BasicBlockStatement extends Statement {
public BasicBlock getBlock() {
return block;
}
@Override
public StartEndPair getStartEndRange() {
if (block.size() > 0) {
return new StartEndPair(block.getStartInstruction(), block.getEndInstruction());
} else {
return new StartEndPair(0, 0);
}
}
}
@@ -1,25 +1,21 @@
// Copyright 2000-2020 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.modules.decompiler.stats;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.BitSet;
public class DummyExitStatement extends Statement {
public Set<Integer> bytecode = null; // offsets of bytecode instructions mapped to dummy exit
public BitSet bytecode = null; // offsets of bytecode instructions mapped to dummy exit
public DummyExitStatement() {
super(StatementType.DUMMY_EXIT);
}
public void addBytecodeOffsets(Collection<Integer> bytecodeOffsets) {
public void addBytecodeOffsets(BitSet bytecodeOffsets) {
if (bytecodeOffsets != null && !bytecodeOffsets.isEmpty()) {
if (bytecode == null) {
bytecode = new HashSet<>(bytecodeOffsets);
}
else {
bytecode.addAll(bytecodeOffsets);
bytecode = new BitSet();
}
bytecode.or(bytecodeOffsets);
}
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
import org.jetbrains.java.decompiler.struct.match.IMatchable;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.util.StartEndPair;
import org.jetbrains.java.decompiler.util.TextBuffer;
import org.jetbrains.java.decompiler.util.TextUtil;
@@ -409,6 +410,13 @@ public final class IfStatement extends Statement {
return elseedge;
}
@Override
public StartEndPair getStartEndRange() {
return StartEndPair.join(super.getStartEndRange(),
ifstat != null ? ifstat.getStartEndRange() : null,
elsestat != null ? elsestat.getStartEndRange(): null);
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -3,6 +3,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.stats;
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.util.StartEndPair;
import org.jetbrains.java.decompiler.util.TextBuffer;
public class RootStatement extends Statement {
@@ -26,4 +27,9 @@ public class RootStatement extends Statement {
public DummyExitStatement getDummyExit() {
return dummyExit;
}
}
@Override
public StartEndPair getStartEndRange() {
return StartEndPair.join(first.getStartEndRange(), dummyExit != null ? dummyExit.getStartEndRange() : null);
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.struct.match.IMatchable;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.StartEndPair;
import org.jetbrains.java.decompiler.util.TextBuffer;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
@@ -813,6 +814,40 @@ public abstract class Statement implements IMatchable {
return Integer.toString(id);
}
//TODO: Cleanup/cache?
public void getOffset(BitSet values) {
if (this instanceof DummyExitStatement && ((DummyExitStatement)this).bytecode != null)
values.or(((DummyExitStatement)this).bytecode);
if (this.getExprents() != null) {
for (Exprent e : this.getExprents()) {
e.getBytecodeRange(values);
}
} else {
for (Object obj : this.getSequentialObjects()) {
if (obj == null) {
//Humm? Skip it
} else if (obj instanceof Statement) {
((Statement)obj).getOffset(values);
} else if (obj instanceof Exprent) {
((Exprent)obj).getBytecodeRange(values);
} else {
System.out.println("WTF?" + obj.getClass());
}
}
}
}
private StartEndPair endpoints;
public StartEndPair getStartEndRange() {
if (endpoints == null) {
BitSet set = new BitSet();
getOffset(set);
endpoints = new StartEndPair(set.nextSetBit(0), set.length() - 1);
}
return endpoints;
}
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
@@ -16,6 +16,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.StatEdge.EdgeType;
import org.jetbrains.java.decompiler.modules.decompiler.SwitchHelper;
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.StartEndPair;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.*;
@@ -296,6 +297,17 @@ public final class SwitchStatement extends Statement {
sortEdgesAndNodes();
}
@Override
public StartEndPair getStartEndRange() {
StartEndPair[] sepairs = new StartEndPair[caseStatements.size() + 1];
int i = 0;
sepairs[i++] = super.getStartEndRange();
for (Statement st : caseStatements) {
sepairs[i++] = st.getStartEndRange();
}
return StartEndPair.join(sepairs);
}
public void sortEdgesAndNodes() {
Map<StatEdge, Integer> edgeIndicesMapping = new HashMap<>();
List<StatEdge> firstSuccessors = first.getSuccessorEdges(EdgeType.DIRECT_ALL);
@@ -253,11 +253,11 @@ public class StructMethod extends StructMember {
}
}
Instruction instr = Instruction.create(opcode, wide, group, bytecodeVersion, ops);
i++;
Instruction instr = Instruction.create(opcode, wide, group, bytecodeVersion, ops, i - offset);
instructions.addWithKey(instr, offset);
i++;
}
// initialize exception table
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2017 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.util;
public class StartEndPair {
public final int start;
public final int end;
public StartEndPair(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public boolean equals(Object obj) {
return ((StartEndPair)obj).start == start && ((StartEndPair)obj).end == end;
}
@Override
public int hashCode() {
return start * 31 + end;
}
@Override
public String toString() {
return String.format("%d->%d",start,end);
}
public static StartEndPair join(StartEndPair... pairs) {
int start = Integer.MAX_VALUE;
int end = Integer.MIN_VALUE;
for (StartEndPair pair : pairs) {
if (pair == null) continue;
start = Math.min(start, pair.start);
end = Math.max(end, pair.end);
}
return new StartEndPair(start, end);
}
}
@@ -26,19 +26,51 @@ class i implements bg {
class 'a/a/a/a/e/f/i' {
method '<init> (La/a/a/a/e/f/b;La/a/a/a/c/j;)V' {
0 13
1 13
2 13
3 13
4 13
5 14
6 14
7 14
8 14
9 14
e 15
}
method 'a (La/a/a/a/c/c;La/a/a/a/a/k;Z)V' {
0 18
1 18
2 18
3 18
4 18
5 18
6 18
7 18
8 18
9 18
a 18
b 18
c 18
d 18
e 18
f 18
10 18
11 19
12 19
13 19
14 19
15 19
16 19
17 19
18 19
19 19
1a 19
1b 19
1c 19
1d 19
1e 19
20 20
}
@@ -16,12 +16,18 @@ public abstract class TestAbstractMethods {
class 'pkg/TestAbstractMethods' {
method 'test (I)I' {
0 6
1 6
}
method 'test2 (Ljava/lang/String;)V' {
0 12
1 12
2 12
3 12
4 12
5 12
6 12
7 13
}
}
@@ -15,7 +15,7 @@ public class TestAccessReplace {
public class Inner {
public Inner(String b) {
TestAccessReplace.fooS();// 26
TestAccessReplace.fooS();// 25
TestAccessReplace.this.foo();// 27
TestAccessReplace.fooSParams(1L, 2L);// 28
TestAccessReplace.this.fooParams(1L, 2L);// 29
@@ -43,14 +43,22 @@ class 'pkg/TestAccessReplace' {
class 'pkg/TestAccessReplace$Inner' {
method '<init> (Lpkg/TestAccessReplace;Ljava/lang/String;)V' {
9 17
d 18
0 17
1 17
2 17
3 18
4 19
5 20
c 18
10 19
11 19
14 19
12 19
13 19
17 20
18 20
19 20
1c 20
1a 20
1b 20
1f 21
}
}
@@ -60,10 +68,10 @@ Lines mapping:
20 <-> 8
21 <-> 11
22 <-> 14
26 <-> 18
25 <-> 18
27 <-> 19
28 <-> 20
29 <-> 21
30 <-> 22
Not mapped:
25
26
@@ -28,16 +28,38 @@ class 'pkg/TestAmbiguousCall' {
method 'test ()V' {
7 10
8 11
9 11
a 11
b 11
c 11
d 11
e 11
f 12
10 12
11 12
12 12
13 12
14 12
15 12
1d 13
1e 14
1f 14
20 14
21 14
22 14
23 14
24 14
25 15
26 15
27 15
28 15
29 15
2a 15
2b 15
2c 15
2d 15
2e 15
2f 16
}
}
@@ -28,16 +28,38 @@ class 'pkg/TestAmbiguousCall' {
method 'test ()V' {
7 10
8 11
9 11
a 11
b 11
c 11
d 11
e 11
f 12
10 12
11 12
12 12
13 12
14 12
15 12
1d 13
1e 14
1f 14
20 14
21 14
22 14
23 14
24 14
25 15
26 15
27 15
28 15
29 15
2a 15
2b 15
2c 15
2d 15
2e 15
2f 16
}
}
@@ -46,12 +46,12 @@ public abstract class TestAnonymousClass {
void foo(int var1) throws Exception {
if (var1 > 0) {// 10
I var2 = new I() {
I var2 = new I() {// 11
public void foo() throws Exception {
boolean var1 = true;// 13
boolean var2 = true;// 14
}// 15
};// 11
};
var2.foo();// 17
} else {
System.out.println(5);// 21
@@ -67,6 +67,10 @@ public abstract class TestAnonymousClass {
boolean var1 = true;// 39
}// 40
interface I {
void foo() throws Exception;
}
private static class Inner {
private static Runnable R_I = new Runnable() {
public void run() {
@@ -77,19 +81,15 @@ public abstract class TestAnonymousClass {
}
static class InnerRecursive {
InnerRecursive r;
TestAnonymousClass.InnerRecursive r;
public InnerRecursive(InnerRecursive var1) {
public InnerRecursive(TestAnonymousClass.InnerRecursive var1) {
this.r = var1;// 105
}// 106
void foo() {
}// 110
}
interface I {
void foo() throws Exception;
}
}
class 'pkg/TestAnonymousClass$2' {
@@ -158,10 +158,18 @@ class 'pkg/TestAnonymousClass$1' {
class 'pkg/TestAnonymousClass' {
method 'foo (I)V' {
0 47
1 47
c 53
c 48
d 54
e 54
f 54
10 54
11 54
12 54
16 56
17 56
18 56
19 56
1a 56
1d 59
@@ -182,28 +190,32 @@ class 'pkg/TestAnonymousClass' {
class 'pkg/TestAnonymousClass$Inner$1' {
method 'run ()V' {
0 72
1 72
2 73
3 73
4 74
0 76
1 76
2 77
3 77
4 78
}
}
class 'pkg/TestAnonymousClass$InnerRecursive' {
method '<init> (Lpkg/TestAnonymousClass$InnerRecursive;)V' {
6 82
9 83
4 86
5 86
6 86
7 86
8 86
9 87
}
method 'foo ()V' {
0 86
0 90
}
}
Lines mapping:
10 <-> 48
11 <-> 54
11 <-> 49
13 <-> 51
14 <-> 52
15 <-> 53
@@ -223,9 +235,9 @@ Lines mapping:
53 <-> 18
54 <-> 19
55 <-> 20
66 <-> 73
67 <-> 74
68 <-> 75
66 <-> 77
67 <-> 78
68 <-> 79
75 <-> 24
76 <-> 25
77 <-> 26
@@ -234,9 +246,9 @@ Lines mapping:
91 <-> 37
92 <-> 38
93 <-> 39
105 <-> 83
106 <-> 84
110 <-> 87
105 <-> 87
106 <-> 88
110 <-> 91
Not mapped:
18
104
@@ -65,34 +65,16 @@ class TestAnonymousClassConstructor {
System.out.println("n(): " + s);// 53
}// 54
class InnerPrivateString {
private InnerPrivateString(String s) {
TestAnonymousClassConstructor.n(s);// 58
}// 59
}
class InnerPrivate {
private InnerPrivate(long a, int b) {
TestAnonymousClassConstructor.n(a + "+" + b);// 64
}// 65
}
static class InnerStaticPrivateString {
private InnerStaticPrivateString(String s) {
TestAnonymousClassConstructor.n(s);// 70
}// 71
}
static class InnerStaticPrivate {
private InnerStaticPrivate(long a, int b) {
TestAnonymousClassConstructor.n(a + "+" + b);// 76
}// 77
}
class InnerPublicString {
public InnerPublicString(String s) {
TestAnonymousClassConstructor.n(s);// 82
}// 83
class InnerPrivateString {
private InnerPrivateString(String s) {
TestAnonymousClassConstructor.n(s);// 58
}// 59
}
class InnerPublic {
@@ -101,10 +83,22 @@ class TestAnonymousClassConstructor {
}// 89
}
static class InnerStaticPublicString {
public InnerStaticPublicString(String s) {
TestAnonymousClassConstructor.n(s);// 94
}// 95
class InnerPublicString {
public InnerPublicString(String s) {
TestAnonymousClassConstructor.n(s);// 82
}// 83
}
static class InnerStaticPrivate {
private InnerStaticPrivate(long a, int b) {
TestAnonymousClassConstructor.n(a + "+" + b);// 76
}// 77
}
static class InnerStaticPrivateString {
private InnerStaticPrivateString(String s) {
TestAnonymousClassConstructor.n(s);// 70
}// 71
}
static class InnerStaticPublic {
@@ -112,145 +106,219 @@ class TestAnonymousClassConstructor {
TestAnonymousClassConstructor.n(a + "+" + b);// 100
}// 101
}
static class InnerStaticPublicString {
public InnerStaticPublicString(String s) {
TestAnonymousClassConstructor.n(s);// 94
}// 95
}
}
class 'pkg/TestAnonymousClassConstructor' {
method 'innerPrivateString ()V' {
5 4
6 4
b 6
}
method 'innerPrivate ()V' {
5 9
6 9
7 9
8 9
d 11
}
method 'innerStaticPrivateString ()V' {
5 14
6 14
b 16
}
method 'innerStaticPrivate ()V' {
5 19
6 19
7 19
8 19
d 21
}
method 'innerStaticPrivateStringStatic ()V' {
4 24
5 24
a 26
}
method 'innerStaticPrivateStatic ()V' {
4 29
5 29
6 29
7 29
c 31
}
method 'innerPublicString ()V' {
5 34
6 34
b 36
}
method 'innerPublic ()V' {
5 39
6 39
7 39
8 39
d 41
}
method 'innerStaticPublicString ()V' {
5 44
6 44
b 46
}
method 'innerStaticPublic ()V' {
5 49
6 49
7 49
8 49
d 51
}
method 'innerStaticPublicStringStatic ()V' {
4 54
5 54
a 56
}
method 'innerStaticPublicStatic ()V' {
4 59
5 59
6 59
7 59
c 61
}
method 'n (Ljava/lang/String;)V' {
0 64
1 64
2 64
a 64
b 64
f 64
13 64
14 64
15 64
16 64
17 64
18 64
19 65
}
}
class 'pkg/TestAnonymousClassConstructor$InnerPrivateString' {
method '<init> (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' {
a 69
d 70
}
}
class 'pkg/TestAnonymousClassConstructor$InnerPrivate' {
method '<init> (Lpkg/TestAnonymousClassConstructor;JI)V' {
14 75
1e 75
21 75
24 76
10 69
14 69
15 69
19 69
1a 69
1e 69
1f 69
20 69
21 69
22 69
23 69
24 70
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivateString' {
method '<init> (Ljava/lang/String;)V' {
5 81
8 82
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivate' {
method '<init> (JI)V' {
f 87
18 87
1b 87
1e 88
}
}
class 'pkg/TestAnonymousClassConstructor$InnerPublicString' {
class 'pkg/TestAnonymousClassConstructor$InnerPrivateString' {
method '<init> (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' {
a 93
d 94
9 75
a 75
b 75
c 75
d 76
}
}
class 'pkg/TestAnonymousClassConstructor$InnerPublic' {
method '<init> (Lpkg/TestAnonymousClassConstructor;JI)V' {
14 99
1e 99
21 99
24 100
10 81
14 81
15 81
19 81
1a 81
1e 81
1f 81
20 81
21 81
22 81
23 81
24 82
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPublicString' {
class 'pkg/TestAnonymousClassConstructor$InnerPublicString' {
method '<init> (Lpkg/TestAnonymousClassConstructor;Ljava/lang/String;)V' {
9 87
a 87
b 87
c 87
d 88
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivate' {
method '<init> (JI)V' {
b 93
f 93
10 93
14 93
18 93
19 93
1a 93
1b 93
1c 93
1d 93
1e 94
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPrivateString' {
method '<init> (Ljava/lang/String;)V' {
5 105
8 106
4 99
5 99
6 99
7 99
8 100
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPublic' {
method '<init> (JI)V' {
f 111
18 111
1b 111
1e 112
b 105
f 105
10 105
14 105
18 105
19 105
1a 105
1b 105
1c 105
1d 105
1e 106
}
}
class 'pkg/TestAnonymousClassConstructor$InnerStaticPublicString' {
method '<init> (Ljava/lang/String;)V' {
4 111
5 111
6 111
7 111
8 112
}
}
@@ -281,22 +349,22 @@ Lines mapping:
50 <-> 62
53 <-> 65
54 <-> 66
58 <-> 70
59 <-> 71
64 <-> 76
65 <-> 77
70 <-> 82
71 <-> 83
76 <-> 88
77 <-> 89
82 <-> 94
83 <-> 95
88 <-> 100
89 <-> 101
94 <-> 106
95 <-> 107
100 <-> 112
101 <-> 113
58 <-> 76
59 <-> 77
64 <-> 70
65 <-> 71
70 <-> 100
71 <-> 101
76 <-> 94
77 <-> 95
82 <-> 88
83 <-> 89
88 <-> 82
89 <-> 83
94 <-> 112
95 <-> 113
100 <-> 106
101 <-> 107
Not mapped:
57
63
@@ -6,31 +6,38 @@ import java.io.InputStream;
public class TestAnonymousParams {
void foo(InputStream in, final int a) throws IOException {
FilterInputStream filterInputStream = new FilterInputStream(in) {
FilterInputStream filterInputStream = new FilterInputStream(in) {// 24
public int read() throws IOException {
return a;// 27
}
};// 24
};
filterInputStream.read();// 30
}// 31
}
class 'pkg/TestAnonymousParams$1' {
method 'read ()I' {
1 10
2 10
3 10
4 10
}
}
class 'pkg/TestAnonymousParams' {
method 'foo (Ljava/io/InputStream;I)V' {
a 12
5 8
a 8
b 13
c 13
d 13
e 13
10 14
}
}
Lines mapping:
24 <-> 13
24 <-> 9
27 <-> 11
30 <-> 14
31 <-> 15
@@ -21,6 +21,8 @@ public class TestAnonymousSignature {
class 'pkg/TestAnonymousSignature$1' {
method 'size ()I' {
1 9
2 9
3 9
4 9
}
}
@@ -35,9 +37,17 @@ class 'pkg/TestAnonymousSignature$2' {
class 'pkg/TestAnonymousSignature' {
method 'main ([Ljava/lang/String;)V' {
0 7
1 7
2 7
a 7
b 7
c 7
d 12
e 12
f 12
17 12
18 12
19 12
1a 17
}
}
@@ -16,10 +16,13 @@ class 'pkg/TestAsserts' {
method 'foo ()I' {
0 4
1 4
8 6
9 6
a 6
1b 8
1c 8
1d 8
20 8
21 8
22 8
2d 10
@@ -63,19 +63,39 @@ class 'pkg/TestClashName' {
}
method 'm ()I' {
1 31
4 31
6 32
9 32
c 33
f 33
11 34
14 34
17 35
1a 35
1d 36
1f 36
20 36
0 20
1 20
2 20
3 20
4 20
5 21
6 21
7 21
8 21
9 21
a 21
b 21
c 22
d 22
e 22
f 22
10 23
11 23
12 23
13 23
14 23
15 23
16 23
17 24
18 24
19 24
1a 24
1b 25
1c 25
1d 25
1e 25
1f 25
20 25
}
method 'f ()V' {
@@ -16,14 +16,29 @@ public class TestClassCast {
class 'pkg/TestClassCast' {
method 'test (Ljava/util/List;)V' {
0 7
1 7
3 8
f 9
10 9
11 9
12 9
13 9
14 9
15 9
16 9
18 12
19 12
1a 12
1b 12
1c 12
1d 12
1e 12
1f 12
20 12
21 12
22 12
23 12
24 13
}
}
@@ -19,12 +19,13 @@ public class TestClassFields {
class 'pkg/TestClassFields' {
method '<clinit> ()V' {
11 8
12 8
13 8
14 8
17 8
1b 9
1f 10
22 10
25 11
18 8
19 8
20 9
}
}
@@ -22,12 +22,12 @@ public class TestClassLambda {
public void testLambda1() {
int var1 = (int)Math.random();// 39
Runnable var2 = () -> {
Runnable var2 = () -> {// 40
System.out.println("hello1" + var1);
};// 40
Runnable var3 = () -> {
};
Runnable var3 = () -> {// 41
System.out.println("hello2" + var1);
};// 41
};
}// 42
public void testLambda2() {
@@ -76,51 +76,88 @@ public class TestClassLambda {
public void nestedLambdas() {
byte var1 = 5;// 85
Runnable var2 = () -> {
Runnable var1x = () -> {
Runnable var2 = () -> {// 86
Runnable var1x = () -> {// 87
System.out.println("hello2" + var1);
};// 87
};
System.out.println("hello1" + var1);// 88
};// 86 89
};// 89
}// 90
}
class 'pkg/TestClassLambda' {
method 'lambda$testLambda$0 (ILjava/lang/Integer;)V' {
0 17
2 17
5 17
6 17
7 18
c 18
e 18
11 18
12 18
15 19
0 20
1 20
2 20
3 20
4 20
5 20
6 20
7 21
8 21
9 21
a 21
b 21
c 21
d 21
e 21
f 21
10 21
11 21
12 21
13 21
14 21
15 22
}
method 'testLambda ()V' {
7 14
8 14
e 14
f 14
15 14
16 14
1c 14
1d 14
23 14
24 14
2a 14
2c 14
33 14
35 14
39 14
3c 14
3d 15
40 15
41 15
4a 16
4f 20
7 17
8 17
9 17
a 17
e 17
f 17
10 17
11 17
15 17
16 17
17 17
18 17
1c 17
1d 17
1e 17
1f 17
23 17
24 17
25 17
26 17
2a 17
2b 17
2c 17
2d 17
2e 17
33 17
34 17
35 17
36 17
37 17
39 17
3a 17
3b 17
3c 17
3d 18
3e 18
3f 18
40 18
41 18
42 19
4a 19
4b 19
4c 19
4d 19
4e 19
4f 23
}
method 'lambda$testLambda1$1 (I)V' {
@@ -133,74 +170,143 @@ class 'pkg/TestClassLambda' {
method 'lambda$testLambda1$2 (I)V' {
0 28
1 28
2 28
a 28
b 28
f 28
13 28
14 28
15 28
16 28
17 28
18 28
19 29
}
method 'lambda$testLambda1$2 (I)V' {
0 31
1 31
2 31
a 31
b 31
f 31
13 31
14 31
15 31
16 31
17 31
18 31
19 32
}
method 'testLambda1 ()V' {
0 23
3 23
4 23
b 26
12 29
13 30
0 26
1 26
2 26
3 26
4 26
b 27
12 30
13 33
}
method 'lambda$testLambda2$3 (II)I' {
2 34
5 34
0 37
1 37
2 37
3 37
4 37
5 37
}
method 'testLambda2 ()V' {
5 33
9 36
5 36
6 36
7 36
9 39
}
method 'testLambda3 ()V' {
5 39
9 40
5 42
6 42
7 42
9 43
}
method 'testLambda4 ()V' {
5 43
9 44
5 46
6 46
7 46
9 47
}
method 'testLambda5 ()V' {
0 47
2 47
e 48
12 49
0 50
1 50
2 50
e 51
f 51
10 51
12 52
}
method 'lambda$testLambda6$4 (IILjava/lang/String;)Z' {
2 56
5 56
9 56
d 56
15 56
0 59
1 59
2 59
3 59
4 59
5 59
8 59
9 59
a 59
b 59
c 59
d 59
15 59
}
method 'testLambda6 ()V' {
7 52
9 53
e 53
f 53
10 53
12 54
17 54
18 54
19 54
22 55
28 58
7 55
8 56
9 56
a 56
b 56
c 56
d 56
e 56
f 56
10 56
11 57
12 57
13 57
14 57
15 57
16 57
17 57
18 57
19 57
1a 58
22 58
23 58
24 58
25 58
26 58
28 61
}
method 'testLambda7 ([Ljava/lang/annotation/Annotation;)V' {
1 61
9 61
f 62
0 64
1 64
2 64
3 64
9 64
a 64
b 64
c 64
d 64
f 65
}
method 'reduce (Ljava/util/function/IntBinaryOperator;)Ljava/util/OptionalInt;' {
@@ -209,9 +315,16 @@ class 'pkg/TestClassLambda' {
}
method 'function (Ljava/util/function/Supplier;)Ljava/lang/String;' {
1 69
6 69
9 69
0 72
1 72
2 72
3 72
4 72
5 72
6 72
7 72
8 72
9 72
}
method 'localMax (II)I' {
@@ -220,64 +333,80 @@ class 'pkg/TestClassLambda' {
}
method 'lambda$null$5 (I)V' {
0 80
a 80
13 80
16 80
19 81
0 83
1 83
2 83
a 83
b 83
f 83
13 83
14 83
15 83
16 83
17 83
18 83
19 84
}
method 'lambda$nestedLambdas$6 (I)V' {
6 81
7 82
11 82
1a 82
1d 82
20 83
6 82
7 85
8 85
9 85
11 85
12 85
16 85
1a 85
1b 85
1c 85
1d 85
1e 85
1f 85
20 86
}
method 'nestedLambdas ()V' {
0 77
1 77
8 83
9 84
0 80
1 80
8 81
9 87
}
}
Lines mapping:
29 <-> 15
30 <-> 16
32 <-> 17
33 <-> 18
34 <-> 19
35 <-> 20
36 <-> 21
39 <-> 24
40 <-> 27
41 <-> 30
42 <-> 31
45 <-> 34
46 <-> 37
49 <-> 40
50 <-> 41
53 <-> 44
54 <-> 45
57 <-> 48
58 <-> 49
59 <-> 50
62 <-> 53
63 <-> 54
64 <-> 55
65 <-> 56
66 <-> 59
69 <-> 62
70 <-> 63
73 <-> 66
77 <-> 70
81 <-> 74
85 <-> 78
86 <-> 84
87 <-> 82
88 <-> 83
89 <-> 84
90 <-> 85
29 <-> 18
30 <-> 19
32 <-> 20
33 <-> 21
34 <-> 22
35 <-> 23
36 <-> 24
39 <-> 27
40 <-> 28
41 <-> 31
42 <-> 34
45 <-> 37
46 <-> 40
49 <-> 43
50 <-> 44
53 <-> 47
54 <-> 48
57 <-> 51
58 <-> 52
59 <-> 53
62 <-> 56
63 <-> 57
64 <-> 58
65 <-> 59
66 <-> 62
69 <-> 65
70 <-> 66
73 <-> 69
77 <-> 73
81 <-> 77
85 <-> 81
86 <-> 82
87 <-> 83
88 <-> 86
89 <-> 87
90 <-> 88
@@ -78,41 +78,68 @@ public class TestClassLoop {
class 'pkg/TestClassLoop' {
method 'testSimpleInfinite ()V' {
0 5
1 5
2 5
3 5
4 5
5 5
}
method 'testFinally ()V' {
0 10
1 10
2 10
3 10
4 10
d 10
e 14
f 14
1a 15
26 18
27 18
28 18
29 18
2a 18
2b 18
}
method 'testFinallyContinue ()V' {
0 24
1 24
2 24
3 24
4 24
d 24
e 29
f 29
10 29
11 29
12 29
13 29
25 32
26 32
2a 33
2b 33
2c 33
2d 33
2e 33
2f 33
30 33
31 33
32 34
37 39
38 39
39 39
3a 39
3b 39
3c 39
}
method 'testWhileCombined (Ljava/lang/String;)I' {
0 44
1 44
2 44
3 44
4 44
5 45
6 45
@@ -120,29 +147,58 @@ class 'pkg/TestClassLoop' {
8 46
9 47
a 47
b 47
c 48
d 48
e 48
f 49
10 49
11 49
12 51
13 51
14 51
15 51
16 51
17 51
1a 52
1b 52
1c 52
1d 52
1e 52
1f 52
20 52
21 53
22 53
23 53
24 53
25 53
28 54
29 54
2a 54
2e 56
2f 56
30 56
31 56
32 56
35 60
36 60
3d 61
3e 61
42 61
43 64
44 64
45 64
46 65
47 65
48 65
4b 66
4e 69
4f 69
50 51
51 51
52 51
56 73
57 73
58 73
}
}
@@ -4,34 +4,45 @@ public class TestClassNestedInitializer {
public String secret;
public void test() {
TestClassNestedInitializer var1 = new TestClassNestedInitializer() {
TestClassNestedInitializer var1 = new TestClassNestedInitializer() {// 22
{
this.secret = "one";
}
};// 22
};
System.out.println(var1.secret);// 23
}// 24
}
class 'pkg/TestClassNestedInitializer$1' {
method '<init> (Lpkg/TestClassNestedInitializer;)V' {
9 8
a 8
b 8
c 8
d 8
e 8
f 9
}
}
class 'pkg/TestClassNestedInitializer' {
method 'test ()V' {
8 10
8 6
9 11
a 11
b 11
c 11
d 11
e 11
f 11
10 11
11 11
12 11
13 12
}
}
Lines mapping:
22 <-> 11
22 <-> 7
23 <-> 12
24 <-> 13
@@ -49,8 +49,13 @@ public class TestClassSimpleBytecodeMapping {
class 'pkg/TestClassSimpleBytecodeMapping$1' {
method 'run ()V' {
0 7
1 7
2 7
3 7
4 7
5 7
6 7
7 7
8 8
}
}
@@ -58,40 +63,77 @@ class 'pkg/TestClassSimpleBytecodeMapping$1' {
class 'pkg/TestClassSimpleBytecodeMapping' {
method 'test ()I' {
0 4
1 4
2 4
3 4
4 4
5 4
6 4
7 4
8 5
11 5
12 5
13 5
14 10
15 10
16 10
17 10
18 10
19 10
1a 11
1b 11
1c 11
1d 11
1e 11
1f 11
22 12
23 12
24 12
25 12
26 12
27 12
28 12
29 12
2a 13
2b 13
2c 15
2d 15
2e 15
2f 15
30 15
31 15
32 15
33 15
34 16
35 16
}
method 'test2 (Ljava/lang/String;)V' {
0 22
1 22
2 22
3 22
10 23
11 24
12 24
13 24
15 24
23 26
24 26
25 26
26 26
27 26
28 26
2e 29
}
method 'run (Ljava/lang/Runnable;)V' {
0 32
1 32
2 32
3 32
4 32
5 32
6 33
}
}
@@ -99,8 +141,13 @@ class 'pkg/TestClassSimpleBytecodeMapping' {
class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' {
method 'print ()V' {
0 37
1 37
2 37
3 37
4 37
5 37
6 37
7 37
8 38
}
}
@@ -108,8 +155,13 @@ class 'pkg/TestClassSimpleBytecodeMapping$InnerClass' {
class 'pkg/TestClassSimpleBytecodeMapping$InnerClass2' {
method 'print ()V' {
0 43
1 43
2 43
3 43
4 43
5 43
6 43
7 43
8 44
}
}
@@ -15,12 +15,20 @@ public class TestClassSwitch {
class 'pkg/TestClassSwitch' {
method 'testCaseOrder (I)V' {
0 4
1 4
1c 10
1d 10
1e 10
1f 10
20 10
21 10
22 10
23 10
24 12
25 6
26 6
27 6
28 6
29 6
2c 8
@@ -53,29 +53,41 @@ class 'pkg/TestClassTypes' {
0 7
1 7
2 8
3 8
4 8
5 8
6 9
7 9
8 9
9 9
a 9
b 9
c 9
d 9
10 10
11 10
15 11
16 11
17 11
18 11
19 11
1a 11
1b 11
1c 11
1f 12
20 12
21 15
22 15
23 15
26 16
27 16
28 16
29 16
2c 19
}
method 'testBit (I)Z' {
0 22
1 22
2 22
3 22
@@ -84,30 +96,59 @@ class 'pkg/TestClassTypes' {
}
method 'testSwitchConsts (I)V' {
0 26
1 26
2c 28
2d 28
2e 28
2f 28
30 28
31 28
32 28
33 28
34 29
37 31
38 31
39 31
3a 31
3b 31
3c 31
3d 31
3e 31
3f 32
42 35
43 35
44 35
45 35
46 35
47 35
4a 38
}
method 'testAssignmentType (Ljava/util/List;)V' {
0 41
1 41
3 42
f 43
10 43
11 43
12 43
13 43
14 43
15 43
16 43
18 46
19 46
1a 46
1b 46
1c 46
1d 46
1e 46
1f 46
20 46
21 46
22 46
23 46
24 47
}
}
@@ -42,20 +42,32 @@ class 'pkg/TestClassVar' {
method 'testFieldSSAU ()V' {
0 7
1 7
2 7
3 7
4 7
5 7
8 9
9 9
a 9
b 9
1e 11
1f 11
20 11
21 11
22 11
26 12
27 12
28 12
29 12
2e 7
34 18
}
method 'testFieldSSAU1 ()Ljava/lang/Long;' {
4 21
6 21
7 21
8 21
b 21
f 21
13 21
@@ -64,17 +76,29 @@ class 'pkg/TestClassVar' {
method 'testComplexPropagation ()V' {
0 25
1 25
2 27
3 27
4 27
5 27
8 29
9 29
a 29
b 29
c 29
d 29
10 29
11 29
14 29
1c 32
1f 33
22 33
28 37
15 29
16 29
1a 33
1b 33
1c 33
1f 34
20 34
21 34
22 34
28 38
}
}
@@ -15,11 +15,16 @@ class TestCodeConstructs {
class 'pkg/TestCodeConstructs' {
method 'expressions ()V' {
7 6
8 6
9 6
b 7
}
method 'fieldIncrement ()Ljava/lang/Integer;' {
4 10
6 10
7 10
8 10
b 10
12 10
}
@@ -23,22 +23,44 @@ class TestDebugSymbols {
class 'pkg/TestDebugSymbols' {
method 'm ()I' {
0 4
1 4
2 4
3 5
4 5
5 5
6 5
7 6
8 6
9 6
a 6
b 6
c 6
d 6
e 7
f 7
10 7
11 7
12 7
13 7
14 7
1c 8
20 8
21 8
25 8
29 8
2a 8
2e 8
2f 8
33 8
34 8
38 8
39 8
3d 8
3e 8
3f 8
40 8
41 8
42 8
43 8
}
@@ -50,13 +50,20 @@ class 'pkg/TestEnum' {
method '<init> (Ljava/lang/String;I)V' {
3 20
4 20
5 20
6 20
7 20
8 20
9 21
}
method '<init> (Ljava/lang/String;ILjava/lang/String;Lpkg/TestEnum$Type;)V' {
6 24
7 24
8 24
9 24
a 24
b 25
}
}
@@ -21,7 +21,10 @@ class 'pkg/TestExtendingSubclass$Subclass1' {
class 'pkg/TestExtendingSubclass$Subclass2' {
method '<init> (Lpkg/TestExtendingSubclass;Ljava/lang/String;)V' {
7 10
8 10
9 10
a 10
b 11
}
}
@@ -32,54 +32,91 @@ public class TestIffSimplification {
class 'pkg/TestIffSimplification' {
method 'simpleIff (Z[I)I' {
0 4
1 4
4 4
5 4
6 4
a 4
b 4
c 4
d 4
}
method 'simpleIf (Z[I)I' {
0 8
1 8
4 8
5 8
6 8
8 8
9 8
a 8
}
method 'nestedIf (ZZ[I)I' {
0 12
1 12
4 13
5 13
8 13
9 13
a 13
c 13
d 13
e 13
10 15
11 15
12 15
13 15
}
method 'compareTo (IIBBDDII)I' {
0 20
1 20
2 20
5 21
6 21
7 21
a 21
e 21
f 21
10 22
11 22
12 22
13 22
16 23
17 23
18 23
19 23
1c 23
20 23
21 23
22 24
23 24
24 24
25 24
26 24
27 24
28 24
29 24
2a 24
2b 24
2c 24
2d 24
2e 24
31 25
32 25
33 25
34 25
35 25
38 25
3c 25
3d 25
3e 27
3f 27
40 27
41 27
42 27
43 27
46 27
@@ -21,10 +21,19 @@ public final class TestIllegalVarName {
class 'pkg/TestIllegalVarName' {
method 'm (Ljava/lang/String;I)Ljava/lang/String;' {
0 16
1 16
2 16
3 16
4 16
5 16
d 17
11 17
12 17
16 17
1a 17
1b 17
1c 17
1d 17
}
}
@@ -13,22 +13,23 @@ class TestInnerClassConstructor {
System.out.println("n(): " + var1);// 13
}// 14
final class Inner {
private Inner(String var2) {
TestInnerClassConstructor.this.n(var2);// 18
}// 19
}
private class Another {
private Another(int var2, int var3) {
TestInnerClassConstructor.this.n(var2 + "+" + var3);// 24
}// 25
}
final class Inner {
private Inner(String var2) {
TestInnerClassConstructor.this.n(var2);// 18
}// 19
}
}
class 'pkg/TestInnerClassConstructor' {
method 'l ()V' {
5 4
6 4
c 5
}
@@ -40,26 +41,46 @@ class 'pkg/TestInnerClassConstructor' {
method 'n (Ljava/lang/String;)V' {
0 12
1 12
2 12
a 12
b 12
f 12
13 12
14 12
15 12
16 12
17 12
18 12
19 13
}
}
class 'pkg/TestInnerClassConstructor$Inner' {
method '<init> (Lpkg/TestInnerClassConstructor;Ljava/lang/String;)V' {
b 17
e 18
}
}
class 'pkg/TestInnerClassConstructor$Another' {
method '<init> (Lpkg/TestInnerClassConstructor;II)V' {
15 23
1e 23
21 23
24 24
9 17
11 17
15 17
16 17
1a 17
1e 17
1f 17
20 17
21 17
22 17
23 17
24 18
}
}
class 'pkg/TestInnerClassConstructor$Inner' {
method '<init> (Lpkg/TestInnerClassConstructor;Ljava/lang/String;)V' {
9 23
a 23
b 23
c 23
d 23
e 24
}
}
@@ -70,10 +91,10 @@ Lines mapping:
10 <-> 10
13 <-> 13
14 <-> 14
18 <-> 18
19 <-> 19
24 <-> 24
25 <-> 25
18 <-> 24
19 <-> 25
24 <-> 18
25 <-> 19
Not mapped:
17
23
@@ -33,9 +33,9 @@ public class TestInnerLocal {
class Inner1 {
final String x;
public Inner1(@Deprecated String x) {
this.x = x;// 32
}// 33
public Inner1(String var2) {
this.x = var2;// 46
}// 47
}
static class Inner1Static {
@@ -57,76 +57,103 @@ public class TestInnerLocal {
class 'pkg/TestInnerLocal$1Inner' {
method '<init> (Ljava/lang/String;)V' {
6 8
9 9
4 6
5 6
6 6
7 6
8 6
9 7
}
}
class 'pkg/TestInnerLocal' {
method 'testStaticMethod ()V' {
4 12
e 13
18 14
1e 15
4 10
5 10
e 11
f 11
18 12
19 12
1e 13
}
method 'testMethod ()V' {
5 26
f 27
1a 28
24 29
2a 30
5 24
6 24
f 25
10 25
1a 26
1b 26
24 27
25 27
2a 28
}
}
class 'pkg/TestInnerLocal$2Inner' {
method '<init> (Lpkg/TestInnerLocal;Ljava/lang/String;)V' {
b 22
e 23
class 'TestInnerLocal$2Inner' {
method '<init> (LTestInnerLocal;Ljava/lang/String;)V' {
9 20
a 20
b 20
c 20
d 20
e 21
}
}
class 'pkg/TestInnerLocal$Inner1' {
method '<init> (Lpkg/TestInnerLocal;Ljava/lang/String;)V' {
b 36
e 37
class 'TestInnerLocal$Inner1' {
method '<init> (LTestInnerLocal;Ljava/lang/String;)V' {
9 34
a 34
b 34
c 34
d 34
e 35
}
}
class 'pkg/TestInnerLocal$Inner1Static' {
class 'TestInnerLocal$Inner1Static' {
method '<init> (Ljava/lang/String;)V' {
6 44
9 45
4 42
5 42
6 42
7 42
8 42
9 43
}
}
class 'pkg/TestInnerLocal$Inner1Static$Inner2Static' {
method '<init> (Ljava/lang/String;)V' {
6 51
9 52
4 49
5 49
6 49
7 49
8 49
9 50
}
}
Lines mapping:
8 <-> 9
9 <-> 10
11 <-> 13
12 <-> 14
13 <-> 15
14 <-> 16
20 <-> 23
21 <-> 24
23 <-> 27
24 <-> 28
25 <-> 29
26 <-> 30
27 <-> 31
32 <-> 37
33 <-> 38
39 <-> 45
40 <-> 46
45 <-> 52
46 <-> 53
22 <-> 7
23 <-> 8
25 <-> 11
26 <-> 12
27 <-> 13
28 <-> 14
34 <-> 21
35 <-> 22
37 <-> 25
38 <-> 26
39 <-> 27
40 <-> 28
41 <-> 29
46 <-> 35
47 <-> 36
53 <-> 43
54 <-> 44
59 <-> 50
60 <-> 51
Not mapped:
7
19
@@ -28,54 +28,91 @@ public class TestInnerSignature<A, B, C> {
B b;
C c;
public InnerStatic(A a, @Deprecated B b, C c) {
this.a = a;// 32
this.b = b;// 33
this.c = c;// 34
}// 35
public InnerStatic(A var1, B var2, C var3) {
this.a = var1;// 46
this.b = var2;// 47
this.c = var3;// 48
}// 49
}
}
class 'pkg/TestInnerSignature' {
method '<init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' {
6 8
b 9
10 10
13 11
4 6
5 6
6 6
7 6
8 6
9 7
a 7
b 7
c 7
d 7
e 8
f 8
10 8
11 8
12 8
13 9
}
}
class 'pkg/TestInnerSignature$Inner' {
method '<init> (Lpkg/TestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' {
b 19
10 20
16 21
19 22
class 'TestInnerSignature$Inner' {
method '<init> (LTestInnerSignature;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' {
9 17
a 17
b 17
c 17
d 17
e 18
f 18
10 18
11 18
12 18
13 19
14 19
15 19
16 19
17 19
18 19
19 20
}
}
class 'pkg/TestInnerSignature$InnerStatic' {
class 'TestInnerSignature$InnerStatic' {
method '<init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V' {
6 31
b 32
10 33
13 34
4 29
5 29
6 29
7 29
8 29
9 30
a 30
b 30
c 30
d 30
e 31
f 31
10 31
11 31
12 31
13 32
}
}
Lines mapping:
9 <-> 9
10 <-> 10
11 <-> 11
12 <-> 12
20 <-> 20
21 <-> 21
22 <-> 22
23 <-> 23
32 <-> 32
33 <-> 33
34 <-> 34
35 <-> 35
23 <-> 7
24 <-> 8
25 <-> 9
26 <-> 10
34 <-> 18
35 <-> 19
36 <-> 20
37 <-> 21
46 <-> 30
47 <-> 31
48 <-> 32
49 <-> 33
Not mapped:
8
19
@@ -12,12 +12,25 @@ public class TestJava9StringConcat {
class 'java9/TestJava9StringConcat' {
method 'test1 (Ljava/lang/String;I)Ljava/lang/String;' {
0 4
1 4
2 4
3 4
4 4
5 4
6 4
7 4
}
method 'test2 (Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;' {
0 8
1 8
2 8
3 8
4 8
5 8
6 8
7 8
8 8
}
}
@@ -16,12 +16,12 @@ import kotlin.collections.CollectionsKt;
public final class TestKotlinConstructorKt {
private static final List<Mapping> foo(Collection<String> list) {
Iterable $receiver$iv = (Iterable)list;// 2
Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10)));// 10
Iterator var4 = $receiver$iv.iterator();// 11
Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver$iv, 10)));
Iterator var4 = $receiver$iv.iterator();// 10 11
while(var4.hasNext()) {
Object item$iv$iv = var4.next();
String it = (String)item$iv$iv;// 12
String it = (String)item$iv$iv;
Mapping var10000 = new Mapping;
if (it == null) {// 3
throw new TypeCastException("null cannot be cast to non-null type kotlin.String");
@@ -29,7 +29,7 @@ public final class TestKotlinConstructorKt {
var10000.<init>((String)it);
Mapping var11 = var10000;
destination$iv$iv.add(var11);
destination$iv$iv.add(var11);// 12
}
return CollectionsKt.toList((Iterable)((List)destination$iv$iv));// 4 13
@@ -38,29 +38,84 @@ public final class TestKotlinConstructorKt {
class 'TestKotlinConstructorKt' {
method 'foo (Ljava/util/Collection;)Ljava/util/List;' {
0 17
1 17
2 17
3 17
4 17
6 19
c 18
d 18
e 18
f 18
10 18
11 18
15 18
16 18
17 18
18 18
1b 19
1c 19
1d 19
1e 19
1f 19
20 19
21 19
22 21
23 21
24 21
25 21
26 21
27 21
28 21
2c 22
2d 22
2e 22
2f 22
30 22
31 22
32 22
33 22
34 22
35 31
36 23
37 23
38 23
39 23
3a 23
3b 23
3c 23
43 25
44 25
46 25
4d 26
4e 26
52 26
53 29
54 29
55 29
56 29
57 29
58 29
59 30
5a 30
5d 31
5e 31
5f 31
60 31
61 31
62 31
63 31
68 34
69 34
6a 34
6b 34
6c 34
6d 34
6e 34
6f 34
70 34
71 34
72 34
}
}
@@ -69,7 +124,7 @@ Lines mapping:
2 <-> 18
3 <-> 26
4 <-> 35
10 <-> 19
10 <-> 20
11 <-> 20
12 <-> 24
12 <-> 32
13 <-> 35
@@ -26,40 +26,104 @@ public class TestLocalsNames {
class 'pkg/TestLocalsNames' {
method 'rename (Ljava/io/File;Z)V' {
0 6
1 6
2 6
3 6
4 6
7 7
8 7
9 7
a 7
b 8
c 8
d 8
e 8
f 8
10 8
11 9
12 9
13 9
14 9
17 10
18 10
19 10
1a 12
1b 12
1c 12
1d 12
1e 12
1f 12
20 12
21 12
24 13
25 13
26 13
27 13
28 13
29 13
2a 13
36 14
37 14
38 14
39 14
3a 14
3e 14
3f 14
43 14
44 14
45 14
49 14
4a 14
51 16
52 16
53 16
54 16
55 16
56 16
57 16
66 16
67 16
6b 16
6c 16
70 16
71 16
75 16
76 16
7a 16
7b 16
7c 16
81 12
82 12
83 12
87 19
88 19
89 19
8a 19
8b 19
8c 19
8d 19
8e 20
8f 20
90 20
98 20
99 20
9d 20
9e 20
a2 20
a3 20
a7 20
a8 20
a9 20
aa 20
ab 20
ac 20
ad 20
b1 20
b2 20
b6 20
b7 20
b8 20
b9 20
bc 23
}
@@ -13,8 +13,14 @@ public class TestLocalsSignature {
class 'pkg/TestLocalsSignature' {
method 'main ([Ljava/lang/String;)V' {
7 7
8 8
9 8
a 8
b 8
c 8
d 8
e 8
f 8
11 9
}
}
@@ -22,9 +22,14 @@ class TestMemberAnnotations {
class 'pkg/TestMemberAnnotations' {
method 'f (I)I' {
0 13
1 13
2 13
3 13
4 13
5 13
6 13
7 13
8 13
9 13
}
@@ -14,9 +14,19 @@ public class TestMethodReferenceSameName {
class 'TestMethodReferenceSameName' {
method 'foo ()V' {
0 4
1 4
e 5
13 6
2 4
3 4
5 5
6 5
7 5
e 6
f 6
10 6
11 6
12 6
13 7
}
}
@@ -172,143 +172,178 @@ public class TestPrimitives {
class 'pkg/TestPrimitives' {
method 'printAll ()V' {
1 6
2 6
6 7
8 7
c 8
f 8
13 9
15 9
19 10
1c 10
20 11
22 11
26 12
29 12
2d 13
2f 13
33 14
37 14
3b 15
40 15
44 16
4a 16
4e 17
52 17
56 18
5b 18
5f 19
65 19
69 20
6e 20
72 21
78 21
7c 22
81 22
85 23
87 23
8a 23
8d 23
91 24
93 24
96 24
99 24
9d 25
9f 25
a2 25
a5 25
a9 26
ab 26
ae 26
b1 26
b5 27
b7 27
ba 27
bd 27
c1 28
c3 28
c6 28
c9 28
cd 29
cf 29
d2 29
d5 29
dd 30
e2 30
e5 30
ea 31
ed 31
f0 31
f5 32
f8 32
fb 32
fe 33
101 33
10a 33
10b 33
111 33
112 33
118 33
11b 33
121 33
123 33
129 33
12b 33
131 33
134 33
138 33
13c 34
13f 34
148 34
14b 34
152 34
155 34
15c 34
15f 34
166 34
169 34
16d 34
175 35
176 35
178 35
17b 35
17d 35
180 35
182 35
185 35
18f 36
194 36
19a 36
19f 36
1a5 36
1aa 36
1b0 36
1b5 36
1c1 37
1c3 37
1c6 37
1c9 37
1cb 37
1ce 37
1d1 37
1d3 37
1d6 37
1d9 37
1db 37
1de 37
1e1 37
1e3 37
1e6 37
1e9 37
1eb 37
1ee 37
1f1 37
1f3 37
1f6 37
1fd 37
202 37
209 38
0 4
1 4
2 4
3 4
4 4
5 5
6 5
7 5
8 5
9 5
a 5
b 6
c 6
d 6
e 6
f 6
10 6
11 6
12 7
13 7
14 7
15 7
16 7
17 7
18 8
19 8
1a 8
1b 8
1c 8
1d 8
1e 8
1f 9
20 9
21 9
22 9
23 9
24 9
25 10
26 10
27 10
28 10
29 10
2a 10
2b 10
2c 11
2d 11
2e 11
2f 11
30 11
31 11
32 12
33 12
37 12
3b 13
40 13
44 14
4a 14
4e 15
52 15
56 16
5b 16
5f 17
65 17
69 18
6e 18
72 19
78 19
7c 20
81 20
85 21
87 21
8a 21
8d 21
91 22
93 22
96 22
99 22
9d 23
9f 23
a2 23
a5 23
a9 24
ab 24
ae 24
b1 24
b5 25
b7 25
ba 25
bd 25
c1 26
c3 26
c6 26
c9 26
cd 27
cf 27
d2 27
d5 27
dd 28
e2 28
e5 28
ea 29
ed 29
f0 29
f5 30
f8 30
fb 30
fe 31
101 31
10a 31
10b 31
111 31
112 31
118 31
11b 31
121 31
123 31
129 31
12b 31
131 31
134 31
138 31
13c 32
13f 32
148 32
14b 32
152 32
155 32
15c 32
15f 32
166 32
169 32
16d 32
175 33
176 33
178 33
17b 33
17d 33
180 33
182 33
185 33
18f 34
194 34
19a 34
19f 34
1a5 34
1aa 34
1b0 34
1b5 34
1c1 35
1c3 35
1c6 35
1c9 35
1cb 35
1ce 35
1d1 35
1d3 35
1d6 35
1d9 35
1db 35
1de 35
1e1 35
1e3 35
1e6 35
1e9 35
1eb 35
1ee 35
1f1 35
1f3 35
1f6 35
1fd 35
202 35
209 36
}
method '<init> (ZBSIJFDC)V' {
@@ -10,7 +10,10 @@ public class TestStaticNameClash {
class 'pkg/TestStaticNameClash' {
method 'setProperty (Ljava/lang/String;)V' {
0 6
1 6
2 6
3 6
4 7
}
}
@@ -12,16 +12,29 @@ public class TestStringConcat {
class 'pkg/TestStringConcat' {
method 'test1 (Ljava/lang/String;I)Ljava/lang/String;' {
7 4
b 4
f 4
10 4
11 4
12 4
}
method 'test2 (Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;' {
7 8
8 8
c 8
10 8
11 8
15 8
19 8
1a 8
1e 8
22 8
23 8
27 8
28 8
29 8
2a 8
}
}
@@ -12,20 +12,39 @@ public class TestStringLiterals {
class 'pkg/TestStringLiterals' {
method 'main ([Ljava/lang/String;)V' {
0 4
1 4
2 4
9 5
a 5
e 5
f 5
13 5
14 5
18 5
19 5
1d 5
1e 5
22 5
23 5
28 5
29 5
2e 5
2f 5
31 5
32 6
33 6
34 6
35 6
36 6
37 6
38 6
39 7
3a 7
3b 7
3c 7
3d 7
3e 7
3f 7
40 8
}
}
@@ -50,6 +50,7 @@ public class TestSwitchOnEnum {
class 'pkg/TestSwitchOnEnum' {
method 'testSOE (Ljava/util/concurrent/TimeUnit;)I' {
3 8
8 8
24 10
25 10
@@ -16,16 +16,26 @@ public class TestSynchronizedMapping {
class 'pkg/TestSynchronizedMapping' {
method 'test (I)I' {
0 4
3 4
4 5
5 5
6 5
8 6
12 8
13 8
14 8
15 8
}
method 'test2 (Ljava/lang/String;)V' {
0 12
1 12
2 12
3 12
4 12
5 12
6 12
7 13
}
}
@@ -4,6 +4,16 @@ class TestSyntheticAccess {
private static int s;
private int i;
private class Assigner {
void assignI(int var1) {
TestSyntheticAccess.this.i = var1;// 32
}// 33
void assignS(int var1) {
TestSyntheticAccess.s = var1;// 36
}// 37
}
private class Incrementer {
void orI() {
TestSyntheticAccess.this.i = TestSyntheticAccess.this.i | 1;// 10
@@ -25,73 +35,86 @@ class TestSyntheticAccess {
TestSyntheticAccess.s--;// 26
}// 27
}
}
private class Assigner {
void assignI(int var1) {
TestSyntheticAccess.this.i = var1;// 32
}// 33
class 'pkg/TestSyntheticAccess$Assigner' {
method 'assignI (I)V' {
1 8
2 8
3 8
4 8
5 8
9 9
}
void assignS(int var1) {
TestSyntheticAccess.s = var1;// 36
}// 37
method 'assignS (I)V' {
0 12
2 12
3 12
4 12
5 13
}
}
class 'pkg/TestSyntheticAccess$Incrementer' {
method 'orI ()V' {
8 8
b 8
d 8
11 9
1 18
2 18
3 18
4 18
5 18
6 18
7 18
b 18
d 18
11 19
}
method 'incrementI ()V' {
2 12
4 12
8 13
1 22
2 22
3 22
4 22
7 22
8 23
}
method 'decrementI ()V' {
2 16
4 16
8 17
1 26
2 26
3 26
4 26
6 26
8 27
}
method 'incrementS ()V' {
0 20
4 21
0 30
1 30
2 30
4 30
}
method 'decrementS ()V' {
0 24
4 25
}
}
class 'pkg/TestSyntheticAccess$Assigner' {
method 'assignI (I)V' {
5 30
9 31
}
method 'assignS (I)V' {
0 34
1 34
5 35
2 34
4 35
}
}
Lines mapping:
10 <-> 9
11 <-> 10
14 <-> 13
15 <-> 14
18 <-> 17
19 <-> 18
22 <-> 21
23 <-> 22
26 <-> 25
27 <-> 26
32 <-> 31
33 <-> 32
36 <-> 35
37 <-> 36
10 <-> 19
11 <-> 20
14 <-> 23
15 <-> 24
18 <-> 27
19 <-> 28
22 <-> 31
23 <-> 32
26 <-> 35
27 <-> 36
32 <-> 9
33 <-> 10
36 <-> 13
37 <-> 14
@@ -26,10 +26,15 @@ class 'pkg/TestThrowException$1' {
class 'pkg/TestThrowException' {
method '<init> (I)V' {
4 6
5 6
c 7
d 7
11 7
12 9
1b 9
1c 9
1d 9
1e 15
}
}
@@ -42,42 +42,74 @@ public class TestTryCatchFinally {
class 'pkg/TestTryCatchFinally' {
method 'test1 (Ljava/lang/String;)V' {
0 5
1 5
2 5
3 5
4 5
5 5
14 8
15 8
16 8
17 8
18 8
19 8
1f 9
2b 12
2d 12
30 12
38 15
2b 13
2c 13
2d 13
2e 13
2f 13
30 13
31 13
38 16
}
method 'foo (I)I' {
1 18
2 18
c 19
e 20
f 20
13 21
1b 23
0 19
1 19
2 19
c 20
d 21
e 21
f 21
12 22
13 22
1b 24
}
method 'test (Ljava/lang/String;)I' {
1 29
4 29
e 30
f 31
10 32
1a 32
23 32
26 32
31 37
34 34
35 34
38 34
3f 37
0 30
1 30
2 30
3 30
4 30
d 31
e 31
f 32
10 33
11 33
12 33
1a 33
1b 33
23 33
24 33
25 33
26 33
31 38
32 38
33 38
34 35
35 35
36 35
37 35
38 35
39 35
3a 38
3b 38
3c 38
3d 38
3e 38
3f 38
}
}
@@ -27,58 +27,135 @@ public class TestVarArgCalls {
class 'pkg/TestVarArgCalls' {
method 'doSmth ()V' {
0 4
1 4
2 4
7 4
8 4
9 4
a 5
b 5
c 5
13 5
14 5
16 5
17 5
18 5
19 6
1a 6
1b 6
22 6
23 6
27 6
28 6
2a 6
2b 6
2c 6
2d 7
2e 7
2f 7
34 7
35 7
36 7
37 8
38 8
39 8
46 8
47 8
4a 8
4b 8
4c 8
4d 9
4e 9
4f 9
5c 9
5d 9
68 9
69 9
6c 9
6d 9
6e 9
6f 10
70 10
75 10
76 10
77 10
79 11
7a 11
81 11
82 11
83 11
84 11
85 11
87 11
88 11
89 11
8b 12
8c 12
93 12
94 12
95 12
96 12
97 12
9b 12
9c 12
9e 12
9f 12
a0 12
a8 13
a9 13
ab 13
ac 14
ad 14
b4 14
b6 14
b7 14
b8 14
ba 15
bb 15
bc 15
bd 15
be 15
bf 15
c0 15
c1 15
c2 15
c4 16
}
method 'printAll (Ljava/lang/String;[Ljava/lang/String;)V' {
0 19
1 19
2 19
3 19
4 19
5 19
6 19
7 19
8 19
9 19
a 19
b 19
c 19
d 19
e 20
}
method 'printComplex (Ljava/lang/String;[[Ljava/lang/String;)V' {
0 23
1 23
2 23
3 23
4 23
5 23
6 23
7 23
8 23
9 23
a 23
b 23
c 23
d 23
e 24
}
}