wasm-module-builder.cc 27.7 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/wasm/wasm-module-builder.h"
6

7 8
#include "src/base/memory.h"
#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 16
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
17
#include "src/zone/zone-containers.h"
18 19 20 21 22

namespace v8 {
namespace internal {
namespace wasm {

23 24
namespace {

25
// Emit a section code and the size as a padded varint that can be patched
26
// later.
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.
36 37 38
void FixupSection(ZoneBuffer* buffer, size_t start) {
  buffer->patch_u32v(start, static_cast<uint32_t>(buffer->offset() - start -
                                                  kPaddedVarInt32Size));
39
}
40

41 42
}  // namespace

43 44 45 46
WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder)
    : builder_(builder),
      locals_(builder->zone()),
      signature_index_(0),
47
      func_index_(static_cast<uint32_t>(builder->functions_.size())),
48
      body_(builder->zone(), 256),
49 50 51
      i32_temps_(builder->zone()),
      i64_temps_(builder->zone()),
      f32_temps_(builder->zone()),
52
      f64_temps_(builder->zone()),
53 54
      direct_calls_(builder->zone()),
      asm_offsets_(builder->zone(), 8) {}
55

56 57
void WasmFunctionBuilder::EmitByte(byte val) { body_.write_u8(val); }

58
void WasmFunctionBuilder::EmitI32V(int32_t val) { body_.write_i32v(val); }
59

60
void WasmFunctionBuilder::EmitU32V(uint32_t val) { body_.write_u32v(val); }
61

62 63 64
void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
  DCHECK(!locals_.has_sig());
  locals_.set_sig(sig);
65
  signature_index_ = builder_->AddSignature(sig);
66 67
}

68
uint32_t WasmFunctionBuilder::AddLocal(ValueType type) {
69 70
  DCHECK(locals_.has_sig());
  return locals_.AddLocals(1, type);
71 72
}

73
void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
74
  EmitWithU32V(kExprLocalGet, local_index);
75 76 77
}

void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
78
  EmitWithU32V(kExprLocalSet, local_index);
79
}
80

81
void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
82
  EmitWithU32V(kExprLocalTee, local_index);
83 84
}

85
void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
86
  body_.write(code, code_size);
87 88
}

89
void WasmFunctionBuilder::Emit(WasmOpcode opcode) { body_.write_u8(opcode); }
90

91 92 93
void WasmFunctionBuilder::EmitWithPrefix(WasmOpcode opcode) {
  DCHECK_NE(0, opcode & 0xff00);
  body_.write_u8(opcode >> 8);
94 95 96 97 98 99
  if ((opcode >> 8) == WasmOpcode::kSimdPrefix) {
    // SIMD opcodes are LEB encoded
    body_.write_u32v(opcode & 0xff);
  } else {
    body_.write_u8(opcode);
  }
100 101
}

102
void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
103 104
  body_.write_u8(opcode);
  body_.write_u8(immediate);
105 106
}

107 108
void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode, const byte imm1,
                                       const byte imm2) {
109 110 111
  body_.write_u8(opcode);
  body_.write_u8(imm1);
  body_.write_u8(imm2);
112 113
}

114 115 116
void WasmFunctionBuilder::EmitWithI32V(WasmOpcode opcode, int32_t immediate) {
  body_.write_u8(opcode);
  body_.write_i32v(immediate);
117 118
}

119 120 121
void WasmFunctionBuilder::EmitWithU32V(WasmOpcode opcode, uint32_t immediate) {
  body_.write_u8(opcode);
  body_.write_u32v(immediate);
122
}
123

124
void WasmFunctionBuilder::EmitI32Const(int32_t value) {
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
  EmitWithI32V(kExprI32Const, value);
}

void WasmFunctionBuilder::EmitI64Const(int64_t value) {
  body_.write_u8(kExprI64Const);
  body_.write_i64v(value);
}

void WasmFunctionBuilder::EmitF32Const(float value) {
  body_.write_u8(kExprF32Const);
  body_.write_f32(value);
}

void WasmFunctionBuilder::EmitF64Const(double value) {
  body_.write_u8(kExprF64Const);
  body_.write_f64(value);
141 142
}

