bool Wamr::link()

in plugins/experimental/wasm/lib/src/wamr/wamr.cc [252:381]


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

  WasmImporttypeVec import_types;
  wasm_module_imports(module_.get(), import_types.get());

  std::vector<wasm_extern_t *> imports;
  for (size_t i = 0; i < import_types.get()->size; i++) {
    const wasm_name_t *module_name_ptr = wasm_importtype_module(import_types.get()->data[i]);
    const wasm_name_t *name_ptr = wasm_importtype_name(import_types.get()->data[i]);
    const wasm_externtype_t *extern_type = wasm_importtype_type(import_types.get()->data[i]);

    if (std::strlen(name_ptr->data) == 0) {
      fail(FailState::UnableToInitializeCode, std::string("The name field of import_types[") +
                                                  std::to_string(i) + std::string("] is empty"));
      return false;
    }

    std::string_view module_name(module_name_ptr->data);
    std::string_view name(name_ptr->data);

    switch (wasm_externtype_kind(extern_type)) {
    case WASM_EXTERN_FUNC: {
      auto it = host_functions_.find(std::string(module_name) + "." + 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_name) + "." + std::string(name));
        return false;
      }

      auto *func = it->second->callback_.get();
      const wasm_functype_t *exp_type = wasm_externtype_as_functype_const(extern_type);
      WasmFunctypePtr actual_type = wasm_func_type(it->second->callback_.get());
      if (!equalValTypes(wasm_functype_params(exp_type), wasm_functype_params(actual_type.get())) ||
          !equalValTypes(wasm_functype_results(exp_type),
                         wasm_functype_results(actual_type.get()))) {
        fail(
            FailState::UnableToInitializeCode,
            std::string("Failed to load Wasm module due to an import type mismatch for function ") +
                std::string(module_name) + "." + std::string(name) +
                ", want: " + printValTypes(wasm_functype_params(exp_type)) + " -> " +
                printValTypes(wasm_functype_results(exp_type)) +
                ", but host exports: " + printValTypes(wasm_functype_params(actual_type.get())) +
                " -> " + printValTypes(wasm_functype_results(actual_type.get())));
        return false;
      }
      imports.push_back(wasm_func_as_extern(func));
    } break;
    case WASM_EXTERN_GLOBAL: {
      // TODO(mathetake): add support when/if needed.
      fail(FailState::UnableToInitializeCode,
           "Failed to load Wasm module due to a missing import: " + std::string(module_name) + "." +
               std::string(name));
      return false;
    } break;
    case WASM_EXTERN_MEMORY: {
      assert(memory_ == nullptr);
      const wasm_memorytype_t *memory_type =
          wasm_externtype_as_memorytype_const(extern_type); // owned by `extern_type`
      if (memory_type == nullptr) {
        return false;
      }
      memory_ = wasm_memory_new(store_.get(), memory_type);
      if (memory_ == nullptr) {
        return false;
      }
      imports.push_back(wasm_memory_as_extern(memory_.get()));
    } break;
    case WASM_EXTERN_TABLE: {
      assert(table_ == nullptr);
      const wasm_tabletype_t *table_type =
          wasm_externtype_as_tabletype_const(extern_type); // owned by `extern_type`
      if (table_type == nullptr) {
        return false;
      }
      table_ = wasm_table_new(store_.get(), table_type, nullptr);
      if (table_ == nullptr) {
        return false;
      }
      imports.push_back(wasm_table_as_extern(table_.get()));
    } break;
    }
  }

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

  wasm_extern_vec_t imports_vec = {imports.size(), imports.data(), imports.size()};
  instance_ = wasm_instance_new(store_.get(), module_.get(), &imports_vec, nullptr);
  if (instance_ == nullptr) {
    fail(FailState::UnableToInitializeCode, "Failed to create new Wasm instance");
    return false;
  }

  WasmExportTypeVec export_types;
  wasm_module_exports(module_.get(), export_types.get());

  WasmExternVec exports;
  wasm_instance_exports(instance_.get(), exports.get());

  for (size_t i = 0; i < export_types.get()->size; i++) {
    wasm_extern_t *actual_extern = exports.get()->data[i];

    wasm_externkind_t kind = wasm_extern_kind(actual_extern);
    assert(kind == wasm_externtype_kind(wasm_exporttype_type(export_types.get()->data[i])));
    switch (kind) {
    case WASM_EXTERN_FUNC: {
      WasmFuncPtr func = wasm_func_copy(wasm_extern_as_func(actual_extern));
      const wasm_name_t *name_ptr = wasm_exporttype_name(export_types.get()->data[i]);
      module_functions_.insert_or_assign(std::string(name_ptr->data), std::move(func));
    } break;
    case WASM_EXTERN_GLOBAL: {
      // TODO(mathetake): add support when/if needed.
    } break;
    case WASM_EXTERN_MEMORY: {
      assert(memory_ == nullptr);
      memory_ = wasm_memory_copy(wasm_extern_as_memory(actual_extern));
      if (memory_ == nullptr) {
        return false;
      }
    } break;
    case WASM_EXTERN_TABLE: {
      // TODO(mathetake): add support when/if needed.
    } break;
    }
  }
  return true;
}