1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_LEB128_H_
18 #define ART_RUNTIME_LEB128_H_
19 
20 #include "globals.h"
21 #include "utils.h"
22 
23 namespace art {
24 
25 // Reads an unsigned LEB128 value, updating the given pointer to point
26 // just past the end of the read value. This function tolerates
27 // non-zero high-order bits in the fifth encoded byte.
DecodeUnsignedLeb128(const uint8_t ** data)28 static inline uint32_t DecodeUnsignedLeb128(const uint8_t** data) {
29   const uint8_t* ptr = *data;
30   int result = *(ptr++);
31   if (UNLIKELY(result > 0x7f)) {
32     int cur = *(ptr++);
33     result = (result & 0x7f) | ((cur & 0x7f) << 7);
34     if (cur > 0x7f) {
35       cur = *(ptr++);
36       result |= (cur & 0x7f) << 14;
37       if (cur > 0x7f) {
38         cur = *(ptr++);
39         result |= (cur & 0x7f) << 21;
40         if (cur > 0x7f) {
41           // Note: We don't check to see if cur is out of range here,
42           // meaning we tolerate garbage in the four high-order bits.
43           cur = *(ptr++);
44           result |= cur << 28;
45         }
46       }
47     }
48   }
49   *data = ptr;
50   return static_cast<uint32_t>(result);
51 }
52 
53 // Reads an unsigned LEB128 + 1 value. updating the given pointer to point
54 // just past the end of the read value. This function tolerates
55 // non-zero high-order bits in the fifth encoded byte.
56 // It is possible for this function to return -1.
DecodeUnsignedLeb128P1(const uint8_t ** data)57 static inline int32_t DecodeUnsignedLeb128P1(const uint8_t** data) {
58   return DecodeUnsignedLeb128(data) - 1;
59 }
60 
61 // Reads a signed LEB128 value, updating the given pointer to point
62 // just past the end of the read value. This function tolerates
63 // non-zero high-order bits in the fifth encoded byte.
DecodeSignedLeb128(const uint8_t ** data)64 static inline int32_t DecodeSignedLeb128(const uint8_t** data) {
65   const uint8_t* ptr = *data;
66   int32_t result = *(ptr++);
67   if (result <= 0x7f) {
68     result = (result << 25) >> 25;
69   } else {
70     int cur = *(ptr++);
71     result = (result & 0x7f) | ((cur & 0x7f) << 7);
72     if (cur <= 0x7f) {
73       result = (result << 18) >> 18;
74     } else {
75       cur = *(ptr++);
76       result |= (cur & 0x7f) << 14;
77       if (cur <= 0x7f) {
78         result = (result << 11) >> 11;
79       } else {
80         cur = *(ptr++);
81         result |= (cur & 0x7f) << 21;
82         if (cur <= 0x7f) {
83           result = (result << 4) >> 4;
84         } else {
85           // Note: We don't check to see if cur is out of range here,
86           // meaning we tolerate garbage in the four high-order bits.
87           cur = *(ptr++);
88           result |= cur << 28;
89         }
90       }
91     }
92   }
93   *data = ptr;
94   return result;
95 }
96 
97 // Returns the number of bytes needed to encode the value in unsigned LEB128.
UnsignedLeb128Size(uint32_t data)98 static inline uint32_t UnsignedLeb128Size(uint32_t data) {
99   // bits_to_encode = (data != 0) ? 32 - CLZ(x) : 1  // 32 - CLZ(data | 1)
100   // bytes = ceil(bits_to_encode / 7.0);             // (6 + bits_to_encode) / 7
101   uint32_t x = 6 + 32 - CLZ(data | 1);
102   // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7).
103   // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85.
104   return (x * 37) >> 8;
105 }
106 
107 // Returns the number of bytes needed to encode the value in unsigned LEB128.
SignedLeb128Size(int32_t data)108 static inline uint32_t SignedLeb128Size(int32_t data) {
109   // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign.
110   data = data ^ (data >> 31);
111   uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1);
112   return (x * 37) >> 8;
113 }
114 
EncodeUnsignedLeb128(uint8_t * dest,uint32_t value)115 static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) {
116   uint8_t out = value & 0x7f;
117   value >>= 7;
118   while (value != 0) {
119     *dest++ = out | 0x80;
120     out = value & 0x7f;
121     value >>= 7;
122   }
123   *dest++ = out;
124   return dest;
125 }
126 
EncodeSignedLeb128(uint8_t * dest,int32_t value)127 static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) {
128   uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
129   uint8_t out = value & 0x7f;
130   while (extra_bits != 0u) {
131     *dest++ = out | 0x80;
132     value >>= 7;
133     out = value & 0x7f;
134     extra_bits >>= 7;
135   }
136   *dest++ = out;
137   return dest;
138 }
139 
140 // An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
141 class Leb128EncodingVector {
142  public:
Leb128EncodingVector()143   Leb128EncodingVector() {
144   }
145 
Reserve(uint32_t size)146   void Reserve(uint32_t size) {
147     data_.reserve(size);
148   }
149 
PushBackUnsigned(uint32_t value)150   void PushBackUnsigned(uint32_t value) {
151     uint8_t out = value & 0x7f;
152     value >>= 7;
153     while (value != 0) {
154       data_.push_back(out | 0x80);
155       out = value & 0x7f;
156       value >>= 7;
157     }
158     data_.push_back(out);
159   }
160 
161   template<typename It>
InsertBackUnsigned(It cur,It end)162   void InsertBackUnsigned(It cur, It end) {
163     for (; cur != end; ++cur) {
164       PushBackUnsigned(*cur);
165     }
166   }
167 
PushBackSigned(int32_t value)168   void PushBackSigned(int32_t value) {
169     uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
170     uint8_t out = value & 0x7f;
171     while (extra_bits != 0u) {
172       data_.push_back(out | 0x80);
173       value >>= 7;
174       out = value & 0x7f;
175       extra_bits >>= 7;
176     }
177     data_.push_back(out);
178   }
179 
180   template<typename It>
InsertBackSigned(It cur,It end)181   void InsertBackSigned(It cur, It end) {
182     for (; cur != end; ++cur) {
183       PushBackSigned(*cur);
184     }
185   }
186 
GetData()187   const std::vector<uint8_t>& GetData() const {
188     return data_;
189   }
190 
191  private:
192   std::vector<uint8_t> data_;
193 
194   DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector);
195 };
196 
197 }  // namespace art
198 
199 #endif  // ART_RUNTIME_LEB128_H_
200