open static method

  1. @different
Future<DynamicLibrary> open(
  1. String modulePath, {
  2. String? moduleName,
  3. ModuleLoader? moduleLoader,
  4. WasmType? wasmType,
  5. GlobalMemory? useAsGlobal,
})

Creates a instance based on the given module.

While for each DynamicLibrary a Memory object is created, the Memory objects share the backing memory if they are created based on the same module.

The wasmType parameter can be used to control if the module should be loaded as standalone wasm module or as emscripten module.

The moduleName parameter is only used for debugging purposes. It is needed for the EmscriptenModule to find the correct module. It is ignored for the StandaloneWasmModule.

The useAsGlobal parameter can be used to control if the newly created Memory object should be registered as Memory.global. Loads a library file and provides access to its symbols.

Calling this function multiple times with the same path, even across different isolates, only loads the library into the DartVM process once. Multiple loads of the same library file produces DynamicLibrary objects which are equal (==), but not identical.

Implementation

@different
static Future<DynamicLibrary> open(
  String modulePath, {
  String? moduleName,
  ModuleLoader? moduleLoader,
  WasmType? wasmType,
  GlobalMemory? useAsGlobal,
}) async {
  /// 64-bit wasm is not supported
  if (wasmType == WasmType.wasm64Standalone ||
      wasmType == WasmType.wasm64Emscripten) {
    throw UnsupportedError('64-bit wasm is not supported');
  }

  moduleLoader ??= WebModuleLoader();

  /// Initialize the native types in marshaller
  initTypes();
  registerOpaqueType<Utf8>(1);
  registerOpaqueType<Utf16>(2);

  final uri = Uri.parse(modulePath);

  // extract the module name from the path if not provided
  moduleName ??= path.basenameWithoutExtension(uri.pathSegments.last);

  // Infer the wasm type
  if (wasmType == null) {
    final ext = path.extension(uri.pathSegments.last);
    if (ext == '.js') {
      wasmType = WasmType.wasm32Emscripten;
    } else if (ext == '.wasm') {
      wasmType = WasmType.wasm32Standalone;
    } else {
      if (await moduleLoader.exists('$modulePath.js')) {
        modulePath = '$modulePath.js';
        wasmType = WasmType.wasm32Emscripten;
      } else if (await moduleLoader.exists('$modulePath.wasm')) {
        modulePath = '$modulePath.wasm';
        wasmType = WasmType.wasm32Standalone;
      } else {
        throw ArgumentError('No wasm or js file found at $modulePath');
      }
    }
  }

  late Module module;
  if (wasmType == WasmType.wasm32Emscripten) {
    await importLibrary(modulePath);
    module = await EmscriptenModule.compile(moduleName);
  } else {
    final wasmBinary = await moduleLoader.load(modulePath);
    module = await StandaloneWasmModule.compile(wasmBinary);
  }

  final Memory memory = createMemory(module);

  switch (useAsGlobal ?? GlobalMemory.ifNotSet) {
    case GlobalMemory.yes:
      Memory.global = memory;
      interop.WasmTable.global = module.indirectFunctionTable;
      break;
    case GlobalMemory.no:
      break;
    case GlobalMemory.ifNotSet:
      Memory.global ??= memory;
      interop.WasmTable.global ??= module.indirectFunctionTable;
      break;
  }

  if (module is StandaloneWasmModule) {
    try {
      module
          .lookup<NativeFunction<Void Function()>>(
            '__wasm_call_ctors',
            memory,
          )
          .asFunction<void Function()>()();
    } catch (_) {
      // Ignore if not present
    }
  }

  return DynamicLibrary._(module, memory);
}