Allow stateless and constant objects compile-time init . (#3645)
Allow stateless and constant objects compile-time init.
This commit is contained in:
+1
@@ -26,6 +26,7 @@ object KonanFqNames {
|
|||||||
val sharedImmutable = FqName("kotlin.native.concurrent.SharedImmutable")
|
val sharedImmutable = FqName("kotlin.native.concurrent.SharedImmutable")
|
||||||
val frozen = FqName("kotlin.native.internal.Frozen")
|
val frozen = FqName("kotlin.native.internal.Frozen")
|
||||||
val leakDetectorCandidate = FqName("kotlin.native.internal.LeakDetectorCandidate")
|
val leakDetectorCandidate = FqName("kotlin.native.internal.LeakDetectorCandidate")
|
||||||
|
val canBePrecreated = FqName("kotlin.native.internal.CanBePrecreated")
|
||||||
val typedIntrinsic = FqName("kotlin.native.internal.TypedIntrinsic")
|
val typedIntrinsic = FqName("kotlin.native.internal.TypedIntrinsic")
|
||||||
val objCMethod = FqName("kotlinx.cinterop.ObjCMethod")
|
val objCMethod = FqName("kotlinx.cinterop.ObjCMethod")
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -143,7 +143,6 @@ internal val IrClass.objectInstanceShadowFieldSymbolName: String
|
|||||||
assert (this.isExported())
|
assert (this.isExported())
|
||||||
assert (this.kind.isSingleton)
|
assert (this.kind.isSingleton)
|
||||||
assert (!this.isUnit())
|
assert (!this.isUnit())
|
||||||
assert (this.objectIsShared)
|
|
||||||
|
|
||||||
return "kshadowobjref:$fqNameForIrSerialization"
|
return "kshadowobjref:$fqNameForIrSerialization"
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-10
@@ -18,6 +18,28 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||||
import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin
|
import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||||
|
|
||||||
|
private fun IrConstructor.isAnyConstructorDelegation(context: Context): Boolean {
|
||||||
|
val statements = this.body?.statements ?: return false
|
||||||
|
if (statements.size != 2) return false
|
||||||
|
val lastStatement = statements[1]
|
||||||
|
if (lastStatement !is IrReturn ||
|
||||||
|
(lastStatement.value as? IrGetObjectValue)?.symbol != context.irBuiltIns.unitClass) return false
|
||||||
|
val constructorCall = statements[0] as? IrDelegatingConstructorCall ?: return false
|
||||||
|
val constructor = constructorCall.symbol.owner as? IrConstructor ?: return false
|
||||||
|
return constructor.constructedClass.isAny()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: shall we memoize that property?
|
||||||
|
internal fun IrClass.hasConstStateAndNoSideEffects(context: Context): Boolean {
|
||||||
|
if (!context.shouldOptimize()) return false
|
||||||
|
if (this.hasAnnotation(KonanFqNames.canBePrecreated)) return true
|
||||||
|
val fields = context.getLayoutBuilder(this).fields
|
||||||
|
return fields.isEmpty() && this.constructors.all { it.isAnyConstructorDelegation(context) }
|
||||||
|
}
|
||||||
|
|
||||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||||
|
|
||||||
@@ -42,7 +64,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
fun functionEntryPointAddress(function: IrFunction) = function.entryPointAddress.llvm
|
fun functionEntryPointAddress(function: IrFunction) = function.entryPointAddress.llvm
|
||||||
fun functionHash(function: IrFunction): LLVMValueRef = function.functionName.localHash.llvm
|
fun functionHash(function: IrFunction): LLVMValueRef = function.functionName.localHash.llvm
|
||||||
|
|
||||||
fun getObjectInstanceStorage(irClass: IrClass, shared: Boolean): LLVMValueRef {
|
fun getObjectInstanceStorage(irClass: IrClass, kind: ObjectStorageKind): LLVMValueRef {
|
||||||
assert (!irClass.isUnit())
|
assert (!irClass.isUnit())
|
||||||
val llvmGlobal = if (!isExternal(irClass)) {
|
val llvmGlobal = if (!isExternal(irClass)) {
|
||||||
context.llvmDeclarations.forSingleton(irClass).instanceFieldRef
|
context.llvmDeclarations.forSingleton(irClass).instanceFieldRef
|
||||||
@@ -52,19 +74,21 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
irClass.objectInstanceFieldSymbolName,
|
irClass.objectInstanceFieldSymbolName,
|
||||||
llvmType,
|
llvmType,
|
||||||
origin = irClass.llvmSymbolOrigin,
|
origin = irClass.llvmSymbolOrigin,
|
||||||
threadLocal = !shared
|
threadLocal = kind == ObjectStorageKind.THREAD_LOCAL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (shared)
|
when (kind) {
|
||||||
context.llvm.sharedObjects += llvmGlobal
|
ObjectStorageKind.SHARED -> context.llvm.sharedObjects += llvmGlobal
|
||||||
else
|
ObjectStorageKind.THREAD_LOCAL -> context.llvm.objects += llvmGlobal
|
||||||
context.llvm.objects += llvmGlobal
|
ObjectStorageKind.PERMANENT -> { /* Do nothing, no need to free such an instance. */ }
|
||||||
|
}
|
||||||
|
|
||||||
return llvmGlobal
|
return llvmGlobal
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getObjectInstanceShadowStorage(irClass: IrClass): LLVMValueRef {
|
fun getObjectInstanceShadowStorage(irClass: IrClass): LLVMValueRef {
|
||||||
assert (!irClass.isUnit())
|
assert (!irClass.isUnit())
|
||||||
assert (irClass.objectIsShared)
|
assert (irClass.storageKind(context) == ObjectStorageKind.SHARED)
|
||||||
val llvmGlobal = if (!isExternal(irClass)) {
|
val llvmGlobal = if (!isExternal(irClass)) {
|
||||||
context.llvmDeclarations.forSingleton(irClass).instanceShadowFieldRef!!
|
context.llvmDeclarations.forSingleton(irClass).instanceShadowFieldRef!!
|
||||||
} else {
|
} else {
|
||||||
@@ -893,6 +917,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
startLocationInfo: LocationInfo?,
|
startLocationInfo: LocationInfo?,
|
||||||
endLocationInfo: LocationInfo? = null
|
endLocationInfo: LocationInfo? = null
|
||||||
): LLVMValueRef {
|
): LLVMValueRef {
|
||||||
|
// TODO: could be processed the same way as other stateless objects.
|
||||||
if (irClass.isUnit()) {
|
if (irClass.isUnit()) {
|
||||||
return codegen.theUnitInstanceRef.llvm
|
return codegen.theUnitInstanceRef.llvm
|
||||||
}
|
}
|
||||||
@@ -910,9 +935,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val storageKind = irClass.storageKind(context)
|
||||||
|
if (storageKind == ObjectStorageKind.PERMANENT) {
|
||||||
|
return loadSlot(codegen.getObjectInstanceStorage(irClass, storageKind), false)
|
||||||
|
}
|
||||||
|
|
||||||
val shared = irClass.objectIsShared && context.config.threadsAreAllowed
|
val objectPtr = codegen.getObjectInstanceStorage(irClass, storageKind)
|
||||||
val objectPtr = codegen.getObjectInstanceStorage(irClass, shared)
|
|
||||||
val bbInit = basicBlock("label_init", startLocationInfo, endLocationInfo)
|
val bbInit = basicBlock("label_init", startLocationInfo, endLocationInfo)
|
||||||
val bbExit = basicBlock("label_continue", startLocationInfo, endLocationInfo)
|
val bbExit = basicBlock("label_continue", startLocationInfo, endLocationInfo)
|
||||||
val objectVal = loadSlot(objectPtr, false)
|
val objectVal = loadSlot(objectPtr, false)
|
||||||
@@ -925,7 +953,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
val defaultConstructor = irClass.constructors.single { it.valueParameters.size == 0 }
|
val defaultConstructor = irClass.constructors.single { it.valueParameters.size == 0 }
|
||||||
val ctor = codegen.llvmFunction(defaultConstructor)
|
val ctor = codegen.llvmFunction(defaultConstructor)
|
||||||
val (initFunction, args) =
|
val (initFunction, args) =
|
||||||
if (shared) {
|
if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) {
|
||||||
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(irClass)
|
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(irClass)
|
||||||
context.llvm.initSharedInstanceFunction to listOf(objectPtr, shadowObjectPtr, typeInfo, ctor)
|
context.llvm.initSharedInstanceFunction to listOf(objectPtr, shadowObjectPtr, typeInfo, ctor)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+41
-19
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
|
|||||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation
|
import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation
|
||||||
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
|
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
@@ -33,33 +32,43 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
internal enum class FieldStorage {
|
internal enum class FieldStorageKind {
|
||||||
MAIN_THREAD,
|
MAIN_THREAD,
|
||||||
SHARED,
|
SHARED,
|
||||||
THREAD_LOCAL
|
THREAD_LOCAL
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe unannotated singleton objects shall be accessed from main thread only as well?
|
internal enum class ObjectStorageKind {
|
||||||
val IrClass.objectIsShared get() =
|
PERMANENT,
|
||||||
!annotations.hasAnnotation(KonanFqNames.threadLocal)
|
THREAD_LOCAL,
|
||||||
|
SHARED
|
||||||
|
}
|
||||||
|
|
||||||
internal val IrField.storageClass: FieldStorage get() {
|
// TODO: maybe unannotated singleton objects shall be accessed from main thread only as well?
|
||||||
|
internal val IrField.storageKind: FieldStorageKind get() {
|
||||||
// TODO: Is this correct?
|
// TODO: Is this correct?
|
||||||
val annotations = correspondingPropertySymbol?.owner?.annotations ?: annotations
|
val annotations = correspondingPropertySymbol?.owner?.annotations ?: annotations
|
||||||
return when {
|
return when {
|
||||||
annotations.hasAnnotation(KonanFqNames.threadLocal) -> FieldStorage.THREAD_LOCAL
|
annotations.hasAnnotation(KonanFqNames.threadLocal) -> FieldStorageKind.THREAD_LOCAL
|
||||||
!isFinal -> FieldStorage.MAIN_THREAD
|
!isFinal -> FieldStorageKind.MAIN_THREAD
|
||||||
annotations.hasAnnotation(KonanFqNames.sharedImmutable) -> FieldStorage.SHARED
|
annotations.hasAnnotation(KonanFqNames.sharedImmutable) -> FieldStorageKind.SHARED
|
||||||
// TODO: simplify, once IR types are fully there.
|
// TODO: simplify, once IR types are fully there.
|
||||||
(type.classifierOrNull?.owner as? IrAnnotationContainer)
|
(type.classifierOrNull?.owner as? IrAnnotationContainer)
|
||||||
?.annotations?.hasAnnotation(KonanFqNames.frozen) == true -> FieldStorage.SHARED
|
?.annotations?.hasAnnotation(KonanFqNames.frozen) == true -> FieldStorageKind.SHARED
|
||||||
else -> FieldStorage.MAIN_THREAD
|
else -> FieldStorageKind.MAIN_THREAD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun IrClass.storageKind(context: Context): ObjectStorageKind = when {
|
||||||
|
this.annotations.hasAnnotation(KonanFqNames.threadLocal) &&
|
||||||
|
context.config.threadsAreAllowed -> ObjectStorageKind.THREAD_LOCAL
|
||||||
|
this.hasConstStateAndNoSideEffects(context) -> ObjectStorageKind.PERMANENT
|
||||||
|
else -> ObjectStorageKind.SHARED
|
||||||
|
}
|
||||||
|
|
||||||
val IrField.isMainOnlyNonPrimitive get() = when {
|
val IrField.isMainOnlyNonPrimitive get() = when {
|
||||||
descriptor.type.computePrimitiveBinaryTypeOrNull() != null -> false
|
descriptor.type.computePrimitiveBinaryTypeOrNull() != null -> false
|
||||||
else -> storageClass == FieldStorage.MAIN_THREAD
|
else -> storageKind == FieldStorageKind.MAIN_THREAD
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") {
|
internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") {
|
||||||
@@ -384,10 +393,10 @@ 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<*>?) {
|
||||||
if (it.storageClass != FieldStorage.THREAD_LOCAL) {
|
if (it.storageKind != FieldStorageKind.THREAD_LOCAL) {
|
||||||
val initialization = evaluateExpression(it.initializer!!.expression)
|
val initialization = evaluateExpression(it.initializer!!.expression)
|
||||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||||
if (it.storageClass == FieldStorage.SHARED)
|
if (it.storageKind == FieldStorageKind.SHARED)
|
||||||
freeze(initialization, currentCodeContext.exceptionHandler)
|
freeze(initialization, currentCodeContext.exceptionHandler)
|
||||||
storeAny(initialization, address, false)
|
storeAny(initialization, address, false)
|
||||||
}
|
}
|
||||||
@@ -400,7 +409,7 @@ 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<*>?) {
|
||||||
if (it.storageClass == FieldStorage.THREAD_LOCAL) {
|
if (it.storageKind == FieldStorageKind.THREAD_LOCAL) {
|
||||||
val initialization = evaluateExpression(it.initializer!!.expression)
|
val initialization = evaluateExpression(it.initializer!!.expression)
|
||||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||||
storeAny(initialization, address, false)
|
storeAny(initialization, address, false)
|
||||||
@@ -413,7 +422,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
appendingTo(bbLocalDeinit) {
|
appendingTo(bbLocalDeinit) {
|
||||||
context.llvm.fileInitializers.forEach {
|
context.llvm.fileInitializers.forEach {
|
||||||
// Only if a subject for memory management.
|
// Only if a subject for memory management.
|
||||||
if (it.type.binaryTypeIsReference() && it.storageClass == FieldStorage.THREAD_LOCAL) {
|
if (it.type.binaryTypeIsReference() && it.storageKind == FieldStorageKind.THREAD_LOCAL) {
|
||||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||||
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
||||||
}
|
}
|
||||||
@@ -426,7 +435,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
context.llvm.fileInitializers
|
context.llvm.fileInitializers
|
||||||
// Only if a subject for memory management.
|
// Only if a subject for memory management.
|
||||||
.forEach {
|
.forEach {
|
||||||
if (it.type.binaryTypeIsReference() && it.storageClass != FieldStorage.THREAD_LOCAL) {
|
if (it.type.binaryTypeIsReference() && it.storageKind != FieldStorageKind.THREAD_LOCAL) {
|
||||||
val address = context.llvmDeclarations.forStaticField(it).storage
|
val address = context.llvmDeclarations.forStaticField(it).storage
|
||||||
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
||||||
}
|
}
|
||||||
@@ -738,9 +747,22 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
it.acceptVoid(this)
|
it.acceptVoid(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (declaration.kind.isSingleton && !declaration.isUnit()) {
|
||||||
|
val value = context.llvmDeclarations.forSingleton(declaration).instanceFieldRef
|
||||||
|
LLVMSetInitializer(value, if (declaration.storageKind(context) == ObjectStorageKind.PERMANENT)
|
||||||
|
context.llvm.staticData.createConstKotlinObject(declaration,
|
||||||
|
*computeFields(declaration)).llvm else codegen.kNullObjHeaderPtr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
private fun computeFields(declaration: IrClass): Array<ConstValue> {
|
||||||
|
val fields = context.getLayoutBuilder(declaration).fields
|
||||||
|
return Array(fields.size) { index ->
|
||||||
|
val initializer = fields[index].initializer!!.expression as IrConst<*>
|
||||||
|
constValue(evaluateConst(initializer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitProperty(declaration: IrProperty) {
|
override fun visitProperty(declaration: IrProperty) {
|
||||||
declaration.getter?.acceptVoid(this)
|
declaration.getter?.acceptVoid(this)
|
||||||
@@ -1527,7 +1549,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
|
val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
|
||||||
if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive)
|
if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive)
|
||||||
functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler)
|
functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler)
|
||||||
if (value.symbol.owner.storageClass == FieldStorage.SHARED)
|
if (value.symbol.owner.storageKind == FieldStorageKind.SHARED)
|
||||||
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
|
functionGenerationContext.freeze(valueToAssign, currentCodeContext.exceptionHandler)
|
||||||
functionGenerationContext.storeAny(valueToAssign, globalValue, false)
|
functionGenerationContext.storeAny(valueToAssign, globalValue, false)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -273,12 +273,10 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
} else {
|
} else {
|
||||||
"kobjref:" + qualifyInternalName(irClass)
|
"kobjref:" + qualifyInternalName(irClass)
|
||||||
}
|
}
|
||||||
val threadLocal = !(irClass.objectIsShared && context.config.threadsAreAllowed)
|
val threadLocal = irClass.storageKind(context) == ObjectStorageKind.THREAD_LOCAL
|
||||||
val instanceFieldRef = addGlobal(
|
val instanceFieldRef = addGlobal(
|
||||||
symbolName, getLLVMType(irClass.defaultType), isExported = isExported, threadLocal = threadLocal)
|
symbolName, getLLVMType(irClass.defaultType), isExported = isExported, threadLocal = threadLocal)
|
||||||
|
|
||||||
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
|
|
||||||
|
|
||||||
val instanceShadowFieldRef =
|
val instanceShadowFieldRef =
|
||||||
if (threadLocal) null
|
if (threadLocal) null
|
||||||
else {
|
else {
|
||||||
@@ -329,7 +327,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
val name = "kvar:" + qualifyInternalName(declaration)
|
val name = "kvar:" + qualifyInternalName(declaration)
|
||||||
val storage = addGlobal(
|
val storage = addGlobal(
|
||||||
name, getLLVMType(declaration.type), isExported = false,
|
name, getLLVMType(declaration.type), isExported = false,
|
||||||
threadLocal = declaration.storageClass == FieldStorage.THREAD_LOCAL)
|
threadLocal = declaration.storageKind == FieldStorageKind.THREAD_LOCAL)
|
||||||
|
|
||||||
this.staticFields[declaration] = StaticFieldLlvmDeclarations(storage)
|
this.staticFields[declaration] = StaticFieldLlvmDeclarations(storage)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.ir.expressions.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||||
|
import org.jetbrains.kotlin.ir.types.isString
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
@@ -64,6 +66,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
|
|||||||
val initializer = declaration.initializer ?: return declaration
|
val initializer = declaration.initializer ?: return declaration
|
||||||
val startOffset = initializer.startOffset
|
val startOffset = initializer.startOffset
|
||||||
val endOffset = initializer.endOffset
|
val endOffset = initializer.endOffset
|
||||||
|
val initExpression = initializer.expression
|
||||||
initializers.add(IrBlockImpl(startOffset, endOffset,
|
initializers.add(IrBlockImpl(startOffset, endOffset,
|
||||||
context.irBuiltIns.unitType,
|
context.irBuiltIns.unitType,
|
||||||
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
|
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
|
||||||
@@ -73,11 +76,19 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
|
|||||||
startOffset, endOffset,
|
startOffset, endOffset,
|
||||||
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
|
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
|
||||||
),
|
),
|
||||||
initializer.expression,
|
initExpression,
|
||||||
context.irBuiltIns.unitType,
|
context.irBuiltIns.unitType,
|
||||||
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))
|
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))
|
||||||
)
|
)
|
||||||
declaration.initializer = null
|
|
||||||
|
// We shall keep initializer for constants for compile-time instantiation.
|
||||||
|
declaration.initializer =
|
||||||
|
if (initExpression is IrConst<*> &&
|
||||||
|
(initExpression.type.isPrimitiveType() || initExpression.type.isString())) {
|
||||||
|
IrExpressionBodyImpl(initExpression.copy())
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
return declaration
|
return declaration
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+8
-7
@@ -225,14 +225,15 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitField(declaration: IrField) {
|
override fun visitField(declaration: IrField) {
|
||||||
declaration.initializer?.let {
|
if (declaration.parent is IrFile)
|
||||||
DEBUG_OUTPUT(0) {
|
declaration.initializer?.let {
|
||||||
println("Analysing global field ${declaration.descriptor}")
|
DEBUG_OUTPUT(0) {
|
||||||
println("IR: ${ir2stringWhole(declaration)}")
|
println("Analysing global field ${declaration.descriptor}")
|
||||||
|
println("IR: ${ir2stringWhole(declaration)}")
|
||||||
|
}
|
||||||
|
analyze(declaration, IrSetFieldImpl(it.startOffset, it.endOffset, declaration.symbol, null,
|
||||||
|
it.expression, context.irBuiltIns.unitType))
|
||||||
}
|
}
|
||||||
analyze(declaration, IrSetFieldImpl(it.startOffset, it.endOffset, declaration.symbol, null,
|
|
||||||
it.expression, context.irBuiltIns.unitType))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyze(declaration: IrDeclaration, body: IrElement?) {
|
private fun analyze(declaration: IrDeclaration, body: IrElement?) {
|
||||||
|
|||||||
+5
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.optimizations
|
package org.jetbrains.kotlin.backend.konan.optimizations
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
|
||||||
import org.jetbrains.kotlin.backend.konan.*
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.target
|
import org.jetbrains.kotlin.backend.konan.descriptors.target
|
||||||
@@ -487,7 +488,10 @@ internal object DataFlowIR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitField(declaration: IrField) {
|
override fun visitField(declaration: IrField) {
|
||||||
declaration.initializer?.let { mapFunction(declaration) }
|
if (declaration.parent is IrFile)
|
||||||
|
declaration.initializer?.let {
|
||||||
|
mapFunction(declaration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ fun foo(x: Any, y: Any) {
|
|||||||
y.use()
|
y.use()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun runTest() {
|
@Test fun runTest1() {
|
||||||
var x = Integer(0)
|
var x = Integer(0)
|
||||||
|
|
||||||
for (i in 0..1) {
|
for (i in 0..1) {
|
||||||
@@ -31,4 +31,32 @@ fun foo(x: Any, y: Any) {
|
|||||||
|
|
||||||
fun Any?.use() {
|
fun Any?.use() {
|
||||||
var x = this
|
var x = this
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.native.internal.CanBePrecreated
|
||||||
|
object CompileTime {
|
||||||
|
|
||||||
|
const val int = Int.MIN_VALUE
|
||||||
|
const val byte = Byte.MIN_VALUE
|
||||||
|
const val short = Short.MIN_VALUE
|
||||||
|
const val long = Long.MIN_VALUE
|
||||||
|
const val boolean = true
|
||||||
|
const val float = 1.0f
|
||||||
|
const val double = 1.0
|
||||||
|
const val char = Char.MIN_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
class AClass {
|
||||||
|
companion object {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun runTest2() {
|
||||||
|
assertEquals(Int.MIN_VALUE, CompileTime.int)
|
||||||
|
assertEquals(Byte.MIN_VALUE, CompileTime.byte)
|
||||||
|
assertEquals(Short.MIN_VALUE, CompileTime.short)
|
||||||
|
assertEquals(Long.MIN_VALUE, CompileTime.long)
|
||||||
|
assertEquals(true, CompileTime.boolean)
|
||||||
|
assertEquals(1.0f, CompileTime.float)
|
||||||
|
assertEquals(1.0, CompileTime.double)
|
||||||
|
assertEquals(Char.MIN_VALUE, CompileTime.char)
|
||||||
}
|
}
|
||||||
@@ -65,6 +65,7 @@ public class Char private constructor() : Comparable<Char> {
|
|||||||
@TypedIntrinsic(IntrinsicType.UNSIGNED_TO_FLOAT)
|
@TypedIntrinsic(IntrinsicType.UNSIGNED_TO_FLOAT)
|
||||||
external public fun toDouble(): Double
|
external public fun toDouble(): Double
|
||||||
|
|
||||||
|
@kotlin.native.internal.CanBePrecreated
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* The minimum value of a character code unit.
|
* The minimum value of a character code unit.
|
||||||
|
|||||||
@@ -7,15 +7,16 @@
|
|||||||
|
|
||||||
package kotlin
|
package kotlin
|
||||||
|
|
||||||
|
import kotlin.native.internal.CanBePrecreated
|
||||||
|
import kotlin.native.internal.IntrinsicType
|
||||||
import kotlin.native.internal.NumberConverter
|
import kotlin.native.internal.NumberConverter
|
||||||
import kotlin.native.internal.TypedIntrinsic
|
import kotlin.native.internal.TypedIntrinsic
|
||||||
import kotlin.native.internal.IntrinsicType
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a 8-bit signed integer.
|
* Represents a 8-bit signed integer.
|
||||||
*/
|
*/
|
||||||
public final class Byte private constructor() : Number(), Comparable<Byte> {
|
public final class Byte private constructor() : Number(), Comparable<Byte> {
|
||||||
|
@CanBePrecreated
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* A constant holding the minimum value an instance of Byte can have.
|
* A constant holding the minimum value an instance of Byte can have.
|
||||||
@@ -284,6 +285,7 @@ public final class Byte private constructor() : Number(), Comparable<Byte> {
|
|||||||
* Represents a 16-bit signed integer.
|
* Represents a 16-bit signed integer.
|
||||||
*/
|
*/
|
||||||
public final class Short private constructor() : Number(), Comparable<Short> {
|
public final class Short private constructor() : Number(), Comparable<Short> {
|
||||||
|
@CanBePrecreated
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* A constant holding the minimum value an instance of Short can have.
|
* A constant holding the minimum value an instance of Short can have.
|
||||||
@@ -551,6 +553,7 @@ public final class Short private constructor() : Number(), Comparable<Short> {
|
|||||||
* Represents a 32-bit signed integer.
|
* Represents a 32-bit signed integer.
|
||||||
*/
|
*/
|
||||||
public final class Int private constructor() : Number(), Comparable<Int> {
|
public final class Int private constructor() : Number(), Comparable<Int> {
|
||||||
|
@CanBePrecreated
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* A constant holding the minimum value an instance of Int can have.
|
* A constant holding the minimum value an instance of Int can have.
|
||||||
@@ -844,6 +847,7 @@ public final class Int private constructor() : Number(), Comparable<Int> {
|
|||||||
* Represents a 64-bit signed integer.
|
* Represents a 64-bit signed integer.
|
||||||
*/
|
*/
|
||||||
public final class Long private constructor() : Number(), Comparable<Long> {
|
public final class Long private constructor() : Number(), Comparable<Long> {
|
||||||
|
@CanBePrecreated
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* A constant holding the minimum value an instance of Long can have.
|
* A constant holding the minimum value an instance of Long can have.
|
||||||
|
|||||||
@@ -505,8 +505,9 @@ actual class HashMap<K, V> private constructor(
|
|||||||
internal fun valuesIterator() = ValuesItr(this)
|
internal fun valuesIterator() = ValuesItr(this)
|
||||||
internal fun entriesIterator() = EntriesItr(this)
|
internal fun entriesIterator() = EntriesItr(this)
|
||||||
|
|
||||||
|
@kotlin.native.internal.CanBePrecreated
|
||||||
private companion object {
|
private companion object {
|
||||||
const val MAGIC = 2654435769L.toInt() // golden ratio
|
const val MAGIC = -1640531527 // 2654435769L.toInt(), golden ratio
|
||||||
const val INITIAL_CAPACITY = 8
|
const val INITIAL_CAPACITY = 8
|
||||||
const val INITIAL_MAX_PROBE_DISTANCE = 2
|
const val INITIAL_MAX_PROBE_DISTANCE = 2
|
||||||
const val TOMBSTONE = -1
|
const val TOMBSTONE = -1
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ package kotlin.native
|
|||||||
*/
|
*/
|
||||||
public class BitSet(size: Int = ELEMENT_SIZE) {
|
public class BitSet(size: Int = ELEMENT_SIZE) {
|
||||||
|
|
||||||
|
@kotlin.native.internal.CanBePrecreated
|
||||||
companion object {
|
companion object {
|
||||||
// Default size of one element in the array used to store bits.
|
// Default size of one element in the array used to store bits.
|
||||||
private const val ELEMENT_SIZE = 64
|
private const val ELEMENT_SIZE = 64
|
||||||
|
|||||||
@@ -121,4 +121,13 @@ annotation class Independent
|
|||||||
* Marks a class whose instances to be added to the list of leak detector candidates.
|
* Marks a class whose instances to be added to the list of leak detector candidates.
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@PublishedApi internal annotation class LeakDetectorCandidate
|
@PublishedApi internal annotation class LeakDetectorCandidate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that given top level signleton object can be created in compile time and thus
|
||||||
|
* members access doesn't need to use an init barrier and allow better optimizations for
|
||||||
|
* field access, such as constant folding.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
|
public annotation class CanBePrecreated
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ external fun getNativeNullPtr(): NativePtr
|
|||||||
|
|
||||||
class NativePtr @PublishedApi internal constructor(private val value: NonNullNativePtr?) {
|
class NativePtr @PublishedApi internal constructor(private val value: NonNullNativePtr?) {
|
||||||
companion object {
|
companion object {
|
||||||
|
// TODO: make it properly precreated, maybe use an intrinsic for that.
|
||||||
val NULL = getNativeNullPtr()
|
val NULL = getNativeNullPtr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user