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.
EmitSection(WasmSectionCode code,ZoneBuffer & buffer)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.
FixupSection(ZoneBuffer & buffer,size_t start)44 void FixupSection(ZoneBuffer& buffer, size_t start) {
45   buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start -
46                                                  kPaddedVarInt32Size));
47 }
48 
WasmFunctionBuilder(WasmModuleBuilder * builder)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 
EmitVarInt(uint32_t val)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 
SetSignature(FunctionSig * sig)74 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
75   DCHECK(!locals_.has_sig());
76   locals_.set_sig(sig);
77   signature_index_ = builder_->AddSignature(sig);
78 }
79 
AddLocal(LocalType type)80 uint32_t WasmFunctionBuilder::AddLocal(LocalType type) {
81   DCHECK(locals_.has_sig());
82   return locals_.AddLocals(1, type);
83 }
84 
EmitGetLocal(uint32_t local_index)85 void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
86   EmitWithVarInt(kExprGetLocal, local_index);
87 }
88 
EmitSetLocal(uint32_t local_index)89 void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
90   EmitWithVarInt(kExprSetLocal, local_index);
91 }
92 
EmitTeeLocal(uint32_t local_index)93 void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
94   EmitWithVarInt(kExprTeeLocal, local_index);
95 }
96 
EmitCode(const byte * code,uint32_t code_size)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 
Emit(WasmOpcode opcode)103 void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
104   body_.push_back(static_cast<byte>(opcode));
105 }
106 
EmitWithU8(WasmOpcode opcode,const byte immediate)107 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
108   body_.push_back(static_cast<byte>(opcode));
109   body_.push_back(immediate);
110 }
111 
EmitWithU8U8(WasmOpcode opcode,const byte imm1,const byte imm2)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 
EmitWithVarInt(WasmOpcode opcode,uint32_t immediate)119 void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode,
120                                          uint32_t immediate) {
121   body_.push_back(static_cast<byte>(opcode));
122   EmitVarInt(immediate);
123 }
124 
EmitI32Const(int32_t value)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 
EmitDirectCallIndex(uint32_t index)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 
Export()144 void WasmFunctionBuilder::Export() { exported_ = true; }
145 
ExportAs(Vector<const char> name)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 
SetName(Vector<const char> name)152 void WasmFunctionBuilder::SetName(Vector<const char> name) {
153   name_.resize(name.length());
154   memcpy(name_.data(), name.start(), name.length());
155 }
156 
AddAsmWasmOffset(int asm_position)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 
WriteSignature(ZoneBuffer & buffer) const171 void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const {
172   buffer.write_u32v(signature_index_);
173 }
174 
WriteExport(ZoneBuffer & buffer) const175 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 
WriteBody(ZoneBuffer & buffer) const188 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 
WriteAsmWasmOffsetTable(ZoneBuffer & buffer) const206 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 
WasmModuleBuilder(Zone * zone)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 
AddFunction(FunctionSig * sig)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 
AddDataSegment(const byte * data,uint32_t size,uint32_t dest)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 
operator ()(FunctionSig * a,FunctionSig * b) const245 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 
AddSignature(FunctionSig * sig)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 
AddIndirectFunction(uint32_t index)274 void WasmModuleBuilder::AddIndirectFunction(uint32_t index) {
275   indirect_functions_.push_back(index);
276 }
277 
AddImport(const char * name,int name_length,FunctionSig * sig)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 
MarkStartFunction(WasmFunctionBuilder * function)284 void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
285   start_function_index_ = function->func_index();
286 }
287 
AddGlobal(LocalType type,bool exported,bool mutability,const WasmInitExpr & init)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 
WriteTo(ZoneBuffer & buffer) const295 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 
WriteAsmJsOffsetTable(ZoneBuffer & buffer) const530 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