| // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package com.android.tools.r8.utils; | |
| import com.android.tools.r8.dex.BinaryReader; | |
| import com.android.tools.r8.dex.DexOutputBuffer; | |
| import java.util.Arrays; | |
| public class LebUtils { | |
| private static final int BITS_PER_ENCODED_BYTE = 7; | |
| private static final int PAYLOAD_MASK = 0x7f; | |
| private static final int MORE_DATA_TAG_BIT = 0x80; | |
| private static final int MAX_BYTES_PER_VALUE = 5; | |
| public static int parseUleb128(BinaryReader reader) { | |
| int result = 0; | |
| byte b; | |
| int shift = 0; | |
| do { | |
| b = reader.get(); | |
| result |= (b & (byte) PAYLOAD_MASK) << shift; | |
| shift += BITS_PER_ENCODED_BYTE; | |
| } while ((b & ~(byte) PAYLOAD_MASK) == ~(byte) PAYLOAD_MASK); | |
| assert shift <= MAX_BYTES_PER_VALUE * BITS_PER_ENCODED_BYTE; // At most five bytes are used. | |
| assert result >= 0; // Ensure the java int didn't overflow. | |
| return result; | |
| } | |
| // Inspired by com.android.dex.Leb128.java | |
| public static byte[] encodeUleb128(int value) { | |
| byte result[] = new byte[MAX_BYTES_PER_VALUE]; | |
| int remaining = value >>> BITS_PER_ENCODED_BYTE; | |
| int bytes = 0; | |
| while (remaining != 0) { | |
| result[bytes++] = (byte) ((value & PAYLOAD_MASK) | MORE_DATA_TAG_BIT); | |
| value = remaining; | |
| remaining >>>= BITS_PER_ENCODED_BYTE; | |
| } | |
| result[bytes++] = (byte) (value & PAYLOAD_MASK); | |
| return Arrays.copyOf(result, bytes); | |
| } | |
| // Inspired by com.android.dex.Leb128.java | |
| public static void putUleb128(DexOutputBuffer outputBuffer, int value) { | |
| int remaining = value >>> BITS_PER_ENCODED_BYTE; | |
| while (remaining != 0) { | |
| outputBuffer.putByte((byte) ((value & PAYLOAD_MASK) | MORE_DATA_TAG_BIT)); | |
| value = remaining; | |
| remaining >>>= BITS_PER_ENCODED_BYTE; | |
| } | |
| outputBuffer.putByte((byte) (value & PAYLOAD_MASK)); | |
| } | |
| public static int sizeAsUleb128(int value) { | |
| return Math | |
| .max(1, (Integer.SIZE - Integer.numberOfLeadingZeros(value) + 6) / BITS_PER_ENCODED_BYTE); | |
| } | |
| public static int parseSleb128(BinaryReader reader) { | |
| int result = 0; | |
| byte b; | |
| int shift = 0; | |
| do { | |
| b = reader.get(); | |
| result |= (b & (byte) PAYLOAD_MASK) << shift; | |
| shift += BITS_PER_ENCODED_BYTE; | |
| } while ((b & ~(byte) PAYLOAD_MASK) == ~(byte) PAYLOAD_MASK); | |
| int mask = 1 << (shift - 1); | |
| assert shift <= MAX_BYTES_PER_VALUE * BITS_PER_ENCODED_BYTE; // At most five bytes are used. | |
| return (result ^ mask) - mask; | |
| } | |
| // Inspired by com.android.dex.Leb128.java | |
| public static byte[] encodeSleb128(int value) { | |
| byte result[] = new byte[MAX_BYTES_PER_VALUE]; | |
| int remaining = value >> BITS_PER_ENCODED_BYTE; | |
| boolean hasMore = true; | |
| int end = value >= 0 ? 0 : -1; | |
| int bytes = 0; | |
| while (hasMore) { | |
| hasMore = (remaining != end) | |
| || ((remaining & 1) != ((value >> 6) & 1)); | |
| result[bytes++] = (byte) ((value & PAYLOAD_MASK) | (hasMore ? MORE_DATA_TAG_BIT : 0)); | |
| value = remaining; | |
| remaining >>= BITS_PER_ENCODED_BYTE; | |
| } | |
| return Arrays.copyOf(result, bytes); | |
| } | |
| // Inspired by com.android.dex.Leb128.java | |
| public static void putSleb128(DexOutputBuffer outputBuffer, int value) { | |
| int remaining = value >> BITS_PER_ENCODED_BYTE; | |
| boolean hasMore = true; | |
| int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; | |
| while (hasMore) { | |
| hasMore = (remaining != end) | |
| || ((remaining & 1) != ((value >> 6) & 1)); | |
| outputBuffer.putByte((byte) ((value & PAYLOAD_MASK) | (hasMore ? MORE_DATA_TAG_BIT : 0))); | |
| value = remaining; | |
| remaining >>= BITS_PER_ENCODED_BYTE; | |
| } | |
| } | |
| public static int sizeAsSleb128(int value) { | |
| if (value < 0) { | |
| value = ~value; | |
| } | |
| // Note the + 7 to account for the extra bit on 7-bit boundaries. | |
| return (Integer.SIZE - Integer.numberOfLeadingZeros(value) + 7) / BITS_PER_ENCODED_BYTE; | |
| } | |
| public static byte[] encodeUleb128p1(int value) { | |
| return encodeUleb128(value + 1); | |
| } | |
| public static byte[][] encodeUleb128p1(int[] values) { | |
| byte[][] result = new byte[values.length][]; | |
| for (int i = 0; i < result.length; i++) { | |
| result[i] = encodeUleb128p1(values[i]); | |
| } | |
| return result; | |
| } | |
| } |