• 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/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.
EmitSection(WasmSectionCode code,ZoneBuffer & buffer)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.
FixupSection(ZoneBuffer & buffer,size_t start)46 void FixupSection(ZoneBuffer& buffer, size_t start) {
47   buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start -
48                                                  kPaddedVarInt32Size));
49 }
50 
WasmFunctionBuilder(WasmModuleBuilder * builder)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 
EmitVarInt(int32_t val)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 
EmitVarUint(uint32_t val)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 
SetSignature(FunctionSig * sig)82 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
83   DCHECK(!locals_.has_sig());
84   locals_.set_sig(sig);
85   signature_index_ = builder_->AddSignature(sig);
86 }
87 
AddLocal(ValueType type)88 uint32_t WasmFunctionBuilder::AddLocal(ValueType type) {
89   DCHECK(locals_.has_sig());
90   return locals_.AddLocals(1, type);
91 }
92 
EmitGetLocal(uint32_t local_index)93 void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
94   EmitWithVarUint(kExprGetLocal, local_index);
95 }
96 
EmitSetLocal(uint32_t local_index)97 void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
98   EmitWithVarUint(kExprSetLocal, local_index);
99 }
100 
EmitTeeLocal(uint32_t local_index)101 void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
102   EmitWithVarUint(kExprTeeLocal, local_index);
103 }
104 
EmitCode(const byte * code,uint32_t code_size)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 
Emit(WasmOpcode opcode)111 void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
112   body_.push_back(static_cast<byte>(opcode));
113 }
114 
EmitWithU8(WasmOpcode opcode,const byte immediate)115 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
116   body_.push_back(static_cast<byte>(opcode));
117   body_.push_back(immediate);
118 }
119 
EmitWithU8U8(WasmOpcode opcode,const byte imm1,const byte imm2)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 
EmitWithVarInt(WasmOpcode opcode,int32_t immediate)127 void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode, int32_t immediate) {
128   body_.push_back(static_cast<byte>(opcode));
129   EmitVarInt(immediate);
130 }
131 
EmitWithVarUint(WasmOpcode opcode,uint32_t immediate)132 void WasmFunctionBuilder::EmitWithVarUint(WasmOpcode opcode,
133                                           uint32_t immediate) {
134   body_.push_back(static_cast<byte>(opcode));
135   EmitVarUint(immediate);
136 }
137 
EmitI32Const(int32_t value)138 void WasmFunctionBuilder::EmitI32Const(int32_t value) {
139   EmitWithVarInt(kExprI32Const, value);
140 }
141 
EmitDirectCallIndex(uint32_t index)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 
ExportAs(Vector<const char> name)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 
SetName(Vector<const char> name)156 void WasmFunctionBuilder::SetName(Vector<const char> name) {
157   name_.resize(name.length());
158   memcpy(name_.data(), name.start(), name.length());
159 }
160 
AddAsmWasmOffset(int call_position,int to_number_position)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 
SetAsmFunctionStartPosition(int position)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 
WriteSignature(ZoneBuffer & buffer) const188 void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const {
189   buffer.write_u32v(signature_index_);
190 }
191 
WriteExports(ZoneBuffer & buffer) const192 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 
WriteBody(ZoneBuffer & buffer) const202 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 
WriteAsmWasmOffsetTable(ZoneBuffer & buffer) const220 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 
WasmModuleBuilder(Zone * zone)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 
AddFunction(FunctionSig * sig)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 
AddDataSegment(const byte * data,uint32_t size,uint32_t dest)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 
operator ()(FunctionSig * a,FunctionSig * b) const264 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 
AddSignature(FunctionSig * sig)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 
AllocateIndirectFunctions(uint32_t count)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 
SetIndirectFunction(uint32_t indirect,uint32_t direct)299 void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
300                                             uint32_t direct) {
301   indirect_functions_[indirect] = direct;
302 }
303 
AddImport(const char * name,int name_length,FunctionSig * sig)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 
MarkStartFunction(WasmFunctionBuilder * function)310 void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
311   start_function_index_ = function->func_index();
312 }
313 
AddGlobal(ValueType type,bool exported,bool mutability,const WasmInitExpr & init)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 
WriteTo(ZoneBuffer & buffer) const321 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 
WriteAsmJsOffsetTable(ZoneBuffer & buffer) const554 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