From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- third_party/wasm2c/src/leb128.cc | 361 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 third_party/wasm2c/src/leb128.cc (limited to 'third_party/wasm2c/src/leb128.cc') diff --git a/third_party/wasm2c/src/leb128.cc b/third_party/wasm2c/src/leb128.cc new file mode 100644 index 0000000000..29b20f61bc --- /dev/null +++ b/third_party/wasm2c/src/leb128.cc @@ -0,0 +1,361 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wabt/leb128.h" + +#include + +#include "wabt/stream.h" + +#define MAX_U32_LEB128_BYTES 5 +#define MAX_U64_LEB128_BYTES 10 + +namespace wabt { + +Offset U32Leb128Length(uint32_t value) { + uint32_t size = 0; + do { + value >>= 7; + size++; + } while (value != 0); + return size; +} + +#define LEB128_LOOP_UNTIL(end_cond) \ + do { \ + uint8_t byte = value & 0x7f; \ + value >>= 7; \ + if (end_cond) { \ + data[length++] = byte; \ + break; \ + } else { \ + data[length++] = byte | 0x80; \ + } \ + } while (1) + +Offset WriteFixedU32Leb128At(Stream* stream, + Offset offset, + uint32_t value, + const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = + WriteFixedU32Leb128Raw(data, data + MAX_U32_LEB128_BYTES, value); + stream->WriteDataAt(offset, data, length, desc); + return length; +} + +void WriteU32Leb128(Stream* stream, uint32_t value, const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(value == 0); + stream->WriteData(data, length, desc); +} + +void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = + WriteFixedU32Leb128Raw(data, data + MAX_U32_LEB128_BYTES, value); + stream->WriteData(data, length, desc); +} + +// returns the length of the leb128. +Offset WriteU32Leb128At(Stream* stream, + Offset offset, + uint32_t value, + const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(value == 0); + stream->WriteDataAt(offset, data, length, desc); + return length; +} + +Offset WriteU32Leb128Raw(uint8_t* dest, uint8_t* dest_end, uint32_t value) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(value == 0); + if (static_cast(dest_end - dest) < length) { + return 0; + } + memcpy(dest, data, length); + return length; +} + +Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value) { + if (end - data < MAX_U32_LEB128_BYTES) { + return 0; + } + data[0] = (value & 0x7f) | 0x80; + data[1] = ((value >> 7) & 0x7f) | 0x80; + data[2] = ((value >> 14) & 0x7f) | 0x80; + data[3] = ((value >> 21) & 0x7f) | 0x80; + data[4] = ((value >> 28) & 0x0f); + return MAX_U32_LEB128_BYTES; +} + +static void WriteS32Leb128(Stream* stream, int32_t value, const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = 0; + if (value < 0) { + LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40)); + } else { + LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); + } + + stream->WriteData(data, length, desc); +} + +static void WriteS64Leb128(Stream* stream, int64_t value, const char* desc) { + uint8_t data[MAX_U64_LEB128_BYTES]; + Offset length = 0; + if (value < 0) { + LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40)); + } else { + LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40)); + } + + stream->WriteData(data, length, desc); +} + +void WriteS32Leb128(Stream* stream, uint32_t value, const char* desc) { + WriteS32Leb128(stream, Bitcast(value), desc); +} + +void WriteU64Leb128(Stream* stream, uint64_t value, const char* desc) { + uint8_t data[MAX_U64_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(value == 0); + stream->WriteData(data, length, desc); +} + +void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc) { + WriteS64Leb128(stream, Bitcast(value), desc); +} + +void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc) { + uint8_t data[MAX_U32_LEB128_BYTES]; + data[0] = (value & 0x7f) | 0x80; + data[1] = ((value >> 7) & 0x7f) | 0x80; + data[2] = ((value >> 14) & 0x7f) | 0x80; + data[3] = ((value >> 21) & 0x7f) | 0x80; + // The last byte needs to be sign-extended. + data[4] = ((value >> 28) & 0x0f); + if (static_cast(value) < 0) { + data[4] |= 0x70; + } + stream->WriteData(data, MAX_U32_LEB128_BYTES, desc); +} + +#undef LEB128_LOOP_UNTIL + +#define BYTE_AT(type, i, shift) ((static_cast(p[i]) & 0x7f) << (shift)) + +#define LEB128_1(type) (BYTE_AT(type, 0, 0)) +#define LEB128_2(type) (BYTE_AT(type, 1, 7) | LEB128_1(type)) +#define LEB128_3(type) (BYTE_AT(type, 2, 14) | LEB128_2(type)) +#define LEB128_4(type) (BYTE_AT(type, 3, 21) | LEB128_3(type)) +#define LEB128_5(type) (BYTE_AT(type, 4, 28) | LEB128_4(type)) +#define LEB128_6(type) (BYTE_AT(type, 5, 35) | LEB128_5(type)) +#define LEB128_7(type) (BYTE_AT(type, 6, 42) | LEB128_6(type)) +#define LEB128_8(type) (BYTE_AT(type, 7, 49) | LEB128_7(type)) +#define LEB128_9(type) (BYTE_AT(type, 8, 56) | LEB128_8(type)) +#define LEB128_10(type) (BYTE_AT(type, 9, 63) | LEB128_9(type)) + +#define SHIFT_AMOUNT(type, sign_bit) (sizeof(type) * 8 - 1 - (sign_bit)) +#define SIGN_EXTEND(type, value, sign_bit) \ + (static_cast((value) << SHIFT_AMOUNT(type, sign_bit)) >> \ + SHIFT_AMOUNT(type, sign_bit)) + +size_t ReadU32Leb128(const uint8_t* p, + const uint8_t* end, + uint32_t* out_value) { + if (p < end && (p[0] & 0x80) == 0) { + *out_value = LEB128_1(uint32_t); + return 1; + } else if (p + 1 < end && (p[1] & 0x80) == 0) { + *out_value = LEB128_2(uint32_t); + return 2; + } else if (p + 2 < end && (p[2] & 0x80) == 0) { + *out_value = LEB128_3(uint32_t); + return 3; + } else if (p + 3 < end && (p[3] & 0x80) == 0) { + *out_value = LEB128_4(uint32_t); + return 4; + } else if (p + 4 < end && (p[4] & 0x80) == 0) { + // The top bits set represent values > 32 bits. + if (p[4] & 0xf0) { + return 0; + } + *out_value = LEB128_5(uint32_t); + return 5; + } else { + // past the end. + *out_value = 0; + return 0; + } +} + +size_t ReadU64Leb128(const uint8_t* p, + const uint8_t* end, + uint64_t* out_value) { + if (p < end && (p[0] & 0x80) == 0) { + *out_value = LEB128_1(uint64_t); + return 1; + } else if (p + 1 < end && (p[1] & 0x80) == 0) { + *out_value = LEB128_2(uint64_t); + return 2; + } else if (p + 2 < end && (p[2] & 0x80) == 0) { + *out_value = LEB128_3(uint64_t); + return 3; + } else if (p + 3 < end && (p[3] & 0x80) == 0) { + *out_value = LEB128_4(uint64_t); + return 4; + } else if (p + 4 < end && (p[4] & 0x80) == 0) { + *out_value = LEB128_5(uint64_t); + return 5; + } else if (p + 5 < end && (p[5] & 0x80) == 0) { + *out_value = LEB128_6(uint64_t); + return 6; + } else if (p + 6 < end && (p[6] & 0x80) == 0) { + *out_value = LEB128_7(uint64_t); + return 7; + } else if (p + 7 < end && (p[7] & 0x80) == 0) { + *out_value = LEB128_8(uint64_t); + return 8; + } else if (p + 8 < end && (p[8] & 0x80) == 0) { + *out_value = LEB128_9(uint64_t); + return 9; + } else if (p + 9 < end && (p[9] & 0x80) == 0) { + // The top bits set represent values > 32 bits. + if (p[9] & 0xf0) { + return 0; + } + *out_value = LEB128_10(uint64_t); + return 10; + } else { + // past the end. + *out_value = 0; + return 0; + } +} + +size_t ReadS32Leb128(const uint8_t* p, + const uint8_t* end, + uint32_t* out_value) { + if (p < end && (p[0] & 0x80) == 0) { + uint32_t result = LEB128_1(uint32_t); + *out_value = SIGN_EXTEND(int32_t, result, 6); + return 1; + } else if (p + 1 < end && (p[1] & 0x80) == 0) { + uint32_t result = LEB128_2(uint32_t); + *out_value = SIGN_EXTEND(int32_t, result, 13); + return 2; + } else if (p + 2 < end && (p[2] & 0x80) == 0) { + uint32_t result = LEB128_3(uint32_t); + *out_value = SIGN_EXTEND(int32_t, result, 20); + return 3; + } else if (p + 3 < end && (p[3] & 0x80) == 0) { + uint32_t result = LEB128_4(uint32_t); + *out_value = SIGN_EXTEND(int32_t, result, 27); + return 4; + } else if (p + 4 < end && (p[4] & 0x80) == 0) { + // The top bits should be a sign-extension of the sign bit. + bool sign_bit_set = (p[4] & 0x8); + int top_bits = p[4] & 0xf0; + if ((sign_bit_set && top_bits != 0x70) || + (!sign_bit_set && top_bits != 0)) { + return 0; + } + uint32_t result = LEB128_5(uint32_t); + *out_value = result; + return 5; + } else { + // Past the end. + return 0; + } +} + +size_t ReadS64Leb128(const uint8_t* p, + const uint8_t* end, + uint64_t* out_value) { + if (p < end && (p[0] & 0x80) == 0) { + uint64_t result = LEB128_1(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 6); + return 1; + } else if (p + 1 < end && (p[1] & 0x80) == 0) { + uint64_t result = LEB128_2(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 13); + return 2; + } else if (p + 2 < end && (p[2] & 0x80) == 0) { + uint64_t result = LEB128_3(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 20); + return 3; + } else if (p + 3 < end && (p[3] & 0x80) == 0) { + uint64_t result = LEB128_4(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 27); + return 4; + } else if (p + 4 < end && (p[4] & 0x80) == 0) { + uint64_t result = LEB128_5(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 34); + return 5; + } else if (p + 5 < end && (p[5] & 0x80) == 0) { + uint64_t result = LEB128_6(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 41); + return 6; + } else if (p + 6 < end && (p[6] & 0x80) == 0) { + uint64_t result = LEB128_7(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 48); + return 7; + } else if (p + 7 < end && (p[7] & 0x80) == 0) { + uint64_t result = LEB128_8(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 55); + return 8; + } else if (p + 8 < end && (p[8] & 0x80) == 0) { + uint64_t result = LEB128_9(uint64_t); + *out_value = SIGN_EXTEND(int64_t, result, 62); + return 9; + } else if (p + 9 < end && (p[9] & 0x80) == 0) { + // The top bits should be a sign-extension of the sign bit. + bool sign_bit_set = (p[9] & 0x1); + int top_bits = p[9] & 0xfe; + if ((sign_bit_set && top_bits != 0x7e) || + (!sign_bit_set && top_bits != 0)) { + return 0; + } + uint64_t result = LEB128_10(uint64_t); + *out_value = result; + return 10; + } else { + // Past the end. + return 0; + } +} + +#undef BYTE_AT +#undef LEB128_1 +#undef LEB128_2 +#undef LEB128_3 +#undef LEB128_4 +#undef LEB128_5 +#undef LEB128_6 +#undef LEB128_7 +#undef LEB128_8 +#undef LEB128_9 +#undef LEB128_10 +#undef SHIFT_AMOUNT +#undef SIGN_EXTEND + +} // namespace wabt -- cgit v1.2.3