[Wasm] Wasi stdlib implementation
KT-56608
This commit is contained in:
committed by
Zalim Bashorov
parent
090f393f97
commit
8cc0660693
@@ -1,4 +1,6 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetAttribute
|
||||
import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink
|
||||
|
||||
@@ -81,14 +83,20 @@ kotlin {
|
||||
@Suppress("DEPRECATION")
|
||||
@OptIn(org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl::class)
|
||||
wasm("wasm") {
|
||||
d8()
|
||||
nodejs()
|
||||
}
|
||||
|
||||
fun KotlinSourceSet.addWasmMainDirs() {
|
||||
kotlin.srcDirs("builtins", "internal", "runtime", "src", "stubs")
|
||||
kotlin.srcDirs("$rootDir/libraries/stdlib/native-wasm/src")
|
||||
kotlin.srcDirs(files(builtInsSources.map { it.destinationDir }))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
named("wasmMain") {
|
||||
kotlin.srcDirs("builtins", "internal", "runtime", "src", "stubs")
|
||||
kotlin.srcDirs("$rootDir/libraries/stdlib/native-wasm/src")
|
||||
kotlin.srcDirs(files(builtInsSources.map { it.destinationDir }))
|
||||
addWasmMainDirs()
|
||||
// kotlin.srcDirs("js/builtins/kotlin", "js/internal", "js/src/kotlin", "js/src/kotlinx", "js/src/org.w3c")
|
||||
kotlin.srcDirs("wasi/builtins/kotlin", "wasi/internal", "wasi/src/kotlin", "wasi/src/kotlinx")
|
||||
}
|
||||
|
||||
named("commonMain") {
|
||||
@@ -153,8 +161,17 @@ val compileTestDevelopmentExecutableKotlinWasm = tasks.named<KotlinJsIrLink>("co
|
||||
(this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += listOf("-Xwasm-enable-array-range-checks")
|
||||
}
|
||||
|
||||
val runtimeElements by configurations.creating {}
|
||||
val apiElements by configurations.creating {}
|
||||
val runtimeElements by configurations.creating {
|
||||
attributes {
|
||||
attributes.attribute(KotlinWasmTargetAttribute.wasmTargetAttribute, KotlinWasmTargetAttribute.js)
|
||||
}
|
||||
}
|
||||
|
||||
val apiElements by configurations.creating {
|
||||
attributes {
|
||||
attributes.attribute(KotlinWasmTargetAttribute.wasmTargetAttribute, KotlinWasmTargetAttribute.js)
|
||||
}
|
||||
}
|
||||
|
||||
publish(sbom = false) {
|
||||
pom.packaging = "klib"
|
||||
|
||||
@@ -3,50 +3,4 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.ExternalInterfaceType
|
||||
import kotlin.wasm.internal.getSimpleName
|
||||
import kotlin.wasm.internal.jsToKotlinStringAdapter
|
||||
|
||||
/**
|
||||
* The base class for all errors and exceptions. Only instances of this class can be thrown or caught.
|
||||
*
|
||||
* @param message the detail message string.
|
||||
* @param cause the cause of this throwable.
|
||||
*/
|
||||
public open class Throwable(open val message: String?, open val cause: kotlin.Throwable?) {
|
||||
constructor(message: String?) : this(message, null)
|
||||
|
||||
constructor(cause: Throwable?) : this(cause?.toString(), cause)
|
||||
|
||||
constructor() : this(null, null)
|
||||
|
||||
internal val jsStack: ExternalInterfaceType = captureStackTrace()
|
||||
|
||||
private var _stack: String? = null
|
||||
internal val stack: String
|
||||
get() {
|
||||
var value = _stack
|
||||
if (value == null) {
|
||||
value = jsToKotlinStringAdapter(jsStack).removePrefix("Error\n")
|
||||
_stack = value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
internal var suppressedExceptionsList: MutableList<Throwable>? = null
|
||||
|
||||
/**
|
||||
* Returns the short description of this throwable consisting of the exception class name
|
||||
* followed by the exception message if it is not null.
|
||||
*/
|
||||
public override fun toString(): String {
|
||||
val s = getSimpleName(this.typeInfo)
|
||||
return if (message != null) s + ": " + message.toString() else s
|
||||
}
|
||||
}
|
||||
|
||||
private fun captureStackTrace(): ExternalInterfaceType =
|
||||
js("new Error().stack")
|
||||
package kotlin
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.wasm.internal
|
||||
|
||||
internal var isNotFirstWasmExportCall: Boolean = false
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.wasm.internal
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@ExcludedFromCodegen
|
||||
/*
|
||||
* Compiler generates inplace next code:
|
||||
* ```
|
||||
* block (result anyref) {
|
||||
* local.get 0
|
||||
* extern.internalize
|
||||
* br_on_cast_fail 0000_0011b 0 (type any) (type $kotlin.Any)
|
||||
* return
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
internal fun returnArgumentIfItIsKotlinAny(): Unit = implementedAsIntrinsic
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
package kotlin.wasm.internal
|
||||
|
||||
import kotlin.wasm.internal.ExternalInterfaceType
|
||||
|
||||
@WasmOp(WasmOp.UNREACHABLE)
|
||||
internal fun wasm_unreachable(): Nothing =
|
||||
implementedAsIntrinsic
|
||||
@@ -495,10 +493,4 @@ internal fun wasm_i64_popcnt(a: Long): Long =
|
||||
@PublishedApi
|
||||
@WasmOp(WasmOp.I64_CTZ)
|
||||
internal fun wasm_i64_ctz(a: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
// Reference type operators
|
||||
|
||||
@WasmOp(WasmOp.REF_IS_NULL)
|
||||
internal external fun wasm_externref_is_null(a: ExternalInterfaceType?): Boolean =
|
||||
implementedAsIntrinsic
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.ExternalInterfaceType
|
||||
import kotlin.wasm.internal.getSimpleName
|
||||
import kotlin.wasm.internal.jsToKotlinStringAdapter
|
||||
|
||||
/**
|
||||
* The base class for all errors and exceptions. Only instances of this class can be thrown or caught.
|
||||
*
|
||||
* @param message the detail message string.
|
||||
* @param cause the cause of this throwable.
|
||||
*/
|
||||
public open class Throwable(open val message: String?, open val cause: kotlin.Throwable?) {
|
||||
constructor(message: String?) : this(message, null)
|
||||
|
||||
constructor(cause: Throwable?) : this(cause?.toString(), cause)
|
||||
|
||||
constructor() : this(null, null)
|
||||
|
||||
internal val jsStack: ExternalInterfaceType = captureStackTrace()
|
||||
|
||||
private var _stack: String? = null
|
||||
internal val stack: String
|
||||
get() {
|
||||
var value = _stack
|
||||
if (value == null) {
|
||||
value = jsToKotlinStringAdapter(jsStack).removePrefix("Error\n")
|
||||
_stack = value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
internal var suppressedExceptionsList: MutableList<Throwable>? = null
|
||||
|
||||
/**
|
||||
* Returns the short description of this throwable consisting of the exception class name
|
||||
* followed by the exception message if it is not null.
|
||||
*/
|
||||
public override fun toString(): String {
|
||||
val s = getSimpleName(this.typeInfo)
|
||||
return if (message != null) s + ": " + message.toString() else s
|
||||
}
|
||||
}
|
||||
|
||||
private fun captureStackTrace(): ExternalInterfaceType =
|
||||
js("new Error().stack")
|
||||
+1
-3
@@ -18,6 +18,4 @@ private fun throwJsError(message: String?, wasmTypeName: String?, stack: Externa
|
||||
|
||||
internal fun throwAsJsException(t: Throwable): Nothing {
|
||||
throwJsError(t.message, getSimpleName(t.typeInfo), t.jsStack)
|
||||
}
|
||||
|
||||
internal var isNotFirstWasmExportCall: Boolean = false
|
||||
}
|
||||
+1
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -145,21 +145,6 @@ private fun Any.asWasmExternRef(): ExternalInterfaceType =
|
||||
internal fun isNullish(ref: ExternalInterfaceType?): Boolean =
|
||||
js("ref == null")
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@ExcludedFromCodegen
|
||||
/*
|
||||
* Compiler generates inplace next code:
|
||||
* ```
|
||||
* block (result anyref) {
|
||||
* local.get 0
|
||||
* extern.internalize
|
||||
* br_on_cast_fail 0000_0011b 0 (type any) (type $kotlin.Any)
|
||||
* return
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
internal fun returnArgumentIfItIsKotlinAny(): Unit = implementedAsIntrinsic
|
||||
|
||||
internal fun externRefToAny(ref: ExternalInterfaceType): Any? {
|
||||
// TODO rewrite it so to get something like:
|
||||
// block {
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:ExcludedFromCodegen
|
||||
@file:Suppress("unused", "NON_ABSTRACT_FUNCTION_WITH_NO_BODY", "INLINE_CLASS_IN_EXTERNAL_DECLARATION", "UNUSED_PARAMETER")
|
||||
|
||||
|
||||
package kotlin.wasm.internal
|
||||
|
||||
import kotlin.wasm.internal.ExternalInterfaceType
|
||||
|
||||
// Reference type operators
|
||||
|
||||
@WasmOp(WasmOp.REF_IS_NULL)
|
||||
internal external fun wasm_externref_is_null(a: ExternalInterfaceType?): Boolean
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -37,6 +37,4 @@ public actual fun print(message: Any?) {
|
||||
public actual fun readln(): String = throw UnsupportedOperationException("readln is not supported in Kotlin/WASM")
|
||||
|
||||
@SinceKotlin("1.6")
|
||||
public actual fun readlnOrNull(): String? = throw UnsupportedOperationException("readlnOrNull is not supported in Kotlin/WASM")
|
||||
|
||||
internal actual interface Serializable
|
||||
public actual fun readlnOrNull(): String? = throw UnsupportedOperationException("readlnOrNull is not supported in Kotlin/WASM")
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.random
|
||||
|
||||
private fun initialSeed(): Int =
|
||||
js("((Math.random() * Math.pow(2, 32)) | 0)")
|
||||
|
||||
internal actual fun defaultPlatformRandom(): Random =
|
||||
Random(initialSeed())
|
||||
-1
@@ -23,7 +23,6 @@ internal actual fun formatToExactDecimals(value: Double, decimals: Int): String
|
||||
} else {
|
||||
val pow = (10.0).pow(decimals)
|
||||
round(abs(value) * pow) / pow * sign(value)
|
||||
round(abs(value) * pow) / pow * sign(value)
|
||||
}
|
||||
return if (abs(rounded) < 1e21) {
|
||||
// toFixed switches to scientific format after 1e21
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.io
|
||||
|
||||
internal actual interface Serializable
|
||||
@@ -5,11 +5,5 @@
|
||||
|
||||
package kotlin.random
|
||||
|
||||
private fun initialSeed(): Int =
|
||||
js("((Math.random() * Math.pow(2, 32)) | 0)")
|
||||
|
||||
internal actual fun defaultPlatformRandom(): Random =
|
||||
Random(initialSeed())
|
||||
|
||||
internal actual fun doubleFromParts(hi26: Int, low27: Int): Double =
|
||||
(hi26.toLong().shl(27) + low27) / (1L shl 53).toDouble()
|
||||
|
||||
@@ -3,9 +3,6 @@ package test.wasm.unsafe
|
||||
import kotlin.wasm.unsafe.*
|
||||
import kotlin.test.*
|
||||
|
||||
private fun jsConcatStrings(a: String, b: String): String =
|
||||
js("a + b")
|
||||
|
||||
@OptIn(UnsafeWasmMemoryApi::class)
|
||||
class MemoryAllocationTest {
|
||||
val pageSize = 65_536
|
||||
@@ -128,14 +125,6 @@ class MemoryAllocationTest {
|
||||
assertTrue(max1 < min1_1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testJsIntropInsideAllocations() {
|
||||
withScopedMemoryAllocator { allocator ->
|
||||
assertEquals(jsConcatStrings("str1", "str2"), "str1str2")
|
||||
allocator.allocate(10)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNestedAllocatorThrows() {
|
||||
var leakedAllocator1: MemoryAllocator? = null
|
||||
|
||||
+5
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package test.js
|
||||
|
||||
import kotlin.js.*
|
||||
@@ -0,0 +1,18 @@
|
||||
package test.wasm.unsafe
|
||||
|
||||
import kotlin.wasm.unsafe.*
|
||||
import kotlin.test.*
|
||||
|
||||
private fun jsConcatStrings(a: String, b: String): String =
|
||||
js("a + b")
|
||||
|
||||
@OptIn(UnsafeWasmMemoryApi::class)
|
||||
class MemoryAllocationJsTest {
|
||||
@Test
|
||||
fun testJsIntropInsideAllocations() {
|
||||
withScopedMemoryAllocator { allocator ->
|
||||
assertEquals(jsConcatStrings("str1", "str2"), "str1str2")
|
||||
allocator.allocate(10)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.getSimpleName
|
||||
|
||||
/**
|
||||
* The base class for all errors and exceptions. Only instances of this class can be thrown or caught.
|
||||
*
|
||||
* @param message the detail message string.
|
||||
* @param cause the cause of this throwable.
|
||||
*/
|
||||
public open class Throwable(open val message: String?, open val cause: kotlin.Throwable?) {
|
||||
constructor(message: String?) : this(message, null)
|
||||
|
||||
constructor(cause: Throwable?) : this(cause?.toString(), cause)
|
||||
|
||||
constructor() : this(null, null)
|
||||
|
||||
//TODO: Investigate possibility to make WASI stack discoverable (KT-60965)
|
||||
internal val stack: String get() = ""
|
||||
|
||||
internal var suppressedExceptionsList: MutableList<Throwable>? = null
|
||||
|
||||
/**
|
||||
* Returns the short description of this throwable consisting of the exception class name
|
||||
* followed by the exception message if it is not null.
|
||||
*/
|
||||
public override fun toString(): String {
|
||||
val s = getSimpleName(this.typeInfo)
|
||||
return if (message != null) s + ": " + message.toString() else s
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.wasm
|
||||
|
||||
/**
|
||||
* [WASI Error codes for preview1](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md)
|
||||
*/
|
||||
internal enum class WasiErrorCode {
|
||||
/**
|
||||
* No error occurred. System call completed successfully.
|
||||
*/
|
||||
SUCCESS,
|
||||
|
||||
/**
|
||||
* Argument list too long.
|
||||
*/
|
||||
_2BIG,
|
||||
|
||||
/**
|
||||
* Permission denied.
|
||||
*/
|
||||
ACCES,
|
||||
|
||||
/**
|
||||
* Address in use.
|
||||
*/
|
||||
ADDRINUSE,
|
||||
|
||||
/**
|
||||
* Address not available.
|
||||
*/
|
||||
ADDRNOTAVAIL,
|
||||
|
||||
/**
|
||||
* Address family not supported.
|
||||
*/
|
||||
AFNOSUPPORT,
|
||||
|
||||
/**
|
||||
* Resource unavailable, or operation would block.
|
||||
*/
|
||||
AGAIN,
|
||||
|
||||
/**
|
||||
* Connection already in progress.
|
||||
*/
|
||||
ALREADY,
|
||||
|
||||
/**
|
||||
* Bad file descriptor.
|
||||
*/
|
||||
BADF,
|
||||
|
||||
/**
|
||||
* Bad message.
|
||||
*/
|
||||
BADMSG,
|
||||
|
||||
/**
|
||||
* Device or resource busy.
|
||||
*/
|
||||
BUSY,
|
||||
|
||||
/**
|
||||
* Operation canceled.
|
||||
*/
|
||||
CANCELED,
|
||||
|
||||
/**
|
||||
* No child processes.
|
||||
*/
|
||||
CHILD,
|
||||
|
||||
/**
|
||||
* Connection aborted.
|
||||
*/
|
||||
CONNABORTED,
|
||||
|
||||
/**
|
||||
* Connection refused.
|
||||
*/
|
||||
CONNREFUSED,
|
||||
|
||||
/**
|
||||
* Connection reset.
|
||||
*/
|
||||
CONNRESET,
|
||||
|
||||
/**
|
||||
* Resource deadlock would occur.
|
||||
*/
|
||||
DEADLK,
|
||||
|
||||
/**
|
||||
* Destination address required.
|
||||
*/
|
||||
DESTADDRREQ,
|
||||
|
||||
/**
|
||||
* Mathematics argument out of domain of function.
|
||||
*/
|
||||
DOM,
|
||||
|
||||
/**
|
||||
* Reserved.
|
||||
*/
|
||||
DQUOT,
|
||||
|
||||
/**
|
||||
* File exists.
|
||||
*/
|
||||
EXIST,
|
||||
|
||||
/**
|
||||
* Bad address.
|
||||
*/
|
||||
FAULT,
|
||||
|
||||
/**
|
||||
* File too large.
|
||||
*/
|
||||
FBIG,
|
||||
|
||||
/**
|
||||
* Host is unreachable.
|
||||
*/
|
||||
HOSTUNREACH,
|
||||
|
||||
/**
|
||||
* Identifier removed.
|
||||
*/
|
||||
IDRM,
|
||||
|
||||
/**
|
||||
* Illegal byte sequence.
|
||||
*/
|
||||
ILSEQ,
|
||||
|
||||
/**
|
||||
* Operation in progress.
|
||||
*/
|
||||
INPROGRESS,
|
||||
|
||||
/**
|
||||
* Interrupted function.
|
||||
*/
|
||||
INTR,
|
||||
|
||||
/**
|
||||
* Invalid argument.
|
||||
*/
|
||||
INVAL,
|
||||
|
||||
/**
|
||||
* I/O error.
|
||||
*/
|
||||
IO,
|
||||
|
||||
/**
|
||||
* Socket is connected.
|
||||
*/
|
||||
ISCONN,
|
||||
|
||||
/**
|
||||
* Is a directory.
|
||||
*/
|
||||
ISDIR,
|
||||
|
||||
/**
|
||||
* Too many levels of symbolic links.
|
||||
*/
|
||||
LOOP,
|
||||
|
||||
/**
|
||||
* File descriptor value too large.
|
||||
*/
|
||||
MFILE,
|
||||
|
||||
/**
|
||||
* Too many links.
|
||||
*/
|
||||
MLINK,
|
||||
|
||||
/**
|
||||
* Message too large.
|
||||
*/
|
||||
MSGSIZE,
|
||||
|
||||
/**
|
||||
* Reserved.
|
||||
*/
|
||||
MULTIHOP,
|
||||
|
||||
/**
|
||||
* Filename too long.
|
||||
*/
|
||||
NAMETOOLONG,
|
||||
|
||||
/**
|
||||
* Network is down.
|
||||
*/
|
||||
NETDOWN,
|
||||
|
||||
/**
|
||||
* Connection aborted by network.
|
||||
*/
|
||||
NETRESET,
|
||||
|
||||
/**
|
||||
* Network unreachable.
|
||||
*/
|
||||
NETUNREACH,
|
||||
|
||||
/**
|
||||
* Too many files open in system.
|
||||
*/
|
||||
NFILE,
|
||||
|
||||
/**
|
||||
* No buffer space available.
|
||||
*/
|
||||
NOBUFS,
|
||||
|
||||
/**
|
||||
* No such device.
|
||||
*/
|
||||
NODEV,
|
||||
|
||||
/**
|
||||
* No such file or directory.
|
||||
*/
|
||||
NOENT,
|
||||
|
||||
/**
|
||||
* Executable file format error.
|
||||
*/
|
||||
NOEXEC,
|
||||
|
||||
/**
|
||||
* No locks available.
|
||||
*/
|
||||
NOLCK,
|
||||
|
||||
/**
|
||||
* Reserved.
|
||||
*/
|
||||
NOLINK,
|
||||
|
||||
/**
|
||||
* Not enough space.
|
||||
*/
|
||||
NOMEM,
|
||||
|
||||
/**
|
||||
* No message of the desired type.
|
||||
*/
|
||||
NOMSG,
|
||||
|
||||
/**
|
||||
* Protocol not available.
|
||||
*/
|
||||
NOPROTOOPT,
|
||||
|
||||
/**
|
||||
* No space left on device.
|
||||
*/
|
||||
NOSPC,
|
||||
|
||||
/**
|
||||
* Function not supported.
|
||||
*/
|
||||
NOSYS,
|
||||
|
||||
/**
|
||||
* The socket is not connected.
|
||||
*/
|
||||
NOTCONN,
|
||||
|
||||
/**
|
||||
* Not a directory or a symbolic link to a directory.
|
||||
*/
|
||||
NOTDIR,
|
||||
|
||||
/**
|
||||
* Directory not empty.
|
||||
*/
|
||||
NOTEMPTY,
|
||||
|
||||
/**
|
||||
* State not recoverable.
|
||||
*/
|
||||
NOTRECOVERABLE,
|
||||
|
||||
/**
|
||||
* Not a socket.
|
||||
*/
|
||||
NOTSOCK,
|
||||
|
||||
/**
|
||||
* Not supported, or operation not supported on socket.
|
||||
*/
|
||||
NOTSUP,
|
||||
|
||||
/**
|
||||
* Inappropriate I/O control operation.
|
||||
*/
|
||||
NOTTY,
|
||||
|
||||
/**
|
||||
* No such device or address.
|
||||
*/
|
||||
NXIO,
|
||||
|
||||
/**
|
||||
* Value too large to be stored in data type.
|
||||
*/
|
||||
OVERFLOW,
|
||||
|
||||
/**
|
||||
* Previous owner died.
|
||||
*/
|
||||
OWNERDEAD,
|
||||
|
||||
/**
|
||||
* Operation not permitted.
|
||||
*/
|
||||
PERM,
|
||||
|
||||
/**
|
||||
* Broken pipe.
|
||||
*/
|
||||
PIPE,
|
||||
|
||||
/**
|
||||
* Protocol error.
|
||||
*/
|
||||
PROTO,
|
||||
|
||||
/**
|
||||
* Protocol not supported.
|
||||
*/
|
||||
PROTONOSUPPORT,
|
||||
|
||||
/**
|
||||
* Protocol wrong type for socket.
|
||||
*/
|
||||
PROTOTYPE,
|
||||
|
||||
/**
|
||||
* Result too large.
|
||||
*/
|
||||
RANGE,
|
||||
|
||||
/**
|
||||
* Read-only file system.
|
||||
*/
|
||||
ROFS,
|
||||
|
||||
/**
|
||||
* Invalid seek.
|
||||
*/
|
||||
SPIPE,
|
||||
|
||||
/**
|
||||
* No such process.
|
||||
*/
|
||||
SRCH,
|
||||
|
||||
/**
|
||||
* Reserved.
|
||||
*/
|
||||
STALE,
|
||||
|
||||
/**
|
||||
* Connection timed out.
|
||||
*/
|
||||
TIMEDOUT,
|
||||
|
||||
/**
|
||||
* Text file busy.
|
||||
*/
|
||||
TXTBSY,
|
||||
|
||||
/**
|
||||
* Cross-device link.
|
||||
*/
|
||||
XDEV,
|
||||
|
||||
/**
|
||||
* Extension: Capabilities insufficient.
|
||||
*/
|
||||
NOTCAPABLE,
|
||||
}
|
||||
|
||||
internal class WasiError(val error: WasiErrorCode) : Throwable(message = "WASI call failed with $error")
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.io
|
||||
|
||||
import kotlin.wasm.WasiError
|
||||
import kotlin.wasm.WasiErrorCode
|
||||
import kotlin.wasm.WasmImport
|
||||
import kotlin.wasm.unsafe.MemoryAllocator
|
||||
import kotlin.wasm.unsafe.withScopedMemoryAllocator
|
||||
|
||||
private const val STDOUT = 1
|
||||
private const val STDERR = 2
|
||||
|
||||
/**
|
||||
* Write to a file descriptor. Note: This is similar to `writev` in POSIX.
|
||||
*/
|
||||
@WasmImport("wasi_snapshot_preview1", "fd_write")
|
||||
private external fun wasiRawFdWrite(descriptor: Int, scatterPtr: Int, scatterSize: Int, errorPtr: Int): Int
|
||||
|
||||
internal fun wasiPrintImpl(
|
||||
allocator: MemoryAllocator,
|
||||
data: ByteArray?,
|
||||
newLine: Boolean,
|
||||
useErrorStream: Boolean
|
||||
) {
|
||||
val dataSize = data?.size ?: 0
|
||||
val memorySize = dataSize + (if (newLine) 1 else 0)
|
||||
if (memorySize == 0) return
|
||||
|
||||
val ptr = allocator.allocate(memorySize)
|
||||
if (data != null) {
|
||||
var currentPtr = ptr
|
||||
for (el in data) {
|
||||
currentPtr.storeByte(el)
|
||||
currentPtr += 1
|
||||
}
|
||||
}
|
||||
if (newLine) {
|
||||
(ptr + dataSize).storeByte(0x0A)
|
||||
}
|
||||
|
||||
val scatterPtr = allocator.allocate(8)
|
||||
(scatterPtr + 0).storeInt(ptr.address.toInt())
|
||||
(scatterPtr + 4).storeInt(memorySize)
|
||||
|
||||
val rp0 = allocator.allocate(4)
|
||||
|
||||
val ret =
|
||||
wasiRawFdWrite(
|
||||
descriptor = if (useErrorStream) STDERR else STDOUT,
|
||||
scatterPtr = scatterPtr.address.toInt(),
|
||||
scatterSize = 1,
|
||||
errorPtr = rp0.address.toInt()
|
||||
)
|
||||
|
||||
if (ret != 0) {
|
||||
throw WasiError(WasiErrorCode.values()[ret])
|
||||
}
|
||||
}
|
||||
|
||||
private fun printImpl(message: String?, useErrorStream: Boolean, newLine: Boolean) {
|
||||
withScopedMemoryAllocator { allocator ->
|
||||
wasiPrintImpl(
|
||||
allocator = allocator,
|
||||
data = message?.encodeToByteArray(),
|
||||
newLine = newLine,
|
||||
useErrorStream = useErrorStream,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun printError(error: String?) {
|
||||
printImpl(error, useErrorStream = true, newLine = false)
|
||||
}
|
||||
|
||||
/** Prints the line separator to the standard output stream. */
|
||||
public actual fun println() {
|
||||
printImpl(null, useErrorStream = false, newLine = true)
|
||||
}
|
||||
|
||||
/** Prints the given [message] and the line separator to the standard output stream. */
|
||||
public actual fun println(message: Any?) {
|
||||
printImpl(message?.toString(), useErrorStream = false, newLine = true)
|
||||
}
|
||||
|
||||
/** Prints the given [message] to the standard output stream. */
|
||||
public actual fun print(message: Any?) {
|
||||
printImpl(message?.toString(), useErrorStream = false, newLine = false)
|
||||
}
|
||||
|
||||
@SinceKotlin("1.6")
|
||||
public actual fun readln(): String = TODO("wasi")
|
||||
|
||||
@SinceKotlin("1.6")
|
||||
public actual fun readlnOrNull(): String? = TODO("wasi")
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.random
|
||||
|
||||
import kotlin.wasm.WasiError
|
||||
import kotlin.wasm.WasiErrorCode
|
||||
import kotlin.wasm.WasmImport
|
||||
import kotlin.wasm.unsafe.withScopedMemoryAllocator
|
||||
|
||||
/**
|
||||
* Write high-quality random data into a buffer. This function blocks when the implementation is
|
||||
* unable to immediately provide sufficient high-quality random data. This function may execute
|
||||
* slowly, so when large mounts of random data are required, it's advisable to use this function to
|
||||
* seed a pseudo-random number generator, rather than to provide the random data directly.
|
||||
*/
|
||||
@WasmImport("wasi_snapshot_preview1", "random_get")
|
||||
//TODO: Better to use 64-bit Long as a seed if possible. (KT-60962)
|
||||
internal external fun wasiRawRandomGet(address: Int, size: Int): Int
|
||||
|
||||
private fun wasiRandomGet(): Int {
|
||||
withScopedMemoryAllocator { allocator ->
|
||||
val memory = allocator.allocate(Int.SIZE_BYTES)
|
||||
val ret = wasiRawRandomGet(memory.address.toInt(), Int.SIZE_BYTES)
|
||||
return if (ret == 0) {
|
||||
memory.loadInt()
|
||||
} else {
|
||||
throw WasiError(WasiErrorCode.values()[ret])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun defaultPlatformRandom(): Random =
|
||||
Random(wasiRandomGet())
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.time
|
||||
|
||||
import kotlin.math.fdlibm.__ieee754_pow
|
||||
|
||||
internal actual fun formatToExactDecimals(value: Double, decimals: Int): String {
|
||||
// TODO Make correct implementation (KT-60964)
|
||||
val pow = __ieee754_pow(10.0, decimals.toDouble())
|
||||
val round = kotlin.math.fdlibm.rint(value * pow)
|
||||
return (round / pow).toString()
|
||||
}
|
||||
|
||||
internal actual fun formatUpToDecimals(value: Double, decimals: Int): String = TODO("Wasi Implement")
|
||||
|
||||
internal actual inline val durationAssertionsEnabled: Boolean get() = true
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.time
|
||||
|
||||
import kotlin.time.Duration.Companion.nanoseconds
|
||||
import kotlin.time.TimeSource.Monotonic.ValueTimeMark
|
||||
import kotlin.wasm.WasiError
|
||||
import kotlin.wasm.WasiErrorCode
|
||||
import kotlin.wasm.WasmImport
|
||||
import kotlin.wasm.unsafe.Pointer
|
||||
import kotlin.wasm.unsafe.withScopedMemoryAllocator
|
||||
|
||||
private const val MONOTONIC = 1
|
||||
|
||||
/**
|
||||
* Return the time value of a clock. Note: This is similar to `clock_gettime` in POSIX.
|
||||
*/
|
||||
@WasmImport("wasi_snapshot_preview1", "clock_time_get")
|
||||
private external fun wasiRawClockTimeGet(clockId: Int, precision: Long, resultPtr: Int): Int
|
||||
|
||||
private fun clockTimeGet(): Long = withScopedMemoryAllocator { allocator ->
|
||||
val rp0 = allocator.allocate(8)
|
||||
val ret = wasiRawClockTimeGet(
|
||||
clockId = MONOTONIC,
|
||||
precision = 1,
|
||||
resultPtr = rp0.address.toInt()
|
||||
)
|
||||
if (ret == 0) {
|
||||
(Pointer(rp0.address.toInt().toUInt())).loadLong()
|
||||
} else {
|
||||
throw WasiError(WasiErrorCode.values()[ret])
|
||||
}
|
||||
}
|
||||
|
||||
@SinceKotlin("1.3")
|
||||
//TODO: Try use implementation of K/JVM since it uses a Long nanosecond counter similar to System.nanoTime (KT-60963)
|
||||
internal actual object MonotonicTimeSource : TimeSource.WithComparableMarks {
|
||||
actual override fun markNow(): ValueTimeMark =
|
||||
ValueTimeMark(clockTimeGet())
|
||||
|
||||
actual fun elapsedFrom(timeMark: ValueTimeMark): Duration =
|
||||
(clockTimeGet() - timeMark.reading).nanoseconds
|
||||
|
||||
actual fun adjustReading(timeMark: ValueTimeMark, duration: Duration): ValueTimeMark =
|
||||
ValueTimeMark(timeMark.reading + duration.toLong(DurationUnit.NANOSECONDS))
|
||||
|
||||
actual fun differenceBetween(one: ValueTimeMark, another: ValueTimeMark): Duration {
|
||||
val ms1 = one.reading
|
||||
val ms2 = another.reading
|
||||
return if (ms1 == ms2) Duration.ZERO else (ms1 - ms2).nanoseconds
|
||||
}
|
||||
|
||||
override fun toString(): String = "WASI monotonic time source"
|
||||
}
|
||||
|
||||
@Suppress("ACTUAL_WITHOUT_EXPECT") // visibility
|
||||
internal actual typealias ValueTimeMarkReading = Long
|
||||
Reference in New Issue
Block a user