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/zone-containers.h"
     10 
     11 #include "src/wasm/ast-decoder.h"
     12 #include "src/wasm/leb-helper.h"
     13 #include "src/wasm/wasm-macro-gen.h"
     14 #include "src/wasm/wasm-module-builder.h"
     15 #include "src/wasm/wasm-module.h"
     16 #include "src/wasm/wasm-opcodes.h"
     17 
     18 #include "src/v8memory.h"
     19 
     20 #if DEBUG
     21 #define TRACE(...)                                    \
     22   do {                                                \
     23     if (FLAG_trace_wasm_encoder) PrintF(__VA_ARGS__); \
     24   } while (false)
     25 #else
     26 #define TRACE(...)
     27 #endif
     28 
     29 namespace v8 {
     30 namespace internal {
     31 namespace wasm {
     32 
     33 // Emit a section code and the size as a padded varint that can be patched
     34 // later.
     35 size_t EmitSection(WasmSectionCode code, ZoneBuffer& buffer) {
     36   // Emit the section code.
     37   buffer.write_u8(code);
     38 
     39   // Emit a placeholder for the length.
     40   return buffer.reserve_u32v();
     41 }
     42 
     43 // Patch the size of a section after it's finished.
     44 void FixupSection(ZoneBuffer& buffer, size_t start) {
     45   buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start -
     46                                                  kPaddedVarInt32Size));
     47 }
     48 
     49 WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder)
     50     : builder_(builder),
     51       locals_(builder->zone()),
     52       signature_index_(0),
     53       exported_(0),
     54       func_index_(static_cast<uint32_t>(builder->functions_.size())),
     55       body_(builder->zone()),
     56       name_(builder->zone()),
     57       exported_name_(builder->zone()),
     58       i32_temps_(builder->zone()),
     59       i64_temps_(builder->zone()),
     60       f32_temps_(builder->zone()),
     61       f64_temps_(builder->zone()),
     62       direct_calls_(builder->zone()),
     63       asm_offsets_(builder->zone(), 8) {}
     64 
     65 void WasmFunctionBuilder::EmitVarInt(uint32_t val) {
     66   byte buffer[8];
     67   byte* ptr = buffer;
     68   LEBHelper::write_u32v(&ptr, val);
     69   for (byte* p = buffer; p < ptr; p++) {
     70     body_.push_back(*p);
     71   }
     72 }
     73 
     74 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
     75   DCHECK(!locals_.has_sig());
     76   locals_.set_sig(sig);
     77   signature_index_ = builder_->AddSignature(sig);
     78 }
     79 
     80 uint32_t WasmFunctionBuilder::AddLocal(LocalType type) {
     81   DCHECK(locals_.has_sig());
     82   return locals_.AddLocals(1, type);
     83 }
     84 
     85 void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
     86   EmitWithVarInt(kExprGetLocal, local_index);
     87 }
     88 
     89 void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
     90   EmitWithVarInt(kExprSetLocal, local_index);
     91 }
     92 
     93 void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
     94   EmitWithVarInt(kExprTeeLocal, local_index);
     95 }
     96 
     97 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
     98   for (size_t i = 0; i < code_size; ++i) {
     99     body_.push_back(code[i]);
    100   }
    101 }
    102 
    103 void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
    104   body_.push_back(static_cast<byte>(opcode));
    105 }
    106 
    107 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
    108   body_.push_back(static_cast<byte>(opcode));
    109   body_.push_back(immediate);
    110 }
    111 
    112 void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode, const byte imm1,
    113                                        const byte imm2) {
    114   body_.push_back(static_cast<byte>(opcode));
    115   body_.push_back(imm1);
    116   body_.push_back(imm2);
    117 }
    118 
    119 void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode,
    120                                          uint32_t immediate) {
    121   body_.push_back(static_cast<byte>(opcode));
    122   EmitVarInt(immediate);
    123 }
    124 
    125 void WasmFunctionBuilder::EmitI32Const(int32_t value) {
    126   // TODO(titzer): variable-length signed and unsigned i32 constants.
    127   if (-128 <= value && value <= 127) {
    128     EmitWithU8(kExprI8Const, static_cast<byte>(value));
    129   } else {
    130     byte code[] = {WASM_I32V_5(value)};
    131     EmitCode(code, sizeof(code));
    132   }
    133 }
    134 
    135 void WasmFunctionBuilder::EmitDirectCallIndex(uint32_t index) {
    136   DirectCallIndex call;
    137   call.offset = body_.size();
    138   call.direct_index = index;
    139   direct_calls_.push_back(call);
    140   byte code[] = {U32V_5(0)};
    141   EmitCode(code, sizeof(code));
    142 }
    143 
    144 void WasmFunctionBuilder::Export() { exported_ = true; }
    145 
    146 void WasmFunctionBuilder::ExportAs(Vector<const char> name) {
    147   exported_ = true;
    148   exported_name_.resize(name.length());
    149   memcpy(exported_name_.data(), name.start(), name.length());
    150 }
    151 
    152 void WasmFunctionBuilder::SetName(Vector<const char> name) {
    153   name_.resize(name.length());
    154   memcpy(name_.data(), name.start(), name.length());
    155 }
    156 
    157 void WasmFunctionBuilder::AddAsmWasmOffset(int asm_position) {
    158   // We only want to emit one mapping per byte offset:
    159   DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_);
    160 
    161   DCHECK_LE(body_.size(), kMaxUInt32);
    162   uint32_t byte_offset = static_cast<uint32_t>(body_.size());
    163   asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_);
    164   last_asm_byte_offset_ = byte_offset;
    165 
    166   DCHECK_GE(asm_position, 0);
    167   asm_offsets_.write_i32v(asm_position - last_asm_source_position_);
    168   last_asm_source_position_ = asm_position;
    169 }
    170 
    171 void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const {
    172   buffer.write_u32v(signature_index_);
    173 }
    174 
    175 void WasmFunctionBuilder::WriteExport(ZoneBuffer& buffer) const {
    176   if (exported_) {
    177     const ZoneVector<char>* exported_name =
    178         exported_name_.size() == 0 ? &name_ : &exported_name_;
    179     buffer.write_size(exported_name->size());
    180     buffer.write(reinterpret_cast<const byte*>(exported_name->data()),
    181                  exported_name->size());
    182     buffer.write_u8(kExternalFunction);
    183     buffer.write_u32v(func_index_ +
    184                       static_cast<uint32_t>(builder_->imports_.size()));
    185   }
    186 }
    187 
    188 void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer) const {
    189   size_t locals_size = locals_.Size();
    190   buffer.write_size(locals_size + body_.size());
    191   buffer.EnsureSpace(locals_size);
    192   byte** ptr = buffer.pos_ptr();
    193   locals_.Emit(*ptr);
    194   (*ptr) += locals_size;  // UGLY: manual bump of position pointer
    195   if (body_.size() > 0) {
    196     size_t base = buffer.offset();
    197     buffer.write(&body_[0], body_.size());
    198     for (DirectCallIndex call : direct_calls_) {
    199       buffer.patch_u32v(
    200           base + call.offset,
    201           call.direct_index + static_cast<uint32_t>(builder_->imports_.size()));
    202     }
    203   }
    204 }
    205 
    206 void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer& buffer) const {
    207   if (asm_offsets_.size() == 0) {
    208     buffer.write_size(0);
    209     return;
    210   }
    211   buffer.write_size(asm_offsets_.size() + kInt32Size);
    212   // Offset of the recorded byte offsets.
    213   DCHECK_GE(kMaxUInt32, locals_.Size());
    214   buffer.write_u32(static_cast<uint32_t>(locals_.Size()));
    215   buffer.write(asm_offsets_.begin(), asm_offsets_.size());
    216 }
    217 
    218 WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
    219     : zone_(zone),
    220       signatures_(zone),
    221       imports_(zone),
    222       functions_(zone),
    223       data_segments_(zone),
    224       indirect_functions_(zone),
    225       globals_(zone),
    226       signature_map_(zone),
    227       start_function_index_(-1) {}
    228 
    229 WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) {
    230   functions_.push_back(new (zone_) WasmFunctionBuilder(this));
    231   // Add the signature if one was provided here.
    232   if (sig) functions_.back()->SetSignature(sig);
    233   return functions_.back();
    234 }
    235 
    236 void WasmModuleBuilder::AddDataSegment(const byte* data, uint32_t size,
    237                                        uint32_t dest) {
    238   data_segments_.push_back({ZoneVector<byte>(zone()), dest});
    239   ZoneVector<byte>& vec = data_segments_.back().data;
    240   for (uint32_t i = 0; i < size; i++) {
    241     vec.push_back(data[i]);
    242   }
    243 }
    244 
    245 bool WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a,
    246                                                         FunctionSig* b) const {
    247   if (a->return_count() < b->return_count()) return true;
    248   if (a->return_count() > b->return_count()) return false;
    249   if (a->parameter_count() < b->parameter_count()) return true;
    250   if (a->parameter_count() > b->parameter_count()) return false;
    251   for (size_t r = 0; r < a->return_count(); r++) {
    252     if (a->GetReturn(r) < b->GetReturn(r)) return true;
    253     if (a->GetReturn(r) > b->GetReturn(r)) return false;
    254   }
    255   for (size_t p = 0; p < a->parameter_count(); p++) {
    256     if (a->GetParam(p) < b->GetParam(p)) return true;
    257     if (a->GetParam(p) > b->GetParam(p)) return false;
    258   }
    259   return false;
    260 }
    261 
    262 uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
    263   SignatureMap::iterator pos = signature_map_.find(sig);
    264   if (pos != signature_map_.end()) {
    265     return pos->second;
    266   } else {
    267     uint32_t index = static_cast<uint32_t>(signatures_.size());
    268     signature_map_[sig] = index;
    269     signatures_.push_back(sig);
    270     return index;
    271   }
    272 }
    273 
    274 void WasmModuleBuilder::AddIndirectFunction(uint32_t index) {
    275   indirect_functions_.push_back(index);
    276 }
    277 
    278 uint32_t WasmModuleBuilder::AddImport(const char* name, int name_length,
    279                                       FunctionSig* sig) {
    280   imports_.push_back({AddSignature(sig), name, name_length});
    281   return static_cast<uint32_t>(imports_.size() - 1);
    282 }
    283 
    284 void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
    285   start_function_index_ = function->func_index();
    286 }
    287 
    288 uint32_t WasmModuleBuilder::AddGlobal(LocalType type, bool exported,
    289                                       bool mutability,
    290                                       const WasmInitExpr& init) {
    291   globals_.push_back({type, exported, mutability, init});
    292   return static_cast<uint32_t>(globals_.size() - 1);
    293 }
    294 
    295 void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
    296   uint32_t exports = 0;
    297 
    298   // == Emit magic =============================================================
    299   TRACE("emit magic\n");
    300   buffer.write_u32(kWasmMagic);
    301   buffer.write_u32(kWasmVersion);
    302 
    303   // == Emit signatures ========================================================
    304   if (signatures_.size() > 0) {
    305     size_t start = EmitSection(kTypeSectionCode, buffer);
    306     buffer.write_size(signatures_.size());
    307 
    308     for (FunctionSig* sig : signatures_) {
    309       buffer.write_u8(kWasmFunctionTypeForm);
    310       buffer.write_size(sig->parameter_count());
    311       for (size_t j = 0; j < sig->parameter_count(); j++) {
    312         buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
    313       }
    314       buffer.write_size(sig->return_count());
    315       for (size_t j = 0; j < sig->return_count(); j++) {
    316         buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(sig->GetReturn(j)));
    317       }
    318     }
    319     FixupSection(buffer, start);
    320   }
    321 
    322   // == Emit imports ===========================================================
    323   if (imports_.size() > 0) {
    324     size_t start = EmitSection(kImportSectionCode, buffer);
    325     buffer.write_size(imports_.size());
    326     for (auto import : imports_) {
    327       buffer.write_u32v(import.name_length);  // module name length
    328       buffer.write(reinterpret_cast<const byte*>(import.name),  // module name
    329                    import.name_length);
    330       buffer.write_u32v(0);  // field name length
    331       buffer.write_u8(kExternalFunction);
    332       buffer.write_u32v(import.sig_index);
    333     }
    334     FixupSection(buffer, start);
    335   }
    336 
    337   // == Emit function signatures ===============================================
    338   bool has_names = false;
    339   if (functions_.size() > 0) {
    340     size_t start = EmitSection(kFunctionSectionCode, buffer);
    341     buffer.write_size(functions_.size());
    342     for (auto function : functions_) {
    343       function->WriteSignature(buffer);
    344       if (function->exported()) exports++;
    345       if (function->name_.size() > 0) has_names = true;
    346     }
    347     FixupSection(buffer, start);
    348   }
    349 
    350   // == emit function table ====================================================
    351   if (indirect_functions_.size() > 0) {
    352     size_t start = EmitSection(kTableSectionCode, buffer);
    353     buffer.write_u8(1);  // table count
    354     buffer.write_u8(kWasmAnyFunctionTypeForm);
    355     buffer.write_u8(kResizableMaximumFlag);
    356     buffer.write_size(indirect_functions_.size());
    357     buffer.write_size(indirect_functions_.size());
    358     FixupSection(buffer, start);
    359   }
    360 
    361   // == emit memory declaration ================================================
    362   {
    363     size_t start = EmitSection(kMemorySectionCode, buffer);
    364     buffer.write_u8(1);  // memory count
    365     buffer.write_u32v(kResizableMaximumFlag);
    366     buffer.write_u32v(16);  // min memory size
    367     buffer.write_u32v(32);  // max memory size
    368     FixupSection(buffer, start);
    369   }
    370 
    371   // == Emit globals ===========================================================
    372   if (globals_.size() > 0) {
    373     size_t start = EmitSection(kGlobalSectionCode, buffer);
    374     buffer.write_size(globals_.size());
    375 
    376     for (auto global : globals_) {
    377       buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(global.type));
    378       buffer.write_u8(global.mutability ? 1 : 0);
    379       switch (global.init.kind) {
    380         case WasmInitExpr::kI32Const: {
    381           DCHECK_EQ(kAstI32, global.type);
    382           const byte code[] = {WASM_I32V_5(global.init.val.i32_const)};
    383           buffer.write(code, sizeof(code));
    384           break;
    385         }
    386         case WasmInitExpr::kI64Const: {
    387           DCHECK_EQ(kAstI64, global.type);
    388           const byte code[] = {WASM_I64V_10(global.init.val.i64_const)};
    389           buffer.write(code, sizeof(code));
    390           break;
    391         }
    392         case WasmInitExpr::kF32Const: {
    393           DCHECK_EQ(kAstF32, global.type);
    394           const byte code[] = {WASM_F32(global.init.val.f32_const)};
    395           buffer.write(code, sizeof(code));
    396           break;
    397         }
    398         case WasmInitExpr::kF64Const: {
    399           DCHECK_EQ(kAstF64, global.type);
    400           const byte code[] = {WASM_F64(global.init.val.f64_const)};
    401           buffer.write(code, sizeof(code));
    402           break;
    403         }
    404         case WasmInitExpr::kGlobalIndex: {
    405           const byte code[] = {kExprGetGlobal,
    406                                U32V_5(global.init.val.global_index)};
    407           buffer.write(code, sizeof(code));
    408           break;
    409         }
    410         default: {
    411           // No initializer, emit a default value.
    412           switch (global.type) {
    413             case kAstI32: {
    414               const byte code[] = {WASM_I32V_1(0)};
    415               buffer.write(code, sizeof(code));
    416               break;
    417             }
    418             case kAstI64: {
    419               const byte code[] = {WASM_I64V_1(0)};
    420               buffer.write(code, sizeof(code));
    421               break;
    422             }
    423             case kAstF32: {
    424               const byte code[] = {WASM_F32(0.0)};
    425               buffer.write(code, sizeof(code));
    426               break;
    427             }
    428             case kAstF64: {
    429               const byte code[] = {WASM_F64(0.0)};
    430               buffer.write(code, sizeof(code));
    431               break;
    432             }
    433             default:
    434               UNREACHABLE();
    435           }
    436         }
    437       }
    438       buffer.write_u8(kExprEnd);
    439     }
    440     FixupSection(buffer, start);
    441   }
    442 
    443   // == emit exports ===========================================================
    444   if (exports > 0) {
    445     size_t start = EmitSection(kExportSectionCode, buffer);
    446     buffer.write_u32v(exports);
    447     for (auto function : functions_) function->WriteExport(buffer);
    448     FixupSection(buffer, start);
    449   }
    450 
    451   // == emit start function index ==============================================
    452   if (start_function_index_ >= 0) {
    453     size_t start = EmitSection(kStartSectionCode, buffer);
    454     buffer.write_u32v(start_function_index_ +
    455                       static_cast<uint32_t>(imports_.size()));
    456     FixupSection(buffer, start);
    457   }
    458 
    459   // == emit function table elements ===========================================
    460   if (indirect_functions_.size() > 0) {
    461     size_t start = EmitSection(kElementSectionCode, buffer);
    462     buffer.write_u8(1);              // count of entries
    463     buffer.write_u8(0);              // table index
    464     buffer.write_u8(kExprI32Const);  // offset
    465     buffer.write_u32v(0);
    466     buffer.write_u8(kExprEnd);
    467     buffer.write_size(indirect_functions_.size());  // element count
    468 
    469     for (auto index : indirect_functions_) {
    470       buffer.write_u32v(index + static_cast<uint32_t>(imports_.size()));
    471     }
    472 
    473     FixupSection(buffer, start);
    474   }
    475 
    476   // == emit code ==============================================================
    477   if (functions_.size() > 0) {
    478     size_t start = EmitSection(kCodeSectionCode, buffer);
    479     buffer.write_size(functions_.size());
    480     for (auto function : functions_) {
    481       function->WriteBody(buffer);
    482     }
    483     FixupSection(buffer, start);
    484   }
    485 
    486   // == emit data segments =====================================================
    487   if (data_segments_.size() > 0) {
    488     size_t start = EmitSection(kDataSectionCode, buffer);
    489     buffer.write_size(data_segments_.size());
    490 
    491     for (auto segment : data_segments_) {
    492       buffer.write_u8(0);              // linear memory segment
    493       buffer.write_u8(kExprI32Const);  // initializer expression for dest
    494       buffer.write_u32v(segment.dest);
    495       buffer.write_u8(kExprEnd);
    496       buffer.write_u32v(static_cast<uint32_t>(segment.data.size()));
    497       buffer.write(&segment.data[0], segment.data.size());
    498     }
    499     FixupSection(buffer, start);
    500   }
    501 
    502   // == Emit names =============================================================
    503   if (has_names) {
    504     // Emit the section code.
    505     buffer.write_u8(kUnknownSectionCode);
    506     // Emit a placeholder for the length.
    507     size_t start = buffer.reserve_u32v();
    508     // Emit the section string.
    509     buffer.write_size(4);
    510     buffer.write(reinterpret_cast<const byte*>("name"), 4);
    511     // Emit the names.
    512     size_t count = functions_.size() + imports_.size();
    513     buffer.write_size(count);
    514     for (size_t i = 0; i < imports_.size(); i++) {
    515       buffer.write_u8(0);  // empty name for import
    516       buffer.write_u8(0);  // no local variables
    517     }
    518     for (auto function : functions_) {
    519       buffer.write_size(function->name_.size());
    520       if (function->name_.size() > 0) {
    521         buffer.write(reinterpret_cast<const byte*>(&function->name_[0]),
    522                      function->name_.size());
    523       }
    524       buffer.write_u8(0);
    525     }
    526     FixupSection(buffer, start);
    527   }
    528 }
    529 
    530 void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer& buffer) const {
    531   // == Emit asm.js offset table ===============================================
    532   buffer.write_size(functions_.size());
    533   // Emit the offset table per function.
    534   for (auto function : functions_) {
    535     function->WriteAsmWasmOffsetTable(buffer);
    536   }
    537 }
    538 }  // namespace wasm
    539 }  // namespace internal
    540 }  // namespace v8
    541