[K/N] Do not compile for deprecated targets and legacy MM
^KT-56533 ^KT-58853
This commit is contained in:
committed by
Space Team
parent
d1ce55cbd2
commit
aea8bac7d2
@@ -18,7 +18,6 @@ private enum class TestProperty(shortName: String) {
|
||||
FORCE_STANDALONE("forceStandalone"),
|
||||
COMPILE_ONLY("compileOnly"),
|
||||
OPTIMIZATION_MODE("optimizationMode"),
|
||||
MEMORY_MODEL("memoryModel"),
|
||||
USE_THREAD_STATE_CHECKER("useThreadStateChecker"),
|
||||
GC_TYPE("gcType"),
|
||||
GC_SCHEDULER("gcScheduler"),
|
||||
@@ -166,7 +165,6 @@ fun Project.nativeTest(
|
||||
compute(FORCE_STANDALONE)
|
||||
compute(COMPILE_ONLY)
|
||||
compute(OPTIMIZATION_MODE)
|
||||
compute(MEMORY_MODEL)
|
||||
compute(USE_THREAD_STATE_CHECKER)
|
||||
compute(GC_TYPE)
|
||||
compute(GC_SCHEDULER)
|
||||
|
||||
+1
-1
@@ -393,7 +393,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
var overrideKonanProperties: Array<String>? = null
|
||||
|
||||
@Argument(value="-Xdestroy-runtime-mode", valueDescription = "<mode>", description = "When to destroy runtime. 'legacy' and 'on-shutdown' are currently supported. NOTE: 'legacy' mode is deprecated and will be removed.")
|
||||
var destroyRuntimeMode: String? = "on-shutdown"
|
||||
var destroyRuntimeMode: String? = null
|
||||
|
||||
@Argument(value="-Xgc", valueDescription = "<gc>", description = "GC to use, 'noop', 'stms' and 'cms' are currently supported. Works only with -memory-model experimental")
|
||||
var gc: String? = null
|
||||
|
||||
@@ -23,7 +23,6 @@ enum class TargetBackend(
|
||||
ANDROID(false, JVM),
|
||||
ANDROID_IR(true, JVM_IR),
|
||||
NATIVE(true),
|
||||
NATIVE_WITH_LEGACY_MM(true, NATIVE),
|
||||
JVM_WITH_OLD_EVALUATOR(false),
|
||||
JVM_IR_WITH_OLD_EVALUATOR(true),
|
||||
JVM_WITH_IR_EVALUATOR(false),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM, NATIVE_WITH_LEGACY_MM
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||
// FILE: lib.kt
|
||||
val x: String = computeX()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM, NATIVE_WITH_LEGACY_MM
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||
// FILE: lib.kt
|
||||
val x: String = computeX()
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// TARGET_BACKEND: NATIVE
|
||||
// IGNORE_BACKEND: NATIVE_WITH_LEGACY_MM
|
||||
// FILE: lib.kt
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// TARGET_BACKEND: NATIVE
|
||||
// IGNORE_BACKEND: NATIVE_WITH_LEGACY_MM
|
||||
// FILE: lib.kt
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
|
||||
+54
-119
@@ -48,7 +48,9 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
|
||||
private val platformManager = PlatformManager(distribution)
|
||||
internal val targetManager = platformManager.targetManager(configuration.get(KonanConfigKeys.TARGET))
|
||||
internal val target = targetManager.target
|
||||
internal val target = targetManager.target.also { target ->
|
||||
require(target.supportsThreads()) { "All supported targets must have threads, but was given $target" }
|
||||
}
|
||||
val targetHasAddressDependency get() = target.hasAddressDependencyInMemoryModel()
|
||||
internal val flexiblePhaseConfig = configuration.get(CLIConfigurationKeys.FLEXIBLE_PHASE_CONFIG)!!
|
||||
|
||||
@@ -72,55 +74,23 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
return@takeIf true
|
||||
}
|
||||
|
||||
private val defaultMemoryModel get() =
|
||||
if (target.supportsThreads()) {
|
||||
MemoryModel.EXPERIMENTAL
|
||||
val memoryModel: MemoryModel get() = configuration.get(BinaryOptions.memoryModel)?.also {
|
||||
if (it != MemoryModel.EXPERIMENTAL) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR, "Legacy MM is deprecated and no longer works.")
|
||||
} else {
|
||||
MemoryModel.STRICT
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "-memory-model and memoryModel switches are deprecated and will be removed in a future release.")
|
||||
}
|
||||
|
||||
val memoryModel: MemoryModel by lazy {
|
||||
when (configuration.get(BinaryOptions.memoryModel)) {
|
||||
MemoryModel.STRICT -> {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "Legacy MM is deprecated and will be removed in version 1.9.20")
|
||||
MemoryModel.STRICT
|
||||
}
|
||||
MemoryModel.RELAXED -> {
|
||||
configuration.report(CompilerMessageSeverity.ERROR,
|
||||
"Relaxed MM is deprecated and isn't expected to work right way with current Kotlin version.")
|
||||
MemoryModel.STRICT
|
||||
}
|
||||
MemoryModel.EXPERIMENTAL -> {
|
||||
if (!target.supportsThreads()) {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING,
|
||||
"New MM requires threads, which are not supported on a deprecated target ${target.name}. Using deprecated legacy MM.")
|
||||
MemoryModel.STRICT
|
||||
} else {
|
||||
MemoryModel.EXPERIMENTAL
|
||||
}
|
||||
}
|
||||
null -> defaultMemoryModel // If target does not support threads, it's deprecated, no need to spam with our own deprecation message.
|
||||
}.also {
|
||||
if (it == MemoryModel.EXPERIMENTAL && destroyRuntimeMode == DestroyRuntimeMode.LEGACY) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR,
|
||||
"New MM is incompatible with 'legacy' destroy runtime mode.")
|
||||
}
|
||||
}.let { MemoryModel.EXPERIMENTAL }
|
||||
val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)?.also {
|
||||
if (it != DestroyRuntimeMode.ON_SHUTDOWN) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR, "New MM is incompatible with 'legacy' destroy runtime mode.")
|
||||
} else {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "-Xdestroy-runtime-mode switch is deprecated and will be removed in a future release.")
|
||||
}
|
||||
}
|
||||
val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)!!
|
||||
private val defaultGC get() = if (target.supportsThreads()) GC.CONCURRENT_MARK_AND_SWEEP else GC.SAME_THREAD_MARK_AND_SWEEP
|
||||
}.let { DestroyRuntimeMode.ON_SHUTDOWN }
|
||||
private val defaultGC get() = GC.CONCURRENT_MARK_AND_SWEEP
|
||||
val gc: GC by lazy {
|
||||
val configGc = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR)
|
||||
val (gcFallbackReason, realGc) = when {
|
||||
configGc == GC.CONCURRENT_MARK_AND_SWEEP && !target.supportsThreads() ->
|
||||
"Concurrent mark and sweep gc is not supported for this target. Fallback to Same thread mark and sweep is done" to GC.SAME_THREAD_MARK_AND_SWEEP
|
||||
configGc == null -> null to defaultGC
|
||||
else -> null to configGc
|
||||
}
|
||||
if (gcFallbackReason != null) {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, gcFallbackReason)
|
||||
}
|
||||
realGc
|
||||
configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR) ?: defaultGC
|
||||
}
|
||||
val runtimeAssertsMode: RuntimeAssertsMode get() = configuration.get(BinaryOptions.runtimeAssertionsMode) ?: RuntimeAssertsMode.IGNORE
|
||||
private val defaultDisableMmap get() = target.family == Family.MINGW
|
||||
@@ -138,48 +108,29 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
}
|
||||
}
|
||||
}
|
||||
val workerExceptionHandling: WorkerExceptionHandling get() = configuration.get(KonanConfigKeys.WORKER_EXCEPTION_HANDLING) ?: when (memoryModel) {
|
||||
MemoryModel.EXPERIMENTAL -> WorkerExceptionHandling.USE_HOOK
|
||||
else -> WorkerExceptionHandling.LEGACY
|
||||
val workerExceptionHandling: WorkerExceptionHandling get() = configuration.get(KonanConfigKeys.WORKER_EXCEPTION_HANDLING)?.also {
|
||||
if (it != WorkerExceptionHandling.USE_HOOK) {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "Legacy exception handling in workers is deprecated")
|
||||
}
|
||||
} ?: WorkerExceptionHandling.USE_HOOK
|
||||
val runtimeLogs: String? get() = configuration.get(KonanConfigKeys.RUNTIME_LOGS)
|
||||
val suspendFunctionsFromAnyThreadFromObjC: Boolean by lazy { configuration.get(BinaryOptions.objcExportSuspendFunctionLaunchThreadRestriction) == ObjCExportSuspendFunctionLaunchThreadRestriction.NONE }
|
||||
private val defaultFreezing get() = when (memoryModel) {
|
||||
MemoryModel.EXPERIMENTAL -> Freezing.Disabled
|
||||
else -> Freezing.Full
|
||||
}
|
||||
val freezing: Freezing by lazy {
|
||||
val freezingMode = configuration.get(BinaryOptions.freezing)
|
||||
when {
|
||||
freezingMode == null -> defaultFreezing
|
||||
memoryModel != MemoryModel.EXPERIMENTAL && freezingMode != Freezing.Full -> {
|
||||
configuration.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
"`freezing` can only be adjusted with new MM. Falling back to default behavior.")
|
||||
Freezing.Full
|
||||
}
|
||||
memoryModel == MemoryModel.EXPERIMENTAL && freezingMode != Freezing.Disabled -> {
|
||||
// INFO because deprecation is currently ignorable via OptIn. Using WARNING will require silencing (for warnings-as-errors)
|
||||
// by some compiler flag.
|
||||
// TODO: When moving into proper deprecation cycle replace with WARNING.
|
||||
configuration.report(
|
||||
CompilerMessageSeverity.INFO,
|
||||
"`freezing` should not be enabled with the new MM. Freezing API is deprecated since 1.7.20. See https://kotlinlang.org/docs/native-migration-guide.html for details"
|
||||
)
|
||||
freezingMode
|
||||
}
|
||||
else -> freezingMode
|
||||
val freezing: Freezing get() = configuration.get(BinaryOptions.freezing)?.also {
|
||||
if (it != Freezing.Disabled) {
|
||||
configuration.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
"`freezing` is not supported with the new MM. Freezing API is deprecated since 1.7.20. See https://kotlinlang.org/docs/native-migration-guide.html for details"
|
||||
)
|
||||
} else {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "freezing switch is deprecated and will be removed in a future release.")
|
||||
}
|
||||
}
|
||||
}.let { Freezing.Disabled }
|
||||
val sourceInfoType: SourceInfoType
|
||||
get() = configuration.get(BinaryOptions.sourceInfoType)
|
||||
?: SourceInfoType.CORESYMBOLICATION.takeIf { debug && target.supportsCoreSymbolication() }
|
||||
?: SourceInfoType.NOOP
|
||||
|
||||
val defaultGCSchedulerType get() = when {
|
||||
!target.supportsThreads() -> GCSchedulerType.ON_SAFE_POINTS
|
||||
else -> GCSchedulerType.WITH_TIMER
|
||||
}
|
||||
val defaultGCSchedulerType get() = GCSchedulerType.WITH_TIMER
|
||||
|
||||
val gcSchedulerType: GCSchedulerType by lazy {
|
||||
configuration.get(BinaryOptions.gcSchedulerType) ?: defaultGCSchedulerType
|
||||
@@ -272,7 +223,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
private val shouldCoverLibraries = !configuration.getList(KonanConfigKeys.LIBRARIES_TO_COVER).isNullOrEmpty()
|
||||
|
||||
private val defaultAllocationMode get() = when {
|
||||
memoryModel == MemoryModel.EXPERIMENTAL && target.supportsMimallocAllocator() && sanitizer == null -> {
|
||||
target.supportsMimallocAllocator() && sanitizer == null -> {
|
||||
AllocationMode.MIMALLOC
|
||||
}
|
||||
else -> AllocationMode.STD
|
||||
@@ -305,33 +256,21 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
|
||||
internal val runtimeNativeLibraries: List<String> = mutableListOf<String>().apply {
|
||||
if (debug) add("debug.bc")
|
||||
when (memoryModel) {
|
||||
MemoryModel.STRICT -> {
|
||||
add("strict.bc")
|
||||
add("legacy_memory_manager.bc")
|
||||
}
|
||||
MemoryModel.RELAXED -> {
|
||||
add("relaxed.bc")
|
||||
add("legacy_memory_manager.bc")
|
||||
}
|
||||
MemoryModel.EXPERIMENTAL -> {
|
||||
add("common_gc.bc")
|
||||
if (allocationMode == AllocationMode.CUSTOM) {
|
||||
add("experimental_memory_manager_custom.bc")
|
||||
add("concurrent_ms_gc_custom.bc")
|
||||
} else {
|
||||
add("experimental_memory_manager.bc")
|
||||
when (gc) {
|
||||
GC.SAME_THREAD_MARK_AND_SWEEP -> {
|
||||
add("same_thread_ms_gc.bc")
|
||||
}
|
||||
GC.NOOP -> {
|
||||
add("noop_gc.bc")
|
||||
}
|
||||
GC.CONCURRENT_MARK_AND_SWEEP -> {
|
||||
add("concurrent_ms_gc.bc")
|
||||
}
|
||||
}
|
||||
add("common_gc.bc")
|
||||
if (allocationMode == AllocationMode.CUSTOM) {
|
||||
add("experimental_memory_manager_custom.bc")
|
||||
add("concurrent_ms_gc_custom.bc")
|
||||
} else {
|
||||
add("experimental_memory_manager.bc")
|
||||
when (gc) {
|
||||
GC.SAME_THREAD_MARK_AND_SWEEP -> {
|
||||
add("same_thread_ms_gc.bc")
|
||||
}
|
||||
GC.NOOP -> {
|
||||
add("noop_gc.bc")
|
||||
}
|
||||
GC.CONCURRENT_MARK_AND_SWEEP -> {
|
||||
add("concurrent_ms_gc.bc")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,12 +329,12 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
|
||||
internal val isInteropStubs: Boolean get() = manifestProperties?.getProperty("interop") == "true"
|
||||
|
||||
private val defaultPropertyLazyInitialization get() = when (memoryModel) {
|
||||
MemoryModel.EXPERIMENTAL -> true
|
||||
else -> false
|
||||
}
|
||||
internal val propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION) ?:
|
||||
defaultPropertyLazyInitialization
|
||||
private val defaultPropertyLazyInitialization = true
|
||||
internal val propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION)?.also {
|
||||
if (!it) {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING, "Eager property initialization is deprecated")
|
||||
}
|
||||
} ?: defaultPropertyLazyInitialization
|
||||
|
||||
internal val lazyIrForCaches: Boolean get() = configuration.get(KonanConfigKeys.LAZY_IR_FOR_CACHES)!!
|
||||
|
||||
@@ -428,10 +367,6 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
if (debug) append("-g")
|
||||
append("STATIC")
|
||||
|
||||
if (memoryModel != defaultMemoryModel)
|
||||
append("-mm=$memoryModel")
|
||||
if (freezing != defaultFreezing)
|
||||
append("-freezing=${freezing.name}")
|
||||
if (propertyLazyInitialization != defaultPropertyLazyInitialization)
|
||||
append("-lazy_init=${if (propertyLazyInitialization) "enable" else "disable"}")
|
||||
}
|
||||
@@ -443,9 +378,9 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
append("-runtime_debug")
|
||||
if (allocationMode != defaultAllocationMode)
|
||||
append("-allocator=${allocationMode.name}")
|
||||
if (memoryModel == MemoryModel.EXPERIMENTAL && gc != defaultGC)
|
||||
if (gc != defaultGC)
|
||||
append("-gc=${gc.name}")
|
||||
if (memoryModel == MemoryModel.EXPERIMENTAL && gcSchedulerType != defaultGCSchedulerType)
|
||||
if (gcSchedulerType != defaultGCSchedulerType)
|
||||
append("-gc-scheduler=${gcSchedulerType.name}")
|
||||
if (runtimeAssertsMode != RuntimeAssertsMode.IGNORE)
|
||||
append("-runtime_asserts=${runtimeAssertsMode.name}")
|
||||
|
||||
+11
-3
@@ -23,13 +23,16 @@ import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
private val deprecatedTargets = setOf(
|
||||
KonanTarget.WATCHOS_X86,
|
||||
KonanTarget.IOS_ARM32,
|
||||
KonanTarget.LINUX_ARM32_HFP,
|
||||
KonanTarget.MINGW_X86,
|
||||
KonanTarget.LINUX_MIPS32,
|
||||
KonanTarget.LINUX_MIPSEL32,
|
||||
KonanTarget.WASM32
|
||||
)
|
||||
|
||||
private val softDeprecatedTargets = setOf(
|
||||
KonanTarget.LINUX_ARM32_HFP,
|
||||
)
|
||||
|
||||
private const val DEPRECATION_LINK = "https://kotl.in/native-targets-tiers"
|
||||
|
||||
class KonanDriver(
|
||||
@@ -64,8 +67,13 @@ class KonanDriver(
|
||||
}
|
||||
if (konanConfig.infoArgsOnly) return
|
||||
|
||||
if (konanConfig.target in deprecatedTargets || konanConfig.target is KonanTarget.ZEPHYR) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR,
|
||||
"target ${konanConfig.target} is no longer available. See: $DEPRECATION_LINK")
|
||||
}
|
||||
|
||||
// Avoid showing warning twice in 2-phase compilation.
|
||||
if (konanConfig.produce != CompilerOutputKind.LIBRARY && konanConfig.target in deprecatedTargets) {
|
||||
if (konanConfig.produce != CompilerOutputKind.LIBRARY && konanConfig.target in softDeprecatedTargets) {
|
||||
configuration.report(CompilerMessageSeverity.STRONG_WARNING,
|
||||
"target ${konanConfig.target} is deprecated and will be removed soon. See: $DEPRECATION_LINK")
|
||||
}
|
||||
@@ -94,4 +102,4 @@ class KonanDriver(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -201,12 +201,13 @@ fun CompilerConfiguration.setupFromArguments(arguments: K2NativeCompilerArgument
|
||||
put(FAKE_OVERRIDE_VALIDATOR, arguments.fakeOverrideValidator)
|
||||
putIfNotNull(PRE_LINK_CACHES, parsePreLinkCachesValue(this@setupFromArguments, arguments.preLinkCaches))
|
||||
putIfNotNull(OVERRIDE_KONAN_PROPERTIES, parseOverrideKonanProperties(arguments, this@setupFromArguments))
|
||||
put(DESTROY_RUNTIME_MODE, when (arguments.destroyRuntimeMode) {
|
||||
putIfNotNull(DESTROY_RUNTIME_MODE, when (arguments.destroyRuntimeMode) {
|
||||
null -> null
|
||||
"legacy" -> DestroyRuntimeMode.LEGACY
|
||||
"on-shutdown" -> DestroyRuntimeMode.ON_SHUTDOWN
|
||||
else -> {
|
||||
report(ERROR, "Unsupported destroy runtime mode ${arguments.destroyRuntimeMode}")
|
||||
DestroyRuntimeMode.ON_SHUTDOWN
|
||||
null
|
||||
}
|
||||
})
|
||||
putIfNotNull(GARBAGE_COLLECTOR, when (arguments.gc) {
|
||||
@@ -298,13 +299,11 @@ internal fun CompilerConfiguration.setupCommonOptionsForCaches(konanConfig: Kona
|
||||
put(DEBUG, konanConfig.debug)
|
||||
setupPartialLinkageConfig(konanConfig.partialLinkageConfig)
|
||||
putIfNotNull(EXTERNAL_DEPENDENCIES, konanConfig.externalDependenciesFile?.absolutePath)
|
||||
put(BinaryOptions.memoryModel, konanConfig.memoryModel)
|
||||
put(PROPERTY_LAZY_INITIALIZATION, konanConfig.propertyLazyInitialization)
|
||||
put(BinaryOptions.stripDebugInfoFromNativeLibs, !konanConfig.useDebugInfoInNativeLibs)
|
||||
put(ALLOCATION_MODE, konanConfig.allocationMode)
|
||||
put(GARBAGE_COLLECTOR, konanConfig.gc)
|
||||
put(BinaryOptions.gcSchedulerType, konanConfig.gcSchedulerType)
|
||||
put(BinaryOptions.freezing, konanConfig.freezing)
|
||||
put(BinaryOptions.runtimeAssertionsMode, konanConfig.runtimeAssertsMode)
|
||||
put(LAZY_IR_FOR_CACHES, konanConfig.lazyIrForCaches)
|
||||
put(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS, konanConfig.threadsCount)
|
||||
@@ -562,4 +561,4 @@ private fun parseCompileFromBitcode(
|
||||
"Compilation from bitcode is not available when producing ${outputKind.visibleName}")
|
||||
}
|
||||
return arguments.compileFromBitcode
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import kotlin.native.Platform
|
||||
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
|
||||
fun leakMemory() {
|
||||
StableRef.create(Any())
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 "testlib_api.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
std::thread t([]() {
|
||||
testlib_symbols()->kotlin.root.enableMemoryChecker();
|
||||
testlib_symbols()->kotlin.root.leakMemory();
|
||||
});
|
||||
t.join();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
|
||||
import kotlinx.interop.wasm.math.*
|
||||
import kotlinx.wasm.jsinterop.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val e = Math.E
|
||||
val pi = Math.PI
|
||||
|
||||
val sin_pi = Math.sin(pi)
|
||||
val sin_pi_2 = Math.sin(pi/2)
|
||||
val ln_1 = Math.log(1.0)
|
||||
val ln_e = Math.log(e)
|
||||
|
||||
println("e = $e, pi = $pi, sin(pi) = $sin_pi, sin(pi/2) = $sin_pi_2, ln(1) = $ln_1, ln(e) = $ln_e")
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
e = 2.718281828459045, pi = 3.141592653589793, sin(pi) = 1.2246467991473532E-16, sin(pi/2) = 1.0, ln(1) = 0.0, ln(e) = 1.0
|
||||
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println("Hello")
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
This is a side effect of a test library linked into the binary.
|
||||
You should not be seeing this.
|
||||
|
||||
Hello
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class)
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.internal.Frozen
|
||||
|
||||
class NonFrozenClass
|
||||
|
||||
@Frozen
|
||||
class FrozenClass
|
||||
|
||||
val globalNonFrozen = NonFrozenClass()
|
||||
@SharedImmutable
|
||||
val sharedImmutableNonFrozen = NonFrozenClass()
|
||||
|
||||
val globalFrozen = FrozenClass()
|
||||
@SharedImmutable
|
||||
val sharedImmutableFrozen = FrozenClass()
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val mode = args.first()
|
||||
val localNonFrozen = NonFrozenClass()
|
||||
val localFrozen = FrozenClass()
|
||||
|
||||
when (mode) {
|
||||
"full" -> {
|
||||
checkFreezeCheck(localNonFrozen, false, true)
|
||||
checkFreezeCheck(localFrozen, true, true)
|
||||
checkFreezeCheck(globalNonFrozen, false, true)
|
||||
checkFreezeCheck(sharedImmutableNonFrozen, true, true)
|
||||
checkFreezeCheck(globalFrozen, true, true)
|
||||
checkFreezeCheck(sharedImmutableFrozen, true, true)
|
||||
}
|
||||
"disabled" -> {
|
||||
checkFreezeCheck(localNonFrozen, false, false)
|
||||
checkFreezeCheck(localFrozen, false, false)
|
||||
checkFreezeCheck(globalNonFrozen, false, false)
|
||||
checkFreezeCheck(sharedImmutableNonFrozen, false, false)
|
||||
checkFreezeCheck(globalFrozen, false, false)
|
||||
checkFreezeCheck(sharedImmutableFrozen, false, false)
|
||||
}
|
||||
"explicitOnly" -> {
|
||||
checkFreezeCheck(localNonFrozen, false, true)
|
||||
checkFreezeCheck(localFrozen, false, true)
|
||||
checkFreezeCheck(globalNonFrozen, false, true)
|
||||
checkFreezeCheck(sharedImmutableNonFrozen, false, true)
|
||||
checkFreezeCheck(globalFrozen, false, true)
|
||||
checkFreezeCheck(sharedImmutableFrozen, false, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFreezeCheck(arg: Any, isFrozenBefore: Boolean, isFrozenAfter: Boolean) {
|
||||
assertEquals(isFrozenBefore, arg.isFrozen)
|
||||
arg.freeze()
|
||||
assertEquals(isFrozenAfter, arg.isFrozen)
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.runtime.GC
|
||||
import kotlin.native.Platform
|
||||
import kotlin.test.*
|
||||
|
||||
fun test1() {
|
||||
val a = AtomicReference<Any?>(null)
|
||||
val b = AtomicReference<Any?>(null)
|
||||
a.value = b
|
||||
b.value = a
|
||||
}
|
||||
|
||||
class Holder(var other: Any?)
|
||||
|
||||
fun test2() {
|
||||
val array = arrayOf(AtomicReference<Any?>(null), AtomicReference<Any?>(null))
|
||||
val obj1 = Holder(array).freeze()
|
||||
array[0].value = obj1
|
||||
}
|
||||
|
||||
fun test3() {
|
||||
val a1 = FreezableAtomicReference<Any?>(null)
|
||||
val head = Holder(null)
|
||||
var current = head
|
||||
repeat(30) {
|
||||
val next = Holder(null)
|
||||
current.other = next
|
||||
current = next
|
||||
}
|
||||
a1.value = head
|
||||
current.other = a1
|
||||
current.freeze()
|
||||
}
|
||||
|
||||
|
||||
fun makeIt(): Holder {
|
||||
val atomic = AtomicReference<Holder?>(null)
|
||||
val holder = Holder(atomic).freeze()
|
||||
atomic.value = holder
|
||||
return holder
|
||||
}
|
||||
|
||||
|
||||
fun test4() {
|
||||
val holder = makeIt()
|
||||
// To clean rc count coming from rememberNewContainer().
|
||||
kotlin.native.runtime.GC.collect()
|
||||
// Request cyclic collection.
|
||||
kotlin.native.runtime.GC.collectCyclic()
|
||||
// Ensure we processed delayed release.
|
||||
repeat(10) {
|
||||
// Wait a bit and process queue.
|
||||
Worker.current.park(10)
|
||||
Worker.current.processQueue()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
}
|
||||
val value = @Suppress("UNCHECKED_CAST") (holder.other as? AtomicReference<Holder?>?)
|
||||
assertTrue(value != null)
|
||||
assertTrue(value.value == holder)
|
||||
}
|
||||
|
||||
fun createRef(): AtomicReference<Any?> {
|
||||
val atomic1 = AtomicReference<Any?>(null)
|
||||
val atomic2 = AtomicReference<Any?>(null)
|
||||
atomic1.value = atomic2
|
||||
atomic2.value = atomic1
|
||||
return atomic1
|
||||
}
|
||||
|
||||
class Holder2(var value: AtomicReference<Any?>) {
|
||||
fun switch() {
|
||||
value = value.value as AtomicReference<Any?>
|
||||
}
|
||||
}
|
||||
|
||||
fun createHolder2() = Holder2(createRef())
|
||||
|
||||
fun test5() {
|
||||
val holder = createHolder2()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
kotlin.native.runtime.GC.collectCyclic()
|
||||
Worker.current.park(100 * 1000)
|
||||
holder.switch()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
Worker.current.park(100 * 1000)
|
||||
withWorker {
|
||||
executeAfter(0L, {
|
||||
kotlin.native.runtime.GC.collect()
|
||||
}.freeze())
|
||||
}
|
||||
Worker.current.park(1000)
|
||||
assertTrue(holder.value.value != null)
|
||||
}
|
||||
|
||||
fun test6() {
|
||||
val atomic = AtomicReference<Any?>(null)
|
||||
atomic.value = Pair(atomic, Holder(atomic)).freeze()
|
||||
}
|
||||
|
||||
fun createRoot(): AtomicReference<Any?> {
|
||||
val ref1 = AtomicReference<Any?>(null)
|
||||
val ref2 = AtomicReference<Any?>(null)
|
||||
|
||||
ref1.value = Holder(ref2).freeze()
|
||||
ref2.value = Any().freeze()
|
||||
|
||||
return ref1
|
||||
}
|
||||
|
||||
fun test7() {
|
||||
val ref1 = createRoot()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
|
||||
kotlin.native.runtime.GC.collectCyclic()
|
||||
Worker.current.park(500 * 1000L)
|
||||
|
||||
withWorker {
|
||||
executeAfter(0L, {}.freeze())
|
||||
Worker.current.park(500 * 1000L)
|
||||
|
||||
val node = ref1.value as Holder
|
||||
val ref2 = node.other as AtomicReference<Any?>
|
||||
assertTrue(ref2.value != null)
|
||||
}
|
||||
}
|
||||
|
||||
fun array(size: Int) = Array<Any?>(size, { null })
|
||||
|
||||
fun test8() {
|
||||
val ref = AtomicReference<Any?>(null)
|
||||
val obj1 = array(2)
|
||||
val obj2 = array(1)
|
||||
val obj3 = array(2)
|
||||
|
||||
obj1[0] = obj2
|
||||
obj1[1] = obj3
|
||||
|
||||
obj2[0] = obj3
|
||||
|
||||
obj3[0] = obj2
|
||||
obj3[1] = ref
|
||||
|
||||
ref.value = obj1.freeze()
|
||||
}
|
||||
|
||||
fun createNode1(): Holder {
|
||||
val ref = AtomicReference<Any?>(null)
|
||||
val node2 = Holder(ref)
|
||||
val node1 = Holder(node2)
|
||||
ref.value = node1.freeze()
|
||||
|
||||
return node1
|
||||
}
|
||||
|
||||
fun getNode2(): Holder {
|
||||
val node1 = createNode1()
|
||||
GC.collect()
|
||||
|
||||
return node1.other as Holder
|
||||
}
|
||||
|
||||
fun test9() {
|
||||
withWorker {
|
||||
val node2 = getNode2()
|
||||
executeAfter(10 * 1000L, { GC.collectCyclic() }.freeze())
|
||||
|
||||
GC.collect()
|
||||
|
||||
Worker.current.park(50 * 1000L)
|
||||
|
||||
execute(TransferMode.SAFE, {}, {}).result
|
||||
|
||||
val ref = node2.other as AtomicReference<Any?>
|
||||
assertTrue(ref.value != null)
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
kotlin.native.runtime.GC.cyclicCollectorEnabled = true
|
||||
test1()
|
||||
test2()
|
||||
test3()
|
||||
test4()
|
||||
repeat(10) {
|
||||
test5()
|
||||
}
|
||||
test6()
|
||||
test7()
|
||||
test8()
|
||||
test9()
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.test.*
|
||||
|
||||
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
fun main() {
|
||||
kotlin.native.runtime.GC.cyclicCollectorEnabled = true
|
||||
|
||||
repeat(10000) {
|
||||
// Create atomic cyclic garbage:
|
||||
val ref = AtomicReference<Any?>(null)
|
||||
ref.value = ref
|
||||
}
|
||||
|
||||
// main thread will then run cycle collector termination, which involves running it and cleaning everything up.
|
||||
// 10000 references should hit [kGcThreshold] then.
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.runtime.GC
|
||||
import kotlin.native.Platform
|
||||
import kotlin.test.*
|
||||
|
||||
class Holder(var other: Any?)
|
||||
|
||||
class Holder2(var field1: Any?, var field2: Any?)
|
||||
|
||||
val <T> Array<T>.description: String
|
||||
get() {
|
||||
val result = StringBuilder()
|
||||
result.append('[')
|
||||
for (elem in this) {
|
||||
result.append(elem.toString())
|
||||
result.append(',')
|
||||
}
|
||||
result.append(']')
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
fun assertArrayEquals(
|
||||
expected: Array<Any>,
|
||||
actual: Array<Any>
|
||||
): Unit {
|
||||
val lazyMessage: () -> String? = {
|
||||
"Expected <${expected.description}>, actual <${actual.description}>."
|
||||
}
|
||||
|
||||
asserter.assertTrue(lazyMessage, expected.size == actual.size)
|
||||
for (i in expected.indices) {
|
||||
asserter.assertTrue(lazyMessage, expected[i] == actual[i])
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeTest
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noCycles() {
|
||||
val atomic1 = AtomicReference<Any?>(null)
|
||||
val atomic2 = AtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic1.value = atomic2
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(0, cycles.size)
|
||||
assertNull(GC.findCycle(atomic1));
|
||||
assertNull(GC.findCycle(atomic2));
|
||||
} finally {
|
||||
atomic1.value = null
|
||||
atomic2.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun oneCycle() {
|
||||
val atomic = AtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic.value = atomic
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(1, cycles.size)
|
||||
assertArrayEquals(arrayOf(atomic, atomic), GC.findCycle(cycles[0])!!)
|
||||
} finally {
|
||||
atomic.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun oneCycleWithHolder() {
|
||||
val atomic = AtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic.value = Holder(atomic).freeze()
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(1, cycles.size)
|
||||
assertArrayEquals(arrayOf(atomic, atomic.value!!, atomic), GC.findCycle(cycles[0])!!)
|
||||
assertArrayEquals(arrayOf(atomic.value!!, atomic, atomic.value!!), GC.findCycle(atomic.value!!)!!)
|
||||
} finally {
|
||||
atomic.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun oneCycleWithArray() {
|
||||
val array = arrayOf(AtomicReference<Any?>(null), AtomicReference<Any?>(null))
|
||||
try {
|
||||
array[0].value = Holder(array).freeze()
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(1, cycles.size)
|
||||
assertArrayEquals(arrayOf(array[0], array[0].value!!, array, array[0]), GC.findCycle(cycles[0])!!)
|
||||
} finally {
|
||||
array[0].value = null
|
||||
array[1].value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun oneCycleWithLongChain() {
|
||||
val atomic = AtomicReference<Any?>(null)
|
||||
try {
|
||||
val head = Holder(null)
|
||||
var current = head
|
||||
repeat(30) {
|
||||
val next = Holder(null)
|
||||
current.other = next
|
||||
current = next
|
||||
}
|
||||
current.other = atomic
|
||||
atomic.value = head.freeze()
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(1, cycles.size)
|
||||
val cycle = GC.findCycle(cycles[0])!!
|
||||
assertEquals(33, cycle.size)
|
||||
} finally {
|
||||
atomic.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun twoCycles() {
|
||||
val atomic1 = AtomicReference<Any?>(null)
|
||||
val atomic2 = AtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic1.value = atomic2
|
||||
atomic2.value = atomic1
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(2, cycles.size)
|
||||
assertArrayEquals(arrayOf(atomic2, atomic1, atomic2), GC.findCycle(cycles[0])!!)
|
||||
assertArrayEquals(arrayOf(atomic1, atomic2, atomic1), GC.findCycle(cycles[1])!!)
|
||||
} finally {
|
||||
atomic1.value = null
|
||||
atomic2.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun twoCyclesWithHolder() {
|
||||
val atomic1 = AtomicReference<Any?>(null)
|
||||
val atomic2 = AtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic1.value = atomic2
|
||||
atomic2.value = Holder(atomic1).freeze()
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(2, cycles.size)
|
||||
assertArrayEquals(arrayOf(atomic2, atomic2.value!!, atomic1, atomic2), GC.findCycle(cycles[0])!!)
|
||||
assertArrayEquals(arrayOf(atomic1, atomic2, atomic2.value!!, atomic1), GC.findCycle(cycles[1])!!)
|
||||
} finally {
|
||||
atomic1.value = null
|
||||
atomic2.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun threeSeparateCycles() {
|
||||
val atomic1 = AtomicReference<Any?>(null)
|
||||
val atomic2 = AtomicReference<Any?>(null)
|
||||
val atomic3 = AtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic1.value = atomic1
|
||||
atomic2.value = Holder2(atomic1, atomic2).freeze()
|
||||
atomic3.value = Holder2(atomic3, atomic1).freeze()
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(3, cycles.size)
|
||||
assertArrayEquals(arrayOf(atomic3, atomic3.value!!, atomic3), GC.findCycle(cycles[0])!!)
|
||||
assertArrayEquals(arrayOf(atomic2, atomic2.value!!, atomic2), GC.findCycle(cycles[1])!!)
|
||||
assertArrayEquals(arrayOf(atomic1, atomic1), GC.findCycle(cycles[2])!!)
|
||||
} finally {
|
||||
atomic1.value = null
|
||||
atomic2.value = null
|
||||
atomic3.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noCyclesWithFreezableAtomicReference() {
|
||||
val atomic = FreezableAtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic.value = atomic
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(0, cycles.size)
|
||||
} finally {
|
||||
atomic.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun oneCycleWithFrozenFreezableAtomicReference() {
|
||||
val atomic = FreezableAtomicReference<Any?>(null)
|
||||
try {
|
||||
atomic.value = atomic
|
||||
atomic.freeze()
|
||||
val cycles = GC.detectCycles()!!
|
||||
assertEquals(1, cycles.size)
|
||||
assertArrayEquals(arrayOf(atomic, atomic), GC.findCycle(cycles[0])!!)
|
||||
} finally {
|
||||
atomic.value = null
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||
|
||||
package runtime.workers.freeze0
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
data class SharedDataMember(val double: Double)
|
||||
|
||||
data class SharedData(val string: String, val int: Int, val member: SharedDataMember)
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = Worker.start()
|
||||
// Create immutable shared data.
|
||||
val immutable = SharedData("Hello", 10, SharedDataMember(0.1)).freeze()
|
||||
println("frozen bit is ${immutable.isFrozen}")
|
||||
|
||||
val future = worker.execute(TransferMode.SAFE, { immutable } ) {
|
||||
input ->
|
||||
println("Worker: $input")
|
||||
input
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Main: $result")
|
||||
}
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
frozen bit is true
|
||||
Worker: SharedData(string=Hello, int=10, member=SharedDataMember(double=0.1))
|
||||
Main: SharedData(string=Hello, int=10, member=SharedDataMember(double=0.1))
|
||||
OK
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class)
|
||||
|
||||
package runtime.workers.freeze1
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
data class Node(var previous: Node?, var data: Int)
|
||||
|
||||
fun makeCycle(count: Int): Node {
|
||||
val first = Node(null, 0)
|
||||
var current = first
|
||||
for (index in 1 .. count - 1) {
|
||||
current = Node(current, index)
|
||||
}
|
||||
first.previous = current
|
||||
return first
|
||||
}
|
||||
|
||||
data class Node2(var leaf1: Node2?, var leaf2: Node2?)
|
||||
|
||||
fun makeDiamond(): Node2 {
|
||||
val bottom = Node2(null, null)
|
||||
val mid1prime = Node2(bottom, null)
|
||||
val mid1 = Node2(mid1prime, null)
|
||||
val mid2 = Node2(bottom, null)
|
||||
return Node2(mid1, mid2)
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
makeCycle(10).freeze()
|
||||
|
||||
// Must be able to freeze diamond shaped graph.
|
||||
val diamond = makeDiamond().freeze()
|
||||
|
||||
val immutable = Node(null, 4).freeze()
|
||||
try {
|
||||
immutable.data = 42
|
||||
} catch (e: InvalidMutabilityException) {
|
||||
println("OK, cannot mutate frozen")
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
OK, cannot mutate frozen
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||
|
||||
package runtime.workers.freeze2
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
data class Data(var int: Int)
|
||||
|
||||
@Test fun runTest() {
|
||||
// Ensure that we can not mutate frozen objects and arrays.
|
||||
val a0 = Data(2)
|
||||
a0.int++
|
||||
a0.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> {a0.int++ }
|
||||
|
||||
val a1 = ByteArray(2)
|
||||
a1[1]++
|
||||
a1.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a1[1]++ }
|
||||
|
||||
val a2 = ShortArray(2)
|
||||
a2[1]++
|
||||
a2.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a2[1]++ }
|
||||
|
||||
val a3 = IntArray(2)
|
||||
a3[1]++
|
||||
a3.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a3[1]++ }
|
||||
|
||||
val a4 = LongArray(2)
|
||||
a4[1]++
|
||||
a4.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a4[1]++ }
|
||||
|
||||
val a5 = BooleanArray(2)
|
||||
a5[1] = true
|
||||
a5.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a5[1] = false }
|
||||
|
||||
val a6 = CharArray(2)
|
||||
a6[1] = 'a'
|
||||
a6.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a6[1] = 'b' }
|
||||
|
||||
val a7 = FloatArray(2)
|
||||
a7[1] = 1.0f
|
||||
a7.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a7[1] = 2.0f }
|
||||
|
||||
val a8 = DoubleArray(2)
|
||||
a8[1] = 1.0
|
||||
a8.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> { a8[1] = 2.0 }
|
||||
|
||||
// Ensure that String and integral boxes are frozen by default, by passing local to the worker.
|
||||
val worker = Worker.start()
|
||||
var data: Any = "Hello" + " " + "world"
|
||||
assertTrue(data.isFrozen)
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker 1: $input")
|
||||
}.result
|
||||
|
||||
data = 42
|
||||
assertTrue(data.isFrozen)
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker2: $input")
|
||||
}.result
|
||||
|
||||
data = 239.0
|
||||
assertTrue(data.isFrozen)
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker3: $input")
|
||||
}.result
|
||||
|
||||
data = 'a'
|
||||
assertTrue(data.isFrozen)
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker4: $input")
|
||||
}.result
|
||||
|
||||
worker.requestTermination().result
|
||||
|
||||
println("OK")
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
Worker 1: Hello world
|
||||
Worker2: 42
|
||||
Worker3: 239.0
|
||||
Worker4: a
|
||||
OK
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||
|
||||
package runtime.workers.freeze3
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
object AnObject {
|
||||
var x = 1
|
||||
}
|
||||
|
||||
@ThreadLocal
|
||||
object Mutable {
|
||||
var x = 2
|
||||
}
|
||||
|
||||
val topLevelInline: ULong = 0xc3a5c85c97cb3127U
|
||||
|
||||
@Test fun runTest1() {
|
||||
assertEquals(1, AnObject.x)
|
||||
if (Platform.memoryModel == MemoryModel.STRICT) {
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
AnObject.x++
|
||||
}
|
||||
assertEquals(1, AnObject.x)
|
||||
} else {
|
||||
AnObject.x++
|
||||
assertEquals(2, AnObject.x)
|
||||
}
|
||||
|
||||
Mutable.x++
|
||||
assertEquals(3, Mutable.x)
|
||||
println("OK")
|
||||
}
|
||||
|
||||
@Test fun runTest2() {
|
||||
val ok = AtomicInt(0)
|
||||
withWorker() {
|
||||
executeAfter(0, {
|
||||
assertEquals(0xc3a5c85c97cb3127U, topLevelInline)
|
||||
ok.increment()
|
||||
}.freeze())
|
||||
}
|
||||
assertEquals(1, ok.value)
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
OK
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class)
|
||||
|
||||
package runtime.workers.freeze4
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
data class Data(val x: Int, val s: String, val next: Data? = null)
|
||||
|
||||
@Test fun runTest() {
|
||||
val data1 = Data(1, "")
|
||||
data1.freeze()
|
||||
assertFailsWith<FreezingException> {
|
||||
data1.ensureNeverFrozen()
|
||||
}
|
||||
|
||||
val dataNF = Data(42, "42")
|
||||
dataNF.ensureNeverFrozen()
|
||||
val data2 = Data(2, "2", dataNF)
|
||||
assertFailsWith<FreezingException> {
|
||||
data2.freeze()
|
||||
}
|
||||
assert(!data2.isFrozen)
|
||||
println("OK")
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
OK
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
|
||||
package runtime.workers.freeze5
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
object Keys {
|
||||
internal val myMap: Map<String, List<String>> = mapOf(
|
||||
"val1" to listOf("a1", "a2", "a3"),
|
||||
"val2" to listOf("b1", "b2")
|
||||
)
|
||||
|
||||
fun getKey(name: String): String {
|
||||
for (key in myMap.keys) {
|
||||
if (key == name) {
|
||||
return key
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
fun getValue(name: String): String {
|
||||
for (value in myMap.values) {
|
||||
if (value.contains(name)) {
|
||||
return name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
fun getEntry(name: String): String {
|
||||
for (entry in myMap.entries) {
|
||||
if (entry.key == name) {
|
||||
return entry.key
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@Test fun runTest() {
|
||||
assertEquals("val2", Keys.getKey("val2"))
|
||||
assertEquals("a1", Keys.getValue("a1"))
|
||||
assertEquals("val1", Keys.getEntry("val1"))
|
||||
println("OK")
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
OK
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
|
||||
package runtime.workers.freeze6
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.*
|
||||
|
||||
data class Hi(val s: String)
|
||||
data class Nested(val hi: Hi)
|
||||
|
||||
@Test
|
||||
fun ensureNeverFrozenNoFreezeChild(){
|
||||
val noFreeze = Hi("qwert")
|
||||
noFreeze.ensureNeverFrozen()
|
||||
|
||||
val nested = Nested(noFreeze)
|
||||
assertFails { nested.freeze() }
|
||||
|
||||
println("OK")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ensureNeverFrozenFailsTarget(){
|
||||
val noFreeze = Hi("qwert")
|
||||
noFreeze.ensureNeverFrozen()
|
||||
|
||||
assertFalse(noFreeze.isFrozen)
|
||||
assertFails { noFreeze.freeze() }
|
||||
assertFalse(noFreeze.isFrozen)
|
||||
println("OK")
|
||||
}
|
||||
|
||||
fun createRef1(): FreezableAtomicReference<Any?> {
|
||||
val ref = FreezableAtomicReference<Any?>(null)
|
||||
ref.value = ref
|
||||
ref.freeze()
|
||||
ref.value = null
|
||||
return ref
|
||||
}
|
||||
|
||||
var global = 0
|
||||
|
||||
@Test
|
||||
fun ensureFreezableHandlesCycles1() {
|
||||
val ref = createRef1()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
|
||||
val obj: Any = ref
|
||||
global = obj.hashCode()
|
||||
}
|
||||
|
||||
class Node(var ref: Any?)
|
||||
|
||||
/**
|
||||
* ref1 -> Node <- ref3
|
||||
* | /\
|
||||
* V |
|
||||
* ref2 ---
|
||||
*/
|
||||
fun createRef2(): Pair<FreezableAtomicReference<Node?>, Any> {
|
||||
val ref1 = FreezableAtomicReference<Node?>(null)
|
||||
|
||||
val node = Node(null)
|
||||
val ref3 = FreezableAtomicReference<Any?>(node)
|
||||
val ref2 = FreezableAtomicReference<Any?>(ref3)
|
||||
|
||||
node.ref = ref2
|
||||
ref1.value = node
|
||||
|
||||
ref1.freeze()
|
||||
ref3.value = null
|
||||
|
||||
assertTrue(node.isFrozen)
|
||||
assertTrue(ref1.isFrozen)
|
||||
assertTrue(ref2.isFrozen)
|
||||
assertTrue(ref3.isFrozen)
|
||||
|
||||
return ref1 to ref2
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ensureFreezableHandlesCycles2() {
|
||||
val (ref, obj) = createRef2()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
|
||||
assertTrue(obj.toString().length > 0)
|
||||
global = ref.value!!.ref!!.hashCode()
|
||||
}
|
||||
|
||||
fun createRef3(): FreezableAtomicReference<Any?> {
|
||||
val ref = FreezableAtomicReference<Any?>(null)
|
||||
val node = Node(ref)
|
||||
ref.value = node
|
||||
ref.freeze()
|
||||
|
||||
assertTrue(node.isFrozen)
|
||||
assertTrue(ref.isFrozen)
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ensureFreezableHandlesCycles3() {
|
||||
val ref = createRef3()
|
||||
ref.value = null
|
||||
kotlin.native.runtime.GC.collect()
|
||||
|
||||
val obj: Any = ref
|
||||
assertTrue(obj.toString().length > 0)
|
||||
global = obj.hashCode()
|
||||
}
|
||||
|
||||
lateinit var weakRef: WeakReference<Any>
|
||||
|
||||
fun createRef4(): FreezableAtomicReference<Any?> {
|
||||
val ref = FreezableAtomicReference<Any?>(null)
|
||||
val node = Node(ref)
|
||||
weakRef = WeakReference(node)
|
||||
ref.value = node
|
||||
ref.freeze()
|
||||
assertTrue(weakRef.get() != null)
|
||||
return ref
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ensureWeakRefNotLeaks1() {
|
||||
val ref = createRef4()
|
||||
ref.value = null
|
||||
// We cannot check weakRef.get() here, as value read will be stored in the stack slot,
|
||||
// and thus hold weak reference from release.
|
||||
kotlin.native.runtime.GC.collect()
|
||||
|
||||
assertTrue(weakRef.get() == null)
|
||||
}
|
||||
|
||||
lateinit var node1: Node
|
||||
lateinit var weakNode2: WeakReference<Node>
|
||||
|
||||
fun createRef5() {
|
||||
val ref = FreezableAtomicReference<Any?>(null)
|
||||
node1 = Node(ref)
|
||||
val node2 = Node(node1)
|
||||
weakNode2 = WeakReference(node2)
|
||||
ref.value = node2
|
||||
node1.freeze()
|
||||
assertTrue(weakNode2.get() != null)
|
||||
ref.value = null
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ensureWeakRefNotLeaks2() {
|
||||
createRef5()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
assertTrue(weakNode2.get() == null)
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
OK
|
||||
OK
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
@file:OptIn(FreezingIsDeprecated::class)
|
||||
|
||||
package runtime.workers.freeze_stress
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
class Random(private var seed: Int) {
|
||||
fun next(): Int {
|
||||
seed = (1103515245 * seed + 12345) and 0x7fffffff
|
||||
return seed
|
||||
}
|
||||
|
||||
fun next(maxExclusiveValue: Int) = if (maxExclusiveValue == 0) 0 else next() % maxExclusiveValue
|
||||
|
||||
fun next(minInclusiveValue: Int, maxInclusiveValue: Int) =
|
||||
minInclusiveValue + next(maxInclusiveValue - minInclusiveValue + 1)
|
||||
}
|
||||
|
||||
class Node(val id: Int) {
|
||||
var numberOfEdges = 0
|
||||
|
||||
lateinit var edge0: Node
|
||||
lateinit var edge1: Node
|
||||
lateinit var edge2: Node
|
||||
lateinit var edge3: Node
|
||||
lateinit var edge4: Node
|
||||
lateinit var edge5: Node
|
||||
lateinit var edge6: Node
|
||||
lateinit var edge7: Node
|
||||
lateinit var edge8: Node
|
||||
lateinit var edge9: Node
|
||||
|
||||
fun addEdge(child: Node) {
|
||||
when (numberOfEdges) {
|
||||
0 -> edge0 = child
|
||||
1 -> edge1 = child
|
||||
2 -> edge2 = child
|
||||
3 -> edge3 = child
|
||||
4 -> edge4 = child
|
||||
5 -> edge5 = child
|
||||
6 -> edge6 = child
|
||||
7 -> edge7 = child
|
||||
8 -> edge8 = child
|
||||
9 -> edge9 = child
|
||||
else -> error("Too many edges")
|
||||
}
|
||||
++numberOfEdges
|
||||
}
|
||||
|
||||
fun getEdges(): List<Node> {
|
||||
val result = mutableListOf<Node>()
|
||||
if (numberOfEdges > 0) result += edge0
|
||||
if (numberOfEdges > 1) result += edge1
|
||||
if (numberOfEdges > 2) result += edge2
|
||||
if (numberOfEdges > 3) result += edge3
|
||||
if (numberOfEdges > 4) result += edge4
|
||||
if (numberOfEdges > 5) result += edge5
|
||||
if (numberOfEdges > 6) result += edge6
|
||||
if (numberOfEdges > 7) result += edge7
|
||||
if (numberOfEdges > 8) result += edge8
|
||||
if (numberOfEdges > 9) result += edge9
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
class Graph(val nodes: List<Node>, val roots: List<Node>)
|
||||
|
||||
fun min(x: Int, y: Int) = if (x < y) x else y
|
||||
fun max(x: Int, y: Int) = if (x > y) x else y
|
||||
|
||||
@ThreadLocal
|
||||
val random = Random(42)
|
||||
|
||||
fun generate(condensationSize: Int, branchingFactor: Int, swellingFactor: Int): Graph {
|
||||
var id = 0
|
||||
val nodes = mutableListOf<Node>()
|
||||
|
||||
fun genDAG(n: Int): Node {
|
||||
val node = Node(id++)
|
||||
nodes += node
|
||||
if (n == 1) return node
|
||||
val numberOfChildren = random.next(1, min(n - 1, branchingFactor))
|
||||
val used = BooleanArray(n)
|
||||
val points = IntArray(numberOfChildren + 1)
|
||||
points[0] = 0
|
||||
points[numberOfChildren] = n - 1
|
||||
used[0] = true
|
||||
used[n - 1] = true
|
||||
for (i in 1 until numberOfChildren) {
|
||||
var p: Int
|
||||
do {
|
||||
p = random.next(1, n - 1)
|
||||
} while (used[p])
|
||||
used[p] = true
|
||||
points[i] = p
|
||||
}
|
||||
points.sort()
|
||||
for (i in 1..numberOfChildren) {
|
||||
val childSize = points[i] - points[i - 1]
|
||||
val child = genDAG(childSize)
|
||||
if (random.next(2) == 0)
|
||||
node.addEdge(child)
|
||||
else
|
||||
child.addEdge(node)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
genDAG(condensationSize)
|
||||
|
||||
val numberOfEnters = IntArray(condensationSize)
|
||||
for (node in nodes)
|
||||
for (edge in node.getEdges())
|
||||
++numberOfEnters[edge.id]
|
||||
val roots = nodes.filter { numberOfEnters[it.id] == 0 }
|
||||
for (i in 0 until condensationSize) {
|
||||
val node = nodes[i]
|
||||
val componentSize = random.next(1, swellingFactor)
|
||||
if (componentSize == 1 && random.next(2) == 0)
|
||||
continue
|
||||
val component = Array(componentSize) {
|
||||
if (it == 0) node else Node(id++).also { nodes += it }
|
||||
}
|
||||
for (j in 0 until componentSize)
|
||||
component[j].addEdge(component[(j - 1 + componentSize) % componentSize])
|
||||
val numberOfAdditionalEdges = random.next((componentSize + 1) / 2)
|
||||
for (j in 0 until numberOfAdditionalEdges)
|
||||
component[random.next(componentSize)].addEdge(component[random.next(componentSize)])
|
||||
}
|
||||
|
||||
return Graph(nodes, roots)
|
||||
}
|
||||
|
||||
fun freezeOneGraph() {
|
||||
val graph = generate(100, 5, 20)
|
||||
graph.roots.forEach { it.freeze() }
|
||||
for (node in graph.nodes)
|
||||
assert (node.isFrozen, { "All nodes should be frozen" })
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
for (i in 0..1000) {
|
||||
freezeOneGraph()
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
OK
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.
|
||||
*/
|
||||
|
||||
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||
package runtime.workers.worker9
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest1() {
|
||||
withLock { println("zzz") }
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, {}) {
|
||||
withLock {
|
||||
println("42")
|
||||
}
|
||||
}
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
|
||||
fun withLock(op: () -> Unit) {
|
||||
op()
|
||||
}
|
||||
|
||||
@Test fun runTest2() {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, {}) {
|
||||
val me = Worker.current
|
||||
var x = 1
|
||||
me.executeAfter (20000) {
|
||||
println("second ${++x}")
|
||||
}
|
||||
me.executeAfter(10000) {
|
||||
println("first ${++x}")
|
||||
}
|
||||
}
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test fun runTest3() {
|
||||
val worker = Worker.start()
|
||||
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
worker.executeAfter {
|
||||
println("unfrozen OK")
|
||||
}
|
||||
} else {
|
||||
assertFailsWith<IllegalStateException> {
|
||||
val message = "shall not happen"
|
||||
worker.executeAfter {
|
||||
println(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
val message = "shall not happen"
|
||||
worker.executeAfter(-1, {
|
||||
println(message)
|
||||
}.freeze())
|
||||
}
|
||||
|
||||
worker.executeAfter(0, {
|
||||
println("frozen OK")
|
||||
}.freeze())
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
class Node(var node: Node?, var outher: Node?)
|
||||
|
||||
fun makeCyclic(): Node {
|
||||
val inner = Node(null, null)
|
||||
inner.node = inner
|
||||
val outer = Node(null, null)
|
||||
inner.outher = outer
|
||||
return outer
|
||||
}
|
||||
|
||||
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
@Test fun runTest4() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val future = worker.execute(TransferMode.SAFE, { }) {
|
||||
makeCyclic().also {
|
||||
kotlin.native.runtime.GC.collect()
|
||||
}
|
||||
}
|
||||
assert(future.result != null)
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
zzz
|
||||
42
|
||||
OK
|
||||
first 2
|
||||
second 3
|
||||
frozen OK
|
||||
@@ -46,7 +46,6 @@ val buildSamplesWithPlatformLibs by tasks.creating {
|
||||
}
|
||||
dependsOn(":echoServer:assemble")
|
||||
dependsOn(":globalState:assemble")
|
||||
dependsOn(":html5Canvas:assemble")
|
||||
dependsOn(":workers:assemble")
|
||||
|
||||
if (isMacos || isLinux) {
|
||||
|
||||
@@ -4,8 +4,7 @@ plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
// Add two additional presets for Raspberry Pi and Linux/ARM64.
|
||||
val raspberryPiPresets: List<KotlinNativeTargetPreset> = listOf("linuxArm32Hfp", "linuxArm64").map {
|
||||
val additionalPresets: List<KotlinNativeTargetPreset> = listOf("linuxArm64").map {
|
||||
kotlin.presets[it] as KotlinNativeTargetPreset
|
||||
}
|
||||
|
||||
@@ -22,13 +21,13 @@ kotlin {
|
||||
}
|
||||
|
||||
// Create cross-targets.
|
||||
val raspberryPiTargets = raspberryPiPresets.map { preset ->
|
||||
val additionalTargets = additionalPresets.map { preset ->
|
||||
val targetName = "echoServer${preset.name.capitalize()}"
|
||||
targetFromPreset(preset, targetName) {}
|
||||
}
|
||||
|
||||
// Configure executables for all targets.
|
||||
configure(raspberryPiTargets + listOf(hostTarget)) {
|
||||
configure(additionalTargets + listOf(hostTarget)) {
|
||||
binaries {
|
||||
executable {
|
||||
entryPoint = "sample.echoserver.main"
|
||||
@@ -39,7 +38,7 @@ kotlin {
|
||||
|
||||
sourceSets {
|
||||
val echoServerMain by getting
|
||||
raspberryPiPresets.forEach { preset ->
|
||||
additionalPresets.forEach { preset ->
|
||||
val mainSourceSetName = "echoServer${preset.name.capitalize()}Main"
|
||||
getByName(mainSourceSetName).dependsOn(echoServerMain)
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
val hostOs = System.getProperty("os.name")
|
||||
val isWindows = hostOs.startsWith("Windows")
|
||||
|
||||
val packageName = "kotlinx.interop.wasm.dom"
|
||||
val jsinteropKlibFile = buildDir.resolve("klib").resolve("$packageName-jsinterop.klib")
|
||||
|
||||
kotlin {
|
||||
wasm32("html5Canvas") {
|
||||
binaries {
|
||||
executable {
|
||||
entryPoint = "sample.html5canvas.main"
|
||||
}
|
||||
}
|
||||
}
|
||||
jvm("httpServer")
|
||||
sourceSets {
|
||||
val html5CanvasMain by getting {
|
||||
dependencies {
|
||||
implementation(files(jsinteropKlibFile))
|
||||
}
|
||||
}
|
||||
val httpServerMain by getting {
|
||||
dependencies {
|
||||
implementation("io.ktor:ktor-server-netty:1.2.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val jsinterop by tasks.creating(Exec::class) {
|
||||
workingDir = projectDir
|
||||
|
||||
val ext = if (isWindows) ".bat" else ""
|
||||
val distributionPath = project.properties["kotlin.native.home"] as String?
|
||||
|
||||
if (distributionPath != null) {
|
||||
val jsinteropCommand = file(distributionPath).resolve("bin").resolve("jsinterop$ext")
|
||||
|
||||
inputs.property("jsinteropCommand", jsinteropCommand)
|
||||
inputs.property("jsinteropPackageName", packageName)
|
||||
outputs.file(jsinteropKlibFile)
|
||||
|
||||
commandLine(
|
||||
jsinteropCommand,
|
||||
"-pkg", packageName,
|
||||
"-o", jsinteropKlibFile,
|
||||
"-target", "wasm32"
|
||||
)
|
||||
} else {
|
||||
doFirst {
|
||||
// Abort build execution if the distribution path isn't specified.
|
||||
throw GradleException(
|
||||
"""
|
||||
|
|
||||
|Kotlin/Native distribution path must be specified to build the JavaScript interop.
|
||||
|Use 'kotlin.native.home' project property to specify it.
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(AbstractKotlinNativeCompile::class).all {
|
||||
dependsOn(jsinterop)
|
||||
}
|
||||
|
||||
val assemble by tasks.getting
|
||||
|
||||
// This is to run embedded HTTP server with Ktor:
|
||||
val runProgram by tasks.creating(JavaExec::class) {
|
||||
dependsOn(assemble)
|
||||
|
||||
val httpServer: KotlinJvmTarget by kotlin.targets
|
||||
val httpServerMainCompilation = httpServer.compilations["main"]
|
||||
|
||||
main = "sample.html5canvas.httpserver.HttpServer"
|
||||
classpath = files(httpServerMainCompilation.output) + httpServerMainCompilation.runtimeDependencyFiles
|
||||
args = listOf(projectDir.toString())
|
||||
}
|
||||
|
||||
tasks.withType(KotlinJvmCompile::class).all {
|
||||
runProgram.dependsOn(this)
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.import.noCommonSourceSets=true
|
||||
@@ -1,14 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<script src="build/bin/html5Canvas/releaseExecutable/html5Canvas.wasm.js" wasm="build/bin/html5Canvas/releaseExecutable/html5Canvas.wasm"> </script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="myCanvas" width="640" height="480" style="border:1px solid #000000;">
|
||||
</canvas>
|
||||
<p>Draw something using the mouse!</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package sample.html5canvas
|
||||
|
||||
import kotlinx.interop.wasm.dom.*
|
||||
import kotlinx.wasm.jsinterop.*
|
||||
|
||||
fun main() {
|
||||
|
||||
val canvas = document.getElementById("myCanvas").asCanvas
|
||||
val ctx = canvas.getContext("2d")
|
||||
val rect = canvas.getBoundingClientRect()
|
||||
val rectLeft = rect.left
|
||||
val rectTop = rect.top
|
||||
|
||||
var mouseX: Int = 0
|
||||
var mouseY: Int = 0
|
||||
var draw: Boolean = false
|
||||
|
||||
document.setter("onmousemove") { arguments: ArrayList<JsValue> ->
|
||||
val event = MouseEvent(arguments[0])
|
||||
mouseX = event.getInt("clientX") - rectLeft
|
||||
mouseY = event.getInt("clientY") - rectTop
|
||||
|
||||
if (mouseX < 0) mouseX = 0
|
||||
if (mouseX > 639) mouseX = 639
|
||||
if (mouseY < 0) mouseY = 0
|
||||
if (mouseY > 479) mouseY = 479
|
||||
}
|
||||
|
||||
document.setter("onmousedown") {
|
||||
draw = true
|
||||
}
|
||||
|
||||
document.setter("onmouseup") {
|
||||
draw = false
|
||||
}
|
||||
|
||||
setInterval(10) {
|
||||
if (draw) {
|
||||
ctx.strokeStyle = "#222222"
|
||||
ctx.lineTo(mouseX, mouseY)
|
||||
ctx.stroke()
|
||||
} else {
|
||||
ctx.moveTo(mouseX, mouseY)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:JvmName("HttpServer")
|
||||
|
||||
package sample.html5canvas.httpserver
|
||||
|
||||
import io.ktor.application.call
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.content.LocalFileContent
|
||||
import io.ktor.http.content.default
|
||||
import io.ktor.http.content.files
|
||||
import io.ktor.http.content.static
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.routing.get
|
||||
import io.ktor.routing.routing
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.netty.Netty
|
||||
import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
check(args.size == 1) { "Invalid number of arguments: $args.\nExpected one argument with content root." }
|
||||
|
||||
val contentRoot = File(args[0])
|
||||
check(contentRoot.isDirectory) { "Invalid content root: $contentRoot." }
|
||||
|
||||
println(
|
||||
"""
|
||||
|
||||
IMPORTANT: Please open http://localhost:8080/ in your browser!
|
||||
|
||||
To stop embedded HTTP server use Ctrl+C (Cmd+C for Mac OS X).
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val server = embeddedServer(Netty, 8080) {
|
||||
routing {
|
||||
val wasm = "build/bin/html5Canvas/releaseExecutable/html5Canvas.wasm"
|
||||
get(wasm) {
|
||||
// TODO: ktor as of now doesn't know about 'application/wasm'.
|
||||
// The newer browsers (firefox and chrome at least) don't allow
|
||||
// 'application/octet-stream' for wasm anymore.
|
||||
// We provide the proper content type here and,
|
||||
// at the same time, put it into the ktor database.
|
||||
// Remove this whole get() clause when ktor fix is available.
|
||||
call.respond(LocalFileContent(File(wasm), ContentType("application", "wasm")))
|
||||
}
|
||||
static("/") {
|
||||
files(contentRoot)
|
||||
default("index.html")
|
||||
}
|
||||
}
|
||||
}
|
||||
server.start(wait = true)
|
||||
}
|
||||
@@ -8,7 +8,7 @@ plugins {
|
||||
val sdkName: String? = System.getenv("SDK_NAME")
|
||||
|
||||
enum class Target(val simulator: Boolean, val key: String) {
|
||||
WATCHOS_X86(true, "watchos"), WATCHOS_ARM64(false, "watchos"),
|
||||
WATCHOS_X64(true, "watchos"), WATCHOS_ARM64(false, "watchos"),
|
||||
IOS_X64(true, "ios"), IOS_ARM64(false, "ios")
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ val target = sdkName.orEmpty().let {
|
||||
it.startsWith("iphoneos") -> Target.IOS_ARM64
|
||||
it.startsWith("iphonesimulator") -> Target.IOS_X64
|
||||
it.startsWith("watchos") -> Target.WATCHOS_ARM64
|
||||
it.startsWith("watchsimulator") -> Target.WATCHOS_X86
|
||||
else -> Target.WATCHOS_X86
|
||||
it.startsWith("watchsimulator") -> Target.WATCHOS_X64
|
||||
else -> Target.WATCHOS_X64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ kotlin {
|
||||
watchosArm64("watchos")
|
||||
} else {
|
||||
// Simulator.
|
||||
watchosX86("watchos")
|
||||
watchosX64("watchos")
|
||||
}
|
||||
|
||||
// Declare the output program.
|
||||
|
||||
+1
-6
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.LibraryCompil
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.MemoryModel
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.File
|
||||
@@ -89,14 +88,10 @@ class CompilerOutputTest : AbstractNativeSimpleTest() {
|
||||
}
|
||||
|
||||
private fun normalizeOutput(output: String, exitCode: ExitCode): String {
|
||||
var normalizedOutput = AbstractCliTest.getNormalizedCompilerOutput(
|
||||
return AbstractCliTest.getNormalizedCompilerOutput(
|
||||
output,
|
||||
exitCode,
|
||||
"compiler/testData/compileKotlinAgainstCustomBinaries/"
|
||||
)
|
||||
if (testRunSettings.get<MemoryModel>() != MemoryModel.EXPERIMENTAL) {
|
||||
normalizedOutput = normalizedOutput.replace("warning: legacy MM is deprecated and will be removed in version 1.9.20\n", "")
|
||||
}
|
||||
return normalizedOutput
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -60,7 +60,6 @@ internal enum class ClassLevelProperty(shortName: String) {
|
||||
FORCE_STANDALONE("forceStandalone"),
|
||||
COMPILE_ONLY("compileOnly"),
|
||||
OPTIMIZATION_MODE("optimizationMode"),
|
||||
MEMORY_MODEL("memoryModel"),
|
||||
USE_THREAD_STATE_CHECKER("useThreadStateChecker"),
|
||||
GC_TYPE("gcType"),
|
||||
GC_SCHEDULER("gcScheduler"),
|
||||
|
||||
-18
@@ -150,13 +150,9 @@ private object NativeTestSupport {
|
||||
val enforcedProperties = EnforcedProperties(enclosingTestClass)
|
||||
|
||||
val optimizationMode = computeOptimizationMode(enforcedProperties)
|
||||
val memoryModel = computeMemoryModel(enforcedProperties)
|
||||
|
||||
val threadStateChecker = computeThreadStateChecker(enforcedProperties)
|
||||
if (threadStateChecker == ThreadStateChecker.ENABLED) {
|
||||
assertEquals(MemoryModel.EXPERIMENTAL, memoryModel) {
|
||||
"Thread state checker can be enabled only with experimental memory model"
|
||||
}
|
||||
assertEquals(OptimizationMode.DEBUG, optimizationMode) {
|
||||
"Thread state checker can be enabled only with debug optimization mode"
|
||||
}
|
||||
@@ -164,18 +160,8 @@ private object NativeTestSupport {
|
||||
val sanitizer = computeSanitizer(enforcedProperties)
|
||||
|
||||
val gcType = computeGCType(enforcedProperties)
|
||||
if (gcType != GCType.UNSPECIFIED) {
|
||||
assertEquals(MemoryModel.EXPERIMENTAL, memoryModel) {
|
||||
"GC type can be specified only with experimental memory model"
|
||||
}
|
||||
}
|
||||
|
||||
val gcScheduler = computeGCScheduler(enforcedProperties)
|
||||
if (gcScheduler != GCScheduler.UNSPECIFIED) {
|
||||
assertEquals(MemoryModel.EXPERIMENTAL, memoryModel) {
|
||||
"GC scheduler can be specified only with experimental memory model"
|
||||
}
|
||||
}
|
||||
|
||||
val nativeHome = getOrCreateTestProcessSettings().get<KotlinNativeHome>()
|
||||
|
||||
@@ -194,7 +180,6 @@ private object NativeTestSupport {
|
||||
}
|
||||
|
||||
output += optimizationMode
|
||||
output += memoryModel
|
||||
output += threadStateChecker
|
||||
output += gcType
|
||||
output += gcScheduler
|
||||
@@ -221,9 +206,6 @@ private object NativeTestSupport {
|
||||
default = OptimizationMode.DEBUG
|
||||
)
|
||||
|
||||
private fun computeMemoryModel(enforcedProperties: EnforcedProperties): MemoryModel =
|
||||
ClassLevelProperty.MEMORY_MODEL.readValue(enforcedProperties, MemoryModel.values(), default = MemoryModel.EXPERIMENTAL)
|
||||
|
||||
private fun computeThreadStateChecker(enforcedProperties: EnforcedProperties): ThreadStateChecker {
|
||||
val useThreadStateChecker =
|
||||
ClassLevelProperty.USE_THREAD_STATE_CHECKER.readValue(enforcedProperties, String::toBooleanStrictOrNull, default = false)
|
||||
|
||||
-5
@@ -68,7 +68,6 @@ internal class NativeTestGroupingMessageCollector(
|
||||
|| isUnsafeCompilerArgumentsWarning(message)
|
||||
|| isLibraryIncludedMoreThanOnceWarning(message)
|
||||
|| isK2Experimental(message)
|
||||
|| isLegacyMMWarning(message)
|
||||
|| isPartialLinkageWarning(message) -> {
|
||||
// These warnings are known and should not be reported as errors.
|
||||
severity
|
||||
@@ -110,9 +109,6 @@ internal class NativeTestGroupingMessageCollector(
|
||||
|
||||
private fun isK2Experimental(message: String): Boolean = message.startsWith(K2_NATIVE_EXPERIMENTAL_WARNING_PREFIX)
|
||||
|
||||
// Legacy MM is deprecated and will be removed in 1.9.20. Until that moment we still need to run tests with it.
|
||||
private fun isLegacyMMWarning(message: String): Boolean = message.startsWith(LEGACY_MM_WARNING_PREFIX)
|
||||
|
||||
private fun isPartialLinkageWarning(message: String): Boolean = message.matches(PARTIAL_LINKAGE_WARNING_REGEX)
|
||||
|
||||
override fun hasErrors() = hasWarningsWithRaisedSeverity || super.hasErrors()
|
||||
@@ -122,7 +118,6 @@ internal class NativeTestGroupingMessageCollector(
|
||||
private const val UNSAFE_COMPILER_ARGS_WARNING_PREFIX = "ATTENTION!\nThis build uses unsafe internal compiler arguments:\n\n"
|
||||
private const val LIBRARY_INCLUDED_MORE_THAN_ONCE_WARNING_PREFIX = "library included more than once: "
|
||||
private const val K2_NATIVE_EXPERIMENTAL_WARNING_PREFIX = "Language version 2.0 is experimental"
|
||||
private const val LEGACY_MM_WARNING_PREFIX = "Legacy MM is deprecated and will be removed"
|
||||
|
||||
private val PARTIAL_LINKAGE_WARNING_REGEX = Regex("^<[^<>]+>( @ (?:(?!: ).)+)?: .*")
|
||||
|
||||
|
||||
-5
@@ -128,7 +128,6 @@ internal abstract class SourceBasedCompilation<A : TestCompilationArtifact>(
|
||||
classLoader: KotlinNativeClassLoader,
|
||||
optimizationMode: OptimizationMode,
|
||||
compilerOutputInterceptor: CompilerOutputInterceptor,
|
||||
private val memoryModel: MemoryModel,
|
||||
private val threadStateChecker: ThreadStateChecker,
|
||||
private val sanitizer: Sanitizer,
|
||||
private val gcType: GCType,
|
||||
@@ -150,7 +149,6 @@ internal abstract class SourceBasedCompilation<A : TestCompilationArtifact>(
|
||||
) {
|
||||
override fun applySpecificArgs(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) {
|
||||
add("-repo", home.librariesDir.path)
|
||||
memoryModel.compilerFlags?.let { compilerFlags -> add(compilerFlags) }
|
||||
threadStateChecker.compilerFlag?.let { compilerFlag -> add(compilerFlag) }
|
||||
sanitizer.compilerFlag?.let { compilerFlag -> add(compilerFlag) }
|
||||
gcType.compilerFlag?.let { compilerFlag -> add(compilerFlag) }
|
||||
@@ -191,7 +189,6 @@ internal class LibraryCompilation(
|
||||
classLoader = settings.get(),
|
||||
optimizationMode = settings.get(),
|
||||
compilerOutputInterceptor = settings.get(),
|
||||
memoryModel = settings.get(),
|
||||
threadStateChecker = settings.get(),
|
||||
sanitizer = settings.get(),
|
||||
gcType = settings.get(),
|
||||
@@ -225,7 +222,6 @@ internal class ObjCFrameworkCompilation(
|
||||
classLoader = settings.get(),
|
||||
optimizationMode = settings.get(),
|
||||
compilerOutputInterceptor = settings.get(),
|
||||
memoryModel = settings.get(),
|
||||
threadStateChecker = settings.get(),
|
||||
sanitizer = settings.get(),
|
||||
gcType = settings.get(),
|
||||
@@ -310,7 +306,6 @@ internal class ExecutableCompilation(
|
||||
classLoader = settings.get(),
|
||||
optimizationMode = settings.get(),
|
||||
compilerOutputInterceptor = settings.get(),
|
||||
memoryModel = settings.get(),
|
||||
threadStateChecker = settings.get(),
|
||||
sanitizer = settings.get(),
|
||||
gcType = settings.get(),
|
||||
|
||||
-28
@@ -75,7 +75,6 @@ internal class ExtTestCaseGroupProvider : TestCaseGroupProvider, TestDisposable(
|
||||
customKlibs = settings.get(),
|
||||
pipelineType = settings.get(),
|
||||
timeouts = settings.get(),
|
||||
memoryModel = settings.get(),
|
||||
)
|
||||
|
||||
if (extTestDataFile.isRelevant)
|
||||
@@ -101,7 +100,6 @@ private class ExtTestDataFile(
|
||||
private val customKlibs: CustomKlibs,
|
||||
private val pipelineType: PipelineType,
|
||||
private val timeouts: Timeouts,
|
||||
private val memoryModel: MemoryModel
|
||||
) {
|
||||
private val structure by lazy {
|
||||
val allSourceTransformers: ExternalSourceTransformers = if (customSourceTransformers.isNullOrEmpty())
|
||||
@@ -141,7 +139,6 @@ private class ExtTestDataFile(
|
||||
val isRelevant: Boolean =
|
||||
isCompatibleTarget(TargetBackend.NATIVE, testDataFile) // Checks TARGET_BACKEND/DONT_TARGET_EXACT_BACKEND directives.
|
||||
&& !isIgnoredTarget(pipelineType, testDataFile, TargetBackend.NATIVE) // Checks IGNORE_BACKEND directives.
|
||||
&& (memoryModel != MemoryModel.LEGACY || !isIgnoredTarget(pipelineType, testDataFile, TargetBackend.NATIVE_WITH_LEGACY_MM)) // Checks IGNORE_BACKEND directives.
|
||||
&& testDataFileSettings.languageSettings.none { it in INCOMPATIBLE_LANGUAGE_SETTINGS }
|
||||
&& INCOMPATIBLE_DIRECTIVES.none { it in structure.directives }
|
||||
&& structure.directives[API_VERSION_DIRECTIVE] !in INCOMPATIBLE_API_VERSIONS
|
||||
@@ -180,10 +177,6 @@ private class ExtTestDataFile(
|
||||
fun createTestCase(settings: Settings, sharedModules: ThreadSafeCache<String, TestModule.Shared?>): TestCase {
|
||||
assertTrue(isRelevant)
|
||||
|
||||
if (settings.get<MemoryModel>() == MemoryModel.LEGACY) {
|
||||
makeObjectsMutable()
|
||||
}
|
||||
|
||||
val definitelyStandaloneTest = settings.get<ForcedStandaloneTestKind>().value
|
||||
val isStandaloneTest = definitelyStandaloneTest || determineIfStandaloneTest()
|
||||
patchPackageNames(isStandaloneTest)
|
||||
@@ -221,25 +214,6 @@ private class ExtTestDataFile(
|
||||
isStandaloneTest
|
||||
}
|
||||
|
||||
/** Annotate all objects and companion objects with [THREAD_LOCAL_ANNOTATION] to make them mutable. */
|
||||
private fun makeObjectsMutable() = with(structure) {
|
||||
filesToTransform.forEach { handler ->
|
||||
handler.accept(object : KtTreeVisitorVoid() {
|
||||
override fun visitObjectDeclaration(objectDeclaration: KtObjectDeclaration) {
|
||||
if (!objectDeclaration.isObjectLiteral()) {
|
||||
// FIXME: find only those that have vars inside
|
||||
addAnnotationEntry(
|
||||
objectDeclaration,
|
||||
handler.psiFactory.createAnnotationEntry(THREAD_LOCAL_ANNOTATION)
|
||||
).ensureSurroundedByWhiteSpace()
|
||||
}
|
||||
|
||||
super.visitObjectDeclaration(objectDeclaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For every Kotlin file (*.kt) stored in this text:
|
||||
*
|
||||
@@ -581,8 +555,6 @@ private class ExtTestDataFile(
|
||||
private fun Directives.multiValues(key: String, predicate: (String) -> Boolean = { true }): Set<String> =
|
||||
listValues(key)?.flatMap { it.split(' ') }?.filter(predicate)?.toSet().orEmpty()
|
||||
|
||||
private const val THREAD_LOCAL_ANNOTATION = "@kotlin.native.ThreadLocal"
|
||||
|
||||
private val BOX_FUNCTION_NAME = Name.identifier("box")
|
||||
private val OPT_IN_ANNOTATION_NAME = Name.identifier("OptIn")
|
||||
private val HELPERS_PACKAGE_NAME = Name.identifier("helpers")
|
||||
|
||||
+2
-15
@@ -117,20 +117,7 @@ internal enum class OptimizationMode(private val description: String, val compil
|
||||
}
|
||||
|
||||
/**
|
||||
* The Kotlin/Native memory model.
|
||||
*/
|
||||
internal enum class MemoryModel(val compilerFlags: List<String>?) {
|
||||
/**
|
||||
* but it should be done at some point.
|
||||
*/
|
||||
LEGACY(listOf("-memory-model", "strict")),
|
||||
EXPERIMENTAL(listOf("-memory-model", "experimental"));
|
||||
|
||||
override fun toString() = compilerFlags?.joinToString(prefix = "(", separator = " ", postfix = ")").orEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread state checked. Can be applied only with [MemoryModel.EXPERIMENTAL], [OptimizationMode.DEBUG], [CacheMode.WithoutCache].
|
||||
* Thread state checked. Can be applied only with [OptimizationMode.DEBUG], [CacheMode.WithoutCache].
|
||||
*/
|
||||
internal enum class ThreadStateChecker(val compilerFlag: String?) {
|
||||
DISABLED(null),
|
||||
@@ -150,7 +137,7 @@ internal enum class Sanitizer(val compilerFlag: String?) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collector type. Can be applied only with [MemoryModel.EXPERIMENTAL].
|
||||
* Garbage collector type.
|
||||
*/
|
||||
internal enum class GCType(val compilerFlag: String?) {
|
||||
UNSPECIFIED(null),
|
||||
|
||||
Reference in New Issue
Block a user