dvInstallLoadingUnits function

Future<int> dvInstallLoadingUnits(
  1. DVBinaryPayload payload
)

Makes the deferred code units payload carries loadable from where they lie, and returns how many it carries: zero for a program compiled as one unit, which needs nothing.

Throws UnsupportedError when the payload carries units that this process cannot load -- a native library without the loader, or a runtime that does not export the embedding API -- so the binary fails at start rather than at the first request that needs one.

Implementation

Future<int> dvInstallLoadingUnits(DVBinaryPayload payload) async {
  final Map<int, int> units = <int, int>{};
  for (final String name in payload.names) {
    if (!name.startsWith('unit.')) continue;
    final int? id = int.tryParse(name.substring(5));
    final ({int offset, int length})? at = payload.locate(name);
    if (id != null && at != null) units[id] = at.offset;
  }
  if (units.isEmpty) return 0;
  final ffi.DynamicLibrary library = (await openNativeServerLibrary()).library;
  if (!library.providesSymbol('aw_units_load') ||
      library.lookupFunction<ffi.Int32 Function(), int Function()>('aw_units_supported')() == 0) {
    throw UnsupportedError('dartvel: this binary carries deferred code that its '
        'native server library or runtime cannot load');
  }
  final int Function(int, ffi.Pointer<ffi.Uint8>, int, int) register = library.lookupFunction<
      ffi.Int32 Function(ffi.IntPtr, ffi.Pointer<ffi.Uint8>, ffi.Size, ffi.Uint64),
      int Function(int, ffi.Pointer<ffi.Uint8>, int, int)>('aw_units_register');
  final Uint8List path = utf8.encode(payload.path);
  final ffi.Pointer<ffi.Uint8> native = pkgffi.calloc<ffi.Uint8>(path.length);
  try {
    native.asTypedList(path.length).setAll(0, path);
    for (final MapEntry<int, int> unit in units.entries) {
      if (register(unit.key, native, path.length, unit.value) != 0) {
        throw UnsupportedError('dartvel: code unit ${unit.key} could not be registered');
      }
    }
  } finally {
    pkgffi.calloc.free(native);
  }
  ffi.DynamicLibrary.executable().lookupFunction<_SetN, _SetD>('Dart_SetDeferredLoadHandler')(
      library.lookup<ffi.NativeFunction<_HandlerN>>('aw_units_load'));
  _library = library;
  return units.length;
}