| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * 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 com.android.dx.io; |
| |
| import java.io.EOFException; |
| |
| /** |
| * Representation of an instruction format, which knows how to decode into |
| * and encode from instances of {@link DecodedInstruction}. |
| */ |
| public enum InstructionCodec { |
| FORMAT_00X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return new DecodedInstruction(this, opcodeUnit, 0, null, |
| 0, 0L, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit()); |
| } |
| }, |
| |
| FORMAT_10X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int literal = byte1(opcodeUnit); // should be zero |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit()); |
| } |
| }, |
| |
| FORMAT_12X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = nibble2(opcodeUnit); |
| int b = nibble3(opcodeUnit); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, 0L, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcodeUnit(), |
| makeByte(insn.getA(), insn.getB()))); |
| } |
| }, |
| |
| FORMAT_11N() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = nibble2(opcodeUnit); |
| int literal = (nibble3(opcodeUnit) << 28) >> 28; // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcodeUnit(), |
| makeByte(insn.getA(), insn.getLiteralNibble()))); |
| } |
| }, |
| |
| FORMAT_11X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, 0L, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(codeUnit(insn.getOpcode(), insn.getA())); |
| } |
| }, |
| |
| FORMAT_10T() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int baseOffset = in.cursor() - 1; |
| int opcode = byte0(opcodeUnit); |
| int target = (byte) byte1(opcodeUnit); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| baseOffset + target, 0L, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(codeUnit(insn.getOpcode(), insn.getTargetByte())); |
| } |
| }, |
| |
| FORMAT_20T() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int baseOffset = in.cursor() - 1; |
| int opcode = byte0(opcodeUnit); |
| int literal = byte1(opcodeUnit); // should be zero |
| int target = (short) in.read(); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| baseOffset + target, literal, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit(), insn.getTargetUnit()); |
| } |
| }, |
| |
| FORMAT_20BC() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| // Note: We use the literal field to hold the decoded AA value. |
| int opcode = byte0(opcodeUnit); |
| int literal = byte1(opcodeUnit); |
| int index = in.read(); |
| return new DecodedInstruction(this, opcode, |
| index, IndexType.VARIES, |
| 0, literal, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getLiteralByte()), |
| insn.getIndexUnit()); |
| } |
| }, |
| |
| FORMAT_22X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int b = in.read(); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, 0L, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| insn.getBUnit()); |
| } |
| }, |
| |
| FORMAT_21T() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int baseOffset = in.cursor() - 1; |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int target = (short) in.read(); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| baseOffset + target, 0L, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| insn.getTargetUnit()); |
| } |
| }, |
| |
| FORMAT_21S() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int literal = (short) in.read(); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| insn.getLiteralUnit()); |
| } |
| }, |
| |
| FORMAT_21H() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int literal = (short) in.read(); // sign-extend |
| |
| /* |
| * Format 21h decodes differently depending on the opcode, |
| * because the "signed hat" might represent either a 32- |
| * or 64- bit value. |
| */ |
| literal <<= (opcode == Opcodes.CONST_HIGH16) ? 16 : 48; |
| |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| // See above. |
| int opcode = insn.getOpcode(); |
| int shift = (opcode == Opcodes.CONST_HIGH16) ? 16 : 48; |
| short literal = (short) (insn.getLiteral() >> shift); |
| |
| out.write(codeUnit(opcode, insn.getA()), literal); |
| } |
| }, |
| |
| FORMAT_21C() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int index = in.read(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcode); |
| return new DecodedInstruction(this, opcode, index, indexType, |
| 0, 0L, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| insn.getLiteralUnit()); |
| } |
| }, |
| |
| FORMAT_23X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int bc = in.read(); |
| int b = byte0(bc); |
| int c = byte1(bc); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, 0L, null, |
| 3, a, b, c, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| codeUnit(insn.getB(), insn.getC())); |
| } |
| }, |
| |
| FORMAT_22B() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int bc = in.read(); |
| int b = byte0(bc); |
| int literal = (byte) byte1(bc); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| codeUnit(insn.getB(), |
| insn.getLiteralByte())); |
| } |
| }, |
| |
| FORMAT_22T() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int baseOffset = in.cursor() - 1; |
| int opcode = byte0(opcodeUnit); |
| int a = nibble2(opcodeUnit); |
| int b = nibble3(opcodeUnit); |
| int target = (short) in.read(); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| baseOffset + target, 0L, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), |
| makeByte(insn.getA(), insn.getB())), |
| insn.getTargetUnit()); |
| } |
| }, |
| |
| FORMAT_22S() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = nibble2(opcodeUnit); |
| int b = nibble3(opcodeUnit); |
| int literal = (short) in.read(); // sign-extend |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), |
| makeByte(insn.getA(), insn.getB())), |
| insn.getLiteralUnit()); |
| } |
| }, |
| |
| FORMAT_22C() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = nibble2(opcodeUnit); |
| int b = nibble3(opcodeUnit); |
| int index = in.read(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcode); |
| return new DecodedInstruction(this, opcode, index, indexType, |
| 0, 0L, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), |
| makeByte(insn.getA(), insn.getB())), |
| insn.getIndexUnit()); |
| } |
| }, |
| |
| FORMAT_22CS() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = nibble2(opcodeUnit); |
| int b = nibble3(opcodeUnit); |
| int index = in.read(); |
| return new DecodedInstruction(this, opcode, |
| index, IndexType.FIELD_OFFSET, |
| 0, 0L, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| codeUnit(insn.getOpcode(), |
| makeByte(insn.getA(), insn.getB())), |
| insn.getIndexUnit()); |
| } |
| }, |
| |
| FORMAT_30T() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int baseOffset = in.cursor() - 1; |
| int opcode = byte0(opcodeUnit); |
| int literal = byte1(opcodeUnit); // should be zero |
| int target = in.readInt(); |
| return new DecodedInstruction(this, opcode, 0, null, |
| baseOffset + target, literal, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int target = insn.getTarget(); |
| out.write(insn.getOpcodeUnit(), unit0(target), unit1(target)); |
| } |
| }, |
| |
| FORMAT_32X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int literal = byte1(opcodeUnit); // should be zero |
| int a = in.read(); |
| int b = in.read(); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit(), insn.getAUnit(), insn.getBUnit()); |
| } |
| }, |
| |
| FORMAT_31I() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int literal = in.readInt(); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int literal = insn.getLiteralInt(); |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| unit0(literal), |
| unit1(literal)); |
| } |
| }, |
| |
| FORMAT_31T() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int baseOffset = in.cursor() - 1; |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int target = in.readInt(); |
| return new DecodedInstruction(this, opcode, 0, null, |
| baseOffset + target, 0L, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int target = insn.getTarget(); |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| unit0(target), |
| unit1(target)); |
| } |
| }, |
| |
| FORMAT_31C() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| int index = in.readInt(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcode); |
| return new DecodedInstruction(this, opcode, index, indexType, |
| 0, 0L, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int index = insn.getIndex(); |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| unit0(index), |
| unit1(index)); |
| } |
| }, |
| |
| FORMAT_35C() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return decodeRegisterList(this, opcodeUnit, in); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| encodeRegisterList(insn, out); |
| } |
| }, |
| |
| FORMAT_35MS() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return decodeRegisterList(this, opcodeUnit, in); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| encodeRegisterList(insn, out); |
| } |
| }, |
| |
| FORMAT_35MI() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return decodeRegisterList(this, opcodeUnit, in); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| encodeRegisterList(insn, out); |
| } |
| }, |
| |
| FORMAT_3RC() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return decodeRegisterRange(this, opcodeUnit, in); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| encodeRegisterRange(insn, out); |
| } |
| }, |
| |
| FORMAT_3RMS() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return decodeRegisterRange(this, opcodeUnit, in); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| encodeRegisterRange(insn, out); |
| } |
| }, |
| |
| FORMAT_3RMI() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| return decodeRegisterRange(this, opcodeUnit, in); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| encodeRegisterRange(insn, out); |
| } |
| }, |
| |
| FORMAT_51L() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int a = byte1(opcodeUnit); |
| long literal = in.readLong(); |
| return new DecodedInstruction(this, opcode, 0, null, |
| 0, literal, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int literal = insn.getLiteralInt(); |
| out.write( |
| codeUnit(insn.getOpcode(), insn.getA()), |
| unit0(literal), |
| unit1(literal), |
| unit2(literal), |
| unit3(literal)); |
| } |
| }, |
| |
| FORMAT_33X() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int ab = in.read(); |
| int a = byte0(ab); |
| int b = byte1(ab); |
| int c = in.read(); |
| return new DecodedInstruction(this, opcodeUnit, 0, null, |
| 0, 0L, null, |
| 3, a, b, c, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| insn.getOpcodeUnit(), |
| codeUnit(insn.getA(), insn.getB()), |
| insn.getCUnit()); |
| } |
| }, |
| |
| FORMAT_32S() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int ab = in.read(); |
| int a = byte0(ab); |
| int b = byte1(ab); |
| int literal = (short) in.read(); // sign-extend |
| return new DecodedInstruction(this, opcodeUnit, 0, null, |
| 0, literal, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write( |
| insn.getOpcodeUnit(), |
| codeUnit(insn.getA(), insn.getB()), |
| insn.getLiteralUnit()); |
| } |
| }, |
| |
| FORMAT_40SC() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| // Note: We use the literal field to hold the decoded AA value. |
| int index = in.readInt(); |
| int literal = in.read(); |
| return new DecodedInstruction(this, opcodeUnit, |
| index, IndexType.VARIES, |
| 0, literal, null, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int index = insn.getIndex(); |
| out.write( |
| insn.getOpcodeUnit(), |
| unit0(index), |
| unit1(index), |
| insn.getLiteralUnit()); |
| } |
| }, |
| |
| FORMAT_41C() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int index = in.readInt(); |
| int a = in.read(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcodeUnit); |
| return new DecodedInstruction(this, opcodeUnit, index, indexType, |
| 0, 0L, null, |
| 1, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int index = insn.getIndex(); |
| out.write( |
| insn.getOpcodeUnit(), |
| unit0(index), |
| unit1(index), |
| insn.getAUnit()); |
| } |
| }, |
| |
| FORMAT_52C() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int index = in.readInt(); |
| int a = in.read(); |
| int b = in.read(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcodeUnit); |
| return new DecodedInstruction(this, opcodeUnit, index, indexType, |
| 0, 0L, null, |
| 2, a, b, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int index = insn.getIndex(); |
| out.write( |
| insn.getOpcodeUnit(), |
| unit0(index), |
| unit1(index), |
| insn.getAUnit(), |
| insn.getBUnit()); |
| } |
| }, |
| |
| FORMAT_5RC() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int index = in.readInt(); |
| int registerCount = in.read(); |
| int a = in.read(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcodeUnit); |
| return new DecodedInstruction(this, opcodeUnit, index, indexType, |
| 0, 0L, null, |
| registerCount, a, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| int index = insn.getIndex(); |
| out.write( |
| insn.getOpcodeUnit(), |
| unit0(index), |
| unit1(index), |
| insn.getRegisterCountUnit(), |
| insn.getAUnit()); |
| } |
| }, |
| |
| FORMAT_PACKED_SWITCH_PAYLOAD() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int size = in.read(); |
| int unitCount = (size * 2) + 3; // Doesn't count the opcode unit. |
| short[] data = new short[unitCount]; |
| |
| data[0] = (short) size; |
| |
| for (int i = 1; i < unitCount; i++) { |
| data[i] = (short) in.read(); |
| } |
| |
| return new DecodedInstruction(this, opcodeUnit, 0, null, |
| 0, 0L, data, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit()); |
| out.write(insn.getData()); |
| } |
| }, |
| |
| FORMAT_SPARSE_SWITCH_PAYLOAD() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int size = in.read(); |
| int unitCount = (size * 4) + 1; // Doesn't count the opcode unit. |
| short[] data = new short[unitCount]; |
| |
| data[0] = (short) size; |
| |
| for (int i = 1; i < unitCount; i++) { |
| data[i] = (short) in.read(); |
| } |
| |
| return new DecodedInstruction(this, opcodeUnit, 0, null, |
| 0, 0L, data, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit()); |
| out.write(insn.getData()); |
| } |
| }, |
| |
| FORMAT_FILL_ARRAY_DATA_PAYLOAD() { |
| @Override public DecodedInstruction decode(int opcodeUnit, |
| CodeInput in) throws EOFException { |
| int elementWidth = in.read(); |
| int size = in.readInt(); |
| |
| // Doesn't count the opcode unit. |
| int unitCount = (size * elementWidth + 1) / 2 + 3; |
| |
| short[] data = new short[unitCount]; |
| |
| data[0] = unit0(size); |
| data[1] = unit1(size); |
| data[2] = (short) elementWidth; |
| |
| for (int i = 3; i < unitCount; i++) { |
| data[i] = (short) in.read(); |
| } |
| |
| return new DecodedInstruction(this, opcodeUnit, 0, null, |
| 0, 0L, data, |
| 0, 0, 0, 0, 0, 0); |
| } |
| |
| @Override public void encode(DecodedInstruction insn, CodeOutput out) { |
| out.write(insn.getOpcodeUnit()); |
| out.write(insn.getData()); |
| } |
| }; |
| |
| /** |
| * Decodes an instruction specified by the given opcode unit, reading |
| * any required additional code units from the given input source. |
| */ |
| public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in) |
| throws EOFException; |
| |
| /** |
| * Encodes the given instruction. |
| */ |
| public abstract void encode(DecodedInstruction insn, CodeOutput out); |
| |
| /** |
| * Helper method that decodes any of the register-list formats. |
| */ |
| private static DecodedInstruction decodeRegisterList( |
| InstructionCodec format, int opcodeUnit, CodeInput in) |
| throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int e = nibble2(opcodeUnit); |
| int registerCount = nibble3(opcodeUnit); |
| int index = in.read(); |
| int abcd = in.read(); |
| int a = nibble0(abcd); |
| int b = nibble1(abcd); |
| int c = nibble2(abcd); |
| int d = nibble3(abcd); |
| IndexType indexType = OpcodeInfo.getIndexType(opcode); |
| return new DecodedInstruction(format, opcode, index, indexType, |
| 0, 0L, null, |
| registerCount, a, b, c, d, e); |
| } |
| |
| /** |
| * Helper method that encodes any of the register-list formats. |
| */ |
| private static void encodeRegisterList(DecodedInstruction insn, |
| CodeOutput out) { |
| out.write(codeUnit(insn.getOpcode(), |
| makeByte(insn.getE(), insn.getRegisterCount())), |
| insn.getIndexUnit(), |
| codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD())); |
| } |
| |
| /** |
| * Helper method that decodes any of the three-unit register-range formats. |
| */ |
| private static DecodedInstruction decodeRegisterRange( |
| InstructionCodec format, int opcodeUnit, CodeInput in) |
| throws EOFException { |
| int opcode = byte0(opcodeUnit); |
| int registerCount = byte1(opcodeUnit); |
| int index = in.read(); |
| int a = in.read(); |
| IndexType indexType = OpcodeInfo.getIndexType(opcode); |
| return new DecodedInstruction(format, opcode, index, indexType, |
| 0, 0L, null, |
| registerCount, a, 0, 0, 0, 0); |
| } |
| |
| /** |
| * Helper method that encodes any of the three-unit register-range formats. |
| */ |
| private static void encodeRegisterRange(DecodedInstruction insn, |
| CodeOutput out) { |
| out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()), |
| insn.getIndexUnit(), |
| insn.getAUnit()); |
| } |
| |
| private static short codeUnit(int lowByte, int highByte) { |
| if ((lowByte & ~0xff) != 0) { |
| throw new IllegalArgumentException("bogus lowByte"); |
| } |
| |
| if ((highByte & ~0xff) != 0) { |
| throw new IllegalArgumentException("bogus highByte"); |
| } |
| |
| return (short) (lowByte | (highByte << 8)); |
| } |
| |
| private static short codeUnit(int nibble0, int nibble1, int nibble2, |
| int nibble3) { |
| if ((nibble0 & ~0xf) != 0) { |
| throw new IllegalArgumentException("bogus nibble0"); |
| } |
| |
| if ((nibble1 & ~0xf) != 0) { |
| throw new IllegalArgumentException("bogus nibble1"); |
| } |
| |
| if ((nibble2 & ~0xf) != 0) { |
| throw new IllegalArgumentException("bogus nibble2"); |
| } |
| |
| if ((nibble3 & ~0xf) != 0) { |
| throw new IllegalArgumentException("bogus nibble3"); |
| } |
| |
| return (short) (nibble0 | (nibble1 << 4) |
| | (nibble2 << 8) | (nibble3 << 12)); |
| } |
| |
| private static int makeByte(int lowNibble, int highNibble) { |
| if ((lowNibble & ~0xf) != 0) { |
| throw new IllegalArgumentException("bogus lowNibble"); |
| } |
| |
| if ((highNibble & ~0xf) != 0) { |
| throw new IllegalArgumentException("bogus highNibble"); |
| } |
| |
| return lowNibble | (highNibble << 4); |
| } |
| |
| private static short unit0(int value) { |
| return (short) value; |
| } |
| |
| private static short unit1(int value) { |
| return (short) (value >> 16); |
| } |
| |
| private static short unit0(long value) { |
| return (short) value; |
| } |
| |
| private static short unit1(long value) { |
| return (short) (value >> 16); |
| } |
| |
| private static short unit2(long value) { |
| return (short) (value >> 32); |
| } |
| |
| private static short unit3(long value) { |
| return (short) (value >> 48); |
| } |
| |
| private static int byte0(int value) { |
| return value & 0xff; |
| } |
| |
| private static int byte1(int value) { |
| return (value >> 8) & 0xff; |
| } |
| |
| private static int byte2(int value) { |
| return (value >> 16) & 0xff; |
| } |
| |
| private static int byte3(int value) { |
| return value >>> 24; |
| } |
| |
| private static int nibble0(int value) { |
| return value & 0xf; |
| } |
| |
| private static int nibble1(int value) { |
| return (value >> 4) & 0xf; |
| } |
| |
| private static int nibble2(int value) { |
| return (value >> 8) & 0xf; |
| } |
| |
| private static int nibble3(int value) { |
| return (value >> 12) & 0xf; |
| } |
| } |