143 144 145 146 147
void WasmFunctionBuilder::EmitDirectCallIndex(uint32_t index) {
  DirectCallIndex call;
  call.offset = body_.size();
  call.direct_index = index;
  direct_calls_.push_back(call);
148 149
  byte placeholder_bytes[kMaxVarInt32Size] = {0};
  EmitCode(placeholder_bytes, arraysize(placeholder_bytes));
150 151
}

152
void WasmFunctionBuilder::SetName(Vector<const char> name) { name_ = name; }
153

154 155
void WasmFunctionBuilder::AddAsmWasmOffset(size_t call_position,
                                           size_t to_number_position) {
156
  // We only want to emit one mapping per byte offset.
157 158 159 160 161 162 163
  DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_);

  DCHECK_LE(body_.size(), kMaxUInt32);
  uint32_t byte_offset = static_cast<uint32_t>(body_.size());
  asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_);
  last_asm_byte_offset_ = byte_offset;

164 165 166
  DCHECK_GE(std::numeric_limits<uint32_t>::max(), call_position);
  uint32_t call_position_u32 = static_cast<uint32_t>(call_position);
  asm_offsets_.write_i32v(call_position_u32 - last_asm_source_position_);
167

168 169 170 171
  DCHECK_GE(std::numeric_limits<uint32_t>::max(), to_number_position);
  uint32_t to_number_position_u32 = static_cast<uint32_t>(to_number_position);
  asm_offsets_.write_i32v(to_number_position_u32 - call_position_u32);
  last_asm_source_position_ = to_number_position_u32;
172 173
}

174 175
void WasmFunctionBuilder::SetAsmFunctionStartPosition(
    size_t function_position) {
176
  DCHECK_EQ(0, asm_func_start_source_position_);
177 178
  DCHECK_GE(std::numeric_limits<uint32_t>::max(), function_position);
  uint32_t function_position_u32 = static_cast<uint32_t>(function_position);
179 180
  // Must be called before emitting any asm.js source position.
  DCHECK_EQ(0, asm_offsets_.size());
181 182
  asm_func_start_source_position_ = function_position_u32;
  last_asm_source_position_ = function_position_u32;
183 184
}

185 186 187 188 189 190 191 192 193 194
void WasmFunctionBuilder::SetCompilationHint(
    WasmCompilationHintStrategy strategy, WasmCompilationHintTier baseline,
    WasmCompilationHintTier top_tier) {
  uint8_t hint_byte = static_cast<uint8_t>(strategy) |
                      static_cast<uint8_t>(baseline) << 2 |
                      static_cast<uint8_t>(top_tier) << 4;
  DCHECK_NE(hint_byte, kNoCompilationHint);
  hint_ = hint_byte;
}

195
void WasmFunctionBuilder::DeleteCodeAfter(size_t position) {
196
  DCHECK_LE(position, body_.size());
197
  body_.Truncate(position);
198 199
}

200 201
void WasmFunctionBuilder::WriteSignature(ZoneBuffer* buffer) const {
  buffer->write_u32v(signature_index_);
202 203
}

204
void WasmFunctionBuilder::WriteBody(ZoneBuffer* buffer) const {
205
  size_t locals_size = locals_.Size();
206 207 208
  buffer->write_size(locals_size + body_.size());
  buffer->EnsureSpace(locals_size);
  byte** ptr = buffer->pos_ptr();
209 210
  locals_.Emit(*ptr);
  (*ptr) += locals_size;  // UGLY: manual bump of position pointer
211
  if (body_.size() > 0) {
212 213
    size_t base = buffer->offset();
    buffer->write(body_.begin(), body_.size());
214
    for (DirectCallIndex call : direct_calls_) {
215
      buffer->patch_u32v(
216
          base + call.offset,
217 218
          call.direct_index +
              static_cast<uint32_t>(builder_->function_imports_.size()));
219
    }
220 221 222
  }
}

