or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdarrays-runtime.mdc-interop.mdindex.mdmemory-management.mdunsigned-types.md

arrays-runtime.mddocs/

0

# Native Arrays and Runtime

1

2

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.

3

4

## Native Array Types

5

6

### Base Array Class

7

8

```scala { .api }

9

sealed abstract class Array[T] {

10

def length: Int

11

def stride: Int

12

def at(i: Int): Ptr[T]

13

def atUnsafe(i: Int): Ptr[T]

14

def apply(i: Int): T

15

def update(i: Int, value: T): Unit

16

def clone(): Array[T]

17

}

18

```

19

20

**Array methods**:

21

- `length` - Number of elements in the array

22

- `stride` - Size in bytes of each element

23

- `at(i)` - Get pointer to element at index i (bounds checked)

24

- `atUnsafe(i)` - Get pointer to element at index i (no bounds checking)

25

- `apply(i)` - Read element at index i

26

- `update(i, value)` - Write element at index i

27

- `clone()` - Create a copy of the array

28

29

### Typed Array Classes

30

31

```scala { .api }

32

final class BooleanArray extends Array[Boolean]

33

final class CharArray extends Array[Char]

34

final class ByteArray extends Array[Byte]

35

final class ShortArray extends Array[Short]

36

final class IntArray extends Array[Int]

37

final class LongArray extends Array[Long]

38

final class FloatArray extends Array[Float]

39

final class DoubleArray extends Array[Double]

40

final class ObjectArray[T] extends Array[T]

41

```

42

43

### Array Companion Objects

44

45

Each array type provides allocation methods:

46

47

```scala { .api }

48

object BooleanArray {

49

def alloc(size: Int): BooleanArray

50

def snapshot(values: scala.Array[Boolean]): BooleanArray

51

}

52

53

object CharArray {

54

def alloc(size: Int): CharArray

55

def snapshot(values: scala.Array[Char]): CharArray

56

}

57

58

object ByteArray {

59

def alloc(size: Int): ByteArray

60

def snapshot(values: scala.Array[Byte]): ByteArray

61

}

62

63

object ShortArray {

64

def alloc(size: Int): ShortArray

65

def snapshot(values: scala.Array[Short]): ShortArray

66

}

67

68

object IntArray {

69

def alloc(size: Int): IntArray

70

def snapshot(values: scala.Array[Int]): IntArray

71

}

72

73

object LongArray {

74

def alloc(size: Int): LongArray

75

def snapshot(values: scala.Array[Long]): LongArray

76

}

77

78

object FloatArray {

79

def alloc(size: Int): FloatArray

80

def snapshot(values: scala.Array[Float]): FloatArray

81

}

82

83

object DoubleArray {

84

def alloc(size: Int): DoubleArray

85

def snapshot(values: scala.Array[Double]): DoubleArray

86

}

87

88

object ObjectArray {

89

def alloc[T](size: Int): ObjectArray[T]

90

def snapshot[T](values: scala.Array[T]): ObjectArray[T]

91

}

92

```

93

94

**Allocation methods**:

95

- `alloc(size)` - Allocate new array of given size

96

- `snapshot(values)` - Create native array from Scala array

97

98

### BlobArray

99

100

Special array type for conservative garbage collection:

101

102

```scala { .api }

103

final class BlobArray extends Array[Byte] {

104

def scannableLimit: Int

105

def withScannableLimit(limit: Int): BlobArray

106

}

107

108

object BlobArray {

109

def alloc(size: Int): BlobArray

110

def snapshot(values: scala.Array[Byte]): BlobArray

111

}

112

```

113

114

**BlobArray methods**:

115

- `scannableLimit` - Get limit for GC scanning (conservative collection)

116

- `withScannableLimit(limit)` - Set scanning limit for this array

117

118

## Runtime Services

119

120

### Garbage Collector Interface

121

122

Complete interface to the Boehm conservative garbage collector:

123

124

