[K/N] Apply initializers lowering to any declaration container
This commit is contained in:
committed by
Space Team
parent
9516094755
commit
7006eb938d
+1
-1
@@ -163,7 +163,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config), Confi
|
||||
}
|
||||
|
||||
fun needGlobalInit(field: IrField): Boolean {
|
||||
if (field.descriptor.containingDeclaration !is PackageFragmentDescriptor) return false
|
||||
if (field.descriptor.containingDeclaration !is PackageFragmentDescriptor) return field.isStatic
|
||||
// TODO: add some smartness here. Maybe if package of the field is in never accessed
|
||||
// assume its global init can be actually omitted.
|
||||
return true
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
configuration.get(BinaryOptions.mimallocUseDefaultOptions) ?: false
|
||||
}
|
||||
|
||||
val mimallocUseCompaction by lazy {
|
||||
val mimallocUseCompaction: Boolean by lazy {
|
||||
// Turned off by default, because it slows down allocation.
|
||||
configuration.get(BinaryOptions.mimallocUseCompaction) ?: false
|
||||
}
|
||||
|
||||
-2
@@ -573,8 +573,6 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
||||
}
|
||||
disableUnless(verifyBitcodePhase, config.needCompilerVerification || getBoolean(KonanConfigKeys.VERIFY_BITCODE))
|
||||
|
||||
disableUnless(staticInitializersPhase, config.propertyLazyInitialization)
|
||||
disableUnless(removeRedundantCallsToStaticInitializersPhase, config.propertyLazyInitialization)
|
||||
|
||||
disableUnless(removeRedundantSafepointsPhase, config.memoryModel == MemoryModel.EXPERIMENTAL)
|
||||
|
||||
|
||||
+2
-2
@@ -101,11 +101,11 @@ internal val dcePhase = makeKonanModuleOpPhase(
|
||||
|
||||
val referencedFunctions = mutableSetOf<IrFunction>()
|
||||
callGraph.rootExternalFunctions.forEach {
|
||||
if (!it.isTopLevelFieldInitializer)
|
||||
if (!it.isStaticFieldInitializer)
|
||||
referencedFunctions.add(it.irFunction ?: error("No IR for: $it"))
|
||||
}
|
||||
for (node in callGraph.directEdges.values) {
|
||||
if (!node.symbol.isTopLevelFieldInitializer)
|
||||
if (!node.symbol.isStaticFieldInitializer)
|
||||
referencedFunctions.add(node.symbol.irFunction ?: error("No IR for: ${node.symbol}"))
|
||||
node.callSites.forEach {
|
||||
assert (!it.isVirtual) { "There should be no virtual calls in the call graph, but was: ${it.actualCallee}" }
|
||||
|
||||
+17
-12
@@ -235,25 +235,30 @@ internal interface ContextUtils : RuntimeAware {
|
||||
*/
|
||||
internal fun stringAsBytes(str: String) = str.toByteArray(Charsets.UTF_8)
|
||||
|
||||
internal class InitializersGenerationState {
|
||||
val fileGlobalInitStates = mutableMapOf<IrFile, LLVMValueRef>()
|
||||
val fileThreadLocalInitStates = mutableMapOf<IrFile, AddressAccess>()
|
||||
|
||||
internal class ScopeInitializersGenerationState {
|
||||
val topLevelFields = mutableListOf<IrField>()
|
||||
var globalInitFunction: IrFunction? = null
|
||||
var globalInitState: LLVMValueRef? = null
|
||||
var threadLocalInitFunction: IrFunction? = null
|
||||
var threadLocalInitState: AddressAccess? = null
|
||||
val globalSharedObjects = mutableSetOf<LLVMValueRef>()
|
||||
fun isEmpty() = topLevelFields.isEmpty() &&
|
||||
globalInitState == null &&
|
||||
threadLocalInitState == null &&
|
||||
globalSharedObjects.isEmpty()
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
topLevelFields.clear()
|
||||
globalInitFunction = null
|
||||
globalInitState = null
|
||||
threadLocalInitFunction = null
|
||||
threadLocalInitState = null
|
||||
internal class InitializersGenerationState {
|
||||
val fileGlobalInitStates = mutableMapOf<IrDeclarationContainer, LLVMValueRef>()
|
||||
val fileThreadLocalInitStates = mutableMapOf<IrDeclarationContainer, AddressAccess>()
|
||||
|
||||
var scopeState = ScopeInitializersGenerationState()
|
||||
|
||||
fun reset(newState: ScopeInitializersGenerationState) : ScopeInitializersGenerationState {
|
||||
val t = scopeState
|
||||
scopeState = newState
|
||||
return t
|
||||
}
|
||||
|
||||
fun isEmpty() = topLevelFields.isEmpty() && globalInitState == null && threadLocalInitState == null
|
||||
}
|
||||
|
||||
internal class ConstInt1(llvm: Llvm, val value: Boolean) : ConstValue {
|
||||
|
||||
+63
-63
@@ -15,9 +15,9 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation
|
||||
import org.jetbrains.kotlin.backend.konan.lower.*
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -364,24 +364,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAndProcessInitializers(konanLibrary: KotlinLibrary?, f: () -> Unit) {
|
||||
// TODO: collect those two in one place.
|
||||
llvm.fileUsesThreadLocalObjects = false
|
||||
llvm.globalSharedObjects.clear()
|
||||
|
||||
llvm.initializersGenerationState.reset()
|
||||
|
||||
f()
|
||||
|
||||
llvm.initializersGenerationState.globalInitFunction?.let { fileInitFunction ->
|
||||
private fun buildInitializerFunctions(scopeState: ScopeInitializersGenerationState) {
|
||||
scopeState.globalInitFunction?.let { fileInitFunction ->
|
||||
generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) {
|
||||
using(FunctionScope(fileInitFunction, this)) {
|
||||
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
|
||||
using(parameterScope) usingParameterScope@{
|
||||
using(VariableScope()) usingVariableScope@{
|
||||
llvm.initializersGenerationState.topLevelFields
|
||||
scopeState.topLevelFields
|
||||
.filter { it.storageKind(context) != FieldStorageKind.THREAD_LOCAL }
|
||||
.filterNot { it.shouldBeInitializedEagerly }
|
||||
.filterNot { context.shouldBeInitializedEagerly(it) }
|
||||
.forEach { initGlobalField(it) }
|
||||
ret(null)
|
||||
}
|
||||
@@ -390,15 +382,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
|
||||
llvm.initializersGenerationState.threadLocalInitFunction?.let { fileInitFunction ->
|
||||
scopeState.threadLocalInitFunction?.let { fileInitFunction ->
|
||||
generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) {
|
||||
using(FunctionScope(fileInitFunction, this)) {
|
||||
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
|
||||
using(parameterScope) usingParameterScope@{
|
||||
using(VariableScope()) usingVariableScope@{
|
||||
llvm.initializersGenerationState.topLevelFields
|
||||
scopeState.topLevelFields
|
||||
.filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
|
||||
.filterNot { it.shouldBeInitializedEagerly }
|
||||
.filterNot { context.shouldBeInitializedEagerly(it) }
|
||||
.forEach { initThreadLocalField(it) }
|
||||
ret(null)
|
||||
}
|
||||
@@ -406,15 +398,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!llvm.fileUsesThreadLocalObjects && llvm.globalSharedObjects.isEmpty()
|
||||
&& llvm.initializersGenerationState.isEmpty()) {
|
||||
return
|
||||
private fun runAndProcessInitializers(konanLibrary: KotlinLibrary?, f: () -> Unit) {
|
||||
val oldScopeState = llvm.initializersGenerationState.reset(ScopeInitializersGenerationState())
|
||||
f()
|
||||
val scopeState = llvm.initializersGenerationState.reset(oldScopeState)
|
||||
scopeState.takeIf { !it.isEmpty() }?.let {
|
||||
buildInitializerFunctions(it)
|
||||
val initNode = createInitNode(createInitBody(it))
|
||||
llvm.irStaticInitializers.add(IrStaticInitializer(konanLibrary, createInitCtor(initNode)))
|
||||
}
|
||||
|
||||
// Create global initialization records.
|
||||
val initNode = createInitNode(createInitBody())
|
||||
llvm.irStaticInitializers.add(IrStaticInitializer(konanLibrary, createInitCtor(initNode)))
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -468,7 +462,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
val FILE_NOT_INITIALIZED = 0
|
||||
val FILE_INITIALIZED = 2
|
||||
|
||||
private fun createInitBody(): LLVMValueRef {
|
||||
private fun createInitBody(state: ScopeInitializersGenerationState): LLVMValueRef {
|
||||
val initFunction = addLlvmFunctionWithDefaultAttributes(
|
||||
context,
|
||||
llvm.module,
|
||||
@@ -495,21 +489,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
// Globals initializers may contain accesses to objects, so visit them first.
|
||||
appendingTo(bbInit) {
|
||||
llvm.initializersGenerationState.topLevelFields
|
||||
.filter { !context.useLazyFileInitializers() || it.shouldBeInitializedEagerly }
|
||||
state.topLevelFields
|
||||
.filter { context.shouldBeInitializedEagerly(it) }
|
||||
.filterNot { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
|
||||
.forEach { initGlobalField(it) }
|
||||
ret(null)
|
||||
}
|
||||
|
||||
appendingTo(bbLocalInit) {
|
||||
llvm.initializersGenerationState.threadLocalInitState?.let {
|
||||
val address = it.getAddress(functionGenerationContext)
|
||||
store(llvm.int32(FILE_NOT_INITIALIZED), address)
|
||||
LLVMSetInitializer(address, llvm.int32(FILE_NOT_INITIALIZED))
|
||||
}
|
||||
llvm.initializersGenerationState.topLevelFields
|
||||
.filter { !context.useLazyFileInitializers() || it.shouldBeInitializedEagerly }
|
||||
state.topLevelFields
|
||||
.filter { context.shouldBeInitializedEagerly(it) }
|
||||
.filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
|
||||
.forEach { initThreadLocalField(it) }
|
||||
ret(null)
|
||||
@@ -524,7 +513,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
|
||||
appendingTo(bbGlobalDeinit) {
|
||||
llvm.initializersGenerationState.topLevelFields
|
||||
state.topLevelFields
|
||||
// Only if a subject for memory management.
|
||||
.forEach { irField ->
|
||||
if (irField.type.binaryTypeIsReference() && irField.storageKind(context) != FieldStorageKind.THREAD_LOCAL) {
|
||||
@@ -534,10 +523,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
||||
}
|
||||
}
|
||||
llvm.globalSharedObjects.forEach { address ->
|
||||
state.globalSharedObjects.forEach { address ->
|
||||
storeHeapRef(codegen.kNullObjHeaderPtr, address)
|
||||
}
|
||||
llvm.initializersGenerationState.globalInitState?.let {
|
||||
state.globalInitState?.let {
|
||||
store(llvm.int32(FILE_NOT_INITIALIZED), it)
|
||||
}
|
||||
ret(null)
|
||||
@@ -774,16 +763,24 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun getGlobalInitStateFor(file: IrFile): LLVMValueRef =
|
||||
llvm.initializersGenerationState.fileGlobalInitStates.getOrPut(file) {
|
||||
codegen.addGlobal("state_global$${file.fileEntry.name}", llvm.int32Type, false).also {
|
||||
private val IrDeclarationContainer.initVariableSuffix get() = when (this) {
|
||||
is IrFile -> "${fqName}\$${fileEntry.name}"
|
||||
else -> fqNameForIrSerialization.asString()
|
||||
}
|
||||
|
||||
private fun getGlobalInitStateFor(container: IrDeclarationContainer): LLVMValueRef =
|
||||
llvm.initializersGenerationState.fileGlobalInitStates.getOrPut(container) {
|
||||
codegen.addGlobal("state_global$${container.initVariableSuffix}", llvm.int32Type, false).also {
|
||||
LLVMSetInitializer(it, llvm.int32(FILE_NOT_INITIALIZED))
|
||||
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getThreadLocalInitStateFor(file: IrFile): AddressAccess =
|
||||
llvm.initializersGenerationState.fileThreadLocalInitStates.getOrPut(file) {
|
||||
codegen.addKotlinThreadLocal("state_thread_local$${file.fileEntry.name}", llvm.int32Type)
|
||||
private fun getThreadLocalInitStateFor(container: IrDeclarationContainer): AddressAccess =
|
||||
llvm.initializersGenerationState.fileThreadLocalInitStates.getOrPut(container) {
|
||||
codegen.addKotlinThreadLocal("state_thread_local$${container.initVariableSuffix}", llvm.int32Type).also {
|
||||
LLVMSetInitializer((it as GlobalAddressAccess).getAddress(null), llvm.int32(FILE_NOT_INITIALIZED))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
@@ -791,22 +788,23 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
val body = declaration.body
|
||||
|
||||
if (declaration.origin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER) {
|
||||
require(llvm.initializersGenerationState.globalInitFunction == null) { "There can only be at most one global file initializer" }
|
||||
val scopeState = llvm.initializersGenerationState.scopeState
|
||||
if (declaration.origin == DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER) {
|
||||
require(scopeState.globalInitFunction == null) { "There can only be at most one global file initializer" }
|
||||
require(body == null) { "The body of file initializer should be null" }
|
||||
require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" }
|
||||
require(declaration.returnsUnit()) { "File initializer must return Unit" }
|
||||
llvm.initializersGenerationState.globalInitFunction = declaration
|
||||
llvm.initializersGenerationState.globalInitState = getGlobalInitStateFor(declaration.parent as IrFile)
|
||||
scopeState.globalInitFunction = declaration
|
||||
scopeState.globalInitState = getGlobalInitStateFor(declaration.parent as IrDeclarationContainer)
|
||||
}
|
||||
if (declaration.origin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|
||||
|| declaration.origin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER) {
|
||||
require(llvm.initializersGenerationState.threadLocalInitFunction == null) { "There can only be at most one thread local file initializer" }
|
||||
if (declaration.origin == DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||
|| declaration.origin == DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER) {
|
||||
require(scopeState.threadLocalInitFunction == null) { "There can only be at most one thread local file initializer" }
|
||||
require(body == null) { "The body of file initializer should be null" }
|
||||
require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" }
|
||||
require(declaration.returnsUnit()) { "File initializer must return Unit" }
|
||||
llvm.initializersGenerationState.threadLocalInitFunction = declaration
|
||||
llvm.initializersGenerationState.threadLocalInitState = getThreadLocalInitStateFor(declaration.parent as IrFile)
|
||||
scopeState.threadLocalInitFunction = declaration
|
||||
scopeState.threadLocalInitState = getThreadLocalInitStateFor(declaration.parent as IrDeclarationContainer)
|
||||
}
|
||||
|
||||
|
||||
@@ -879,8 +877,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return
|
||||
}
|
||||
using(ClassScope(declaration)) {
|
||||
declaration.declarations.forEach {
|
||||
it.acceptVoid(this)
|
||||
runAndProcessInitializers(declaration.konanLibrary) {
|
||||
declaration.declarations.forEach {
|
||||
it.acceptVoid(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,7 +947,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
// (Cannot do this before the global is initialized).
|
||||
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
|
||||
}
|
||||
llvm.initializersGenerationState.topLevelFields.add(declaration)
|
||||
llvm.initializersGenerationState.scopeState.topLevelFields.add(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2399,15 +2399,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return when {
|
||||
function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args, resultSlot)
|
||||
function.isBuiltInOperator -> evaluateOperatorCall(callee, args)
|
||||
function.origin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER -> evaluateFileGlobalInitializerCall(function)
|
||||
function.origin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER -> evaluateFileThreadLocalInitializerCall(function)
|
||||
function.origin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER -> evaluateFileStandaloneThreadLocalInitializerCall(function)
|
||||
function.origin == DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER -> evaluateFileGlobalInitializerCall(function)
|
||||
function.origin == DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER -> evaluateFileThreadLocalInitializerCall(function)
|
||||
function.origin == DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER -> evaluateFileStandaloneThreadLocalInitializerCall(function)
|
||||
else -> evaluateSimpleFunctionCall(function, args, resultLifetime, callee.superQualifierSymbol?.owner, resultSlot)
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluateFileGlobalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
|
||||
val statePtr = getGlobalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val statePtr = getGlobalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
|
||||
|
||||
val bbInit = basicBlock("label_init", null)
|
||||
@@ -2426,8 +2426,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
|
||||
private fun evaluateFileThreadLocalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
|
||||
val globalStatePtr = getGlobalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val localState = getThreadLocalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val globalStatePtr = getGlobalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
|
||||
val localState = getThreadLocalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
|
||||
val localStatePtr = localState.getAddress(functionGenerationContext)
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
|
||||
|
||||
@@ -2453,7 +2453,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
|
||||
private fun evaluateFileStandaloneThreadLocalInitializerCall(fileInitializer: IrFunction) = with(functionGenerationContext) {
|
||||
val state = getThreadLocalInitStateFor(fileInitializer.parent as IrFile)
|
||||
val state = getThreadLocalInitStateFor(fileInitializer.parent as IrDeclarationContainer)
|
||||
val statePtr = state.getAddress(functionGenerationContext)
|
||||
val initializerPtr = with(codegen) { fileInitializer.llvmFunction.llvmValue }
|
||||
|
||||
|
||||
+44
-21
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.ConfigChecks
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENTRY_POINT
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.FieldStorageKind
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.needsGCRegistration
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.storageKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -23,34 +25,55 @@ 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.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal object DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER : IrDeclarationOriginImpl("FILE_GLOBAL_INITIALIZER")
|
||||
internal object DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER : IrDeclarationOriginImpl("FILE_THREAD_LOCAL_INITIALIZER")
|
||||
internal object DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER : IrDeclarationOriginImpl("FILE_STANDALONE_THREAD_LOCAL_INITIALIZER")
|
||||
internal object DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER : IrDeclarationOriginImpl("STATIC_GLOBAL_INITIALIZER")
|
||||
internal object DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER : IrDeclarationOriginImpl("STATIC_THREAD_LOCAL_INITIALIZER")
|
||||
internal object DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER : IrDeclarationOriginImpl("STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER")
|
||||
|
||||
internal val IrFunction.isFileInitializer: Boolean
|
||||
get() = origin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER
|
||||
|| origin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|
||||
|| origin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
internal val IrFunction.isStaticInitializer: Boolean
|
||||
get() = origin == DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER
|
||||
|| origin == DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||
|| origin == DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
|
||||
internal fun IrBuilderWithScope.irCallFileInitializer(initializer: IrFunctionSymbol) =
|
||||
irCall(initializer)
|
||||
|
||||
internal val IrField.shouldBeInitializedEagerly: Boolean
|
||||
get() {
|
||||
val annotations = correspondingPropertySymbol?.owner?.annotations ?: annotations
|
||||
return annotations.hasAnnotation(KonanFqNames.eagerInitialization)
|
||||
internal fun ConfigChecks.shouldBeInitializedEagerly(irField: IrField): Boolean {
|
||||
if (irField.parent is IrFile || irField.correspondingPropertySymbol?.owner?.parent is IrFile) {
|
||||
if (!useLazyFileInitializers()) return true
|
||||
}
|
||||
val annotations = irField.correspondingPropertySymbol?.owner?.annotations ?: irField.annotations
|
||||
return annotations.hasAnnotation(KonanFqNames.eagerInitialization)
|
||||
}
|
||||
|
||||
// TODO: ExplicitlyExported for IR proto are not longer needed.
|
||||
internal class StaticInitializersLowering(val context: Context) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
processDeclarationContainter(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
processDeclarationContainter(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun processDeclarationContainter(container: IrDeclarationContainer) {
|
||||
var requireGlobalInitializer = false
|
||||
var requireThreadLocalInitializer = false
|
||||
for (declaration in irFile.declarations) {
|
||||
for (declaration in container.declarations) {
|
||||
val irField = (declaration as? IrField) ?: (declaration as? IrProperty)?.backingField
|
||||
if (irField == null || !irField.needsInitializationAtRuntime || irField.shouldBeInitializedEagerly) continue
|
||||
if (irField == null || !irField.isStatic || !irField.needsInitializationAtRuntime || context.shouldBeInitializedEagerly(irField)) continue
|
||||
if (irField.storageKind(context) != FieldStorageKind.THREAD_LOCAL) {
|
||||
requireGlobalInitializer = true
|
||||
} else {
|
||||
@@ -64,18 +87,18 @@ internal class StaticInitializersLowering(val context: Context) : FileLoweringPa
|
||||
|
||||
val globalInitFunction =
|
||||
if (requireGlobalInitializer)
|
||||
buildInitFileFunction(irFile, "\$init_global", DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER)
|
||||
buildInitFileFunction(container, "\$init_global", DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER)
|
||||
else null
|
||||
val threadLocalInitFunction =
|
||||
if (requireThreadLocalInitializer)
|
||||
buildInitFileFunction(irFile, "\$init_thread_local",
|
||||
buildInitFileFunction(container, "\$init_thread_local",
|
||||
if (requireGlobalInitializer)
|
||||
DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|
||||
else DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||
else DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
)
|
||||
else null
|
||||
|
||||
irFile.simpleFunctions()
|
||||
container.simpleFunctions()
|
||||
.filterNot { it.origin == DECLARATION_ORIGIN_ENTRY_POINT }
|
||||
.forEach {
|
||||
val body = it.body ?: return@forEach
|
||||
@@ -89,7 +112,7 @@ internal class StaticInitializersLowering(val context: Context) : FileLoweringPa
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildInitFileFunction(irFile: IrFile, name: String, origin: IrDeclarationOrigin) = context.irFactory.buildFun {
|
||||
private fun buildInitFileFunction(container: IrDeclarationContainer, name: String, origin: IrDeclarationOrigin) = context.irFactory.buildFun {
|
||||
startOffset = SYNTHETIC_OFFSET
|
||||
endOffset = SYNTHETIC_OFFSET
|
||||
this.origin = origin
|
||||
@@ -97,8 +120,8 @@ internal class StaticInitializersLowering(val context: Context) : FileLoweringPa
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
returnType = context.irBuiltIns.unitType
|
||||
}.apply {
|
||||
parent = irFile
|
||||
irFile.declarations.add(0, this)
|
||||
parent = container
|
||||
container.declarations.add(0, this)
|
||||
}
|
||||
|
||||
private val IrField.needsInitializationAtRuntime: Boolean
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
if (declaration.parent is IrFile)
|
||||
if (declaration.isStatic)
|
||||
declaration.initializer?.let {
|
||||
context.logMultiple {
|
||||
+"Analysing global field ${declaration.descriptor}"
|
||||
|
||||
+4
-4
@@ -110,7 +110,7 @@ internal object DataFlowIR {
|
||||
}
|
||||
|
||||
object FunctionAttributes {
|
||||
val IS_TOP_LEVEL_FIELD_INITIALIZER = 1
|
||||
val IS_STATIC_FIELD_INITIALIZER = 1
|
||||
val RETURNS_UNIT = 4
|
||||
val RETURNS_NOTHING = 8
|
||||
val EXPLICITLY_EXPORTED = 16
|
||||
@@ -122,7 +122,7 @@ internal object DataFlowIR {
|
||||
lateinit var parameters: Array<FunctionParameter>
|
||||
lateinit var returnParameter: FunctionParameter
|
||||
|
||||
val isTopLevelFieldInitializer = attributes.and(FunctionAttributes.IS_TOP_LEVEL_FIELD_INITIALIZER) != 0
|
||||
val isStaticFieldInitializer = attributes.and(FunctionAttributes.IS_STATIC_FIELD_INITIALIZER) != 0
|
||||
val returnsUnit = attributes.and(FunctionAttributes.RETURNS_UNIT) != 0
|
||||
val returnsNothing = attributes.and(FunctionAttributes.RETURNS_NOTHING) != 0
|
||||
val explicitlyExported = attributes.and(FunctionAttributes.EXPLICITLY_EXPORTED) != 0
|
||||
@@ -656,8 +656,8 @@ internal object DataFlowIR {
|
||||
private fun mapPropertyInitializer(irField: IrField): FunctionSymbol {
|
||||
functionMap[irField]?.let { return it }
|
||||
|
||||
assert(irField.parent !is IrClass) { "All local properties initializers should've been lowered" }
|
||||
val attributes = FunctionAttributes.IS_TOP_LEVEL_FIELD_INITIALIZER or FunctionAttributes.RETURNS_UNIT
|
||||
assert(irField.isStatic) { "All local properties initializers should've been lowered" }
|
||||
val attributes = FunctionAttributes.IS_STATIC_FIELD_INITIALIZER or FunctionAttributes.RETURNS_UNIT
|
||||
val symbol = FunctionSymbol.Private(privateFunIndex++, module, -1, attributes, irField, null, takeName { "${irField.computeSymbolName()}_init" })
|
||||
|
||||
functionMap[irField] = symbol
|
||||
|
||||
+2
-3
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isBoxOrUnboxCall
|
||||
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis.irCoerce
|
||||
import org.jetbrains.kotlin.backend.konan.util.IntArrayList
|
||||
import org.jetbrains.kotlin.backend.konan.util.LongArrayList
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
@@ -83,8 +82,8 @@ internal object DevirtualizationAnalysis {
|
||||
// TODO: Are globals initializers always called whether they are actually reachable from roots or not?
|
||||
// TODO: With the changed semantics of global initializers this is no longer the case - rework.
|
||||
val globalInitializers =
|
||||
moduleDFG.symbolTable.functionMap.values.filter { it.isTopLevelFieldInitializer } +
|
||||
externalModulesDFG.functionDFGs.keys.filter { it.isTopLevelFieldInitializer }
|
||||
moduleDFG.symbolTable.functionMap.values.filter { it.isStaticFieldInitializer } +
|
||||
externalModulesDFG.functionDFGs.keys.filter { it.isStaticFieldInitializer }
|
||||
|
||||
val explicitlyExported =
|
||||
moduleDFG.symbolTable.functionMap.values.filter { it.explicitlyExported } +
|
||||
|
||||
+49
-53
@@ -58,13 +58,13 @@ internal object StaticInitializersOptimization {
|
||||
val callSitesRequiringGlobalInitializerCall: Set<IrFunctionAccessExpression>,
|
||||
val callSitesRequiringThreadLocalInitializerCall: Set<IrFunctionAccessExpression>)
|
||||
|
||||
private class InitializedFiles(val fileIds: Map<IrFile, Int>) {
|
||||
private class InitializedContainers(val containerIds: Map<IrDeclarationContainer, Int>) {
|
||||
val afterCall = mutableMapOf<IrFunction, BitSet>()
|
||||
val beforeCallGlobal = mutableMapOf<IrFunction, BitSet>()
|
||||
val beforeCallThreadLocal = mutableMapOf<IrFunction, BitSet>()
|
||||
}
|
||||
|
||||
private val invalidFileId = 0
|
||||
private val invalidContainerId = 0
|
||||
|
||||
private class InterproceduralAnalysis(val context: Context, val callGraph: CallGraph,
|
||||
val rootSet: Set<IrFunction>) {
|
||||
@@ -109,20 +109,18 @@ internal object StaticInitializersOptimization {
|
||||
+""
|
||||
}
|
||||
|
||||
var fileId = invalidFileId
|
||||
val fileIds = mutableMapOf<IrFile, Int>()
|
||||
for (node in callGraph.directEdges.values) {
|
||||
val callerFile = node.symbol.irFile
|
||||
if (callerFile != null && fileIds[callerFile] == null)
|
||||
fileIds[callerFile] = ++fileId
|
||||
for (callSite in node.callSites) {
|
||||
val calleeFile = callSite.actualCallee.irFile
|
||||
if (calleeFile != null && fileIds[calleeFile] == null)
|
||||
fileIds[calleeFile] = ++fileId
|
||||
val functions = buildSet {
|
||||
callGraph.directEdges.values.forEach {
|
||||
add(it.symbol.irFunction)
|
||||
it.callSites.forEach { callSite -> add(callSite.actualCallee.irFunction) }
|
||||
}
|
||||
}
|
||||
val containers = functions
|
||||
.mapNotNull { it?.calledInitializer }
|
||||
.distinct()
|
||||
val containerIds = containers.indices.associate { containers[it] to it + 1 }
|
||||
|
||||
val initializedFiles = InitializedFiles(fileIds)
|
||||
val initializedFiles = InitializedContainers(containerIds)
|
||||
|
||||
context.log { "FIRST PHASE: compute initialized after call" }
|
||||
|
||||
@@ -163,11 +161,10 @@ internal object StaticInitializersOptimization {
|
||||
): Set<IrFunction> {
|
||||
val result = mutableSetOf<IrFunction>()
|
||||
initializedFiles.forEach { (function, functionInitializedFiles) ->
|
||||
val irFile = function.fileOrNull
|
||||
val containter = function.calledInitializer ?: return@forEach
|
||||
val backingField = (function as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.backingField
|
||||
val isDefaultAccessor = backingField != null && function.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
|
||||
if (irFile == null ||
|
||||
(!functionInitializedFiles.get(fileIds[irFile]!!)
|
||||
if ((!functionInitializedFiles.get(containerIds[containter]!!)
|
||||
&& function !in functionsWhoseInitializerCallCanBeExtractedToCallSites
|
||||
// Extract calls to file initializers off of default accessors to simplify their inlining.
|
||||
&& (!isDefaultAccessor || function in rootSet))
|
||||
@@ -194,7 +191,7 @@ internal object StaticInitializersOptimization {
|
||||
}
|
||||
|
||||
private fun analyze(multiNode: DirectedGraphMultiNode<DataFlowIR.FunctionSymbol.Declared>,
|
||||
initializedFiles: InitializedFiles,
|
||||
initializedFiles: InitializedContainers,
|
||||
analysisGoal: AnalysisGoal) {
|
||||
val nodes = multiNode.nodes.toList()
|
||||
|
||||
@@ -244,12 +241,12 @@ internal object StaticInitializersOptimization {
|
||||
CollectCallSites
|
||||
}
|
||||
|
||||
private fun IrFunction.callsFileInitializer() =
|
||||
(body?.statements?.get(0) as? IrCall)?.symbol?.owner?.isFileInitializer == true
|
||||
private val IrFunction.calledInitializer get() =
|
||||
(body?.statements?.get(0) as? IrCall)?.symbol?.owner?.takeIf { it.isStaticInitializer }?.parent as IrDeclarationContainer?
|
||||
|
||||
private fun intraproceduralAnalysis(
|
||||
node: CallGraphNode,
|
||||
initializedFiles: InitializedFiles,
|
||||
initializedContainers: InitializedContainers,
|
||||
analysisGoal: AnalysisGoal,
|
||||
callSitesRequiringGlobalInitializerCall: MutableSet<IrFunctionAccessExpression> = dummySet,
|
||||
callSitesRequiringThreadLocalInitializerCall: MutableSet<IrFunctionAccessExpression> = dummySet,
|
||||
@@ -257,7 +254,7 @@ internal object StaticInitializersOptimization {
|
||||
callSitesNotRequiringThreadLocalInitializerCall: MutableSet<IrFunctionAccessExpression> = dummySet
|
||||
) {
|
||||
val irDeclaration = node.symbol.irDeclaration ?: return
|
||||
val body = if (node.symbol.isTopLevelFieldInitializer)
|
||||
val body = if (node.symbol.isStaticFieldInitializer)
|
||||
(irDeclaration as IrField).initializer?.expression
|
||||
else {
|
||||
val function = irDeclaration as IrFunction
|
||||
@@ -266,11 +263,11 @@ internal object StaticInitializersOptimization {
|
||||
}
|
||||
if (body == null) return
|
||||
|
||||
val filesWithInitializedGlobals = BitSet()
|
||||
val filesWithInitializedThreadLocals = BitSet()
|
||||
if (!node.symbol.isTopLevelFieldInitializer) {
|
||||
initializedFiles.beforeCallGlobal[irDeclaration as IrFunction]?.let { filesWithInitializedGlobals.or(it) }
|
||||
initializedFiles.beforeCallThreadLocal[irDeclaration]?.let { filesWithInitializedThreadLocals.or(it) }
|
||||
val containersWithInitializedGlobals = BitSet()
|
||||
val containersWithInitializedThreadLocals = BitSet()
|
||||
if (!node.symbol.isStaticFieldInitializer) {
|
||||
initializedContainers.beforeCallGlobal[irDeclaration as IrFunction]?.let { containersWithInitializedGlobals.or(it) }
|
||||
initializedContainers.beforeCallThreadLocal[irDeclaration]?.let { containersWithInitializedThreadLocals.or(it) }
|
||||
}
|
||||
|
||||
val producerInvocations = mutableMapOf<IrExpression, IrCall>()
|
||||
@@ -409,25 +406,24 @@ internal object StaticInitializersOptimization {
|
||||
if (this.get(bit)) this else copy().also { it.set(bit) }
|
||||
|
||||
private fun getResultAfterCall(function: IrFunction, set: BitSet): BitSet {
|
||||
val result = initializedFiles.afterCall[function]
|
||||
val result = initializedContainers.afterCall[function]
|
||||
if (result == null) {
|
||||
if (!function.callsFileInitializer()) return set
|
||||
val file = function.fileOrNull ?: return set
|
||||
return set.withSetBit(initializedFiles.fileIds[file]!!)
|
||||
val file = function.calledInitializer ?: return set
|
||||
return set.withSetBit(initializedContainers.containerIds[file]!!)
|
||||
}
|
||||
return result.copy().also { it.or(set) }
|
||||
}
|
||||
|
||||
private fun updateResultForFunction(function: IrFunction, globalSet: BitSet, threadLocalSet: BitSet) {
|
||||
if (analysisGoal != AnalysisGoal.ComputeInitializedBeforeCall) return
|
||||
intersectInitializedFiles(initializedFiles.beforeCallGlobal, function, globalSet)
|
||||
intersectInitializedFiles(initializedFiles.beforeCallThreadLocal, function, threadLocalSet)
|
||||
intersectInitializedFiles(initializedContainers.beforeCallGlobal, function, globalSet)
|
||||
intersectInitializedFiles(initializedContainers.beforeCallThreadLocal, function, threadLocalSet)
|
||||
}
|
||||
|
||||
private fun updateResultForFunction(function: IrFunction, set: BitSet) {
|
||||
if (analysisGoal != AnalysisGoal.ComputeInitializedBeforeCall) return
|
||||
intersectInitializedFiles(initializedFiles.beforeCallGlobal, function, set.copy().also { it.or(filesWithInitializedGlobals) })
|
||||
intersectInitializedFiles(initializedFiles.beforeCallThreadLocal, function, set.copy().also { it.or(filesWithInitializedThreadLocals) })
|
||||
intersectInitializedFiles(initializedContainers.beforeCallGlobal, function, set.copy().also { it.or(containersWithInitializedGlobals) })
|
||||
intersectInitializedFiles(initializedContainers.beforeCallThreadLocal, function, set.copy().also { it.or(containersWithInitializedThreadLocals) })
|
||||
}
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, data: BitSet): BitSet {
|
||||
@@ -446,22 +442,22 @@ internal object StaticInitializersOptimization {
|
||||
val arguments = expression.getArgumentsWithIr()
|
||||
val argumentsResult = arguments.fold(data) { set, arg -> arg.second.accept(this, set) }
|
||||
updateResultForFunction(actualCallee, argumentsResult)
|
||||
val file = actualCallee.fileOrNull
|
||||
val fileId = file?.let { initializedFiles.fileIds[it]!! } ?: invalidFileId
|
||||
if (analysisGoal == AnalysisGoal.CollectCallSites && file != null
|
||||
val container = actualCallee.calledInitializer
|
||||
val containerId = initializedContainers.containerIds[container] ?: invalidContainerId
|
||||
if (analysisGoal == AnalysisGoal.CollectCallSites &&
|
||||
// Only extract initializer calls from non-virtual functions.
|
||||
&& !actualCallee.isOverridable
|
||||
!actualCallee.isOverridable
|
||||
) {
|
||||
// The initializer won't be optimized away from the function.
|
||||
if (!initializedFiles.beforeCallGlobal[actualCallee]!!.get(fileId)) {
|
||||
if (argumentsResult.get(fileId) || filesWithInitializedGlobals.get(fileId))
|
||||
if (!initializedContainers.beforeCallGlobal[actualCallee]!!.get(containerId)) {
|
||||
if (argumentsResult.get(containerId) || containersWithInitializedGlobals.get(containerId))
|
||||
callSitesNotRequiringGlobalInitializerCall += expression
|
||||
else
|
||||
callSitesRequiringGlobalInitializerCall += expression
|
||||
}
|
||||
// The initializer won't be optimized away from the function.
|
||||
if (!initializedFiles.beforeCallThreadLocal[actualCallee]!!.get(fileId)) {
|
||||
if (argumentsResult.get(fileId) || filesWithInitializedThreadLocals.get(fileId))
|
||||
if (!initializedContainers.beforeCallThreadLocal[actualCallee]!!.get(containerId)) {
|
||||
if (argumentsResult.get(containerId) || containersWithInitializedThreadLocals.get(containerId))
|
||||
callSitesNotRequiringThreadLocalInitializerCall += expression
|
||||
else
|
||||
callSitesRequiringThreadLocalInitializerCall += expression
|
||||
@@ -480,7 +476,7 @@ internal object StaticInitializersOptimization {
|
||||
if (analysisGoal != AnalysisGoal.CollectCallSites) {
|
||||
require(!jobInvocation.isVirtualCall) { "Expected a static call but was: ${jobInvocation.render()}" }
|
||||
updateResultForFunction(jobInvocation.actualCallee,
|
||||
curData.copy().also { it.or(filesWithInitializedGlobals) }, // Globals (= shared) visible to other threads as well.
|
||||
curData.copy().also { it.or(containersWithInitializedGlobals) }, // Globals (= shared) visible to other threads as well.
|
||||
BitSet() // A new thread is about to be created - no thread locals initialized yet.
|
||||
)
|
||||
}
|
||||
@@ -499,8 +495,8 @@ internal object StaticInitializersOptimization {
|
||||
processCall(expression, expression.actualCallee, data)
|
||||
|
||||
override fun visitCall(expression: IrCall, data: BitSet): BitSet {
|
||||
if (expression.symbol.owner.isFileInitializer)
|
||||
return data.withSetBit(initializedFiles.fileIds[irDeclaration.file]!!)
|
||||
if (expression.symbol.owner.isStaticInitializer)
|
||||
return data.withSetBit(initializedContainers.containerIds[expression.symbol.owner.parent as IrDeclarationContainer]!!)
|
||||
if (expression.symbol == executeImplSymbol)
|
||||
return processExecuteImpl(expression, data)
|
||||
if (expression.symbol == getContinuationSymbol)
|
||||
@@ -528,8 +524,8 @@ internal object StaticInitializersOptimization {
|
||||
}, BitSet())
|
||||
|
||||
if (analysisGoal == AnalysisGoal.ComputeInitializedAfterCall) {
|
||||
if (!node.symbol.isTopLevelFieldInitializer)
|
||||
initializedFiles.afterCall[irDeclaration as IrFunction] = returnTargetsInitializedFiles[irDeclaration.symbol] ?: callerResult
|
||||
if (!node.symbol.isStaticFieldInitializer)
|
||||
initializedContainers.afterCall[irDeclaration as IrFunction] = returnTargetsInitializedFiles[irDeclaration.symbol] ?: callerResult
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -560,10 +556,10 @@ internal object StaticInitializersOptimization {
|
||||
.take(2) // The very first statements by construction.
|
||||
.filter {
|
||||
val calleeOrigin = (it as? IrCall)?.symbol?.owner?.origin
|
||||
val isNotOptimizedAwayGlobalInitializerCall = calleeOrigin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER
|
||||
val isNotOptimizedAwayGlobalInitializerCall = calleeOrigin == DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER
|
||||
&& callee !in analysisResult.functionsRequiringGlobalInitializerCall
|
||||
val isNotOptimizedAwayThreadLocalInitializerCall = (calleeOrigin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|
||||
|| calleeOrigin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER)
|
||||
val isNotOptimizedAwayThreadLocalInitializerCall = (calleeOrigin == DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||
|| calleeOrigin == DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER)
|
||||
&& callee !in analysisResult.functionsRequiringThreadLocalInitializerCall
|
||||
if (isNotOptimizedAwayGlobalInitializerCall)
|
||||
++numberOfCallSitesToFunctionsWithGlobalInitializerCall
|
||||
@@ -596,7 +592,7 @@ internal object StaticInitializersOptimization {
|
||||
.take(2) // The very first statements by construction.
|
||||
.indexOfFirst {
|
||||
val calleeOrigin = (it as? IrCall)?.symbol?.owner?.origin
|
||||
calleeOrigin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER
|
||||
calleeOrigin == DECLARATION_ORIGIN_STATIC_GLOBAL_INITIALIZER
|
||||
}
|
||||
if (globalInitializerCallIndex >= 0) {
|
||||
++numberOfFunctionsWithGlobalInitializerCall
|
||||
@@ -609,8 +605,8 @@ internal object StaticInitializersOptimization {
|
||||
.take(2)
|
||||
.indexOfFirst {
|
||||
val calleeOrigin = (it as? IrCall)?.symbol?.owner?.origin
|
||||
calleeOrigin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|
||||
|| calleeOrigin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
calleeOrigin == DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||
|| calleeOrigin == DECLARATION_ORIGIN_STATIC_STANDALONE_THREAD_LOCAL_INITIALIZER
|
||||
}
|
||||
if (threadLocalInitializerCallIndex >= 0) {
|
||||
++numberOfFunctionsWithThreadLocalInitializerCall
|
||||
|
||||
Reference in New Issue
Block a user