NIFs and BIFs
Relevant source files
The following files were used as context for generating this wiki page:
Native Implemented Functions (NIFs) and Built-In Functions (BIFs) are the primary mechanisms AtomVM uses to execute native C code from within the Erlang virtual machine environment. While BIFs are integrated into the core instruction set and often handle fundamental language operations, NIFs provide a standard way to extend the VM's functionality with platform-specific or performance-critical logic.
In the AtomVM architecture, these native functions bridge the gap between high-level BEAM bytecode and the underlying hardware or operating system. They are essential for interfacing with peripherals like GPIO, I2C, and UART, as well as providing core services like process management, mathematics, and networking protocols.
Sources: doc/src/atomvm-internals.md:21-30, src/libAtomVM/exportedfunction.h:48-60
Architecture and Function Dispatch
AtomVM classifies native functions into several types based on how they are invoked and whether they interact with the garbage collector. The system uses a dispatch mechanism that identifies functions by their Module:Function/Arity (MFA) signature.
Function Type Classification
The VM distinguishes between standard NIFs, BIFs, and specialized GC-aware BIFs through the FunctionType enumeration.
| Function Type | Enumeration Value | Description |
|---|---|---|
NIFFunctionType | 2 | Standard NIF returning a term. |
BIFFunctionType | 5 | Built-in function with fixed arity (0, 1, or 2). |
GCBIFFunctionType | 6 | BIFs that may trigger GC and require "live" register counts. |
ModuleNativeFunction | 7 | Functions executed natively by the JIT backend. |
Sources: src/libAtomVM/exportedfunction.h:48-60, src/libAtomVM/nifs.c:1300-1310
Native Dispatch Flow
When the VM encounters a call to a native function, it uses a lookup table (often generated via gperf) to find the corresponding C implementation.
The dispatch logic first checks for BIFs, then NIFs, and finally searches for exported functions in loaded BEAM modules.
Sources: src/libAtomVM/nifs.c:1290-1315, src/libAtomVM/exportedfunction.h:95-110
Implementation of NIFs
Standard NIFs follow a specific signature: term NifImpl(Context *ctx, int argc, term argv[]). This allows them to receive an arbitrary number of arguments and return a valid Erlang term or an exception.
Argument Validation
NIFs frequently use macros to validate inputs and raise Erlang exceptions if the types do not match.
VALIDATE_ARG: Ensures an argument at a specific index matches a predicate (e.g.,term_is_integer).RAISE_ERROR: Sets the exception class toERROR_ATOMand sets the reason (typicallyBADARG_ATOM).
Sources: src/libAtomVM/nifs.h:38-50, src/libAtomVM/nifs.c:100-125
Memory Management in NIFs
Because NIFs can allocate memory on the process heap, they must ensure sufficient space exists before creating new terms. If allocation fails, they may trigger garbage collection or return an OUT_OF_MEMORY_ATOM.
if (UNLIKELY(memory_ensure_free_opt(ctx, REF_SIZE, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
Sources: src/libAtomVM/nifs.c:1410-1415, doc/src/atomvm-internals.md:450-465
Platform and Hardware NIFs
AtomVM provides platform-specific NIFs to handle features unique to certain environments, such as the Emscripten/WebAssembly port.
Emscripten Specific NIFs
The Emscripten port implements NIFs for interacting with the browser's JavaScript environment and HTML5 APIs.
| Module | Function | Description |
|---|---|---|
emscripten | run_script/1,2 | Executes a JavaScript string on the main thread or worker. |
emscripten | promise_resolve/2 | Resolves a JS Promise from an Erlang process. |
websocket | new/3 | Opens a new HTML5 WebSocket connection. |
Sources: src/platforms/emscripten/src/lib/platform_nifs.c:60-100, src/platforms/emscripten/src/lib/websocket_nifs.c:230-250
HTML5 Event Handling
AtomVM uses a resource-based approach to map browser events (like click or keydown) back to Erlang processes.
The callback function (e.g., html5api_mouse_callback) converts the browser's event structure into an Erlang map and enqueues it to the target process's mailbox using sys_enqueue_emscripten_htmlevent_message.
Sources: src/platforms/emscripten/src/lib/platform_nifs.c:300-350, src/platforms/emscripten/src/lib/platform_nifs.c:450-480
Built-In Functions (BIFs)
BIFs are core functions integrated directly into the VM. In AtomVM, these are often defined in bif.c and registered in a global BIF table. They handle essential tasks such as:
- Process Spawning:
erlang:spawn_opt/4handles the creation of newContextstructures and stack initialization. - Arithmetic: Core math operations that are too complex for simple opcodes.
- Term Comparison: Functions for checking equality or ordering of complex data structures.
Sources: src/libAtomVM/nifs.c:500-550, src/libAtomVM/exportedfunction.h:35-45
Process Management via NIFs
The spawn family of functions illustrates how NIFs interact with the VM scheduler. When do_spawn is called, it allocates a new Context, copies arguments to the new heap, and initializes the instruction pointer (saved_ip) or native entry point.
Conclusion
NIFs and BIFs are fundamental to the extensibility and core operations of AtomVM. By providing a structured interface for C-Erlang interaction, AtomVM allows for highly optimized implementations of standard library functions and seamless integration with hardware-level features on constrained IoT devices. Whether through the generic NIF interface or platform-specific extensions like the Emscripten HTML5 integration, these native components ensure the VM remains both functional and performant.