blob: d80a27533884401ae845ec185b385225c56361c7 [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) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010033 WriteUnalignedUInt16(*b, x);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 *b += 2;
35}
36
37
38void EmitUint32(byte** b, uint32_t x) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010039 WriteUnalignedUInt32(*b, x);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000040 *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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) {
125 body_.push_back(immediate);
126 return static_cast<uint32_t>(body_.size()) - 1;
127}
128
129
130void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) {
131 DCHECK(offset < body_.size());
132 body_[offset] = immediate;
133}
134
135
136void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; }
137
138
139void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; }
140
141void WasmFunctionBuilder::SetName(const unsigned char* name, int name_length) {
142 name_.clear();
143 if (name_length > 0) {
144 for (int i = 0; i < name_length; i++) {
145 name_.push_back(*(name + i));
146 }
147 name_.push_back('\0');
148 }
149}
150
151
152WasmFunctionEncoder* WasmFunctionBuilder::Build(Zone* zone,
153 WasmModuleBuilder* mb) const {
154 WasmFunctionEncoder* e =
155 new (zone) WasmFunctionEncoder(zone, return_type_, exported_, external_);
156 uint16_t* var_index = zone->NewArray<uint16_t>(locals_.size());
157 IndexVars(e, var_index);
158 if (body_.size() > 0) {
159 // TODO(titzer): iterate over local indexes, not the bytes.
160 const byte* start = &body_[0];
161 const byte* end = start + body_.size();
162 size_t local_index = 0;
163 for (size_t i = 0; i < body_.size();) {
164 if (local_index < local_indices_.size() &&
165 i == local_indices_[local_index]) {
166 int length = 0;
167 uint32_t index;
168 ReadUnsignedLEB128Operand(start + i, end, &length, &index);
169 uint16_t new_index = var_index[index];
170 const std::vector<uint8_t>& index_vec = UnsignedLEB128From(new_index);
171 for (size_t j = 0; j < index_vec.size(); j++) {
172 e->body_.push_back(index_vec.at(j));
173 }
174 i += length;
175 local_index++;
176 } else {
177 e->body_.push_back(*(start + i));
178 i++;
179 }
180 }
181 }
182 FunctionSig::Builder sig(zone, return_type_ == kAstStmt ? 0 : 1,
183 e->params_.size());
184 if (return_type_ != kAstStmt) {
185 sig.AddReturn(static_cast<LocalType>(return_type_));
186 }
187 for (size_t i = 0; i < e->params_.size(); i++) {
188 sig.AddParam(static_cast<LocalType>(e->params_[i]));
189 }
190 e->signature_index_ = mb->AddSignature(sig.Build());
191 e->name_.insert(e->name_.begin(), name_.begin(), name_.end());
192 return e;
193}
194
195
196void WasmFunctionBuilder::IndexVars(WasmFunctionEncoder* e,
197 uint16_t* var_index) const {
198 uint16_t param = 0;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100199 uint16_t i32 = 0;
200 uint16_t i64 = 0;
201 uint16_t f32 = 0;
202 uint16_t f64 = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 for (size_t i = 0; i < locals_.size(); i++) {
204 if (locals_.at(i).param_) {
205 param++;
206 } else if (locals_.at(i).type_ == kAstI32) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 i32++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 } else if (locals_.at(i).type_ == kAstI64) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100209 i64++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 } else if (locals_.at(i).type_ == kAstF32) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211 f32++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 } else if (locals_.at(i).type_ == kAstF64) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100213 f64++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 }
215 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 e->local_i32_count_ = i32;
217 e->local_i64_count_ = i64;
218 e->local_f32_count_ = f32;
219 e->local_f64_count_ = f64;
220 f64 = param + i32 + i64 + f32;
221 f32 = param + i32 + i64;
222 i64 = param + i32;
223 i32 = param;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 param = 0;
225 for (size_t i = 0; i < locals_.size(); i++) {
226 if (locals_.at(i).param_) {
227 e->params_.push_back(locals_.at(i).type_);
228 var_index[i] = param++;
229 } else if (locals_.at(i).type_ == kAstI32) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100230 var_index[i] = i32++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 } else if (locals_.at(i).type_ == kAstI64) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100232 var_index[i] = i64++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 } else if (locals_.at(i).type_ == kAstF32) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100234 var_index[i] = f32++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235 } else if (locals_.at(i).type_ == kAstF64) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100236 var_index[i] = f64++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 }
238 }
239}
240
241
242WasmFunctionEncoder::WasmFunctionEncoder(Zone* zone, LocalType return_type,
243 bool exported, bool external)
244 : params_(zone),
245 exported_(exported),
246 external_(external),
247 body_(zone),
248 name_(zone) {}
249
250
251uint32_t WasmFunctionEncoder::HeaderSize() const {
252 uint32_t size = 3;
253 if (HasLocals()) size += 8;
254 if (!external_) size += 2;
255 if (HasName()) size += 4;
256 return size;
257}
258
259
260uint32_t WasmFunctionEncoder::BodySize(void) const {
261 return external_ ? 0 : static_cast<uint32_t>(body_.size());
262}
263
264
265uint32_t WasmFunctionEncoder::NameSize() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100266 return HasName() ? static_cast<uint32_t>(name_.size()) : 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267}
268
269
270void WasmFunctionEncoder::Serialize(byte* buffer, byte** header,
271 byte** body) const {
272 uint8_t decl_bits = (exported_ ? kDeclFunctionExport : 0) |
273 (external_ ? kDeclFunctionImport : 0) |
274 (HasLocals() ? kDeclFunctionLocals : 0) |
275 (HasName() ? kDeclFunctionName : 0);
276
277 EmitUint8(header, decl_bits);
278 EmitUint16(header, signature_index_);
279
280 if (HasName()) {
281 uint32_t name_offset = static_cast<uint32_t>(*body - buffer);
282 EmitUint32(header, name_offset);
283 std::memcpy(*body, &name_[0], name_.size());
284 (*body) += name_.size();
285 }
286
287 if (HasLocals()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100288 EmitUint16(header, local_i32_count_);
289 EmitUint16(header, local_i64_count_);
290 EmitUint16(header, local_f32_count_);
291 EmitUint16(header, local_f64_count_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 }
293
294 if (!external_) {
295 EmitUint16(header, static_cast<uint16_t>(body_.size()));
296 if (body_.size() > 0) {
297 std::memcpy(*header, &body_[0], body_.size());
298 (*header) += body_.size();
299 }
300 }
301}
302
303
304WasmDataSegmentEncoder::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
313uint32_t WasmDataSegmentEncoder::HeaderSize() const {
314 static const int kDataSegmentSize = 13;
315 return kDataSegmentSize;
316}
317
318
319uint32_t WasmDataSegmentEncoder::BodySize() const {
320 return static_cast<uint32_t>(data_.size());
321}
322
323
324void 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_[0], data_.size());
333 (*body) += data_.size();
334}
335
336
337WasmModuleBuilder::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
347uint16_t WasmModuleBuilder::AddFunction() {
348 functions_.push_back(new (zone_) WasmFunctionBuilder(zone_));
349 return static_cast<uint16_t>(functions_.size() - 1);
350}
351
352
353WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) {
354 if (functions_.size() > index) {
355 return functions_.at(index);
356 } else {
357 return nullptr;
358 }
359}
360
361
362void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) {
363 data_segments_.push_back(data);
364}
365
366
Ben Murdoch097c5b22016-05-18 11:27:45 +0100367bool WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a,
368 FunctionSig* b) const {
369 if (a->return_count() < b->return_count()) return true;
370 if (a->return_count() > b->return_count()) return false;
371 if (a->parameter_count() < b->parameter_count()) return true;
372 if (a->parameter_count() > b->parameter_count()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 for (size_t r = 0; r < a->return_count(); r++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100374 if (a->GetReturn(r) < b->GetReturn(r)) return true;
375 if (a->GetReturn(r) > b->GetReturn(r)) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376 }
377 for (size_t p = 0; p < a->parameter_count(); p++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100378 if (a->GetParam(p) < b->GetParam(p)) return true;
379 if (a->GetParam(p) > b->GetParam(p)) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100381 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382}
383
384
385uint16_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
386 SignatureMap::iterator pos = signature_map_.find(sig);
387 if (pos != signature_map_.end()) {
388 return pos->second;
389 } else {
390 uint16_t index = static_cast<uint16_t>(signatures_.size());
391 signature_map_[sig] = index;
392 signatures_.push_back(sig);
393 return index;
394 }
395}
396
397
398void WasmModuleBuilder::AddIndirectFunction(uint16_t index) {
399 indirect_functions_.push_back(index);
400}
401
402
403WasmModuleWriter* WasmModuleBuilder::Build(Zone* zone) {
404 WasmModuleWriter* writer = new (zone) WasmModuleWriter(zone);
405 for (auto function : functions_) {
406 writer->functions_.push_back(function->Build(zone, this));
407 }
408 for (auto segment : data_segments_) {
409 writer->data_segments_.push_back(segment);
410 }
411 for (auto sig : signatures_) {
412 writer->signatures_.push_back(sig);
413 }
414 for (auto index : indirect_functions_) {
415 writer->indirect_functions_.push_back(index);
416 }
417 for (auto global : globals_) {
418 writer->globals_.push_back(global);
419 }
420 return writer;
421}
422
423
424uint32_t WasmModuleBuilder::AddGlobal(MachineType type, bool exported) {
425 globals_.push_back(std::make_pair(type, exported));
426 return static_cast<uint32_t>(globals_.size() - 1);
427}
428
429
430WasmModuleWriter::WasmModuleWriter(Zone* zone)
431 : functions_(zone),
432 data_segments_(zone),
433 signatures_(zone),
434 indirect_functions_(zone),
435 globals_(zone) {}
436
437
438struct Sizes {
439 size_t header_size;
440 size_t body_size;
441
442 size_t total() { return header_size + body_size; }
443
444 void Add(size_t header, size_t body) {
445 header_size += header;
446 body_size += body;
447 }
448
449 void AddSection(size_t size) {
450 if (size > 0) {
451 Add(1, 0);
452 while (size > 0) {
453 Add(1, 0);
454 size = size >> 7;
455 }
456 }
457 }
458};
459
460
461WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
462 Sizes sizes = {0, 0};
463
464 sizes.Add(1, 0);
465 sizes.Add(kDeclMemorySize, 0);
466
467 sizes.AddSection(signatures_.size());
468 for (auto sig : signatures_) {
469 sizes.Add(2 + sig->parameter_count(), 0);
470 }
471
472 sizes.AddSection(globals_.size());
473 if (globals_.size() > 0) {
474 sizes.Add(kDeclGlobalSize * globals_.size(), 0);
475 }
476
477 sizes.AddSection(functions_.size());
478 for (auto function : functions_) {
479 sizes.Add(function->HeaderSize() + function->BodySize(),
480 function->NameSize());
481 }
482
483 sizes.AddSection(data_segments_.size());
484 for (auto segment : data_segments_) {
485 sizes.Add(segment->HeaderSize(), segment->BodySize());
486 }
487
488 sizes.AddSection(indirect_functions_.size());
489 sizes.Add(2 * static_cast<uint32_t>(indirect_functions_.size()), 0);
490
491 if (sizes.body_size > 0) sizes.Add(1, 0);
492
493 ZoneVector<uint8_t> buffer_vector(sizes.total(), zone);
494 byte* buffer = &buffer_vector[0];
495 byte* header = buffer;
496 byte* body = buffer + sizes.header_size;
497
498 // -- emit memory declaration ------------------------------------------------
499 EmitUint8(&header, kDeclMemory);
500 EmitUint8(&header, 16); // min memory size
501 EmitUint8(&header, 16); // max memory size
502 EmitUint8(&header, 0); // memory export
503
504 // -- emit globals -----------------------------------------------------------
505 if (globals_.size() > 0) {
506 EmitUint8(&header, kDeclGlobals);
507 EmitVarInt(&header, globals_.size());
508
509 for (auto global : globals_) {
510 EmitUint32(&header, 0);
511 EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first));
512 EmitUint8(&header, global.second);
513 }
514 }
515
516 // -- emit signatures --------------------------------------------------------
517 if (signatures_.size() > 0) {
518 EmitUint8(&header, kDeclSignatures);
519 EmitVarInt(&header, signatures_.size());
520
521 for (FunctionSig* sig : signatures_) {
522 EmitUint8(&header, static_cast<byte>(sig->parameter_count()));
523 if (sig->return_count() > 0) {
524 EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn()));
525 } else {
526 EmitUint8(&header, kLocalVoid);
527 }
528 for (size_t j = 0; j < sig->parameter_count(); j++) {
529 EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
530 }
531 }
532 }
533
534 // -- emit functions ---------------------------------------------------------
535 if (functions_.size() > 0) {
536 EmitUint8(&header, kDeclFunctions);
537 EmitVarInt(&header, functions_.size());
538
539 for (auto func : functions_) {
540 func->Serialize(buffer, &header, &body);
541 }
542 }
543
544 // -- emit data segments -----------------------------------------------------
545 if (data_segments_.size() > 0) {
546 EmitUint8(&header, kDeclDataSegments);
547 EmitVarInt(&header, data_segments_.size());
548
549 for (auto segment : data_segments_) {
550 segment->Serialize(buffer, &header, &body);
551 }
552 }
553
554 // -- emit function table ----------------------------------------------------
555 if (indirect_functions_.size() > 0) {
556 EmitUint8(&header, kDeclFunctionTable);
557 EmitVarInt(&header, indirect_functions_.size());
558
559 for (auto index : indirect_functions_) {
560 EmitUint16(&header, index);
561 }
562 }
563
564 if (sizes.body_size > 0) EmitUint8(&header, kDeclEnd);
565
566 return new (zone) WasmModuleIndex(buffer, buffer + sizes.total());
567}
568
569
570std::vector<uint8_t> UnsignedLEB128From(uint32_t result) {
571 std::vector<uint8_t> output;
572 uint8_t next = 0;
573 int shift = 0;
574 do {
575 next = static_cast<uint8_t>(result >> shift);
576 if (((result >> shift) & 0xFFFFFF80) != 0) {
577 next = next | 0x80;
578 }
579 output.push_back(next);
580 shift += 7;
581 } while ((next & 0x80) != 0);
582 return output;
583}
584} // namespace wasm
585} // namespace internal
586} // namespace v8