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

Side by Side Diff: src/wasm/encoder.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/encoder.h ('k') | src/wasm/module-decoder.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/signature.h"
6
7 #include "src/handles.h"
8 #include "src/v8.h"
9 #include "src/zone-containers.h"
10
11 #include "src/wasm/ast-decoder.h"
12 #include "src/wasm/encoder.h"
13 #include "src/wasm/wasm-module.h"
14 #include "src/wasm/wasm-opcodes.h"
15
16 #include "src/v8memory.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace wasm {
21
22 /*TODO: add error cases for adding too many locals, too many functions and bad
23 indices in body */
24
25 namespace {
26 void EmitUint8(byte** b, uint8_t x) {
27 Memory::uint8_at(*b) = x;
28 *b += 1;
29 }
30
31
32 void EmitUint16(byte** b, uint16_t x) {
33 Memory::uint16_at(*b) = x;
34 *b += 2;
35 }
36
37
38 void EmitUint32(byte** b, uint32_t x) {
39 Memory::uint32_at(*b) = x;
40 *b += 4;
41 }
42
43
44 void EmitVarInt(byte** b, size_t val) {
45 while (true) {
46 size_t next = val >> 7;
47 byte out = static_cast<byte>(val & 0x7f);
48 if (next) {
49 *((*b)++) = 0x80 | out;
50 val = next;
51 } else {
52 *((*b)++) = out;
53 break;
54 }
55 }
56 }
57 } // namespace
58
59
60 struct WasmFunctionBuilder::Type {
61 bool param_;
62 LocalType type_;
63 };
64
65
66 WasmFunctionBuilder::WasmFunctionBuilder(Zone* zone, const unsigned char* name,
67 int name_length)
68 : return_type_(kAstI32),
69 locals_(zone),
70 exported_(0),
71 external_(0),
72 body_(zone),
73 local_indices_(zone),
74 name_(zone) {
75 if (name_length > 0) {
76 for (int i = 0; i < name_length; i++) {
77 name_.push_back(*(name + i));
78 }
79 name_.push_back('\0');
80 }
81 }
82
83
84 uint16_t WasmFunctionBuilder::AddParam(LocalType type) {
85 return AddVar(type, true);
86 }
87
88
89 uint16_t WasmFunctionBuilder::AddLocal(LocalType type) {
90 return AddVar(type, false);
91 }
92
93
94 uint16_t WasmFunctionBuilder::AddVar(LocalType type, bool param) {
95 locals_.push_back({param, type});
96 return static_cast<uint16_t>(locals_.size() - 1);
97 }
98
99
100 void WasmFunctionBuilder::ReturnType(LocalType type) { return_type_ = type; }
101
102
103 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
104 EmitCode(code, code_size, NULL, 0);
105 }
106
107
108 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size,
109 const uint32_t* local_indices,
110 uint32_t indices_size) {
111 size_t size = body_.size();
112 for (size_t i = 0; i < code_size; i++) {
113 body_.push_back(code[i]);
114 }
115 for (size_t i = 0; i < indices_size; i++) {
116 local_indices_.push_back(local_indices[i] + static_cast<uint32_t>(size));
117 }
118 }
119
120
121 void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
122 body_.push_back(static_cast<byte>(opcode));
123 }
124
125
126 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
127 body_.push_back(static_cast<byte>(opcode));
128 body_.push_back(immediate);
129 }
130
131
132 void WasmFunctionBuilder::EmitWithLocal(WasmOpcode opcode) {
133 body_.push_back(static_cast<byte>(opcode));
134 local_indices_.push_back(static_cast<uint32_t>(body_.size()) - 1);
135 }
136
137
138 uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) {
139 body_.push_back(immediate);
140 return static_cast<uint32_t>(body_.size()) - 1;
141 }
142
143
144 void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) {
145 DCHECK(offset < body_.size());
146 body_[offset] = immediate;
147 }
148
149
150 void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; }
151
152
153 void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; }
154
155
156 WasmFunctionEncoder* WasmFunctionBuilder::Build(Zone* zone,
157 WasmModuleBuilder* mb) const {
158 WasmFunctionEncoder* e =
159 new (zone) WasmFunctionEncoder(zone, return_type_, exported_, external_);
160 auto var_index = new uint16_t[locals_.size()];
161 IndexVars(e, var_index);
162 const byte* start = body_.data();
163 const byte* end = start + body_.size();
164 size_t local_index = 0;
165 for (size_t i = 0; i < body_.size();) {
166 if (local_index < local_indices_.size() &&
167 i == local_indices_[local_index]) {
168 int length = 0;
169 uint32_t index;
170 ReadUnsignedLEB128Operand(start + i, end, &length, &index);
171 uint16_t new_index = var_index[index];
172 const std::vector<uint8_t>& index_vec = UnsignedLEB128From(new_index);
173 for (size_t j = 0; j < index_vec.size(); j++) {
174 e->body_.push_back(index_vec.at(j));
175 }
176 i += length;
177 local_index++;
178 } else {
179 e->body_.push_back(*(start + i));
180 i++;
181 }
182 }
183 FunctionSig::Builder sig(zone, return_type_ == kAstStmt ? 0 : 1,
184 e->params_.size());
185 if (return_type_ != kAstStmt) {
186 sig.AddReturn(static_cast<LocalType>(return_type_));
187 }
188 for (size_t i = 0; i < e->params_.size(); i++) {
189 sig.AddParam(static_cast<LocalType>(e->params_[i]));
190 }
191 e->signature_index_ = mb->AddSignature(sig.Build());
192 delete[] var_index;
193 e->name_.insert(e->name_.begin(), name_.begin(), name_.end());
194 return e;
195 }
196
197
198 void WasmFunctionBuilder::IndexVars(WasmFunctionEncoder* e,
199 uint16_t* var_index) const {
200 uint16_t param = 0;
201 uint16_t int32 = 0;
202 uint16_t int64 = 0;
203 uint16_t float32 = 0;
204 uint16_t float64 = 0;
205 for (size_t i = 0; i < locals_.size(); i++) {
206 if (locals_.at(i).param_) {
207 param++;
208 } else if (locals_.at(i).type_ == kAstI32) {
209 int32++;
210 } else if (locals_.at(i).type_ == kAstI64) {
211 int64++;
212 } else if (locals_.at(i).type_ == kAstF32) {
213 float32++;
214 } else if (locals_.at(i).type_ == kAstF64) {
215 float64++;
216 }
217 }
218 e->local_int32_count_ = int32;
219 e->local_int64_count_ = int64;
220 e->local_float32_count_ = float32;
221 e->local_float64_count_ = float64;
222 float64 = param + int32 + int64 + float32;
223 float32 = param + int32 + int64;
224 int64 = param + int32;
225 int32 = param;
226 param = 0;
227 for (size_t i = 0; i < locals_.size(); i++) {
228 if (locals_.at(i).param_) {
229 e->params_.push_back(locals_.at(i).type_);
230 var_index[i] = param++;
231 } else if (locals_.at(i).type_ == kAstI32) {
232 var_index[i] = int32++;
233 } else if (locals_.at(i).type_ == kAstI64) {
234 var_index[i] = int64++;
235 } else if (locals_.at(i).type_ == kAstF32) {
236 var_index[i] = float32++;
237 } else if (locals_.at(i).type_ == kAstF64) {
238 var_index[i] = float64++;
239 }
240 }
241 }
242
243
244 WasmFunctionEncoder::WasmFunctionEncoder(Zone* zone, LocalType return_type,
245 bool exported, bool external)
246 : params_(zone),
247 exported_(exported),
248 external_(external),
249 body_(zone),
250 name_(zone) {}
251
252
253 uint32_t WasmFunctionEncoder::HeaderSize() const {
254 uint32_t size = 3;
255 if (HasLocals()) size += 8;
256 if (!external_) size += 2;
257 if (HasName()) size += 4;
258 return size;
259 }
260
261
262 uint32_t WasmFunctionEncoder::BodySize(void) const {
263 return external_ ? 0 : static_cast<uint32_t>(body_.size());
264 }
265
266
267 uint32_t WasmFunctionEncoder::NameSize() const {
268 return exported_ ? static_cast<uint32_t>(name_.size()) : 0;
269 }
270
271
272 void WasmFunctionEncoder::Serialize(byte* buffer, byte** header,
273 byte** body) const {
274 uint8_t decl_bits = (exported_ ? kDeclFunctionExport : 0) |
275 (external_ ? kDeclFunctionImport : 0) |
276 (HasLocals() ? kDeclFunctionLocals : 0) |
277 (HasName() ? kDeclFunctionName : 0);
278
279 EmitUint8(header, decl_bits);
280 EmitUint16(header, signature_index_);
281
282 if (HasName()) {
283 uint32_t name_offset = static_cast<uint32_t>(*body - buffer);
284 EmitUint32(header, name_offset);
285 std::memcpy(*body, name_.data(), name_.size());
286 (*body) += name_.size();
287 }
288
289 if (HasLocals()) {
290 EmitUint16(header, local_int32_count_);
291 EmitUint16(header, local_int64_count_);
292 EmitUint16(header, local_float32_count_);
293 EmitUint16(header, local_float64_count_);
294 }
295
296 if (!external_) {
297 EmitUint16(header, static_cast<uint16_t>(body_.size()));
298 std::memcpy(*header, body_.data(), body_.size());
299 (*header) += body_.size();
300 }
301 }
302
303
304 WasmDataSegmentEncoder::WasmDataSegmentEncoder(Zone* zone, const byte* data,
305 uint32_t size, uint32_t dest)
306 : data_(zone), dest_(dest) {
307 for (size_t i = 0; i < size; i++) {
308 data_.push_back(data[i]);
309 }
310 }
311
312
313 uint32_t WasmDataSegmentEncoder::HeaderSize() const {
314 static const int kDataSegmentSize = 13;
315 return kDataSegmentSize;
316 }
317
318
319 uint32_t WasmDataSegmentEncoder::BodySize() const {
320 return static_cast<uint32_t>(data_.size());
321 }
322
323
324 void WasmDataSegmentEncoder::Serialize(byte* buffer, byte** header,
325 byte** body) const {
326 uint32_t body_offset = static_cast<uint32_t>(*body - buffer);
327 EmitUint32(header, dest_);
328 EmitUint32(header, body_offset);
329 EmitUint32(header, static_cast<uint32_t>(data_.size()));
330 EmitUint8(header, 1); // init
331
332 std::memcpy(*body, data_.data(), data_.size());
333 (*body) += data_.size();
334 }
335
336
337 WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
338 : zone_(zone),
339 signatures_(zone),
340 functions_(zone),
341 data_segments_(zone),
342 indirect_functions_(zone),
343 globals_(zone),
344 signature_map_(zone) {}
345
346
347 uint16_t WasmModuleBuilder::AddFunction(const unsigned char* name,
348 int name_length) {
349 functions_.push_back(new (zone_)
350 WasmFunctionBuilder(zone_, name, name_length));
351 return static_cast<uint16_t>(functions_.size() - 1);
352 }
353
354
355 WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) {
356 if (functions_.size() > index) {
357 return functions_.at(index);
358 } else {
359 return nullptr;
360 }
361 }
362
363
364 void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) {
365 data_segments_.push_back(data);
366 }
367
368
369 int WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a,
370 FunctionSig* b) {
371 if (a->return_count() < b->return_count()) return -1;
372 if (a->return_count() > b->return_count()) return 1;
373 if (a->parameter_count() < b->parameter_count()) return -1;
374 if (a->parameter_count() > b->parameter_count()) return 1;
375 for (size_t r = 0; r < a->return_count(); r++) {
376 if (a->GetReturn(r) < b->GetReturn(r)) return -1;
377 if (a->GetReturn(r) > b->GetReturn(r)) return 1;
378 }
379 for (size_t p = 0; p < a->parameter_count(); p++) {
380 if (a->GetParam(p) < b->GetParam(p)) return -1;
381 if (a->GetParam(p) > b->GetParam(p)) return 1;
382 }
383 return 0;
384 }
385
386
387 uint16_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
388 SignatureMap::iterator pos = signature_map_.find(sig);
389 if (pos != signature_map_.end()) {
390 return pos->second;
391 } else {
392 uint16_t index = static_cast<uint16_t>(signatures_.size());
393 signature_map_[sig] = index;
394 signatures_.push_back(sig);
395 return index;
396 }
397 }
398
399
400 void WasmModuleBuilder::AddIndirectFunction(uint16_t index) {
401 indirect_functions_.push_back(index);
402 }
403
404
405 WasmModuleWriter* WasmModuleBuilder::Build(Zone* zone) {
406 WasmModuleWriter* writer = new (zone) WasmModuleWriter(zone);
407 for (auto function : functions_) {
408 writer->functions_.push_back(function->Build(zone, this));
409 }
410 for (auto segment : data_segments_) {
411 writer->data_segments_.push_back(segment);
412 }
413 for (auto sig : signatures_) {
414 writer->signatures_.push_back(sig);
415 }
416 for (auto index : indirect_functions_) {
417 writer->indirect_functions_.push_back(index);
418 }
419 for (auto global : globals_) {
420 writer->globals_.push_back(global);
421 }
422 return writer;
423 }
424
425
426 uint32_t WasmModuleBuilder::AddGlobal(MachineType type, bool exported) {
427 globals_.push_back(std::make_pair(type, exported));
428 return static_cast<uint32_t>(globals_.size() - 1);
429 }
430
431
432 WasmModuleWriter::WasmModuleWriter(Zone* zone)
433 : functions_(zone),
434 data_segments_(zone),
435 signatures_(zone),
436 indirect_functions_(zone),
437 globals_(zone) {}
438
439
440 struct Sizes {
441 size_t header_size;
442 size_t body_size;
443
444 size_t total() { return header_size + body_size; }
445
446 void Add(size_t header, size_t body) {
447 header_size += header;
448 body_size += body;
449 }
450
451 void AddSection(size_t size) {
452 if (size > 0) {
453 Add(1, 0);
454 while (size > 0) {
455 Add(1, 0);
456 size = size >> 7;
457 }
458 }
459 }
460 };
461
462
463 WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
464 Sizes sizes = {0, 0};
465
466 sizes.Add(1, 0);
467 sizes.Add(kDeclMemorySize, 0);
468
469 sizes.AddSection(signatures_.size());
470 for (auto sig : signatures_) {
471 sizes.Add(2 + sig->parameter_count(), 0);
472 }
473
474 sizes.AddSection(globals_.size());
475 if (globals_.size() > 0) {
476 sizes.Add(kDeclGlobalSize * globals_.size(), 0);
477 }
478
479 sizes.AddSection(functions_.size());
480 for (auto function : functions_) {
481 sizes.Add(function->HeaderSize() + function->BodySize(),
482 function->NameSize());
483 }
484
485 sizes.AddSection(data_segments_.size());
486 for (auto segment : data_segments_) {
487 sizes.Add(segment->HeaderSize(), segment->BodySize());
488 }
489
490 sizes.AddSection(indirect_functions_.size());
491 sizes.Add(2 * static_cast<uint32_t>(indirect_functions_.size()), 0);
492
493 if (sizes.body_size > 0) sizes.Add(1, 0);
494
495 ZoneVector<uint8_t> buffer_vector(sizes.total(), zone);
496 byte* buffer = buffer_vector.data();
497 byte* header = buffer;
498 byte* body = buffer + sizes.header_size;
499
500 // -- emit memory declaration ------------------------------------------------
501 EmitUint8(&header, kDeclMemory);
502 EmitUint8(&header, 16); // min memory size
503 EmitUint8(&header, 16); // max memory size
504 EmitUint8(&header, 0); // memory export
505
506 // -- emit globals -----------------------------------------------------------
507 if (globals_.size() > 0) {
508 EmitUint8(&header, kDeclGlobals);
509 EmitVarInt(&header, globals_.size());
510
511 for (auto global : globals_) {
512 EmitUint32(&header, 0);
513 EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first));
514 EmitUint8(&header, global.second);
515 }
516 }
517
518 // -- emit signatures --------------------------------------------------------
519 if (signatures_.size() > 0) {
520 EmitUint8(&header, kDeclSignatures);
521 EmitVarInt(&header, signatures_.size());
522
523 for (FunctionSig* sig : signatures_) {
524 EmitUint8(&header, static_cast<byte>(sig->parameter_count()));
525 if (sig->return_count() > 0) {
526 EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn()));
527 } else {
528 EmitUint8(&header, kLocalVoid);
529 }
530 for (size_t j = 0; j < sig->parameter_count(); j++) {
531 EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
532 }
533 }
534 }
535
536 // -- emit functions ---------------------------------------------------------
537 if (functions_.size() > 0) {
538 EmitUint8(&header, kDeclFunctions);
539 EmitVarInt(&header, functions_.size());
540
541 for (auto func : functions_) {
542 func->Serialize(buffer, &header, &body);
543 }
544 }
545
546 // -- emit data segments -----------------------------------------------------
547 if (data_segments_.size() > 0) {
548 EmitUint8(&header, kDeclDataSegments);
549 EmitVarInt(&header, data_segments_.size());
550
551 for (auto segment : data_segments_) {
552 segment->Serialize(buffer, &header, &body);
553 }
554 }
555
556 // -- emit function table ----------------------------------------------------
557 if (indirect_functions_.size() > 0) {
558 EmitUint8(&header, kDeclFunctionTable);
559 EmitVarInt(&header, indirect_functions_.size());
560
561 for (auto index : indirect_functions_) {
562 EmitUint16(&header, index);
563 }
564 }
565
566 if (sizes.body_size > 0) EmitUint8(&header, kDeclEnd);
567
568 return new (zone) WasmModuleIndex(buffer, buffer + sizes.total());
569 }
570
571
572 std::vector<uint8_t> UnsignedLEB128From(uint32_t result) {
573 std::vector<uint8_t> output;
574 uint8_t next = 0;
575 int shift = 0;
576 do {
577 next = static_cast<uint8_t>(result >> shift);
578 if (((result >> shift) & 0xFFFFFF80) != 0) {
579 next = next | 0x80;
580 }
581 output.push_back(next);
582 shift += 7;
583 } while ((next & 0x80) != 0);
584 return output;
585 }
586 } // namespace wasm
587 } // namespace internal
588 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/encoder.h ('k') | src/wasm/module-decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698