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 {
EmitUint8(byte ** b,uint8_t x)26 void EmitUint8(byte** b, uint8_t x) {
27 Memory::uint8_at(*b) = x;
28 *b += 1;
29 }
30
31
EmitUint16(byte ** b,uint16_t x)32 void EmitUint16(byte** b, uint16_t x) {
33 Memory::uint16_at(*b) = x;
34 *b += 2;
35 }
36
37
EmitUint32(byte ** b,uint32_t x)38 void EmitUint32(byte** b, uint32_t x) {
39 Memory::uint32_at(*b) = x;
40 *b += 4;
41 }
42
43
EmitVarInt(byte ** b,size_t val)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
WasmFunctionBuilder(Zone * zone)66 WasmFunctionBuilder::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
AddParam(LocalType type)76 uint16_t WasmFunctionBuilder::AddParam(LocalType type) {
77 return AddVar(type, true);
78 }
79
80
AddLocal(LocalType type)81 uint16_t WasmFunctionBuilder::AddLocal(LocalType type) {
82 return AddVar(type, false);
83 }
84
85
AddVar(LocalType type,bool param)86 uint16_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
ReturnType(LocalType type)92 void WasmFunctionBuilder::ReturnType(LocalType type) { return_type_ = type; }
93
94
EmitCode(const byte * code,uint32_t code_size)95 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
96 EmitCode(code, code_size, nullptr, 0);
97 }
98
99
EmitCode(const byte * code,uint32_t code_size,const uint32_t * local_indices,uint32_t indices_size)100 void 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
Emit(WasmOpcode opcode)113 void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
114 body_.push_back(static_cast<byte>(opcode));
115 }
116
117
EmitWithU8(WasmOpcode opcode,const byte immediate)118 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
119 body_.push_back(static_cast<byte>(opcode));
120 body_.push_back(immediate);
121 }
122
123
EmitWithLocal(WasmOpcode opcode)124 void 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
EmitEditableImmediate(const byte immediate)130 uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) {
131 body_.push_back(immediate);
132 return static_cast<uint32_t>(body_.size()) - 1;
133 }
134
135
EditImmediate(uint32_t offset,const byte immediate)136 void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) {
137 DCHECK(offset < body_.size());
138 body_[offset] = immediate;
139 }
140
141
Exported(uint8_t flag)142 void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; }
143
144
External(uint8_t flag)145 void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; }
146
SetName(const unsigned char * name,int name_length)147 void 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
Build(Zone * zone,WasmModuleBuilder * mb) const158 WasmFunctionEncoder* 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
IndexVars(WasmFunctionEncoder * e,uint16_t * var_index) const202 void 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
WasmFunctionEncoder(Zone * zone,LocalType return_type,bool exported,bool external)248 WasmFunctionEncoder::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
HeaderSize() const257 uint32_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
BodySize(void) const266 uint32_t WasmFunctionEncoder::BodySize(void) const {
267 return external_ ? 0 : static_cast<uint32_t>(body_.size());
268 }
269
270
NameSize() const271 uint32_t WasmFunctionEncoder::NameSize() const {
272 return exported_ ? static_cast<uint32_t>(name_.size()) : 0;
273 }
274
275
Serialize(byte * buffer,byte ** header,byte ** body) const276 void 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
WasmDataSegmentEncoder(Zone * zone,const byte * data,uint32_t size,uint32_t dest)310 WasmDataSegmentEncoder::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
HeaderSize() const319 uint32_t WasmDataSegmentEncoder::HeaderSize() const {
320 static const int kDataSegmentSize = 13;
321 return kDataSegmentSize;
322 }
323
324
BodySize() const325 uint32_t WasmDataSegmentEncoder::BodySize() const {
326 return static_cast<uint32_t>(data_.size());
327 }
328
329
Serialize(byte * buffer,byte ** header,byte ** body) const330 void 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
WasmModuleBuilder(Zone * zone)343 WasmModuleBuilder::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
AddFunction()353 uint16_t WasmModuleBuilder::AddFunction() {
354 functions_.push_back(new (zone_) WasmFunctionBuilder(zone_));
355 return static_cast<uint16_t>(functions_.size() - 1);
356 }
357
358
FunctionAt(size_t index)359 WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) {
360 if (functions_.size() > index) {
361 return functions_.at(index);
362 } else {
363 return nullptr;
364 }
365 }
366
367
AddDataSegment(WasmDataSegmentEncoder * data)368 void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) {
369 data_segments_.push_back(data);
370 }
371
372
operator ()(FunctionSig * a,FunctionSig * b) const373 int 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
AddSignature(FunctionSig * sig)391 uint16_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
AddIndirectFunction(uint16_t index)404 void WasmModuleBuilder::AddIndirectFunction(uint16_t index) {
405 indirect_functions_.push_back(index);
406 }
407
408
Build(Zone * zone)409 WasmModuleWriter* 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
AddGlobal(MachineType type,bool exported)430 uint32_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
WasmModuleWriter(Zone * zone)436 WasmModuleWriter::WasmModuleWriter(Zone* zone)
437 : functions_(zone),
438 data_segments_(zone),
439 signatures_(zone),
440 indirect_functions_(zone),
441 globals_(zone) {}
442
443
444 struct Sizes {
445 size_t header_size;
446 size_t body_size;
447
totalv8::internal::wasm::Sizes448 size_t total() { return header_size + body_size; }
449
Addv8::internal::wasm::Sizes450 void Add(size_t header, size_t body) {
451 header_size += header;
452 body_size += body;
453 }
454
AddSectionv8::internal::wasm::Sizes455 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
WriteTo(Zone * zone) const467 WasmModuleIndex* 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
UnsignedLEB128From(uint32_t result)576 std::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
593