1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2 // for details. All rights reserved. Use of this source code is governed by a 3 // BSD-style license that can be found in the LICENSE file. 4 package com.android.tools.r8.utils; 5 6 import com.android.tools.r8.dex.DexFile; 7 import com.android.tools.r8.dex.DexOutputBuffer; 8 import java.util.Arrays; 9 10 public class LebUtils { 11 private static final int BITS_PER_ENCODED_BYTE = 7; 12 private static final int PAYLOAD_MASK = 0x7f; 13 private static final int MORE_DATA_TAG_BIT = 0x80; 14 private static final int MAX_BYTES_PER_VALUE = 5; 15 parseUleb128(DexFile file)16 public static int parseUleb128(DexFile file) { 17 int result = 0; 18 byte b; 19 int shift = 0; 20 do { 21 b = file.get(); 22 result |= (b & (byte) PAYLOAD_MASK) << shift; 23 shift += BITS_PER_ENCODED_BYTE; 24 } while ((b & ~(byte) PAYLOAD_MASK) == ~(byte) PAYLOAD_MASK); 25 assert shift <= MAX_BYTES_PER_VALUE * BITS_PER_ENCODED_BYTE; // At most five bytes are used. 26 assert result >= 0; // Ensure the java int didn't overflow. 27 return result; 28 } 29 30 // Inspired by com.android.dex.Leb128.java encodeUleb128(int value)31 public static byte[] encodeUleb128(int value) { 32 byte result[] = new byte[MAX_BYTES_PER_VALUE]; 33 int remaining = value >>> BITS_PER_ENCODED_BYTE; 34 int bytes = 0; 35 while (remaining != 0) { 36 result[bytes++] = (byte) ((value & PAYLOAD_MASK) | MORE_DATA_TAG_BIT); 37 value = remaining; 38 remaining >>>= BITS_PER_ENCODED_BYTE; 39 } 40 result[bytes++] = (byte) (value & PAYLOAD_MASK); 41 return Arrays.copyOf(result, bytes); 42 } 43 44 // Inspired by com.android.dex.Leb128.java putUleb128(DexOutputBuffer outputBuffer, int value)45 public static void putUleb128(DexOutputBuffer outputBuffer, int value) { 46 int remaining = value >>> BITS_PER_ENCODED_BYTE; 47 while (remaining != 0) { 48 outputBuffer.putByte((byte) ((value & PAYLOAD_MASK) | MORE_DATA_TAG_BIT)); 49 value = remaining; 50 remaining >>>= BITS_PER_ENCODED_BYTE; 51 } 52 outputBuffer.putByte((byte) (value & PAYLOAD_MASK)); 53 } 54 sizeAsUleb128(int value)55 public static int sizeAsUleb128(int value) { 56 return Math 57 .max(1, (Integer.SIZE - Integer.numberOfLeadingZeros(value) + 6) / BITS_PER_ENCODED_BYTE); 58 } 59 parseSleb128(DexFile file)60 public static int parseSleb128(DexFile file) { 61 int result = 0; 62 byte b; 63 int shift = 0; 64 do { 65 b = file.get(); 66 result |= (b & (byte) PAYLOAD_MASK) << shift; 67 shift += BITS_PER_ENCODED_BYTE; 68 } while ((b & ~(byte) PAYLOAD_MASK) == ~(byte) PAYLOAD_MASK); 69 int mask = 1 << (shift - 1); 70 assert shift <= MAX_BYTES_PER_VALUE * BITS_PER_ENCODED_BYTE; // At most five bytes are used. 71 return (result ^ mask) - mask; 72 } 73 74 // Inspired by com.android.dex.Leb128.java encodeSleb128(int value)75 public static byte[] encodeSleb128(int value) { 76 byte result[] = new byte[MAX_BYTES_PER_VALUE]; 77 int remaining = value >> BITS_PER_ENCODED_BYTE; 78 boolean hasMore = true; 79 int end = value >= 0 ? 0 : -1; 80 int bytes = 0; 81 while (hasMore) { 82 hasMore = (remaining != end) 83 || ((remaining & 1) != ((value >> 6) & 1)); 84 result[bytes++] = (byte) ((value & PAYLOAD_MASK) | (hasMore ? MORE_DATA_TAG_BIT : 0)); 85 value = remaining; 86 remaining >>= BITS_PER_ENCODED_BYTE; 87 } 88 return Arrays.copyOf(result, bytes); 89 } 90 91 // Inspired by com.android.dex.Leb128.java putSleb128(DexOutputBuffer outputBuffer, int value)92 public static void putSleb128(DexOutputBuffer outputBuffer, int value) { 93 int remaining = value >> BITS_PER_ENCODED_BYTE; 94 boolean hasMore = true; 95 int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; 96 while (hasMore) { 97 hasMore = (remaining != end) 98 || ((remaining & 1) != ((value >> 6) & 1)); 99 outputBuffer.putByte((byte) ((value & PAYLOAD_MASK) | (hasMore ? MORE_DATA_TAG_BIT : 0))); 100 value = remaining; 101 remaining >>= BITS_PER_ENCODED_BYTE; 102 } 103 } 104 sizeAsSleb128(int value)105 public static int sizeAsSleb128(int value) { 106 if (value < 0) { 107 value = ~value; 108 } 109 // Note the + 7 to account for the extra bit on 7-bit boundaries. 110 return (Integer.SIZE - Integer.numberOfLeadingZeros(value) + 7) / BITS_PER_ENCODED_BYTE; 111 } 112 encodeUleb128p1(int value)113 public static byte[] encodeUleb128p1(int value) { 114 return encodeUleb128(value + 1); 115 } 116 encodeUleb128p1(int[] values)117 public static byte[][] encodeUleb128p1(int[] values) { 118 byte[][] result = new byte[values.length][]; 119 for (int i = 0; i < result.length; i++) { 120 result[i] = encodeUleb128p1(values[i]); 121 } 122 return result; 123 } 124 } 125