Native interoperability library for Scala Native providing unsafe operations, C-style data types, and memory management primitives for direct interaction with native code
—
Scala Native provides high-performance native array types optimized for native code generation, along with runtime utilities for garbage collection, memory intrinsics, and system integration.
sealed abstract class Array[T] {
def length: Int
def stride: Int
def at(i: Int): Ptr[T]
def atUnsafe(i: Int): Ptr[T]
def apply(i: Int): T
def update(i: Int, value: T): Unit
def clone(): Array[T]
}Array methods:
length - Number of elements in the arraystride - Size in bytes of each elementat(i) - Get pointer to element at index i (bounds checked)atUnsafe(i) - Get pointer to element at index i (no bounds checking)apply(i) - Read element at index iupdate(i, value) - Write element at index iclone() - Create a copy of the arrayfinal class BooleanArray extends Array[Boolean]
final class CharArray extends Array[Char]
final class ByteArray extends Array[Byte]
final class ShortArray extends Array[Short]
final class IntArray extends Array[Int]
final class LongArray extends Array[Long]
final class FloatArray extends Array[Float]
final class DoubleArray extends Array[Double]
final class ObjectArray[T] extends Array[T]Each array type provides allocation methods:
object BooleanArray {
def alloc(size: Int): BooleanArray
def snapshot(values: scala.Array[Boolean]): BooleanArray
}
object CharArray {
def alloc(size: Int): CharArray
def snapshot(values: scala.Array[Char]): CharArray
}
object ByteArray {
def alloc(size: Int): ByteArray
def snapshot(values: scala.Array[Byte]): ByteArray
}
object ShortArray {
def alloc(size: Int): ShortArray
def snapshot(values: scala.Array[Short]): ShortArray
}
object IntArray {
def alloc(size: Int): IntArray
def snapshot(values: scala.Array[Int]): IntArray
}
object LongArray {
def alloc(size: Int): LongArray
def snapshot(values: scala.Array[Long]): LongArray
}
object FloatArray {
def alloc(size: Int): FloatArray
def snapshot(values: scala.Array[Float]): FloatArray
}
object DoubleArray {
def alloc(size: Int): DoubleArray
def snapshot(values: scala.Array[Double]): DoubleArray
}
object ObjectArray {
def alloc[T](size: Int): ObjectArray[T]
def snapshot[T](values: scala.Array[T]): ObjectArray[T]
}Allocation methods:
alloc(size) - Allocate new array of given sizesnapshot(values) - Create native array from Scala arraySpecial array type for conservative garbage collection:
final class BlobArray extends Array[Byte] {
def scannableLimit: Int
def withScannableLimit(limit: Int): BlobArray
}
object BlobArray {
def alloc(size: Int): BlobArray
def snapshot(values: scala.Array[Byte]): BlobArray
}BlobArray methods:
scannableLimit - Get limit for GC scanning (conservative collection)withScannableLimit(limit) - Set scanning limit for this arrayComplete interface to the Boehm conservative garbage collector:
object GC {
// Heap statistics
def getInitHeapSize(): CSize
def getMaxHeapSize(): CSize
def getUsedHeapSize(): CSize
// Collection statistics
def getStatsCollectionTotal(): CSize
def getStatsCollectionDurationTotal(): CSize
// Manual collection
def collect(): Unit
// Thread registration and management
type ThreadStartRoutine = CFuncPtr1[ThreadRoutineArg, CVoidPtr]
type ThreadRoutineArg = CVoidPtr
// POSIX thread creation proxy (registers thread with GC)
def pthread_create(
thread: Ptr[CUnsignedLongInt],
attr: Ptr[CUnsignedLongLong],
startroutine: ThreadStartRoutine,
args: ThreadRoutineArg
): CInt
// Windows thread creation proxy (registers thread with GC)
def CreateThread(
threadAttributes: Ptr[CStruct3[CUnsignedInt, CVoidPtr, Boolean]],
stackSize: CSize,
startRoutine: ThreadStartRoutine,
routineArg: ThreadRoutineArg,
creationFlags: CUnsignedInt,
threadId: Ptr[CUnsignedInt]
): CVoidPtr
// Thread state management (cooperative GC)
object MutatorThreadState {
def Managed: CInt // Thread executing Scala Native code
def Unmanaged: CInt // Thread executing foreign/blocking code
}
// GC cooperation and synchronization
def setMutatorThreadState(newState: CInt): Unit
def `yield`(): Unit
def yieldPointTrap: RawPtr
// Root set management for external memory
def addRoots(addressLow: CVoidPtr, addressHigh: CVoidPtr): Unit
def removeRoots(addressLow: CVoidPtr, addressHigh: CVoidPtr): Unit
// Weak references callback support
type WeakReferencesCollectedCallback = CFuncPtr0[Unit]
def setWeakReferencesCollectedCallback(callback: WeakReferencesCollectedCallback): Unit
}GC heap statistics:
getInitHeapSize() - Initial heap size in bytesgetMaxHeapSize() - Maximum heap size in bytesgetUsedHeapSize() - Currently used heap size in bytesGC collection statistics:
getStatsCollectionTotal() - Total number of GC collectionsgetStatsCollectionDurationTotal() - Total time spent in GC (nanoseconds)GC control:
collect() - Force garbage collectionsetWeakReferencesCollectedCallback - Set callback for weak reference cleanupThread registration:
pthread_create - POSIX thread creation with GC registrationCreateThread - Windows thread creation with GC registrationThread cooperation:
MutatorThreadState.Managed - Thread executing managed Scala Native codeMutatorThreadState.Unmanaged - Thread executing foreign/blocking operationssetMutatorThreadState - Notify GC of thread state changesyield - Cooperative yield point for stop-the-world collectionyieldPointTrap - Low-overhead trap-based yield point mechanismRoot set management:
addRoots - Register external memory range for GC scanningremoveRoots - Unregister external memory range from GC scanningApplication and system information available at runtime:
// Package object scala.scalanative.runtime
def filename: String
def startTime: Long
def uptime: Long
// Pointer and size conversions
def fromRawPtr[T](rawptr: RawPtr): Ptr[T]
def toRawPtr[T](ptr: Ptr[T]): RawPtr
def fromRawSize(rawSize: RawSize): Size
def fromRawUSize(rawSize: RawSize): USize
def toRawSize(size: Size): RawSize
def toRawSize(size: USize): RawSize
// Monitor and synchronization support
def getMonitor(obj: Object): Monitor
def enterMonitor(obj: Object): Unit
def exitMonitor(obj: Object): Unit
// Stack overflow protection
object StackOverflowGuards {
def size: Int
def setup(isMainThread: Boolean): Unit
def reset(): Unit
def close(): Unit
}
// Runtime exception handling
def throwDivisionByZero(): Nothing
def throwClassCast(from: RawPtr, to: RawPtr): Nothing
def throwNullPointer(): Nothing
def throwUndefined(): Nothing
def throwOutOfBounds(i: Int, length: Int): Nothing
def throwNoSuchMethod(sig: String): NothingApplication information:
filename - Executable filenamestartTime - Application start time (milliseconds since epoch)uptime - Application uptime (milliseconds)Memory conversions:
fromRawPtr / toRawPtr - Convert between raw and typed pointersfromRawSize / toRawSize - Convert between raw and sized typesfromRawUSize - Convert raw size to unsigned sizeThread synchronization:
getMonitor - Get monitor object for synchronizationenterMonitor / exitMonitor - Monitor entry/exit operationsStack overflow protection:
StackOverflowGuards.size - Size of stack guard regionStackOverflowGuards.setup - Initialize stack overflow detectionStackOverflowGuards.reset - Reset after stack overflow recoveryStackOverflowGuards.close - Cleanup stack guardsRuntime exception helpers:
throwDivisionByZero - Division by zero exceptionthrowClassCast - Class cast exception with type informationthrowNullPointer - Null pointer exceptionthrowUndefined - Undefined behavior errorthrowOutOfBounds - Array bounds exceptionthrowNoSuchMethod - Reflection method not foundLow-level memory operations (from Intrinsics object):
object Intrinsics {
// Stack allocation
def stackalloc[T](implicit tag: Tag[T]): Ptr[T]
def stackalloc[T](count: Int)(implicit tag: Tag[T]): Ptr[T]
def stackalloc[T](count: UInt)(implicit tag: Tag[T]): Ptr[T]
def stackalloc[T](count: ULong)(implicit tag: Tag[T]): Ptr[T]
def stackalloc[T](count: CSize)(implicit tag: Tag[T]): Ptr[T]
// Memory load operations
def loadBoolean(ptr: Ptr[Byte]): Boolean
def loadChar(ptr: Ptr[Byte]): Char
def loadByte(ptr: Ptr[Byte]): Byte
def loadShort(ptr: Ptr[Byte]): Short
def loadInt(ptr: Ptr[Byte]): Int
def loadLong(ptr: Ptr[Byte]): Long
def loadFloat(ptr: Ptr[Byte]): Float
def loadDouble(ptr: Ptr[Byte]): Double
def loadObject(ptr: Ptr[Byte]): Object
def loadRawPtr(ptr: Ptr[Byte]): RawPtr
def loadRawSize(ptr: Ptr[Byte]): RawSize
// Memory store operations
def storeBoolean(ptr: Ptr[Byte], value: Boolean): Unit
def storeChar(ptr: Ptr[Byte], value: Char): Unit
def storeByte(ptr: Ptr[Byte], value: Byte): Unit
def storeShort(ptr: Ptr[Byte], value: Short): Unit
def storeInt(ptr: Ptr[Byte], value: Int): Unit
def storeLong(ptr: Ptr[Byte], value: Long): Unit
def storeFloat(ptr: Ptr[Byte], value: Float): Unit
def storeDouble(ptr: Ptr[Byte], value: Double): Unit
def storeObject(ptr: Ptr[Byte], value: Object): Unit
def storeRawPtr(ptr: Ptr[Byte], value: RawPtr): Unit
def storeRawSize(ptr: Ptr[Byte], value: RawSize): Unit
// Unsigned arithmetic
def divUInt(l: UInt, r: UInt): UInt
def remUInt(l: UInt, r: UInt): UInt
def divULong(l: ULong, r: ULong): ULong
def remULong(l: ULong, r: ULong): ULong
// Type conversions
def byteToUInt(value: Byte): Int
def byteToULong(value: Byte): Long
def shortToUInt(value: Short): Int
def shortToULong(value: Short): Long
def intToULong(value: Int): Long
// Pointer arithmetic
def elemRawPtr(ptr: RawPtr, offset: RawSize): RawPtr
// Type casting
def castIntToFloat(value: Int): Float
def castFloatToInt(value: Float): Int
def castLongToDouble(value: Long): Double
def castDoubleToLong(value: Double): Long
def castRawPtrToObject(value: RawPtr): Object
def castObjectToRawPtr(value: Object): RawPtr
def castRawPtrToLong(value: RawPtr): Long
def castRawPtrToInt(value: RawPtr): Int
def castIntToRawPtr(value: Int): RawPtr
def castLongToRawPtr(value: Long): RawPtr
def castIntToRawSize(value: Int): RawSize
def castIntToRawSizeUnsigned(value: Int): RawSize
def castLongToRawSize(value: Long): RawSize
}object Boxes {
// Unsigned type boxing
def boxToUByte(value: Byte): UByte
def boxToUShort(value: Short): UShort
def boxToUInt(value: Int): UInt
def boxToULong(value: Long): ULong
def boxToUSize(value: RawSize): USize
def unboxToUByte(value: UByte): Byte
def unboxToUShort(value: UShort): Short
def unboxToUInt(value: UInt): Int
def unboxToULong(value: ULong): Long
def unboxToUSize(value: USize): RawSize
// Pointer boxing
def boxToPtr[T](value: RawPtr): Ptr[T]
def unboxToPtr[T](value: Ptr[T]): RawPtr
// Size boxing
def boxToSize(value: RawSize): Size
def unboxToSize(value: Size): RawSize
}import scala.scalanative.runtime._
// Allocate arrays
val intArray = IntArray.alloc(100)
val doubleArray = DoubleArray.alloc(50)
// Initialize with values
for (i <- 0 until intArray.length) {
intArray(i) = i * i
}
// Access elements
val value = intArray(25) // Get element at index 25
intArray(30) = 900 // Set element at index 30
// Get pointers to elements
val ptr = intArray.at(10) // Pointer to element 10
val unsafePtr = intArray.atUnsafe(10) // No bounds checking
// Clone array
val copy = intArray.clone()import scala.scalanative.runtime._
// Convert Scala array to native array
val scalaArray = Array(1, 2, 3, 4, 5)
val nativeArray = IntArray.snapshot(scalaArray)
// Work with native array
nativeArray(0) = 10
val firstElement = nativeArray(0) // 10
// String array example
val strings = Array("hello", "world", "native")
val nativeStrings = ObjectArray.snapshot(strings)
val greeting = nativeStrings(0) // "hello"import scala.scalanative.runtime._
// Check heap status
val usedHeap = GC.getUsedHeapSize()
val maxHeap = GC.getMaxHeapSize()
println(s"Heap usage: ${usedHeap}/${maxHeap} bytes")
// Force garbage collection
GC.collect()
// Check collection statistics
val totalCollections = GC.getStatsCollectionTotal()
val totalDuration = GC.getStatsCollectionDurationTotal()
println(s"GC: ${totalCollections} collections, ${totalDuration} ns total")import scala.scalanative.runtime._
// Allocate blob array (conservative GC scanning)
val blob = BlobArray.alloc(1024)
// Set scanning limit (only first 512 bytes scanned by GC)
val limitedBlob = blob.withScannableLimit(512)
// Use as regular byte array
blob(0) = 0x42.toByte
blob(1) = 0x24.toByte
val scannableLimit = limitedBlob.scannableLimit // 512import scala.scalanative.runtime.Intrinsics._
import scala.scalanative.unsafe._
// Stack allocation (automatic cleanup)
def processData(): Unit = {
val buffer = stackalloc[CInt](256)
// Initialize buffer
var i = 0
while (i < 256) {
storeInt(buffer.asInstanceOf[Ptr[Byte]] + (i * 4), i)
i += 1
}
// Read values back
val value = loadInt(buffer.asInstanceOf[Ptr[Byte]] + (100 * 4)) // Get 100th element
// buffer automatically freed on function exit
}
// Pointer arithmetic
Zone.acquire { implicit z =>
val array = alloc[CInt](10)
val basePtr = toRawPtr(array)
// Move to 5th element (5 * sizeof(CInt))
val fifthPtr = elemRawPtr(basePtr, castIntToRawSize(5 * 4))
val typedPtr = fromRawPtr[CInt](fifthPtr)
!typedPtr = 42 // Set 5th element
}import scala.scalanative.runtime._
// Get application info
val executableName = filename
val applicationStartTime = startTime
val runningTime = uptime
println(s"Running $executableName for ${runningTime}ms")
// Convert between pointer types
Zone.acquire { implicit z =>
val ptr = alloc[CInt]
val rawPtr = toRawPtr(ptr)
val backToTyped = fromRawPtr[CInt](rawPtr)
// Size conversions
val size = Size.valueOf(1024)
val rawSize = toRawSize(size)
val backToSize = fromRawSize(rawSize)
}Install with Tessl CLI
npx tessl i tessl/maven-org-scala-native--nativelib-native0-5-3