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
31namespace v8 {
32namespace internal {
33namespace wasm {
34
35// Emit a section code and the size as a padded varint that can be patched
36// later.
37size_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.
46void FixupSection(ZoneBuffer& buffer, size_t start) {
47  buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start -
48                                                 kPaddedVarInt32Size));
49}
50
51WasmFunctionBuilder::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
66void 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
74void 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
82void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
83  DCHECK(!locals_.has_sig());
84  locals_.set_sig(sig);
85  signature_index_ = builder_->AddSignature(sig);
86}
87
88uint32_t WasmFunctionBuilder::AddLocal(ValueType type) {
89  DCHECK(locals_.has_sig());
90  return locals_.AddLocals(1, type);
91}
92
93void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
94  EmitWithVarUint(kExprGetLocal, local_index);
95}
96
97void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
98  EmitWithVarUint(kExprSetLocal, local_index);
99}
100
101void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
102  EmitWithVarUint(kExprTeeLocal, local_index);
103}
104
105void 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
111void WasmFunctionBuilder::Emit(WasmOpcode opcode) {
112  body_.push_back(static_cast<byte>(opcode));
113}
114
115void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
116  body_.push_back(static_cast<byte>(opcode));
117  body_.push_back(immediate);
118}
119
120void 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
127void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode, int32_t immediate) {
128  body_.push_back(static_cast<byte>(opcode));
129  EmitVarInt(immediate);
130}
131
132void WasmFunctionBuilder::EmitWithVarUint(WasmOpcode opcode,
133                                          uint32_t immediate) {
134  body_.push_back(static_cast<byte>(opcode));
135  EmitVarUint(immediate);
136}
137
138void WasmFunctionBuilder::EmitI32Const(int32_t value) {
139  EmitWithVarInt(kExprI32Const, value);
140}
141
142void 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
151void WasmFunctionBuilder::ExportAs(Vector<const char> name) {
152  exported_names_.push_back(ZoneVector<char>(
153      name.start(), name.start() + name.length(), builder_->zone()));
154}
155
156void WasmFunctionBuilder::SetName(Vector<const char> name) {
157  name_.resize(name.length());
158  memcpy(name_.data(), name.start(), name.length());
159}
160
161void 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
179void 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
188void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const {
189  buffer.write_u32v(signature_index_);
190}
191
192void 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
202void 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
220void 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
237WasmModuleBuilder::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
248WasmFunctionBuilder* 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
255void 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
264bool 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
281uint32_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
293uint32_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
299void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
300                                            uint32_t direct) {
301  indirect_functions_[indirect] = direct;
302}
303
304uint32_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
310void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
311  start_function_index_ = function->func_index();
312}
313
314uint32_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
321void 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
554void 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