```scala { .api }

125

object GC {

126

// Heap statistics

127

def getInitHeapSize(): CSize

128

def getMaxHeapSize(): CSize

129

def getUsedHeapSize(): CSize

130

131

// Collection statistics

132

def getStatsCollectionTotal(): CSize

133

def getStatsCollectionDurationTotal(): CSize

134

135

// Manual collection

136

def collect(): Unit

137

138

// Thread registration and management

139

type ThreadStartRoutine = CFuncPtr1[ThreadRoutineArg, CVoidPtr]

140

type ThreadRoutineArg = CVoidPtr

141

142

// POSIX thread creation proxy (registers thread with GC)

143

def pthread_create(

144

thread: Ptr[CUnsignedLongInt],

145

attr: Ptr[CUnsignedLongLong],

146

startroutine: ThreadStartRoutine,

147

args: ThreadRoutineArg

148

): CInt

149

150

// Windows thread creation proxy (registers thread with GC)

151

def CreateThread(

152

threadAttributes: Ptr[CStruct3[CUnsignedInt, CVoidPtr, Boolean]],

153

stackSize: CSize,

154

startRoutine: ThreadStartRoutine,

155

routineArg: ThreadRoutineArg,

156

creationFlags: CUnsignedInt,

157

threadId: Ptr[CUnsignedInt]

158

): CVoidPtr

159

160

// Thread state management (cooperative GC)

161

object MutatorThreadState {

162

def Managed: CInt // Thread executing Scala Native code

163

def Unmanaged: CInt // Thread executing foreign/blocking code

164

}

165

166

// GC cooperation and synchronization

167

def setMutatorThreadState(newState: CInt): Unit

168

def `yield`(): Unit

169

def yieldPointTrap: RawPtr

170

171

// Root set management for external memory

172

def addRoots(addressLow: CVoidPtr, addressHigh: CVoidPtr): Unit

173

def removeRoots(addressLow: CVoidPtr, addressHigh: CVoidPtr): Unit

174

175

// Weak references callback support

176

type WeakReferencesCollectedCallback = CFuncPtr0[Unit]

177

def setWeakReferencesCollectedCallback(callback: WeakReferencesCollectedCallback): Unit

178

}

179

```

180

181

**GC heap statistics**:

182

- `getInitHeapSize()` - Initial heap size in bytes

183

- `getMaxHeapSize()` - Maximum heap size in bytes

184

- `getUsedHeapSize()` - Currently used heap size in bytes

185

186

**GC collection statistics**:

187

- `getStatsCollectionTotal()` - Total number of GC collections

188

- `getStatsCollectionDurationTotal()` - Total time spent in GC (nanoseconds)

189

190

**GC control**:

191

- `collect()` - Force garbage collection

192

- `setWeakReferencesCollectedCallback` - Set callback for weak reference cleanup

193

194

**Thread registration**:

195

- `pthread_create` - POSIX thread creation with GC registration

196

- `CreateThread` - Windows thread creation with GC registration

197

- Both proxies ensure threads are properly registered with garbage collector

198

199

**Thread cooperation**:

200

- `MutatorThreadState.Managed` - Thread executing managed Scala Native code

201

- `MutatorThreadState.Unmanaged` - Thread executing foreign/blocking operations

202

- `setMutatorThreadState` - Notify GC of thread state changes

203

- `yield` - Cooperative yield point for stop-the-world collection

204

- `yieldPointTrap` - Low-overhead trap-based yield point mechanism

205

206

**Root set management**:

207

- `addRoots` - Register external memory range for GC scanning

208

- `removeRoots` - Unregister external memory range from GC scanning

209

- Used for malloc'd memory containing GC pointers

210

211

### Runtime Information

212

213

Application and system information available at runtime:

214

215

