InstructionOffsetMap { public InstructionOffsetMap(@Nonnull List<? extends Instruction> instructions) { this.instructionCodeOffsets = new int[instructions.size()]; int codeOffset = 0; for (int i=0; i<instructions.size(); i++) { instructionCodeOffsets[i] = codeOffset; codeOffset += instructions.get(i).getCodeUnits(); } } InstructionOffsetMap(@Nonnull List<? extends Instruction> instructions); int getInstructionIndexAtCodeOffset(int codeOffset); int getInstructionIndexAtCodeOffset(int codeOffset, boolean exact); int getInstructionCodeOffset(int index);  }
@Test public void testInstructionOffsetMap() { ImmutableList<ImmutableInstruction> instructions = ImmutableList.of( new ImmutableInstruction10t(Opcode.GOTO, 1), new ImmutableInstruction10x(Opcode.NOP), new ImmutableInstruction11n(Opcode.CONST_4, 2, 3), new ImmutableInstruction11x(Opcode.RETURN, 4), new ImmutableInstruction12x(Opcode.ARRAY_LENGTH, 5, 6), new ImmutableInstruction20t(Opcode.GOTO_16, 7), new ImmutableInstruction21c(Opcode.CONST_STRING, 8, new ImmutableStringReference("blah")), new ImmutableInstruction21ih(Opcode.CONST_HIGH16, 9, 0x10000), new ImmutableInstruction21lh(Opcode.CONST_WIDE_HIGH16, 10, 0x1000000000000L), new ImmutableInstruction21s(Opcode.CONST_16, 11, 12), new ImmutableInstruction21t(Opcode.IF_EQZ, 12, 13), new ImmutableInstruction22b(Opcode.ADD_INT_LIT8, 14, 15, 16), new ImmutableInstruction22c(Opcode.INSTANCE_OF, 0, 1, new ImmutableTypeReference("Ltype;")), new ImmutableInstruction22s(Opcode.ADD_INT_LIT16, 2, 3, 17), new ImmutableInstruction22t(Opcode.IF_EQ, 4, 5, 18), new ImmutableInstruction22x(Opcode.MOVE_FROM16, 19, 20), new ImmutableInstruction23x(Opcode.AGET, 21, 22, 23), new ImmutableInstruction30t(Opcode.GOTO_32, 24), new ImmutableInstruction31c(Opcode.CONST_STRING_JUMBO, 25, new ImmutableStringReference("this is a string")), new ImmutableInstruction31i(Opcode.CONST, 26, 27), new ImmutableInstruction31t(Opcode.FILL_ARRAY_DATA, 28, 29), new ImmutableInstruction32x(Opcode.MOVE_16, 30, 31), new ImmutableInstruction35c(Opcode.FILLED_NEW_ARRAY, 0, 0, 0, 0, 0, 0, new ImmutableTypeReference("Ltype;")), new ImmutableInstruction3rc(Opcode.FILLED_NEW_ARRAY_RANGE, 0, 0, new ImmutableTypeReference("Ltype;")), new ImmutableInstruction51l(Opcode.CONST_WIDE, 32, 33), new ImmutableInstruction10t(Opcode.GOTO, 1) ); ImmutableMethodImplementation impl = new ImmutableMethodImplementation(33, instructions, null, null); InstructionOffsetMap instructionOffsetMap = new InstructionOffsetMap(instructions); int[] expectedOffsets = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x20, 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x32, 0x37}; for (int i=0; i<instructions.size(); i++) { Assert.assertEquals(expectedOffsets[i], instructionOffsetMap.getInstructionCodeOffset(i)); Assert.assertEquals(i, instructionOffsetMap.getInstructionIndexAtCodeOffset(expectedOffsets[i], true)); Assert.assertEquals(i, instructionOffsetMap.getInstructionIndexAtCodeOffset(expectedOffsets[i], false)); } int instructionIndex = -1; for (int codeOffset=0; codeOffset<=expectedOffsets[expectedOffsets.length-1]; codeOffset++) { if (codeOffset == expectedOffsets[instructionIndex+1]) { instructionIndex++; } else { Assert.assertEquals(instructionIndex, instructionOffsetMap.getInstructionIndexAtCodeOffset(codeOffset, false)); try { instructionOffsetMap.getInstructionIndexAtCodeOffset(codeOffset, true); Assert.fail(String.format("Exception exception didn't occur for code offset 0x%x", codeOffset)); } catch (ExceptionWithContext ex) { } } } Assert.assertEquals(expectedOffsets.length-1, instructionOffsetMap.getInstructionIndexAtCodeOffset(expectedOffsets[expectedOffsets.length-1]+1, false)); Assert.assertEquals(expectedOffsets.length-1, instructionOffsetMap.getInstructionIndexAtCodeOffset(expectedOffsets[expectedOffsets.length-1]+10, false)); }