• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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