1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "namemangler.h"
17 #include <regex>
18 #include <cassert>
19 #include <map>
20
21 namespace namemangler {
22 #ifdef __MRT_DEBUG
23 #define DEBUG_ASSERT(f) assert(f)
24 #else
25 #define DEBUG_ASSERT(f) ((void)0)
26 #endif
27
28 const int kLocalCodebufSize = 1024;
29 const int kMaxCodecbufSize = (1 << 16); // Java spec support a max name length of 64K.
30
31 #define GETHEXCHAR(n) static_cast<char>((n) < 10 ? (n) + '0' : (n)-10 + 'a')
32 #define GETHEXCHARU(n) static_cast<char>((n) < 10 ? (n) + '0' : (n)-10 + 'A')
33
34 bool doCompression = false;
35
36 // Store a mapping between full string and its compressed version
37 // More frequent and specific strings go before general ones,
38 // e.g. Ljava_2Flang_2FObject_3B goes before Ljava_2Flang_2F
39 //
40 using StringMap = std::map<const std::string, const std::string>;
41
42 const StringMap kInternalMangleTable = {
43 {"Ljava_2Flang_2FObject_3B", "L0_3B"}, {"Ljava_2Flang_2FClass_3B", "L1_3B"}, {"Ljava_2Flang_2FString_3B", "L2_3B"}};
44
45 // This mapping is mainly used for compressing annotation strings
46 const StringMap kOriginalMangleTable = {
47 {"Ljava/lang/Object", "L0"}, {"Ljava/lang/Class", "L1"}, {"Ljava/lang/String", "L2"}};
48
49 // The returned buffer needs to be explicitly freed
AllocCodecBuf(size_t maxLen)50 static inline char *AllocCodecBuf(size_t maxLen)
51 {
52 if (maxLen == 0) {
53 return nullptr;
54 }
55 // each char may have 2 more char, so give out the max space buffer
56 constexpr int multi = 3;
57 return reinterpret_cast<char *>(malloc((maxLen <= kLocalCodebufSize) ? multi * maxLen : multi * kMaxCodecbufSize));
58 }
59
FreeCodecBuf(char * buf)60 static inline void FreeCodecBuf(char *buf)
61 {
62 free(buf);
63 }
64
CompressName(std::string & name,const StringMap & mapping=kInternalMangleTable)65 static std::string CompressName(std::string &name, const StringMap &mapping = kInternalMangleTable)
66 {
67 for (auto &entry : mapping) {
68 if (name.find(entry.first) != std::string::npos) {
69 name = std::regex_replace(name, std::regex(entry.first), entry.second);
70 }
71 }
72 return name;
73 }
74
DecompressName(std::string & name,const StringMap & mapping=kInternalMangleTable)75 static std::string DecompressName(std::string &name, const StringMap &mapping = kInternalMangleTable)
76 {
77 for (auto &entry : mapping) {
78 if (name.find(entry.second) != std::string::npos) {
79 name = std::regex_replace(name, std::regex(entry.second), entry.first);
80 }
81 }
82 return name;
83 }
84
GetInternalNameLiteral(std::string name)85 std::string GetInternalNameLiteral(std::string name)
86 {
87 return (doCompression ? CompressName(name) : name);
88 }
89
GetOriginalNameLiteral(std::string name)90 std::string GetOriginalNameLiteral(std::string name)
91 {
92 return (doCompression ? CompressName(name, kOriginalMangleTable) : name);
93 }
94
EncodeName(const std::string & name)95 std::string EncodeName(const std::string &name)
96 {
97 // name is guaranteed to be null-terminated
98 size_t nameLen = name.length();
99 nameLen = nameLen > kMaxCodecbufSize ? kMaxCodecbufSize : nameLen;
100 char *buf = AllocCodecBuf(nameLen);
101 if (buf == nullptr) {
102 return std::string(name);
103 }
104
105 size_t pos = 0;
106 size_t i = 0;
107 std::string str(name);
108 std::u16string str16;
109 while (i < nameLen) {
110 unsigned char c = static_cast<unsigned char>(name[i]);
111 if (c == '_') {
112 buf[pos++] = '_';
113 buf[pos++] = '_';
114 } else if (c == '[') {
115 buf[pos++] = 'A';
116 } else if (isalnum(c)) {
117 buf[pos++] = static_cast<char>(c);
118 } else if (c <= 0x7F) {
119 // _XX: '_' followed by ascii code in hex
120 if (c == '.') {
121 c = '/'; // use / in package name
122 }
123 buf[pos++] = '_';
124 unsigned char n = c >> 4; // get the high 4 bit and calculate
125 buf[pos++] = GETHEXCHARU(n);
126 n = static_cast<unsigned char>(c - static_cast<unsigned char>(n << 4)); // revert the high 4 bit
127 buf[pos++] = GETHEXCHARU(n);
128 } else {
129 str16.clear();
130 // process one 16-bit char at a time
131 unsigned int n = UTF8ToUTF16(str16, str.substr(i), 1, false);
132 buf[pos++] = '_';
133 if ((n >> 16) == 1) { // if n is 16-bit
134 unsigned short m = str16[0];
135 buf[pos++] = 'u';
136 buf[pos++] = GETHEXCHAR((m & 0xF000) >> 12);
137 buf[pos++] = GETHEXCHAR((m & 0x0F00) >> 8);
138 buf[pos++] = GETHEXCHAR((m & 0x00F0) >> 4);
139 buf[pos++] = GETHEXCHAR(m & 0x000F);
140 } else {
141 unsigned short m = str16[0];
142 buf[pos++] = 'U';
143 buf[pos++] = GETHEXCHAR((m & 0xF000) >> 12);
144 buf[pos++] = GETHEXCHAR((m & 0x0F00) >> 8);
145 buf[pos++] = GETHEXCHAR((m & 0x00F0) >> 4);
146 buf[pos++] = GETHEXCHAR(m & 0x000F);
147 m = str16[1];
148 buf[pos++] = GETHEXCHAR((m & 0xF000) >> 12);
149 buf[pos++] = GETHEXCHAR((m & 0x0F00) >> 8);
150 buf[pos++] = GETHEXCHAR((m & 0x00F0) >> 4);
151 buf[pos++] = GETHEXCHAR(m & 0x000F);
152 }
153 i += static_cast<size_t>(int32_t(n & 0xFFFF) - 1);
154 }
155 i++;
156 }
157
158 buf[pos] = '\0';
159 std::string newName = std::string(buf, pos);
160 FreeCodecBuf(buf);
161 if (doCompression) {
162 newName = CompressName(newName);
163 }
164 return newName;
165 }
166
UpdatePrimType(bool primType,int splitNo,uint32_t ch)167 static inline bool UpdatePrimType(bool primType, int splitNo, uint32_t ch)
168 {
169 if (ch == 'L') {
170 return false;
171 }
172
173 if (((ch == ';') || (ch == '(') || (ch == ')')) && (splitNo > 1)) {
174 return true;
175 }
176
177 return primType;
178 }
179
180 namespace {
181 constexpr int kNumLimit = 10;
182 constexpr int kCodeOffset3 = 12;
183 constexpr int kCodeOffset2 = 8;
184 constexpr int kCodeOffset = 4;
185 constexpr int kJavaStrLength = 5;
186 constexpr size_t k64BitShift = 6; // 64 is 1 << 6
187 }
188
DecodeName(const std::string & name)189 std::string DecodeName(const std::string &name)
190 {
191 if (name.find(';') != std::string::npos) { // no need Decoding a non-encoded string
192 return name;
193 }
194 std::string decompressedName;
195 const char *namePtr = nullptr;
196 size_t nameLen;
197
198 if (doCompression) {
199 decompressedName = name;
200 decompressedName = DecompressName(decompressedName);
201 namePtr = decompressedName.c_str();
202 nameLen = decompressedName.length();
203 } else {
204 namePtr = name.c_str();
205 nameLen = name.length();
206 }
207
208 // Demangled name is supposed to be shorter. No buffer overflow issue here.
209 std::string newName(nameLen, '\0');
210
211 bool primType = true;
212 int splitNo = 0; // split: class 0 | method 1 | signature 2
213 size_t pos = 0;
214 std::string str;
215 std::u16string str16;
216 for (size_t i = 0; i < nameLen;) {
217 unsigned char c = static_cast<unsigned char>(namePtr[i]);
218 ++i;
219 if (c == '_') { // _XX: '_' followed by ascii code in hex
220 if (i >= nameLen) {
221 break;
222 }
223 if (namePtr[i] == '_') {
224 newName[pos++] = namePtr[i++];
225 } else if (namePtr[i] == 'u') {
226 str.clear();
227 str16.clear();
228 i++;
229 c = static_cast<unsigned char>(namePtr[i++]);
230 uint8_t b1 = (c <= '9') ? c - '0' : c - 'a' + kNumLimit;
231 c = static_cast<unsigned char>(namePtr[i++]);
232 uint8_t b2 = (c <= '9') ? c - '0' : c - 'a' + kNumLimit;
233 c = static_cast<unsigned char>(namePtr[i++]);
234 uint8_t b3 = (c <= '9') ? c - '0' : c - 'a' + kNumLimit;
235 c = static_cast<unsigned char>(namePtr[i++]);
236 uint8_t b4 = (c <= '9') ? c - '0' : c - 'a' + kNumLimit;
237 uint32_t codepoint = (b1 << kCodeOffset3) | (b2 << kCodeOffset2) | (b3 << kCodeOffset) | b4;
238 str16 += (char16_t)codepoint;
239 unsigned int count = UTF16ToUTF8(str, str16, 1, false) >> 16; // shift 16 to get count
240 if (count == 2) { // the count of str equal 2 to 4, use array to save the utf8
241 newName[pos++] = str[0];
242 newName[pos++] = str[1];
243 } else if (count == 3) {
244 newName[pos++] = str[0];
245 newName[pos++] = str[1];
246 newName[pos++] = str[2]; // 2 is index of third char
247 } else if (count == 4) {
248 newName[pos++] = str[0];
249 newName[pos++] = str[1];
250 newName[pos++] = str[2]; // 2 is index of third char
251 newName[pos++] = str[3]; // 3 is index of fourth char
252 }
253 } else {
254 c = static_cast<unsigned char>(namePtr[i++]);
255 unsigned int v = (c <= '9') ? c - '0' : c - 'A' + kNumLimit;
256 unsigned int asc = v << kCodeOffset;
257 if (i >= nameLen) {
258 break;
259 }
260 c = static_cast<unsigned char>(namePtr[i++]);
261 v = (c <= '9') ? c - '0' : c - 'A' + kNumLimit;
262 asc += v;
263
264 newName[pos++] = static_cast<char>(asc);
265
266 if (asc == '|') {
267 splitNo++;
268 }
269
270 primType = UpdatePrimType(primType, splitNo, asc);
271 }
272 } else {
273 if (splitNo < 2) { // split: class 0 | method 1 | signature 2
274 newName[pos++] = static_cast<char>(c);
275 continue;
276 }
277
278 primType = UpdatePrimType(primType, splitNo, c);
279 if (primType) {
280 newName[pos++] = (c == 'A') ? '[' : c;
281 } else {
282 newName[pos++] = static_cast<char>(c);
283 }
284 }
285 }
286
287 newName.resize(pos);
288 return newName;
289 }
290
291 // input: maple name
292 // output: Ljava/lang/Object; [Ljava/lang/Object;
DecodeMapleNameToJavaDescriptor(const std::string & nameIn,std::string & nameOut)293 void DecodeMapleNameToJavaDescriptor(const std::string &nameIn, std::string &nameOut)
294 {
295 nameOut = DecodeName(nameIn);
296 if (nameOut[0] == 'A') {
297 size_t i = 0;
298 while (nameOut[i] == 'A') {
299 nameOut[i++] = '[';
300 }
301 }
302 }
303
304 // convert maple name to java name
305 // http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names
NativeJavaName(const std::string & name,bool overLoaded)306 std::string NativeJavaName(const std::string &name, bool overLoaded)
307 {
308 // Decompress name first because the generated native function name needs
309 // to follow certain spec, not something maple can control.
310 std::string decompressedName(name);
311 if (doCompression) {
312 decompressedName = DecompressName(decompressedName);
313 }
314
315 unsigned int nameLen = static_cast<unsigned int>(decompressedName.length()) + kJavaStrLength;
316 std::string newName = "Java_";
317 unsigned int i = 0;
318
319 // leading A's are array
320 while (i < nameLen && name[i] == 'A') {
321 newName += "_3";
322 i++;
323 }
324
325 bool isProto = false; // class names in prototype have 'L' and ';'
326 bool isFuncname = false;
327 bool isTypename = false;
328 while (i < nameLen) {
329 char c = decompressedName[i];
330 if (c == '_') {
331 i++;
332 // UTF16 unicode
333 if (decompressedName[i] == 'u') {
334 newName += "_0";
335 i++;
336 } else if (decompressedName[i] == '_') {
337 newName += "_1";
338 i++;
339 } else {
340 // _XX: '_' followed by ascii code in hex
341 c = decompressedName[i++];
342 unsigned char v = (c <= '9') ? c - '0' : c - 'A' + kNumLimit;
343 unsigned char asc = v << kCodeOffset;
344 c = decompressedName[i++];
345 v = (c <= '9') ? c - '0' : c - 'A' + kNumLimit;
346 asc += v;
347 if (asc == '/') {
348 newName += "_";
349 } else if (asc == '|' && !isFuncname) {
350 newName += "_";
351 isFuncname = true;
352 } else if (asc == '|' && isFuncname) {
353 if (!overLoaded) {
354 break;
355 }
356 newName += "_";
357 isFuncname = false;
358 } else if (asc == '(') {
359 newName += "_";
360 isProto = true;
361 } else if (asc == ')') {
362 break;
363 } else if (asc == ';' && !isFuncname) {
364 if (isProto) {
365 newName += "_2";
366 }
367 isTypename = false;
368 } else if (asc == '$') {
369 newName += "_00024";
370 } else if (asc == '-') {
371 newName += "_0002d";
372 } else {
373 printf("name = %s\n", decompressedName.c_str());
374 printf("c = %c\n", asc);
375 DEBUG_ASSERT(false && "more cases in NativeJavaName");
376 }
377 }
378 } else {
379 if (c == 'L' && !isFuncname && !isTypename) {
380 if (isProto) {
381 newName += c;
382 }
383 isTypename = true;
384 i++;
385 } else if (c == 'A' && !isTypename && !isFuncname) {
386 while (name[i] == 'A') {
387 newName += "_3";
388 i++;
389 }
390 } else {
391 newName += c;
392 i++;
393 }
394 }
395 }
396 return newName;
397 }
398
ChangeEndian16(uint16_t u16)399 static uint16_t ChangeEndian16(uint16_t u16)
400 {
401 return ((u16 & 0xFF00) >> kCodeOffset2) | ((u16 & 0xFF) << kCodeOffset2);
402 }
403
404 /* UTF8
405 * U+0000 - U+007F 0xxxxxxx
406 * U+0080 - U+07FF 110xxxxx 10xxxxxx
407 * U+0800 - U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
408 * U+10000- U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
409 *
410 * UTF16
411 * U+0000 - U+D7FF codePoint
412 * U+E000 - U+FFFF codePoint
413 * U+10000- U+10FFFF XXXX YYYY
414 * code = codePoint - 0x010000, ie, 20-bit number in the range 0x000000..0x0FFFFF
415 * XXXX: top 10 bits of code + 0xD800: 0xD800..0xDBFF
416 * YYYY: low 10 bits of code + 0xDC00: 0xDC00..0xDFFF
417 *
418 * convert upto num UTF8 elements
419 * return two 16-bit values: return_number_of_elements | consumed_input_number_of_elements
420 */
421 const int kCodepointOffset1 = 6; // U+0080 - U+07FF 110xxxxx 10xxxxxx
422 const int kCodepointOffset2 = 12; // U+0800 - U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
423 const int kCodepointOffset3 = 18; // U+10000- U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
424 const int kCountOffset = 16;
425 const int kCodeAfterMinusOffset = 10; // codePoint equals itself minus 0x10000
426
UTF16ToUTF8(std::string & str,const std::u16string & str16,unsigned short num,bool isBigEndian)427 unsigned UTF16ToUTF8(std::string &str, const std::u16string &str16, unsigned short num, bool isBigEndian)
428 {
429 uint32_t codePoint = 0;
430 uint32_t i = 0;
431 unsigned short count = 0;
432 unsigned short retNum = 0;
433 while (i < str16.length()) {
434 if (isBigEndian || num == 1) {
435 codePoint = str16[i++];
436 } else {
437 codePoint = ChangeEndian16(str16[i++]);
438 }
439 if (codePoint > 0xFFFF) {
440 codePoint &= 0x3FF;
441 codePoint <<= kNumLimit;
442 if (isBigEndian) {
443 codePoint += str16[i++] & 0x3FF;
444 } else {
445 codePoint += ChangeEndian16(str16[i++]) & 0x3FF;
446 }
447 }
448 if (codePoint <= 0x7F) {
449 str += static_cast<char>(codePoint);
450 retNum += 1; // 1 UTF8 char
451 } else if (codePoint <= 0x7FF) {
452 str += static_cast<char>(0xC0 + (codePoint >> kCodepointOffset1));
453 str += static_cast<char>(0x80 + (codePoint & 0x3F));
454 retNum += 2; // 2 UTF8 chars
455 } else if (codePoint <= 0xFFFF) {
456 str += static_cast<char>(0xE0 + ((codePoint >> kCodepointOffset2) & 0xF));
457 str += static_cast<char>(0x80 + ((codePoint >> kCodepointOffset1) & 0x3F));
458 str += static_cast<char>(0x80 + (codePoint & 0x3F));
459 retNum += 3; // 3 UTF8 chars
460 } else {
461 str += static_cast<char>(0xF0 + ((codePoint >> kCodepointOffset3) & 0x7));
462 str += static_cast<char>(0x80 + ((codePoint >> kCodepointOffset2) & 0x3F));
463 str += static_cast<char>(0x80 + ((codePoint >> kCodepointOffset1) & 0x3F));
464 str += static_cast<char>(0x80 + (codePoint & 0x3F));
465 retNum += 4; // 4 UTF8 chars
466 }
467 count++;
468 if (num == count) {
469 return ((static_cast<unsigned>(retNum)) << kCountOffset) | static_cast<unsigned>(i);
470 }
471 }
472 return i;
473 }
474
NeedConvertUTF16(const std::string & str8)475 bool NeedConvertUTF16(const std::string &str8)
476 {
477 uint32_t a = 0;
478 size_t i = 0;
479 size_t size = str8.length();
480 while (i < size) {
481 a = static_cast<uint8_t>(str8[i++]);
482 constexpr uint8_t maxValidAscii = 0x7F;
483 if (a > maxValidAscii) {
484 return true;
485 }
486 }
487 return false;
488 }
489
GetCodePoint(const std::string & str8,uint32_t & i)490 uint32_t GetCodePoint(const std::string &str8, uint32_t &i)
491 {
492 uint32_t b;
493 uint32_t c;
494 uint32_t d;
495 uint32_t codePoint = 0;
496 uint32_t a = static_cast<uint8_t>(str8[i++]);
497 if (a <= 0x7F) { // 0...
498 codePoint = a;
499 } else if (a >= 0xF0) { // 11110...
500 b = static_cast<uint32_t>(str8[i++]);
501 c = static_cast<uint32_t>(str8[i++]);
502 d = static_cast<uint32_t>(str8[i++]);
503 codePoint = ((a & 0x7) << kCodepointOffset3) | ((b & 0x3F) << kCodepointOffset2) |
504 ((c & 0x3F) << kCodepointOffset1) | (d & 0x3F);
505 } else if (a >= 0xE0) { // 1110...
506 b = static_cast<uint32_t>(str8[i++]);
507 c = static_cast<uint32_t>(str8[i++]);
508 codePoint = ((a & 0xF) << kCodepointOffset2) | ((b & 0x3F) << kCodepointOffset1) | (c & 0x3F);
509 } else if (a >= 0xC0) { // 110...
510 b = static_cast<uint32_t>(str8[i++]);
511 codePoint = ((a & 0x1F) << kCodepointOffset1) | (b & 0x3F);
512 } else {
513 DEBUG_ASSERT(false && "invalid UTF-8");
514 }
515 return codePoint;
516 }
517
518 // convert upto num UTF16 elements
519 // two 16-bit values: return_number_of_elements | consumed_input_number_of_elements
UTF8ToUTF16(std::u16string & str16,const std::string & str8,unsigned short num,bool isBigEndian)520 unsigned UTF8ToUTF16(std::u16string &str16, const std::string &str8, unsigned short num, bool isBigEndian)
521 {
522 uint32_t i = 0;
523 unsigned short count = 0;
524 unsigned short retNum = 0;
525 while (i < str8.length()) {
526 uint32_t codePoint = GetCodePoint(str8, i);
527 if (codePoint <= 0xFFFF) {
528 if (isBigEndian || num == 1) {
529 str16 += static_cast<char16_t>(codePoint);
530 } else {
531 str16 += static_cast<char16_t>(ChangeEndian16(static_cast<uint16_t>(codePoint)));
532 }
533 retNum += 1; // 1 utf16
534 } else {
535 codePoint -= 0x10000;
536 if (isBigEndian || num == 1) {
537 str16 += static_cast<char16_t>((codePoint >> kCodeAfterMinusOffset) | 0xD800);
538 str16 += static_cast<char16_t>((codePoint & 0x3FF) | 0xDC00);
539 } else {
540 str16 += static_cast<char16_t>(
541 ChangeEndian16(static_cast<uint16_t>((codePoint >> kCodeAfterMinusOffset) | 0xD800)));
542 str16 += static_cast<char16_t>(ChangeEndian16((codePoint & 0x3FF) | 0xDC00));
543 }
544 retNum += 2; // 2 utf16
545 }
546 count++;
547 // only convert num elmements
548 if (num == count) {
549 return (static_cast<char16_t>(retNum) << kCountOffset) | static_cast<char16_t>(i);
550 }
551 }
552 return i;
553 }
554
555 const uint32_t kGreybackOffset = 7;
GetUnsignedLeb128Encode(std::vector<uint8_t> & dest,uint32_t value)556 void GetUnsignedLeb128Encode(std::vector<uint8_t> &dest, uint32_t value)
557 {
558 bool done = false;
559 do {
560 uint8_t byte = value & 0x7f;
561 value >>= kGreybackOffset;
562 done = (value == 0);
563 if (!done) {
564 byte |= 0x80;
565 }
566 dest.push_back(byte);
567 } while (!done);
568 }
569
GetUnsignedLeb128Decode(const uint8_t ** data)570 uint32_t GetUnsignedLeb128Decode(const uint8_t **data)
571 {
572 DEBUG_ASSERT(data != nullptr && "data in GetUnsignedLeb128Decode() is nullptr");
573 const uint8_t *ptr = *data;
574 uint32_t result = 0;
575 uint32_t shift = 0;
576 uint8_t byte = 0;
577 while (true) {
578 byte = *(ptr++);
579 result |= (byte & 0x7f) << shift;
580 if ((byte & 0x80) == 0) {
581 break;
582 }
583 shift += kGreybackOffset;
584 }
585 *data = ptr;
586 return result;
587 }
588
GetLEB128Encode(int64_t val,bool isUnsigned)589 uint64_t GetLEB128Encode(int64_t val, bool isUnsigned)
590 {
591 uint64_t res = 0;
592 uint8_t byte = 0;
593 uint8_t count = 0;
594 bool done = false;
595 do {
596 byte = static_cast<uint64_t>(val) & 0x7f;
597 val >>= kGreybackOffset; // intended signed shift: block codedex here
598 done = (isUnsigned ? val == 0 : (val == 0 || val == -1));
599 if (!done) {
600 byte |= 0x80;
601 }
602 res |= (static_cast<uint64_t>(byte) << (count++ << 3)); // each byte need 8 bit (left shift 3)
603 } while (!done);
604 return res;
605 }
606
GetUleb128Encode(uint64_t val)607 uint64_t GetUleb128Encode(uint64_t val)
608 {
609 return GetLEB128Encode(int64_t(val), true);
610 }
611
GetSleb128Encode(int64_t val)612 uint64_t GetSleb128Encode(int64_t val)
613 {
614 return GetLEB128Encode(val, false);
615 }
616
GetUleb128Decode(uint64_t val)617 uint64_t GetUleb128Decode(uint64_t val)
618 {
619 return val;
620 }
621
GetSleb128Decode(uint64_t val)622 int64_t GetSleb128Decode(uint64_t val)
623 {
624 return static_cast<int64_t>(val);
625 }
626
GetUleb128Size(uint64_t v)627 size_t GetUleb128Size(uint64_t v)
628 {
629 DEBUG_ASSERT(v && "if v == 0, __builtin_clzll(v) is not defined");
630 size_t clz = static_cast<size_t>(__builtin_clzll(v));
631 // num of 7-bit groups, (64 - clz + 6) / 7
632 return size_t((64 - clz + 6) / 7);
633 }
634
GetSleb128Size(int32_t v)635 size_t GetSleb128Size(int32_t v)
636 {
637 size_t size = 0;
638 int rem = v >> kGreybackOffset;
639 bool hasMore = true;
640 int end = ((v >= 0) ? 0 : -1);
641
642 while (hasMore) {
643 hasMore = (rem != end) || ((rem & 1) != ((v >> k64BitShift) & 1)); // judege whether has More valid rem
644 size++;
645 v = rem;
646 rem >>= static_cast<int>(kGreybackOffset); // intended signed shift: block codedex here
647 }
648 return size;
649 }
650 } // namespace namemangler
651