• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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