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 printPerformanceStatistics = 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);
}
// compare the version of the compiler of the bytecode to my version.
final compilerVersion = _handleVersion();
var incompatible = false;
if (compilerVersion.major > 0) {
if (compilerVersion.major > kHetuVersion.major) {
incompatible = true;
}
} else {
if (compilerVersion != kHetuVersion) {
incompatible = true;
}
}
if (incompatible) {
throw HTError.version(
_currentBytecodeModule.version.toString(),
kHetuVersion.toString(),
filename: _currentFileName,
line: _currentLine,
column: _column,
);
}
// read the version of the bytecode.
final hasVersion = _currentBytecodeModule.readBool();
if (hasVersion) {
_currentBytecodeModule.version = _handleVersion();
}
_currentBytecodeModule.compiledAt =
_currentBytecodeModule.readUtf8String();
_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.values[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 (printPerformanceStatistics) {
var message =
'hetu: ${tok - tik}ms\tto load module\t${_currentBytecodeModule.id}';
if (_currentBytecodeModule.version != null) {
message += '@${_currentBytecodeModule.version}';
}
message +=
' (compiled at ${_currentBytecodeModule.compiledAt} UTC with hetu@$compilerVersion)';
print(message);
}
stackTraceList.clear();
return result;
} catch (error, stackTrace) {
if (config.processError) {
processError(error, stackTrace);
} else {
rethrow;
}
}
}