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