Freeze top-level val. (#1906)

This commit is contained in:
Nikolay Igotti
2018-08-22 14:30:42 +03:00
committed by GitHub
parent f0cfbb9918
commit a216bf8903
17 changed files with 107 additions and 39 deletions
@@ -173,7 +173,6 @@ object KotlinTypes {
val set by CollectionClassifier val set by CollectionClassifier
val map by CollectionClassifier val map by CollectionClassifier
val nativePtr by InteropType val nativePtr by InteropType
val cOpaque by InteropType val cOpaque by InteropType
@@ -198,7 +197,6 @@ object KotlinTypes {
val cFunction by InteropClassifier val cFunction by InteropClassifier
val objCObjectVar by InteropClassifier val objCObjectVar by InteropClassifier
val objCStringVarOf by InteropClassifier
val objCObjectBase by InteropClassifier val objCObjectBase by InteropClassifier
val objCObjectBaseMeta by InteropClassifier val objCObjectBaseMeta by InteropClassifier
@@ -220,6 +218,7 @@ object KotlinTypes {
private object InteropClassifier : ClassifierAtPackage("kotlinx.cinterop") private object InteropClassifier : ClassifierAtPackage("kotlinx.cinterop")
private object InteropType : TypeAtPackage("kotlinx.cinterop") private object InteropType : TypeAtPackage("kotlinx.cinterop")
} }
abstract class KotlinFile( abstract class KotlinFile(
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -367,6 +368,9 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val listOfInternal = internalFunction("listOfInternal") val listOfInternal = internalFunction("listOfInternal")
val threadLocal =
context.builtIns.builtInsModule.findClassAcrossModuleDependencies(ClassId.topLevel(FqName("kotlin.native.ThreadLocal")))!!
private fun internalFunction(name: String): IrSimpleFunctionSymbol = private fun internalFunction(name: String): IrSimpleFunctionSymbol =
symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single()) symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single())
@@ -307,7 +307,7 @@ internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String
assert (this.isExported()) assert (this.isExported())
assert (this.kind.isSingleton) assert (this.kind.isSingleton)
assert (!this.isUnit()) assert (!this.isUnit())
assert (this.symbol.objectIsShared) assert (this.objectIsShared)
return "kshadowobjref:$fqNameSafe" return "kshadowobjref:$fqNameSafe"
} }
@@ -77,7 +77,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun getObjectInstanceShadowStorage(descriptor: ClassDescriptor): LLVMValueRef { fun getObjectInstanceShadowStorage(descriptor: ClassDescriptor): LLVMValueRef {
assert (!descriptor.isUnit()) assert (!descriptor.isUnit())
assert (descriptor.symbol.objectIsShared) assert (descriptor.objectIsShared)
val llvmGlobal = if (!isExternal(descriptor)) { val llvmGlobal = if (!isExternal(descriptor)) {
context.llvmDeclarations.forSingleton(descriptor).instanceShadowFieldRef!! context.llvmDeclarations.forSingleton(descriptor).instanceShadowFieldRef!!
} else { } else {
@@ -300,6 +300,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
} }
fun freeze(value: LLVMValueRef, exceptionHandler: ExceptionHandler) {
if (isObjectRef(value))
call(context.llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler)
}
private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) { private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
call(context.llvm.updateReturnRefFunction, listOf(address, value)) call(context.llvm.updateReturnRefFunction, listOf(address, value))
} }
@@ -694,7 +699,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
} }
val shared = descriptor.symbol.objectIsShared && context.config.threadsAreAllowed val shared = descriptor.objectIsShared && context.config.threadsAreAllowed
val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared) val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared)
val bbCurrent = currentBlock val bbCurrent = currentBlock
val bbInit= basicBlock("label_init", locationInfo) val bbInit= basicBlock("label_init", locationInfo)
@@ -418,6 +418,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val appendToInitalizersTail = importRtFunction("AppendToInitializersTail") val appendToInitalizersTail = importRtFunction("AppendToInitializersTail")
val initRuntimeIfNeeded = importRtFunction("Kotlin_initRuntimeIfNeeded") val initRuntimeIfNeeded = importRtFunction("Kotlin_initRuntimeIfNeeded")
val mutationCheck = importRtFunction("MutationCheck") val mutationCheck = importRtFunction("MutationCheck")
val freezeSubgraph = importRtFunction("FreezeSubgraph")
val createKotlinObjCClass by lazy { importRtFunction("CreateKotlinObjCClass") } val createKotlinObjCClass by lazy { importRtFunction("CreateKotlinObjCClass") }
val getObjCKotlinTypeInfo by lazy { importRtFunction("GetObjCKotlinTypeInfo") } val getObjCKotlinTypeInfo by lazy { importRtFunction("GetObjCKotlinTypeInfo") }
@@ -50,9 +50,12 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
private val threadLocalAnnotationFqName = FqName("kotlin.native.ThreadLocal") private val threadLocalAnnotationFqName = FqName("kotlin.native.ThreadLocal")
val IrClassSymbol.objectIsShared get() = val IrClass.objectIsShared get() =
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) !descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName)
val IrField.isShared get() =
!descriptor.annotations.hasAnnotation(threadLocalAnnotationFqName) && !descriptor.isVar
internal fun emitLLVM(context: Context, phaser: PhaseManager) { internal fun emitLLVM(context: Context, phaser: PhaseManager) {
val irModule = context.irModule!! val irModule = context.irModule!!
@@ -373,14 +376,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
val INIT_GLOBALS = 0 val INIT_GLOBALS = 0
val DEINIT_THREAD_LOCAL_GLOBALS = 1 val INIT_THREAD_LOCAL_GLOBALS = 1
val DEINIT_GLOBALS = 2 val DEINIT_THREAD_LOCAL_GLOBALS = 2
val DEINIT_GLOBALS = 3
private fun createInitBody(): LLVMValueRef { private fun createInitBody(): LLVMValueRef {
val initFunction = LLVMAddFunction(context.llvmModule, "", kInitFuncType)!! val initFunction = LLVMAddFunction(context.llvmModule, "", kInitFuncType)!!
generateFunction(codegen, initFunction) { generateFunction(codegen, initFunction) {
using(FunctionScope(initFunction, "init_body", it)) { using(FunctionScope(initFunction, "init_body", it)) {
val bbInit = basicBlock("init", null) val bbInit = basicBlock("init", null)
val bbLocalInit = basicBlock("local_init", null)
val bbLocalDeinit = basicBlock("local_deinit", null) val bbLocalDeinit = basicBlock("local_deinit", null)
val bbGlobalDeinit = basicBlock("global_deinit", null) val bbGlobalDeinit = basicBlock("global_deinit", null)
val bbDefault = basicBlock("default", null) { val bbDefault = basicBlock("default", null) {
@@ -389,6 +394,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
switch(LLVMGetParam(initFunction, 0)!!, switch(LLVMGetParam(initFunction, 0)!!,
listOf(Int32(INIT_GLOBALS).llvm to bbInit, listOf(Int32(INIT_GLOBALS).llvm to bbInit,
Int32(INIT_THREAD_LOCAL_GLOBALS).llvm to bbLocalInit,
Int32(DEINIT_THREAD_LOCAL_GLOBALS).llvm to bbLocalDeinit, Int32(DEINIT_THREAD_LOCAL_GLOBALS).llvm to bbLocalDeinit,
Int32(DEINIT_GLOBALS).llvm to bbGlobalDeinit), Int32(DEINIT_GLOBALS).llvm to bbGlobalDeinit),
bbDefault) bbDefault)
@@ -398,9 +404,26 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.llvm.fileInitializers context.llvm.fileInitializers
.forEach { .forEach {
if (it.initializer?.expression !is IrConst<*>?) { if (it.initializer?.expression !is IrConst<*>?) {
val initialization = evaluateExpression(it.initializer!!.expression) if (it.isShared) {
val address = context.llvmDeclarations.forStaticField(it).storage val initialization = evaluateExpression(it.initializer!!.expression)
storeAny(initialization, address) val address = context.llvmDeclarations.forStaticField(it).storage
freeze(initialization, currentCodeContext.exceptionHandler)
storeAny(initialization, address)
}
}
}
ret(null)
}
appendingTo(bbLocalInit) {
context.llvm.fileInitializers
.forEach {
if (it.initializer?.expression !is IrConst<*>?) {
if (!it.isShared) {
val initialization = evaluateExpression(it.initializer!!.expression)
val address = context.llvmDeclarations.forStaticField(it).storage
storeAny(initialization, address)
}
} }
} }
ret(null) ret(null)
@@ -408,17 +431,25 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbLocalDeinit) { appendingTo(bbLocalDeinit) {
context.llvm.fileInitializers.forEach { context.llvm.fileInitializers.forEach {
val descriptor = it // Only if a subject for memory management.
if (!descriptor.type.binaryTypeIsReference()) if (it.type.binaryTypeIsReference() && !it.isShared) {
return@forEach // Is not a subject for memory management. val address = context.llvmDeclarations.forStaticField(it).storage
val address = context.llvmDeclarations.forStaticField(descriptor).storage storeAny(codegen.kNullObjHeaderPtr, address)
storeAny(codegen.kNullObjHeaderPtr, address) }
} }
context.llvm.objects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) } context.llvm.objects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
ret(null) ret(null)
} }
appendingTo(bbGlobalDeinit) { appendingTo(bbGlobalDeinit) {
context.llvm.fileInitializers
// Only if a subject for memory management.
.forEach {
if (it.type.binaryTypeIsReference() && it.isShared) {
val address = context.llvmDeclarations.forStaticField(it).storage
storeAny(codegen.kNullObjHeaderPtr, address)
}
}
context.llvm.sharedObjects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) } context.llvm.sharedObjects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
ret(null) ret(null)
} }
@@ -1426,8 +1457,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner)) functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner))
} else { } else {
assert (value.receiver == null) assert(value.receiver == null)
val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
if (value.symbol.owner.isShared)
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
functionGenerationContext.storeAny(valueToAssign, globalValue) functionGenerationContext.storeAny(valueToAssign, globalValue)
} }
@@ -330,7 +330,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} else { } else {
"kobjref:" + qualifyInternalName(descriptor) "kobjref:" + qualifyInternalName(descriptor)
} }
val threadLocal = !(descriptor.symbol.objectIsShared && context.config.threadsAreAllowed) val threadLocal = !(descriptor.objectIsShared && context.config.threadsAreAllowed)
val instanceFieldRef = addGlobal( val instanceFieldRef = addGlobal(
symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = threadLocal) symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = threadLocal)
@@ -390,7 +390,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val name = "kvar:" + qualifyInternalName(descriptor) val name = "kvar:" + qualifyInternalName(descriptor)
val storage = addGlobal( val storage = addGlobal(
name, getLLVMType(descriptor.type), isExported = false, threadLocal = true) name, getLLVMType(descriptor.type), isExported = false, threadLocal = !declaration.isShared)
this.staticFields[descriptor] = StaticFieldLlvmDeclarations(storage) this.staticFields[descriptor] = StaticFieldLlvmDeclarations(storage)
} }
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.backend.konan.llvm package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -121,7 +122,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
internal fun createImmutable(descriptor: ValueDescriptor, value: LLVMValueRef) : Int { internal fun createImmutable(descriptor: ValueDescriptor, value: LLVMValueRef) : Int {
if (contextVariablesToIndex.containsKey(descriptor)) if (contextVariablesToIndex.containsKey(descriptor))
throw Error("$descriptor is already defined") throw Error("${ir2string(descriptor)} is already defined")
val index = variables.size val index = variables.size
variables.add(ValueRecord(value, descriptor.name)) variables.add(ValueRecord(value, descriptor.name))
contextVariablesToIndex[descriptor] = index contextVariablesToIndex[descriptor] = index
@@ -69,7 +69,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
currentFile = irFile currentFile = irFile
irFile.transformChildrenVoid(this) irFile.transformChildrenVoid(this)
topLevelInitializers.forEach { irFile.addTopLevelInitializer(it) } topLevelInitializers.forEach { irFile.addTopLevelInitializer(it, context, false) }
topLevelInitializers.clear() topLevelInitializers.clear()
} }
@@ -565,8 +565,8 @@ internal class TestProcessor (val context: KonanBackendContext) {
irFile.addChild(ir) irFile.addChild(ir)
val irConstructor = ir.constructors.single() val irConstructor = ir.constructors.single()
irFile.addTopLevelInitializer( irFile.addTopLevelInitializer(
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irConstructor.returnType, irConstructor.symbol) IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irConstructor.returnType, irConstructor.symbol),
) context, threadLocal = true)
} }
/** Check if this fqName already used or not. */ /** Check if this fqName already used or not. */
@@ -587,6 +587,8 @@ internal class TestProcessor (val context: KonanBackendContext) {
return return
} }
// TODO: an awful hack, we make this initializer thread local, so that it doesn't freeze suite,
// and later on we could modify some suite's properties. This shall be redesigned.
irFile.addTopLevelInitializer(builder.irBlock { irFile.addTopLevelInitializer(builder.irBlock {
val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply { val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply {
putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
@@ -597,7 +599,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
symbols.topLevelSuiteRegisterTestCase, symbols.topLevelSuiteRegisterTestCase,
symbols.topLevelSuiteRegisterFunction, symbols.topLevelSuiteRegisterFunction,
functions) functions)
}) }, context, threadLocal = true)
} }
private fun createTestSuites(irFile: IrFile, annotationCollector: AnnotationCollector) { private fun createTestSuites(irFile: IrFile, annotationCollector: AnnotationCollector) {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.substitute import org.jetbrains.kotlin.backend.common.descriptors.substitute
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
@@ -27,7 +28,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -47,7 +50,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingStrategy import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
@@ -58,10 +60,14 @@ internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrC
private var topLevelInitializersCounter = 0 private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression) { internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
val fieldDescriptor = PropertyDescriptorImpl.create( val fieldDescriptor = PropertyDescriptorImpl.create(
this.packageFragmentDescriptor, this.packageFragmentDescriptor,
Annotations.EMPTY, if (threadLocal)
AnnotationsImpl(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
else
Annotations.EMPTY,
Modality.FINAL, Modality.FINAL,
Visibilities.PRIVATE, Visibilities.PRIVATE,
false, false,
@@ -76,7 +82,6 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression) {
false false
) )
val builtIns = fieldDescriptor.builtIns
fieldDescriptor.setType(expression.type.toKotlinType(), emptyList(), null, null as KotlinType?) fieldDescriptor.setType(expression.type.toKotlinType(), emptyList(), null, null as KotlinType?)
fieldDescriptor.initialize(null, null) fieldDescriptor.initialize(null, null)
@@ -123,8 +128,8 @@ private fun createFakeOverride(
is PropertyDescriptor -> is PropertyDescriptor ->
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor).apply { IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor).apply {
// TODO: add field if getter is missing? // TODO: add field if getter is missing?
getter = descriptor.getter?.createFunction() as IrSimpleFunction? getter = descriptor.getter?.createFunction()
setter = descriptor.setter?.createFunction() as IrSimpleFunction? setter = descriptor.setter?.createFunction()
} }
else -> TODO(descriptor.toString()) else -> TODO(descriptor.toString())
} }
@@ -238,7 +243,7 @@ fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) {
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap { fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
when (it) { when (it) {
is IrSimpleFunction -> listOf(it) is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter as IrSimpleFunction?, it.setter as IrSimpleFunction?) is IrProperty -> listOfNotNull(it.getter, it.setter)
else -> emptyList() else -> emptyList()
} }
} }
@@ -19,6 +19,7 @@ fun bar(b: B) {
foo(c) foo(c)
} }
@ThreadLocal
val global = B() val global = B()
@Test fun runTest() { @Test fun runTest() {
@@ -68,6 +68,7 @@ class Graph(val nodes: List<Node>, val roots: List<Node>)
fun min(x: Int, y: Int) = if (x < y) x else y fun min(x: Int, y: Int) = if (x < y) x else y
fun max(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) val random = Random(42)
fun generate(condensationSize: Int, branchingFactor: Int, swellingFactor: Int): Graph { fun generate(condensationSize: Int, branchingFactor: Int, swellingFactor: Int): Graph {
+2 -1
View File
@@ -1667,7 +1667,7 @@ void freezeCyclic(ContainerHeader* rootContainer, const KStdVector<ContainerHead
* Theory of operations. * Theory of operations.
* *
* Kotlin/Native supports object graph freezing, allowing to make certain subgraph immutable and thus * Kotlin/Native supports object graph freezing, allowing to make certain subgraph immutable and thus
* suitable for safe sharing amongs multiple concurrent executors. This operation recursively operates * suitable for safe sharing amongst multiple concurrent executors. This operation recursively operates
* on all objects reachable from the given object, and marks them as frozen. In frozen state object's * on all objects reachable from the given object, and marks them as frozen. In frozen state object's
* fields cannot be modified, and so, lifetime of frozen objects correlates. Practically, it means * fields cannot be modified, and so, lifetime of frozen objects correlates. Practically, it means
* that lifetimes of all strongly connected components are fully controlled by incoming reference * that lifetimes of all strongly connected components are fully controlled by incoming reference
@@ -1687,6 +1687,7 @@ void freezeCyclic(ContainerHeader* rootContainer, const KStdVector<ContainerHead
* references could be passed across multiple threads. * references could be passed across multiple threads.
*/ */
void FreezeSubgraph(ObjHeader* root) { void FreezeSubgraph(ObjHeader* root) {
if (root == nullptr) return;
// First check that passed object graph has no cycles. // First check that passed object graph has no cycles.
// If there are cycles - run graph condensation on cyclic graphs using Kosoraju-Sharir. // If there are cycles - run graph condensation on cyclic graphs using Kosoraju-Sharir.
ContainerHeader* rootContainer = root->container(); ContainerHeader* rootContainer = root->container();
+9 -5
View File
@@ -39,8 +39,9 @@ InitNode* initTailNode = nullptr;
enum { enum {
INIT_GLOBALS = 0, INIT_GLOBALS = 0,
DEINIT_THREAD_LOCAL_GLOBALS = 1, INIT_THREAD_LOCAL_GLOBALS = 1,
DEINIT_GLOBALS = 2 DEINIT_THREAD_LOCAL_GLOBALS = 2,
DEINIT_GLOBALS = 3
}; };
enum { enum {
@@ -78,10 +79,13 @@ RuntimeState* initRuntime() {
RuntimeState* result = konanConstructInstance<RuntimeState>(); RuntimeState* result = konanConstructInstance<RuntimeState>();
if (!result) return nullptr; if (!result) return nullptr;
result->memoryState = InitMemory(); result->memoryState = InitMemory();
bool firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1;
// Keep global variables in state as well. // Keep global variables in state as well.
InitOrDeinitGlobalVariables(INIT_GLOBALS); if (firstRuntime) {
konan::consoleInit(); konan::consoleInit();
atomicAdd(&aliveRuntimesCount, 1); InitOrDeinitGlobalVariables(INIT_GLOBALS);
}
InitOrDeinitGlobalVariables(INIT_THREAD_LOCAL_GLOBALS);
return result; return result;
} }
@@ -18,6 +18,7 @@ package kotlin.native.test
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ThreadLocal
private val _generatedSuites = mutableListOf<TestSuite>() private val _generatedSuites = mutableListOf<TestSuite>()
internal fun registerSuite(suite: TestSuite): Unit { internal fun registerSuite(suite: TestSuite): Unit {
@@ -173,9 +173,19 @@ class AtomicReference<T>(private var value: T? = null) {
external public fun get(): T? external public fun get(): T?
} }
internal object UNINITIALIZED internal object UNINITIALIZED {
// So that single-threaded configs can use those as well.
init {
freeze()
}
}
internal object INITIALIZING internal object INITIALIZING {
// So that single-threaded configs can use those as well.
init {
freeze()
}
}
@Frozen @Frozen
internal class AtomicLazyImpl<out T>(initializer: () -> T) : Lazy<T> { internal class AtomicLazyImpl<out T>(initializer: () -> T) : Lazy<T> {