[K/N] Call class static initializer in constructors
^KT-59058
This commit is contained in:
committed by
Space Team
parent
c40bf720d9
commit
12455451fc
@@ -1,7 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// KT-59058
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
var global = "A"
|
||||
|
||||
class C {
|
||||
|
||||
Vendored
-2
@@ -1,7 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: NESTED_OBJECT_INIT
|
||||
// KT-59058
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
|
||||
+15
-14
@@ -19,10 +19,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.hasNonConstInitializer
|
||||
import org.jetbrains.kotlin.ir.util.simpleFunctions
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -96,18 +93,22 @@ internal class StaticInitializersLowering(val context: Context) : FileLoweringPa
|
||||
)
|
||||
else null
|
||||
|
||||
fun IrFunction.addInitializersCall() {
|
||||
val body = body ?: return
|
||||
val statements = (body as IrBlockBody).statements
|
||||
context.createIrBuilder(symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).run {
|
||||
// The order of calling initializers: first global, then thread-local.
|
||||
// It is ok for a thread local top level property to reference a global, but not vice versa.
|
||||
threadLocalInitFunction?.let { statements.add(0, irCallFileInitializer(it.symbol)) }
|
||||
globalInitFunction?.let { statements.add(0, irCallFileInitializer(it.symbol)) }
|
||||
}
|
||||
}
|
||||
|
||||
container.simpleFunctions()
|
||||
.filter { it.dispatchReceiverParameter == null }
|
||||
.filterNot { it.origin == DECLARATION_ORIGIN_ENTRY_POINT }
|
||||
.forEach {
|
||||
val body = it.body ?: return@forEach
|
||||
val statements = (body as IrBlockBody).statements
|
||||
context.createIrBuilder(it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).run {
|
||||
// The order of calling initializers: first global, then thread-local.
|
||||
// It is ok for a thread local top level property to reference a global, but not vice versa.
|
||||
threadLocalInitFunction?.let { statements.add(0, irCallFileInitializer(it.symbol)) }
|
||||
globalInitFunction?.let { statements.add(0, irCallFileInitializer(it.symbol)) }
|
||||
}
|
||||
}
|
||||
.forEach { it.addInitializersCall() }
|
||||
(container as? IrClass)?.constructors?.forEach { it.addInitializersCall() }
|
||||
}
|
||||
|
||||
private fun buildInitFileFunction(container: IrDeclarationContainer, name: String, origin: IrDeclarationOrigin) = context.irFactory.buildFun {
|
||||
|
||||
+19
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.backend.konan.DirectedGraphCondensationBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.DirectedGraphMultiNode
|
||||
import org.jetbrains.kotlin.backend.konan.ir.actualCallee
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isVirtualCall
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.IntrinsicType
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.tryGetIntrinsicType
|
||||
import org.jetbrains.kotlin.backend.konan.logMultiple
|
||||
import org.jetbrains.kotlin.backend.konan.lower.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -542,6 +544,23 @@ internal object StaticInitializersOptimization {
|
||||
expression.transformChildren(this, data)
|
||||
|
||||
val callee = expression.actualCallee
|
||||
/*
|
||||
* There can be construction like `initInstance(constructorCall())` in IR
|
||||
* Which can be transformed to `initInstance({ callClassStaticInits(); conctructorCall() })`
|
||||
* which is not valid for code-gen, as it expects the intrinsic argument to be a constructor call.
|
||||
*
|
||||
* So we here fix it by postporcessing to `{ callClassStaticInitis(); initInstance(constructorCall()) }`
|
||||
*/
|
||||
if (tryGetIntrinsicType(expression) == IntrinsicType.INIT_INSTANCE) {
|
||||
val constructorArg = expression.getValueArgument(1)
|
||||
if (constructorArg is IrBlock) {
|
||||
val realConstructorArg = constructorArg.statements.last() as IrConstructorCall
|
||||
constructorArg.statements[constructorArg.statements.lastIndex] = expression.apply {
|
||||
putValueArgument(1, realConstructorArg)
|
||||
}
|
||||
return constructorArg
|
||||
}
|
||||
}
|
||||
val body = callee.body ?: return expression
|
||||
val initializerCalls = (body as IrBlockBody).statements
|
||||
.take(2) // The very first statements by construction.
|
||||
|
||||
+10
-8
@@ -18,14 +18,6 @@ fun getStackTrace() : List<String> {
|
||||
|
||||
open class Foo {
|
||||
open fun foo(): List<String> { return emptyList() }
|
||||
|
||||
companion object {
|
||||
var trace: List<String> = emptyList()
|
||||
|
||||
init {
|
||||
trace = getStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Bar : Foo() {
|
||||
@@ -40,6 +32,16 @@ object Object {
|
||||
}
|
||||
}
|
||||
|
||||
class WithCompanion {
|
||||
companion object {
|
||||
var trace: List<String> = emptyList()
|
||||
|
||||
init {
|
||||
trace = getStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class E {
|
||||
A {
|
||||
init {
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ func testKotlin2Objc() throws {
|
||||
}
|
||||
|
||||
func testCompanionObject() throws {
|
||||
let trace = Foo.companion.trace
|
||||
try assertTrue(trace[8].contains("objc2kotlin_kclass:Foo#companion"))
|
||||
let trace = WithCompanion.companion.trace
|
||||
try assertTrue(trace[8].contains("objc2kotlin_kclass:WithCompanion#companion"))
|
||||
}
|
||||
|
||||
func testStandaloneObject() throws {
|
||||
|
||||
Reference in New Issue
Block a user