/* * 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.taobao.android.dx.io.instructions; import com.taobao.android.dex.DexException; import com.taobao.android.dx.io.IndexType; import com.taobao.android.dx.io.OpcodeInfo; import com.taobao.android.dx.io.Opcodes; import com.taobao.android.dx.util.Hex; 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 ZeroRegisterDecodedInstruction( this, opcodeUnit, 0, null, 0, 0L); } @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 ZeroRegisterDecodedInstruction( this, opcode, 0, null, 0, literal); } @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 TwoRegisterDecodedInstruction( this, opcode, 0, null, 0, 0L, a, b); } @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 OneRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a); } @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 OneRegisterDecodedInstruction( this, opcode, 0, null, 0, 0L, a); } @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 baseAddress = in.cursor() - 1; int opcode = byte0(opcodeUnit); int target = (byte) byte1(opcodeUnit); // sign-extend return new ZeroRegisterDecodedInstruction( this, opcode, 0, null, baseAddress + target, 0L); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { int relativeTarget = insn.getTargetByte(out.cursor()); out.write(codeUnit(insn.getOpcode(), relativeTarget)); } }, FORMAT_20T() { @Override public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException { int baseAddress = in.cursor() - 1; int opcode = byte0(opcodeUnit); int literal = byte1(opcodeUnit); // should be zero int target = (short) in.read(); // sign-extend return new ZeroRegisterDecodedInstruction( this, opcode, 0, null, baseAddress + target, literal); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { short relativeTarget = insn.getTargetUnit(out.cursor()); out.write(insn.getOpcodeUnit(), relativeTarget); } }, 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 ZeroRegisterDecodedInstruction( this, opcode, index, IndexType.VARIES, 0, literal); } @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 TwoRegisterDecodedInstruction( this, opcode, 0, null, 0, 0L, a, b); } @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 baseAddress = in.cursor() - 1; int opcode = byte0(opcodeUnit); int a = byte1(opcodeUnit); int target = (short) in.read(); // sign-extend return new OneRegisterDecodedInstruction( this, opcode, 0, null, baseAddress + target, 0L, a); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { short relativeTarget = insn.getTargetUnit(out.cursor()); out.write(codeUnit(insn.getOpcode(), insn.getA()), relativeTarget); } }, 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 OneRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a); } @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); long 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 OneRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a); } @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 OneRegisterDecodedInstruction( this, opcode, index, indexType, 0, 0L, a); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { out.write( codeUnit(insn.getOpcode(), insn.getA()), insn.getIndexUnit()); } }, 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 ThreeRegisterDecodedInstruction( this, opcode, 0, null, 0, 0L, a, b, c); } @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 TwoRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a, b); } @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 baseAddress = in.cursor() - 1; int opcode = byte0(opcodeUnit); int a = nibble2(opcodeUnit); int b = nibble3(opcodeUnit); int target = (short) in.read(); // sign-extend return new TwoRegisterDecodedInstruction( this, opcode, 0, null, baseAddress + target, 0L, a, b); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { short relativeTarget = insn.getTargetUnit(out.cursor()); out.write( codeUnit(insn.getOpcode(), makeByte(insn.getA(), insn.getB())), relativeTarget); } }, 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 TwoRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a, b); } @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 TwoRegisterDecodedInstruction( this, opcode, index, indexType, 0, 0L, a, b); } @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 TwoRegisterDecodedInstruction( this, opcode, index, IndexType.FIELD_OFFSET, 0, 0L, a, b); } @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 baseAddress = in.cursor() - 1; int opcode = byte0(opcodeUnit); int literal = byte1(opcodeUnit); // should be zero int target = in.readInt(); return new ZeroRegisterDecodedInstruction( this, opcode, 0, null, baseAddress + target, literal); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { int relativeTarget = insn.getTarget(out.cursor()); out.write(insn.getOpcodeUnit(), unit0(relativeTarget), unit1(relativeTarget)); } }, 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 TwoRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a, b); } @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 OneRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a); } @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 baseAddress = in.cursor() - 1; int opcode = byte0(opcodeUnit); int a = byte1(opcodeUnit); int target = baseAddress + in.readInt(); /* * Switch instructions need to "forward" their addresses to their * payload target instructions. */ switch (opcode) { case Opcodes.PACKED_SWITCH: case Opcodes.SPARSE_SWITCH: { in.setBaseAddress(target, baseAddress); break; } } return new OneRegisterDecodedInstruction( this, opcode, 0, null, target, 0L, a); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { int relativeTarget = insn.getTarget(out.cursor()); out.write( codeUnit(insn.getOpcode(), insn.getA()), unit0(relativeTarget), unit1(relativeTarget)); } }, 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 OneRegisterDecodedInstruction( this, opcode, index, indexType, 0, 0L, a); } @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 OneRegisterDecodedInstruction( this, opcode, 0, null, 0, literal, a); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { long literal = insn.getLiteral(); out.write( codeUnit(insn.getOpcode(), insn.getA()), unit0(literal), unit1(literal), unit2(literal), unit3(literal)); } }, FORMAT_PACKED_SWITCH_PAYLOAD() { @Override public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException { int baseAddress = in.baseAddressForCursor() - 1; // already read opcode int size = in.read(); int firstKey = in.readInt(); int[] targets = new int[size]; for (int i = 0; i < size; i++) { targets[i] = baseAddress + in.readInt(); } return new PackedSwitchPayloadDecodedInstruction( this, opcodeUnit, firstKey, targets); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { PackedSwitchPayloadDecodedInstruction payload = (PackedSwitchPayloadDecodedInstruction) insn; int[] targets = payload.getTargets(); int baseAddress = out.baseAddressForCursor(); out.write(payload.getOpcodeUnit()); out.write(asUnsignedUnit(targets.length)); out.writeInt(payload.getFirstKey()); for (int target : targets) { out.writeInt(target - baseAddress); } } }, FORMAT_SPARSE_SWITCH_PAYLOAD() { @Override public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException { int baseAddress = in.baseAddressForCursor() - 1; // already read opcode int size = in.read(); int[] keys = new int[size]; int[] targets = new int[size]; for (int i = 0; i < size; i++) { keys[i] = in.readInt(); } for (int i = 0; i < size; i++) { targets[i] = baseAddress + in.readInt(); } return new SparseSwitchPayloadDecodedInstruction( this, opcodeUnit, keys, targets); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { SparseSwitchPayloadDecodedInstruction payload = (SparseSwitchPayloadDecodedInstruction) insn; int[] keys = payload.getKeys(); int[] targets = payload.getTargets(); int baseAddress = out.baseAddressForCursor(); out.write(payload.getOpcodeUnit()); out.write(asUnsignedUnit(targets.length)); for (int key : keys) { out.writeInt(key); } for (int target : targets) { out.writeInt(target - baseAddress); } } }, FORMAT_FILL_ARRAY_DATA_PAYLOAD() { @Override public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException { int elementWidth = in.read(); int size = in.readInt(); switch (elementWidth) { case 1: { byte[] array = new byte[size]; boolean even = true; for (int i = 0, value = 0; i < size; i++, even = !even) { if (even) { value = in.read(); } array[i] = (byte) (value & 0xff); value >>= 8; } return new FillArrayDataPayloadDecodedInstruction( this, opcodeUnit, array); } case 2: { short[] array = new short[size]; for (int i = 0; i < size; i++) { array[i] = (short) in.read(); } return new FillArrayDataPayloadDecodedInstruction( this, opcodeUnit, array); } case 4: { int[] array = new int[size]; for (int i = 0; i < size; i++) { array[i] = in.readInt(); } return new FillArrayDataPayloadDecodedInstruction( this, opcodeUnit, array); } case 8: { long[] array = new long[size]; for (int i = 0; i < size; i++) { array[i] = in.readLong(); } return new FillArrayDataPayloadDecodedInstruction( this, opcodeUnit, array); } } throw new DexException("bogus element_width: " + Hex.u2(elementWidth)); } @Override public void encode(DecodedInstruction insn, CodeOutput out) { FillArrayDataPayloadDecodedInstruction payload = (FillArrayDataPayloadDecodedInstruction) insn; short elementWidth = payload.getElementWidthUnit(); Object data = payload.getData(); out.write(payload.getOpcodeUnit()); out.write(elementWidth); out.writeInt(payload.getSize()); switch (elementWidth) { case 1: out.write((byte[]) data); break; case 2: out.write((short[]) data); break; case 4: out.write((int[]) data); break; case 8: out.write((long[]) data); break; default: { throw new DexException("bogus element_width: " + Hex.u2(elementWidth)); } } } }; /** * 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); // TODO: Having to switch like this is less than ideal. switch (registerCount) { case 0: return new ZeroRegisterDecodedInstruction( format, opcode, index, indexType, 0, 0L); case 1: return new OneRegisterDecodedInstruction( format, opcode, index, indexType, 0, 0L, a); case 2: return new TwoRegisterDecodedInstruction( format, opcode, index, indexType, 0, 0L, a, b); case 3: return new ThreeRegisterDecodedInstruction( format, opcode, index, indexType, 0, 0L, a, b, c); case 4: return new FourRegisterDecodedInstruction( format, opcode, index, indexType, 0, 0L, a, b, c, d); case 5: return new FiveRegisterDecodedInstruction( format, opcode, index, indexType, 0, 0L, a, b, c, d, e); } throw new DexException("bogus registerCount: " + Hex.uNibble(registerCount)); } /** * 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 RegisterRangeDecodedInstruction( format, opcode, index, indexType, 0, 0L, a, registerCount); } /** * 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 asUnsignedUnit(int value) { if ((value & ~0xffff) != 0) { throw new IllegalArgumentException("bogus unsigned code unit"); } return (short) value; } 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; } }