/* Software Name : AsmDex * Version : 1.0 * * Copyright © 2012 France Télécom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.ow2.asmdex.instruction; import org.ow2.asmdex.lowLevelUtils.ByteVector; import org.ow2.asmdex.structureWriter.ConstantPool; /** * Represents an instruction of the Dalvik bytecode. * * An instruction also has a Line Number, superior to 0 if set. * * @author Julien Névo */ public abstract class Instruction { /** * Represents the data of the opcode (8 bits). */ protected int opcodeHighOrderByte; /** * Represents the opcode itself (8 bits). */ protected int opcodeByte; /** * Line Number of this Instruction. It must be superior to 0, unless the Line Number has not been * set. */ protected int lineNumber; /** * Builds an instruction from its 16-bit opcode. * @param opcode the 16-bit opcode of the instruction. */ public Instruction(int opcode) { opcodeHighOrderByte = (opcode >> 8) & 0xff; opcodeByte = opcode & 0xff; } public void recycle() { } // ----------------------------------------------------- // Public Methods. // ----------------------------------------------------- /** * Encodes the instruction, in the Dalvik format, to an output buffer. * @param out output buffer. * @param constantPool the constantPool. */ public abstract void write(ByteVector out, ConstantPool constantPool); // ----------------------------------------------------- // Getters and Setters. // ----------------------------------------------------- /** * Returns the size of the instruction in bytes. * @return the size of the instruction in bytes. */ public abstract int getSize(); /** * Returns the high order byte of the 16-bit opcode. * @return the high order byte of the 16-bit opcode. */ public int getOpcodeHighOrderByte() { return opcodeHighOrderByte; } /** * Returns the low order byte of the 16-bit opcode (i.e. the opcode itself). * @return the low order byte of the 16-bit opcode (i.e. the opcode itself). */ public int getOpcodeByte() { return opcodeByte; } /** * Returns a list of the registers used by this instruction. May be null. According to the opcode, * the registers may be given as pairs. * @return the list of the registers used by this instruction. May be null. */ //public abstract int[] getUsedRegisters(); /** * Returns the number of registers encoded by this Instruction. Pair registers do NOT count as two. * @return the number of registers encoded by this Instruction. */ //public abstract int getNbEncodedRegisters(); /** * Returns the line number of the Instruction. A line number equals to 0 means that no line number has * been set. * @return the line number of the Instruction. */ public int getLineNumber() { return lineNumber; } /** * Sets the line number of the Instruction. It must be superior to 0 in order to be valid. * @param lineNumber the line number. */ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } // ----------------------------------------------------- // Static methods and values. // ----------------------------------------------------- /** * Tests if the given number can be held in 4 bits, throw an IllegalArgumentException otherwise. */ public static void test4BitsLimit(int number) { if (number > 0xf) { throw new IllegalArgumentException("The number " + number +" can't be held in 4 bits !"); } } /** * Tests if the given number can be held in 8 bits, throw an IllegalArgumentException otherwise. */ public static void test8BitsLimit(int number) { if ((number & 0xffffff00) != 0) { throw new IllegalArgumentException("The number " + number +" can't be held in 8 bits !"); } } /** * Tests if the given number can be held in 16 bits, throw an IllegalArgumentException otherwise. */ public static void test16BitsLimit(int number) { if ((number & 0xffff0000) != 0) { throw new IllegalArgumentException("The number " + number +" can't be held in 16 bits !"); } } /** * Tests if the given numbers can be held in 4 bits, throw an IllegalArgumentException otherwise. */ public static void test4BitsLimit(int[] numbers) { for (int number : numbers) { test4BitsLimit(number); } } /** * Tests if the given number can be held in 4 bits, throw an IllegalArgumentException otherwise. */ public static void testRange(int[] numbers) { int length = numbers.length; if (length == 0) throw new IllegalArgumentException("Too short for a range"); int expected = numbers[0]; for(int i=1; i<length; i++) { if (numbers[i] != ++expected) throw new IllegalArgumentException("The register at position " + i +" is not consecutive."); } } /** * Size in bytes of every instructions. Includes 256 opcodes. */ final private static byte[] instructionSizeInBytes = new byte[] { 2,2,4,6,2,4,6,2,4,6,2,2,2,2,2,2, // 0x00 2,2,2,4,6,4,4,6,10,4,4,6,4,2,2,4, // 0x10 4,2,4,4,6,6,6,2,2,4,6,6,6,4,4,4, // 0x20 4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2, // 0x30 2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4, // 0x40 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 0x50 4,4,4,4,4,4,4,4,4,4,4,4,4,4,6,6, // 0x60 6,6,6,2,6,6,6,6,6,2,2,2,2,2,2,2, // 0x70 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0x80 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 0x90 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 0xa0 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xb0 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xc0 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 0xd0 4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xe0 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 // 0xf0 }; /** * Returns the size in bytes of the given opcode. * @param opcode from 0 to 255. * @return the size in bytes of the given opcode. */ public static byte getInstructionSizeInByte(int opcode) { return instructionSizeInBytes[opcode]; } }