dvInstallLoadingUnits function
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;
}