223
void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer* buffer) const {
224
  if (asm_func_start_source_position_ == 0 && asm_offsets_.size() == 0) {
225
    buffer->write_size(0);
226 227
    return;
  }
228 229 230
  size_t locals_enc_size = LEBHelper::sizeof_u32v(locals_.Size());
  size_t func_start_size =
      LEBHelper::sizeof_u32v(asm_func_start_source_position_);
231
  buffer->write_size(asm_offsets_.size() + locals_enc_size + func_start_size);
232 233
  // Offset of the recorded byte offsets.
  DCHECK_GE(kMaxUInt32, locals_.Size());
234
  buffer->write_u32v(static_cast<uint32_t>(locals_.Size()));
235
  // Start position of the function.
236 237
  buffer->write_u32v(asm_func_start_source_position_);
  buffer->write(asm_offsets_.begin(), asm_offsets_.size());
238 239
}

240 241
WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
    : zone_(zone),
242
      types_(zone),
243 244
      function_imports_(zone),
      global_imports_(zone),
245
      exports_(zone),
246
      functions_(zone),
247
      tables_(zone),
248 249 250
      data_segments_(zone),
      indirect_functions_(zone),
      globals_(zone),
251
      signature_map_(zone),
252
      start_function_index_(-1),
253 254
      min_memory_size_(16),
      max_memory_size_(0),
255 256
      has_max_memory_size_(false),
      has_shared_memory_(false) {}
257

258
WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) {
259
  functions_.push_back(zone_->New<WasmFunctionBuilder>(this));
260 261 262
  // Add the signature if one was provided here.
  if (sig) functions_.back()->SetSignature(sig);
  return functions_.back();
263 264
}

265 266 267 268 269 270 271
void WasmModuleBuilder::AddDataSegment(const byte* data, uint32_t size,
                                       uint32_t dest) {
  data_segments_.push_back({ZoneVector<byte>(zone()), dest});
  ZoneVector<byte>& vec = data_segments_.back().data;
  for (uint32_t i = 0; i < size; i++) {
    vec.push_back(data[i]);
  }
272 273
}

274
uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
275 276
  auto sig_entry = signature_map_.find(*sig);
  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 280 281 282 283 284 285
  types_.push_back(Type(sig));
  return index;
}

uint32_t WasmModuleBuilder::AddStructType(StructType* type) {
  uint32_t index = static_cast<uint32_t>(types_.size());
  types_.push_back(Type(type));
286
  return index;
287 288
}

289 290 291 292 293 294
uint32_t WasmModuleBuilder::AddArrayType(ArrayType* type) {
  uint32_t index = static_cast<uint32_t>(types_.size());
  types_.push_back(Type(type));
  return index;
}

295
uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
296
  DCHECK(allocating_indirect_functions_allowed_);
297 298 299 300 301
  uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
  DCHECK_GE(FLAG_wasm_max_table_size, index);
  if (count > FLAG_wasm_max_table_size - index) {
    return std::numeric_limits<uint32_t>::max();
  }
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
  uint32_t new_size = static_cast<uint32_t>(indirect_functions_.size()) + count;
  DCHECK(max_table_size_ == 0 || new_size <= max_table_size_);
  indirect_functions_.resize(new_size, WasmElemSegment::kNullIndex);
  uint32_t max = max_table_size_ > 0 ? max_table_size_ : new_size;
  if (tables_.empty()) {
    // This cannot use {AddTable} because that would flip the
    // {allocating_indirect_functions_allowed_} flag.
    tables_.push_back({kWasmFuncRef, new_size, max, true});
  } else {
    // There can only be the indirect function table so far, otherwise the
    // {allocating_indirect_functions_allowed_} flag would have been false.
    DCHECK_EQ(1u, tables_.size());
    DCHECK_EQ(kWasmFuncRef, tables_[0].type);
    DCHECK(tables_[0].has_maximum);
    tables_[0].min_size = new_size;
    tables_[0].max_size = max;
  }
319
  return index;
320 321 322 323 324
}

void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
                                            uint32_t direct) {
  indirect_functions_[indirect] = direct;
325 326
}

327 328 329 330
void WasmModuleBuilder::SetMaxTableSize(uint32_t max) {
  DCHECK_GE(FLAG_wasm_max_table_size, max);
  DCHECK_GE(max, indirect_functions_.size());
  max_table_size_ = max;
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
  DCHECK(allocating_indirect_functions_allowed_);
  if (!tables_.empty()) {
    tables_[0].max_size = max;
  }
}

uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size) {
#if DEBUG
  allocating_indirect_functions_allowed_ = false;
#endif
  tables_.push_back({type, min_size, 0, false});
  return static_cast<uint32_t>(tables_.size() - 1);
}

uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size,
                                     uint32_t max_size) {
#if DEBUG
  allocating_indirect_functions_allowed_ = false;
#endif
  tables_.push_back({type, min_size, max_size, true});
  return static_cast<uint32_t>(tables_.size() - 1);
352 353
}

354 355
uint32_t WasmModuleBuilder::AddImport(Vector<const char> name, FunctionSig* sig,
                                      Vector<const char> module) {
356
  DCHECK(adding_imports_allowed_);
357
  function_imports_.push_back({module, name, AddSignature(sig)});
358 359 360
  return static_cast<uint32_t>(function_imports_.size() - 1);
}

361
uint32_t WasmModuleBuilder::AddGlobalImport(Vector<const char> name,
362 363 364
                                            ValueType type, bool mutability,
                                            Vector<const char> module) {
  global_imports_.push_back({module, name, type.value_type_code(), mutability});
365
  return static_cast<uint32_t>(global_imports_.size() - 1);
366 367
}

368 369
void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
  start_function_index_ = function->func_index();
370
}
371

372
void WasmModuleBuilder::AddExport(Vector<const char> name,
373 374 375
                                  ImportExportKindCode kind, uint32_t index) {
  DCHECK_LE(index, std::numeric_limits<int>::max());
  exports_.push_back({name, kind, static_cast<int>(index)});
376 377
}

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 384 385
  return index;
}

386 387
void WasmModuleBuilder::ExportImportedFunction(Vector<const char> name,
                                               int import_index) {
388 389 390 391
#if DEBUG
  // The size of function_imports_ must not change any more.
  adding_imports_allowed_ = false;
#endif
392 393 394
  exports_.push_back(
      {name, kExternalFunction,
       import_index - static_cast<int>(function_imports_.size())});
395 396
}

397
uint32_t WasmModuleBuilder::AddGlobal(ValueType type, bool mutability,
398 399
                                      WasmInitExpr init) {
  globals_.push_back({type, mutability, std::move(init)});
400 401 402
  return static_cast<uint32_t>(globals_.size() - 1);
}

403 404 405 406
void WasmModuleBuilder::SetMinMemorySize(uint32_t value) {
  min_memory_size_ = value;
}

407 408 409 410 411
void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) {
  has_max_memory_size_ = true;
  max_memory_size_ = value;
}

412 413
void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }

414 415 416
namespace {
void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
  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
  }
}

