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