```scala { .api }

216

// Package object scala.scalanative.runtime

217

def filename: String

218

def startTime: Long

219

def uptime: Long

220

221

// Pointer and size conversions

222

def fromRawPtr[T](rawptr: RawPtr): Ptr[T]

223

def toRawPtr[T](ptr: Ptr[T]): RawPtr

224

def fromRawSize(rawSize: RawSize): Size

225

def fromRawUSize(rawSize: RawSize): USize

226

def toRawSize(size: Size): RawSize

227

def toRawSize(size: USize): RawSize

228

229

// Monitor and synchronization support

230

def getMonitor(obj: Object): Monitor

231

def enterMonitor(obj: Object): Unit

232

def exitMonitor(obj: Object): Unit

233

234

// Stack overflow protection

235

object StackOverflowGuards {

236

def size: Int

237

def setup(isMainThread: Boolean): Unit

238

def reset(): Unit

239

def close(): Unit

240

}

241

242

// Runtime exception handling

243

def throwDivisionByZero(): Nothing

244

def throwClassCast(from: RawPtr, to: RawPtr): Nothing

245

def throwNullPointer(): Nothing

246

def throwUndefined(): Nothing

247

def throwOutOfBounds(i: Int, length: Int): Nothing

248

def throwNoSuchMethod(sig: String): Nothing

249

```

250

251

**Application information**:

252

- `filename` - Executable filename

253

- `startTime` - Application start time (milliseconds since epoch)

254

- `uptime` - Application uptime (milliseconds)

255

256

**Memory conversions**:

257

- `fromRawPtr` / `toRawPtr` - Convert between raw and typed pointers

258

- `fromRawSize` / `toRawSize` - Convert between raw and sized types

259

- `fromRawUSize` - Convert raw size to unsigned size

260

261

**Thread synchronization**:

262

- `getMonitor` - Get monitor object for synchronization

263

- `enterMonitor` / `exitMonitor` - Monitor entry/exit operations

264

- Available only in multithreading mode

265

266

**Stack overflow protection**:

267

- `StackOverflowGuards.size` - Size of stack guard region

268

- `StackOverflowGuards.setup` - Initialize stack overflow detection

269

- `StackOverflowGuards.reset` - Reset after stack overflow recovery

270

- `StackOverflowGuards.close` - Cleanup stack guards

271

272

**Runtime exception helpers**:

273

- `throwDivisionByZero` - Division by zero exception

274

- `throwClassCast` - Class cast exception with type information

275

- `throwNullPointer` - Null pointer exception

276

- `throwUndefined` - Undefined behavior error

277

- `throwOutOfBounds` - Array bounds exception

278

- `throwNoSuchMethod` - Reflection method not found

279

280

### Memory Intrinsics

281

282

Low-level memory operations (from `Intrinsics` object):

283

284