425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
                            ValueType type) {
  switch (init.kind()) {
    case WasmInitExpr::kI32Const:
      buffer->write_u8(kExprI32Const);
      buffer->write_i32v(init.immediate().i32_const);
      break;
    case WasmInitExpr::kI64Const:
      buffer->write_u8(kExprI64Const);
      buffer->write_i64v(init.immediate().i64_const);
      break;
    case WasmInitExpr::kF32Const:
      buffer->write_u8(kExprF32Const);
      buffer->write_f32(init.immediate().f32_const);
      break;
    case WasmInitExpr::kF64Const:
      buffer->write_u8(kExprF64Const);
      buffer->write_f64(init.immediate().f64_const);
      break;
444 445 446
    case WasmInitExpr::kS128Const:
      buffer->write_u8(kSimdPrefix);
      buffer->write_u8(kExprS128Const & 0xFF);
447
      buffer->write(init.immediate().s128_const.data(), kSimd128Size);
448
      break;
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
    case WasmInitExpr::kGlobalGet:
      buffer->write_u8(kExprGlobalGet);
      buffer->write_u32v(init.immediate().index);
      break;
    case WasmInitExpr::kRefNullConst:
      buffer->write_u8(kExprRefNull);
      buffer->write_i32v(HeapType(init.immediate().heap_type).code());
      break;
    case WasmInitExpr::kRefFuncConst:
      buffer->write_u8(kExprRefFunc);
      buffer->write_u32v(init.immediate().index);
      break;
    case WasmInitExpr::kNone: {
      // No initializer, emit a default value.
      switch (type.kind()) {
        case ValueType::kI32:
          buffer->write_u8(kExprI32Const);
          // LEB encoding of 0.
          buffer->write_u8(0);
          break;
        case ValueType::kI64:
          buffer->write_u8(kExprI64Const);
          // LEB encoding of 0.
          buffer->write_u8(0);
          break;
        case ValueType::kF32:
          buffer->write_u8(kExprF32Const);
          buffer->write_f32(0.f);
          break;
        case ValueType::kF64:
          buffer->write_u8(kExprF64Const);
          buffer->write_f64(0.);
          break;
        case ValueType::kOptRef:
          buffer->write_u8(kExprRefNull);
          break;
        case ValueType::kI8:
        case ValueType::kI16:
        case ValueType::kStmt:
        case ValueType::kS128:
        case ValueType::kBottom:
        case ValueType::kRef:
        case ValueType::kRtt:
          UNREACHABLE();
      }
      break;
    }
496
    case WasmInitExpr::kRttCanon:
497 498 499 500
      STATIC_ASSERT((kExprRttCanon >> 8) == kGCPrefix);
      buffer->write_u8(kGCPrefix);
      buffer->write_u8(static_cast<uint8_t>(kExprRttCanon));
      buffer->write_i32v(HeapType(init.immediate().heap_type).code());
501 502 503 504
      break;
    case WasmInitExpr::kRttSub:
      // TODO(7748): If immediates for rtts remain in the standard, adapt this
      // to emit them.
505 506 507 508
      STATIC_ASSERT((kExprRttSub >> 8) == kGCPrefix);
      buffer->write_u8(kGCPrefix);
      buffer->write_u8(static_cast<uint8_t>(kExprRttSub));
      buffer->write_i32v(HeapType(init.immediate().heap_type).code());
509 510
      WriteGlobalInitializer(buffer, *init.operand(), kWasmBottom);
      break;
511 512 513
  }
}

514 515
}  // namespace

516
void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
517
  // == Emit magic =============================================================
518 519
  buffer->write_u32(kWasmMagic);
  buffer->write_u32(kWasmVersion);
520

521 522
  // == Emit types =============================================================
  if (types_.size() > 0) {
523
    size_t start = EmitSection(kTypeSectionCode, buffer);
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
    buffer->write_size(types_.size());

    for (const Type& type : types_) {
      switch (type.kind) {
        case Type::kFunctionSig: {
          FunctionSig* sig = type.sig;
          buffer->write_u8(kWasmFunctionTypeCode);
          buffer->write_size(sig->parameter_count());
          for (auto param : sig->parameters()) {
            WriteValueType(buffer, param);
          }
          buffer->write_size(sig->return_count());
          for (auto ret : sig->returns()) {
            WriteValueType(buffer, ret);
          }
          break;
        }
        case Type::kStructType: {
542
          StructType* struct_type = type.struct_type;
543 544
          buffer->write_u8(kWasmStructTypeCode);
          buffer->write_size(struct_type->field_count());
545 546 547
          for (uint32_t i = 0; i < struct_type->field_count(); i++) {
            WriteValueType(buffer, struct_type->field(i));
            buffer->write_u8(struct_type->mutability(i) ? 1 : 0);
548 549 550
          }
          break;
        }
551 552 553 554
        case Type::kArrayType: {
          ArrayType* array_type = type.array_type;
          buffer->write_u8(kWasmArrayTypeCode);
          WriteValueType(buffer, array_type->element_type());
555
          buffer->write_u8(array_type->mutability() ? 1 : 0);
556 557
          break;
        }
558
      }
559
    }
560 561 562 563
    FixupSection(buffer, start);
  }

  // == 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 569
      buffer->write_string(import.module);  // module name
      buffer->write_string(import.name);    // field name
570 571
      buffer->write_u8(kExternalGlobal);
      buffer->write_u8(import.type_code);
572
      buffer->write_u8(import.mutability ? 1 : 0);
