Instruction3rc.java revision ea7afb02658cc72b5e7156f5dadc51b9c6c212b0
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver (JesusFreke) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.dexlib.Code.Format; 30 31import org.jf.dexlib.Code.Instruction; 32import org.jf.dexlib.Code.InstructionWithReference; 33import org.jf.dexlib.Code.Opcode; 34import org.jf.dexlib.Code.RegisterRangeInstruction; 35import org.jf.dexlib.DexFile; 36import org.jf.dexlib.Item; 37import org.jf.dexlib.MethodIdItem; 38import org.jf.dexlib.TypeIdItem; 39import org.jf.dexlib.Util.AnnotatedOutput; 40import org.jf.dexlib.Util.NumberUtils; 41 42import static org.jf.dexlib.Code.Opcode.*; 43 44public class Instruction3rc extends InstructionWithReference implements RegisterRangeInstruction, 45 InstructionWithJumboVariant { 46 public static final Instruction.InstructionFactory Factory = new Factory(); 47 private byte regCount; 48 private short startReg; 49 50 public Instruction3rc(Opcode opcode, short regCount, int startReg, Item referencedItem) { 51 super(opcode, referencedItem); 52 53 if (regCount >= 1 << 8) { 54 throw new RuntimeException("regCount must be less than 256"); 55 } 56 if (regCount < 0) { 57 throw new RuntimeException("regCount cannot be negative"); 58 } 59 60 if (startReg >= 1 << 16) { 61 throw new RuntimeException("The beginning register of the range must be less than 65536"); 62 } 63 if (startReg < 0) { 64 throw new RuntimeException("The beginning register of the range cannot be negative"); 65 } 66 67 this.regCount = (byte)regCount; 68 this.startReg = (short)startReg; 69 70 checkItem(opcode, referencedItem, regCount); 71 } 72 73 private Instruction3rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { 74 super(dexFile, opcode, buffer, bufferIndex); 75 76 this.regCount = (byte)NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]); 77 this.startReg = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4); 78 79 checkItem(opcode, getReferencedItem(), getRegCount()); 80 } 81 82 protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) { 83 if(getReferencedItem().getIndex() > 0xFFFF) { 84 if (opcode.hasJumboOpcode()) { 85 throw new RuntimeException(String.format("%s index is too large. Use the %s instruction instead.", 86 opcode.referenceType.name(), opcode.getJumboOpcode().name)); 87 } else { 88 throw new RuntimeException(String.format("%s index is too large.", opcode.referenceType.name())); 89 } 90 } 91 92 out.writeByte(opcode.value); 93 out.writeByte(regCount); 94 out.writeShort(this.getReferencedItem().getIndex()); 95 out.writeShort(startReg); 96 } 97 98 public Format getFormat() { 99 return Format.Format3rc; 100 } 101 102 public int getRegCount() { 103 return (short)(regCount & 0xFF); 104 } 105 106 public int getStartRegister() { 107 return startReg & 0xFFFF; 108 } 109 110 private static void checkItem(Opcode opcode, Item item, int regCount) { 111 if (opcode == FILLED_NEW_ARRAY_RANGE) { 112 //check data for filled-new-array/range opcode 113 String type = ((TypeIdItem) item).getTypeDescriptor(); 114 if (type.charAt(0) != '[') { 115 throw new RuntimeException("The type must be an array type"); 116 } 117 if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { 118 throw new RuntimeException("The type cannot be an array of longs or doubles"); 119 } 120 } else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value || 121 opcode == INVOKE_OBJECT_INIT_RANGE) { 122 //check data for invoke-*/range opcodes 123 MethodIdItem methodIdItem = (MethodIdItem) item; 124 int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount(); 125 if (opcode != INVOKE_STATIC_RANGE) { 126 parameterRegisterCount++; 127 } 128 if (parameterRegisterCount != regCount) { 129 throw new RuntimeException("regCount does not match the number of arguments of the method"); 130 } 131 } 132 } 133 134 public Instruction makeJumbo() { 135 Opcode jumboOpcode = opcode.getJumboOpcode(); 136 if (jumboOpcode == null) { 137 return null; 138 } 139 140 return new Instruction5rc(jumboOpcode, getRegCount(), getStartRegister(), getReferencedItem()); 141 } 142 143 private static class Factory implements Instruction.InstructionFactory { 144 public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { 145 return new Instruction3rc(dexFile, opcode, buffer, bufferIndex); 146 } 147 } 148} 149