bool V8::link()

in plugins/experimental/wasm/lib/src/v8/v8.cc [342:463]


bool V8::link(std::string_view /*debug_name*/) {
  assert(module_ != nullptr);

  const auto import_types = module_.get()->imports();
  std::vector<const wasm::Extern *> imports;

  for (size_t i = 0; i < import_types.size(); i++) {
    std::string_view module(import_types[i]->module().get(), import_types[i]->module().size());
    std::string_view name(import_types[i]->name().get(), import_types[i]->name().size());
    const auto *import_type = import_types[i]->type();

    switch (import_type->kind()) {

    case wasm::EXTERN_FUNC: {
      auto it = host_functions_.find(std::string(module) + "." + std::string(name));
      if (it == host_functions_.end()) {
        fail(FailState::UnableToInitializeCode,
             std::string("Failed to load Wasm module due to a missing import: ") +
                 std::string(module) + "." + std::string(name));
        return false;
      }
      auto *func = it->second->callback_.get();
      if (!equalValTypes(import_type->func()->params(), func->type()->params()) ||
          !equalValTypes(import_type->func()->results(), func->type()->results())) {
        fail(FailState::UnableToInitializeCode,
             std::string("Failed to load Wasm module due to an import type mismatch: ") +
                 std::string(module) + "." + std::string(name) +
                 ", want: " + printValTypes(import_type->func()->params()) + " -> " +
                 printValTypes(import_type->func()->results()) +
                 ", but host exports: " + printValTypes(func->type()->params()) + " -> " +
                 printValTypes(func->type()->results()));
        return false;
      }
      imports.push_back(func);
    } break;

    case wasm::EXTERN_GLOBAL: {
      // TODO(PiotrSikora): add support when/if needed.
      fail(FailState::UnableToInitializeCode,
           "Failed to load Wasm module due to a missing import: " + std::string(module) + "." +
               std::string(name));
      return false;
    } break;

    case wasm::EXTERN_MEMORY: {
      assert(memory_ == nullptr);
      auto type = wasm::MemoryType::make(import_type->memory()->limits());
      if (type == nullptr) {
        return false;
      }
      memory_ = wasm::Memory::make(store_.get(), type.get());
      if (memory_ == nullptr) {
        return false;
      }
      imports.push_back(memory_.get());
    } break;

    case wasm::EXTERN_TABLE: {
      assert(table_ == nullptr);
      auto type =
          wasm::TableType::make(wasm::ValType::make(import_type->table()->element()->kind()),
                                import_type->table()->limits());
      if (type == nullptr) {
        return false;
      }
      table_ = wasm::Table::make(store_.get(), type.get());
      if (table_ == nullptr) {
        return false;
      }
      imports.push_back(table_.get());
    } break;
    }
  }

  if (import_types.size() != imports.size()) {
    return false;
  }

  instance_ = wasm::Instance::make(store_.get(), module_.get(), imports.data());
  if (instance_ == nullptr) {
    fail(FailState::UnableToInitializeCode, "Failed to create new Wasm instance");
    return false;
  }

  const auto export_types = module_.get()->exports();
  const auto exports = instance_.get()->exports();
  assert(export_types.size() == exports.size());

  for (size_t i = 0; i < export_types.size(); i++) {
    std::string_view name(export_types[i]->name().get(), export_types[i]->name().size());
    const auto *export_type = export_types[i]->type();
    auto *export_item = exports[i].get();
    assert(export_type->kind() == export_item->kind());

    switch (export_type->kind()) {

    case wasm::EXTERN_FUNC: {
      assert(export_item->func() != nullptr);
      module_functions_.insert_or_assign(std::string(name), export_item->func()->copy());
    } break;

    case wasm::EXTERN_GLOBAL: {
      // TODO(PiotrSikora): add support when/if needed.
    } break;

    case wasm::EXTERN_MEMORY: {
      assert(export_item->memory() != nullptr);
      assert(memory_ == nullptr);
      memory_ = exports[i]->memory()->copy();
      if (memory_ == nullptr) {
        return false;
      }
    } break;

    case wasm::EXTERN_TABLE: {
      // TODO(PiotrSikora): add support when/if needed.
    } break;
    }
  }

  return true;
}