573 574
    }
    for (auto import : function_imports_) {
575 576
      buffer->write_string(import.module);  // module name
      buffer->write_string(import.name);    // field name
577 578
      buffer->write_u8(kExternalFunction);
      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 596
  // == Emit tables ============================================================
  if (tables_.size() > 0) {
597
    size_t start = EmitSection(kTableSectionCode, buffer);
598 599
    buffer->write_size(tables_.size());
    for (const WasmTable& table : tables_) {
600
      buffer->write_u8(table.type.value_type_code());
601 602 603 604
      buffer->write_u8(table.has_maximum ? kHasMaximumFlag : kNoMaximumFlag);
      buffer->write_size(table.min_size);
      if (table.has_maximum) buffer->write_size(table.max_size);
    }
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 614
      buffer->write_u8(has_max_memory_size_ ? MemoryFlags::kSharedAndMaximum
                                            : MemoryFlags::kSharedNoMaximum);
615
    } else {
616 617
      buffer->write_u8(has_max_memory_size_ ? MemoryFlags::kMaximum
                                            : MemoryFlags::kNoMaximum);
618
    }
619
    buffer->write_u32v(min_memory_size_);
620
    if (has_max_memory_size_) {
621
      buffer->write_u32v(max_memory_size_);
622
    }
623 624 625 626 627 628
    FixupSection(buffer, start);
  }

  // == Emit globals ===========================================================
  if (globals_.size() > 0) {
    size_t start = EmitSection(kGlobalSectionCode, buffer);
629
    buffer->write_size(globals_.size());
630

631
    for (const WasmGlobal& global : globals_) {
632
      WriteValueType(buffer, global.type);
633
      buffer->write_u8(global.mutability ? 1 : 0);
634
      WriteGlobalInitializer(buffer, global.init, global.type);
635
      buffer->write_u8(kExprEnd);
636
    }
637
    FixupSection(buffer, start);
638 639
  }

640
  // == emit exports ===========================================================
641
  if (exports_.size() > 0) {
642
    size_t start = EmitSection(kExportSectionCode, buffer);
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
    buffer->write_size(exports_.size());
    for (auto ex : exports_) {
      buffer->write_string(ex.name);
      buffer->write_u8(ex.kind);
      switch (ex.kind) {
        case kExternalFunction:
          buffer->write_size(ex.index + function_imports_.size());
          break;
        case kExternalGlobal:
          buffer->write_size(ex.index + global_imports_.size());
          break;
        case kExternalMemory:
        case kExternalTable:
          // The WasmModuleBuilder doesn't support importing tables or memories
          // yet, so there is no index offset to add.
          buffer->write_size(ex.index);
          break;
        case kExternalException:
          UNREACHABLE();
      }
663
    }
664 665 666 667
    FixupSection(buffer, start);
  }

  // == emit start function index ==============================================
668
  if (start_function_index_ >= 0) {
669
    size_t start = EmitSection(kStartSectionCode, buffer);
670
    buffer->write_size(start_function_index_ + function_imports_.size());
671
    FixupSection(buffer, start);
672 673
  }

674 675 676
  // == emit function table elements ===========================================
  if (indirect_functions_.size() > 0) {
    size_t start = EmitSection(kElementSectionCode, buffer);
677 678
    buffer->write_u8(1);              // count of entries
    buffer->write_u8(0);              // table index
679 680 681 682 683 684 685 686 687 688 689
    uint32_t first_element = 0;
    while (first_element < indirect_functions_.size() &&
           indirect_functions_[first_element] == WasmElemSegment::kNullIndex) {
      first_element++;
    }
    uint32_t last_element =
        static_cast<uint32_t>(indirect_functions_.size() - 1);
    while (last_element >= first_element &&
           indirect_functions_[last_element] == WasmElemSegment::kNullIndex) {
      last_element--;
    }
690
    buffer->write_u8(kExprI32Const);  // offset
691
    buffer->write_u32v(first_element);
692
    buffer->write_u8(kExprEnd);
693 694 695 696
    uint32_t element_count = last_element - first_element + 1;
    buffer->write_size(element_count);
    for (uint32_t i = first_element; i <= last_element; i++) {
      buffer->write_size(indirect_functions_[i] + function_imports_.size());
697 698 699 700 701
    }

    FixupSection(buffer, start);
  }

