|  | // 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; | 
|  | } | 
|  | } |