[K/N][New MM] Support thread state switching
Including * Support thread state switching in codegen * Introduce and use GCUnsafeCall annotation * Switch thread state in C++ runtime code Also * Register current thread in Mark&Sweep tests * Store MemoryState in Worker instance * Set worker tid in WorkerInit
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
@@ -158,10 +159,10 @@ public fun CPointer<ShortVar>.toKString(): String = this.toKStringFromUtf16()
|
||||
|
||||
public fun CPointer<UShortVar>.toKString(): String = this.toKStringFromUtf16()
|
||||
|
||||
@SymbolName("Kotlin_interop_malloc")
|
||||
@GCUnsafeCall("Kotlin_interop_malloc")
|
||||
private external fun malloc(size: Long, align: Int): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_interop_free")
|
||||
@GCUnsafeCall("Kotlin_interop_free")
|
||||
private external fun cfree(ptr: NativePtr)
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_READ_BITS)
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
package kotlinx.cinterop
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
@SymbolName("Kotlin_Interop_createStablePointer")
|
||||
@GCUnsafeCall("Kotlin_Interop_createStablePointer")
|
||||
internal external fun createStablePointer(any: Any): COpaquePointer
|
||||
|
||||
@SymbolName("Kotlin_Interop_disposeStablePointer")
|
||||
@GCUnsafeCall("Kotlin_Interop_disposeStablePointer")
|
||||
internal external fun disposeStablePointer(pointer: COpaquePointer)
|
||||
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_Interop_derefStablePointer")
|
||||
@GCUnsafeCall("Kotlin_Interop_derefStablePointer")
|
||||
internal external fun derefStablePointer(pointer: COpaquePointer): Any
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
internal fun encodeToUtf8(str: String): ByteArray = str.encodeToByteArray()
|
||||
|
||||
@SymbolName("Kotlin_CString_toKStringFromUtf8Impl")
|
||||
@GCUnsafeCall("Kotlin_CString_toKStringFromUtf8Impl")
|
||||
internal external fun CPointer<ByteVar>.toKStringFromUtf8Impl(): String
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.INTEROP_BITS_TO_FLOAT)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package kotlinx.cinterop
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
data class Pinned<out T : Any> internal constructor(private val stablePtr: COpaquePointer) {
|
||||
|
||||
@@ -92,38 +93,38 @@ private inline fun <T : Any, P : CPointed> T.usingPinned(
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
private external fun ByteArray.addressOfElement(index: Int): CPointer<ByteVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getStringAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getStringAddressOfElement")
|
||||
private external fun String.addressOfElement(index: Int): CPointer<COpaque>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getCharArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getCharArrayAddressOfElement")
|
||||
private external fun CharArray.addressOfElement(index: Int): CPointer<COpaque>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
private external fun ShortArray.addressOfElement(index: Int): CPointer<ShortVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getIntArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getIntArrayAddressOfElement")
|
||||
private external fun IntArray.addressOfElement(index: Int): CPointer<IntVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
private external fun LongArray.addressOfElement(index: Int): CPointer<LongVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
private external fun UByteArray.addressOfElement(index: Int): CPointer<UByteVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
private external fun UShortArray.addressOfElement(index: Int): CPointer<UShortVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getIntArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getIntArrayAddressOfElement")
|
||||
private external fun UIntArray.addressOfElement(index: Int): CPointer<UIntVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
private external fun ULongArray.addressOfElement(index: Int): CPointer<ULongVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getFloatArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getFloatArrayAddressOfElement")
|
||||
private external fun FloatArray.addressOfElement(index: Int): CPointer<FloatVar>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getDoubleArrayAddressOfElement")
|
||||
@GCUnsafeCall("Kotlin_Arrays_getDoubleArrayAddressOfElement")
|
||||
private external fun DoubleArray.addressOfElement(index: Int): CPointer<DoubleVar>
|
||||
|
||||
@@ -194,6 +194,7 @@ targetList.each { target ->
|
||||
'-Xmulti-platform', '-Xopt-in=kotlin.RequiresOptIn', '-Xinline-classes',
|
||||
'-Xopt-in=kotlin.contracts.ExperimentalContracts',
|
||||
'-Xopt-in=kotlin.ExperimentalMultiplatform',
|
||||
'-Xopt-in=kotlin.native.internal.InternalForKotlinNative',
|
||||
'-Xallow-result-return-type',
|
||||
*commonSrc.toList(),
|
||||
*testAnnotationCommon.toList(),
|
||||
|
||||
+1
@@ -32,4 +32,5 @@ object KonanFqNames {
|
||||
val objCMethod = FqName("kotlinx.cinterop.ObjCMethod")
|
||||
val hasFinalizer = FqName("kotlin.native.internal.HasFinalizer")
|
||||
val hasFreezeHook = FqName("kotlin.native.internal.HasFreezeHook")
|
||||
val gcUnsafeCall = FqName("kotlin.native.internal.GCUnsafeCall")
|
||||
}
|
||||
|
||||
+15
-9
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
@@ -73,10 +70,11 @@ internal class KotlinBridgeBuilder(
|
||||
cName: String,
|
||||
stubs: KotlinStubs,
|
||||
isExternal: Boolean,
|
||||
foreignExceptionMode: ForeignExceptionMode.Mode
|
||||
foreignExceptionMode: ForeignExceptionMode.Mode,
|
||||
origin: IrDeclarationOrigin
|
||||
) {
|
||||
private var counter = 0
|
||||
private val bridge: IrFunction = createKotlinBridge(startOffset, endOffset, cName, stubs, isExternal, foreignExceptionMode)
|
||||
private val bridge: IrFunction = createKotlinBridge(startOffset, endOffset, cName, stubs, isExternal, foreignExceptionMode, origin)
|
||||
val irBuilder: IrBuilderWithScope = irBuilder(stubs.irBuiltIns, bridge.symbol).at(startOffset, endOffset)
|
||||
|
||||
fun addParameter(type: IrType): IrValueParameter {
|
||||
@@ -110,12 +108,13 @@ private fun createKotlinBridge(
|
||||
cBridgeName: String,
|
||||
stubs: KotlinStubs,
|
||||
isExternal: Boolean,
|
||||
foreignExceptionMode: ForeignExceptionMode.Mode
|
||||
foreignExceptionMode: ForeignExceptionMode.Mode,
|
||||
origin: IrDeclarationOrigin
|
||||
): IrFunction {
|
||||
val bridge = IrFunctionImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
origin,
|
||||
IrSimpleFunctionSymbolImpl(),
|
||||
Name.identifier(cBridgeName),
|
||||
DescriptorVisibilities.PRIVATE,
|
||||
@@ -151,7 +150,9 @@ internal class KotlinCBridgeBuilder(
|
||||
isKotlinToC: Boolean,
|
||||
foreignExceptionMode: ForeignExceptionMode.Mode = ForeignExceptionMode.default
|
||||
) {
|
||||
private val kotlinBridgeBuilder = KotlinBridgeBuilder(startOffset, endOffset, cName, stubs, isExternal = isKotlinToC, foreignExceptionMode)
|
||||
private val origin: CBridgeOrigin = if (isKotlinToC) CBridgeOrigin.KOTLIN_TO_C_BRIDGE else CBridgeOrigin.C_TO_KOTLIN_BRIDGE
|
||||
|
||||
private val kotlinBridgeBuilder = KotlinBridgeBuilder(startOffset, endOffset, cName, stubs, isExternal = isKotlinToC, foreignExceptionMode, origin)
|
||||
private val cBridgeBuilder = CFunctionBuilder()
|
||||
|
||||
val kotlinIrBuilder: IrBuilderWithScope get() = kotlinBridgeBuilder.irBuilder
|
||||
@@ -251,3 +252,8 @@ internal class CCallBuilder {
|
||||
append(')')
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CBridgeOrigin(name: String): IrDeclarationOriginImpl(name, isSynthetic = true) {
|
||||
object KOTLIN_TO_C_BRIDGE: CBridgeOrigin("KOTLIN_TO_C_BRIDGE")
|
||||
object C_TO_KOTLIN_BRIDGE: CBridgeOrigin("C_TO_KOTLIN_BRIDGE")
|
||||
}
|
||||
|
||||
+3
-1
@@ -291,6 +291,8 @@ fun <T> IrConstructorCall.getAnnotationValueOrNull(name: String): T? {
|
||||
fun IrFunction.externalSymbolOrThrow(): String? {
|
||||
annotations.findAnnotation(RuntimeNames.symbolNameAnnotation)?.let { return it.getAnnotationStringValue() }
|
||||
|
||||
annotations.findAnnotation(KonanFqNames.gcUnsafeCall)?.let { return it.getAnnotationStringValue("callee") }
|
||||
|
||||
if (annotations.hasAnnotation(KonanFqNames.objCMethod)) return null
|
||||
|
||||
if (annotations.hasAnnotation(KonanFqNames.typedIntrinsic)) return null
|
||||
@@ -299,7 +301,7 @@ fun IrFunction.externalSymbolOrThrow(): String? {
|
||||
|
||||
if (origin == InternalAbi.INTERNAL_ABI_ORIGIN) return null
|
||||
|
||||
throw Error("external function ${this.longName} must have @TypedIntrinsic, @SymbolName or @ObjCMethod annotation")
|
||||
throw Error("external function ${this.longName} must have @TypedIntrinsic, @SymbolName, @GCUnsafeCall or @ObjCMethod annotation")
|
||||
}
|
||||
|
||||
val IrFunction.isBuiltInOperator get() = origin == IrBuiltIns.BUILTIN_OPERATOR
|
||||
|
||||
+50
-11
@@ -9,6 +9,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.cgen.CBridgeOrigin
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.ClassGlobalHierarchyInfo
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
@@ -16,6 +17,8 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Native
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Runnable
|
||||
import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||
@@ -91,6 +94,10 @@ internal sealed class ExceptionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
internal enum class ThreadState {
|
||||
Native, Runnable
|
||||
}
|
||||
|
||||
val LLVMValueRef.name:String?
|
||||
get() = LLVMGetValueName(this)?.toKString()
|
||||
|
||||
@@ -341,7 +348,7 @@ internal class StackLocalsManagerImpl(
|
||||
internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
val codegen: CodeGenerator,
|
||||
startLocation: LocationInfo?,
|
||||
endLocation: LocationInfo?,
|
||||
private val endLocation: LocationInfo?,
|
||||
internal val irFunction: IrFunction? = null): ContextUtils {
|
||||
|
||||
override val context = codegen.context
|
||||
@@ -528,6 +535,19 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun switchThreadState(state: ThreadState) {
|
||||
check(context.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
"Thread state switching is allowed in the experimental memory model only."
|
||||
}
|
||||
check(!forbidRuntime) {
|
||||
"Attempt to switch the thread state when runtime is forbidden"
|
||||
}
|
||||
when (state) {
|
||||
Native -> call(context.llvm.Kotlin_mm_switchThreadStateNative, emptyList())
|
||||
Runnable -> call(context.llvm.Kotlin_mm_switchThreadStateRunnable, emptyList())
|
||||
}.let {} // Force exhaustive.
|
||||
}
|
||||
|
||||
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
|
||||
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
|
||||
@@ -755,7 +775,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
return LLVMBuildExtractElement(builder, vector, index, name)!!
|
||||
}
|
||||
|
||||
fun filteringExceptionHandler(codeContext: CodeContext, foreignExceptionMode: ForeignExceptionMode.Mode): ExceptionHandler {
|
||||
fun filteringExceptionHandler(codeContext: CodeContext, foreignExceptionMode: ForeignExceptionMode.Mode, switchThreadState: Boolean): ExceptionHandler {
|
||||
val lpBlock = basicBlockInFunction("filteringExceptionHandler", position()?.start)
|
||||
|
||||
val wrapExceptionMode = context.config.target.family.isAppleFamily &&
|
||||
@@ -769,6 +789,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
}
|
||||
LLVMAddClause(landingpad, LLVMConstNull(kInt8Ptr))
|
||||
|
||||
if (switchThreadState) {
|
||||
switchThreadState(Runnable)
|
||||
}
|
||||
|
||||
val fatalForeignExceptionBlock = basicBlock("fatalForeignException", position()?.start)
|
||||
val forwardKotlinExceptionBlock = basicBlock("forwardKotlinException", position()?.start)
|
||||
|
||||
@@ -829,9 +853,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
}
|
||||
}
|
||||
|
||||
fun kotlinExceptionHandler(
|
||||
block: FunctionGenerationContext.(exception: LLVMValueRef) -> Unit
|
||||
): ExceptionHandler {
|
||||
fun kotlinExceptionHandler(block: FunctionGenerationContext.(exception: LLVMValueRef) -> Unit): ExceptionHandler {
|
||||
val lpBlock = basicBlock("kotlinExceptionHandler", position()?.end)
|
||||
|
||||
appendingTo(lpBlock) {
|
||||
@@ -1248,6 +1270,14 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
if (isObjectType(returnType!!)) {
|
||||
returnSlot = LLVMGetParam(function, numParameters(function.type) - 1)
|
||||
}
|
||||
|
||||
if (context.memoryModel == MemoryModel.EXPERIMENTAL &&
|
||||
irFunction?.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE) {
|
||||
check(!forbidRuntime) { "Attempt to switch the thread state when runtime is forbidden" }
|
||||
positionAtEnd(prologueBb)
|
||||
switchThreadState(Runnable)
|
||||
}
|
||||
|
||||
positionAtEnd(localsInitBb)
|
||||
slotsPhi = phi(kObjHeaderPtrPtr)
|
||||
// Is removed by DCE trivially, if not needed.
|
||||
@@ -1307,8 +1337,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
returnType == voidType -> {
|
||||
releaseVars()
|
||||
assert(returnSlot == null)
|
||||
if (!forbidRuntime && context.memoryModel == MemoryModel.EXPERIMENTAL)
|
||||
call(context.llvm.Kotlin_mm_safePointFunctionEpilogue, emptyList())
|
||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointFunctionEpilogue)
|
||||
LLVMBuildRetVoid(builder)
|
||||
}
|
||||
returns.isNotEmpty() -> {
|
||||
@@ -1318,8 +1347,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
updateReturnRef(returnPhi, returnSlot!!)
|
||||
}
|
||||
releaseVars()
|
||||
if (!forbidRuntime && context.memoryModel == MemoryModel.EXPERIMENTAL)
|
||||
call(context.llvm.Kotlin_mm_safePointFunctionEpilogue, emptyList())
|
||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointFunctionEpilogue)
|
||||
LLVMBuildRet(builder, returnPhi)
|
||||
}
|
||||
// Do nothing, all paths throw.
|
||||
@@ -1360,8 +1388,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
}
|
||||
|
||||
releaseVars()
|
||||
if (!forbidRuntime && context.memoryModel == MemoryModel.EXPERIMENTAL)
|
||||
call(context.llvm.Kotlin_mm_safePointExceptionUnwind, emptyList())
|
||||
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
|
||||
LLVMBuildResume(builder, landingpad)
|
||||
}
|
||||
|
||||
@@ -1371,6 +1398,18 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
slotsPhi = null
|
||||
}
|
||||
|
||||
private fun handleEpilogueForExperimentalMM(safePointFunction: LLVMValueRef) {
|
||||
if (context.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
if (!forbidRuntime) {
|
||||
call(safePointFunction, emptyList())
|
||||
}
|
||||
if (irFunction?.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE) {
|
||||
check(!forbidRuntime) { "Generating a bridge when runtime is forbidden" }
|
||||
switchThreadState(Native)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val kotlinExceptionRtti: ConstPointer
|
||||
get() = constPointer(importGlobal(
|
||||
"_ZTI18ExceptionObjHolder", // typeinfo for ObjHolder
|
||||
|
||||
+3
@@ -487,6 +487,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
val getObjCKotlinTypeInfo by lazy { importRtFunction("GetObjCKotlinTypeInfo") }
|
||||
val missingInitImp by lazy { importRtFunction("MissingInitImp") }
|
||||
|
||||
val Kotlin_mm_switchThreadStateNative by lazy { importRtFunction("Kotlin_mm_switchThreadStateNative") }
|
||||
val Kotlin_mm_switchThreadStateRunnable by lazy { importRtFunction("Kotlin_mm_switchThreadStateRunnable") }
|
||||
|
||||
val Kotlin_Interop_DoesObjectConformToProtocol by lazyRtFunction
|
||||
val Kotlin_Interop_IsObjectKindOfClass by lazyRtFunction
|
||||
|
||||
|
||||
+33
-8
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.ir.allParameters
|
||||
import org.jetbrains.kotlin.backend.common.ir.allParametersCount
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.InlinerExpressionLocationHint
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.cgen.CBridgeOrigin
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation
|
||||
@@ -673,7 +674,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
|
||||
override val exceptionHandler get() = ExceptionHandler.Caller
|
||||
override val exceptionHandler: ExceptionHandler
|
||||
get() = ExceptionHandler.Caller
|
||||
|
||||
override fun genThrow(exception: LLVMValueRef) {
|
||||
val objHeaderPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, exception)
|
||||
@@ -1030,7 +1032,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
private inner abstract class CatchingScope : InnerScopeImpl() {
|
||||
|
||||
/**
|
||||
* The LLVM `landingpad` such that if invoked function throws an exception,
|
||||
* The LLVM `landingpad` such that if an invoked function throws an exception,
|
||||
* then this exception is passed to [handler].
|
||||
*/
|
||||
private val landingpad: LLVMBasicBlockRef by lazy {
|
||||
@@ -1087,9 +1089,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
|
||||
override val exceptionHandler: ExceptionHandler get() = object : ExceptionHandler.Local() {
|
||||
override val unwind get() = landingpad
|
||||
}
|
||||
override val exceptionHandler: ExceptionHandler
|
||||
get() = object : ExceptionHandler.Local() {
|
||||
override val unwind get() = landingpad
|
||||
}
|
||||
|
||||
override fun genThrow(exception: LLVMValueRef) {
|
||||
jumpToHandler(exception)
|
||||
@@ -2332,17 +2335,39 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private val IrFunction.needsNativeThreadState: Boolean
|
||||
get() {
|
||||
// We assume that call site thread state switching is required for interop calls only.
|
||||
val result = context.memoryModel == MemoryModel.EXPERIMENTAL && origin == CBridgeOrigin.KOTLIN_TO_C_BRIDGE
|
||||
if (result) {
|
||||
check(isExternal)
|
||||
check(!annotations.hasAnnotation(KonanFqNames.gcUnsafeCall))
|
||||
check(annotations.hasAnnotation(RuntimeNames.filterExceptions))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun call(function: IrFunction, llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
resultLifetime: Lifetime): LLVMValueRef {
|
||||
check(!function.isTypedIntrinsic)
|
||||
|
||||
val needsNativeThreadState = function.needsNativeThreadState
|
||||
val exceptionHandler = function.annotations.findAnnotation(RuntimeNames.filterExceptions)?.let {
|
||||
val foreignExceptionMode = ForeignExceptionMode.byValue(it.getAnnotationValueOrNull<String>("mode"))
|
||||
functionGenerationContext.filteringExceptionHandler(currentCodeContext, foreignExceptionMode)
|
||||
functionGenerationContext.filteringExceptionHandler(currentCodeContext, foreignExceptionMode, needsNativeThreadState)
|
||||
} ?: currentCodeContext.exceptionHandler
|
||||
|
||||
if (needsNativeThreadState) {
|
||||
functionGenerationContext.switchThreadState(ThreadState.Native)
|
||||
}
|
||||
|
||||
val result = call(llvmFunction, args, resultLifetime, exceptionHandler)
|
||||
if (!function.isSuspend && function.returnType.isNothing()) {
|
||||
functionGenerationContext.unreachable()
|
||||
|
||||
when {
|
||||
!function.isSuspend && function.returnType.isNothing() ->
|
||||
functionGenerationContext.unreachable()
|
||||
needsNativeThreadState ->
|
||||
functionGenerationContext.switchThreadState(ThreadState.Runnable)
|
||||
}
|
||||
|
||||
if (LLVMGetReturnType(getFunctionType(llvmFunction)) == voidType) {
|
||||
|
||||
+8
@@ -28,6 +28,10 @@ abstract class AbstractKonanIrMangler(private val withReturnType: Boolean) : IrB
|
||||
// Treat any `@SymbolName` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(KonanFqNames.gcUnsafeCall)) {
|
||||
// Treat any `@GCUnsafeCall` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
|
||||
// Treat any `@ExportForCppRuntime` declaration as exported.
|
||||
return true
|
||||
@@ -99,6 +103,10 @@ abstract class AbstractKonanDescriptorMangler : DescriptorBasedKotlinManglerImpl
|
||||
// Treat any `@SymbolName` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(KonanFqNames.gcUnsafeCall)) {
|
||||
// Treat any `@GCUnsafeCall` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
|
||||
// Treat any `@ExportForCppRuntime` declaration as exported.
|
||||
return true
|
||||
|
||||
@@ -3830,6 +3830,11 @@ createInterop("cppSkia") {
|
||||
it.defFile 'interop/cpp/skia.def'
|
||||
}
|
||||
|
||||
createInterop("threadStates") {
|
||||
it.defFile "interop/threadStates/threadStates.def"
|
||||
it.extraOpts "-Xcompile-source", "$projectDir/interop/threadStates/threadStates.cpp"
|
||||
}
|
||||
|
||||
if (PlatformInfo.isAppleTarget(project)) {
|
||||
createInterop("objcSmoke") {
|
||||
it.defFile 'interop/objc/objcSmoke.def'
|
||||
@@ -4117,6 +4122,20 @@ interopTest("interop_callbacksAndVarargs") {
|
||||
interop = 'ccallbacksAndVarargs'
|
||||
}
|
||||
|
||||
interopTest("interop_threadStates") {
|
||||
disabled = (project.testTarget == 'wasm32') || // No interop for wasm yet.
|
||||
!isExperimentalMM // No thread state switching in the legacy MM.
|
||||
source = "interop/threadStates/threadStates.kt"
|
||||
interop = "threadStates"
|
||||
}
|
||||
|
||||
interopTest("interop_threadStates_callbacksWithExceptions") {
|
||||
disabled = (project.testTarget == 'wasm32') || // No interop for wasm yet.
|
||||
!isExperimentalMM // No thread state switching in the legacy MM.
|
||||
source = "interop/threadStates/callbacksWithExceptions.kt"
|
||||
interop = "threadStates"
|
||||
}
|
||||
|
||||
interopTest("interop_withSpaces") {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
interop ='withSpaces'
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import kotlin.native.internal.Debugging
|
||||
import kotlin.test.*
|
||||
import kotlinx.cinterop.staticCFunction
|
||||
import threadStates.*
|
||||
|
||||
fun main() {
|
||||
callbackWithException()
|
||||
callbackWithFinally()
|
||||
callbackWithFinallyNoCatch()
|
||||
nestedCallbackWithException()
|
||||
nestedCallbackWithFinally()
|
||||
}
|
||||
|
||||
fun assertRunnableThreadState() {
|
||||
assertTrue(Debugging.isThreadStateRunnable)
|
||||
}
|
||||
|
||||
class CustomException() : Exception()
|
||||
|
||||
fun throwException() {
|
||||
assertRunnableThreadState()
|
||||
throw CustomException()
|
||||
}
|
||||
|
||||
fun callbackWithException() {
|
||||
try {
|
||||
runCallback(staticCFunction(::throwException))
|
||||
} catch (e: CustomException) {
|
||||
assertRunnableThreadState()
|
||||
return
|
||||
} catch (e: Throwable) {
|
||||
assertRunnableThreadState()
|
||||
fail("Wrong exception type: ${e.message}")
|
||||
}
|
||||
fail("No exception thrown")
|
||||
}
|
||||
|
||||
fun callbackWithFinally() {
|
||||
try {
|
||||
runCallback(staticCFunction(::throwException))
|
||||
} catch (e: CustomException) {
|
||||
assertRunnableThreadState()
|
||||
return
|
||||
} finally {
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
fail("No exception thrown")
|
||||
}
|
||||
|
||||
fun callbackWithFinallyNoCatch() {
|
||||
try {
|
||||
try {
|
||||
runCallback(staticCFunction(::throwException))
|
||||
} finally {
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
assertRunnableThreadState()
|
||||
} catch (_: CustomException) {}
|
||||
}
|
||||
|
||||
fun nestedCallbackWithException() {
|
||||
try {
|
||||
runCallback(staticCFunction { ->
|
||||
assertRunnableThreadState()
|
||||
runCallback(staticCFunction(::throwException))
|
||||
})
|
||||
} catch (e: CustomException) {
|
||||
assertRunnableThreadState()
|
||||
return
|
||||
} catch (e: Throwable) {
|
||||
assertRunnableThreadState()
|
||||
fail("Wrong exception type: ${e.message}")
|
||||
}
|
||||
fail("No exception thrown")
|
||||
}
|
||||
|
||||
fun nestedCallbackWithFinally() {
|
||||
try {
|
||||
runCallback(staticCFunction { ->
|
||||
assertRunnableThreadState()
|
||||
runCallback(staticCFunction(::throwException))
|
||||
})
|
||||
} catch (e: CustomException) {
|
||||
assertRunnableThreadState()
|
||||
return
|
||||
} finally {
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
fail("No exception thrown")
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <thread>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Implemented in the runtime for test purposes.
|
||||
extern "C" bool Kotlin_Debugging_isThreadStateNative();
|
||||
|
||||
extern "C" void assertNativeThreadState() {
|
||||
if (!Kotlin_Debugging_isThreadStateNative()) {
|
||||
printf("Incorrect thread state. Expected native thread state.");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void runInNewThread(void(*callback)(void)) {
|
||||
std::thread t([callback]() {
|
||||
callback();
|
||||
});
|
||||
t.join();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
language = C
|
||||
|
||||
---
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void assertNativeThreadState();
|
||||
|
||||
void runCallback(void(*callback)(void)) {
|
||||
assertNativeThreadState();
|
||||
callback();
|
||||
assertNativeThreadState();
|
||||
}
|
||||
|
||||
int32_t answer() {
|
||||
assertNativeThreadState();
|
||||
return 42;
|
||||
}
|
||||
|
||||
void runInNewThread(void(*callback)(void));
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import kotlin.native.internal.Debugging
|
||||
import kotlin.test.*
|
||||
import kotlinx.cinterop.*
|
||||
import threadStates.*
|
||||
|
||||
fun main() {
|
||||
nativeCall()
|
||||
callback()
|
||||
nestedCalls()
|
||||
directStaticCFunctionCall()
|
||||
// TODO: Support runtime initialization for callbacks
|
||||
// see: https://youtrack.jetbrains.com/issue/KT-44283
|
||||
// callbackOnSeparateThread()
|
||||
}
|
||||
|
||||
fun assertRunnableThreadState() {
|
||||
assertTrue(Debugging.isThreadStateRunnable)
|
||||
}
|
||||
|
||||
fun nativeCall() {
|
||||
answer()
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
|
||||
fun callback() {
|
||||
runCallback(staticCFunction { ->
|
||||
assertRunnableThreadState()
|
||||
})
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
|
||||
fun nestedCalls() {
|
||||
runCallback(staticCFunction { ->
|
||||
assertRunnableThreadState()
|
||||
answer()
|
||||
Unit
|
||||
})
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
|
||||
fun directStaticCFunctionCall() {
|
||||
val funPtr = staticCFunction { ->
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
assertRunnableThreadState()
|
||||
funPtr()
|
||||
assertRunnableThreadState()
|
||||
}
|
||||
|
||||
fun callbackOnSeparateThread() {
|
||||
runInNewThread(staticCFunction { ->
|
||||
assertRunnableThreadState()
|
||||
})
|
||||
}
|
||||
@@ -110,8 +110,12 @@ int Konan_DebugBufferSizeWithObjectImpl(KRef obj) {
|
||||
|
||||
// Auxilary function which can be called by developer/debugger to inspect an object.
|
||||
int32_t Konan_DebugObjectToUtf8ArrayImpl(KRef obj, char* buffer, int32_t bufferSize) {
|
||||
// We need the runnable thread state to call the Kotlin function 'KonanObjectToUtf8Array' and operate with it's result.
|
||||
// But the current thread can be in any state when this function is called by the debugger. So we use the reentrant state switch.
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kRunnable, /* reentrant */ true);
|
||||
ObjHolder stringHolder;
|
||||
auto data = KonanObjectToUtf8Array(obj, stringHolder.slot())->array();
|
||||
// Kotlin call.
|
||||
ArrayHeader* data = KonanObjectToUtf8Array(obj, stringHolder.slot())->array();
|
||||
if (data == nullptr) return 0;
|
||||
if (bufferSize < 1) return 0;
|
||||
KInt toCopy = data->count_ > static_cast<uint32_t>(bufferSize - 1) ? bufferSize - 1 : data->count_;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "MarkAndSweepUtils.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <TestSupport.hpp>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
@@ -142,6 +143,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
kotlin::ScopedMemoryInit memoryInit;
|
||||
ScopedMarkTraits markTraits_;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <TestSupport.hpp>
|
||||
#include "MarkAndSweepUtils.hpp"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
@@ -232,6 +233,8 @@ public:
|
||||
testing::MockFunction<void(ObjHeader*)>& finalizerHook() { return finalizerHooks_.finalizerHook(); }
|
||||
|
||||
private:
|
||||
// TODO: Provide a common base class for all unit tests that require memory initializtion.
|
||||
kotlin::ScopedMemoryInit memoryInit;
|
||||
FinalizerHooksTestSupport finalizerHooks_;
|
||||
GC::ThreadData gcThreadData_;
|
||||
ObjectFactory objectFactory_;
|
||||
|
||||
@@ -3576,6 +3576,10 @@ RUNTIME_NOTHROW void DisposeStablePointer(KNativePtr pointer) {
|
||||
disposeStablePointer(pointer);
|
||||
}
|
||||
|
||||
RUNTIME_NOTHROW void DisposeStablePointerFor(MemoryState* memoryState, KNativePtr pointer) {
|
||||
DisposeStablePointer(pointer);
|
||||
}
|
||||
|
||||
OBJ_GETTER(DerefStablePointer, KNativePtr pointer) {
|
||||
RETURN_RESULT_OF(derefStablePointer, pointer);
|
||||
}
|
||||
@@ -3716,7 +3720,7 @@ ALWAYS_INLINE ObjHeader* ExceptionObjHolder::GetExceptionObject() noexcept {
|
||||
}
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE kotlin::ThreadState kotlin::SwitchThreadState(MemoryState* thread, ThreadState newState) noexcept {
|
||||
ALWAYS_INLINE kotlin::ThreadState kotlin::SwitchThreadState(MemoryState* thread, ThreadState newState, bool reentrant) noexcept {
|
||||
// no-op, used by the new MM only.
|
||||
return ThreadState::kRunnable;
|
||||
}
|
||||
@@ -3727,4 +3731,9 @@ ALWAYS_INLINE void kotlin::AssertThreadState(MemoryState* thread, ThreadState ex
|
||||
|
||||
MemoryState* kotlin::mm::GetMemoryState() {
|
||||
return ::memoryState;
|
||||
}
|
||||
|
||||
kotlin::ThreadState kotlin::GetThreadState(MemoryState* thread) noexcept {
|
||||
// Assume that we are always in the Runnable thread state.
|
||||
return ThreadState::kRunnable;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "TestSupport.hpp"
|
||||
|
||||
extern "C" void Kotlin_TestSupport_AssertClearGlobalState() {
|
||||
// Nothing to do. Supported for the new MM only.
|
||||
}
|
||||
|
||||
void kotlin::DeinitMemoryForTests(MemoryState* memoryState) {
|
||||
DeinitMemory(memoryState, false);
|
||||
}
|
||||
@@ -66,26 +66,30 @@ RUNTIME_NOTHROW void DisposeCleaner(KRef thiz) {
|
||||
|
||||
void ShutdownCleaners(bool executeScheduledCleaners) {
|
||||
KInt worker = 0;
|
||||
do {
|
||||
worker = atomicGet(&globalCleanerWorker);
|
||||
RuntimeAssert(worker != kCleanerWorkerShutdown, "Cleaner worker must not be shutdown twice");
|
||||
if (worker == kCleanerWorkerUninitialized) {
|
||||
if (!compareAndSet(&globalCleanerWorker, kCleanerWorkerUninitialized, kCleanerWorkerShutdown)) {
|
||||
{
|
||||
// This loop may spin waiting for a proper worker state. Switch to the native thread state.
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
do {
|
||||
worker = atomicGet(&globalCleanerWorker);
|
||||
RuntimeAssert(worker != kCleanerWorkerShutdown, "Cleaner worker must not be shutdown twice");
|
||||
if (worker == kCleanerWorkerUninitialized) {
|
||||
if (!compareAndSet(&globalCleanerWorker, kCleanerWorkerUninitialized, kCleanerWorkerShutdown)) {
|
||||
// Someone is trying to initialize the worker. Try again.
|
||||
continue;
|
||||
}
|
||||
// worker was never initialized. Just return.
|
||||
return;
|
||||
}
|
||||
if (worker == kCleanerWorkerInitializing) {
|
||||
// Someone is trying to initialize the worker. Try again.
|
||||
continue;
|
||||
}
|
||||
// worker was never initialized. Just return.
|
||||
return;
|
||||
}
|
||||
if (worker == kCleanerWorkerInitializing) {
|
||||
// Someone is trying to initialize the worker. Try again.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Worker is in some proper state.
|
||||
break;
|
||||
// Worker is in some proper state.
|
||||
break;
|
||||
|
||||
} while (true);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
RuntimeAssert(worker > 0, "Cleaner worker must be fully initialized here");
|
||||
|
||||
@@ -96,6 +100,8 @@ void ShutdownCleaners(bool executeScheduledCleaners) {
|
||||
|
||||
extern "C" KInt Kotlin_CleanerImpl_getCleanerWorker() {
|
||||
KInt worker = 0;
|
||||
// This loop may spin waiting for a proper worker state. Switch to the native thread state.
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
do {
|
||||
worker = atomicGet(&globalCleanerWorker);
|
||||
RuntimeAssert(worker != kCleanerWorkerShutdown, "Cleaner worker must not have been shutdown");
|
||||
@@ -104,7 +110,7 @@ extern "C" KInt Kotlin_CleanerImpl_getCleanerWorker() {
|
||||
// Someone else is trying to initialize the worker. Try again.
|
||||
continue;
|
||||
}
|
||||
worker = Kotlin_CleanerImpl_createCleanerWorker();
|
||||
worker = kotlin::CallWithThreadState<kotlin::ThreadState::kRunnable>(Kotlin_CleanerImpl_createCleanerWorker);
|
||||
if (!compareAndSet(&globalCleanerWorker, kCleanerWorkerInitializing, worker)) {
|
||||
RuntimeCheck(false, "Someone interrupted worker initializing");
|
||||
}
|
||||
|
||||
@@ -15,13 +15,20 @@
|
||||
#include "TestSupportCompilerGenerated.hpp"
|
||||
#include "Types.h"
|
||||
|
||||
using namespace kotlin;
|
||||
using testing::_;
|
||||
|
||||
// TODO: Also test disposal. (This requires extracting Worker interface)
|
||||
|
||||
TEST(CleanerTest, ConcurrentCreation) {
|
||||
ResetCleanerWorkerForTests();
|
||||
class CleanerTest : public testing::Test {
|
||||
public:
|
||||
CleanerTest() {}
|
||||
~CleanerTest() {
|
||||
ResetCleanerWorkerForTests();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CleanerTest, ConcurrentCreation) {
|
||||
constexpr int threadCount = kotlin::kDefaultThreadCount;
|
||||
constexpr KInt workerId = 42;
|
||||
|
||||
@@ -34,6 +41,8 @@ TEST(CleanerTest, ConcurrentCreation) {
|
||||
KStdVector<std::future<KInt>> futures;
|
||||
for (int i = 0; i < threadCount; ++i) {
|
||||
auto future = std::async(std::launch::async, [&startedThreads, &allowRunning]() {
|
||||
// Thread state switching requires initilized memory subsystem.
|
||||
ScopedMemoryInit init;
|
||||
atomicAdd(&startedThreads, 1);
|
||||
while (!atomicGet(&allowRunning)) {
|
||||
}
|
||||
@@ -53,29 +62,28 @@ TEST(CleanerTest, ConcurrentCreation) {
|
||||
EXPECT_THAT(values, testing::Each(workerId));
|
||||
}
|
||||
|
||||
TEST(CleanerTest, ShutdownWithoutCreation) {
|
||||
ResetCleanerWorkerForTests();
|
||||
TEST_F(CleanerTest, ShutdownWithoutCreation) {
|
||||
RunInNewThread([]() {
|
||||
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
|
||||
auto shutdownCleanerWorkerMock = ScopedShutdownCleanerWorkerMock();
|
||||
|
||||
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
|
||||
auto shutdownCleanerWorkerMock = ScopedShutdownCleanerWorkerMock();
|
||||
|
||||
EXPECT_CALL(*createCleanerWorkerMock, Call()).Times(0);
|
||||
EXPECT_CALL(*shutdownCleanerWorkerMock, Call(_, _)).Times(0);
|
||||
ShutdownCleaners(true);
|
||||
EXPECT_CALL(*createCleanerWorkerMock, Call()).Times(0);
|
||||
EXPECT_CALL(*shutdownCleanerWorkerMock, Call(_, _)).Times(0);
|
||||
ShutdownCleaners(true);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(CleanerTest, ShutdownWithCreation) {
|
||||
ResetCleanerWorkerForTests();
|
||||
TEST_F(CleanerTest, ShutdownWithCreation) {
|
||||
RunInNewThread([]() {
|
||||
constexpr KInt workerId = 42;
|
||||
constexpr bool executeScheduledCleaners = true;
|
||||
|
||||
constexpr KInt workerId = 42;
|
||||
constexpr bool executeScheduledCleaners = true;
|
||||
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
|
||||
auto shutdownCleanerWorkerMock = ScopedShutdownCleanerWorkerMock();
|
||||
EXPECT_CALL(*createCleanerWorkerMock, Call()).WillOnce(testing::Return(workerId));
|
||||
Kotlin_CleanerImpl_getCleanerWorker();
|
||||
|
||||
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
|
||||
auto shutdownCleanerWorkerMock = ScopedShutdownCleanerWorkerMock();
|
||||
|
||||
EXPECT_CALL(*createCleanerWorkerMock, Call()).WillOnce(testing::Return(workerId));
|
||||
Kotlin_CleanerImpl_getCleanerWorker();
|
||||
|
||||
EXPECT_CALL(*shutdownCleanerWorkerMock, Call(workerId, executeScheduledCleaners));
|
||||
ShutdownCleaners(executeScheduledCleaners);
|
||||
EXPECT_CALL(*shutdownCleanerWorkerMock, Call(workerId, executeScheduledCleaners));
|
||||
ShutdownCleaners(executeScheduledCleaners);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,36 +27,44 @@ extern "C" {
|
||||
|
||||
// io/Console.kt
|
||||
void Kotlin_io_Console_print(KString message) {
|
||||
if (message->type_info() != theStringTypeInfo) {
|
||||
ThrowClassCastException(message->obj(), theStringTypeInfo);
|
||||
}
|
||||
// TODO: system stdout must be aware about UTF-8.
|
||||
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
|
||||
KStdString utf8;
|
||||
utf8.reserve(message->count_);
|
||||
// Replace incorrect sequences with a default codepoint (see utf8::with_replacement::default_replacement)
|
||||
utf8::with_replacement::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8));
|
||||
konan::consoleWriteUtf8(utf8.c_str(), utf8.size());
|
||||
if (message->type_info() != theStringTypeInfo) {
|
||||
ThrowClassCastException(message->obj(), theStringTypeInfo);
|
||||
}
|
||||
// TODO: system stdout must be aware about UTF-8.
|
||||
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
|
||||
KStdString utf8;
|
||||
utf8.reserve(message->count_);
|
||||
// Replace incorrect sequences with a default codepoint (see utf8::with_replacement::default_replacement)
|
||||
utf8::with_replacement::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8));
|
||||
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
konan::consoleWriteUtf8(utf8.c_str(), utf8.size());
|
||||
}
|
||||
|
||||
void Kotlin_io_Console_println(KString message) {
|
||||
Kotlin_io_Console_print(message);
|
||||
Kotlin_io_Console_print(message);
|
||||
#ifndef KONAN_ANDROID
|
||||
// On Android single print produces logcat entry, so no need in linefeed.
|
||||
Kotlin_io_Console_println0();
|
||||
// On Android single print produces logcat entry, so no need in linefeed.
|
||||
Kotlin_io_Console_println0();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Kotlin_io_Console_println0() {
|
||||
konan::consoleWriteUtf8("\n", 1);
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
konan::consoleWriteUtf8("\n", 1);
|
||||
}
|
||||
|
||||
OBJ_GETTER0(Kotlin_io_Console_readLine) {
|
||||
char data[4096];
|
||||
if (konan::consoleReadUtf8(data, sizeof(data)) < 0) {
|
||||
RETURN_OBJ(nullptr);
|
||||
}
|
||||
RETURN_RESULT_OF(CreateStringFromCString, data);
|
||||
char data[4096];
|
||||
int32_t result;
|
||||
{
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
result = konan::consoleReadUtf8(data, sizeof(data));
|
||||
}
|
||||
if (result < 0) {
|
||||
RETURN_OBJ(nullptr);
|
||||
}
|
||||
RETURN_RESULT_OF(CreateStringFromCString, data);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -91,6 +91,9 @@ _Unwind_Reason_Code unwindCallback(
|
||||
#else
|
||||
_Unwind_Ptr address = _Unwind_GetIP(context);
|
||||
#endif
|
||||
// We run the unwinding process in the native thread state. But setting a next element
|
||||
// requires writing to a Kotlin array which must be performed in the runnable thread state.
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kRunnable);
|
||||
backtrace->setNextElement(address);
|
||||
|
||||
return _URC_NO_REASON;
|
||||
@@ -100,7 +103,7 @@ _Unwind_Reason_Code unwindCallback(
|
||||
THREAD_LOCAL_VARIABLE bool disallowSourceInfo = false;
|
||||
|
||||
#if !OMIT_BACKTRACE && !USE_GCC_UNWIND
|
||||
SourceInfo getSourceInfo(KConstRef stackTrace, int index) {
|
||||
SourceInfo getSourceInfo(KConstRef stackTrace, int32_t index) {
|
||||
return disallowSourceInfo
|
||||
? SourceInfo { .fileName = nullptr, .lineNumber = -1, .column = -1 }
|
||||
: Kotlin_getSourceInfo(*PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), index));
|
||||
@@ -112,6 +115,7 @@ SourceInfo getSourceInfo(KConstRef stackTrace, int index) {
|
||||
// TODO: this implementation is just a hack, e.g. the result is inexact;
|
||||
// however it is better to have an inexact stacktrace than not to have any.
|
||||
NO_INLINE OBJ_GETTER0(Kotlin_getCurrentStackTrace) {
|
||||
using namespace kotlin;
|
||||
#if OMIT_BACKTRACE
|
||||
return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT);
|
||||
#else
|
||||
@@ -119,17 +123,17 @@ NO_INLINE OBJ_GETTER0(Kotlin_getCurrentStackTrace) {
|
||||
constexpr int kSkipFrames = 2;
|
||||
#if USE_GCC_UNWIND
|
||||
int depth = 0;
|
||||
_Unwind_Backtrace(depthCountCallback, &depth);
|
||||
CallWithThreadState<ThreadState::kNative>(_Unwind_Backtrace, depthCountCallback, static_cast<void*>(&depth));
|
||||
Backtrace result(depth, kSkipFrames);
|
||||
if (result.obj()->array()->count_ > 0) {
|
||||
_Unwind_Backtrace(unwindCallback, &result);
|
||||
CallWithThreadState<ThreadState::kNative>(_Unwind_Backtrace, unwindCallback, static_cast<void*>(&result));
|
||||
}
|
||||
RETURN_OBJ(result.obj());
|
||||
#else
|
||||
const int maxSize = 32;
|
||||
void* buffer[maxSize];
|
||||
|
||||
int size = backtrace(buffer, maxSize);
|
||||
int size = kotlin::CallWithThreadState<kotlin::ThreadState::kNative>(backtrace, buffer, maxSize);
|
||||
if (size < kSkipFrames)
|
||||
return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT);
|
||||
|
||||
@@ -144,6 +148,7 @@ NO_INLINE OBJ_GETTER0(Kotlin_getCurrentStackTrace) {
|
||||
}
|
||||
|
||||
OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
|
||||
using namespace kotlin;
|
||||
#if OMIT_BACKTRACE
|
||||
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT);
|
||||
ObjHolder holder;
|
||||
@@ -151,14 +156,14 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
|
||||
UpdateHeapRef(ArrayAddressOfElementAt(result->array(), 0), holder.obj());
|
||||
return result;
|
||||
#else
|
||||
uint32_t size = stackTrace->array()->count_;
|
||||
int32_t size = static_cast<int32_t>(stackTrace->array()->count_);
|
||||
ObjHolder resultHolder;
|
||||
ObjHeader* strings = AllocArrayInstance(theArrayTypeInfo, size, resultHolder.slot());
|
||||
#if USE_GCC_UNWIND
|
||||
for (uint32_t index = 0; index < size; ++index) {
|
||||
for (int32_t index = 0; index < size; ++index) {
|
||||
KNativePtr address = Kotlin_NativePtrArray_get(stackTrace, index);
|
||||
char symbol[512];
|
||||
if (!AddressToSymbol((const void*) address, symbol, sizeof(symbol))) {
|
||||
if (!CallWithThreadState<ThreadState::kNative>(AddressToSymbol, (const void*) address, symbol, sizeof(symbol))) {
|
||||
// Make empty string:
|
||||
symbol[0] = '\0';
|
||||
}
|
||||
@@ -170,11 +175,12 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
|
||||
}
|
||||
#else
|
||||
if (size > 0) {
|
||||
char **symbols = backtrace_symbols(PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), 0), size);
|
||||
char **symbols = CallWithThreadState<ThreadState::kNative>(
|
||||
backtrace_symbols, PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), 0), size);
|
||||
RuntimeCheck(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
|
||||
|
||||
for (uint32_t index = 0; index < size; ++index) {
|
||||
auto sourceInfo = getSourceInfo(stackTrace, index);
|
||||
for (int32_t index = 0; index < size; ++index) {
|
||||
auto sourceInfo = CallWithThreadState<ThreadState::kNative>(getSourceInfo, stackTrace, index);
|
||||
const char* symbol = symbols[index];
|
||||
const char* result;
|
||||
char line[1024];
|
||||
|
||||
@@ -243,10 +243,13 @@ void LeaveFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|
||||
// checks if subgraph referenced by given root is disjoint from the rest of
|
||||
// object graph, i.e. no external references exists.
|
||||
bool ClearSubgraphReferences(ObjHeader* root, bool checked) RUNTIME_NOTHROW;
|
||||
// Creates stable pointer out of the object.
|
||||
// Creates a stable pointer out of the object.
|
||||
void* CreateStablePointer(ObjHeader* obj) RUNTIME_NOTHROW;
|
||||
// Disposes stable pointer to the object.
|
||||
// Disposes a stable pointer to the object.
|
||||
void DisposeStablePointer(void* pointer) RUNTIME_NOTHROW;
|
||||
// Disposes a stable pointer to the object.
|
||||
// Accepts a MemoryState, thus can be called from deinitiliazation methods, when TLS is already deallocated.
|
||||
void DisposeStablePointerFor(MemoryState* memoryState, void* pointer) RUNTIME_NOTHROW;
|
||||
// Translate stable pointer to object reference.
|
||||
OBJ_GETTER(DerefStablePointer, void*) RUNTIME_NOTHROW;
|
||||
// Move stable pointer ownership.
|
||||
@@ -394,8 +397,14 @@ enum class ThreadState {
|
||||
kRunnable, kNative
|
||||
};
|
||||
|
||||
ThreadState GetThreadState(MemoryState* thread) noexcept;
|
||||
|
||||
inline ThreadState GetThreadState() noexcept {
|
||||
return GetThreadState(mm::GetMemoryState());
|
||||
}
|
||||
|
||||
// Switches the state of the given thread to `newState` and returns the previous thread state.
|
||||
ALWAYS_INLINE ThreadState SwitchThreadState(MemoryState* thread, ThreadState newState) noexcept;
|
||||
ALWAYS_INLINE ThreadState SwitchThreadState(MemoryState* thread, ThreadState newState, bool reentrant = false) noexcept;
|
||||
|
||||
// Asserts that the given thread is in the given state.
|
||||
ALWAYS_INLINE void AssertThreadState(MemoryState* thread, ThreadState expected) noexcept;
|
||||
@@ -409,35 +418,27 @@ ALWAYS_INLINE inline void AssertThreadState(ThreadState expected) noexcept {
|
||||
class ThreadStateGuard final : private Pinned {
|
||||
public:
|
||||
// Set the state for the given thread.
|
||||
ThreadStateGuard(MemoryState* thread, ThreadState state) noexcept : thread_(thread) {
|
||||
oldState_ = SwitchThreadState(thread_, state);
|
||||
ThreadStateGuard(MemoryState* thread, ThreadState state, bool reentrant = false) noexcept : thread_(thread), reentrant_(reentrant) {
|
||||
oldState_ = SwitchThreadState(thread_, state, reentrant_);
|
||||
}
|
||||
|
||||
// Sets the state for the current thread.
|
||||
explicit ThreadStateGuard(ThreadState state) noexcept
|
||||
: ThreadStateGuard(mm::GetMemoryState(), state) {};
|
||||
explicit ThreadStateGuard(ThreadState state, bool reentrant = false) noexcept
|
||||
: ThreadStateGuard(mm::GetMemoryState(), state, reentrant) {};
|
||||
|
||||
~ThreadStateGuard() noexcept {
|
||||
SwitchThreadState(thread_, oldState_);
|
||||
SwitchThreadState(thread_, oldState_, reentrant_);
|
||||
}
|
||||
private:
|
||||
MemoryState* thread_;
|
||||
ThreadState oldState_;
|
||||
bool reentrant_;
|
||||
};
|
||||
|
||||
// Calls the given function in the `Runnable` thread state.
|
||||
template <typename R, typename... Args>
|
||||
ALWAYS_INLINE inline R CallKotlin(R(*kotlinFunction)(Args...), Args... args) {
|
||||
ThreadStateGuard guard(ThreadState::kRunnable);
|
||||
return kotlinFunction(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Calls the given function in the `Runnable` thread state. The function must be marked as RUNTIME_NORETURN.
|
||||
// If the function returns, behaviour is undefined.
|
||||
template <typename... Args>
|
||||
ALWAYS_INLINE RUNTIME_NORETURN inline void CallKotlinNoReturn(void(*noreturnKotlinFunction)(Args...), Args... args) {
|
||||
CallKotlin(noreturnKotlinFunction, std::forward<Args>(args)...);
|
||||
RuntimeFail("The function must not return");
|
||||
template <ThreadState state, typename R, typename... Args>
|
||||
ALWAYS_INLINE inline R CallWithThreadState(R(*function)(Args...), Args... args) {
|
||||
ThreadStateGuard guard(state);
|
||||
return function(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace kotlin
|
||||
|
||||
@@ -105,7 +105,7 @@ RuntimeState* initRuntime() {
|
||||
case DESTROY_RUNTIME_LEGACY:
|
||||
compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning);
|
||||
result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode
|
||||
result->worker = WorkerInit(true);
|
||||
result->worker = WorkerInit(result->memoryState, true);
|
||||
firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1;
|
||||
if (CurrentMemoryModel == MemoryModel::kExperimental) {
|
||||
RuntimeCheck(firstRuntime, "Experimental MM does not support multiple mutator threads yet");
|
||||
@@ -124,7 +124,7 @@ RuntimeState* initRuntime() {
|
||||
RuntimeCheck(firstRuntime, "Experimental MM does not support multiple mutator threads yet");
|
||||
}
|
||||
result->memoryState = InitMemory(firstRuntime);
|
||||
result->worker = WorkerInit(true);
|
||||
result->worker = WorkerInit(result->memoryState, true);
|
||||
}
|
||||
|
||||
InitOrDeinitGlobalVariables(ALLOC_THREAD_LOCAL_GLOBALS, result->memoryState);
|
||||
@@ -370,4 +370,12 @@ void Kotlin_Debugging_setForceCheckedShutdown(KBoolean value) {
|
||||
g_forceCheckedShutdown = value;
|
||||
}
|
||||
|
||||
KBoolean Kotlin_Debugging_isThreadStateRunnable() {
|
||||
return kotlin::GetThreadState() == kotlin::ThreadState::kRunnable;
|
||||
}
|
||||
|
||||
KBoolean Kotlin_Debugging_isThreadStateNative() {
|
||||
return kotlin::GetThreadState() == kotlin::ThreadState::kNative;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -21,13 +21,16 @@ constexpr int kDefaultThreadCount = 10;
|
||||
constexpr int kDefaultThreadCount = 100;
|
||||
#endif
|
||||
|
||||
inline MemoryState* InitMemoryForTests() { return InitMemory(false); }
|
||||
void DeinitMemoryForTests(MemoryState* memoryState);
|
||||
|
||||
// Scopely initializes the memory subsystem of the current thread for tests.
|
||||
class ScopedRuntimeInit : private kotlin::Pinned {
|
||||
class ScopedMemoryInit : private kotlin::Pinned {
|
||||
public:
|
||||
ScopedRuntimeInit() : memoryState_(InitMemory(false)) {}
|
||||
~ScopedRuntimeInit() {
|
||||
ScopedMemoryInit() : memoryState_(InitMemoryForTests()) {}
|
||||
~ScopedMemoryInit() {
|
||||
ClearMemoryForTests(memoryState());
|
||||
DeinitMemory(memoryState_, false);
|
||||
DeinitMemoryForTests(memoryState());
|
||||
}
|
||||
|
||||
MemoryState* memoryState() { return memoryState_; }
|
||||
@@ -38,7 +41,7 @@ private:
|
||||
// Runs the given function in a separate thread with minimally initialized runtime.
|
||||
inline void RunInNewThread(std::function<void(MemoryState*)> f) {
|
||||
std::thread([&f]() {
|
||||
ScopedRuntimeInit init;
|
||||
ScopedMemoryInit init;
|
||||
f(init.memoryState());
|
||||
}).join();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "Types.h"
|
||||
#include "Worker.h"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
extern "C" {
|
||||
|
||||
RUNTIME_NORETURN void ThrowWorkerInvalidState();
|
||||
@@ -150,7 +152,26 @@ class Worker {
|
||||
|
||||
pthread_t thread() const { return thread_; }
|
||||
|
||||
MemoryState* memoryState() { return memoryState_; }
|
||||
|
||||
private:
|
||||
void setThread(pthread_t thread) {
|
||||
// For workers started using the Worker API, we set thread_ in startEventLoop when calling pthread_create.
|
||||
// But we also set thread_ in WorkerInit to handle the main thread and threads calling Kotlin from native code.
|
||||
// In this case, thread id will be set twice for workers started by the Worker API.
|
||||
// This assert takes this into account.
|
||||
RuntimeAssert(thread_ == 0 || pthread_equal(thread_, thread),
|
||||
"Cannot overwrite thread id for worker with id=%d", id());
|
||||
thread_ = thread;
|
||||
}
|
||||
|
||||
void setMemoryState(MemoryState* state) {
|
||||
RuntimeAssert(memoryState_ == nullptr, "MemoryState is already set for the worker with id=%d", id());
|
||||
memoryState_ = state;
|
||||
}
|
||||
|
||||
friend Worker* WorkerInit(MemoryState* memoryState, KBoolean errorReporting);
|
||||
|
||||
KInt id_;
|
||||
WorkerKind kind_;
|
||||
KStdDeque<Job> queue_;
|
||||
@@ -164,6 +185,9 @@ class Worker {
|
||||
bool errorReporting_;
|
||||
bool terminated_ = false;
|
||||
pthread_t thread_ = 0;
|
||||
// MemoryState for worker's thread.
|
||||
// We set it in WorkerInit and use to correctly switch thread states in woker's destructor.
|
||||
MemoryState* memoryState_ = nullptr;
|
||||
};
|
||||
|
||||
#endif // WITH_WORKERS
|
||||
@@ -184,17 +208,40 @@ KNativePtr transfer(ObjHolder* holder, KInt mode) {
|
||||
return result;
|
||||
}
|
||||
|
||||
class Locker {
|
||||
public:
|
||||
explicit Locker(pthread_mutex_t* lock) : lock_(lock) {
|
||||
pthread_mutex_lock(lock_);
|
||||
}
|
||||
~Locker() {
|
||||
pthread_mutex_unlock(lock_);
|
||||
}
|
||||
void waitInNativeState(pthread_cond_t* cond, pthread_mutex_t* mutex) {
|
||||
CallWithThreadState<ThreadState::kNative>(pthread_cond_wait, cond, mutex);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t* lock_;
|
||||
void waitInNativeState(pthread_cond_t* cond,
|
||||
pthread_mutex_t* mutex,
|
||||
uint64_t timeoutNanoseconds,
|
||||
uint64_t* microsecondsPassed = nullptr) {
|
||||
CallWithThreadState<ThreadState::kNative>(WaitOnCondVar, cond, mutex, timeoutNanoseconds, microsecondsPassed);
|
||||
}
|
||||
|
||||
class Locker {
|
||||
public:
|
||||
explicit Locker(pthread_mutex_t* lock, bool switchThreadState = true) : lock_(lock) {
|
||||
if (switchThreadState) {
|
||||
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||
pthread_mutex_lock(lock_);
|
||||
} else {
|
||||
// We may need to create a locker when the current thread is already unregistered in the memory subsystem.
|
||||
// For such cases we allow locking without switching or checking the thread state.
|
||||
pthread_mutex_lock(lock_);
|
||||
}
|
||||
}
|
||||
Locker(pthread_mutex_t* lock, MemoryState* memoryState) : lock_(lock) {
|
||||
kotlin::ThreadStateGuard guard(memoryState, kotlin::ThreadState::kNative);
|
||||
pthread_mutex_lock(lock_);
|
||||
}
|
||||
|
||||
~Locker() {
|
||||
pthread_mutex_unlock(lock_);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t* lock_;
|
||||
};
|
||||
|
||||
class Future {
|
||||
@@ -222,7 +269,7 @@ class Future {
|
||||
OBJ_GETTER0(consumeResultUnlocked) {
|
||||
Locker locker(&lock_);
|
||||
while (state_ == SCHEDULED) {
|
||||
pthread_cond_wait(&cond_, &lock_);
|
||||
waitInNativeState(&cond_, &lock_);
|
||||
}
|
||||
// TODO: maybe use message from exception?
|
||||
if (state_ == THROWN)
|
||||
@@ -234,7 +281,7 @@ class Future {
|
||||
|
||||
void storeResultUnlocked(KNativePtr result, bool ok);
|
||||
|
||||
void cancelUnlocked();
|
||||
void cancelUnlocked(MemoryState* memoryState);
|
||||
|
||||
// Those are called with the lock taken.
|
||||
KInt state() const { return state_; }
|
||||
@@ -294,7 +341,11 @@ class State {
|
||||
|
||||
void destroyWorkerUnlocked(Worker* worker) {
|
||||
{
|
||||
Locker locker(&lock_);
|
||||
// We call destroyWorkerUnlocked from runtimeDeinit when TLS may be already deallocated,
|
||||
// so we have to use the pointer to MemoryState saved in the worker instance.
|
||||
RuntimeAssert(pthread_equal(worker->thread(), pthread_self()),
|
||||
"Worker destruction must be executed by the worker thread.");
|
||||
Locker locker(&lock_, worker->memoryState());
|
||||
auto id = worker->id();
|
||||
auto it = workers_.find(id);
|
||||
if (it != workers_.end()) {
|
||||
@@ -404,7 +455,6 @@ class State {
|
||||
auto it = futures_.find(id);
|
||||
if (it == futures_.end()) ThrowWorkerInvalidState();
|
||||
future = it->second;
|
||||
|
||||
}
|
||||
|
||||
KRef result = future->consumeResultUnlocked(OBJ_RESULT);
|
||||
@@ -424,12 +474,12 @@ class State {
|
||||
OBJ_GETTER(getWorkerNameUnlocked, KInt id) {
|
||||
ObjHolder nameHolder;
|
||||
{
|
||||
Locker locker(&lock_);
|
||||
auto it = workers_.find(id);
|
||||
if (it == workers_.end()) {
|
||||
ThrowWorkerInvalidState();
|
||||
}
|
||||
DerefStablePointer(it->second->name(), nameHolder.slot());
|
||||
Locker locker(&lock_);
|
||||
auto it = workers_.find(id);
|
||||
if (it == workers_.end()) {
|
||||
ThrowWorkerInvalidState();
|
||||
}
|
||||
DerefStablePointer(it->second->name(), nameHolder.slot());
|
||||
}
|
||||
RETURN_OBJ(nameHolder.obj());
|
||||
}
|
||||
@@ -439,12 +489,12 @@ class State {
|
||||
if (version != currentVersion_) return false;
|
||||
|
||||
if (millis < 0) {
|
||||
pthread_cond_wait(&cond_, &lock_);
|
||||
waitInNativeState(&cond_, &lock_);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t nsDelta = millis * 1000000LL;
|
||||
WaitOnCondVar(&cond_, &lock_, nsDelta);
|
||||
waitInNativeState(&cond_, &lock_, nsDelta);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -456,6 +506,14 @@ class State {
|
||||
pthread_cond_broadcast(&cond_);
|
||||
}
|
||||
|
||||
void signalAnyFuture(MemoryState* memoryState) {
|
||||
{
|
||||
Locker locker(&lock_, memoryState);
|
||||
currentVersion_++;
|
||||
}
|
||||
pthread_cond_broadcast(&cond_);
|
||||
}
|
||||
|
||||
KInt versionToken() {
|
||||
Locker locker(&lock_);
|
||||
return currentVersion_;
|
||||
@@ -466,7 +524,9 @@ class State {
|
||||
KInt nextFutureId() { return currentFutureId_++; }
|
||||
|
||||
void destroyWorkerThreadDataUnlocked(KInt id) {
|
||||
Locker locker(&lock_);
|
||||
// We destroy worker data when its thread is already unresigtered from the memory subsystem,
|
||||
// so there is no need to wrap the lock with a thread state switch.
|
||||
Locker locker(&lock_, false);
|
||||
auto it = terminating_native_workers_.find(id);
|
||||
if (it == terminating_native_workers_.end()) return;
|
||||
// If this worker was not joined, detach it to free resources.
|
||||
@@ -495,6 +555,7 @@ class State {
|
||||
}
|
||||
}
|
||||
|
||||
ThreadStateGuard guard(ThreadState::kNative);
|
||||
for (auto worker : workersToWait) {
|
||||
pthread_join(worker.second, nullptr);
|
||||
}
|
||||
@@ -561,14 +622,14 @@ void Future::storeResultUnlocked(KNativePtr result, bool ok) {
|
||||
theState()->signalAnyFuture();
|
||||
}
|
||||
|
||||
void Future::cancelUnlocked() {
|
||||
void Future::cancelUnlocked(MemoryState* memoryState) {
|
||||
{
|
||||
Locker locker(&lock_);
|
||||
Locker locker(&lock_, memoryState);
|
||||
state_ = CANCELLED;
|
||||
result_ = nullptr;
|
||||
pthread_cond_broadcast(&cond_);
|
||||
}
|
||||
theState()->signalAnyFuture();
|
||||
theState()->signalAnyFuture(memoryState);
|
||||
}
|
||||
|
||||
// Defined in RuntimeUtils.kt.
|
||||
@@ -672,7 +733,7 @@ KBoolean processQueue(KInt id) {
|
||||
}
|
||||
|
||||
KBoolean park(KInt id, KLong timeoutMicroseconds, KBoolean process) {
|
||||
ThrowWorkerUnsupported();
|
||||
ThrowWorkerUnsupported();
|
||||
}
|
||||
|
||||
KInt currentWorker() {
|
||||
@@ -704,7 +765,7 @@ OBJ_GETTER(attachObjectGraphInternal, KNativePtr stable) {
|
||||
}
|
||||
|
||||
KNativePtr detachObjectGraphInternal(KInt transferMode, KRef producer) {
|
||||
ThrowWorkerUnsupported();
|
||||
ThrowWorkerUnsupported();
|
||||
}
|
||||
|
||||
#endif // WITH_WORKERS
|
||||
@@ -719,11 +780,17 @@ KInt GetWorkerId(Worker* worker) {
|
||||
#endif // WITH_WORKERS
|
||||
}
|
||||
|
||||
Worker* WorkerInit(KBoolean errorReporting) {
|
||||
Worker* WorkerInit(MemoryState* memoryState, KBoolean errorReporting) {
|
||||
#if WITH_WORKERS
|
||||
if (::g_worker != nullptr) return ::g_worker;
|
||||
Worker* worker = theState()->addWorkerUnlocked(errorReporting != 0, nullptr, WorkerKind::kOther);
|
||||
::g_worker = worker;
|
||||
Worker* worker;
|
||||
if (::g_worker != nullptr) {
|
||||
worker = ::g_worker;
|
||||
} else {
|
||||
worker = theState()->addWorkerUnlocked(errorReporting != 0, nullptr, WorkerKind::kOther);
|
||||
::g_worker = worker;
|
||||
}
|
||||
worker->setThread(pthread_self());
|
||||
worker->setMemoryState(memoryState);
|
||||
return worker;
|
||||
#else
|
||||
return nullptr;
|
||||
@@ -745,7 +812,7 @@ void WorkerDestroyThreadDataIfNeeded(KInt id) {
|
||||
|
||||
void WaitNativeWorkersTermination() {
|
||||
#if WITH_WORKERS
|
||||
theState()->waitNativeWorkersTerminationUnlocked(true, [](KInt worker) { return true; });
|
||||
theState()->waitNativeWorkersTerminationUnlocked(true, [](KInt worker) { return true; });
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -766,36 +833,40 @@ bool WorkerSchedule(KInt id, KNativePtr jobStablePtr) {
|
||||
#if WITH_WORKERS
|
||||
|
||||
Worker::~Worker() {
|
||||
RuntimeAssert(pthread_equal(thread(), pthread_self()),
|
||||
"Worker destruction must be executed by the worker thread.");
|
||||
// Cleanup jobs in the queue.
|
||||
for (auto job : queue_) {
|
||||
switch (job.kind) {
|
||||
case JOB_REGULAR:
|
||||
DisposeStablePointer(job.regularJob.argument);
|
||||
job.regularJob.future->cancelUnlocked();
|
||||
break;
|
||||
case JOB_EXECUTE_AFTER: {
|
||||
// TODO: what do we do here? Shall we execute them?
|
||||
DisposeStablePointer(job.executeAfter.operation);
|
||||
break;
|
||||
switch (job.kind) {
|
||||
case JOB_REGULAR:
|
||||
DisposeStablePointerFor(memoryState_, job.regularJob.argument);
|
||||
job.regularJob.future->cancelUnlocked(memoryState_);
|
||||
break;
|
||||
case JOB_EXECUTE_AFTER: {
|
||||
// TODO: what do we do here? Shall we execute them?
|
||||
DisposeStablePointerFor(memoryState_, job.executeAfter.operation);
|
||||
break;
|
||||
}
|
||||
case JOB_TERMINATE: {
|
||||
// TODO: any more processing here?
|
||||
job.terminationRequest.future->cancelUnlocked(memoryState_);
|
||||
break;
|
||||
}
|
||||
case JOB_NONE: {
|
||||
RuntimeCheck(false, "Cannot be in queue");
|
||||
break;
|
||||
}
|
||||
}
|
||||
case JOB_TERMINATE: {
|
||||
// TODO: any more processing here?
|
||||
job.terminationRequest.future->cancelUnlocked();
|
||||
break;
|
||||
}
|
||||
case JOB_NONE: {
|
||||
RuntimeCheck(false, "Cannot be in queue");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto job : delayed_) {
|
||||
RuntimeAssert(job.kind == JOB_EXECUTE_AFTER, "Must be delayed");
|
||||
DisposeStablePointer(job.executeAfter.operation);
|
||||
RuntimeAssert(job.kind == JOB_EXECUTE_AFTER, "Must be delayed");
|
||||
DisposeStablePointerFor(memoryState_, job.executeAfter.operation);
|
||||
}
|
||||
|
||||
if (name_ != nullptr) DisposeStablePointer(name_);
|
||||
if (name_ != nullptr) {
|
||||
DisposeStablePointerFor(memoryState_, name_);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&lock_);
|
||||
pthread_cond_destroy(&cond_);
|
||||
@@ -892,12 +963,12 @@ bool Worker::waitForQueueLocked(KLong timeoutMicroseconds, KLong* remaining) {
|
||||
closestToRunMicroseconds = 10LL * 1000 * 1000 * 1000 * 1000;
|
||||
uint64_t nsDelta = closestToRunMicroseconds * 1000LL;
|
||||
uint64_t microsecondsPassed = 0;
|
||||
WaitOnCondVar(&cond_, &lock_, nsDelta, remaining ? µsecondsPassed : nullptr);
|
||||
waitInNativeState(&cond_, &lock_, nsDelta, remaining ? µsecondsPassed : nullptr);
|
||||
if (remaining) {
|
||||
*remaining = timeoutMicroseconds - microsecondsPassed;
|
||||
}
|
||||
} else {
|
||||
pthread_cond_wait(&cond_, &lock_);
|
||||
waitInNativeState(&cond_, &lock_);
|
||||
if (remaining) *remaining = 0;
|
||||
}
|
||||
if (timeoutMicroseconds >= 0) return queue_.size() != 0;
|
||||
@@ -928,8 +999,6 @@ bool Worker::park(KLong timeoutMicroseconds, bool process) {
|
||||
|
||||
JobKind Worker::processQueueElement(bool blocking) {
|
||||
GC_CollectorCallback(this);
|
||||
ObjHolder argumentHolder;
|
||||
ObjHolder resultHolder;
|
||||
if (terminated_) return JOB_TERMINATE;
|
||||
Job job = getJob(blocking);
|
||||
switch (job.kind) {
|
||||
@@ -965,9 +1034,11 @@ JobKind Worker::processQueueElement(bool blocking) {
|
||||
break;
|
||||
}
|
||||
case JOB_REGULAR: {
|
||||
KRef argument = AdoptStablePointer(job.regularJob.argument, argumentHolder.slot());
|
||||
KNativePtr result = nullptr;
|
||||
bool ok = true;
|
||||
ObjHolder argumentHolder;
|
||||
ObjHolder resultHolder;
|
||||
KRef argument = AdoptStablePointer(job.regularJob.argument, argumentHolder.slot());
|
||||
try {
|
||||
#if KONAN_OBJC_INTEROP
|
||||
konan::AutoreleasePool autoreleasePool;
|
||||
@@ -976,14 +1047,14 @@ JobKind Worker::processQueueElement(bool blocking) {
|
||||
argumentHolder.clear();
|
||||
// Transfer the result.
|
||||
result = transfer(&resultHolder, job.regularJob.transferMode);
|
||||
} catch (ExceptionObjHolder& e) {
|
||||
ok = false;
|
||||
if (errorReporting())
|
||||
ReportUnhandledException(e.GetExceptionObject());
|
||||
}
|
||||
// Notify the future.
|
||||
job.regularJob.future->storeResultUnlocked(result, ok);
|
||||
break;
|
||||
} catch (ExceptionObjHolder& e) {
|
||||
ok = false;
|
||||
if (errorReporting())
|
||||
ReportUnhandledException(e.GetExceptionObject());
|
||||
}
|
||||
// Notify the future.
|
||||
job.regularJob.future->storeResultUnlocked(result, ok);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
RuntimeCheck(false, "Must be exhaustive");
|
||||
|
||||
@@ -8,7 +8,7 @@ class Worker;
|
||||
|
||||
KInt GetWorkerId(Worker* worker);
|
||||
|
||||
Worker* WorkerInit(KBoolean errorReporting);
|
||||
Worker* WorkerInit(MemoryState* memoryState, KBoolean errorReporting);
|
||||
void WorkerDeinit(Worker* worker);
|
||||
// Clean up all associated thread state, if this was a native worker.
|
||||
void WorkerDestroyThreadDataIfNeeded(KInt id);
|
||||
|
||||
@@ -7,6 +7,7 @@ package kotlin
|
||||
|
||||
import kotlin.native.identityHashCode
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.
|
||||
@@ -25,7 +26,7 @@ public open class Any {
|
||||
*
|
||||
* Read more about [equality](https://kotlinlang.org/docs/reference/equality.html) in Kotlin.
|
||||
*/
|
||||
@SymbolName("Kotlin_Any_equals")
|
||||
@GCUnsafeCall("Kotlin_Any_equals")
|
||||
external public open operator fun equals(other: Any?): Boolean
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ package kotlin
|
||||
|
||||
import kotlin.native.internal.ExportForCompiler
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.PointsTo
|
||||
|
||||
/**
|
||||
@@ -53,7 +54,7 @@ public final class Array<T> {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_Array_get")
|
||||
@GCUnsafeCall("Kotlin_Array_get")
|
||||
@PointsTo(0x000, 0x000, 0x002) // ret -> this.intestines
|
||||
external public operator fun get(index: Int): T
|
||||
|
||||
@@ -66,7 +67,7 @@ public final class Array<T> {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_Array_set")
|
||||
@GCUnsafeCall("Kotlin_Array_set")
|
||||
@PointsTo(0x300, 0x000, 0x000) // this.intestines -> value
|
||||
external public operator fun set(index: Int, value: T): Unit
|
||||
|
||||
@@ -77,7 +78,7 @@ public final class Array<T> {
|
||||
return IteratorImpl(this)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Array_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_Array_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ package kotlin
|
||||
import kotlin.internal.PureReifiable
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.PointsTo
|
||||
|
||||
@@ -44,7 +45,7 @@ public final class ByteArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_get")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_get")
|
||||
external public operator fun get(index: Int): Byte
|
||||
|
||||
/**
|
||||
@@ -52,10 +53,10 @@ public final class ByteArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_set")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_set")
|
||||
external public operator fun set(index: Int, value: Byte): Unit
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -108,7 +109,7 @@ public final class CharArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_CharArray_get")
|
||||
@GCUnsafeCall("Kotlin_CharArray_get")
|
||||
external public operator fun get(index: Int): Char
|
||||
|
||||
/**
|
||||
@@ -116,10 +117,10 @@ public final class CharArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_CharArray_set")
|
||||
@GCUnsafeCall("Kotlin_CharArray_set")
|
||||
external public operator fun set(index: Int, value: Char): Unit
|
||||
|
||||
@SymbolName("Kotlin_CharArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_CharArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -172,7 +173,7 @@ public final class ShortArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_ShortArray_get")
|
||||
@GCUnsafeCall("Kotlin_ShortArray_get")
|
||||
external public operator fun get(index: Int): Short
|
||||
|
||||
/**
|
||||
@@ -180,10 +181,10 @@ public final class ShortArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_ShortArray_set")
|
||||
@GCUnsafeCall("Kotlin_ShortArray_set")
|
||||
external public operator fun set(index: Int, value: Short): Unit
|
||||
|
||||
@SymbolName("Kotlin_ShortArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_ShortArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -236,7 +237,7 @@ public final class IntArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_IntArray_get")
|
||||
@GCUnsafeCall("Kotlin_IntArray_get")
|
||||
external public operator fun get(index: Int): Int
|
||||
|
||||
/**
|
||||
@@ -244,10 +245,10 @@ public final class IntArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_IntArray_set")
|
||||
@GCUnsafeCall("Kotlin_IntArray_set")
|
||||
external public operator fun set(index: Int, value: Int): Unit
|
||||
|
||||
@SymbolName("Kotlin_IntArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_IntArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -300,7 +301,7 @@ public final class LongArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_LongArray_get")
|
||||
@GCUnsafeCall("Kotlin_LongArray_get")
|
||||
external public operator fun get(index: Int): Long
|
||||
|
||||
/**
|
||||
@@ -308,10 +309,10 @@ public final class LongArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_LongArray_set")
|
||||
@GCUnsafeCall("Kotlin_LongArray_set")
|
||||
external public operator fun set(index: Int, value: Long): Unit
|
||||
|
||||
@SymbolName("Kotlin_LongArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_LongArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -364,7 +365,7 @@ public final class FloatArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_FloatArray_get")
|
||||
@GCUnsafeCall("Kotlin_FloatArray_get")
|
||||
external public operator fun get(index: Int): Float
|
||||
|
||||
/**
|
||||
@@ -372,10 +373,10 @@ public final class FloatArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_FloatArray_set")
|
||||
@GCUnsafeCall("Kotlin_FloatArray_set")
|
||||
external public operator fun set(index: Int, value: Float): Unit
|
||||
|
||||
@SymbolName("Kotlin_FloatArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_FloatArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -424,7 +425,7 @@ public final class DoubleArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_DoubleArray_get")
|
||||
@GCUnsafeCall("Kotlin_DoubleArray_get")
|
||||
external public operator fun get(index: Int): Double
|
||||
|
||||
/**
|
||||
@@ -432,10 +433,10 @@ public final class DoubleArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_DoubleArray_set")
|
||||
@GCUnsafeCall("Kotlin_DoubleArray_set")
|
||||
external public operator fun set(index: Int, value: Double): Unit
|
||||
|
||||
@SymbolName("Kotlin_DoubleArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_DoubleArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -484,7 +485,7 @@ public final class BooleanArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_BooleanArray_get")
|
||||
@GCUnsafeCall("Kotlin_BooleanArray_get")
|
||||
external public operator fun get(index: Int): Boolean
|
||||
|
||||
/**
|
||||
@@ -492,10 +493,10 @@ public final class BooleanArray {
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_BooleanArray_set")
|
||||
@GCUnsafeCall("Kotlin_BooleanArray_set")
|
||||
external public operator fun set(index: Int, value: Boolean): Unit
|
||||
|
||||
@SymbolName("Kotlin_BooleanArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_BooleanArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -531,7 +532,7 @@ public inline fun <reified @PureReifiable T> arrayOfNulls(size: Int): Array<T?>
|
||||
@PointsTo(0x00, 0x01) // ret -> elements
|
||||
public external inline fun <reified @PureReifiable T> arrayOf(vararg elements: T): Array<T>
|
||||
|
||||
@SymbolName("Kotlin_emptyArray")
|
||||
@GCUnsafeCall("Kotlin_emptyArray")
|
||||
external public fun <T> emptyArray(): Array<T>
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
@@ -171,7 +172,7 @@ public class Char private constructor() : Comparable<Char> {
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Char && this.equals(other)
|
||||
|
||||
@SymbolName("Kotlin_Char_toString")
|
||||
@GCUnsafeCall("Kotlin_Char_toString")
|
||||
external public override fun toString(): String
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
@@ -12,38 +13,38 @@ import kotlin.native.internal.IntrinsicType
|
||||
* Returns `true` if the specified number is a
|
||||
* Not-a-Number (NaN) value, `false` otherwise.
|
||||
*/
|
||||
@SymbolName("Kotlin_Double_isNaN")
|
||||
@GCUnsafeCall("Kotlin_Double_isNaN")
|
||||
public actual external fun Double.isNaN(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if the specified number is a
|
||||
* Not-a-Number (NaN) value, `false` otherwise.
|
||||
*/
|
||||
@SymbolName("Kotlin_Float_isNaN")
|
||||
@GCUnsafeCall("Kotlin_Float_isNaN")
|
||||
public actual external fun Float.isNaN(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if this value is infinitely large in magnitude.
|
||||
*/
|
||||
@SymbolName("Kotlin_Double_isInfinite")
|
||||
@GCUnsafeCall("Kotlin_Double_isInfinite")
|
||||
public actual external fun Double.isInfinite(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if this value is infinitely large in magnitude.
|
||||
*/
|
||||
@SymbolName("Kotlin_Float_isInfinite")
|
||||
@GCUnsafeCall("Kotlin_Float_isInfinite")
|
||||
public actual external fun Float.isInfinite(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if the argument is a finite floating-point value; returns `false` otherwise (for `NaN` and infinity arguments).
|
||||
*/
|
||||
@SymbolName("Kotlin_Double_isFinite")
|
||||
@GCUnsafeCall("Kotlin_Double_isFinite")
|
||||
public actual external fun Double.isFinite(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if the argument is a finite floating-point value; returns `false` otherwise (for `NaN` and infinity arguments).
|
||||
*/
|
||||
@SymbolName("Kotlin_Float_isFinite")
|
||||
@GCUnsafeCall("Kotlin_Float_isFinite")
|
||||
public actual external fun Float.isFinite(): Boolean
|
||||
|
||||
/**
|
||||
@@ -109,14 +110,14 @@ internal external fun fromBits(bits: Int): Float
|
||||
*/
|
||||
@SinceKotlin("1.4")
|
||||
@WasExperimental(ExperimentalStdlibApi::class)
|
||||
@SymbolName("Kotlin_Int_countOneBits")
|
||||
@GCUnsafeCall("Kotlin_Int_countOneBits")
|
||||
public actual external fun Int.countOneBits(): Int
|
||||
|
||||
/**
|
||||
* Counts the number of consecutive most significant bits that are zero in the binary representation of [Int] [value].
|
||||
* Returns undefined result for zero [value].
|
||||
*/
|
||||
@SymbolName("Kotlin_Int_countLeadingZeroBits")
|
||||
@GCUnsafeCall("Kotlin_Int_countLeadingZeroBits")
|
||||
private external fun countLeadingZeroBits(value: Int): Int
|
||||
|
||||
/**
|
||||
@@ -131,7 +132,7 @@ public actual fun Int.countLeadingZeroBits(): Int =
|
||||
* Counts the number of consecutive least significant bits that are zero in the binary representation of [Int] [value].
|
||||
* Returns undefined result for zero [value].
|
||||
*/
|
||||
@SymbolName("Kotlin_Int_countTrailingZeroBits")
|
||||
@GCUnsafeCall("Kotlin_Int_countTrailingZeroBits")
|
||||
private external fun countTrailingZeroBits(value: Int): Int
|
||||
|
||||
/**
|
||||
@@ -197,14 +198,14 @@ public actual fun Int.rotateRight(bitCount: Int): Int =
|
||||
*/
|
||||
@SinceKotlin("1.4")
|
||||
@WasExperimental(ExperimentalStdlibApi::class)
|
||||
@SymbolName("Kotlin_Long_countOneBits")
|
||||
@GCUnsafeCall("Kotlin_Long_countOneBits")
|
||||
public actual external fun Long.countOneBits(): Int
|
||||
|
||||
/**
|
||||
* Counts the number of consecutive most significant bits that are zero in the binary representation of [Long] [value].
|
||||
* Returns undefined result for zero [value].
|
||||
*/
|
||||
@SymbolName("Kotlin_Long_countLeadingZeroBits")
|
||||
@GCUnsafeCall("Kotlin_Long_countLeadingZeroBits")
|
||||
private external fun countLeadingZeroBits(value: Long): Int
|
||||
|
||||
/**
|
||||
@@ -219,7 +220,7 @@ public actual fun Long.countLeadingZeroBits(): Int =
|
||||
* Counts the number of consecutive least significant bits that are zero in the binary representation of [Long] [value].
|
||||
* Returns undefined result for zero [value].
|
||||
*/
|
||||
@SymbolName("Kotlin_Long_countTrailingZeroBits")
|
||||
@GCUnsafeCall("Kotlin_Long_countTrailingZeroBits")
|
||||
private external fun countTrailingZeroBits(value: Long): Int
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.native.internal.CanBePrecreated
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
import kotlin.native.internal.NumberConverter
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.*
|
||||
|
||||
/**
|
||||
* Represents a 8-bit signed integer.
|
||||
@@ -307,7 +304,7 @@ public final class Byte private constructor() : Number(), Comparable<Byte> {
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Byte && kotlin.native.internal.areEqualByValue(this, other)
|
||||
|
||||
@SymbolName("Kotlin_Byte_toString")
|
||||
@GCUnsafeCall("Kotlin_Byte_toString")
|
||||
external public override fun toString(): String
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
@@ -609,7 +606,7 @@ public final class Short private constructor() : Number(), Comparable<Short> {
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Short && kotlin.native.internal.areEqualByValue(this, other)
|
||||
|
||||
@SymbolName("Kotlin_Short_toString")
|
||||
@GCUnsafeCall("Kotlin_Short_toString")
|
||||
external public override fun toString(): String
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
@@ -953,7 +950,7 @@ public final class Int private constructor() : Number(), Comparable<Int> {
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Int && kotlin.native.internal.areEqualByValue(this, other)
|
||||
|
||||
@SymbolName("Kotlin_Int_toString")
|
||||
@GCUnsafeCall("Kotlin_Int_toString")
|
||||
external public override fun toString(): String
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
@@ -1301,7 +1298,7 @@ public final class Long private constructor() : Number(), Comparable<Long> {
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Long && kotlin.native.internal.areEqualByValue(this, other)
|
||||
|
||||
@SymbolName("Kotlin_Long_toString")
|
||||
@GCUnsafeCall("Kotlin_Long_toString")
|
||||
external public override fun toString(): String
|
||||
|
||||
public override fun hashCode(): Int {
|
||||
@@ -1577,7 +1574,7 @@ public final class Float private constructor() : Number(), Comparable<Float> {
|
||||
* Returns zero if this `Float` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`,
|
||||
* [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`.
|
||||
*/
|
||||
@SymbolName("Kotlin_Float_toInt")
|
||||
@GCUnsafeCall("Kotlin_Float_toInt")
|
||||
external public override fun toInt(): Int
|
||||
/**
|
||||
* Converts this [Float] value to [Long].
|
||||
@@ -1586,7 +1583,7 @@ public final class Float private constructor() : Number(), Comparable<Float> {
|
||||
* Returns zero if this `Float` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`,
|
||||
* [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`.
|
||||
*/
|
||||
@SymbolName("Kotlin_Float_toLong")
|
||||
@GCUnsafeCall("Kotlin_Float_toLong")
|
||||
external public override fun toLong(): Long
|
||||
|
||||
/** Returns this value. */
|
||||
@@ -1887,7 +1884,7 @@ public final class Double private constructor() : Number(), Comparable<Double> {
|
||||
* Returns zero if this `Double` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`,
|
||||
* [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`.
|
||||
*/
|
||||
@SymbolName("Kotlin_Double_toInt")
|
||||
@GCUnsafeCall("Kotlin_Double_toInt")
|
||||
external public override fun toInt(): Int
|
||||
/**
|
||||
* Converts this [Double] value to [Long].
|
||||
@@ -1896,7 +1893,7 @@ public final class Double private constructor() : Number(), Comparable<Double> {
|
||||
* Returns zero if this `Double` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`,
|
||||
* [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`.
|
||||
*/
|
||||
@SymbolName("Kotlin_Double_toLong")
|
||||
@GCUnsafeCall("Kotlin_Double_toLong")
|
||||
external public override fun toLong(): Long
|
||||
/**
|
||||
* Converts this [Double] value to [Float].
|
||||
|
||||
@@ -7,6 +7,7 @@ package kotlin
|
||||
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.Frozen
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
@ExportTypeInfo("theStringTypeInfo")
|
||||
@Frozen
|
||||
@@ -14,7 +15,7 @@ public final class String : Comparable<String>, CharSequence {
|
||||
public companion object {
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_String_hashCode")
|
||||
@GCUnsafeCall("Kotlin_String_hashCode")
|
||||
external public override fun hashCode(): Int
|
||||
|
||||
public operator fun plus(other: Any?): String {
|
||||
@@ -33,23 +34,23 @@ public final class String : Comparable<String>, CharSequence {
|
||||
*
|
||||
* If the [index] is out of bounds of this string, throws an [IndexOutOfBoundsException].
|
||||
*/
|
||||
@SymbolName("Kotlin_String_get")
|
||||
external override public fun get(index: Int): Char
|
||||
@GCUnsafeCall("Kotlin_String_get")
|
||||
public external override fun get(index: Int): Char
|
||||
|
||||
@SymbolName("Kotlin_String_subSequence")
|
||||
external override public fun subSequence(startIndex: Int, endIndex: Int): CharSequence
|
||||
@GCUnsafeCall("Kotlin_String_subSequence")
|
||||
public external override fun subSequence(startIndex: Int, endIndex: Int): CharSequence
|
||||
|
||||
@SymbolName("Kotlin_String_compareTo")
|
||||
override external public fun compareTo(other: String): Int
|
||||
@GCUnsafeCall("Kotlin_String_compareTo")
|
||||
public external override fun compareTo(other: String): Int
|
||||
|
||||
@SymbolName("Kotlin_String_getStringLength")
|
||||
external private fun getStringLength(): Int
|
||||
@GCUnsafeCall("Kotlin_String_getStringLength")
|
||||
private external fun getStringLength(): Int
|
||||
|
||||
@SymbolName("Kotlin_String_plusImpl")
|
||||
external private fun plusImpl(other: String): String
|
||||
@GCUnsafeCall("Kotlin_String_plusImpl")
|
||||
private external fun plusImpl(other: String): String
|
||||
|
||||
@SymbolName("Kotlin_String_equals")
|
||||
external public override fun equals(other: Any?): Boolean
|
||||
@GCUnsafeCall("Kotlin_String_equals")
|
||||
external override fun equals(other: Any?): Boolean
|
||||
}
|
||||
|
||||
public inline operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String =
|
||||
|
||||
@@ -9,6 +9,7 @@ import kotlin.native.concurrent.freeze
|
||||
import kotlin.native.concurrent.isFrozen
|
||||
import kotlin.native.internal.ExportForCppRuntime
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.NativePtrArray
|
||||
|
||||
/**
|
||||
@@ -139,10 +140,10 @@ public open class Throwable(open val message: String?, open val cause: Throwable
|
||||
internal var suppressedExceptionsList: MutableList<Throwable>? = null
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_getCurrentStackTrace")
|
||||
@GCUnsafeCall("Kotlin_getCurrentStackTrace")
|
||||
private external fun getCurrentStackTrace(): NativePtrArray
|
||||
|
||||
@SymbolName("Kotlin_getStackTraceStrings")
|
||||
@GCUnsafeCall("Kotlin_getStackTraceStrings")
|
||||
private external fun getStackTraceStrings(stackTrace: NativePtrArray): Array<String>
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ package kotlin.collections
|
||||
|
||||
import kotlin.native.internal.PointsTo
|
||||
import kotlin.native.internal.ExportForCppRuntime
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Returns an array of objects of the given type with the given [size], initialized with _uninitialized_ values.
|
||||
@@ -75,32 +76,32 @@ internal fun <E> Array<E>.resetAt(index: Int) {
|
||||
(@Suppress("UNCHECKED_CAST")(this as Array<Any?>))[index] = null
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Array_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_Array_fillImpl")
|
||||
@PointsTo(0x3000, 0x0000, 0x0000, 0x0000) // array.intestines -> value
|
||||
internal external fun <T> arrayFill(array: Array<T>, fromIndex: Int, toIndex: Int, value: T)
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_fillImpl")
|
||||
internal external fun arrayFill(array: ByteArray, fromIndex: Int, toIndex: Int, value: Byte)
|
||||
|
||||
@SymbolName("Kotlin_ShortArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_ShortArray_fillImpl")
|
||||
internal external fun arrayFill(array: ShortArray, fromIndex: Int, toIndex: Int, value: Short)
|
||||
|
||||
@SymbolName("Kotlin_CharArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_CharArray_fillImpl")
|
||||
internal external fun arrayFill(array: CharArray, fromIndex: Int, toIndex: Int, value: Char)
|
||||
|
||||
@SymbolName("Kotlin_IntArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_IntArray_fillImpl")
|
||||
internal external fun arrayFill(array: IntArray, fromIndex: Int, toIndex: Int, value: Int)
|
||||
|
||||
@SymbolName("Kotlin_LongArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_LongArray_fillImpl")
|
||||
internal external fun arrayFill(array: LongArray, fromIndex: Int, toIndex: Int, value: Long)
|
||||
|
||||
@SymbolName("Kotlin_DoubleArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_DoubleArray_fillImpl")
|
||||
internal external fun arrayFill(array: DoubleArray, fromIndex: Int, toIndex: Int, value: Double)
|
||||
|
||||
@SymbolName("Kotlin_FloatArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_FloatArray_fillImpl")
|
||||
internal external fun arrayFill(array: FloatArray, fromIndex: Int, toIndex: Int, value: Float)
|
||||
|
||||
@SymbolName("Kotlin_BooleanArray_fillImpl")
|
||||
@GCUnsafeCall("Kotlin_BooleanArray_fillImpl")
|
||||
internal external fun arrayFill(array: BooleanArray, fromIndex: Int, toIndex: Int, value: Boolean)
|
||||
|
||||
@ExportForCppRuntime
|
||||
@@ -124,32 +125,32 @@ internal fun <E> Array<E>.resetRange(fromIndex: Int, toIndex: Int) {
|
||||
arrayFill(@Suppress("UNCHECKED_CAST") (this as Array<Any?>), fromIndex, toIndex, null)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Array_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_Array_copyImpl")
|
||||
@PointsTo(0x00000, 0x00000, 0x00004, 0x00000, 0x00000) // destination.intestines -> array.intestines
|
||||
internal external fun arrayCopy(array: Array<Any?>, fromIndex: Int, destination: Array<Any?>, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_copyImpl")
|
||||
internal external fun arrayCopy(array: ByteArray, fromIndex: Int, destination: ByteArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_ShortArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_ShortArray_copyImpl")
|
||||
internal external fun arrayCopy(array: ShortArray, fromIndex: Int, destination: ShortArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_CharArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_CharArray_copyImpl")
|
||||
internal external fun arrayCopy(array: CharArray, fromIndex: Int, destination: CharArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_IntArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_IntArray_copyImpl")
|
||||
internal external fun arrayCopy(array: IntArray, fromIndex: Int, destination: IntArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_LongArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_LongArray_copyImpl")
|
||||
internal external fun arrayCopy(array: LongArray, fromIndex: Int, destination: LongArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_FloatArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_FloatArray_copyImpl")
|
||||
internal external fun arrayCopy(array: FloatArray, fromIndex: Int, destination: FloatArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_DoubleArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_DoubleArray_copyImpl")
|
||||
internal external fun arrayCopy(array: DoubleArray, fromIndex: Int, destination: DoubleArray, toIndex: Int, count: Int)
|
||||
|
||||
@SymbolName("Kotlin_BooleanArray_copyImpl")
|
||||
@GCUnsafeCall("Kotlin_BooleanArray_copyImpl")
|
||||
internal external fun arrayCopy(array: BooleanArray, fromIndex: Int, destination: BooleanArray, toIndex: Int, count: Int)
|
||||
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
package kotlin.io
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/** Prints the given [message] to the standard output stream. */
|
||||
@SymbolName("Kotlin_io_Console_print")
|
||||
external public fun print(message: String)
|
||||
@GCUnsafeCall("Kotlin_io_Console_print")
|
||||
public external fun print(message: String)
|
||||
|
||||
/** Prints the given [message] to the standard output stream. */
|
||||
public actual fun print(message: Any?) {
|
||||
@@ -15,8 +17,8 @@ public actual fun print(message: Any?) {
|
||||
}
|
||||
|
||||
/** Prints the given [message] and the line separator to the standard output stream. */
|
||||
@SymbolName("Kotlin_io_Console_println")
|
||||
external public fun println(message: String)
|
||||
@GCUnsafeCall("Kotlin_io_Console_println")
|
||||
public external fun println(message: String)
|
||||
|
||||
/** Prints the given [message] and the line separator to the standard output stream. */
|
||||
public actual fun println(message: Any?) {
|
||||
@@ -24,13 +26,13 @@ public actual fun println(message: Any?) {
|
||||
}
|
||||
|
||||
/** Prints the line separator to the standard output stream. */
|
||||
@SymbolName("Kotlin_io_Console_println0")
|
||||
external public actual fun println()
|
||||
@GCUnsafeCall("Kotlin_io_Console_println0")
|
||||
public actual external fun println()
|
||||
|
||||
/**
|
||||
* Reads a line of input from the standard input stream.
|
||||
*
|
||||
* @return the line read or `null` if the input stream is redirected to a file and the end of file has been reached.
|
||||
*/
|
||||
@SymbolName("Kotlin_io_Console_readLine")
|
||||
external public fun readLine(): String?
|
||||
@GCUnsafeCall("Kotlin_io_Console_readLine")
|
||||
public external fun readLine(): String?
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package kotlin.math
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
// region ================ Double Math ========================================
|
||||
|
||||
/** Computes the sine of the angle [x] given in radians.
|
||||
@@ -13,7 +15,7 @@ package kotlin.math
|
||||
* - `sin(NaN|+Inf|-Inf)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_sin")
|
||||
@GCUnsafeCall("Kotlin_math_sin")
|
||||
external public actual fun sin(x: Double): Double
|
||||
|
||||
/** Computes the cosine of the angle [x] given in radians.
|
||||
@@ -22,7 +24,7 @@ external public actual fun sin(x: Double): Double
|
||||
* - `cos(NaN|+Inf|-Inf)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_cos")
|
||||
@GCUnsafeCall("Kotlin_math_cos")
|
||||
external public actual fun cos(x: Double): Double
|
||||
|
||||
/** Computes the tangent of the angle [x] given in radians.
|
||||
@@ -31,7 +33,7 @@ external public actual fun cos(x: Double): Double
|
||||
* - `tan(NaN|+Inf|-Inf)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_tan")
|
||||
@GCUnsafeCall("Kotlin_math_tan")
|
||||
external public actual fun tan(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,7 @@ external public actual fun tan(x: Double): Double
|
||||
* - `asin(x)` is `NaN`, when `abs(x) > 1` or x is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_asin")
|
||||
@GCUnsafeCall("Kotlin_math_asin")
|
||||
external public actual fun asin(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -53,7 +55,7 @@ external public actual fun asin(x: Double): Double
|
||||
* - `acos(x)` is `NaN`, when `abs(x) > 1` or x is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_acos")
|
||||
@GCUnsafeCall("Kotlin_math_acos")
|
||||
external public actual fun acos(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -64,7 +66,7 @@ external public actual fun acos(x: Double): Double
|
||||
* - `atan(NaN)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_atan")
|
||||
@GCUnsafeCall("Kotlin_math_atan")
|
||||
external public actual fun atan(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -84,7 +86,7 @@ external public actual fun atan(x: Double): Double
|
||||
* - `atan2(NaN, x)` and `atan2(y, NaN)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_atan2")
|
||||
@GCUnsafeCall("Kotlin_math_atan2")
|
||||
external public actual fun atan2(y: Double, x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -96,7 +98,7 @@ external public actual fun atan2(y: Double, x: Double): Double
|
||||
* - `sinh(-Inf)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_sinh")
|
||||
@GCUnsafeCall("Kotlin_math_sinh")
|
||||
external public actual fun sinh(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -107,7 +109,7 @@ external public actual fun sinh(x: Double): Double
|
||||
* - `cosh(+Inf|-Inf)` is `+Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_cosh")
|
||||
@GCUnsafeCall("Kotlin_math_cosh")
|
||||
external public actual fun cosh(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -119,7 +121,7 @@ external public actual fun cosh(x: Double): Double
|
||||
* - `tanh(-Inf)` is `-1.0`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_tanh")
|
||||
@GCUnsafeCall("Kotlin_math_tanh")
|
||||
external public actual fun tanh(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -133,7 +135,7 @@ external public actual fun tanh(x: Double): Double
|
||||
* - `asinh(-Inf)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_asinh")
|
||||
@GCUnsafeCall("Kotlin_math_asinh")
|
||||
external public actual fun asinh(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -147,7 +149,7 @@ external public actual fun asinh(x: Double): Double
|
||||
* - `acosh(+Inf)` is `+Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_acosh")
|
||||
@GCUnsafeCall("Kotlin_math_acosh")
|
||||
external public actual fun acosh(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -162,7 +164,7 @@ external public actual fun acosh(x: Double): Double
|
||||
* - `tanh(-1.0)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_atanh")
|
||||
@GCUnsafeCall("Kotlin_math_atanh")
|
||||
external public actual fun atanh(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -173,7 +175,7 @@ external public actual fun atanh(x: Double): Double
|
||||
* - returns `NaN` if any of arguments is `NaN` and the other is not infinite
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_hypot")
|
||||
@GCUnsafeCall("Kotlin_math_hypot")
|
||||
external public actual fun hypot(x: Double, y: Double): Double
|
||||
|
||||
/**
|
||||
@@ -183,7 +185,7 @@ external public actual fun hypot(x: Double, y: Double): Double
|
||||
* - `sqrt(x)` is `NaN` when `x < 0` or `x` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_sqrt")
|
||||
@GCUnsafeCall("Kotlin_math_sqrt")
|
||||
external public actual fun sqrt(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -195,7 +197,7 @@ external public actual fun sqrt(x: Double): Double
|
||||
* - `exp(-Inf)` is `0.0`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_exp")
|
||||
@GCUnsafeCall("Kotlin_math_exp")
|
||||
external public actual fun exp(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -211,7 +213,7 @@ external public actual fun exp(x: Double): Double
|
||||
* @see [exp] function.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_expm1")
|
||||
@GCUnsafeCall("Kotlin_math_expm1")
|
||||
external public actual fun expm1(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -242,7 +244,7 @@ public actual fun log(x: Double, base: Double): Double {
|
||||
* - `ln(0.0)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_ln")
|
||||
@GCUnsafeCall("Kotlin_math_ln")
|
||||
external public actual fun ln(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -251,7 +253,7 @@ external public actual fun ln(x: Double): Double
|
||||
* @see [ln] actual function for special cases.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_log10")
|
||||
@GCUnsafeCall("Kotlin_math_log10")
|
||||
external public actual fun log10(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -260,7 +262,7 @@ external public actual fun log10(x: Double): Double
|
||||
* @see [ln] actual function for special cases.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_log2")
|
||||
@GCUnsafeCall("Kotlin_math_log2")
|
||||
external public actual fun log2(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -278,7 +280,7 @@ external public actual fun log2(x: Double): Double
|
||||
* @see [expm1] function
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_ln1p")
|
||||
@GCUnsafeCall("Kotlin_math_ln1p")
|
||||
external public actual fun ln1p(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -290,7 +292,7 @@ external public actual fun ln1p(x: Double): Double
|
||||
* - `ceil(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_ceil")
|
||||
@GCUnsafeCall("Kotlin_math_ceil")
|
||||
external public actual fun ceil(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -302,7 +304,7 @@ external public actual fun ceil(x: Double): Double
|
||||
* - `floor(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_floor")
|
||||
@GCUnsafeCall("Kotlin_math_floor")
|
||||
external public actual fun floor(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -327,7 +329,7 @@ public actual fun truncate(x: Double): Double = when {
|
||||
* - `round(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_round")
|
||||
@GCUnsafeCall("Kotlin_math_round")
|
||||
external public actual fun round(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -339,7 +341,7 @@ external public actual fun round(x: Double): Double
|
||||
* @see absoluteValue extension property for [Double]
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_abs")
|
||||
@GCUnsafeCall("Kotlin_math_abs")
|
||||
external public actual fun abs(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -396,7 +398,7 @@ public actual fun max(a: Double, b: Double): Double = when {
|
||||
* - `b.pow(x)` is `NaN` for `b < 0` and `x` is finite and not an integer
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Double_pow")
|
||||
@GCUnsafeCall("Kotlin_math_Double_pow")
|
||||
external public actual fun Double.pow(x: Double): Double
|
||||
|
||||
/**
|
||||
@@ -420,7 +422,7 @@ public actual fun Double.pow(n: Int): Double = pow(n.toDouble())
|
||||
* @see round
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Double_IEEErem")
|
||||
@GCUnsafeCall("Kotlin_math_Double_IEEErem")
|
||||
external public fun Double.IEEErem(divisor: Double): Double
|
||||
|
||||
/**
|
||||
@@ -454,7 +456,7 @@ public actual val Double.sign: Double
|
||||
* If [sign] is `NaN` the sign of the result is undefined.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Double_withSign")
|
||||
@GCUnsafeCall("Kotlin_math_Double_withSign")
|
||||
external public actual fun Double.withSign(sign: Double): Double
|
||||
|
||||
/**
|
||||
@@ -489,13 +491,13 @@ public actual val Double.ulp: Double
|
||||
* Returns the [Double] value nearest to this value in direction of positive infinity.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Double_nextUp")
|
||||
@GCUnsafeCall("Kotlin_math_Double_nextUp")
|
||||
external public actual fun Double.nextUp(): Double
|
||||
/**
|
||||
* Returns the [Double] value nearest to this value in direction of negative infinity.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Double_nextDown")
|
||||
@GCUnsafeCall("Kotlin_math_Double_nextDown")
|
||||
external public actual fun Double.nextDown(): Double
|
||||
|
||||
/**
|
||||
@@ -507,13 +509,13 @@ external public actual fun Double.nextDown(): Double
|
||||
*
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Double_nextTowards")
|
||||
@GCUnsafeCall("Kotlin_math_Double_nextTowards")
|
||||
external public actual fun Double.nextTowards(to: Double): Double
|
||||
|
||||
/**
|
||||
* Returns true if the sign of [this] value is negative and false otherwise
|
||||
*/
|
||||
@SymbolName("Kotlin_math_Double_signBit")
|
||||
@GCUnsafeCall("Kotlin_math_Double_signBit")
|
||||
external private fun Double.signBit(): Boolean
|
||||
|
||||
/**
|
||||
@@ -562,7 +564,7 @@ public actual fun Double.roundToLong(): Long = when {
|
||||
* - `sin(NaN|+Inf|-Inf)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_sinf")
|
||||
@GCUnsafeCall("Kotlin_math_sinf")
|
||||
external public actual fun sin(x: Float): Float
|
||||
|
||||
/** Computes the cosine of the angle [x] given in radians.
|
||||
@@ -571,7 +573,7 @@ external public actual fun sin(x: Float): Float
|
||||
* - `cos(NaN|+Inf|-Inf)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_cosf")
|
||||
@GCUnsafeCall("Kotlin_math_cosf")
|
||||
external public actual fun cos(x: Float): Float
|
||||
|
||||
/** Computes the tangent of the angle [x] given in radians.
|
||||
@@ -580,7 +582,7 @@ external public actual fun cos(x: Float): Float
|
||||
* - `tan(NaN|+Inf|-Inf)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_tanf")
|
||||
@GCUnsafeCall("Kotlin_math_tanf")
|
||||
external public actual fun tan(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -591,7 +593,7 @@ external public actual fun tan(x: Float): Float
|
||||
* - `asin(x)` is `NaN`, when `abs(x) > 1` or x is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_asinf")
|
||||
@GCUnsafeCall("Kotlin_math_asinf")
|
||||
external public actual fun asin(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -602,7 +604,7 @@ external public actual fun asin(x: Float): Float
|
||||
* - `acos(x)` is `NaN`, when `abs(x) > 1` or x is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_acosf")
|
||||
@GCUnsafeCall("Kotlin_math_acosf")
|
||||
external public actual fun acos(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -613,7 +615,7 @@ external public actual fun acos(x: Float): Float
|
||||
* - `atan(NaN)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_atanf")
|
||||
@GCUnsafeCall("Kotlin_math_atanf")
|
||||
external public actual fun atan(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -633,7 +635,7 @@ external public actual fun atan(x: Float): Float
|
||||
* - `atan2(NaN, x)` and `atan2(y, NaN)` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_atan2f")
|
||||
@GCUnsafeCall("Kotlin_math_atan2f")
|
||||
external public actual fun atan2(y: Float, x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -645,7 +647,7 @@ external public actual fun atan2(y: Float, x: Float): Float
|
||||
* - `sinh(-Inf)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_sinhf")
|
||||
@GCUnsafeCall("Kotlin_math_sinhf")
|
||||
external public actual fun sinh(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -656,7 +658,7 @@ external public actual fun sinh(x: Float): Float
|
||||
* - `cosh(+Inf|-Inf)` is `+Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_coshf")
|
||||
@GCUnsafeCall("Kotlin_math_coshf")
|
||||
external public actual fun cosh(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -668,7 +670,7 @@ external public actual fun cosh(x: Float): Float
|
||||
* - `tanh(-Inf)` is `-1.0`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_tanhf")
|
||||
@GCUnsafeCall("Kotlin_math_tanhf")
|
||||
external public actual fun tanh(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -682,7 +684,7 @@ external public actual fun tanh(x: Float): Float
|
||||
* - `asinh(-Inf)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_asinhf")
|
||||
@GCUnsafeCall("Kotlin_math_asinhf")
|
||||
external public actual fun asinh(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -696,7 +698,7 @@ external public actual fun asinh(x: Float): Float
|
||||
* - `acosh(+Inf)` is `+Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_acoshf")
|
||||
@GCUnsafeCall("Kotlin_math_acoshf")
|
||||
external public actual fun acosh(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -711,7 +713,7 @@ external public actual fun acosh(x: Float): Float
|
||||
* - `tanh(-1.0)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_atanhf")
|
||||
@GCUnsafeCall("Kotlin_math_atanhf")
|
||||
external public actual fun atanh(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -722,7 +724,7 @@ external public actual fun atanh(x: Float): Float
|
||||
* - returns `NaN` if any of arguments is `NaN` and the other is not infinite
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_hypotf")
|
||||
@GCUnsafeCall("Kotlin_math_hypotf")
|
||||
external public actual fun hypot(x: Float, y: Float): Float
|
||||
|
||||
/**
|
||||
@@ -732,7 +734,7 @@ external public actual fun hypot(x: Float, y: Float): Float
|
||||
* - `sqrt(x)` is `NaN` when `x < 0` or `x` is `NaN`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_sqrtf")
|
||||
@GCUnsafeCall("Kotlin_math_sqrtf")
|
||||
external public actual fun sqrt(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -744,7 +746,7 @@ external public actual fun sqrt(x: Float): Float
|
||||
* - `exp(-Inf)` is `0.0`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_expf")
|
||||
@GCUnsafeCall("Kotlin_math_expf")
|
||||
external public actual fun exp(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -760,7 +762,7 @@ external public actual fun exp(x: Float): Float
|
||||
* @see [exp] function.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_expm1f")
|
||||
@GCUnsafeCall("Kotlin_math_expm1f")
|
||||
external public actual fun expm1(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -791,7 +793,7 @@ public actual fun log(x: Float, base: Float): Float {
|
||||
* - `ln(0.0)` is `-Inf`
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_lnf")
|
||||
@GCUnsafeCall("Kotlin_math_lnf")
|
||||
external public actual fun ln(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -800,7 +802,7 @@ external public actual fun ln(x: Float): Float
|
||||
* @see [ln] actual function for special cases.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_log10f")
|
||||
@GCUnsafeCall("Kotlin_math_log10f")
|
||||
external public actual fun log10(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -809,7 +811,7 @@ external public actual fun log10(x: Float): Float
|
||||
* @see [ln] actual function for special cases.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_log2f")
|
||||
@GCUnsafeCall("Kotlin_math_log2f")
|
||||
external public actual fun log2(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -827,7 +829,7 @@ external public actual fun log2(x: Float): Float
|
||||
* @see [expm1] function
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_ln1pf")
|
||||
@GCUnsafeCall("Kotlin_math_ln1pf")
|
||||
external public actual fun ln1p(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -839,7 +841,7 @@ external public actual fun ln1p(x: Float): Float
|
||||
* - `ceil(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_ceilf")
|
||||
@GCUnsafeCall("Kotlin_math_ceilf")
|
||||
external public actual fun ceil(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -851,7 +853,7 @@ external public actual fun ceil(x: Float): Float
|
||||
* - `floor(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_floorf")
|
||||
@GCUnsafeCall("Kotlin_math_floorf")
|
||||
external public actual fun floor(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -876,7 +878,7 @@ public actual fun truncate(x: Float): Float = when {
|
||||
* - `round(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_roundf")
|
||||
@GCUnsafeCall("Kotlin_math_roundf")
|
||||
external public actual fun round(x: Float): Float
|
||||
|
||||
|
||||
@@ -889,7 +891,7 @@ external public actual fun round(x: Float): Float
|
||||
* @see absoluteValue extension property for [Float]
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_absf")
|
||||
@GCUnsafeCall("Kotlin_math_absf")
|
||||
external public actual fun abs(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -946,7 +948,7 @@ public actual fun max(a: Float, b: Float): Float = when {
|
||||
* - `b.pow(x)` is `NaN` for `b < 0` and `x` is finite and not an integer
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Float_pow")
|
||||
@GCUnsafeCall("Kotlin_math_Float_pow")
|
||||
external public actual fun Float.pow(x: Float): Float
|
||||
|
||||
/**
|
||||
@@ -970,7 +972,7 @@ public actual fun Float.pow(n: Int): Float = pow(n.toFloat())
|
||||
* @see round
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Float_IEEErem")
|
||||
@GCUnsafeCall("Kotlin_math_Float_IEEErem")
|
||||
external public fun Float.IEEErem(divisor: Float): Float
|
||||
|
||||
/**
|
||||
@@ -1004,7 +1006,7 @@ public actual val Float.sign: Float
|
||||
* If [sign] is `NaN` the sign of the result is undefined.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Float_withSign")
|
||||
@GCUnsafeCall("Kotlin_math_Float_withSign")
|
||||
external public actual fun Float.withSign(sign: Float): Float
|
||||
/**
|
||||
* Returns this value with the sign bit same as of the [sign] value.
|
||||
@@ -1028,13 +1030,13 @@ public val Float.ulp: Float
|
||||
* Returns the [Float] value nearest to this value in direction of positive infinity.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Float_nextUp")
|
||||
@GCUnsafeCall("Kotlin_math_Float_nextUp")
|
||||
external public fun Float.nextUp(): Float
|
||||
/**
|
||||
* Returns the [Float] value nearest to this value in direction of negative infinity.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Float_nextDown")
|
||||
@GCUnsafeCall("Kotlin_math_Float_nextDown")
|
||||
external public fun Float.nextDown(): Float
|
||||
|
||||
/**
|
||||
@@ -1046,13 +1048,13 @@ external public fun Float.nextDown(): Float
|
||||
*
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_Float_nextTowards")
|
||||
@GCUnsafeCall("Kotlin_math_Float_nextTowards")
|
||||
external public fun Float.nextTowards(to: Float): Float
|
||||
|
||||
/**
|
||||
* Returns true if the sign of [this] value is negative and false otherwise
|
||||
*/
|
||||
@SymbolName("Kotlin_math_Float_signBit")
|
||||
@GCUnsafeCall("Kotlin_math_Float_signBit")
|
||||
external private fun Float.signBit(): Boolean
|
||||
|
||||
/**
|
||||
@@ -1104,7 +1106,7 @@ public actual fun Float.roundToLong(): Long = when {
|
||||
* @see absoluteValue extension property for [Int]
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_absi")
|
||||
@GCUnsafeCall("Kotlin_math_absi")
|
||||
external public actual fun abs(n: Int): Int
|
||||
|
||||
/**
|
||||
@@ -1155,7 +1157,7 @@ public actual val Int.sign: Int
|
||||
* @see absoluteValue extension property for [Long]
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@SymbolName("Kotlin_math_absl")
|
||||
@GCUnsafeCall("Kotlin_math_absl")
|
||||
external public actual fun abs(n: Long): Long
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,10 +16,10 @@ public final class ImmutableBlob private constructor() {
|
||||
get() = getArrayLength()
|
||||
|
||||
// Data layout is the same as for ByteArray, so we can share native functions.
|
||||
@SymbolName("Kotlin_ByteArray_get")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_get")
|
||||
public external operator fun get(index: Int): Byte
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getArrayLength")
|
||||
private external fun getArrayLength(): Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
@@ -47,7 +47,7 @@ private class ImmutableBlobIteratorImpl(val blob: ImmutableBlob) : ByteIterator(
|
||||
* @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default.
|
||||
* @param endIndex the end (exclusive) of the subrange to copy, size of this blob by default.
|
||||
*/
|
||||
@SymbolName("Kotlin_ImmutableBlob_toByteArray")
|
||||
@GCUnsafeCall("Kotlin_ImmutableBlob_toByteArray")
|
||||
public external fun ImmutableBlob.toByteArray(startIndex: Int = 0, endIndex: Int = size): ByteArray
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ public external fun ImmutableBlob.toByteArray(startIndex: Int = 0, endIndex: Int
|
||||
* @param endIndex the end (exclusive) of the subrange to copy, size of this blob by default.
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
@SymbolName("Kotlin_ImmutableBlob_toByteArray")
|
||||
@GCUnsafeCall("Kotlin_ImmutableBlob_toByteArray")
|
||||
public external fun ImmutableBlob.toUByteArray(startIndex: Int = 0, endIndex: Int = size): UByteArray
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,7 @@ public fun ImmutableBlob.asCPointer(offset: Int = 0): CPointer<ByteVar> =
|
||||
public fun ImmutableBlob.asUCPointer(offset: Int = 0): CPointer<UByteVar> =
|
||||
interpretCPointer<UByteVar>(asCPointerImpl(offset))!!
|
||||
|
||||
@SymbolName("Kotlin_ImmutableBlob_asCPointerImpl")
|
||||
@GCUnsafeCall("Kotlin_ImmutableBlob_asCPointerImpl")
|
||||
private external fun ImmutableBlob.asCPointerImpl(offset: Int): kotlin.native.internal.NativePtr
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
package kotlin.native
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Operating system family.
|
||||
*/
|
||||
@@ -100,32 +102,32 @@ public object Platform {
|
||||
set(value) = Platform_setCleanersLeakChecker(value)
|
||||
}
|
||||
|
||||
@SymbolName("Konan_Platform_canAccessUnaligned")
|
||||
@GCUnsafeCall("Konan_Platform_canAccessUnaligned")
|
||||
private external fun Platform_canAccessUnaligned(): Int
|
||||
|
||||
@SymbolName("Konan_Platform_isLittleEndian")
|
||||
@GCUnsafeCall("Konan_Platform_isLittleEndian")
|
||||
private external fun Platform_isLittleEndian(): Int
|
||||
|
||||
@SymbolName("Konan_Platform_getOsFamily")
|
||||
@GCUnsafeCall("Konan_Platform_getOsFamily")
|
||||
private external fun Platform_getOsFamily(): Int
|
||||
|
||||
@SymbolName("Konan_Platform_getCpuArchitecture")
|
||||
@GCUnsafeCall("Konan_Platform_getCpuArchitecture")
|
||||
private external fun Platform_getCpuArchitecture(): Int
|
||||
|
||||
@SymbolName("Konan_Platform_getMemoryModel")
|
||||
@GCUnsafeCall("Konan_Platform_getMemoryModel")
|
||||
private external fun Platform_getMemoryModel(): Int
|
||||
|
||||
@SymbolName("Konan_Platform_isDebugBinary")
|
||||
@GCUnsafeCall("Konan_Platform_isDebugBinary")
|
||||
private external fun Platform_isDebugBinary(): Boolean
|
||||
|
||||
@SymbolName("Konan_Platform_getMemoryLeakChecker")
|
||||
@GCUnsafeCall("Konan_Platform_getMemoryLeakChecker")
|
||||
private external fun Platform_getMemoryLeakChecker(): Boolean
|
||||
|
||||
@SymbolName("Konan_Platform_setMemoryLeakChecker")
|
||||
@GCUnsafeCall("Konan_Platform_setMemoryLeakChecker")
|
||||
private external fun Platform_setMemoryLeakChecker(value: Boolean): Unit
|
||||
|
||||
@SymbolName("Konan_Platform_getCleanersLeakChecker")
|
||||
@GCUnsafeCall("Konan_Platform_getCleanersLeakChecker")
|
||||
private external fun Platform_getCleanersLeakChecker(): Boolean
|
||||
|
||||
@SymbolName("Konan_Platform_setCleanersLeakChecker")
|
||||
@GCUnsafeCall("Konan_Platform_setCleanersLeakChecker")
|
||||
private external fun Platform_setCleanersLeakChecker(value: Boolean): Unit
|
||||
|
||||
@@ -5,19 +5,20 @@
|
||||
package kotlin.native
|
||||
|
||||
import kotlin.native.concurrent.InvalidMutabilityException
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.UnhandledExceptionHookHolder
|
||||
|
||||
/**
|
||||
* Initializes Kotlin runtime for the current thread, if not inited already.
|
||||
*/
|
||||
@SymbolName("Kotlin_initRuntimeIfNeeded")
|
||||
@GCUnsafeCall("Kotlin_initRuntimeIfNeeded")
|
||||
external public fun initRuntimeIfNeeded(): Unit
|
||||
|
||||
/**
|
||||
* Deinitializes Kotlin runtime for the current thread, if was inited.
|
||||
* Cannot be called from Kotlin frames holding references, thus deprecated.
|
||||
*/
|
||||
@SymbolName("Kotlin_deinitRuntimeIfNeeded")
|
||||
@GCUnsafeCall("Kotlin_deinitRuntimeIfNeeded")
|
||||
@Deprecated("Deinit runtime can not be called from Kotlin", level = DeprecationLevel.ERROR)
|
||||
external public fun deinitRuntimeIfNeeded(): Unit
|
||||
|
||||
@@ -55,5 +56,5 @@ public fun setUnhandledExceptionHook(hook: ReportUnhandledExceptionHook): Report
|
||||
* Compute stable wrt potential object relocations by the memory manager identity hash code.
|
||||
* @return 0 for `null` object, identity hash code otherwise.
|
||||
*/
|
||||
@SymbolName("Kotlin_Any_hashCode")
|
||||
@GCUnsafeCall("Kotlin_Any_hashCode")
|
||||
public external fun Any?.identityHashCode(): Int
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
package kotlin.native
|
||||
|
||||
import kotlin.native.SymbolName
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Those operations allows to extract primitive values out of the [ByteArray] byte buffers.
|
||||
@@ -23,21 +23,21 @@ public fun ByteArray.getUByteAt(index: Int): UByte = UByte(get(index))
|
||||
* Gets [Char] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getCharAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getCharAt")
|
||||
public external fun ByteArray.getCharAt(index: Int): Char
|
||||
|
||||
/**
|
||||
* Gets [Short] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getShortAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getShortAt")
|
||||
public external fun ByteArray.getShortAt(index: Int): Short
|
||||
|
||||
/**
|
||||
* Gets [UShort] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getShortAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getShortAt")
|
||||
@ExperimentalUnsignedTypes
|
||||
public external fun ByteArray.getUShortAt(index: Int): UShort
|
||||
|
||||
@@ -45,14 +45,14 @@ public external fun ByteArray.getUShortAt(index: Int): UShort
|
||||
* Gets [Int] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getIntAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getIntAt")
|
||||
public external fun ByteArray.getIntAt(index: Int): Int
|
||||
|
||||
/**
|
||||
* Gets [UInt] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getIntAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getIntAt")
|
||||
@ExperimentalUnsignedTypes
|
||||
public external fun ByteArray.getUIntAt(index: Int): UInt
|
||||
|
||||
@@ -60,14 +60,14 @@ public external fun ByteArray.getUIntAt(index: Int): UInt
|
||||
* Gets [Long] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getLongAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getLongAt")
|
||||
public external fun ByteArray.getLongAt(index: Int): Long
|
||||
|
||||
/**
|
||||
* Gets [ULong] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getLongAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getLongAt")
|
||||
@ExperimentalUnsignedTypes
|
||||
public external fun ByteArray.getULongAt(index: Int): ULong
|
||||
|
||||
@@ -75,42 +75,42 @@ public external fun ByteArray.getULongAt(index: Int): ULong
|
||||
* Gets [Float] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getFloatAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getFloatAt")
|
||||
public external fun ByteArray.getFloatAt(index: Int): Float
|
||||
|
||||
/**
|
||||
* Gets [Double] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_getDoubleAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_getDoubleAt")
|
||||
public external fun ByteArray.getDoubleAt(index: Int): Double
|
||||
|
||||
/**
|
||||
* Sets [UByte] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_set")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_set")
|
||||
public external fun ByteArray.setUByteAt(index: Int, value: UByte)
|
||||
|
||||
/**
|
||||
* Sets [Char] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setCharAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setCharAt")
|
||||
public external fun ByteArray.setCharAt(index: Int, value: Char)
|
||||
|
||||
/**
|
||||
* Sets [Short] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setShortAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setShortAt")
|
||||
public external fun ByteArray.setShortAt(index: Int, value: Short)
|
||||
|
||||
/**
|
||||
* Sets [UShort] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setShortAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setShortAt")
|
||||
@ExperimentalUnsignedTypes
|
||||
public external fun ByteArray.setUShortAt(index: Int, value: UShort)
|
||||
|
||||
@@ -118,28 +118,28 @@ public external fun ByteArray.setUShortAt(index: Int, value: UShort)
|
||||
* Sets [Int] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setIntAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setIntAt")
|
||||
public external fun ByteArray.setIntAt(index: Int, value: Int)
|
||||
|
||||
/**
|
||||
* Sets [UInt] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setIntAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setIntAt")
|
||||
public external fun ByteArray.setUIntAt(index: Int, value: UInt)
|
||||
|
||||
/**
|
||||
* Sets [Long] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setLongAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setLongAt")
|
||||
public external fun ByteArray.setLongAt(index: Int, value: Long)
|
||||
|
||||
/**
|
||||
* Sets [ULong] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setLongAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setLongAt")
|
||||
@ExperimentalUnsignedTypes
|
||||
public external fun ByteArray.setULongAt(index: Int, value: ULong)
|
||||
|
||||
@@ -147,12 +147,12 @@ public external fun ByteArray.setULongAt(index: Int, value: ULong)
|
||||
* Sets [Float] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setFloatAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setFloatAt")
|
||||
public external fun ByteArray.setFloatAt(index: Int, value: Float)
|
||||
|
||||
/**
|
||||
* Sets [Double] out of the [ByteArray] byte buffer at specified index [index]
|
||||
* @throws ArrayIndexOutOfBoundsException if [index] is outside of array boundaries.
|
||||
*/
|
||||
@SymbolName("Kotlin_ByteArray_setDoubleAt")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_setDoubleAt")
|
||||
public external fun ByteArray.setDoubleAt(index: Int, value: Double)
|
||||
|
||||
@@ -5,12 +5,8 @@
|
||||
|
||||
package kotlin.native.concurrent
|
||||
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.Frozen
|
||||
import kotlin.native.internal.LeakDetectorCandidate
|
||||
import kotlin.native.internal.NoReorderFields
|
||||
import kotlin.native.SymbolName
|
||||
import kotlinx.cinterop.NativePtr
|
||||
import kotlin.native.internal.*
|
||||
|
||||
/**
|
||||
* Atomic values and freezing: atomics [AtomicInt], [AtomicLong], [AtomicNativePtr] and [AtomicReference]
|
||||
@@ -32,7 +28,7 @@ public class AtomicInt(private var value_: Int) {
|
||||
* @param delta the value to add
|
||||
* @return the new value
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicInt_addAndGet")
|
||||
@GCUnsafeCall("Kotlin_AtomicInt_addAndGet")
|
||||
external public fun addAndGet(delta: Int): Int
|
||||
|
||||
/**
|
||||
@@ -42,7 +38,7 @@ public class AtomicInt(private var value_: Int) {
|
||||
* @param new the new value
|
||||
* @return the old value
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicInt_compareAndSwap")
|
||||
@GCUnsafeCall("Kotlin_AtomicInt_compareAndSwap")
|
||||
external public fun compareAndSwap(expected: Int, new: Int): Int
|
||||
|
||||
/**
|
||||
@@ -52,7 +48,7 @@ public class AtomicInt(private var value_: Int) {
|
||||
* @param new the new value
|
||||
* @return true if successful
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicInt_compareAndSet")
|
||||
@GCUnsafeCall("Kotlin_AtomicInt_compareAndSet")
|
||||
external public fun compareAndSet(expected: Int, new: Int): Boolean
|
||||
|
||||
/**
|
||||
@@ -77,10 +73,10 @@ public class AtomicInt(private var value_: Int) {
|
||||
public override fun toString(): String = value.toString()
|
||||
|
||||
// Implementation details.
|
||||
@SymbolName("Kotlin_AtomicInt_set")
|
||||
@GCUnsafeCall("Kotlin_AtomicInt_set")
|
||||
private external fun setImpl(new: Int): Unit
|
||||
|
||||
@SymbolName("Kotlin_AtomicInt_get")
|
||||
@GCUnsafeCall("Kotlin_AtomicInt_get")
|
||||
private external fun getImpl(): Int
|
||||
}
|
||||
|
||||
@@ -99,7 +95,7 @@ public class AtomicLong(private var value_: Long = 0) {
|
||||
* @param delta the value to add
|
||||
* @return the new value
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicLong_addAndGet")
|
||||
@GCUnsafeCall("Kotlin_AtomicLong_addAndGet")
|
||||
external public fun addAndGet(delta: Long): Long
|
||||
|
||||
/**
|
||||
@@ -117,7 +113,7 @@ public class AtomicLong(private var value_: Long = 0) {
|
||||
* @param new the new value
|
||||
* @return the old value
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicLong_compareAndSwap")
|
||||
@GCUnsafeCall("Kotlin_AtomicLong_compareAndSwap")
|
||||
external public fun compareAndSwap(expected: Long, new: Long): Long
|
||||
|
||||
/**
|
||||
@@ -127,7 +123,7 @@ public class AtomicLong(private var value_: Long = 0) {
|
||||
* @param new the new value
|
||||
* @return true if successful, false if state is unchanged
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicLong_compareAndSet")
|
||||
@GCUnsafeCall("Kotlin_AtomicLong_compareAndSet")
|
||||
external public fun compareAndSet(expected: Long, new: Long): Boolean
|
||||
|
||||
/**
|
||||
@@ -152,10 +148,10 @@ public class AtomicLong(private var value_: Long = 0) {
|
||||
public override fun toString(): String = value.toString()
|
||||
|
||||
// Implementation details.
|
||||
@SymbolName("Kotlin_AtomicLong_set")
|
||||
@GCUnsafeCall("Kotlin_AtomicLong_set")
|
||||
private external fun setImpl(new: Long): Unit
|
||||
|
||||
@SymbolName("Kotlin_AtomicLong_get")
|
||||
@GCUnsafeCall("Kotlin_AtomicLong_get")
|
||||
private external fun getImpl(): Long
|
||||
}
|
||||
|
||||
@@ -177,7 +173,7 @@ public class AtomicNativePtr(private var value_: NativePtr) {
|
||||
* @throws InvalidMutabilityException if [new] is not frozen or a permanent object
|
||||
* @return the old value
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicNativePtr_compareAndSwap")
|
||||
@GCUnsafeCall("Kotlin_AtomicNativePtr_compareAndSwap")
|
||||
external public fun compareAndSwap(expected: NativePtr, new: NativePtr): NativePtr
|
||||
|
||||
/**
|
||||
@@ -187,7 +183,7 @@ public class AtomicNativePtr(private var value_: NativePtr) {
|
||||
* @param new the new value
|
||||
* @return true if successful
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicNativePtr_compareAndSet")
|
||||
@GCUnsafeCall("Kotlin_AtomicNativePtr_compareAndSet")
|
||||
external public fun compareAndSet(expected: NativePtr, new: NativePtr): Boolean
|
||||
|
||||
/**
|
||||
@@ -198,10 +194,10 @@ public class AtomicNativePtr(private var value_: NativePtr) {
|
||||
public override fun toString(): String = value.toString()
|
||||
|
||||
// Implementation details.
|
||||
@SymbolName("Kotlin_AtomicNativePtr_set")
|
||||
@GCUnsafeCall("Kotlin_AtomicNativePtr_set")
|
||||
private external fun setImpl(new: NativePtr): Unit
|
||||
|
||||
@SymbolName("Kotlin_AtomicNativePtr_get")
|
||||
@GCUnsafeCall("Kotlin_AtomicNativePtr_get")
|
||||
private external fun getImpl(): NativePtr
|
||||
}
|
||||
|
||||
@@ -261,7 +257,7 @@ public class AtomicReference<T> {
|
||||
* @throws InvalidMutabilityException if the value is not frozen or a permanent object
|
||||
* @return the old value
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicReference_compareAndSwap")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_compareAndSwap")
|
||||
external public fun compareAndSwap(expected: T, new: T): T
|
||||
|
||||
/**
|
||||
@@ -272,7 +268,7 @@ public class AtomicReference<T> {
|
||||
* @param new the new value
|
||||
* @return true if successful
|
||||
*/
|
||||
@SymbolName("Kotlin_AtomicReference_compareAndSet")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_compareAndSet")
|
||||
external public fun compareAndSet(expected: T, new: T): Boolean
|
||||
|
||||
/**
|
||||
@@ -297,10 +293,10 @@ public class AtomicReference<T> {
|
||||
}
|
||||
|
||||
// Implementation details.
|
||||
@SymbolName("Kotlin_AtomicReference_set")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_set")
|
||||
private external fun setImpl(new: Any?): Unit
|
||||
|
||||
@SymbolName("Kotlin_AtomicReference_get")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_get")
|
||||
private external fun getImpl(): Any?
|
||||
}
|
||||
|
||||
@@ -381,15 +377,15 @@ public class FreezableAtomicReference<T>(private var value_: T) {
|
||||
"${debugString(this)} -> ${debugString(value)}"
|
||||
|
||||
// Implementation details.
|
||||
@SymbolName("Kotlin_AtomicReference_set")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_set")
|
||||
private external fun setImpl(new: Any?): Unit
|
||||
|
||||
@SymbolName("Kotlin_AtomicReference_get")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_get")
|
||||
private external fun getImpl(): Any?
|
||||
|
||||
@SymbolName("Kotlin_AtomicReference_compareAndSwap")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_compareAndSwap")
|
||||
private external fun compareAndSwapImpl(expected: Any?, new: Any?): Any?
|
||||
|
||||
@SymbolName("Kotlin_AtomicReference_compareAndSet")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_compareAndSet")
|
||||
private external fun compareAndSetImpl(expected: Any?, new: Any?): Boolean
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package kotlin.native.concurrent
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Exception thrown whenever freezing is not possible.
|
||||
*
|
||||
@@ -49,5 +51,5 @@ public val Any?.isFrozen
|
||||
* @throws FreezingException thrown immediately if this object is already frozen
|
||||
* @see freeze
|
||||
*/
|
||||
@SymbolName("Kotlin_Worker_ensureNeverFrozen")
|
||||
@GCUnsafeCall("Kotlin_Worker_ensureNeverFrozen")
|
||||
public external fun Any.ensureNeverFrozen()
|
||||
@@ -7,6 +7,7 @@ package kotlin.native.concurrent
|
||||
|
||||
import kotlin.native.internal.DescribeObjectForDebugging
|
||||
import kotlin.native.internal.ExportForCppRuntime
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.InternalForKotlinNative
|
||||
import kotlin.native.internal.debugDescription
|
||||
import kotlin.native.identityHashCode
|
||||
@@ -15,17 +16,17 @@ import kotlinx.cinterop.*
|
||||
|
||||
// Implementation details.
|
||||
|
||||
@SymbolName("Kotlin_Worker_stateOfFuture")
|
||||
@GCUnsafeCall("Kotlin_Worker_stateOfFuture")
|
||||
external internal fun stateOfFuture(id: Int): Int
|
||||
|
||||
@SymbolName("Kotlin_Worker_consumeFuture")
|
||||
@GCUnsafeCall("Kotlin_Worker_consumeFuture")
|
||||
@PublishedApi
|
||||
external internal fun consumeFuture(id: Int): Any?
|
||||
|
||||
@SymbolName("Kotlin_Worker_waitForAnyFuture")
|
||||
@GCUnsafeCall("Kotlin_Worker_waitForAnyFuture")
|
||||
external internal fun waitForAnyFuture(versionToken: Int, millis: Int): Boolean
|
||||
|
||||
@SymbolName("Kotlin_Worker_versionToken")
|
||||
@GCUnsafeCall("Kotlin_Worker_versionToken")
|
||||
external internal fun versionToken(): Int
|
||||
|
||||
@kotlin.native.internal.ExportForCompiler
|
||||
@@ -33,29 +34,29 @@ internal fun executeImpl(worker: Worker, mode: TransferMode, producer: () -> Any
|
||||
job: CPointer<CFunction<*>>): Future<Any?> =
|
||||
Future<Any?>(executeInternal(worker.id, mode.value, producer, job))
|
||||
|
||||
@SymbolName("Kotlin_Worker_startInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_startInternal")
|
||||
external internal fun startInternal(errorReporting: Boolean, name: String?): Int
|
||||
|
||||
@SymbolName("Kotlin_Worker_currentInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_currentInternal")
|
||||
external internal fun currentInternal(): Int
|
||||
|
||||
@SymbolName("Kotlin_Worker_requestTerminationWorkerInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_requestTerminationWorkerInternal")
|
||||
external internal fun requestTerminationInternal(id: Int, processScheduledJobs: Boolean): Int
|
||||
|
||||
@SymbolName("Kotlin_Worker_executeInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_executeInternal")
|
||||
external internal fun executeInternal(
|
||||
id: Int, mode: Int, producer: () -> Any?, job: CPointer<CFunction<*>>): Int
|
||||
|
||||
@SymbolName("Kotlin_Worker_executeAfterInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_executeAfterInternal")
|
||||
external internal fun executeAfterInternal(id: Int, operation: () -> Unit, afterMicroseconds: Long): Unit
|
||||
|
||||
@SymbolName("Kotlin_Worker_processQueueInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_processQueueInternal")
|
||||
external internal fun processQueueInternal(id: Int): Boolean
|
||||
|
||||
@SymbolName("Kotlin_Worker_parkInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_parkInternal")
|
||||
external internal fun parkInternal(id: Int, timeoutMicroseconds: Long, process: Boolean): Boolean
|
||||
|
||||
@SymbolName("Kotlin_Worker_getNameInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_getNameInternal")
|
||||
external internal fun getWorkerNameInternal(id: Int): String?
|
||||
|
||||
@ExportForCppRuntime
|
||||
@@ -70,17 +71,17 @@ internal fun ThrowWorkerInvalidState(): Unit =
|
||||
internal fun WorkerLaunchpad(function: () -> Any?) = function()
|
||||
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_Worker_detachObjectGraphInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_detachObjectGraphInternal")
|
||||
external internal fun detachObjectGraphInternal(mode: Int, producer: () -> Any?): NativePtr
|
||||
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_Worker_attachObjectGraphInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_attachObjectGraphInternal")
|
||||
external internal fun attachObjectGraphInternal(stable: NativePtr): Any?
|
||||
|
||||
@SymbolName("Kotlin_Worker_freezeInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_freezeInternal")
|
||||
internal external fun freezeInternal(it: Any?)
|
||||
|
||||
@SymbolName("Kotlin_Worker_isFrozenInternal")
|
||||
@GCUnsafeCall("Kotlin_Worker_isFrozenInternal")
|
||||
internal external fun isFrozenInternal(it: Any?): Boolean
|
||||
|
||||
@ExportForCppRuntime
|
||||
@@ -99,9 +100,9 @@ internal fun ThrowIllegalObjectSharingException(typeInfo: NativePtr, address: Na
|
||||
throw IncorrectDereferenceException("illegal attempt to access non-shared $description from other thread")
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_AtomicReference_checkIfFrozen")
|
||||
@GCUnsafeCall("Kotlin_AtomicReference_checkIfFrozen")
|
||||
external internal fun checkIfFrozen(ref: Any?)
|
||||
|
||||
@InternalForKotlinNative
|
||||
@SymbolName("Kotlin_Worker_waitTermination")
|
||||
@GCUnsafeCall("Kotlin_Worker_waitTermination")
|
||||
external public fun waitWorkerTermination(worker: Worker)
|
||||
|
||||
@@ -8,13 +8,13 @@ package kotlin.native.concurrent
|
||||
import kotlin.native.internal.*
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
@SymbolName("Kotlin_Any_share")
|
||||
@GCUnsafeCall("Kotlin_Any_share")
|
||||
external private fun Any.share()
|
||||
|
||||
@SymbolName("Kotlin_CPointer_CopyMemory")
|
||||
@GCUnsafeCall("Kotlin_CPointer_CopyMemory")
|
||||
external private fun CopyMemory(to: COpaquePointer?, from: COpaquePointer?, count: Int)
|
||||
|
||||
@SymbolName("ReadHeapRefNoLock")
|
||||
@GCUnsafeCall("ReadHeapRefNoLock")
|
||||
internal external fun readHeapRefNoLock(where: Any, index: Int): Any?
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -7,13 +7,13 @@ package kotlin.native.concurrent
|
||||
|
||||
import kotlin.native.internal.*
|
||||
|
||||
@SymbolName("Kotlin_WorkerBoundReference_create")
|
||||
@GCUnsafeCall("Kotlin_WorkerBoundReference_create")
|
||||
external private fun createWorkerBoundReference(value: Any): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_WorkerBoundReference_deref")
|
||||
@GCUnsafeCall("Kotlin_WorkerBoundReference_deref")
|
||||
external private fun derefWorkerBoundReference(ref: NativePtr): Any?
|
||||
|
||||
@SymbolName("Kotlin_WorkerBoundReference_describe")
|
||||
@GCUnsafeCall("Kotlin_WorkerBoundReference_describe")
|
||||
external private fun describeWorkerBoundReference(ref: NativePtr): String
|
||||
|
||||
/**
|
||||
|
||||
@@ -150,4 +150,17 @@ internal annotation class InternalForKotlinNative
|
||||
* Marks a class that has a freeze hook.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class HasFreezeHook
|
||||
internal annotation class HasFreezeHook
|
||||
|
||||
/**
|
||||
* Indicates that calls of this function will be replaced with calls to the
|
||||
* [callee] implemented in the C++ part of the runtime.
|
||||
*
|
||||
* This annotation is unsafe and should be used with care: [callee] is
|
||||
* responsible for correct interaction with the garbage collector, like
|
||||
* placing safe points and switching thread state when using blocking APIs.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(value = AnnotationRetention.BINARY)
|
||||
@InternalForKotlinNative
|
||||
annotation class GCUnsafeCall(val callee: String)
|
||||
|
||||
@@ -5,29 +5,40 @@
|
||||
|
||||
package kotlin.native.internal
|
||||
|
||||
@SymbolName("getCachedBooleanBox")
|
||||
@GCUnsafeCall("getCachedBooleanBox")
|
||||
external fun getCachedBooleanBox(value: Boolean): Boolean?
|
||||
@SymbolName("inBooleanBoxCache")
|
||||
|
||||
@GCUnsafeCall("inBooleanBoxCache")
|
||||
external fun inBooleanBoxCache(value: Boolean): Boolean
|
||||
@SymbolName("getCachedByteBox")
|
||||
|
||||
@GCUnsafeCall("getCachedByteBox")
|
||||
external fun getCachedByteBox(value: Byte): Byte?
|
||||
@SymbolName("inByteBoxCache")
|
||||
|
||||
@GCUnsafeCall("inByteBoxCache")
|
||||
external fun inByteBoxCache(value: Byte): Boolean
|
||||
@SymbolName("getCachedCharBox")
|
||||
|
||||
@GCUnsafeCall("getCachedCharBox")
|
||||
external fun getCachedCharBox(value: Char): Char?
|
||||
@SymbolName("inCharBoxCache")
|
||||
|
||||
@GCUnsafeCall("inCharBoxCache")
|
||||
external fun inCharBoxCache(value: Char): Boolean
|
||||
@SymbolName("getCachedShortBox")
|
||||
|
||||
@GCUnsafeCall("getCachedShortBox")
|
||||
external fun getCachedShortBox(value: Short): Short?
|
||||
@SymbolName("inShortBoxCache")
|
||||
|
||||
@GCUnsafeCall("inShortBoxCache")
|
||||
external fun inShortBoxCache(value: Short): Boolean
|
||||
@SymbolName("getCachedIntBox")
|
||||
|
||||
@GCUnsafeCall("getCachedIntBox")
|
||||
external fun getCachedIntBox(idx: Int): Int?
|
||||
@SymbolName("inIntBoxCache")
|
||||
|
||||
@GCUnsafeCall("inIntBoxCache")
|
||||
external fun inIntBoxCache(value: Int): Boolean
|
||||
@SymbolName("getCachedLongBox")
|
||||
|
||||
@GCUnsafeCall("getCachedLongBox")
|
||||
external fun getCachedLongBox(value: Long): Long?
|
||||
@SymbolName("inLongBoxCache")
|
||||
|
||||
@GCUnsafeCall("inLongBoxCache")
|
||||
external fun inLongBoxCache(value: Long): Boolean
|
||||
|
||||
// TODO: functions below are used for ObjCExport, move and rename them correspondigly.
|
||||
|
||||
@@ -105,7 +105,7 @@ fun waitCleanerWorker() =
|
||||
Unit
|
||||
}.result
|
||||
|
||||
@SymbolName("Kotlin_CleanerImpl_getCleanerWorker")
|
||||
@GCUnsafeCall("Kotlin_CleanerImpl_getCleanerWorker")
|
||||
external private fun getCleanerWorker(): Worker
|
||||
|
||||
@ExportForCppRuntime("Kotlin_CleanerImpl_shutdownCleanerWorker")
|
||||
@@ -125,8 +125,8 @@ private class CleanerImpl(
|
||||
private val cleanPtr: NativePtr,
|
||||
): Cleaner {}
|
||||
|
||||
@SymbolName("Kotlin_Any_isShareable")
|
||||
@GCUnsafeCall("Kotlin_Any_isShareable")
|
||||
external private fun Any?.isShareable(): Boolean
|
||||
|
||||
@SymbolName("CreateStablePointer")
|
||||
@GCUnsafeCall("CreateStablePointer")
|
||||
external private fun createStablePointer(obj: Any): NativePtr
|
||||
|
||||
@@ -11,10 +11,16 @@ public object Debugging {
|
||||
public var forceCheckedShutdown: Boolean
|
||||
get() = Debugging_getForceCheckedShutdown()
|
||||
set(value) = Debugging_setForceCheckedShutdown(value)
|
||||
|
||||
public val isThreadStateRunnable: Boolean
|
||||
get() = Debugging_isThreadStateRunnable()
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Debugging_getForceCheckedShutdown")
|
||||
@GCUnsafeCall("Kotlin_Debugging_getForceCheckedShutdown")
|
||||
private external fun Debugging_getForceCheckedShutdown(): Boolean
|
||||
|
||||
@SymbolName("Kotlin_Debugging_setForceCheckedShutdown")
|
||||
@GCUnsafeCall("Kotlin_Debugging_setForceCheckedShutdown")
|
||||
private external fun Debugging_setForceCheckedShutdown(value: Boolean): Unit
|
||||
|
||||
@GCUnsafeCall("Kotlin_Debugging_isThreadStateRunnable")
|
||||
private external fun Debugging_isThreadStateRunnable(): Boolean
|
||||
|
||||
@@ -31,7 +31,7 @@ import kotlin.comparisons.*
|
||||
* @return the double closest to the real number
|
||||
* @exception NumberFormatException if the String doesn't represent a positive integer value
|
||||
*/
|
||||
@SymbolName("Kotlin_native_FloatingPointParser_parseDoubleImpl")
|
||||
@GCUnsafeCall("Kotlin_native_FloatingPointParser_parseDoubleImpl")
|
||||
private external fun parseDoubleImpl(s: String, e: Int): Double
|
||||
|
||||
/**
|
||||
@@ -46,7 +46,7 @@ private external fun parseDoubleImpl(s: String, e: Int): Double
|
||||
* @return the float closest to the real number
|
||||
* @exception NumberFormatException if the String doesn't represent a positive integer value
|
||||
*/
|
||||
@SymbolName("Kotlin_native_FloatingPointParser_parseFloatImpl")
|
||||
@GCUnsafeCall("Kotlin_native_FloatingPointParser_parseFloatImpl")
|
||||
private external fun parseFloatImpl(s: String, e: Int): Float
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,39 +26,39 @@ object GC {
|
||||
* To force garbage collection immediately, unless collector is stopped
|
||||
* with [stop] operation. Even if GC is suspended, [collect] still triggers collection.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_collect")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_collect")
|
||||
external fun collect()
|
||||
|
||||
/**
|
||||
* Request global cyclic collector, operation is async and just triggers the collection.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_collectCyclic")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_collectCyclic")
|
||||
external fun collectCyclic()
|
||||
|
||||
/**
|
||||
* Suspend garbage collection. Release candidates are still collected, but
|
||||
* GC algorithm is not executed.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_suspend")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_suspend")
|
||||
external fun suspend()
|
||||
|
||||
/**
|
||||
* Resume garbage collection. Can potentially lead to GC immediately.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_resume")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_resume")
|
||||
external fun resume()
|
||||
|
||||
/**
|
||||
* Stop garbage collection. Cyclical garbage is no longer collected.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_stop")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_stop")
|
||||
external fun stop()
|
||||
|
||||
/**
|
||||
* Start garbage collection. Cyclical garbage produced while GC was stopped
|
||||
* cannot be reclaimed, but all new garbage is collected.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_start")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_start")
|
||||
external fun start()
|
||||
|
||||
/**
|
||||
@@ -105,42 +105,42 @@ object GC {
|
||||
* or `null` if the leak detector is not available. Use [Platform.isMemoryLeakCheckerActive] to check
|
||||
* leak detector availability.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_detectCycles")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_detectCycles")
|
||||
external fun detectCycles(): Array<Any>?
|
||||
|
||||
/**
|
||||
* Find a reference cycle including from the given object, `null` if no cycles detected.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_GC_findCycle")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_findCycle")
|
||||
external fun findCycle(root: Any): Array<Any>?
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_getThreshold")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_getThreshold")
|
||||
private external fun getThreshold(): Int
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_setThreshold")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_setThreshold")
|
||||
private external fun setThreshold(value: Int)
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_getCollectCyclesThreshold")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_getCollectCyclesThreshold")
|
||||
private external fun getCollectCyclesThreshold(): Long
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_setCollectCyclesThreshold")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_setCollectCyclesThreshold")
|
||||
private external fun setCollectCyclesThreshold(value: Long)
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_getThresholdAllocations")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_getThresholdAllocations")
|
||||
private external fun getThresholdAllocations(): Long
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_setThresholdAllocations")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_setThresholdAllocations")
|
||||
private external fun setThresholdAllocations(value: Long)
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_getTuneThreshold")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_getTuneThreshold")
|
||||
private external fun getTuneThreshold(): Boolean
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_setTuneThreshold")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_setTuneThreshold")
|
||||
private external fun setTuneThreshold(value: Boolean)
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_getCyclicCollector")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_getCyclicCollector")
|
||||
private external fun getCyclicCollectorEnabled(): Boolean
|
||||
|
||||
@SymbolName("Kotlin_native_internal_GC_setCyclicCollector")
|
||||
@GCUnsafeCall("Kotlin_native_internal_GC_setCyclicCollector")
|
||||
private external fun setCyclicCollectorEnabled(value: Boolean)
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ package kotlin.native.internal
|
||||
|
||||
import kotlin.text.regex.*
|
||||
|
||||
@SymbolName("Kotlin_native_int_bits_to_float")
|
||||
@GCUnsafeCall("Kotlin_native_int_bits_to_float")
|
||||
private external fun intBitsToFloat(x: Int): Float
|
||||
|
||||
@SymbolName("Kotlin_native_long_bits_to_double")
|
||||
@GCUnsafeCall("Kotlin_native_long_bits_to_double")
|
||||
private external fun longBitsToDouble(x: Long): Double
|
||||
|
||||
/*
|
||||
|
||||
@@ -68,22 +68,22 @@ internal class KClassUnsupportedImpl(private val message: String) : KClass<Any>
|
||||
override fun toString(): String = "unreflected class ($message)"
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_findAssociatedObject")
|
||||
@GCUnsafeCall("Kotlin_TypeInfo_findAssociatedObject")
|
||||
private external fun findAssociatedObjectImpl(typeInfo: NativePtr, key: NativePtr): Any?
|
||||
|
||||
@ExportForCompiler
|
||||
@SymbolName("Kotlin_Any_getTypeInfo")
|
||||
@GCUnsafeCall("Kotlin_Any_getTypeInfo")
|
||||
internal external fun getObjectTypeInfo(obj: Any): NativePtr
|
||||
|
||||
@ExportForCompiler
|
||||
@TypedIntrinsic(IntrinsicType.GET_CLASS_TYPE_INFO)
|
||||
internal external inline fun <reified T : Any> getClassTypeInfo(): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_getPackageName")
|
||||
@GCUnsafeCall("Kotlin_TypeInfo_getPackageName")
|
||||
private external fun getPackageName(typeInfo: NativePtr): String?
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_getRelativeName")
|
||||
@GCUnsafeCall("Kotlin_TypeInfo_getRelativeName")
|
||||
private external fun getRelativeName(typeInfo: NativePtr): String?
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_isInstance")
|
||||
@GCUnsafeCall("Kotlin_TypeInfo_isInstance")
|
||||
private external fun isInstance(obj: Any, typeInfo: NativePtr): Boolean
|
||||
|
||||
@@ -47,15 +47,15 @@ internal class NonNullNativePtr private constructor() { // TODO: refactor to use
|
||||
@ExportTypeInfo("theNativePtrArrayTypeInfo")
|
||||
internal class NativePtrArray {
|
||||
|
||||
@SymbolName("Kotlin_NativePtrArray_get")
|
||||
@GCUnsafeCall("Kotlin_NativePtrArray_get")
|
||||
external public operator fun get(index: Int): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_NativePtrArray_set")
|
||||
@GCUnsafeCall("Kotlin_NativePtrArray_set")
|
||||
external public operator fun set(index: Int, value: NativePtr): Unit
|
||||
|
||||
val size: Int
|
||||
get() = getArrayLength()
|
||||
|
||||
@SymbolName("Kotlin_NativePtrArray_getArrayLength")
|
||||
@GCUnsafeCall("Kotlin_NativePtrArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
package kotlin.native.internal
|
||||
|
||||
@SymbolName("Kotlin_native_NumberConverter_bigIntDigitGeneratorInstImpl")
|
||||
@GCUnsafeCall("Kotlin_native_NumberConverter_bigIntDigitGeneratorInstImpl")
|
||||
private external fun bigIntDigitGeneratorInstImpl(results: IntArray, uArray: IntArray, f: Long, e: Int,
|
||||
isDenormalized: Boolean, mantissaIsZero: Boolean, p: Int)
|
||||
|
||||
@SymbolName("Kotlin_native_NumberConverter_ceil")
|
||||
@GCUnsafeCall("Kotlin_native_NumberConverter_ceil")
|
||||
private external fun ceil(x: Double): Double
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,7 +116,7 @@ internal fun ReportUnhandledException(throwable: Throwable) {
|
||||
throwable.printStackTrace()
|
||||
}
|
||||
|
||||
@SymbolName("TerminateWithUnhandledException")
|
||||
@GCUnsafeCall("TerminateWithUnhandledException")
|
||||
internal external fun TerminateWithUnhandledException(throwable: Throwable)
|
||||
|
||||
// Using object to make sure that `hook` is initialized when it's needed instead of
|
||||
|
||||
@@ -9,5 +9,5 @@ package kotlin.native.internal
|
||||
* Returns undefined value of type `T`.
|
||||
* This method is unsafe and should be used with care.
|
||||
*/
|
||||
@SymbolName("Kotlin_native_internal_undefined")
|
||||
@GCUnsafeCall("Kotlin_native_internal_undefined")
|
||||
internal external fun <T> undefined(): T
|
||||
@@ -8,6 +8,7 @@ package kotlin.native.ref
|
||||
import kotlinx.cinterop.COpaquePointer
|
||||
import kotlin.native.internal.ExportForCppRuntime
|
||||
import kotlin.native.internal.Frozen
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.NoReorderFields
|
||||
import kotlin.native.internal.Escapes
|
||||
|
||||
@@ -43,7 +44,7 @@ internal class WeakReferenceCounter(var referred: COpaquePointer?) : WeakReferen
|
||||
// Optimization for concurrent access.
|
||||
var cookie: Int = 0
|
||||
|
||||
@SymbolName("Konan_WeakReferenceCounter_get")
|
||||
@GCUnsafeCall("Konan_WeakReferenceCounter_get")
|
||||
external override fun get(): Any?
|
||||
}
|
||||
|
||||
@@ -53,7 +54,7 @@ internal abstract class WeakReferenceImpl {
|
||||
}
|
||||
|
||||
// Get a counter from non-null object.
|
||||
@SymbolName("Konan_getWeakReferenceImpl")
|
||||
@GCUnsafeCall("Konan_getWeakReferenceImpl")
|
||||
@Escapes(0b01) // referent escapes.
|
||||
external internal fun getWeakReferenceImpl(referent: Any): WeakReferenceImpl
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
package kotlin.native
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
@@ -50,8 +51,8 @@ public final class Vector128 private constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_Vector4f_of")
|
||||
@GCUnsafeCall("Kotlin_Vector4f_of")
|
||||
external fun vectorOf(f0: Float, f1: Float, f2: Float, f3: Float): Vector128
|
||||
|
||||
@SymbolName("Kotlin_Vector4i32_of")
|
||||
@GCUnsafeCall("Kotlin_Vector4i32_of")
|
||||
external fun vectorOf(f0: Int, f1: Int, f2: Int, f3: Int): Vector128
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package kotlin.system
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Terminates the currently running process.
|
||||
*
|
||||
@@ -13,5 +15,5 @@ package kotlin.system
|
||||
*
|
||||
* @return This method never returns normally.
|
||||
*/
|
||||
@SymbolName("Kotlin_system_exitProcess")
|
||||
@GCUnsafeCall("Kotlin_system_exitProcess")
|
||||
public external fun exitProcess(status: Int): Nothing
|
||||
@@ -5,25 +5,27 @@
|
||||
|
||||
package kotlin.system
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Gets current system time in milliseconds since certain moment in the past,
|
||||
* only delta between two subsequent calls makes sense.
|
||||
*/
|
||||
@SymbolName("Kotlin_system_getTimeMillis")
|
||||
@GCUnsafeCall("Kotlin_system_getTimeMillis")
|
||||
public external fun getTimeMillis() : Long
|
||||
|
||||
/**
|
||||
* Gets current system time in nanoseconds since certain moment in the past,
|
||||
* only delta between two subsequent calls makes sense.
|
||||
*/
|
||||
@SymbolName("Kotlin_system_getTimeNanos")
|
||||
@GCUnsafeCall("Kotlin_system_getTimeNanos")
|
||||
public external fun getTimeNanos() : Long
|
||||
|
||||
/**
|
||||
* Gets current system time in microseconds since certain moment in the past,
|
||||
* only delta between two subsequent calls makes sense.
|
||||
*/
|
||||
@SymbolName("Kotlin_system_getTimeMicros")
|
||||
@GCUnsafeCall("Kotlin_system_getTimeMicros")
|
||||
public external fun getTimeMicros() : Long
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package kotlin.text
|
||||
|
||||
import kotlin.IllegalArgumentException
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Returns `true` if this character (Unicode code point) is defined in Unicode.
|
||||
@@ -77,7 +78,7 @@ public actual fun Char.isDigit(): Boolean {
|
||||
* Returns `true` if this character (Unicode code point) should be regarded as an ignorable
|
||||
* character in a Java identifier or a Unicode identifier.
|
||||
*/
|
||||
@SymbolName("Kotlin_Char_isIdentifierIgnorable")
|
||||
@GCUnsafeCall("Kotlin_Char_isIdentifierIgnorable")
|
||||
external public fun Char.isIdentifierIgnorable(): Boolean
|
||||
|
||||
/**
|
||||
@@ -88,7 +89,7 @@ external public fun Char.isIdentifierIgnorable(): Boolean
|
||||
*
|
||||
* @sample samples.text.Chars.isISOControl
|
||||
*/
|
||||
@SymbolName("Kotlin_Char_isISOControl")
|
||||
@GCUnsafeCall("Kotlin_Char_isISOControl")
|
||||
external public actual fun Char.isISOControl(): Boolean
|
||||
|
||||
/**
|
||||
@@ -231,19 +232,19 @@ public actual fun Char.titlecaseChar(): Char = titlecaseCharImpl()
|
||||
/**
|
||||
* Returns `true` if this character is a Unicode high-surrogate code unit (also known as leading-surrogate code unit).
|
||||
*/
|
||||
@SymbolName("Kotlin_Char_isHighSurrogate")
|
||||
@GCUnsafeCall("Kotlin_Char_isHighSurrogate")
|
||||
external public actual fun Char.isHighSurrogate(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if this character is a Unicode low-surrogate code unit (also known as trailing-surrogate code unit).
|
||||
*/
|
||||
@SymbolName("Kotlin_Char_isLowSurrogate")
|
||||
@GCUnsafeCall("Kotlin_Char_isLowSurrogate")
|
||||
external public actual fun Char.isLowSurrogate(): Boolean
|
||||
|
||||
|
||||
internal actual fun digitOf(char: Char, radix: Int): Int = digitOfChecked(char, checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_Char_digitOfChecked")
|
||||
@GCUnsafeCall("Kotlin_Char_digitOfChecked")
|
||||
external internal fun digitOfChecked(char: Char, radix: Int): Int
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package kotlin.text
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* A mutable sequence of characters.
|
||||
*
|
||||
@@ -803,10 +805,10 @@ public actual inline fun StringBuilder.insertRange(index: Int, value: CharSequen
|
||||
internal fun insertString(array: CharArray, start: Int, value: String): Int =
|
||||
insertString(array, start, value, 0, value.length)
|
||||
|
||||
@SymbolName("Kotlin_StringBuilder_insertString")
|
||||
@GCUnsafeCall("Kotlin_StringBuilder_insertString")
|
||||
internal external fun insertString(array: CharArray, distIndex: Int, value: String, sourceIndex: Int, count: Int): Int
|
||||
|
||||
@SymbolName("Kotlin_StringBuilder_insertInt")
|
||||
@GCUnsafeCall("Kotlin_StringBuilder_insertInt")
|
||||
internal external fun insertInt(array: CharArray, start: Int, value: Int): Int
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package kotlin.text
|
||||
|
||||
import kotlin.native.internal.FloatingPointParser
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Returns a string representation of this [Byte] value in the specified [radix].
|
||||
@@ -25,7 +26,7 @@ public actual inline fun Byte.toString(radix: Int): String = this.toInt().toStri
|
||||
@kotlin.internal.InlineOnly
|
||||
public actual inline fun Short.toString(radix: Int): String = this.toInt().toString(checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_Int_toStringRadix")
|
||||
@GCUnsafeCall("Kotlin_Int_toStringRadix")
|
||||
@PublishedApi
|
||||
external internal fun intToString(value: Int, radix: Int): String
|
||||
|
||||
@@ -38,7 +39,7 @@ external internal fun intToString(value: Int, radix: Int): String
|
||||
@kotlin.internal.InlineOnly
|
||||
public actual inline fun Int.toString(radix: Int): String = intToString(this, checkRadix(radix))
|
||||
|
||||
@SymbolName("Kotlin_Long_toStringRadix")
|
||||
@GCUnsafeCall("Kotlin_Long_toStringRadix")
|
||||
@PublishedApi
|
||||
external internal fun longToString(value: Long, radix: Int): String
|
||||
|
||||
|
||||
@@ -6,29 +6,30 @@
|
||||
package kotlin.text
|
||||
|
||||
import kotlin.native.concurrent.SharedImmutable
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Returns the index within this string of the first occurrence of the specified character, starting from the specified offset.
|
||||
*/
|
||||
@SymbolName("Kotlin_String_indexOfChar")
|
||||
@GCUnsafeCall("Kotlin_String_indexOfChar")
|
||||
internal actual external fun String.nativeIndexOf(ch: Char, fromIndex: Int): Int
|
||||
|
||||
/**
|
||||
* Returns the index within this string of the first occurrence of the specified substring, starting from the specified offset.
|
||||
*/
|
||||
@SymbolName("Kotlin_String_indexOfString")
|
||||
@GCUnsafeCall("Kotlin_String_indexOfString")
|
||||
internal actual external fun String.nativeIndexOf(str: String, fromIndex: Int): Int
|
||||
|
||||
/**
|
||||
* Returns the index within this string of the last occurrence of the specified character.
|
||||
*/
|
||||
@SymbolName("Kotlin_String_lastIndexOfChar")
|
||||
@GCUnsafeCall("Kotlin_String_lastIndexOfChar")
|
||||
internal actual external fun String.nativeLastIndexOf(ch: Char, fromIndex: Int): Int
|
||||
|
||||
/**
|
||||
* Returns the index within this string of the last occurrence of the specified character, starting from the specified offset.
|
||||
*/
|
||||
@SymbolName("Kotlin_String_lastIndexOfString")
|
||||
@GCUnsafeCall("Kotlin_String_lastIndexOfString")
|
||||
internal actual external fun String.nativeLastIndexOf(str: String, fromIndex: Int): Int
|
||||
|
||||
/**
|
||||
@@ -61,7 +62,7 @@ public actual fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boole
|
||||
replaceIgnoreCase(oldChar, newChar)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_String_replace")
|
||||
@GCUnsafeCall("Kotlin_String_replace")
|
||||
private external fun String.replace(oldChar: Char, newChar: Char): String
|
||||
|
||||
private fun String.replaceIgnoreCase(oldChar: Char, newChar: Char): String {
|
||||
@@ -187,7 +188,7 @@ public fun String.regionMatches(
|
||||
}
|
||||
|
||||
// Bounds must be checked before calling this method
|
||||
@SymbolName("Kotlin_String_unsafeRangeEquals")
|
||||
@GCUnsafeCall("Kotlin_String_unsafeRangeEquals")
|
||||
private external fun String.unsafeRangeEquals(thisOffset: Int, other: String, otherOffset: Int, length: Int): Boolean
|
||||
|
||||
// Bounds must be checked before calling this method
|
||||
@@ -245,7 +246,7 @@ public actual fun String.lowercase(): String = lowercaseImpl()
|
||||
*/
|
||||
public actual fun String.toCharArray(): CharArray = toCharArray(this, 0, length)
|
||||
|
||||
@SymbolName("Kotlin_String_toCharArray")
|
||||
@GCUnsafeCall("Kotlin_String_toCharArray")
|
||||
private external fun toCharArray(string: String, start: Int, size: Int): CharArray
|
||||
|
||||
/**
|
||||
@@ -356,7 +357,7 @@ internal fun checkBoundsIndexes(startIndex: Int, endIndex: Int, size: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_String_unsafeStringFromCharArray")
|
||||
@GCUnsafeCall("Kotlin_String_unsafeStringFromCharArray")
|
||||
internal external fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int) : String
|
||||
|
||||
/**
|
||||
@@ -430,16 +431,16 @@ public actual fun String.encodeToByteArray(startIndex: Int, endIndex: Int, throw
|
||||
unsafeStringToUtf8(startIndex, endIndex - startIndex)
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_unsafeStringFromUtf8")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_unsafeStringFromUtf8")
|
||||
internal external fun ByteArray.unsafeStringFromUtf8(start: Int, size: Int) : String
|
||||
|
||||
@SymbolName("Kotlin_ByteArray_unsafeStringFromUtf8OrThrow")
|
||||
@GCUnsafeCall("Kotlin_ByteArray_unsafeStringFromUtf8OrThrow")
|
||||
internal external fun ByteArray.unsafeStringFromUtf8OrThrow(start: Int, size: Int) : String
|
||||
|
||||
@SymbolName("Kotlin_String_unsafeStringToUtf8")
|
||||
@GCUnsafeCall("Kotlin_String_unsafeStringToUtf8")
|
||||
internal external fun String.unsafeStringToUtf8(start: Int, size: Int) : ByteArray
|
||||
|
||||
@SymbolName("Kotlin_String_unsafeStringToUtf8OrThrow")
|
||||
@GCUnsafeCall("Kotlin_String_unsafeStringToUtf8OrThrow")
|
||||
internal external fun String.unsafeStringToUtf8OrThrow(start: Int, size: Int) : ByteArray
|
||||
|
||||
internal fun compareToIgnoreCase(thiz: String, other: String): Int {
|
||||
|
||||
@@ -24,24 +24,26 @@
|
||||
@file:Suppress("DEPRECATION") // Char.toInt()
|
||||
package kotlin.text.regex
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
// Access to the decomposition tables. =========================================================================
|
||||
/** Gets canonical class for given codepoint from decomposition mappings table. */
|
||||
@SymbolName("Kotlin_text_regex_getCanonicalClassInternal")
|
||||
@GCUnsafeCall("Kotlin_text_regex_getCanonicalClassInternal")
|
||||
external private fun getCanonicalClassInternal(ch: Int): Int
|
||||
|
||||
/** Check if the given character is in table of single decompositions. */
|
||||
@SymbolName("Kotlin_text_regex_hasSingleCodepointDecompositionInternal")
|
||||
@GCUnsafeCall("Kotlin_text_regex_hasSingleCodepointDecompositionInternal")
|
||||
external private fun hasSingleCodepointDecompositionInternal(ch: Int): Boolean
|
||||
|
||||
/** Returns a decomposition for a given codepoint. */
|
||||
@SymbolName("Kotlin_text_regex_getDecompositionInternal")
|
||||
@GCUnsafeCall("Kotlin_text_regex_getDecompositionInternal")
|
||||
external private fun getDecompositionInternal(ch: Int): IntArray?
|
||||
|
||||
/**
|
||||
* Decomposes the given string represented as an array of codepoints. Saves the decomposition into [outputCodepoints] array.
|
||||
* Returns the length of the decomposition.
|
||||
*/
|
||||
@SymbolName("Kotlin_text_regex_decomposeString")
|
||||
@GCUnsafeCall("Kotlin_text_regex_decomposeString")
|
||||
external private fun decomposeString(inputCodePoints: IntArray, inputLength: Int, outputCodePoints: IntArray): Int
|
||||
// =============================================================================================================
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
|
||||
package kotlin.text.regex
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
/**
|
||||
* Decomposes the given codepoint. Saves the decomposition into [outputCodepoints] array starting with [fromIndex].
|
||||
* Returns the length of the decomposition.
|
||||
*/
|
||||
@SymbolName("Kotlin_text_regex_decomposeCodePoint")
|
||||
@GCUnsafeCall("Kotlin_text_regex_decomposeCodePoint")
|
||||
external private fun decomposeCodePoint(codePoint: Int, outputCodePoints: IntArray, fromIndex: Int): Int
|
||||
|
||||
/** Represents canonical decomposition of Unicode character. Is used when CANON_EQ flag of Pattern class is specified. */
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
|
||||
package kotlin.time
|
||||
|
||||
import kotlin.native.internal.GCUnsafeCall
|
||||
|
||||
@SymbolName("Kotlin_DurationValue_formatToExactDecimals")
|
||||
@GCUnsafeCall("Kotlin_DurationValue_formatToExactDecimals")
|
||||
internal actual external fun formatToExactDecimals(value: Double, decimals: Int): String
|
||||
|
||||
internal actual fun formatUpToDecimals(value: Double, decimals: Int): String {
|
||||
return formatToExactDecimals(value, decimals).trimEnd('0')
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_DurationValue_formatScientificImpl")
|
||||
@GCUnsafeCall("Kotlin_DurationValue_formatScientificImpl")
|
||||
internal external fun formatScientificImpl(value: Double): String
|
||||
|
||||
internal actual fun formatScientific(value: Double): String {
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#include "Common.h"
|
||||
#include "ObjectOps.hpp"
|
||||
#include "ThreadData.hpp"
|
||||
#include "ThreadState.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
OBJ_GETTER(mm::InitThreadLocalSingleton, ThreadData* threadData, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||
// TODO: Is it possible that threadData != CurrentThreadData?
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
if (auto* value = *location) {
|
||||
// Initialized by someone else.
|
||||
@@ -35,7 +35,6 @@ OBJ_GETTER(mm::InitThreadLocalSingleton, ThreadData* threadData, ObjHeader** loc
|
||||
}
|
||||
|
||||
OBJ_GETTER(mm::InitSingleton, ThreadData* threadData, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
|
||||
// TODO: Is it possible that threadData != CurrentThreadData?
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
auto& initializingSingletons = threadData->initializingSingletons();
|
||||
|
||||
@@ -50,7 +49,10 @@ OBJ_GETTER(mm::InitSingleton, ThreadData* threadData, ObjHeader** location, cons
|
||||
|
||||
// Spin lock.
|
||||
ObjHeader* value = nullptr;
|
||||
while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing) {
|
||||
{
|
||||
ThreadStateGuard guard(ThreadState::kNative);
|
||||
while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing) {
|
||||
}
|
||||
}
|
||||
if (value != nullptr) {
|
||||
// Initialized by someone else.
|
||||
|
||||
@@ -31,36 +31,26 @@ class InitSingletonTest : public testing::Test {
|
||||
public:
|
||||
InitSingletonTest() {
|
||||
globalConstructor_ = &constructor_;
|
||||
|
||||
for (auto& threadData : threadDatas_) {
|
||||
threadData = make_unique<mm::ThreadData>(pthread_t{});
|
||||
}
|
||||
}
|
||||
|
||||
~InitSingletonTest() {
|
||||
globalConstructor_ = nullptr;
|
||||
// Make sure to clean everything allocated by the tests.
|
||||
for (auto& threadData : threadDatas_) {
|
||||
threadData->ClearForTests();
|
||||
}
|
||||
mm::GlobalData::Instance().objectFactory().ClearForTests();
|
||||
mm::GlobalData::Instance().globalsRegistry().ClearForTests();
|
||||
}
|
||||
|
||||
mm::ThreadData& threadData(size_t threadIndex) { return *threadDatas_[threadIndex]; }
|
||||
|
||||
testing::MockFunction<void(ObjHeader*)>& constructor() { return constructor_; }
|
||||
|
||||
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, size_t threadIndex) {
|
||||
RETURN_RESULT_OF(mm::InitThreadLocalSingleton, threadDatas_[threadIndex].get(), location, type_.typeInfo(), constructorImpl);
|
||||
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, mm::ThreadData& threadData) {
|
||||
RETURN_RESULT_OF(mm::InitThreadLocalSingleton, &threadData, location, type_.typeInfo(), constructorImpl);
|
||||
}
|
||||
|
||||
OBJ_GETTER(InitSingleton, ObjHeader** location, size_t threadIndex) {
|
||||
RETURN_RESULT_OF(mm::InitSingleton, threadDatas_[threadIndex].get(), location, type_.typeInfo(), constructorImpl);
|
||||
OBJ_GETTER(InitSingleton, ObjHeader** location, mm::ThreadData& threadData) {
|
||||
RETURN_RESULT_OF(mm::InitSingleton, &threadData, location, type_.typeInfo(), constructorImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
testing::StrictMock<testing::MockFunction<void(ObjHeader*)>> constructor_;
|
||||
// TODO: It makes sense to somehow abstract `ThreadData` stuff away. Allocation in this case.
|
||||
std::array<KStdUniquePtr<mm::ThreadData>, kDefaultThreadCount> threadDatas_;
|
||||
test_support::TypeInfoHolder type_{test_support::TypeInfoHolder::ObjectBuilder<EmptyPayload>()};
|
||||
|
||||
static testing::MockFunction<void(ObjHeader*)>* globalConstructor_;
|
||||
@@ -74,119 +64,136 @@ testing::MockFunction<void(ObjHeader*)>* InitSingletonTest::globalConstructor_ =
|
||||
} // namespace
|
||||
|
||||
TEST_F(InitSingletonTest, InitThreadLocalSingleton) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
|
||||
ObjHeader* valueAtConstructor = nullptr;
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce([&location, &stackLocation, &valueAtConstructor](ObjHeader* value) {
|
||||
ObjHeader* valueAtConstructor = nullptr;
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce(
|
||||
[&location, &stackLocation, &valueAtConstructor](ObjHeader* value) {
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
valueAtConstructor = value;
|
||||
});
|
||||
ObjHeader* value = InitThreadLocalSingleton(&location, threadData, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
valueAtConstructor = value;
|
||||
EXPECT_THAT(valueAtConstructor, location);
|
||||
});
|
||||
ObjHeader* value = InitThreadLocalSingleton(&location, 0, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(valueAtConstructor, location);
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitThreadLocalSingletonTwice) {
|
||||
ObjHeader previousValue;
|
||||
ObjHeader* location = &previousValue;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
ObjHeader previousValue;
|
||||
ObjHeader* location = &previousValue;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
|
||||
EXPECT_CALL(constructor(), Call(_)).Times(0);
|
||||
ObjHeader* value = InitThreadLocalSingleton(&location, 0, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(value, &previousValue);
|
||||
EXPECT_CALL(constructor(), Call(_)).Times(0);
|
||||
ObjHeader* value = InitThreadLocalSingleton(&location, threadData, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(value, &previousValue);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitThreadLocalSingletonFail) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
constexpr int kException = 42;
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
constexpr int kException = 42;
|
||||
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce([]() { throw kException; });
|
||||
try {
|
||||
InitThreadLocalSingleton(&location, 0, &stackLocation);
|
||||
ASSERT_TRUE(false); // Cannot be reached.
|
||||
} catch (int exception) {
|
||||
EXPECT_THAT(exception, kException);
|
||||
}
|
||||
EXPECT_THAT(stackLocation, nullptr);
|
||||
EXPECT_THAT(location, nullptr);
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce([]() { throw kException; });
|
||||
try {
|
||||
InitThreadLocalSingleton(&location, threadData, &stackLocation);
|
||||
ASSERT_TRUE(false); // Cannot be reached.
|
||||
} catch (int exception) {
|
||||
EXPECT_THAT(exception, kException);
|
||||
}
|
||||
EXPECT_THAT(stackLocation, nullptr);
|
||||
EXPECT_THAT(location, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitSingleton) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
|
||||
ObjHeader* valueAtConstructor = nullptr;
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce([&location, &stackLocation, &valueAtConstructor](ObjHeader* value) {
|
||||
ObjHeader* valueAtConstructor = nullptr;
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce(
|
||||
[&location, &stackLocation, &valueAtConstructor](ObjHeader* value) {
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(location, kInitializingSingleton);
|
||||
valueAtConstructor = value;
|
||||
});
|
||||
ObjHeader* value = InitSingleton(&location, threadData, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(location, kInitializingSingleton);
|
||||
valueAtConstructor = value;
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(valueAtConstructor, location);
|
||||
});
|
||||
ObjHeader* value = InitSingleton(&location, 0, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(valueAtConstructor, location);
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitSingletonTwice) {
|
||||
ObjHeader previousValue;
|
||||
ObjHeader* location = &previousValue;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
|
||||
EXPECT_CALL(constructor(), Call(_)).Times(0);
|
||||
ObjHeader* value = InitSingleton(&location, 0, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(value, &previousValue);
|
||||
TEST_F(InitSingletonTest, InitSingletonTwice) {
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
ObjHeader previousValue;
|
||||
ObjHeader* location = &previousValue;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
|
||||
EXPECT_CALL(constructor(), Call(_)).Times(0);
|
||||
ObjHeader* value = InitSingleton(&location, threadData, &stackLocation);
|
||||
EXPECT_THAT(value, stackLocation);
|
||||
EXPECT_THAT(value, location);
|
||||
EXPECT_THAT(value, &previousValue);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitSingletonFail) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
constexpr int kException = 42;
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
ObjHeader* location = nullptr;
|
||||
ObjHeader* stackLocation = nullptr;
|
||||
constexpr int kException = 42;
|
||||
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce([]() { throw kException; });
|
||||
try {
|
||||
InitSingleton(&location, 0, &stackLocation);
|
||||
ASSERT_TRUE(false); // Cannot be reached.
|
||||
} catch (int exception) {
|
||||
EXPECT_THAT(exception, kException);
|
||||
}
|
||||
EXPECT_THAT(stackLocation, nullptr);
|
||||
EXPECT_THAT(location, nullptr);
|
||||
EXPECT_CALL(constructor(), Call(_)).WillOnce([]() { throw kException; });
|
||||
try {
|
||||
InitSingleton(&location, threadData, &stackLocation);
|
||||
ASSERT_TRUE(false); // Cannot be reached.
|
||||
} catch (int exception) {
|
||||
EXPECT_THAT(exception, kException);
|
||||
}
|
||||
EXPECT_THAT(stackLocation, nullptr);
|
||||
EXPECT_THAT(location, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitSingletonRecursive) {
|
||||
// The first singleton. Its constructor depends on the second singleton.
|
||||
ObjHeader* location1 = nullptr;
|
||||
ObjHeader* stackLocation1 = nullptr;
|
||||
// The second singleton. Its constructor depends on the first singleton.
|
||||
ObjHeader* location2 = nullptr;
|
||||
ObjHeader* stackLocation2 = nullptr;
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
// The first singleton. Its constructor depends on the second singleton.
|
||||
ObjHeader* location1 = nullptr;
|
||||
ObjHeader* stackLocation1 = nullptr;
|
||||
// The second singleton. Its constructor depends on the first singleton.
|
||||
ObjHeader* location2 = nullptr;
|
||||
ObjHeader* stackLocation2 = nullptr;
|
||||
|
||||
EXPECT_CALL(constructor(), Call(_))
|
||||
.Times(2) // called only once for each singleton.
|
||||
.WillRepeatedly([this, &location1, &stackLocation1, &location2, &stackLocation2](ObjHeader* value) {
|
||||
if (value == stackLocation1) {
|
||||
ObjHeader* result = InitSingleton(&location2, 0, &stackLocation2);
|
||||
EXPECT_THAT(result, stackLocation2);
|
||||
EXPECT_THAT(result, location2);
|
||||
EXPECT_THAT(result, testing::Not(testing::Truly(isNullOrMarker)));
|
||||
} else {
|
||||
ObjHeader* result = InitSingleton(&location1, 0, &stackLocation1);
|
||||
EXPECT_THAT(result, stackLocation1);
|
||||
EXPECT_THAT(result, testing::Ne(location1));
|
||||
EXPECT_THAT(location1, kInitializingSingleton);
|
||||
}
|
||||
});
|
||||
ObjHeader* value = InitSingleton(&location1, 0, &stackLocation1);
|
||||
EXPECT_THAT(value, stackLocation1);
|
||||
EXPECT_THAT(value, location1);
|
||||
EXPECT_CALL(constructor(), Call(_))
|
||||
.Times(2) // called only once for each singleton.
|
||||
.WillRepeatedly([this, &location1, &stackLocation1, &location2, &stackLocation2, &threadData](ObjHeader* value) {
|
||||
if (value == stackLocation1) {
|
||||
ObjHeader* result = InitSingleton(&location2, threadData, &stackLocation2);
|
||||
EXPECT_THAT(result, stackLocation2);
|
||||
EXPECT_THAT(result, location2);
|
||||
EXPECT_THAT(result, testing::Not(testing::Truly(isNullOrMarker)));
|
||||
} else {
|
||||
ObjHeader* result = InitSingleton(&location1, threadData, &stackLocation1);
|
||||
EXPECT_THAT(result, stackLocation1);
|
||||
EXPECT_THAT(result, testing::Ne(location1));
|
||||
EXPECT_THAT(location1, kInitializingSingleton);
|
||||
}
|
||||
});
|
||||
ObjHeader* value = InitSingleton(&location1, threadData, &stackLocation1);
|
||||
EXPECT_THAT(value, stackLocation1);
|
||||
EXPECT_THAT(value, location1);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(InitSingletonTest, InitSingletonConcurrent) {
|
||||
@@ -200,10 +207,13 @@ TEST_F(InitSingletonTest, InitSingletonConcurrent) {
|
||||
|
||||
for (size_t i = 0; i < kThreadCount; ++i) {
|
||||
threads.emplace_back([this, i, &location, &stackLocations, &actual, &readyCount, &canStart]() {
|
||||
ScopedMemoryInit init;
|
||||
auto* threadData = init.memoryState()->GetThreadData();
|
||||
++readyCount;
|
||||
while (!canStart) {
|
||||
}
|
||||
actual[i] = InitSingleton(&location, i, &stackLocations[i]);
|
||||
actual[i] = InitSingleton(&location, *threadData, &stackLocations[i]);
|
||||
threadData->Publish();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,15 +243,18 @@ TEST_F(InitSingletonTest, InitSingletonConcurrentFailing) {
|
||||
|
||||
for (size_t i = 0; i < kThreadCount; ++i) {
|
||||
threads.emplace_back([this, i, &location, &stackLocations, &readyCount, &canStart]() {
|
||||
ScopedMemoryInit init;
|
||||
auto* threadData = init.memoryState()->GetThreadData();
|
||||
++readyCount;
|
||||
while (!canStart) {
|
||||
}
|
||||
try {
|
||||
InitSingleton(&location, i, &stackLocations[i]);
|
||||
InitSingleton(&location, *threadData, &stackLocations[i]);
|
||||
ASSERT_TRUE(false); // Cannot be reached.
|
||||
} catch (int exception) {
|
||||
EXPECT_THAT(exception, kException);
|
||||
}
|
||||
threadData->Publish();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "StableRefRegistry.hpp"
|
||||
#include "ThreadData.hpp"
|
||||
#include "ThreadRegistry.hpp"
|
||||
#include "ThreadState.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
@@ -354,12 +355,15 @@ extern "C" RUNTIME_NOTHROW void* CreateStablePointer(ObjHeader* object) {
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_NOTHROW void DisposeStablePointer(void* pointer) {
|
||||
DisposeStablePointerFor(kotlin::mm::GetMemoryState(), pointer);
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_NOTHROW void DisposeStablePointerFor(MemoryState* memoryState, void* pointer) {
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||
auto* node = static_cast<mm::StableRefRegistry::Node*>(pointer);
|
||||
mm::StableRefRegistry::Instance().UnregisterStableRef(threadData, node);
|
||||
mm::StableRefRegistry::Instance().UnregisterStableRef(memoryState->GetThreadData(), node);
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_NOTHROW OBJ_GETTER(DerefStablePointer, void* pointer) {
|
||||
@@ -443,16 +447,19 @@ extern "C" void CheckGlobalsAccessible() {
|
||||
|
||||
extern "C" RUNTIME_NOTHROW void Kotlin_mm_safePointFunctionEpilogue() {
|
||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
threadData->gc().SafePointFunctionEpilogue();
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_NOTHROW void Kotlin_mm_safePointWhileLoopBody() {
|
||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
threadData->gc().SafePointLoopBody();
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_NOTHROW void Kotlin_mm_safePointExceptionUnwind() {
|
||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
threadData->gc().SafePointExceptionUnwind();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "ThreadData.hpp"
|
||||
#include "ThreadState.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
@@ -55,14 +56,14 @@ ALWAYS_INLINE OBJ_GETTER(mm::CompareAndSwapHeapRef, ObjHeader** location, ObjHea
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
OBJ_GETTER(mm::AllocateObject, ThreadData* threadData, const TypeInfo* typeInfo) noexcept {
|
||||
AssertThreadState(ThreadState::kRunnable);
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
// TODO: Make this work with GCs that can stop thread at any point.
|
||||
auto* object = threadData->objectFactoryThreadQueue().CreateObject(typeInfo);
|
||||
RETURN_OBJ(object);
|
||||
}
|
||||
|
||||
OBJ_GETTER(mm::AllocateArray, ThreadData* threadData, const TypeInfo* typeInfo, uint32_t elements) noexcept {
|
||||
AssertThreadState(ThreadState::kRunnable);
|
||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||
// TODO: Make this work with GCs that can stop thread at any point.
|
||||
auto* array = threadData->objectFactoryThreadQueue().CreateArray(typeInfo, static_cast<uint32_t>(elements));
|
||||
// `ArrayHeader` and `ObjHeader` are expected to be compatible.
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "GC.hpp"
|
||||
#include "GlobalData.hpp"
|
||||
#include "GlobalsRegistry.hpp"
|
||||
#include "TestSupport.hpp"
|
||||
#include "ThreadData.hpp"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
bool isEmpty(T& iterable) {
|
||||
return iterable.begin() == iterable.end();
|
||||
}
|
||||
|
||||
template <typename E, typename T>
|
||||
std::vector<E> collect(T& iterable) {
|
||||
std::vector<E> result;
|
||||
for (E element : iterable) {
|
||||
result.push_back(element);
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
std::vector<mm::ThreadData*> collect(mm::ThreadRegistry::Iterable& iterable) {
|
||||
std::vector<mm::ThreadData*> result;
|
||||
for (mm::ThreadData& element : iterable) {
|
||||
result.push_back(&element);
|
||||
}
|
||||
// Do not use std::move because clang complains that it prevents copy elision.
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" void Kotlin_TestSupport_AssertClearGlobalState() {
|
||||
// Validate that global registries are empty.
|
||||
auto globals = mm::GlobalsRegistry::Instance().Iter();
|
||||
auto objects = mm::GlobalData::Instance().objectFactory().Iter();
|
||||
auto stableRefs = mm::StableRefRegistry::Instance().Iter();
|
||||
auto threads = mm::ThreadRegistry::Instance().Iter();
|
||||
|
||||
EXPECT_THAT(collect<ObjHeader**>(globals), testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(collect<mm::ObjectFactory<gc::GC>::NodeRef>(objects), testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(collect<ObjHeader*>(stableRefs), testing::UnorderedElementsAre());
|
||||
EXPECT_THAT(collect(threads), testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
void kotlin::DeinitMemoryForTests(MemoryState* memoryState) {
|
||||
DeinitMemory(memoryState, false);
|
||||
mm::ThreadRegistry::TestSupport::ClearCurrentThreadData();
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ShadowStack.hpp"
|
||||
#include "StableRefRegistry.hpp"
|
||||
#include "ThreadLocalStorage.hpp"
|
||||
#include "ThreadState.hpp"
|
||||
#include "Types.h"
|
||||
#include "Utils.hpp"
|
||||
|
||||
|
||||
@@ -37,6 +37,11 @@ public:
|
||||
ALWAYS_INLINE ThreadData* CurrentThreadData() const noexcept;
|
||||
Node* CurrentThreadDataNode() const noexcept { return currentThreadDataNode_; }
|
||||
|
||||
class TestSupport {
|
||||
public:
|
||||
static void ClearCurrentThreadData() { currentThreadDataNode_ = nullptr; }
|
||||
};
|
||||
|
||||
private:
|
||||
friend class GlobalData;
|
||||
|
||||
|
||||
@@ -16,8 +16,14 @@ using namespace kotlin;
|
||||
|
||||
TEST(ThreadRegistryTest, RegisterCurrentThread) {
|
||||
std::thread t([]() {
|
||||
auto* node = mm::ThreadRegistry::Instance().RegisterCurrentThread();
|
||||
auto* threadData = node->Get();
|
||||
class ScopedRegistration {
|
||||
public:
|
||||
ScopedRegistration() : node(mm::ThreadRegistry::Instance().RegisterCurrentThread()) {}
|
||||
~ScopedRegistration() { mm::ThreadRegistry::Instance().Unregister(node); }
|
||||
mm::ThreadRegistry::Node* node;
|
||||
} registration;
|
||||
|
||||
auto* threadData = registration.node->Get();
|
||||
EXPECT_EQ(pthread_self(), threadData->threadId());
|
||||
EXPECT_EQ(threadData, mm::ThreadRegistry::Instance().CurrentThreadData());
|
||||
});
|
||||
|
||||
@@ -7,13 +7,7 @@
|
||||
#include "ThreadData.hpp"
|
||||
#include "ThreadState.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE bool isStateSwitchAllowed(ThreadState oldState, ThreadState newState) noexcept {
|
||||
return oldState != newState;
|
||||
}
|
||||
|
||||
const char* stateToString(ThreadState state) noexcept {
|
||||
const char* kotlin::internal::stateToString(ThreadState state) noexcept {
|
||||
switch (state) {
|
||||
case ThreadState::kRunnable:
|
||||
return "RUNNABLE";
|
||||
@@ -22,29 +16,14 @@ const char* stateToString(ThreadState state) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Switches the state of the given thread to `newState` and returns the previous state.
|
||||
ALWAYS_INLINE ThreadState kotlin::SwitchThreadState(mm::ThreadData* threadData, ThreadState newState) noexcept {
|
||||
auto oldState = threadData->setState(newState);
|
||||
// TODO(perf): Mesaure the impact of this assert in debug and opt modes.
|
||||
RuntimeAssert(isStateSwitchAllowed(oldState, newState),
|
||||
"Illegal thread state switch. Old state: %s. New state: %s.",
|
||||
stateToString(oldState), stateToString(newState));
|
||||
return oldState;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE ThreadState kotlin::SwitchThreadState(MemoryState* thread, ThreadState newState) noexcept {
|
||||
return SwitchThreadState(thread->GetThreadData(), newState);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void kotlin::AssertThreadState(mm::ThreadData* threadData, ThreadState expected) noexcept {
|
||||
auto actual = threadData->state();
|
||||
RuntimeAssert(actual == expected,
|
||||
"Unexpected thread state. Expected: %s. Actual: %s.",
|
||||
stateToString(expected), stateToString(actual));
|
||||
ALWAYS_INLINE ThreadState kotlin::SwitchThreadState(MemoryState* thread, ThreadState newState, bool reentrant) noexcept {
|
||||
return SwitchThreadState(thread->GetThreadData(), newState, reentrant);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void kotlin::AssertThreadState(MemoryState* thread, ThreadState expected) noexcept {
|
||||
AssertThreadState(thread->GetThreadData(), expected);
|
||||
}
|
||||
|
||||
ThreadState kotlin::GetThreadState(MemoryState* thread) noexcept {
|
||||
return thread->GetThreadData()->state();
|
||||
}
|
||||
@@ -9,13 +9,37 @@
|
||||
#include <Common.h>
|
||||
#include <Utils.hpp>
|
||||
|
||||
#include "ThreadData.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
|
||||
namespace internal {
|
||||
|
||||
ALWAYS_INLINE inline bool isStateSwitchAllowed(ThreadState oldState, ThreadState newState, bool reentrant) noexcept {
|
||||
return oldState != newState || reentrant;
|
||||
}
|
||||
|
||||
const char* stateToString(ThreadState state) noexcept;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Switches the state of the given thread to `newState` and returns the previous thread state.
|
||||
ALWAYS_INLINE ThreadState SwitchThreadState(mm::ThreadData* threadData, ThreadState newState) noexcept;
|
||||
ALWAYS_INLINE inline ThreadState SwitchThreadState(mm::ThreadData* threadData, ThreadState newState, bool reentrant = false) noexcept {
|
||||
auto oldState = threadData->setState(newState);
|
||||
// TODO(perf): Mesaure the impact of this assert in debug and opt modes.
|
||||
RuntimeAssert(internal::isStateSwitchAllowed(oldState, newState, reentrant),
|
||||
"Illegal thread state switch. Old state: %s. New state: %s.",
|
||||
internal::stateToString(oldState), internal::stateToString(newState));
|
||||
return oldState;
|
||||
}
|
||||
|
||||
// Asserts that the given thread is in the given state.
|
||||
ALWAYS_INLINE void AssertThreadState(mm::ThreadData* threadData, ThreadState expected) noexcept;
|
||||
ALWAYS_INLINE inline void AssertThreadState(mm::ThreadData* threadData, ThreadState expected) noexcept {
|
||||
auto actual = threadData->state();
|
||||
RuntimeAssert(actual == expected,
|
||||
"Unexpected thread state. Expected: %s. Actual: %s.",
|
||||
internal::stateToString(expected), internal::stateToString(actual));
|
||||
}
|
||||
|
||||
} // namespace kotlin
|
||||
|
||||
|
||||
@@ -20,30 +20,26 @@ namespace {
|
||||
class ThreadStateTest : public testing::Test {
|
||||
public:
|
||||
ThreadStateTest() {
|
||||
globalKotlinFunctionMock = &kotlinFunctionMock_;
|
||||
globalSomeFunctionMock = &someFunctionMock();
|
||||
}
|
||||
|
||||
~ThreadStateTest() {
|
||||
globalKotlinFunctionMock = nullptr;
|
||||
globalSomeFunctionMock = nullptr;
|
||||
}
|
||||
|
||||
testing::MockFunction<int32_t(int32_t)>& kotlinFunctionMock() { return kotlinFunctionMock_; }
|
||||
testing::MockFunction<int32_t(int32_t)>& someFunctionMock() { return someFunctionMock_; }
|
||||
|
||||
static int32_t kotlinFunction(int32_t arg) {
|
||||
return globalKotlinFunctionMock->Call(arg);
|
||||
static int32_t someFunction(int32_t arg) {
|
||||
return globalSomeFunctionMock->Call(arg);
|
||||
}
|
||||
|
||||
static RUNTIME_NORETURN void noReturnKotlinFunciton(int32_t arg) {
|
||||
globalKotlinFunctionMock->Call(arg);
|
||||
throw std::exception();
|
||||
}
|
||||
private:
|
||||
testing::MockFunction<int32_t(int32_t)> kotlinFunctionMock_;
|
||||
static testing::MockFunction<int32_t(int32_t)>* globalKotlinFunctionMock;
|
||||
testing::MockFunction<int32_t(int32_t)> someFunctionMock_;
|
||||
static testing::MockFunction<int32_t(int32_t)>* globalSomeFunctionMock;
|
||||
};
|
||||
|
||||
//static
|
||||
testing::MockFunction<int32_t(int32_t)>* ThreadStateTest::globalKotlinFunctionMock = nullptr;
|
||||
testing::MockFunction<int32_t(int32_t)>* ThreadStateTest::globalSomeFunctionMock = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -109,35 +105,34 @@ TEST_F(ThreadStateTest, StateGuardForCurrentThread) {
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ThreadStateTest, CallKotlin) {
|
||||
TEST_F(ThreadStateTest, CallWithNativeState) {
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
SwitchThreadState(&threadData, ThreadState::kNative);
|
||||
ASSERT_THAT(threadData.state(), ThreadState::kNative);
|
||||
ASSERT_THAT(threadData.state(), ThreadState::kRunnable);
|
||||
|
||||
EXPECT_CALL(kotlinFunctionMock(), Call(42))
|
||||
EXPECT_CALL(someFunctionMock(), Call(42))
|
||||
.WillOnce([&threadData](int32_t arg) {
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kRunnable);
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kNative);
|
||||
return 24;
|
||||
});
|
||||
int32_t result = CallKotlin(kotlinFunction, 42);
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kNative);
|
||||
int32_t result = CallWithThreadState<ThreadState::kNative>(someFunction, 42);
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kRunnable);
|
||||
EXPECT_THAT(result, 24);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ThreadStateTest, CallKotlinNoReturn) {
|
||||
TEST_F(ThreadStateTest, CallWithRunnableState) {
|
||||
RunInNewThread([this](mm::ThreadData& threadData) {
|
||||
SwitchThreadState(&threadData, ThreadState::kNative);
|
||||
ASSERT_THAT(threadData.state(), ThreadState::kNative);
|
||||
SwitchThreadState(&threadData, ThreadState::kNative);
|
||||
ASSERT_THAT(threadData.state(), ThreadState::kNative);
|
||||
|
||||
EXPECT_CALL(kotlinFunctionMock(), Call(42))
|
||||
.WillOnce([&threadData](int32_t arg){
|
||||
EXPECT_CALL(someFunctionMock(), Call(42))
|
||||
.WillOnce([&threadData](int32_t arg) {
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kRunnable);
|
||||
return 24;
|
||||
});
|
||||
|
||||
EXPECT_THROW(CallKotlinNoReturn(noReturnKotlinFunciton, 42), std::exception);
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kNative);
|
||||
int32_t result = CallWithThreadState<ThreadState::kRunnable>(someFunction, 42);
|
||||
EXPECT_THAT(threadData.state(), ThreadState::kNative);
|
||||
EXPECT_THAT(result, 24);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -169,3 +164,13 @@ TEST(ThreadStateDeathTest, IncorrectStateSwitch) {
|
||||
"runtime assert: Illegal thread state switch. Old state: NATIVE. New state: NATIVE");
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ThreadStateDeathTest, ReentrantStateSwitch) {
|
||||
RunInNewThread([](MemoryState* memoryState) {
|
||||
auto* threadData = memoryState->GetThreadData();
|
||||
ASSERT_EQ(threadData->state(), ThreadState::kRunnable);
|
||||
EXPECT_EXIT({ SwitchThreadState(memoryState, ThreadState::kRunnable, true); exit(0); },
|
||||
testing::ExitedWithCode(0),
|
||||
testing::Not(testing::ContainsRegex("runtime assert: Illegal thread state switch.")));
|
||||
});
|
||||
}
|
||||
@@ -6,10 +6,26 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
extern "C" void Kotlin_TestSupport_AssertClearGlobalState();
|
||||
|
||||
namespace {
|
||||
|
||||
class GlobalStateChecker : public testing::Environment {
|
||||
public:
|
||||
void TearDown() override { Kotlin_TestSupport_AssertClearGlobalState(); }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleMock(&argc, argv);
|
||||
|
||||
// Use the `threadsafe` style to mitigate possible issues with multithreaded death tests.
|
||||
// See more about death test styles: https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#how-it-works
|
||||
testing::FLAGS_gtest_death_test_style="threadsafe";
|
||||
|
||||
// Googletest takes ownership of the registered environment object.
|
||||
testing::AddGlobalTestEnvironment(new GlobalStateChecker());
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user