702 703 704 705 706 707 708 709 710 711
  // == emit compilation hints section =========================================
  bool emit_compilation_hints = false;
  for (auto* fn : functions_) {
    if (fn->hint_ != kNoCompilationHint) {
      emit_compilation_hints = true;
      break;
    }
  }
  if (emit_compilation_hints) {
    // Emit the section code.
712
    buffer->write_u8(kUnknownSectionCode);
713
    // Emit a placeholder for section length.
714
    size_t start = buffer->reserve_u32v();
715
    // Emit custom section name.
716
    buffer->write_string(CStrVector("compilationHints"));
717
    // Emit hint count.
718
    buffer->write_size(functions_.size());
719 720 721 722
    // Emit hint bytes.
    for (auto* fn : functions_) {
      uint8_t hint_byte =
          fn->hint_ != kNoCompilationHint ? fn->hint_ : kDefaultCompilationHint;
723
      buffer->write_u8(hint_byte);
724 725 726 727
    }
    FixupSection(buffer, start);
  }

728 729
  // == emit code ==============================================================
  if (functions_.size() > 0) {
730
    size_t start = EmitSection(kCodeSectionCode, buffer);
731
    buffer->write_size(functions_.size());
732
    for (auto* function : functions_) {
733 734 735 736 737 738
      function->WriteBody(buffer);
    }
    FixupSection(buffer, start);
  }

  // == emit data segments =====================================================
739
  if (data_segments_.size() > 0) {
740
    size_t start = EmitSection(kDataSectionCode, buffer);
741
    buffer->write_size(data_segments_.size());
742 743

    for (auto segment : data_segments_) {
744 745 746 747 748 749
      buffer->write_u8(0);              // linear memory segment
      buffer->write_u8(kExprI32Const);  // initializer expression for dest
      buffer->write_u32v(segment.dest);
      buffer->write_u8(kExprEnd);
      buffer->write_u32v(static_cast<uint32_t>(segment.data.size()));
      buffer->write(&segment.data[0], segment.data.size());
750
    }
751
    FixupSection(buffer, start);
752
  }
753 754

  // == Emit names =============================================================
755
  if (num_function_names > 0 || !function_imports_.empty()) {
756
    // Emit the section code.
757
    buffer->write_u8(kUnknownSectionCode);
758
    // Emit a placeholder for the length.
759
    size_t start = buffer->reserve_u32v();
760
    // Emit the section string.
761
    buffer->write_string(CStrVector("name"));
762
    // Emit a subsection for the function names.
763
    buffer->write_u8(NameSectionKindCode::kFunction);
764
    // Emit a placeholder for the subsection length.
765
    size_t functions_start = buffer->reserve_u32v();
766 767 768
    // Emit the function names.
    // Imports are always named.
    uint32_t num_imports = static_cast<uint32_t>(function_imports_.size());
769
    buffer->write_size(num_imports + num_function_names);
770 771 772
    uint32_t function_index = 0;
    for (; function_index < num_imports; ++function_index) {
      const WasmFunctionImport* import = &function_imports_[function_index];
773
      DCHECK(!import->name.empty());
774 775
      buffer->write_u32v(function_index);
      buffer->write_string(import->name);
776
    }
777
    if (num_function_names > 0) {
778
      for (auto* function : functions_) {
779 780
        DCHECK_EQ(function_index,
                  function->func_index() + function_imports_.size());
781
        if (!function->name_.empty()) {
782 783
          buffer->write_u32v(function_index);
          buffer->write_string(function->name_);
784 785 786
        }
        ++function_index;
      }
787
    }
788
    FixupSection(buffer, functions_start);
789 790
    FixupSection(buffer, start);
  }
791
}
792

793
void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer* buffer) const {
794
  // == Emit asm.js offset table ===============================================
795
  buffer->write_size(functions_.size());
796
  // Emit the offset table per function.
797
  for (auto* function : functions_) {
798 799 800
    function->WriteAsmWasmOffsetTable(buffer);
  }
}
801 802 803
}  // namespace wasm
}  // namespace internal
}  // namespace v8