Skip to main content

Overview

The KernelIO interface provides an abstraction for loading and writing Dart kernel Component objects from and to .dill files.
The KernelIO interface is defined in the pure engine layer without dart:io dependencies, allowing RefractorEngine to use it without platform constraints.

KernelIO Interface

abstract class KernelIO {
  Component load(String path);
  void write(Component component, String path);
}

load()

Load a kernel Component from a .dill file at the specified path.
path
String
required
Path to the .dill file to load
return
Component
A kernel Component object from the package:kernel/kernel.dart library
If the file does not exist, implementations should throw an exception.

write()

Write a kernel Component to a .dill file at the specified path.
component
Component
required
The kernel Component to serialize and write
path
String
required
Path where the .dill file will be written
The parent directory will be created automatically if it doesn’t exist.

FileKernelIO Implementation

FileKernelIO is the concrete file-based implementation of KernelIO.
class FileKernelIO implements KernelIO {
  @override
  Component load(String path);

  @override
  void write(Component component, String path);
}

Implementation Details

  • load(): Uses loadComponentFromBinary() from package:kernel/kernel.dart
  • write(): Uses BinaryPrinter from package:kernel/binary/ast_to_binary.dart to serialize the component
  • Creates parent directories recursively when writing
  • Throws FileIoException if the input file doesn’t exist during load

Component Class

The Component class is from the Dart kernel package (package:kernel/kernel.dart). It represents the entire program as an abstract syntax tree (AST).
A Component contains libraries, classes, procedures, and all other program elements in their kernel representation.

Usage Example

import 'package:kernel/kernel.dart';
import 'package:refractor/refractor.dart';
import 'package:refractor/src/engine/kernel/file_kernel_io.dart';

void main() {
  final kernelIO = FileKernelIO();

  // Load a kernel component from disk
  final component = kernelIO.load('build/app.dill');

  print('Loaded ${component.libraries.length} libraries');

  // Modify the component (e.g., with obfuscation passes)
  // ...

  // Write the modified component back to disk
  kernelIO.write(component, 'build/app.obfuscated.dill');
}

Integration with RefractorEngine

KernelIO is used by RefractorEngine to load and save kernel components during the obfuscation pipeline:
import 'package:refractor/refractor.dart';
import 'package:refractor/src/engine/kernel/file_kernel_io.dart';

void main() {
  final kernelIO = FileKernelIO();
  final engine = RefractorEngine(kernelIO: kernelIO);

  // Load kernel
  final component = kernelIO.load('input.dill');

  // Apply obfuscation passes
  engine.run(component, options: PassOptions());

  // Save obfuscated kernel
  kernelIO.write(component, 'output.dill');
}

Binary Format

The .dill format is a binary serialization of the Dart kernel AST:

Compact

Efficient binary representation of the AST

Portable

Platform-independent bytecode format

Fast Loading

Faster than parsing Dart source code

Complete

Contains all program information

Error Handling

FileKernelIO.load() will throw a FileIoException if the input file does not exist.
import 'package:refractor/src/engine/kernel/file_kernel_io.dart';
import 'package:refractor/src/exceptions/refractor_exception.dart';

try {
  final kernelIO = FileKernelIO();
  final component = kernelIO.load('missing.dill');
} on FileIoException catch (e) {
  print('Error loading kernel: $e');
}

See Also

Compiler

Compile Dart source to kernel format

RefractorEngine

Main obfuscation engine

PassRunner

Execute obfuscation passes on components

Build docs developers (and LLMs) love