Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: src/wasm/module-decoder.cc

Issue 1504713014: Initial import of v8-native WASM. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/module-decoder.h ('k') | src/wasm/wasm-js.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "src/macro-assembler.h"
6 #include "src/objects.h"
7 #include "src/v8.h"
8
9 #include "src/wasm/decoder.h"
10 #include "src/wasm/module-decoder.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace wasm {
15
16 #if DEBUG
17 #define TRACE(...) \
18 do { \
19 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
20 } while (false)
21 #else
22 #define TRACE(...)
23 #endif
24
25
26 // The main logic for decoding the bytes of a module.
27 class ModuleDecoder : public Decoder {
28 public:
29 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
30 bool asm_js)
31 : Decoder(module_start, module_end), module_zone(zone), asm_js_(asm_js) {
32 result_.start = start_;
33 if (limit_ < start_) {
34 error(start_, "end is less than start");
35 limit_ = start_;
36 }
37 }
38
39 virtual void onFirstError() {
40 pc_ = limit_; // On error, terminate section decoding loop.
41 }
42
43 // Decodes an entire module.
44 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
45 pc_ = start_;
46 module->module_start = start_;
47 module->module_end = limit_;
48 module->min_mem_size_log2 = 0;
49 module->max_mem_size_log2 = 0;
50 module->mem_export = false;
51 module->mem_external = false;
52 module->globals = new std::vector<WasmGlobal>();
53 module->signatures = new std::vector<FunctionSig*>();
54 module->functions = new std::vector<WasmFunction>();
55 module->data_segments = new std::vector<WasmDataSegment>();
56 module->function_table = new std::vector<uint16_t>();
57
58 bool sections[kMaxModuleSectionCode];
59 memset(sections, 0, sizeof(sections));
60
61 // Decode the module sections.
62 while (pc_ < limit_) {
63 TRACE("DecodeSection\n");
64 WasmSectionDeclCode section =
65 static_cast<WasmSectionDeclCode>(u8("section"));
66 // Each section should appear at most once.
67 if (section < kMaxModuleSectionCode) {
68 CheckForPreviousSection(sections, section, false);
69 sections[section] = true;
70 }
71
72 switch (section) {
73 case kDeclEnd:
74 // Terminate section decoding.
75 limit_ = pc_;
76 break;
77 case kDeclMemory:
78 module->min_mem_size_log2 = u8("min memory");
79 module->max_mem_size_log2 = u8("max memory");
80 module->mem_export = u8("export memory") != 0;
81 break;
82 case kDeclSignatures: {
83 int length;
84 uint32_t signatures_count = u32v(&length, "signatures count");
85 module->signatures->reserve(SafeReserve(signatures_count));
86 // Decode signatures.
87 for (uint32_t i = 0; i < signatures_count; i++) {
88 if (failed()) break;
89 TRACE("DecodeSignature[%d] module+%d\n", i,
90 static_cast<int>(pc_ - start_));
91 FunctionSig* s = sig(); // read function sig.
92 module->signatures->push_back(s);
93 }
94 break;
95 }
96 case kDeclFunctions: {
97 // Functions require a signature table first.
98 CheckForPreviousSection(sections, kDeclSignatures, true);
99 int length;
100 uint32_t functions_count = u32v(&length, "functions count");
101 module->functions->reserve(SafeReserve(functions_count));
102 // Set up module environment for verification.
103 ModuleEnv menv;
104 menv.module = module;
105 menv.globals_area = 0;
106 menv.mem_start = 0;
107 menv.mem_end = 0;
108 menv.function_code = nullptr;
109 menv.asm_js = asm_js_;
110 // Decode functions.
111 for (uint32_t i = 0; i < functions_count; i++) {
112 if (failed()) break;
113 TRACE("DecodeFunction[%d] module+%d\n", i,
114 static_cast<int>(pc_ - start_));
115
116 module->functions->push_back(
117 {nullptr, 0, 0, 0, 0, 0, 0, false, false});
118 WasmFunction* function = &module->functions->back();
119 DecodeFunctionInModule(module, function, false);
120 }
121 if (ok() && verify_functions) {
122 for (uint32_t i = 0; i < functions_count; i++) {
123 if (failed()) break;
124 WasmFunction* function = &module->functions->at(i);
125 if (!function->external) {
126 VerifyFunctionBody(i, &menv, function);
127 if (result_.failed())
128 error(result_.error_pc, result_.error_msg.get());
129 }
130 }
131 }
132 break;
133 }
134 case kDeclGlobals: {
135 int length;
136 uint32_t globals_count = u32v(&length, "globals count");
137 module->globals->reserve(SafeReserve(globals_count));
138 // Decode globals.
139 for (uint32_t i = 0; i < globals_count; i++) {
140 if (failed()) break;
141 TRACE("DecodeGlobal[%d] module+%d\n", i,
142 static_cast<int>(pc_ - start_));
143 module->globals->push_back({0, MachineType::Int32(), 0, false});
144 WasmGlobal* global = &module->globals->back();
145 DecodeGlobalInModule(global);
146 }
147 break;
148 }
149 case kDeclDataSegments: {
150 int length;
151 uint32_t data_segments_count = u32v(&length, "data segments count");
152 module->data_segments->reserve(SafeReserve(data_segments_count));
153 // Decode data segments.
154 for (uint32_t i = 0; i < data_segments_count; i++) {
155 if (failed()) break;
156 TRACE("DecodeDataSegment[%d] module+%d\n", i,
157 static_cast<int>(pc_ - start_));
158 module->data_segments->push_back({0, 0, 0});
159 WasmDataSegment* segment = &module->data_segments->back();
160 DecodeDataSegmentInModule(segment);
161 }
162 break;
163 }
164 case kDeclFunctionTable: {
165 // An indirect function table requires functions first.
166 CheckForPreviousSection(sections, kDeclFunctions, true);
167 int length;
168 uint32_t function_table_count = u32v(&length, "function table count");
169 module->function_table->reserve(SafeReserve(function_table_count));
170 // Decode function table.
171 for (uint32_t i = 0; i < function_table_count; i++) {
172 if (failed()) break;
173 TRACE("DecodeFunctionTable[%d] module+%d\n", i,
174 static_cast<int>(pc_ - start_));
175 uint16_t index = u16();
176 if (index >= module->functions->size()) {
177 error(pc_ - 2, "invalid function index");
178 break;
179 }
180 module->function_table->push_back(index);
181 }
182 break;
183 }
184 default:
185 error(pc_ - 1, nullptr, "unrecognized section 0x%02x", section);
186 break;
187 }
188 }
189
190 return toResult(module);
191 }
192
193 uint32_t SafeReserve(uint32_t count) {
194 // Avoid OOM by only reserving up to a certain size.
195 const uint32_t kMaxReserve = 20000;
196 return count < kMaxReserve ? count : kMaxReserve;
197 }
198
199 void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section,
200 bool present) {
201 if (section >= kMaxModuleSectionCode) return;
202 if (sections[section] == present) return;
203 const char* name = "";
204 switch (section) {
205 case kDeclMemory:
206 name = "memory";
207 break;
208 case kDeclSignatures:
209 name = "signatures";
210 break;
211 case kDeclFunctions:
212 name = "function declaration";
213 break;
214 case kDeclGlobals:
215 name = "global variable";
216 break;
217 case kDeclDataSegments:
218 name = "data segment";
219 break;
220 case kDeclFunctionTable:
221 name = "function table";
222 break;
223 default:
224 name = "";
225 break;
226 }
227 if (present) {
228 error(pc_ - 1, nullptr, "required %s section missing", name);
229 } else {
230 error(pc_ - 1, nullptr, "%s section already present", name);
231 }
232 }
233
234 // Decodes a single anonymous function starting at {start_}.
235 FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
236 WasmFunction* function) {
237 pc_ = start_;
238 function->sig = sig(); // read signature
239 function->name_offset = 0; // ---- name
240 function->code_start_offset = off(pc_ + 8); // ---- code start
241 function->code_end_offset = off(limit_); // ---- code end
242 function->local_int32_count = u16(); // read u16
243 function->local_int64_count = u16(); // read u16
244 function->local_float32_count = u16(); // read u16
245 function->local_float64_count = u16(); // read u16
246 function->exported = false; // ---- exported
247 function->external = false; // ---- external
248
249 if (ok()) VerifyFunctionBody(0, module_env, function);
250
251 FunctionResult result;
252 result.CopyFrom(result_); // Copy error code and location.
253 result.val = function;
254 return result;
255 }
256
257 // Decodes a single function signature at {start}.
258 FunctionSig* DecodeFunctionSignature(const byte* start) {
259 pc_ = start;
260 FunctionSig* result = sig();
261 return ok() ? result : nullptr;
262 }
263
264 private:
265 Zone* module_zone;
266 ModuleResult result_;
267 bool asm_js_;
268
269 uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
270
271 // Decodes a single global entry inside a module starting at {pc_}.
272 void DecodeGlobalInModule(WasmGlobal* global) {
273 global->name_offset = string("global name");
274 global->type = mem_type();
275 global->offset = 0;
276 global->exported = u8("exported") != 0;
277 }
278
279 // Decodes a single function entry inside a module starting at {pc_}.
280 void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
281 bool verify_body = true) {
282 byte decl_bits = u8("function decl");
283
284 const byte* sigpos = pc_;
285 function->sig_index = u16("signature index");
286
287 if (function->sig_index >= module->signatures->size()) {
288 return error(sigpos, "invalid signature index");
289 } else {
290 function->sig = module->signatures->at(function->sig_index);
291 }
292
293 TRACE(" +%d <function attributes:%s%s%s%s%s>\n",
294 static_cast<int>(pc_ - start_),
295 decl_bits & kDeclFunctionName ? " name" : "",
296 decl_bits & kDeclFunctionImport ? " imported" : "",
297 decl_bits & kDeclFunctionLocals ? " locals" : "",
298 decl_bits & kDeclFunctionExport ? " exported" : "",
299 (decl_bits & kDeclFunctionImport) == 0 ? " body" : "");
300
301 if (decl_bits & kDeclFunctionName) {
302 function->name_offset = string("function name");
303 }
304
305 function->exported = decl_bits & kDeclFunctionExport;
306
307 // Imported functions have no locals or body.
308 if (decl_bits & kDeclFunctionImport) {
309 function->external = true;
310 return;
311 }
312
313 if (decl_bits & kDeclFunctionLocals) {
314 function->local_int32_count = u16("int32 count");
315 function->local_int64_count = u16("int64 count");
316 function->local_float32_count = u16("float32 count");
317 function->local_float64_count = u16("float64 count");
318 }
319
320 uint16_t size = u16("body size");
321 if (ok()) {
322 if ((pc_ + size) > limit_) {
323 return error(pc_, limit_,
324 "expected %d bytes for function body, fell off end", size);
325 }
326 function->code_start_offset = static_cast<uint32_t>(pc_ - start_);
327 function->code_end_offset = function->code_start_offset + size;
328 TRACE(" +%d %-20s: (%d bytes)\n", static_cast<int>(pc_ - start_),
329 "function body", size);
330 pc_ += size;
331 }
332 }
333
334 // Decodes a single data segment entry inside a module starting at {pc_}.
335 void DecodeDataSegmentInModule(WasmDataSegment* segment) {
336 segment->dest_addr =
337 u32("destination"); // TODO(titzer): check it's within the memory size.
338 segment->source_offset = offset("source offset");
339 segment->source_size =
340 u32("source size"); // TODO(titzer): check the size is reasonable.
341 segment->init = u8("init");
342 }
343
344 // Verifies the body (code) of a given function.
345 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
346 WasmFunction* function) {
347 if (FLAG_trace_wasm_decode_time) {
348 // TODO(titzer): clean me up a bit.
349 OFStream os(stdout);
350 os << "Verifying WASM function:";
351 if (function->name_offset > 0) {
352 os << menv->module->GetName(function->name_offset);
353 }
354 os << std::endl;
355 }
356 FunctionEnv fenv;
357 fenv.module = menv;
358 fenv.sig = function->sig;
359 fenv.local_int32_count = function->local_int32_count;
360 fenv.local_int64_count = function->local_int64_count;
361 fenv.local_float32_count = function->local_float32_count;
362 fenv.local_float64_count = function->local_float64_count;
363 fenv.SumLocals();
364
365 TreeResult result =
366 VerifyWasmCode(&fenv, start_, start_ + function->code_start_offset,
367 start_ + function->code_end_offset);
368 if (result.failed()) {
369 // Wrap the error message from the function decoder.
370 std::ostringstream str;
371 str << "in function #" << func_num << ": ";
372 // TODO(titzer): add function name for the user?
373 str << result;
374 const char* raw = str.str().c_str();
375 size_t len = strlen(raw);
376 char* buffer = new char[len];
377 strncpy(buffer, raw, len);
378 buffer[len - 1] = 0;
379
380 // Copy error code and location.
381 result_.CopyFrom(result);
382 result_.error_msg.Reset(buffer);
383 }
384 }
385
386 // Reads a single 32-bit unsigned integer interpreted as an offset, checking
387 // the offset is within bounds and advances.
388 uint32_t offset(const char* name = nullptr) {
389 uint32_t offset = u32(name ? name : "offset");
390 if (offset > (limit_ - start_)) {
391 error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
392 }
393 return offset;
394 }
395
396 // Reads a single 32-bit unsigned integer interpreted as an offset into the
397 // data and validating the string there and advances.
398 uint32_t string(const char* name = nullptr) {
399 return offset(name ? name : "string"); // TODO(titzer): validate string
400 }
401
402 // Reads a single 8-bit integer, interpreting it as a local type.
403 LocalType local_type() {
404 byte val = u8("local type");
405 LocalTypeCode t = static_cast<LocalTypeCode>(val);
406 switch (t) {
407 case kLocalVoid:
408 return kAstStmt;
409 case kLocalI32:
410 return kAstI32;
411 case kLocalI64:
412 return kAstI64;
413 case kLocalF32:
414 return kAstF32;
415 case kLocalF64:
416 return kAstF64;
417 default:
418 error(pc_ - 1, "invalid local type");
419 return kAstStmt;
420 }
421 }
422
423 // Reads a single 8-bit integer, interpreting it as a memory type.
424 MachineType mem_type() {
425 byte val = u8("memory type");
426 MemTypeCode t = static_cast<MemTypeCode>(val);
427 switch (t) {
428 case kMemI8:
429 return MachineType::Int8();
430 case kMemU8:
431 return MachineType::Uint8();
432 case kMemI16:
433 return MachineType::Int16();
434 case kMemU16:
435 return MachineType::Uint16();
436 case kMemI32:
437 return MachineType::Int32();
438 case kMemU32:
439 return MachineType::Uint32();
440 case kMemI64:
441 return MachineType::Int64();
442 case kMemU64:
443 return MachineType::Uint64();
444 case kMemF32:
445 return MachineType::Float32();
446 case kMemF64:
447 return MachineType::Float64();
448 default:
449 error(pc_ - 1, "invalid memory type");
450 return MachineType::None();
451 }
452 }
453
454 // Parses an inline function signature.
455 FunctionSig* sig() {
456 byte count = u8("param count");
457 LocalType ret = local_type();
458 FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
459 if (ret != kAstStmt) builder.AddReturn(ret);
460
461 for (int i = 0; i < count; i++) {
462 LocalType param = local_type();
463 if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
464 builder.AddParam(param);
465 }
466 return builder.Build();
467 }
468 };
469
470
471 // Helpers for nice error messages.
472 class ModuleError : public ModuleResult {
473 public:
474 explicit ModuleError(const char* msg) {
475 error_code = kError;
476 size_t len = strlen(msg) + 1;
477 char* result = new char[len];
478 strncpy(result, msg, len);
479 result[len - 1] = 0;
480 error_msg.Reset(result);
481 }
482 };
483
484
485 // Helpers for nice error messages.
486 class FunctionError : public FunctionResult {
487 public:
488 explicit FunctionError(const char* msg) {
489 error_code = kError;
490 size_t len = strlen(msg) + 1;
491 char* result = new char[len];
492 strncpy(result, msg, len);
493 result[len - 1] = 0;
494 error_msg.Reset(result);
495 }
496 };
497
498
499 ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
500 const byte* module_start, const byte* module_end,
501 bool verify_functions, bool asm_js) {
502 size_t size = module_end - module_start;
503 if (module_start > module_end) return ModuleError("start > end");
504 if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
505 WasmModule* module = new WasmModule();
506 ModuleDecoder decoder(zone, module_start, module_end, asm_js);
507 return decoder.DecodeModule(module, verify_functions);
508 }
509
510
511 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
512 const byte* end) {
513 ModuleDecoder decoder(zone, start, end, false);
514 return decoder.DecodeFunctionSignature(start);
515 }
516
517
518 FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
519 ModuleEnv* module_env,
520 const byte* function_start,
521 const byte* function_end) {
522 size_t size = function_end - function_start;
523 if (function_start > function_end) return FunctionError("start > end");
524 if (size > kMaxFunctionSize)
525 return FunctionError("size > maximum function size");
526 WasmFunction* function = new WasmFunction();
527 ModuleDecoder decoder(zone, function_start, function_end, false);
528 return decoder.DecodeSingleFunction(module_env, function);
529 }
530 } // namespace wasm
531 } // namespace internal
532 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/module-decoder.h ('k') | src/wasm/wasm-js.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698