• 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/wasm/wasm-module-builder.h"
6 
7 #include "src/base/memory.h"
8 #include "src/codegen/signature.h"
9 #include "src/handles/handles.h"
10 #include "src/init/v8.h"
11 #include "src/objects/objects-inl.h"
12 #include "src/wasm/function-body-decoder.h"
13 #include "src/wasm/leb-helper.h"
14 #include "src/wasm/wasm-constants.h"
15 #include "src/wasm/wasm-module.h"
16 #include "src/wasm/wasm-opcodes.h"
17 #include "src/zone/zone-containers.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace wasm {
22 
23 namespace {
24 
25 // Emit a section code and the size as a padded varint that can be patched
26 // later.
EmitSection(SectionCode code,ZoneBuffer * buffer)27 size_t EmitSection(SectionCode code, ZoneBuffer* buffer) {
28   // Emit the section code.
29   buffer->write_u8(code);
30 
31   // Emit a placeholder for the length.
32   return buffer->reserve_u32v();
33 }
34 
35 // Patch the size of a section after it's finished.
FixupSection(ZoneBuffer * buffer,size_t start)36 void FixupSection(ZoneBuffer* buffer, size_t start) {
37   buffer->patch_u32v(start, static_cast<uint32_t>(buffer->offset() - start -
38                                                   kPaddedVarInt32Size));
39 }
40 
41 }  // namespace
42 
WasmFunctionBuilder(WasmModuleBuilder * builder)43 WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder)
44     : builder_(builder),
45       locals_(builder->zone()),
46       signature_index_(0),
47       func_index_(static_cast<uint32_t>(builder->functions_.size())),
48       body_(builder->zone(), 256),
49       i32_temps_(builder->zone()),
50       i64_temps_(builder->zone()),
51       f32_temps_(builder->zone()),
52       f64_temps_(builder->zone()),
53       direct_calls_(builder->zone()),
54       asm_offsets_(builder->zone(), 8) {}
55 
EmitByte(byte val)56 void WasmFunctionBuilder::EmitByte(byte val) { body_.write_u8(val); }
57 
EmitI32V(int32_t val)58 void WasmFunctionBuilder::EmitI32V(int32_t val) { body_.write_i32v(val); }
59 
EmitU32V(uint32_t val)60 void WasmFunctionBuilder::EmitU32V(uint32_t val) { body_.write_u32v(val); }
61 
SetSignature(FunctionSig * sig)62 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
63   DCHECK(!locals_.has_sig());
64   locals_.set_sig(sig);
65   signature_index_ = builder_->AddSignature(sig);
66 }
67 
AddLocal(ValueType type)68 uint32_t WasmFunctionBuilder::AddLocal(ValueType type) {
69   DCHECK(locals_.has_sig());
70   return locals_.AddLocals(1, type);
71 }
72 
EmitGetLocal(uint32_t local_index)73 void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
74   EmitWithU32V(kExprLocalGet, local_index);
75 }
76 
EmitSetLocal(uint32_t local_index)77 void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
78   EmitWithU32V(kExprLocalSet, local_index);
79 }
80 
EmitTeeLocal(uint32_t local_index)81 void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
82   EmitWithU32V(kExprLocalTee, local_index);
83 }
84 
EmitCode(const byte * code,uint32_t code_size)85 void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
86   body_.write(code, code_size);
87 }
88 
Emit(WasmOpcode opcode)89 void WasmFunctionBuilder::Emit(WasmOpcode opcode) { body_.write_u8(opcode); }
90 
EmitWithPrefix(WasmOpcode opcode)91 void WasmFunctionBuilder::EmitWithPrefix(WasmOpcode opcode) {
92   DCHECK_NE(0, opcode & 0xff00);
93   body_.write_u8(opcode >> 8);
94   if ((opcode >> 8) == WasmOpcode::kSimdPrefix) {
95     // SIMD opcodes are LEB encoded
96     body_.write_u32v(opcode & 0xff);
97   } else {
98     body_.write_u8(opcode);
99   }
100 }
101 
EmitWithU8(WasmOpcode opcode,const byte immediate)102 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
103   body_.write_u8(opcode);
104   body_.write_u8(immediate);
105 }
106 
EmitWithU8U8(WasmOpcode opcode,const byte imm1,const byte imm2)107 void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode, const byte imm1,
108                                        const byte imm2) {
109   body_.write_u8(opcode);
110   body_.write_u8(imm1);
111   body_.write_u8(imm2);
112 }
113 
EmitWithI32V(WasmOpcode opcode,int32_t immediate)114 void WasmFunctionBuilder::EmitWithI32V(WasmOpcode opcode, int32_t immediate) {
115   body_.write_u8(opcode);
116   body_.write_i32v(immediate);
117 }
118 
EmitWithU32V(WasmOpcode opcode,uint32_t immediate)119 void WasmFunctionBuilder::EmitWithU32V(WasmOpcode opcode, uint32_t immediate) {
120   body_.write_u8(opcode);
121   body_.write_u32v(immediate);
122 }
123 
EmitI32Const(int32_t value)124 void WasmFunctionBuilder::EmitI32Const(int32_t value) {
125   EmitWithI32V(kExprI32Const, value);
126 }
127 
EmitI64Const(int64_t value)128 void WasmFunctionBuilder::EmitI64Const(int64_t value) {
129   body_.write_u8(kExprI64Const);
130   body_.write_i64v(value);
131 }
132 
EmitF32Const(float value)133 void WasmFunctionBuilder::EmitF32Const(float value) {
134   body_.write_u8(kExprF32Const);
135   body_.write_f32(value);
136 }
137 
EmitF64Const(double value)138 void WasmFunctionBuilder::EmitF64Const(double value) {
139   body_.write_u8(kExprF64Const);
140   body_.write_f64(value);
141 }
142 
EmitDirectCallIndex(uint32_t index)143 void WasmFunctionBuilder::EmitDirectCallIndex(uint32_t index) {
144   DirectCallIndex call;
145   call.offset = body_.size();
146   call.direct_index = index;
147   direct_calls_.push_back(call);
148   byte placeholder_bytes[kMaxVarInt32Size] = {0};
149   EmitCode(placeholder_bytes, arraysize(placeholder_bytes));
150 }
151 
SetName(Vector<const char> name)152 void WasmFunctionBuilder::SetName(Vector<const char> name) { name_ = name; }
153 
AddAsmWasmOffset(size_t call_position,size_t to_number_position)154 void WasmFunctionBuilder::AddAsmWasmOffset(size_t call_position,
155                                            size_t to_number_position) {
156   // We only want to emit one mapping per byte offset.
157   DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_);
158 
159   DCHECK_LE(body_.size(), kMaxUInt32);
160   uint32_t byte_offset = static_cast<uint32_t>(body_.size());
161   asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_);
162   last_asm_byte_offset_ = byte_offset;
163 
164   DCHECK_GE(std::numeric_limits<uint32_t>::max(), call_position);
165   uint32_t call_position_u32 = static_cast<uint32_t>(call_position);
166   asm_offsets_.write_i32v(call_position_u32 - last_asm_source_position_);
167 
168   DCHECK_GE(std::numeric_limits<uint32_t>::max(), to_number_position);
169   uint32_t to_number_position_u32 = static_cast<uint32_t>(to_number_position);
170   asm_offsets_.write_i32v(to_number_position_u32 - call_position_u32);
171   last_asm_source_position_ = to_number_position_u32;
172 }
173 
SetAsmFunctionStartPosition(size_t function_position)174 void WasmFunctionBuilder::SetAsmFunctionStartPosition(
175     size_t function_position) {
176   DCHECK_EQ(0, asm_func_start_source_position_);
177   DCHECK_GE(std::numeric_limits<uint32_t>::max(), function_position);
178   uint32_t function_position_u32 = static_cast<uint32_t>(function_position);
179   // Must be called before emitting any asm.js source position.
180   DCHECK_EQ(0, asm_offsets_.size());
181   asm_func_start_source_position_ = function_position_u32;
182   last_asm_source_position_ = function_position_u32;
183 }
184 
SetCompilationHint(WasmCompilationHintStrategy strategy,WasmCompilationHintTier baseline,WasmCompilationHintTier top_tier)185 void WasmFunctionBuilder::SetCompilationHint(
186     WasmCompilationHintStrategy strategy, WasmCompilationHintTier baseline,
187     WasmCompilationHintTier top_tier) {
188   uint8_t hint_byte = static_cast<uint8_t>(strategy) |
189                       static_cast<uint8_t>(baseline) << 2 |
190                       static_cast<uint8_t>(top_tier) << 4;
191   DCHECK_NE(hint_byte, kNoCompilationHint);
192   hint_ = hint_byte;
193 }
194 
DeleteCodeAfter(size_t position)195 void WasmFunctionBuilder::DeleteCodeAfter(size_t position) {
196   DCHECK_LE(position, body_.size());
197   body_.Truncate(position);
198 }
199 
WriteSignature(ZoneBuffer * buffer) const200 void WasmFunctionBuilder::WriteSignature(ZoneBuffer* buffer) const {
201   buffer->write_u32v(signature_index_);
202 }
203 
WriteBody(ZoneBuffer * buffer) const204 void WasmFunctionBuilder::WriteBody(ZoneBuffer* buffer) const {
205   size_t locals_size = locals_.Size();
206   buffer->write_size(locals_size + body_.size());
207   buffer->EnsureSpace(locals_size);
208   byte** ptr = buffer->pos_ptr();
209   locals_.Emit(*ptr);
210   (*ptr) += locals_size;  // UGLY: manual bump of position pointer
211   if (body_.size() > 0) {
212     size_t base = buffer->offset();
213     buffer->write(body_.begin(), body_.size());
214     for (DirectCallIndex call : direct_calls_) {
215       buffer->patch_u32v(
216           base + call.offset,
217           call.direct_index +
218               static_cast<uint32_t>(builder_->function_imports_.size()));
219     }
220   }
221 }
222 
WriteAsmWasmOffsetTable(ZoneBuffer * buffer) const223 void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer* buffer) const {
224   if (asm_func_start_source_position_ == 0 && asm_offsets_.size() == 0) {
225     buffer->write_size(0);
226     return;
227   }
228   size_t locals_enc_size = LEBHelper::sizeof_u32v(locals_.Size());
229   size_t func_start_size =
230       LEBHelper::sizeof_u32v(asm_func_start_source_position_);
231   buffer->write_size(asm_offsets_.size() + locals_enc_size + func_start_size);
232   // Offset of the recorded byte offsets.
233   DCHECK_GE(kMaxUInt32, locals_.Size());
234   buffer->write_u32v(static_cast<uint32_t>(locals_.Size()));
235   // Start position of the function.
236   buffer->write_u32v(asm_func_start_source_position_);
237   buffer->write(asm_offsets_.begin(), asm_offsets_.size());
238 }
239 
WasmModuleBuilder(Zone * zone)240 WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
241     : zone_(zone),
242       types_(zone),
243       function_imports_(zone),
244       global_imports_(zone),
245       exports_(zone),
246       functions_(zone),
247       tables_(zone),
248       data_segments_(zone),
249       indirect_functions_(zone),
250       globals_(zone),
251       signature_map_(zone),
252       start_function_index_(-1),
253       min_memory_size_(16),
254       max_memory_size_(0),
255       has_max_memory_size_(false),
256       has_shared_memory_(false) {}
257 
AddFunction(FunctionSig * sig)258 WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) {
259   functions_.push_back(zone_->New<WasmFunctionBuilder>(this));
260   // Add the signature if one was provided here.
261   if (sig) functions_.back()->SetSignature(sig);
262   return functions_.back();
263 }
264 
AddDataSegment(const byte * data,uint32_t size,uint32_t dest)265 void WasmModuleBuilder::AddDataSegment(const byte* data, uint32_t size,
266                                        uint32_t dest) {
267   data_segments_.push_back({ZoneVector<byte>(zone()), dest});
268   ZoneVector<byte>& vec = data_segments_.back().data;
269   for (uint32_t i = 0; i < size; i++) {
270     vec.push_back(data[i]);
271   }
272 }
273 
AddSignature(FunctionSig * sig)274 uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
275   auto sig_entry = signature_map_.find(*sig);
276   if (sig_entry != signature_map_.end()) return sig_entry->second;
277   uint32_t index = static_cast<uint32_t>(types_.size());
278   signature_map_.emplace(*sig, index);
279   types_.push_back(Type(sig));
280   return index;
281 }
282 
AddStructType(StructType * type)283 uint32_t WasmModuleBuilder::AddStructType(StructType* type) {
284   uint32_t index = static_cast<uint32_t>(types_.size());
285   types_.push_back(Type(type));
286   return index;
287 }
288 
AddArrayType(ArrayType * type)289 uint32_t WasmModuleBuilder::AddArrayType(ArrayType* type) {
290   uint32_t index = static_cast<uint32_t>(types_.size());
291   types_.push_back(Type(type));
292   return index;
293 }
294 
AllocateIndirectFunctions(uint32_t count)295 uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
296   DCHECK(allocating_indirect_functions_allowed_);
297   uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
298   DCHECK_GE(FLAG_wasm_max_table_size, index);
299   if (count > FLAG_wasm_max_table_size - index) {
300     return std::numeric_limits<uint32_t>::max();
301   }
302   uint32_t new_size = static_cast<uint32_t>(indirect_functions_.size()) + count;
303   DCHECK(max_table_size_ == 0 || new_size <= max_table_size_);
304   indirect_functions_.resize(new_size, WasmElemSegment::kNullIndex);
305   uint32_t max = max_table_size_ > 0 ? max_table_size_ : new_size;
306   if (tables_.empty()) {
307     // This cannot use {AddTable} because that would flip the
308     // {allocating_indirect_functions_allowed_} flag.
309     tables_.push_back({kWasmFuncRef, new_size, max, true});
310   } else {
311     // There can only be the indirect function table so far, otherwise the
312     // {allocating_indirect_functions_allowed_} flag would have been false.
313     DCHECK_EQ(1u, tables_.size());
314     DCHECK_EQ(kWasmFuncRef, tables_[0].type);
315     DCHECK(tables_[0].has_maximum);
316     tables_[0].min_size = new_size;
317     tables_[0].max_size = max;
318   }
319   return index;
320 }
321 
SetIndirectFunction(uint32_t indirect,uint32_t direct)322 void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
323                                             uint32_t direct) {
324   indirect_functions_[indirect] = direct;
325 }
326 
SetMaxTableSize(uint32_t max)327 void WasmModuleBuilder::SetMaxTableSize(uint32_t max) {
328   DCHECK_GE(FLAG_wasm_max_table_size, max);
329   DCHECK_GE(max, indirect_functions_.size());
330   max_table_size_ = max;
331   DCHECK(allocating_indirect_functions_allowed_);
332   if (!tables_.empty()) {
333     tables_[0].max_size = max;
334   }
335 }
336 
AddTable(ValueType type,uint32_t min_size)337 uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size) {
338 #if DEBUG
339   allocating_indirect_functions_allowed_ = false;
340 #endif
341   tables_.push_back({type, min_size, 0, false});
342   return static_cast<uint32_t>(tables_.size() - 1);
343 }
344 
AddTable(ValueType type,uint32_t min_size,uint32_t max_size)345 uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size,
346                                      uint32_t max_size) {
347 #if DEBUG
348   allocating_indirect_functions_allowed_ = false;
349 #endif
350   tables_.push_back({type, min_size, max_size, true});
351   return static_cast<uint32_t>(tables_.size() - 1);
352 }
353 
AddImport(Vector<const char> name,FunctionSig * sig,Vector<const char> module)354 uint32_t WasmModuleBuilder::AddImport(Vector<const char> name, FunctionSig* sig,
355                                       Vector<const char> module) {
356   DCHECK(adding_imports_allowed_);
357   function_imports_.push_back({module, name, AddSignature(sig)});
358   return static_cast<uint32_t>(function_imports_.size() - 1);
359 }
360 
AddGlobalImport(Vector<const char> name,ValueType type,bool mutability,Vector<const char> module)361 uint32_t WasmModuleBuilder::AddGlobalImport(Vector<const char> name,
362                                             ValueType type, bool mutability,
363                                             Vector<const char> module) {
364   global_imports_.push_back({module, name, type.value_type_code(), mutability});
365   return static_cast<uint32_t>(global_imports_.size() - 1);
366 }
367 
MarkStartFunction(WasmFunctionBuilder * function)368 void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
369   start_function_index_ = function->func_index();
370 }
371 
AddExport(Vector<const char> name,ImportExportKindCode kind,uint32_t index)372 void WasmModuleBuilder::AddExport(Vector<const char> name,
373                                   ImportExportKindCode kind, uint32_t index) {
374   DCHECK_LE(index, std::numeric_limits<int>::max());
375   exports_.push_back({name, kind, static_cast<int>(index)});
376 }
377 
AddExportedGlobal(ValueType type,bool mutability,WasmInitExpr init,Vector<const char> name)378 uint32_t WasmModuleBuilder::AddExportedGlobal(ValueType type, bool mutability,
379                                               WasmInitExpr init,
380                                               Vector<const char> name) {
381   uint32_t index = AddGlobal(type, mutability, std::move(init));
382   AddExport(name, kExternalGlobal, index);
383   return index;
384 }
385 
ExportImportedFunction(Vector<const char> name,int import_index)386 void WasmModuleBuilder::ExportImportedFunction(Vector<const char> name,
387                                                int import_index) {
388 #if DEBUG
389   // The size of function_imports_ must not change any more.
390   adding_imports_allowed_ = false;
391 #endif
392   exports_.push_back(
393       {name, kExternalFunction,
394        import_index - static_cast<int>(function_imports_.size())});
395 }
396 
AddGlobal(ValueType type,bool mutability,WasmInitExpr init)397 uint32_t WasmModuleBuilder::AddGlobal(ValueType type, bool mutability,
398                                       WasmInitExpr init) {
399   globals_.push_back({type, mutability, std::move(init)});
400   return static_cast<uint32_t>(globals_.size() - 1);
401 }
402 
SetMinMemorySize(uint32_t value)403 void WasmModuleBuilder::SetMinMemorySize(uint32_t value) {
404   min_memory_size_ = value;
405 }
406 
SetMaxMemorySize(uint32_t value)407 void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) {
408   has_max_memory_size_ = true;
409   max_memory_size_ = value;
410 }
411 
SetHasSharedMemory()412 void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
413 
414 namespace {
WriteValueType(ZoneBuffer * buffer,const ValueType & type)415 void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
416   buffer->write_u8(type.value_type_code());
417   if (type.has_depth()) {
418     buffer->write_u32v(type.depth());
419   }
420   if (type.encoding_needs_heap_type()) {
421     buffer->write_i32v(type.heap_type().code());
422   }
423 }
424 
WriteGlobalInitializer(ZoneBuffer * buffer,const WasmInitExpr & init,ValueType type)425 void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
426                             ValueType type) {
427   switch (init.kind()) {
428     case WasmInitExpr::kI32Const:
429       buffer->write_u8(kExprI32Const);
430       buffer->write_i32v(init.immediate().i32_const);
431       break;
432     case WasmInitExpr::kI64Const:
433       buffer->write_u8(kExprI64Const);
434       buffer->write_i64v(init.immediate().i64_const);
435       break;
436     case WasmInitExpr::kF32Const:
437       buffer->write_u8(kExprF32Const);
438       buffer->write_f32(init.immediate().f32_const);
439       break;
440     case WasmInitExpr::kF64Const:
441       buffer->write_u8(kExprF64Const);
442       buffer->write_f64(init.immediate().f64_const);
443       break;
444     case WasmInitExpr::kS128Const:
445       buffer->write_u8(kSimdPrefix);
446       buffer->write_u8(kExprS128Const & 0xFF);
447       buffer->write(init.immediate().s128_const.data(), kSimd128Size);
448       break;
449     case WasmInitExpr::kGlobalGet:
450       buffer->write_u8(kExprGlobalGet);
451       buffer->write_u32v(init.immediate().index);
452       break;
453     case WasmInitExpr::kRefNullConst:
454       buffer->write_u8(kExprRefNull);
455       buffer->write_i32v(HeapType(init.immediate().heap_type).code());
456       break;
457     case WasmInitExpr::kRefFuncConst:
458       buffer->write_u8(kExprRefFunc);
459       buffer->write_u32v(init.immediate().index);
460       break;
461     case WasmInitExpr::kNone: {
462       // No initializer, emit a default value.
463       switch (type.kind()) {
464         case ValueType::kI32:
465           buffer->write_u8(kExprI32Const);
466           // LEB encoding of 0.
467           buffer->write_u8(0);
468           break;
469         case ValueType::kI64:
470           buffer->write_u8(kExprI64Const);
471           // LEB encoding of 0.
472           buffer->write_u8(0);
473           break;
474         case ValueType::kF32:
475           buffer->write_u8(kExprF32Const);
476           buffer->write_f32(0.f);
477           break;
478         case ValueType::kF64:
479           buffer->write_u8(kExprF64Const);
480           buffer->write_f64(0.);
481           break;
482         case ValueType::kOptRef:
483           buffer->write_u8(kExprRefNull);
484           break;
485         case ValueType::kI8:
486         case ValueType::kI16:
487         case ValueType::kStmt:
488         case ValueType::kS128:
489         case ValueType::kBottom:
490         case ValueType::kRef:
491         case ValueType::kRtt:
492           UNREACHABLE();
493       }
494       break;
495     }
496     case WasmInitExpr::kRttCanon:
497       STATIC_ASSERT((kExprRttCanon >> 8) == kGCPrefix);
498       buffer->write_u8(kGCPrefix);
499       buffer->write_u8(static_cast<uint8_t>(kExprRttCanon));
500       buffer->write_i32v(HeapType(init.immediate().heap_type).code());
501       break;
502     case WasmInitExpr::kRttSub:
503       // TODO(7748): If immediates for rtts remain in the standard, adapt this
504       // to emit them.
505       STATIC_ASSERT((kExprRttSub >> 8) == kGCPrefix);
506       buffer->write_u8(kGCPrefix);
507       buffer->write_u8(static_cast<uint8_t>(kExprRttSub));
508       buffer->write_i32v(HeapType(init.immediate().heap_type).code());
509       WriteGlobalInitializer(buffer, *init.operand(), kWasmBottom);
510       break;
511   }
512 }
513 
514 }  // namespace
515 
WriteTo(ZoneBuffer * buffer) const516 void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
517   // == Emit magic =============================================================
518   buffer->write_u32(kWasmMagic);
519   buffer->write_u32(kWasmVersion);
520 
521   // == Emit types =============================================================
522   if (types_.size() > 0) {
523     size_t start = EmitSection(kTypeSectionCode, buffer);
524     buffer->write_size(types_.size());
525 
526     for (const Type& type : types_) {
527       switch (type.kind) {
528         case Type::kFunctionSig: {
529           FunctionSig* sig = type.sig;
530           buffer->write_u8(kWasmFunctionTypeCode);
531           buffer->write_size(sig->parameter_count());
532           for (auto param : sig->parameters()) {
533             WriteValueType(buffer, param);
534           }
535           buffer->write_size(sig->return_count());
536           for (auto ret : sig->returns()) {
537             WriteValueType(buffer, ret);
538           }
539           break;
540         }
541         case Type::kStructType: {
542           StructType* struct_type = type.struct_type;
543           buffer->write_u8(kWasmStructTypeCode);
544           buffer->write_size(struct_type->field_count());
545           for (uint32_t i = 0; i < struct_type->field_count(); i++) {
546             WriteValueType(buffer, struct_type->field(i));
547             buffer->write_u8(struct_type->mutability(i) ? 1 : 0);
548           }
549           break;
550         }
551         case Type::kArrayType: {
552           ArrayType* array_type = type.array_type;
553           buffer->write_u8(kWasmArrayTypeCode);
554           WriteValueType(buffer, array_type->element_type());
555           buffer->write_u8(array_type->mutability() ? 1 : 0);
556           break;
557         }
558       }
559     }
560     FixupSection(buffer, start);
561   }
562 
563   // == Emit imports ===========================================================
564   if (global_imports_.size() + function_imports_.size() > 0) {
565     size_t start = EmitSection(kImportSectionCode, buffer);
566     buffer->write_size(global_imports_.size() + function_imports_.size());
567     for (auto import : global_imports_) {
568       buffer->write_string(import.module);  // module name
569       buffer->write_string(import.name);    // field name
570       buffer->write_u8(kExternalGlobal);
571       buffer->write_u8(import.type_code);
572       buffer->write_u8(import.mutability ? 1 : 0);
573     }
574     for (auto import : function_imports_) {
575       buffer->write_string(import.module);  // module name
576       buffer->write_string(import.name);    // field name
577       buffer->write_u8(kExternalFunction);
578       buffer->write_u32v(import.sig_index);
579     }
580     FixupSection(buffer, start);
581   }
582 
583   // == Emit function signatures ===============================================
584   uint32_t num_function_names = 0;
585   if (functions_.size() > 0) {
586     size_t start = EmitSection(kFunctionSectionCode, buffer);
587     buffer->write_size(functions_.size());
588     for (auto* function : functions_) {
589       function->WriteSignature(buffer);
590       if (!function->name_.empty()) ++num_function_names;
591     }
592     FixupSection(buffer, start);
593   }
594 
595   // == Emit tables ============================================================
596   if (tables_.size() > 0) {
597     size_t start = EmitSection(kTableSectionCode, buffer);
598     buffer->write_size(tables_.size());
599     for (const WasmTable& table : tables_) {
600       WriteValueType(buffer, table.type);
601       buffer->write_u8(table.has_maximum ? kWithMaximum : kNoMaximum);
602       buffer->write_size(table.min_size);
603       if (table.has_maximum) buffer->write_size(table.max_size);
604     }
605     FixupSection(buffer, start);
606   }
607 
608   // == Emit memory declaration ================================================
609   {
610     size_t start = EmitSection(kMemorySectionCode, buffer);
611     buffer->write_u8(1);  // memory count
612     if (has_shared_memory_) {
613       buffer->write_u8(has_max_memory_size_ ? kSharedWithMaximum
614                                             : kSharedNoMaximum);
615     } else {
616       buffer->write_u8(has_max_memory_size_ ? kWithMaximum : kNoMaximum);
617     }
618     buffer->write_u32v(min_memory_size_);
619     if (has_max_memory_size_) {
620       buffer->write_u32v(max_memory_size_);
621     }
622     FixupSection(buffer, start);
623   }
624 
625   // == Emit globals ===========================================================
626   if (globals_.size() > 0) {
627     size_t start = EmitSection(kGlobalSectionCode, buffer);
628     buffer->write_size(globals_.size());
629 
630     for (const WasmGlobal& global : globals_) {
631       WriteValueType(buffer, global.type);
632       buffer->write_u8(global.mutability ? 1 : 0);
633       WriteGlobalInitializer(buffer, global.init, global.type);
634       buffer->write_u8(kExprEnd);
635     }
636     FixupSection(buffer, start);
637   }
638 
639   // == emit exports ===========================================================
640   if (exports_.size() > 0) {
641     size_t start = EmitSection(kExportSectionCode, buffer);
642     buffer->write_size(exports_.size());
643     for (auto ex : exports_) {
644       buffer->write_string(ex.name);
645       buffer->write_u8(ex.kind);
646       switch (ex.kind) {
647         case kExternalFunction:
648           buffer->write_size(ex.index + function_imports_.size());
649           break;
650         case kExternalGlobal:
651           buffer->write_size(ex.index + global_imports_.size());
652           break;
653         case kExternalMemory:
654         case kExternalTable:
655           // The WasmModuleBuilder doesn't support importing tables or memories
656           // yet, so there is no index offset to add.
657           buffer->write_size(ex.index);
658           break;
659         case kExternalException:
660           UNREACHABLE();
661       }
662     }
663     FixupSection(buffer, start);
664   }
665 
666   // == emit start function index ==============================================
667   if (start_function_index_ >= 0) {
668     size_t start = EmitSection(kStartSectionCode, buffer);
669     buffer->write_size(start_function_index_ + function_imports_.size());
670     FixupSection(buffer, start);
671   }
672 
673   // == emit function table elements ===========================================
674   if (indirect_functions_.size() > 0) {
675     size_t start = EmitSection(kElementSectionCode, buffer);
676     buffer->write_u8(1);              // count of entries
677     buffer->write_u8(0);              // table index
678     uint32_t first_element = 0;
679     while (first_element < indirect_functions_.size() &&
680            indirect_functions_[first_element] == WasmElemSegment::kNullIndex) {
681       first_element++;
682     }
683     uint32_t last_element =
684         static_cast<uint32_t>(indirect_functions_.size() - 1);
685     while (last_element >= first_element &&
686            indirect_functions_[last_element] == WasmElemSegment::kNullIndex) {
687       last_element--;
688     }
689     buffer->write_u8(kExprI32Const);  // offset
690     buffer->write_u32v(first_element);
691     buffer->write_u8(kExprEnd);
692     uint32_t element_count = last_element - first_element + 1;
693     buffer->write_size(element_count);
694     for (uint32_t i = first_element; i <= last_element; i++) {
695       buffer->write_size(indirect_functions_[i] + function_imports_.size());
696     }
697 
698     FixupSection(buffer, start);
699   }
700 
701   // == emit compilation hints section =========================================
702   bool emit_compilation_hints = false;
703   for (auto* fn : functions_) {
704     if (fn->hint_ != kNoCompilationHint) {
705       emit_compilation_hints = true;
706       break;
707     }
708   }
709   if (emit_compilation_hints) {
710     // Emit the section code.
711     buffer->write_u8(kUnknownSectionCode);
712     // Emit a placeholder for section length.
713     size_t start = buffer->reserve_u32v();
714     // Emit custom section name.
715     buffer->write_string(CStrVector("compilationHints"));
716     // Emit hint count.
717     buffer->write_size(functions_.size());
718     // Emit hint bytes.
719     for (auto* fn : functions_) {
720       uint8_t hint_byte =
721           fn->hint_ != kNoCompilationHint ? fn->hint_ : kDefaultCompilationHint;
722       buffer->write_u8(hint_byte);
723     }
724     FixupSection(buffer, start);
725   }
726 
727   // == emit code ==============================================================
728   if (functions_.size() > 0) {
729     size_t start = EmitSection(kCodeSectionCode, buffer);
730     buffer->write_size(functions_.size());
731     for (auto* function : functions_) {
732       function->WriteBody(buffer);
733     }
734     FixupSection(buffer, start);
735   }
736 
737   // == emit data segments =====================================================
738   if (data_segments_.size() > 0) {
739     size_t start = EmitSection(kDataSectionCode, buffer);
740     buffer->write_size(data_segments_.size());
741 
742     for (auto segment : data_segments_) {
743       buffer->write_u8(0);              // linear memory segment
744       buffer->write_u8(kExprI32Const);  // initializer expression for dest
745       buffer->write_u32v(segment.dest);
746       buffer->write_u8(kExprEnd);
747       buffer->write_u32v(static_cast<uint32_t>(segment.data.size()));
748       buffer->write(&segment.data[0], segment.data.size());
749     }
750     FixupSection(buffer, start);
751   }
752 
753   // == Emit names =============================================================
754   if (num_function_names > 0 || !function_imports_.empty()) {
755     // Emit the section code.
756     buffer->write_u8(kUnknownSectionCode);
757     // Emit a placeholder for the length.
758     size_t start = buffer->reserve_u32v();
759     // Emit the section string.
760     buffer->write_string(CStrVector("name"));
761     // Emit a subsection for the function names.
762     buffer->write_u8(NameSectionKindCode::kFunction);
763     // Emit a placeholder for the subsection length.
764     size_t functions_start = buffer->reserve_u32v();
765     // Emit the function names.
766     // Imports are always named.
767     uint32_t num_imports = static_cast<uint32_t>(function_imports_.size());
768     buffer->write_size(num_imports + num_function_names);
769     uint32_t function_index = 0;
770     for (; function_index < num_imports; ++function_index) {
771       const WasmFunctionImport* import = &function_imports_[function_index];
772       DCHECK(!import->name.empty());
773       buffer->write_u32v(function_index);
774       buffer->write_string(import->name);
775     }
776     if (num_function_names > 0) {
777       for (auto* function : functions_) {
778         DCHECK_EQ(function_index,
779                   function->func_index() + function_imports_.size());
780         if (!function->name_.empty()) {
781           buffer->write_u32v(function_index);
782           buffer->write_string(function->name_);
783         }
784         ++function_index;
785       }
786     }
787     FixupSection(buffer, functions_start);
788     FixupSection(buffer, start);
789   }
790 }
791 
WriteAsmJsOffsetTable(ZoneBuffer * buffer) const792 void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer* buffer) const {
793   // == Emit asm.js offset table ===============================================
794   buffer->write_size(functions_.size());
795   // Emit the offset table per function.
796   for (auto* function : functions_) {
797     function->WriteAsmWasmOffsetTable(buffer);
798   }
799 }
800 }  // namespace wasm
801 }  // namespace internal
802 }  // namespace v8
803