```scala { .api }

285

object Intrinsics {

286

// Stack allocation

287

def stackalloc[T](implicit tag: Tag[T]): Ptr[T]

288

def stackalloc[T](count: Int)(implicit tag: Tag[T]): Ptr[T]

289

def stackalloc[T](count: UInt)(implicit tag: Tag[T]): Ptr[T]

290

def stackalloc[T](count: ULong)(implicit tag: Tag[T]): Ptr[T]

291

def stackalloc[T](count: CSize)(implicit tag: Tag[T]): Ptr[T]

292

293

// Memory load operations

294

def loadBoolean(ptr: Ptr[Byte]): Boolean

295

def loadChar(ptr: Ptr[Byte]): Char

296

def loadByte(ptr: Ptr[Byte]): Byte

297

def loadShort(ptr: Ptr[Byte]): Short

298

def loadInt(ptr: Ptr[Byte]): Int

299

def loadLong(ptr: Ptr[Byte]): Long

300

def loadFloat(ptr: Ptr[Byte]): Float

301

def loadDouble(ptr: Ptr[Byte]): Double

302

def loadObject(ptr: Ptr[Byte]): Object

303

def loadRawPtr(ptr: Ptr[Byte]): RawPtr

304

def loadRawSize(ptr: Ptr[Byte]): RawSize

305

306

// Memory store operations

307

def storeBoolean(ptr: Ptr[Byte], value: Boolean): Unit

308

def storeChar(ptr: Ptr[Byte], value: Char): Unit

309

def storeByte(ptr: Ptr[Byte], value: Byte): Unit

310

def storeShort(ptr: Ptr[Byte], value: Short): Unit

311

def storeInt(ptr: Ptr[Byte], value: Int): Unit

312

def storeLong(ptr: Ptr[Byte], value: Long): Unit

313

def storeFloat(ptr: Ptr[Byte], value: Float): Unit

314

def storeDouble(ptr: Ptr[Byte], value: Double): Unit

315

def storeObject(ptr: Ptr[Byte], value: Object): Unit

316

def storeRawPtr(ptr: Ptr[Byte], value: RawPtr): Unit

317

def storeRawSize(ptr: Ptr[Byte], value: RawSize): Unit

318

319

// Unsigned arithmetic

320

def divUInt(l: UInt, r: UInt): UInt

321

def remUInt(l: UInt, r: UInt): UInt

322

def divULong(l: ULong, r: ULong): ULong

323

def remULong(l: ULong, r: ULong): ULong

324

325

// Type conversions

326

def byteToUInt(value: Byte): Int

327

def byteToULong(value: Byte): Long

328

def shortToUInt(value: Short): Int

329

def shortToULong(value: Short): Long

330

def intToULong(value: Int): Long

331

332

// Pointer arithmetic

333

def elemRawPtr(ptr: RawPtr, offset: RawSize): RawPtr

334

335

// Type casting

336

def castIntToFloat(value: Int): Float

337

def castFloatToInt(value: Float): Int

338

def castLongToDouble(value: Long): Double

339

def castDoubleToLong(value: Double): Long

340

def castRawPtrToObject(value: RawPtr): Object

341

def castObjectToRawPtr(value: Object): RawPtr

342

def castRawPtrToLong(value: RawPtr): Long

343

def castRawPtrToInt(value: RawPtr): Int

344

def castIntToRawPtr(value: Int): RawPtr

345

def castLongToRawPtr(value: Long): RawPtr

346

def castIntToRawSize(value: Int): RawSize

347

def castIntToRawSizeUnsigned(value: Int): RawSize

348

def castLongToRawSize(value: Long): RawSize

349

}

350

```

351

352

### Boxing Utilities

353

354

```scala { .api }

355

object Boxes {

356

// Unsigned type boxing

357

def boxToUByte(value: Byte): UByte

358

def boxToUShort(value: Short): UShort

359

def boxToUInt(value: Int): UInt

360

def boxToULong(value: Long): ULong

361

def boxToUSize(value: RawSize): USize

362

363

def unboxToUByte(value: UByte): Byte

364

def unboxToUShort(value: UShort): Short

365

def unboxToUInt(value: UInt): Int

366

def unboxToULong(value: ULong): Long

367

def unboxToUSize(value: USize): RawSize

368

369

// Pointer boxing

370

def boxToPtr[T](value: RawPtr): Ptr[T]

371

def unboxToPtr[T](value: Ptr[T]): RawPtr

372

373

// Size boxing

374

def boxToSize(value: RawSize): Size

375

def unboxToSize(value: Size): RawSize

376

}

377

```

378

379

## Usage Examples

380

381

### Native Array Usage

382

383

```scala

384

import scala.scalanative.runtime._

385

386

// Allocate arrays

387

val intArray = IntArray.alloc(100)

388

val doubleArray = DoubleArray.alloc(50)

389

390

// Initialize with values

391

for (i <- 0 until intArray.length) {

392

intArray(i) = i * i

393

}

394

395

// Access elements

396

val value = intArray(25) // Get element at index 25

397

intArray(30) = 900 // Set element at index 30

398

399

// Get pointers to elements

400

val ptr = intArray.at(10) // Pointer to element 10

401

val unsafePtr = intArray.atUnsafe(10) // No bounds checking

402

403

// Clone array

404

val copy = intArray.clone()

405

```

406

407

### Creating Arrays from Scala Arrays

408

409

```scala

410

import scala.scalanative.runtime._

411

412

// Convert Scala array to native array

413

val scalaArray = Array(1, 2, 3, 4, 5)

414

val nativeArray = IntArray.snapshot(scalaArray)

415

416

// Work with native array

417

nativeArray(0) = 10

418

val firstElement = nativeArray(0) // 10

419

420

// String array example

421

val strings = Array("hello", "world", "native")

422

val nativeStrings = ObjectArray.snapshot(strings)

423

val greeting = nativeStrings(0) // "hello"

424

```

