Home | History | Annotate | Download | only in wasm
      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)
     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 
     76 uint16_t WasmFunctionBuilder::AddParam(LocalType type) {
     77   return AddVar(type, true);
     78 }
     79 
     80 
     81 uint16_t WasmFunctionBuilder::AddLocal(LocalType type) {
     82   return AddVar(type, false);
     83 }
     84 
     85 
     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 
     92 void WasmFunctionBuilder::ReturnType(LocalType type) { return_type_ = type; }
     93 
     94 
     95 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
     96   EmitCode(code, code_size, nullptr, 0);
     97 }
     98 
     99 
    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 
    113 void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
    114   body_.push_back(static_cast<byte>(opcode));
    115 }
    116 
    117 
    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 
    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 
    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 
    136 void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) {
    137   DCHECK(offset < body_.size());
    138   body_[offset] = immediate;
    139 }
    140 
    141 
    142 void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; }
    143 
    144 
    145 void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; }
    146 
    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 
    158 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 
    202 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 
    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 
    257 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 
    266 uint32_t WasmFunctionEncoder::BodySize(void) const {
    267   return external_ ? 0 : static_cast<uint32_t>(body_.size());
    268 }
    269 
    270 
    271 uint32_t WasmFunctionEncoder::NameSize() const {
    272   return exported_ ? static_cast<uint32_t>(name_.size()) : 0;
    273 }
    274 
    275 
    276 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 
    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 
    319 uint32_t WasmDataSegmentEncoder::HeaderSize() const {
    320   static const int kDataSegmentSize = 13;
    321   return kDataSegmentSize;
    322 }
    323 
    324 
    325 uint32_t WasmDataSegmentEncoder::BodySize() const {
    326   return static_cast<uint32_t>(data_.size());
    327 }
    328 
    329 
    330 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 
    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 
    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 
    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 
    368 void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) {
    369   data_segments_.push_back(data);
    370 }
    371 
    372 
    373 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 
    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 
    404 void WasmModuleBuilder::AddIndirectFunction(uint16_t index) {
    405   indirect_functions_.push_back(index);
    406 }
    407 
    408 
    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 
    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 
    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 
    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 
    467 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 
    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