Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
leb128.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <sysio/vm/exceptions.hpp>
4#include <sysio/vm/guarded_ptr.hpp>
5
6#include <array>
7#include <cstddef>
8#include <cstdint>
9#include <iostream>
10#include <type_traits>
11
12namespace sysio { namespace vm {
13 template <size_t N>
14 inline size_t constexpr bytes_needed() {
15 if constexpr (N == 1 || N == 7)
16 return 1;
17 else if constexpr (N == 32)
18 return 5;
19 else
20 return 10;
21 }
22
23 template <size_t N>
24 class varuint {
25 public:
26 static_assert(N == 1 || N == 7 || N == 32, "N not valid");
27
28 inline constexpr explicit varuint(bool v) { from(v); }
29 inline constexpr explicit varuint(uint8_t v) { from(v); }
30 inline constexpr explicit varuint(uint32_t v) { from(v); }
31 inline constexpr varuint( guarded_ptr<uint8_t>& code ) { from(code); }
32
33 inline constexpr void from(bool v) { storage[0] = v; }
34 inline constexpr void from(uint8_t v) {
35 storage[0] = v & 0x7f;
36 }
37 inline constexpr void from(uint32_t v) {
38 bytes_used = 0;
39
40#ifdef __clang__
41#pragma unroll
42#elif defined(__GNUC__)
43#pragma GCC unroll 5
44#endif
45 for (; bytes_used < bytes_needed<N>(); bytes_used++) {
46 storage[bytes_used] = v & 0x7f;
47 v >>= 7;
48 if (v!= 0)
49 storage[bytes_used] |= 0x80;
50 else
51 break;
52 }
53 bytes_used++;
54 }
55
56 inline constexpr void from( guarded_ptr<uint8_t>& code ) {
57 uint8_t cnt = 0;
58 for (;; cnt++) {
59 SYS_VM_ASSERT( cnt < bytes_needed<N>(), wasm_interpreter_exception, "incorrect leb128 encoding" );
60 SYS_VM_ASSERT( code.offset()+cnt < code.bounds(), wasm_interpreter_exception, "pointer out of bounds" );
61 storage[cnt] = code[cnt];
62 if ((storage[cnt] & 0x80) == 0) {
63 if( static_cast<size_t>(cnt + 1) == bytes_needed<N>() ) {
64 uint8_t mask = static_cast<uint8_t>(~(uint32_t)0 << uint32_t(N - 7*(bytes_needed<N>()-1))) & 0x7F;
65 SYS_VM_ASSERT((mask & storage[cnt]) == 0, wasm_parse_exception, "unused bits of unsigned leb128 must be 0");
66 }
67 break;
68 }
69 }
70 code += cnt+1;
71 bytes_used = cnt+1;
72 }
73
74 size_t size()const { return bytes_used; }
75
76 template <size_t M=N, typename = typename std::enable_if_t<M == 1, int>>
77 inline constexpr bool to() { return storage[0]; }
78
79 template <size_t M=N, typename = typename std::enable_if_t<M == 7, int>>
80 inline constexpr uint8_t to() { return storage[0] & 0x7f; }
81
82 template <size_t M=N, typename = typename std::enable_if_t<M == 32, int>>
83 inline constexpr uint32_t to() {
84 uint32_t ret = 0;
85
86#ifdef __clang__
87#pragma unroll
88#elif defined(__GNUC__)
89#pragma GCC unroll 5
90#endif
91 for (int i=bytes_used-1; i >= 0; i--) {
92 ret <<= 7;
93 ret |= storage[i] & 0x7f;
94 }
95 return ret;
96 }
97
98 void print()const {
99 for (int i=0; i < bytes_used; i++) {
100 std::cout << std::hex << "0x" << (int)storage[i] << ' ';
101 }
102 std::cout << std::endl;
103 }
104
105 private:
106 std::array<uint8_t, bytes_needed<N>()> storage;
107 uint8_t bytes_used = bytes_needed<N>();
108 };
109
110 template <size_t N>
111 class varint {
112 public:
113 static_assert(N == 7 || N == 32 || N == 64, "N not valid");
114
115 inline constexpr explicit varint(int8_t v) { from(v); }
116 inline constexpr explicit varint(int32_t v) { from(v); }
117 inline constexpr explicit varint(int64_t v) { from(v); }
118 inline constexpr varint( guarded_ptr<uint8_t>& code ) { from(code); }
119
120 inline constexpr void from(int8_t v) {
121 static_assert(N >= 7, "cant use this constructor with N < 7");
122 storage[0] = v & 0x7f;
123 }
124 inline constexpr void from(int32_t v) {
125 static_assert(N >= 32, "cant use this constructor with N < 32");
126 _from(v);
127 }
128 inline constexpr void from(int64_t v) {
129 static_assert(N >= 64, "cant use this constructor with N < 32");
130 _from(v);
131 }
132
133 inline constexpr void from( guarded_ptr<uint8_t>& code ) {
134 uint8_t cnt = 0;
135 for (;; cnt++) {
136 SYS_VM_ASSERT( cnt < bytes_needed<N>(), wasm_interpreter_exception, "incorrect leb128 encoding" );
137 SYS_VM_ASSERT( code.offset()+cnt < code.bounds(), wasm_interpreter_exception, "pointer out of bounds" );
138 storage[cnt] = code[cnt];
139 if ((storage[cnt] & 0x80) == 0) {
140 if( static_cast<size_t>(cnt + 1) == bytes_needed<N>() ) {
141 uint32_t offset = N - 7*(bytes_needed<N>()-1);
142 uint8_t mask = static_cast<uint8_t>(~(uint32_t)0 << offset) & 0x7F;
143 uint8_t expected = (storage[cnt] & (uint32_t(1) << uint32_t(offset - 1)))? mask : 0;
144 SYS_VM_ASSERT((mask & storage[cnt]) == expected, wasm_parse_exception, "unused bits of signed leb128 must be the same as the sign bit");
145 }
146 break;
147 }
148 }
149 code += cnt+1;
150 bytes_used = cnt+1;
151 }
152
153 size_t size()const { return bytes_used; }
154
155 template <size_t M=N, typename = typename std::enable_if_t<M == 1, int>>
156 inline constexpr bool to() { return storage[0]; }
157
158 template <size_t M=N, typename = typename std::enable_if_t<M == 7, int>>
159 inline constexpr int8_t to() {
160 if (storage[0] & 0x40)
161 return storage[0] | (~0u << 7);
162 return storage[0];
163 }
164
165 template <size_t M=N, typename = typename std::enable_if_t<M == 32, int>>
166 inline constexpr int32_t to() { return _to<int32_t>(); }
167
168 template <size_t M=N, typename = typename std::enable_if_t<M == 64, int>>
169 inline constexpr int64_t to() { return _to<int64_t>(); }
170
171 void print()const {
172 for (int i=0; i < bytes_used; i++) {
173 std::cout << std::hex << "0x" << (int)storage[i] << ' ';
174 }
175 std::cout << std::endl;
176 }
177
178 private:
179 template <typename T>
180 inline constexpr void _from(T v) {
181 bytes_used = 0;
182
183#ifdef __clang__
184#pragma unroll
185#elif defined(__GNUC__)
186#pragma GCC unroll 5
187#endif
188 for (; bytes_used < bytes_needed<N>(); bytes_used++) {
189 storage[bytes_used] = v & 0x7f;
190 v >>= 7;
191 if ((v == -1 && (storage[bytes_used] & 0x40)) || (v == 0 && !(storage[bytes_used] & 0x40)))
192 break;
193 storage[bytes_used] |= 0x80;
194 }
195 bytes_used++;
196 }
197
198 template <typename T>
199 inline constexpr T _to() {
200 typename std::make_unsigned<T>::type ret = 0;
201
202#ifdef __clang__
203#pragma unroll
204#elif defined(__GNUC__)
205#pragma GCC unroll 5
206#endif
207 for (int i=bytes_used-1; i >= 0; i--) {
208 ret <<= 7;
209 ret |= storage[i] & 0x7f;
210 }
211 if (bytes_used >= 1 && bytes_used < bytes_needed<N>()) {
212 size_t shift = ((bytes_used) * 7);
213 if (storage[bytes_used-1] & 0x40)
214 ret |= (-1ull) << shift;
215 }
216 return *(T*)&ret;
217 }
218
219 std::array<uint8_t, bytes_needed<N>()> storage;
220 uint8_t bytes_used = bytes_needed<N>();
221 };
222
223}} // ns sysio::vm
constexpr int32_t to()
Definition leb128.hpp:166
constexpr varint(guarded_ptr< uint8_t > &code)
Definition leb128.hpp:118
constexpr void from(int8_t v)
Definition leb128.hpp:120
size_t size() const
Definition leb128.hpp:153
constexpr void from(int64_t v)
Definition leb128.hpp:128
constexpr varint(int64_t v)
Definition leb128.hpp:117
constexpr bool to()
Definition leb128.hpp:156
void print() const
Definition leb128.hpp:171
constexpr varint(int8_t v)
Definition leb128.hpp:115
constexpr void from(int32_t v)
Definition leb128.hpp:124
constexpr varint(int32_t v)
Definition leb128.hpp:116
constexpr int8_t to()
Definition leb128.hpp:159
constexpr void from(guarded_ptr< uint8_t > &code)
Definition leb128.hpp:133
constexpr int64_t to()
Definition leb128.hpp:169
constexpr varuint(bool v)
Definition leb128.hpp:28
constexpr bool to()
Definition leb128.hpp:77
constexpr void from(bool v)
Definition leb128.hpp:33
void print() const
Definition leb128.hpp:98
constexpr void from(uint32_t v)
Definition leb128.hpp:37
constexpr uint8_t to()
Definition leb128.hpp:80
constexpr varuint(uint32_t v)
Definition leb128.hpp:30
constexpr varuint(guarded_ptr< uint8_t > &code)
Definition leb128.hpp:31
constexpr varuint(uint8_t v)
Definition leb128.hpp:29
constexpr uint32_t to()
Definition leb128.hpp:83
size_t size() const
Definition leb128.hpp:74
constexpr void from(guarded_ptr< uint8_t > &code)
Definition leb128.hpp:56
constexpr void from(uint8_t v)
Definition leb128.hpp:34
size_t constexpr bytes_needed()
Definition leb128.hpp:14
#define T(meth, val, expected)
const int N
Definition quantize.cpp:54
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
signed char int8_t
Definition stdint.h:121
#define SYS_VM_ASSERT(expr, exc_type, msg)
Definition exceptions.hpp:8
CK_RV ret