blob: 437a2617ce577da2dfb278603980fa3a254d5f78 [file] [log] [blame]
// 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;
}
}