diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 6ccbda72db8..0c58fe2f6ef 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.backend.konan.lower.DefaultParameterInjector import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering import org.jetbrains.kotlin.backend.konan.lower.LocalDeclarationsLowering +import org.jetbrains.kotlin.backend.konan.lower.SharedVariablesLowering import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.checkDeclarationParents diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt new file mode 100644 index 00000000000..418ca188a81 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SharedVariablesLowering.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ValueDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.IrSetVariable +import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression +import org.jetbrains.kotlin.ir.visitors.* +import java.util.* + +// TODO: Fix .parent for variables and use from common backend. +class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPass { + override fun lower(irFunction: IrFunction) { + SharedVariablesTransformer(irFunction).lowerSharedVariables() + } + + private inner class SharedVariablesTransformer(val irFunction: IrFunction) { + val sharedVariables = mutableSetOf() + + fun lowerSharedVariables() { + collectSharedVariables() + if (sharedVariables.isEmpty()) return + + rewriteSharedVariables() + } + + private fun collectSharedVariables() { + irFunction.acceptVoid(object : IrElementVisitorVoid { + val relevantVars = mutableSetOf() + val functionsVariables = mutableListOf>() + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + functionsVariables.push(mutableSetOf()) + declaration.acceptChildrenVoid(this) + functionsVariables.pop() + } + + override fun visitVariable(declaration: IrVariable) { + declaration.acceptChildrenVoid(this) + + val variableDescriptor = declaration.descriptor + if (variableDescriptor.isVar) { + relevantVars.add(variableDescriptor) + functionsVariables.peek()!!.add(variableDescriptor) + } + } + + override fun visitVariableAccess(expression: IrValueAccessExpression) { + expression.acceptChildrenVoid(this) + + val descriptor = expression.descriptor + //if (descriptor in relevantVars && descriptor.containingDeclaration != currentDeclaration) { + if (descriptor in relevantVars && !functionsVariables.peek()!!.contains(descriptor)) { + sharedVariables.add(descriptor) + } + } + }) + } + + private fun rewriteSharedVariables() { + val transformedDescriptors = HashMap() + + irFunction.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitVariable(declaration: IrVariable): IrStatement { + declaration.transformChildrenVoid(this) + + val oldDescriptor = declaration.descriptor + if (oldDescriptor !in sharedVariables) return declaration + + val newDescriptor = context.sharedVariablesManager.createSharedVariableDescriptor(oldDescriptor) + transformedDescriptors[oldDescriptor] = newDescriptor + + return context.sharedVariablesManager.defineSharedValue(newDescriptor, declaration) + } + }) + + irFunction.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitGetValue(expression: IrGetValue): IrExpression { + expression.transformChildrenVoid(this) + + val newDescriptor = getTransformedDescriptor(expression.descriptor) ?: return expression + + return context.sharedVariablesManager.getSharedValue(newDescriptor, expression) + } + + override fun visitSetVariable(expression: IrSetVariable): IrExpression { + expression.transformChildrenVoid(this) + + val newDescriptor = getTransformedDescriptor(expression.descriptor) ?: return expression + + return context.sharedVariablesManager.setSharedValue(newDescriptor, expression) + } + + private fun getTransformedDescriptor(oldDescriptor: ValueDescriptor): VariableDescriptor? = + transformedDescriptors.getOrElse(oldDescriptor) { + assert(oldDescriptor !in sharedVariables) { + "Shared variable is not transformed: $oldDescriptor" + } + null + } + }) + } + } +} \ No newline at end of file