loadBytecode method
dynamic
loadBytecode({})
Load a pre-compiled bytecode file as a module.
If invokeFunc
is true, execute the bytecode immediately.
Implementation
dynamic loadBytecode({
required Uint8List bytes,
required String moduleName,
bool globallyImport = false,
String? invokeFunc,
List<dynamic> positionalArgs = const [],
Map<String, dynamic> namedArgs = const {},
List<HTType> typeArgs = const [],
bool debugPerformance = false,
}) {
try {
final tik = DateTime.now().millisecondsSinceEpoch;
_currentBytecodeModule = HTBytecodeModule(id: moduleName, bytes: bytes);
cachedModules[_currentBytecodeModule.id] = _currentBytecodeModule;
final signature = _currentBytecodeModule.readUint32();
if (signature != HTCompiler.hetuSignature) {
throw HTError.bytecode(
filename: _currentFileName, line: _currentLine, column: _column);
}
final major = _currentBytecodeModule.read();
final minor = _currentBytecodeModule.read();
final patch = _currentBytecodeModule.readUint16();
final preReleaseLength = _currentBytecodeModule.read();
String? preRelease;
for (var i = 0; i < preReleaseLength; ++i) {
preRelease ??= '';
preRelease += _currentBytecodeModule.readUtf8String();
}
final buildLength = _currentBytecodeModule.read();
String? build;
for (var i = 0; i < buildLength; ++i) {
build ??= '';
build += _currentBytecodeModule.readUtf8String();
}
_currentBytecodeModule.version =
Version(major, minor, patch, pre: preRelease, build: build);
_currentBytecodeModule.compiledAt =
_currentBytecodeModule.readUtf8String();
var incompatible = false;
if (major > 0) {
if (major != kHetuVersion.major) {
incompatible = true;
}
} else {
if (major != kHetuVersion.major ||
minor != kHetuVersion.minor ||
patch != kHetuVersion.patch) {
incompatible = true;
}
}
if (incompatible) {
throw HTError.version('$major.$minor.$patch', '$kHetuVersion',
filename: _currentFileName, line: _currentLine, column: _column);
}
_currentFileName = _currentBytecodeModule.readUtf8String();
final sourceType =
HTResourceType.values.elementAt(_currentBytecodeModule.read());
_isModuleEntryScript = sourceType == HTResourceType.hetuScript ||
sourceType == HTResourceType.hetuLiteralCode ||
sourceType == HTResourceType.hetuValue;
if (sourceType == HTResourceType.hetuLiteralCode) {
_currentNamespace = globalNamespace;
}
while (_currentBytecodeModule.ip < _currentBytecodeModule.bytes.length) {
final result = execute(retractStackFrame: false);
if (result is HTNamespace && result != globalNamespace) {
_currentBytecodeModule.namespaces[result.id!] = result;
} else if (result is HTValueSource) {
_currentBytecodeModule.expressions[result.id] = result.value;
} else {
assert(result == globalNamespace);
}
// TODO: import binary bytes
}
if (!_isModuleEntryScript) {
// handles imports
for (final nsp in _currentBytecodeModule.namespaces.values) {
for (final decl in nsp.imports.values) {
_handleNamespaceImport(nsp, decl);
}
}
}
if (_currentBytecodeModule.namespaces.isNotEmpty) {
_currentNamespace = _currentBytecodeModule.namespaces.values.last;
if (globallyImport) {
globalNamespace.import(_currentNamespace);
}
}
// resolve each declaration after we get all declarations
// if (!_isModuleEntryScript) {
// for (final namespace in _currentBytecodeModule.namespaces.values) {
// for (final decl in namespace.declarations.values) {
// decl.resolve();
// }
// }
// }
cachedModules[_currentBytecodeModule.id] = _currentBytecodeModule;
dynamic result;
if (invokeFunc != null) {
result = invoke(invokeFunc,
moduleName: _currentBytecodeModule.id,
positionalArgs: positionalArgs,
namedArgs: namedArgs);
} else if (_isModuleEntryScript) {
result = _stackFrames.last.first;
}
final tok = DateTime.now().millisecondsSinceEpoch;
if (debugPerformance) {
print(
'hetu: ${tok - tik}ms\tto load\t\t[${_currentBytecodeModule.id}] (version: \'${_currentBytecodeModule.version}\', compiled at: ${_currentBytecodeModule.compiledAt})');
}
stackTraceList.clear();
return result;
} catch (error, stackTrace) {
if (config.processError) {
processError(error, stackTrace);
} else {
rethrow;
}
}
}