425

426

### GC Integration

427

428

```scala

429

import scala.scalanative.runtime._

430

431

// Check heap status

432

val usedHeap = GC.getUsedHeapSize()

433

val maxHeap = GC.getMaxHeapSize()

434

435

println(s"Heap usage: ${usedHeap}/${maxHeap} bytes")

436

437

// Force garbage collection

438

GC.collect()

439

440

// Check collection statistics

441

val totalCollections = GC.getStatsCollectionTotal()

442

val totalDuration = GC.getStatsCollectionDurationTotal()

443

println(s"GC: ${totalCollections} collections, ${totalDuration} ns total")

444

```

445

446

### BlobArray for Conservative GC

447

448

```scala

449

import scala.scalanative.runtime._

450

451

// Allocate blob array (conservative GC scanning)

452

val blob = BlobArray.alloc(1024)

453

454

// Set scanning limit (only first 512 bytes scanned by GC)

455

val limitedBlob = blob.withScannableLimit(512)

456

457

// Use as regular byte array

458

blob(0) = 0x42.toByte

459

blob(1) = 0x24.toByte

460

461

val scannableLimit = limitedBlob.scannableLimit // 512

462

```

463

464

### Low-level Memory Operations

465

466

```scala

467

import scala.scalanative.runtime.Intrinsics._

468

import scala.scalanative.unsafe._

469

470

// Stack allocation (automatic cleanup)

471

def processData(): Unit = {

472

val buffer = stackalloc[CInt](256)

473

474

// Initialize buffer

475

var i = 0

476

while (i < 256) {

477

storeInt(buffer.asInstanceOf[Ptr[Byte]] + (i * 4), i)

478

i += 1

479

}

480

481

// Read values back

482

val value = loadInt(buffer.asInstanceOf[Ptr[Byte]] + (100 * 4)) // Get 100th element

483

484

// buffer automatically freed on function exit

485

}

486

487

// Pointer arithmetic

488

Zone.acquire { implicit z =>

489

val array = alloc[CInt](10)

490

val basePtr = toRawPtr(array)

491

492

// Move to 5th element (5 * sizeof(CInt))

493

val fifthPtr = elemRawPtr(basePtr, castIntToRawSize(5 * 4))

494

val typedPtr = fromRawPtr[CInt](fifthPtr)

495

496

!typedPtr = 42 // Set 5th element

497

}

498

```

499

500

### Runtime Information

501

502

```scala

503

import scala.scalanative.runtime._

504

505

// Get application info

506

val executableName = filename

507

val applicationStartTime = startTime

508

val runningTime = uptime

509

510

println(s"Running $executableName for ${runningTime}ms")

511

512

// Convert between pointer types

513

Zone.acquire { implicit z =>

514

val ptr = alloc[CInt]

515

val rawPtr = toRawPtr(ptr)

516

val backToTyped = fromRawPtr[CInt](rawPtr)

517

518

// Size conversions

519

val size = Size.valueOf(1024)

520

val rawSize = toRawSize(size)

521

val backToSize = fromRawSize(rawSize)

522

}

523

```

524

525

## Performance Considerations

526

527

1. **Use native arrays** for performance-critical code - they avoid boxing overhead

528

2. **Prefer atUnsafe** when bounds are already checked - eliminates redundant checks

529

3. **Stack allocation** is faster than heap allocation for temporary buffers

530

4. **BlobArray scanning limits** can improve GC performance for large binary data

531

5. **Manual GC control** can help with predictable latency requirements

532

6. **Clone sparingly** - creates full copies, can be expensive for large arrays

533

534

## Best Practices

535

536

1. **Choose appropriate array types** - use primitive arrays when possible

537

2. **Handle GC pressure** - monitor heap usage in allocation-heavy code

538

3. **Use snapshot carefully** - creates copies, consider sharing when possible

539

4. **Stack allocate temporary data** - automatic cleanup and better performance

540

5. **Set blob limits appropriately** - balance GC scanning cost vs precision

541

6. **Profile GC behavior** - use statistics to tune collection strategy