OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_WASM_DECODER_H_ | 5 #ifndef V8_WASM_DECODER_H_ |
6 #define V8_WASM_DECODER_H_ | 6 #define V8_WASM_DECODER_H_ |
7 | 7 |
8 #include "src/base/smart-pointers.h" | 8 #include "src/base/smart-pointers.h" |
9 #include "src/flags.h" | 9 #include "src/flags.h" |
10 #include "src/signature.h" | 10 #include "src/signature.h" |
11 #include "src/wasm/wasm-result.h" | 11 #include "src/wasm/wasm-result.h" |
12 #include "src/zone-containers.h" | 12 #include "src/zone-containers.h" |
13 | 13 |
14 namespace v8 { | 14 namespace v8 { |
15 namespace internal { | 15 namespace internal { |
16 namespace wasm { | 16 namespace wasm { |
17 | 17 |
18 #if DEBUG | 18 #if DEBUG |
19 #define TRACE(...) \ | 19 #define TRACE(...) \ |
20 do { \ | 20 do { \ |
21 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ | 21 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ |
22 } while (false) | 22 } while (false) |
23 #else | 23 #else |
24 #define TRACE(...) | 24 #define TRACE(...) |
25 #endif | 25 #endif |
26 | 26 |
| 27 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM) |
| 28 #define UNALIGNED_ACCESS_OK 1 |
| 29 #else |
| 30 #define UNALIGNED_ACCESS_OK 0 |
| 31 #endif |
| 32 |
27 // A helper utility to decode bytes, integers, fields, varints, etc, from | 33 // A helper utility to decode bytes, integers, fields, varints, etc, from |
28 // a buffer of bytes. | 34 // a buffer of bytes. |
29 class Decoder { | 35 class Decoder { |
30 public: | 36 public: |
31 Decoder(const byte* start, const byte* end) | 37 Decoder(const byte* start, const byte* end) |
32 : start_(start), | 38 : start_(start), |
33 pc_(start), | 39 pc_(start), |
34 limit_(end), | 40 limit_(end), |
| 41 end_(end), |
35 error_pc_(nullptr), | 42 error_pc_(nullptr), |
36 error_pt_(nullptr) {} | 43 error_pt_(nullptr) {} |
37 | 44 |
38 virtual ~Decoder() {} | 45 virtual ~Decoder() {} |
39 | 46 |
| 47 // Reads a single 16-bit unsigned integer (little endian). |
| 48 inline uint16_t read_u16(const byte* ptr) { |
| 49 DCHECK(ptr >= start_ && (ptr + 2) <= end_); |
| 50 #if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK |
| 51 return *reinterpret_cast<const uint16_t*>(ptr); |
| 52 #else |
| 53 uint16_t b0 = ptr[0]; |
| 54 uint16_t b1 = ptr[1]; |
| 55 return (b1 << 8) | b0; |
| 56 #endif |
| 57 } |
| 58 |
| 59 // Reads a single 32-bit unsigned integer (little endian). |
| 60 inline uint32_t read_u32(const byte* ptr) { |
| 61 DCHECK(ptr >= start_ && (ptr + 4) <= end_); |
| 62 #if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK |
| 63 return *reinterpret_cast<const uint32_t*>(ptr); |
| 64 #else |
| 65 uint32_t b0 = ptr[0]; |
| 66 uint32_t b1 = ptr[1]; |
| 67 uint32_t b2 = ptr[2]; |
| 68 uint32_t b3 = ptr[3]; |
| 69 return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; |
| 70 #endif |
| 71 } |
| 72 |
| 73 // Reads a single 64-bit unsigned integer (little endian). |
| 74 inline uint64_t read_u64(const byte* ptr) { |
| 75 DCHECK(ptr >= start_ && (ptr + 8) <= end_); |
| 76 #if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK |
| 77 return *reinterpret_cast<const uint64_t*>(ptr); |
| 78 #else |
| 79 uint32_t b0 = ptr[0]; |
| 80 uint32_t b1 = ptr[1]; |
| 81 uint32_t b2 = ptr[2]; |
| 82 uint32_t b3 = ptr[3]; |
| 83 uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; |
| 84 uint32_t b4 = ptr[4]; |
| 85 uint32_t b5 = ptr[5]; |
| 86 uint32_t b6 = ptr[6]; |
| 87 uint32_t b7 = ptr[7]; |
| 88 uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; |
| 89 return (high << 32) | low; |
| 90 #endif |
| 91 } |
| 92 |
40 // Reads a 8-bit unsigned integer (byte) and advances {pc_}. | 93 // Reads a 8-bit unsigned integer (byte) and advances {pc_}. |
41 uint8_t u8(const char* name = nullptr) { | 94 uint8_t consume_u8(const char* name = nullptr) { |
42 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), | 95 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
43 name ? name : "uint8_t"); | 96 name ? name : "uint8_t"); |
44 if (checkAvailable(1)) { | 97 if (checkAvailable(1)) { |
45 byte val = *(pc_++); | 98 byte val = *(pc_++); |
46 TRACE("%02x = %d\n", val, val); | 99 TRACE("%02x = %d\n", val, val); |
47 return val; | 100 return val; |
48 } else { | |
49 error("expected 1 byte, but fell off end"); | |
50 return traceOffEnd<uint8_t>(); | |
51 } | 101 } |
| 102 return traceOffEnd<uint8_t>(); |
52 } | 103 } |
53 | 104 |
54 // Reads a 16-bit unsigned integer (little endian) and advances {pc_}. | 105 // Reads a 16-bit unsigned integer (little endian) and advances {pc_}. |
55 uint16_t u16(const char* name = nullptr) { | 106 uint16_t consume_u16(const char* name = nullptr) { |
56 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), | 107 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
57 name ? name : "uint16_t"); | 108 name ? name : "uint16_t"); |
58 if (checkAvailable(2)) { | 109 if (checkAvailable(2)) { |
59 #ifdef V8_TARGET_LITTLE_ENDIAN | 110 uint16_t val = read_u16(pc_); |
60 byte b0 = pc_[0]; | |
61 byte b1 = pc_[1]; | |
62 #else | |
63 byte b1 = pc_[0]; | |
64 byte b0 = pc_[1]; | |
65 #endif | |
66 uint16_t val = static_cast<uint16_t>(b1 << 8) | b0; | |
67 TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val); | 111 TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val); |
68 pc_ += 2; | 112 pc_ += 2; |
69 return val; | 113 return val; |
70 } else { | |
71 error("expected 2 bytes, but fell off end"); | |
72 return traceOffEnd<uint16_t>(); | |
73 } | 114 } |
| 115 return traceOffEnd<uint16_t>(); |
74 } | 116 } |
75 | 117 |
76 // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. | 118 // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. |
77 uint32_t u32(const char* name = nullptr) { | 119 uint32_t consume_u32(const char* name = nullptr) { |
78 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), | 120 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
79 name ? name : "uint32_t"); | 121 name ? name : "uint32_t"); |
80 if (checkAvailable(4)) { | 122 if (checkAvailable(4)) { |
81 #ifdef V8_TARGET_LITTLE_ENDIAN | 123 uint32_t val = read_u32(pc_); |
82 byte b0 = pc_[0]; | |
83 byte b1 = pc_[1]; | |
84 byte b2 = pc_[2]; | |
85 byte b3 = pc_[3]; | |
86 #else | |
87 byte b3 = pc_[0]; | |
88 byte b2 = pc_[1]; | |
89 byte b1 = pc_[2]; | |
90 byte b0 = pc_[3]; | |
91 #endif | |
92 uint32_t val = static_cast<uint32_t>(b3 << 24) | | |
93 static_cast<uint32_t>(b2 << 16) | | |
94 static_cast<uint32_t>(b1 << 8) | b0; | |
95 TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val); | 124 TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val); |
96 pc_ += 4; | 125 pc_ += 4; |
97 return val; | 126 return val; |
98 } else { | |
99 error("expected 4 bytes, but fell off end"); | |
100 return traceOffEnd<uint32_t>(); | |
101 } | 127 } |
| 128 return traceOffEnd<uint32_t>(); |
102 } | 129 } |
103 | 130 |
104 // Reads a LEB128 variable-length 32-bit integer and advances {pc_}. | 131 // Reads a LEB128 variable-length 32-bit integer and advances {pc_}. |
105 uint32_t u32v(int* length, const char* name = nullptr) { | 132 uint32_t consume_u32v(int* length, const char* name = nullptr) { |
106 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), | 133 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
107 name ? name : "varint"); | 134 name ? name : "varint"); |
108 | 135 |
109 if (!checkAvailable(1)) { | 136 if (checkAvailable(1)) { |
110 error("expected at least 1 byte, but fell off end"); | 137 const byte* pos = pc_; |
111 return traceOffEnd<uint32_t>(); | 138 const byte* end = pc_ + 5; |
| 139 if (end > limit_) end = limit_; |
| 140 |
| 141 uint32_t result = 0; |
| 142 int shift = 0; |
| 143 byte b = 0; |
| 144 while (pc_ < end) { |
| 145 b = *pc_++; |
| 146 TRACE("%02x ", b); |
| 147 result = result | ((b & 0x7F) << shift); |
| 148 if ((b & 0x80) == 0) break; |
| 149 shift += 7; |
| 150 } |
| 151 |
| 152 *length = static_cast<int>(pc_ - pos); |
| 153 if (pc_ == end && (b & 0x80)) { |
| 154 error(pc_ - 1, "varint too large"); |
| 155 } else { |
| 156 TRACE("= %u\n", result); |
| 157 } |
| 158 return result; |
112 } | 159 } |
113 | 160 return traceOffEnd<uint32_t>(); |
114 const byte* pos = pc_; | |
115 const byte* end = pc_ + 5; | |
116 if (end > limit_) end = limit_; | |
117 | |
118 uint32_t result = 0; | |
119 int shift = 0; | |
120 byte b = 0; | |
121 while (pc_ < end) { | |
122 b = *pc_++; | |
123 TRACE("%02x ", b); | |
124 result = result | ((b & 0x7F) << shift); | |
125 if ((b & 0x80) == 0) break; | |
126 shift += 7; | |
127 } | |
128 | |
129 *length = static_cast<int>(pc_ - pos); | |
130 if (pc_ == end && (b & 0x80)) { | |
131 error(pc_ - 1, "varint too large"); | |
132 } else { | |
133 TRACE("= %u\n", result); | |
134 } | |
135 return result; | |
136 } | 161 } |
137 | 162 |
138 // Check that at least {size} bytes exist between {pc_} and {limit_}. | 163 // Check that at least {size} bytes exist between {pc_} and {limit_}. |
139 bool checkAvailable(int size) { | 164 bool checkAvailable(int size) { |
140 if (pc_ < start_ || (pc_ + size) > limit_) { | 165 if (pc_ < start_ || (pc_ + size) > limit_) { |
141 error(pc_, nullptr, "expected %d bytes, fell off end", size); | 166 error(pc_, nullptr, "expected %d bytes, fell off end", size); |
142 return false; | 167 return false; |
143 } else { | 168 } else { |
144 return true; | 169 return true; |
145 } | 170 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 } | 226 } |
202 result.val = val; | 227 result.val = val; |
203 return result; | 228 return result; |
204 } | 229 } |
205 | 230 |
206 // Resets the boundaries of this decoder. | 231 // Resets the boundaries of this decoder. |
207 void Reset(const byte* start, const byte* end) { | 232 void Reset(const byte* start, const byte* end) { |
208 start_ = start; | 233 start_ = start; |
209 pc_ = start; | 234 pc_ = start; |
210 limit_ = end; | 235 limit_ = end; |
| 236 end_ = end; |
211 error_pc_ = nullptr; | 237 error_pc_ = nullptr; |
212 error_pt_ = nullptr; | 238 error_pt_ = nullptr; |
213 error_msg_.Reset(nullptr); | 239 error_msg_.Reset(nullptr); |
214 } | 240 } |
215 | 241 |
216 bool ok() const { return error_pc_ == nullptr; } | 242 bool ok() const { return error_pc_ == nullptr; } |
217 bool failed() const { return error_pc_ != nullptr; } | 243 bool failed() const { return error_pc_ != nullptr; } |
218 | 244 |
219 protected: | 245 protected: |
220 const byte* start_; | 246 const byte* start_; |
221 const byte* pc_; | 247 const byte* pc_; |
222 const byte* limit_; | 248 const byte* limit_; |
| 249 const byte* end_; |
223 const byte* error_pc_; | 250 const byte* error_pc_; |
224 const byte* error_pt_; | 251 const byte* error_pt_; |
225 base::SmartArrayPointer<char> error_msg_; | 252 base::SmartArrayPointer<char> error_msg_; |
226 }; | 253 }; |
227 | 254 |
228 #undef TRACE | 255 #undef TRACE |
229 } // namespace wasm | 256 } // namespace wasm |
230 } // namespace internal | 257 } // namespace internal |
231 } // namespace v8 | 258 } // namespace v8 |
232 | 259 |
233 #endif // V8_WASM_DECODER_H_ | 260 #endif // V8_WASM_DECODER_H_ |
OLD | NEW |