-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
236 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
kt/aoc2024-exe/src/wasmWasiMain/kotlin/com/github/ephemient/aoc2024/exe/IO.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package com.github.ephemient.aoc2024.exe | ||
|
||
internal actual fun getDayInput(day: Int): String = readFile("/data/day$day.txt").decodeToString() |
39 changes: 39 additions & 0 deletions
39
kt/aoc2024-exe/src/wasmWasiMain/kotlin/com/github/ephemient/aoc2024/exe/WasiArgv.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.github.ephemient.aoc2024.exe | ||
|
||
import kotlin.wasm.unsafe.Pointer | ||
import kotlin.wasm.unsafe.UnsafeWasmMemoryApi | ||
import kotlin.wasm.unsafe.withScopedMemoryAllocator | ||
|
||
@WasmImport("wasi_snapshot_preview1", "args_sizes_get") | ||
private external fun argsSizesGet(argcPtr: UInt, bufsizPtr: UInt): Int | ||
|
||
@WasmImport("wasi_snapshot_preview1", "args_get") | ||
private external fun argsGet(argvPtr: UInt, argvBufPtr: UInt): Int | ||
|
||
@OptIn(UnsafeWasmMemoryApi::class) | ||
internal fun argv(): Array<String> { | ||
val argc: Int | ||
val bufsiz: Int | ||
withScopedMemoryAllocator { allocator -> | ||
val argcPtr = allocator.allocate(Int.SIZE_BYTES) | ||
val bufsizPtr = allocator.allocate(Int.SIZE_BYTES) | ||
val errno = argsSizesGet(argcPtr.address, bufsizPtr.address) | ||
check(errno == 0) { "args_sizes_get: $errno" } | ||
argc = argcPtr.loadInt() | ||
bufsiz = bufsizPtr.loadInt() | ||
} | ||
val buffer = ByteArray(bufsiz) | ||
return withScopedMemoryAllocator { allocator -> | ||
val argvPtr = allocator.allocate(argc * Int.SIZE_BYTES) | ||
val errno = argsGet(argvPtr.address, allocator.allocate(bufsiz).address) | ||
check(errno == 0) { "args_get: $errno" } | ||
Array(argc) { | ||
val argPtr = Pointer(argvPtr.plus(it * Int.SIZE_BYTES).loadInt().toUInt()) | ||
for (i in buffer.indices) { | ||
buffer[i] = argPtr.plus(i).loadByte() | ||
if (buffer[i] == 0.toByte()) return@Array buffer.decodeToString(endIndex = i) | ||
} | ||
error("missing \\0") | ||
} | ||
} | ||
} |
134 changes: 134 additions & 0 deletions
134
kt/aoc2024-exe/src/wasmWasiMain/kotlin/com/github/ephemient/aoc2024/exe/WasiFilesystem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package com.github.ephemient.aoc2024.exe | ||
|
||
import kotlin.wasm.unsafe.UnsafeWasmMemoryApi | ||
import kotlin.wasm.unsafe.withScopedMemoryAllocator | ||
|
||
@WasmImport("wasi_snapshot_preview1", "fd_prestat_get") | ||
private external fun fdPrestatGet(fd: Int, prestat: UInt): Int | ||
|
||
@WasmImport("wasi_snapshot_preview1", "fd_prestat_dir_name") | ||
private external fun fdPrestatDirName(fd: Int, path: UInt, pathLen: Int): Int | ||
|
||
@OptIn(UnsafeWasmMemoryApi::class) | ||
private val preloadedFds = buildMap { | ||
withScopedMemoryAllocator { allocator -> | ||
val prestatPtr = allocator.allocate(8) | ||
|
||
var fd = 3 | ||
while (true) { | ||
when (val errno = fdPrestatGet(fd, prestatPtr.address)) { | ||
8 -> break // errno.badf | ||
0 -> {} // errno.success | ||
else -> error("fd_prestat_get: $errno") | ||
} | ||
when (val prestatTag = prestatPtr.loadByte()) { | ||
0.toByte() -> { // preopentype.dir | ||
val prNameLen = prestatPtr.plus(Int.SIZE_BYTES).loadInt() | ||
val dirName = withScopedMemoryAllocator { allocator -> | ||
val pathPtr = allocator.allocate(prNameLen) | ||
val errno = fdPrestatDirName(fd, pathPtr.address, prNameLen) | ||
check(errno == 0) { "fd_prestat_dir_name: $errno" } | ||
ByteArray(prNameLen) { pathPtr.plus(it).loadByte() } | ||
}.decodeToString() | ||
put(dirName.removeSuffix("/") + "/", fd) | ||
} | ||
else -> error("unknown propentype $prestatTag") | ||
} | ||
fd++ | ||
} | ||
} | ||
} | ||
|
||
@WasmImport("wasi_snapshot_preview1", "path_open") | ||
private external fun pathOpen( | ||
fd: Int, | ||
dirflags: Int, | ||
path: UInt, | ||
pathLen: Int, | ||
oflags: Short, | ||
fsRightsBase: Long, | ||
fsRightsInheriting: Long, | ||
fdflags: Short, | ||
fdPtr: UInt, | ||
): Int | ||
|
||
@WasmImport("wasi_snapshot_preview1", "fd_filestat_get") | ||
private external fun fdFilestatGet(fd: Int, filestat: UInt): Int | ||
|
||
@WasmImport("wasi_snapshot_preview1", "fd_seek") | ||
private external fun fdSeek(fd: Int, offset: Long, whence: Byte, filesize: UInt): Int | ||
|
||
@WasmImport("wasi_snapshot_preview1", "fd_pread") | ||
private external fun fdPread(fd: Int, iovsPtr: UInt, iovs: Int, offset: Long, sizePtr: UInt): Int | ||
|
||
@WasmImport("wasi_snapshot_preview1", "fd_close") | ||
private external fun fdClose(fd: Int): Int | ||
|
||
// fd_read + fd_seek + fd_filestat_get | ||
private const val READ_RIGHTS = 0x200006L | ||
private const val BUFSIZ = 4096 | ||
|
||
@OptIn(UnsafeWasmMemoryApi::class) | ||
internal fun readFile(path: String): ByteArray { | ||
val (prefix, dirfd) = checkNotNull( | ||
preloadedFds.filterKeys(path::startsWith).maxByOrNull { it.key.length } | ||
) { "file not found: $path" } | ||
val fd = withScopedMemoryAllocator { allocator -> | ||
val pathBytes = path.removePrefix(prefix).encodeToByteArray() | ||
val pathPtr = allocator.allocate(pathBytes.size) | ||
for ((i, b) in pathBytes.withIndex()) pathPtr.plus(i).storeByte(b) | ||
val fdPtr = allocator.allocate(Int.SIZE_BYTES) | ||
// fsRightsBase = fd_read + fd_seek + fd_tell + fd_filestat_get | ||
val errno = pathOpen(dirfd, 1, pathPtr.address, pathBytes.size, 0, READ_RIGHTS, 0, 0, fdPtr.address) | ||
check(errno == 0) { "path_open: $errno" } | ||
fdPtr.loadInt() | ||
} | ||
try { | ||
var size = 0UL | ||
if (size == 0UL) withScopedMemoryAllocator { allocator -> | ||
val filestatPtr = allocator.allocate(8 * Long.SIZE_BYTES) | ||
val errno = fdFilestatGet(fd, filestatPtr.address) | ||
if (errno == 0) size = filestatPtr.plus(4 * Long.SIZE_BYTES).loadLong().toULong() | ||
} | ||
if (size == 0UL) withScopedMemoryAllocator { allocator -> | ||
val filesizePtr = allocator.allocate(Long.SIZE_BYTES) | ||
val errno = fdSeek(fd, 0, 2, filesizePtr.address) | ||
if (errno == 0) size = filesizePtr.loadLong().toULong() | ||
} | ||
withScopedMemoryAllocator { allocator -> | ||
val iovsPtr = allocator.allocate(Long.SIZE_BYTES) | ||
val sizePtr = allocator.allocate(Long.SIZE_BYTES) | ||
var offset = 0UL | ||
val buffers = buildList { | ||
var bufsiz = if (size in 1UL..Int.MAX_VALUE.toULong()) size.toInt() else BUFSIZ | ||
while (true) { | ||
val bufferPtr = allocator.allocate(bufsiz) | ||
iovsPtr.storeInt(bufferPtr.address.toInt()) | ||
iovsPtr.plus(Int.SIZE_BYTES).storeInt(bufsiz) | ||
var errno: Int | ||
do { | ||
errno = fdPread(fd, iovsPtr.address, 1, offset.toLong(), sizePtr.address) | ||
} while (errno == 6) // errno.again | ||
check(errno == 0) { "fd_pread: $errno" } | ||
val size = sizePtr.loadLong().toULong() | ||
check(size <= bufsiz.toULong()) { "fd_read: $size > $bufsiz" } | ||
if (size == 0UL) break | ||
add(bufferPtr to size.toInt()) | ||
offset += size | ||
bufsiz = BUFSIZ | ||
check(offset <= Int.MAX_VALUE.toULong()) { "readFile: 22" } | ||
} | ||
} | ||
val buffer = ByteArray(offset.toInt()) | ||
buffers.fold(0) { acc, (bufferPtr, size) -> | ||
repeat(size) { | ||
buffer[acc + it] = bufferPtr.plus(it).loadByte() | ||
} | ||
acc + size | ||
} | ||
return buffer | ||
} | ||
} finally { | ||
fdClose(fd) | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
kt/aoc2024-exe/src/wasmWasiMain/kotlin/com/github/ephemient/aoc2024/exe/WasmWasiMain.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.github.ephemient.aoc2024.exe | ||
|
||
suspend fun main() { | ||
val argv = argv() | ||
mainImpl(argv.copyOfRange(2, argv.size)) | ||
} |