targetInstruction = getFirstNonNop(targetLocation.index + 1); ((BuilderOffsetInstruction) instruction).getTarget()); replaceInstruction(location.index, replacement); madeChanges = true; BuilderOffsetInstruction replacement = new BuilderInstruction30t(Opcode.GOTO_32, ((BuilderOffsetInstruction) instruction).getTarget()); replaceInstruction(location.index, replacement); madeChanges = true; if (((BuilderSwitchPayload) instruction).referrer == null) { removeInstruction(index); index--; madeChanges = true; assert previousInstruction != null; if (previousInstruction.getOpcode() == Opcode.NOP) { removeInstruction(previousIndex); index--; } else { addInstruction(location.index, new BuilderInstruction10x(Opcode.NOP)); index++;
convertAndSetInstruction(location, codeAddressToIndex, instruction); int locationIndex = mapCodeAddressToIndex(codeAddressToIndex, debugCodeAddress); MethodLocation debugLocation = instructionList.get(locationIndex); BuilderDebugItem builderDebugItem = convertDebugItem(debugItem); debugLocation.getDebugItems().add(builderDebugItem); builderDebugItem.location = debugLocation; Label startLabel = newLabel(codeAddressToIndex, tryBlock.getStartCodeAddress()); Label endLabel = newLabel(codeAddressToIndex, tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount()); (TypeReference) convertReference(exceptionHandler.getExceptionTypeReference()), newLabel(codeAddressToIndex, exceptionHandler.getHandlerCodeAddress())));
@Nonnull private BuilderPackedSwitchPayload newBuilderPackedSwitchPayload(@Nonnull MethodLocation location, @Nonnull int[] codeAddressToIndex, @Nonnull PackedSwitchPayload instruction) { List<? extends SwitchElement> switchElements = instruction.getSwitchElements(); if (switchElements.size() == 0) { return new BuilderPackedSwitchPayload(0, null); } MethodLocation switchLocation = findSwitchForPayload(location); int baseAddress; if (switchLocation == null) { baseAddress = 0; } else { baseAddress = switchLocation.codeAddress; } List<Label> labels = Lists.newArrayList(); for (SwitchElement element : switchElements) { labels.add(newLabel(codeAddressToIndex, element.getOffset() + baseAddress)); } return new BuilderPackedSwitchPayload(switchElements.get(0).getKey(), labels); }
switch (instruction.getOpcode().format) { case Format10t: setInstruction(location, newBuilderInstruction10t(location.codeAddress, codeAddressToIndex, (Instruction10t) instruction)); return; case Format10x: setInstruction(location, newBuilderInstruction10x((Instruction10x) instruction)); return; case Format11n: setInstruction(location, newBuilderInstruction11n((Instruction11n) instruction)); return; case Format11x: setInstruction(location, newBuilderInstruction11x((Instruction11x) instruction)); return; case Format12x: setInstruction(location, newBuilderInstruction12x((Instruction12x) instruction)); return; case Format20bc: setInstruction(location, newBuilderInstruction20bc((Instruction20bc) instruction)); return; case Format20t: setInstruction(location, newBuilderInstruction20t(location.codeAddress, codeAddressToIndex, (Instruction20t) instruction)); return; case Format21c: setInstruction(location, newBuilderInstruction21c((Instruction21c) instruction)); return;
@Nonnull private BuilderInstruction20bc newBuilderInstruction20bc(@Nonnull Instruction20bc instruction) { return new BuilderInstruction20bc( instruction.getOpcode(), instruction.getVerificationError(), convertReference(instruction.getReference())); }
@Nonnull private Label newLabel(@Nonnull int[] codeAddressToIndex, int codeAddress) { MethodLocation referent = instructionList.get(mapCodeAddressToIndex(codeAddressToIndex, codeAddress)); return referent.addNewLabel(); }
@Nonnull @Override public List<BuilderTryBlock> getTryBlocks() { if (fixInstructions) { fixInstructions(); } return Collections.unmodifiableList(tryBlocks); }
public void addInstruction(int index, BuilderInstruction instruction) { // the end check here is intentially >= rather than >, because the list always includes an "empty" // (null instruction) MethodLocation at the end. To add an instruction to the end of the list, the user would // provide the index of this empty item, which would be size() - 1. if (index >= instructionList.size()) { throw new IndexOutOfBoundsException(); } if (index == instructionList.size() - 1) { addInstruction(instruction); return; } int codeAddress = instructionList.get(index).getCodeAddress(); MethodLocation newLoc = new MethodLocation(instruction, codeAddress, index); instructionList.add(index, newLoc); instruction.location = newLoc; codeAddress += instruction.getCodeUnits(); for (int i = index + 1; i < instructionList.size(); i++) { MethodLocation location = instructionList.get(i); location.index++; location.codeAddress = codeAddress; if (location.instruction != null) { codeAddress += location.instruction.getCodeUnits(); } else { // only the last MethodLocation should have a null instruction assert i == instructionList.size() - 1; } } this.fixInstructions = true; }
MethodImplementation methodImpl = method.getImplementation(); if (methodImpl != null) { methodImpl = new BuilderMutableMethodImplementation(dexBuilder, methodImpl);
switch (instruction.getOpcode().format) { case Format10t: setInstruction(location, newBuilderInstruction10t(location.codeAddress, codeAddressToIndex, (Instruction10t) instruction)); return; case Format10x: setInstruction(location, newBuilderInstruction10x((Instruction10x) instruction)); return; case Format11n: setInstruction(location, newBuilderInstruction11n((Instruction11n) instruction)); return; case Format11x: setInstruction(location, newBuilderInstruction11x((Instruction11x) instruction)); return; case Format12x: setInstruction(location, newBuilderInstruction12x((Instruction12x) instruction)); return; case Format20bc: setInstruction(location, newBuilderInstruction20bc((Instruction20bc) instruction)); return; case Format20t: setInstruction(location, newBuilderInstruction20t(location.codeAddress, codeAddressToIndex, (Instruction20t) instruction)); return; case Format21c: setInstruction(location, newBuilderInstruction21c((Instruction21c) instruction)); return;
@Nonnull private BuilderInstruction21c newBuilderInstruction21c(@Nonnull Instruction21c instruction) { return new BuilderInstruction21c( instruction.getOpcode(), instruction.getRegisterA(), convertReference(instruction.getReference())); }
@Nonnull public Label newLabelForAddress(int codeAddress) { if (codeAddress < 0 || codeAddress > instructionList.get(instructionList.size() - 1).codeAddress) { throw new IndexOutOfBoundsException(String.format("codeAddress %d out of bounds", codeAddress)); } MethodLocation referent = instructionList.get(mapCodeAddressToIndex(codeAddress)); return referent.addNewLabel(); }
@Nonnull public List<BuilderInstruction> getInstructions() { if (fixInstructions) { fixInstructions(); } return new AbstractList<BuilderInstruction>() { @Override public BuilderInstruction get(int i) { if (i >= size()) { throw new IndexOutOfBoundsException(); } if (fixInstructions) { fixInstructions(); } return instructionList.get(i).instruction; } @Override public int size() { if (fixInstructions) { fixInstructions(); } // don't include the last MethodLocation, which always has a null instruction return instructionList.size() - 1; } }; }
public void addInstruction(int index, BuilderInstruction instruction) { // the end check here is intentially >= rather than >, because the list always includes an "empty" // (null instruction) MethodLocation at the end. To add an instruction to the end of the list, the user would // provide the index of this empty item, which would be size() - 1. if (index >= instructionList.size()) { throw new IndexOutOfBoundsException(); } if (index == instructionList.size() - 1) { addInstruction(instruction); return; } int codeAddress = instructionList.get(index).getCodeAddress(); MethodLocation newLoc = new MethodLocation(instruction, codeAddress, index); instructionList.add(index, newLoc); instruction.location = newLoc; codeAddress += instruction.getCodeUnits(); for (int i = index + 1; i < instructionList.size(); i++) { MethodLocation location = instructionList.get(i); location.index++; location.codeAddress = codeAddress; if (location.instruction != null) { codeAddress += location.instruction.getCodeUnits(); } else { // only the last MethodLocation should have a null instruction assert i == instructionList.size() - 1; } } this.fixInstructions = true; }
MethodImplementation methodImpl = method.getImplementation(); if (methodImpl != null) { methodImpl = new BuilderMutableMethodImplementation(dexBuilder, methodImpl);
convertAndSetInstruction(location, codeAddressToIndex, instruction); int locationIndex = mapCodeAddressToIndex(codeAddressToIndex, debugCodeAddress); MethodLocation debugLocation = instructionList.get(locationIndex); BuilderDebugItem builderDebugItem = convertDebugItem(debugItem); debugLocation.getDebugItems().add(builderDebugItem); builderDebugItem.location = debugLocation; Label startLabel = newLabel(codeAddressToIndex, tryBlock.getStartCodeAddress()); Label endLabel = newLabel(codeAddressToIndex, tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount()); (TypeReference) convertReference(exceptionHandler.getExceptionTypeReference()), newLabel(codeAddressToIndex, exceptionHandler.getHandlerCodeAddress())));
targetInstruction = getFirstNonNop(targetLocation.index + 1); ((BuilderOffsetInstruction) instruction).getTarget()); replaceInstruction(location.index, replacement); madeChanges = true; BuilderOffsetInstruction replacement = new BuilderInstruction30t(Opcode.GOTO_32, ((BuilderOffsetInstruction) instruction).getTarget()); replaceInstruction(location.index, replacement); madeChanges = true; if (((BuilderSwitchPayload) instruction).referrer == null) { removeInstruction(index); index--; madeChanges = true; assert previousInstruction != null; if (previousInstruction.getOpcode() == Opcode.NOP) { removeInstruction(previousIndex); index--; } else { addInstruction(location.index, new BuilderInstruction10x(Opcode.NOP)); index++;
@Nonnull private BuilderSparseSwitchPayload newBuilderSparseSwitchPayload(@Nonnull MethodLocation location, @Nonnull int[] codeAddressToIndex, @Nonnull SparseSwitchPayload instruction) { List<? extends SwitchElement> switchElements = instruction.getSwitchElements(); if (switchElements.size() == 0) { return new BuilderSparseSwitchPayload(null); } MethodLocation switchLocation = findSwitchForPayload(location); int baseAddress; if (switchLocation == null) { baseAddress = 0; } else { baseAddress = switchLocation.codeAddress; } List<SwitchLabelElement> labelElements = Lists.newArrayList(); for (SwitchElement element : switchElements) { labelElements.add(new SwitchLabelElement(element.getKey(), newLabel(codeAddressToIndex, element.getOffset() + baseAddress))); } return new BuilderSparseSwitchPayload(labelElements); }
@Nonnull private BuilderInstruction31c newBuilderInstruction31c(@Nonnull Instruction31c instruction) { return new BuilderInstruction31c( instruction.getOpcode(), instruction.getRegisterA(), convertReference(instruction.getReference())); }
@Nonnull public Label newSwitchPayloadReferenceLabel(@Nonnull MethodLocation switchLocation, @Nonnull int[] codeAddressToIndex, int codeAddress) { MethodLocation referent = instructionList.get(mapCodeAddressToIndex(codeAddressToIndex, codeAddress)); SwitchPayloadReferenceLabel label = new SwitchPayloadReferenceLabel(); label.switchLocation = switchLocation; referent.getLabels().add(label); return label; }