From 191c98ec601bab318fd6bcd3df5850f8a59c150b Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Thu, 8 Dec 2016 11:16:10 +0700 Subject: [PATCH] backend/common: copy some sources from JVM BE --- .../kotlin/backend/common/BackendContext.kt | 33 ++ .../jetbrains/kotlin/backend/common/Lower.kt | 103 +++++ .../descriptors/SharedVariablesManager.kt | 203 ++++++++++ .../common/lower/LocalFunctionsLowering.kt | 369 ++++++++++++++++++ .../common/lower/SharedVariablesLowering.kt | 131 +++++++ 5 files changed, 839 insertions(+) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/BackendContext.kt create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/Lower.kt create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/SharedVariablesManager.kt create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalFunctionsLowering.kt create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/BackendContext.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/BackendContext.kt new file mode 100644 index 00000000000..d87a1df5834 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/BackendContext.kt @@ -0,0 +1,33 @@ +/* + * 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.jvm + +import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager +import org.jetbrains.kotlin.backend.jvm.descriptors.SpecialDescriptorsFactory +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.psi2ir.PsiSourceManager + +class JvmBackendContext( + val state: GenerationState, + val psiSourceManager: PsiSourceManager, + val irBuiltIns: IrBuiltIns +) { + val builtIns = state.module.builtIns + val specialDescriptorsFactory = SpecialDescriptorsFactory(psiSourceManager, builtIns) + val sharedVariablesManager = JvmSharedVariablesManager(builtIns) +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/Lower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/Lower.kt new file mode 100644 index 00000000000..68a6f9f01bc --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/Lower.kt @@ -0,0 +1,103 @@ +/* + * 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.jvm + +import org.jetbrains.kotlin.backend.jvm.lower.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid + +class JvmLower(val context: JvmBackendContext) { + fun lower(irFile: IrFile) { + // TODO run lowering passes as callbacks in bottom-up visitor + FileClassLowering(context).lower(irFile) + ConstAndJvmFieldPropertiesLowering().lower(irFile) + PropertiesLowering().lower(irFile) + InterfaceLowering(context.state).runOnFilePostfix(irFile) + InterfaceDelegationLowering(context.state).runOnFilePostfix(irFile) + SharedVariablesLowering(context).runOnFilePostfix(irFile) + InnerClassesLowering(context).runOnFilePostfix(irFile) + InnerClassConstructorCallsLowering(context).runOnFilePostfix(irFile) + LocalFunctionsLowering(context).runOnFilePostfix(irFile) + EnumClassLowering(context).runOnFilePostfix(irFile) + ObjectClassLowering(context).runOnFilePostfix(irFile) + InitializersLowering(context).runOnFilePostfix(irFile) + SingletonReferencesLowering(context).runOnFilePostfix(irFile) + SyntheticAccessorLowering(context.state).lower(irFile) + BridgeLowering(context.state).runOnFilePostfix(irFile) + } +} + +interface FileLoweringPass { + fun lower(irFile: IrFile) +} + +interface ClassLoweringPass { + fun lower(irClass: IrClass) +} + +interface FunctionLoweringPass { + fun lower(irFunction: IrFunction) +} + +interface BodyLoweringPass { + fun lower(irBody: IrBody) +} + +fun ClassLoweringPass.runOnFilePostfix(irFile: IrFile) { + irFile.acceptVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitClass(declaration: IrClass) { + declaration.acceptChildrenVoid(this) + lower(declaration) + } + }) +} + +fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile) { + irFile.acceptVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitBody(body: IrBody) { + body.acceptChildrenVoid(this) + lower(body) + } + }) +} + +fun FunctionLoweringPass.runOnFilePostfix(irFile: IrFile) { + irFile.acceptVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + declaration.acceptChildrenVoid(this) + lower(declaration) + } + }) +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/SharedVariablesManager.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/SharedVariablesManager.kt new file mode 100644 index 00000000000..5ea59789264 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/descriptors/SharedVariablesManager.kt @@ -0,0 +1,203 @@ +/* + * 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.jvm.descriptors + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl +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.impl.* +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.types.* + +interface SharedVariablesManager { + fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor + fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement + fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression + fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression +} + +class JvmSharedVariablesManager(val builtIns: KotlinBuiltIns) : SharedVariablesManager { + private val kotlinJvmInternalPackage = KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.jvm.internal")) + private val refNamespaceClass = KnownClassDescriptor.createClass(Name.identifier("Ref"), kotlinJvmInternalPackage, listOf(builtIns.anyType)) + + private class PrimitiveRefDescriptorsProvider(type: KotlinType, refClass: ClassDescriptor) { + val refType: KotlinType = refClass.defaultType + + val refConstructor: ClassConstructorDescriptor = + ClassConstructorDescriptorImpl.create(refClass, Annotations.EMPTY, true, SourceElement.NO_SOURCE).apply { + initialize(emptyList(), Visibilities.PUBLIC, emptyList()) + returnType = refType + } + + val elementField: PropertyDescriptor = + PropertyDescriptorImpl.create( + refClass, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, true, + Name.identifier("element"), CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE, + false, false, false, false + ).initialize(type, dispatchReceiverParameter = refClass.thisAsReceiverParameter) + } + + private val primitiveRefDescriptorProviders: Map = + PrimitiveType.values().associate { + val type = builtIns.getPrimitiveKotlinType(it) + + val refClassName = Name.identifier(it.typeName.asString() + "Ref") + val refClass = KnownClassDescriptor.createClass(refClassName, refNamespaceClass, listOf(builtIns.anyType)) + + it to PrimitiveRefDescriptorsProvider(type, refClass) + } + + private inner class ObjectRefDescriptorsProvider { + val genericRefClass: ClassDescriptor = + KnownClassDescriptor.createClassWithTypeParameters( + Name.identifier("ObjectRef"), refNamespaceClass, listOf(builtIns.anyType), listOf(Name.identifier("T")) + ) + + val genericRefConstructor: ClassConstructorDescriptor = + ClassConstructorDescriptorImpl.create(genericRefClass, Annotations.EMPTY, true, SourceElement.NO_SOURCE).apply { + initialize(emptyList(), Visibilities.PUBLIC) + val typeParameter = typeParameters[0] + val typeParameterType = KotlinTypeFactory.simpleType(Annotations.EMPTY, typeParameter.typeConstructor, listOf(), false, MemberScope.Empty) + returnType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, genericRefClass, listOf(TypeProjectionImpl(Variance.INVARIANT, typeParameterType))) + } + + val constructorTypeParameter: TypeParameterDescriptor = + genericRefConstructor.typeParameters[0] + + fun getSubstitutedRefConstructor(valueType: KotlinType): ClassConstructorDescriptor = + genericRefConstructor.substitute(TypeSubstitutor.create( + mapOf(constructorTypeParameter.typeConstructor to TypeProjectionImpl(Variance.INVARIANT, valueType)) + ))!! + + val genericElementField: PropertyDescriptor = + PropertyDescriptorImpl.create( + genericRefClass, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, true, + Name.identifier("element"), CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE, + false, false, false, false + ).initialize( + type = builtIns.anyType, + dispatchReceiverParameter = genericRefClass.thisAsReceiverParameter + ) + + fun getRefType(valueType: KotlinType) = + KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, genericRefClass, listOf(TypeProjectionImpl(Variance.INVARIANT, valueType))) + } + + private val objectRefDescriptorsProvider = ObjectRefDescriptorsProvider() + + override fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor = + LocalVariableDescriptor( + variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name, + getSharedVariableType(variableDescriptor.type), + false, false, variableDescriptor.source + ) + + override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement { + val valueType = originalDeclaration.descriptor.type + val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)] + + val refConstructor = + primitiveRefDescriptorsProvider?.refConstructor ?: + objectRefDescriptorsProvider.getSubstitutedRefConstructor(valueType) + + val refConstructorTypeArguments = + if (primitiveRefDescriptorsProvider != null) null + else mapOf(objectRefDescriptorsProvider.constructorTypeParameter to valueType) + + val elementPropertyDescriptor = + primitiveRefDescriptorsProvider?.elementField ?: + objectRefDescriptorsProvider.genericElementField + + val refConstructorCall = IrCallImpl( + originalDeclaration.startOffset, originalDeclaration.endOffset, + refConstructor, refConstructorTypeArguments + ) + val sharedVariableDeclaration = IrVariableImpl( + originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin, + sharedVariableDescriptor, refConstructorCall + ) + + val initializer = originalDeclaration.initializer ?: + return sharedVariableDeclaration + + val sharedVariableInitialization = IrSetFieldImpl( + initializer.startOffset, initializer.endOffset, + elementPropertyDescriptor, + IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDescriptor), + initializer + ) + + return IrCompositeImpl( + originalDeclaration.startOffset, originalDeclaration.endOffset, builtIns.unitType, null, + listOf(sharedVariableDeclaration, sharedVariableInitialization) + ) + } + + private fun getElementFieldDescriptor(valueType: KotlinType): PropertyDescriptor { + val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)] + + return primitiveRefDescriptorsProvider?.elementField ?: + objectRefDescriptorsProvider.genericElementField + } + + override fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression = + IrGetFieldImpl( + originalGet.startOffset, originalGet.endOffset, + getElementFieldDescriptor(originalGet.descriptor.type), + IrGetValueImpl(originalGet.startOffset, originalGet.endOffset, sharedVariableDescriptor), + originalGet.origin + ) + + override fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression = + IrSetFieldImpl( + originalSet.startOffset, originalSet.endOffset, + getElementFieldDescriptor(originalSet.descriptor.type), + IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableDescriptor), + originalSet.value, + originalSet.origin + ) + + private fun getSharedVariableType(valueType: KotlinType): KotlinType = + primitiveRefDescriptorProviders[getPrimitiveType(valueType)]?.refType ?: + objectRefDescriptorsProvider.getRefType(valueType) + + private fun getPrimitiveType(type: KotlinType): PrimitiveType? = + when { + KotlinBuiltIns.isBoolean(type) -> PrimitiveType.BOOLEAN + KotlinBuiltIns.isChar(type) -> PrimitiveType.CHAR + KotlinBuiltIns.isByte(type) -> PrimitiveType.BYTE + KotlinBuiltIns.isShort(type) -> PrimitiveType.SHORT + KotlinBuiltIns.isInt(type) -> PrimitiveType.INT + KotlinBuiltIns.isLong(type) -> PrimitiveType.LONG + KotlinBuiltIns.isFloat(type) -> PrimitiveType.FLOAT + KotlinBuiltIns.isDouble(type) -> PrimitiveType.DOUBLE + else -> null + } + +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalFunctionsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalFunctionsLowering.kt new file mode 100644 index 00000000000..c6244717116 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalFunctionsLowering.kt @@ -0,0 +1,369 @@ +/* + * 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.jvm.lower + +import org.jetbrains.kotlin.backend.common.AbstractClosureAnnotator +import org.jetbrains.kotlin.backend.common.Closure +import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.util.transformFlat +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.parents +import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf +import org.jetbrains.kotlin.types.KotlinType +import java.util.* + +class LocalFunctionsLowering(val context: JvmBackendContext): ClassLoweringPass { + override fun lower(irClass: IrClass) { + irClass.declarations.transformFlat { memberDeclaration -> + if (memberDeclaration is IrFunction) + LocalFunctionsTransformer(memberDeclaration).lowerLocalFunctions() + else + null + } + } + + private class LocalFunctionContext(val declaration: IrFunction) { + lateinit var closure: Closure + + val closureParametersCount: Int get() = closure.capturedValues.size + + lateinit var transformedDescriptor: FunctionDescriptor + + val old2new: MutableMap = HashMap() + + var index: Int = -1 + + override fun toString(): String = + "LocalFunctionContext for ${declaration.descriptor}" + } + + private inner class LocalFunctionsTransformer(val memberFunction: IrFunction) { + val localFunctions: MutableMap = LinkedHashMap() + val new2old: MutableMap = HashMap() + + fun lowerLocalFunctions(): List? { + collectLocalFunctions() + if (localFunctions.isEmpty()) return null + + collectClosures() + + transformDescriptors() + + rewriteBodies() + + return collectRewrittenDeclarations() + } + + private fun collectRewrittenDeclarations(): ArrayList = + ArrayList(localFunctions.size + 1).apply { + add(memberFunction) + + localFunctions.values.mapTo(this) { + val original = it.declaration + IrFunctionImpl( + original.startOffset, original.endOffset, original.origin, + it.transformedDescriptor, + original.body + ) + } + } + + private inner class FunctionBodiesRewriter(val localFunctionContext: LocalFunctionContext?) : IrElementTransformerVoid() { + + override fun visitClass(declaration: IrClass): IrStatement { + // ignore local classes for now + return declaration + } + + override fun visitFunction(declaration: IrFunction): IrStatement { + // replace local function definition with an empty composite + return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType) + } + + override fun visitGetValue(expression: IrGetValue): IrExpression { + val remapped = localFunctionContext?.let { it.old2new[expression.descriptor] } + return if (remapped == null) + expression + else + IrGetValueImpl(expression.startOffset, expression.endOffset, remapped, expression.origin) + } + + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + val oldCallee = expression.descriptor.original + val localFunctionData = localFunctions[oldCallee] ?: return expression + + val newCallee = localFunctionData.transformedDescriptor + + val newCall = createNewCall(expression, newCallee).fillArguments(localFunctionData, expression) + + return newCall + } + + private fun T.fillArguments(calleeContext: LocalFunctionContext, oldExpression: IrMemberAccessExpression): T { + val closureParametersCount = calleeContext.closureParametersCount + + mapValueParametersIndexed { index, newValueParameterDescriptor -> + val capturedValueDescriptor = new2old[newValueParameterDescriptor] ?: + throw AssertionError("Non-mapped parameter $newValueParameterDescriptor") + if (index >= closureParametersCount) + oldExpression.getValueArgument(capturedValueDescriptor as ValueParameterDescriptor) + else { + val remappedValueDescriptor = localFunctionContext?.let { it.old2new[capturedValueDescriptor] } + IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset, + remappedValueDescriptor ?: capturedValueDescriptor) + } + + } + + dispatchReceiver = oldExpression.dispatchReceiver + extensionReceiver = oldExpression.extensionReceiver + + return this + } + + override fun visitCallableReference(expression: IrCallableReference): IrExpression { + expression.transformChildrenVoid(this) + + val oldCallee = expression.descriptor.original + val localFunctionData = localFunctions[oldCallee] ?: return expression + val newCallee = localFunctionData.transformedDescriptor + + val newCallableReference = IrCallableReferenceImpl( + expression.startOffset, expression.endOffset, + expression.type, // TODO functional type for transformed descriptor + newCallee, + remapTypeArguments(expression, newCallee), + expression.origin + ).fillArguments(localFunctionData, expression) + + return newCallableReference + } + + override fun visitReturn(expression: IrReturn): IrExpression { + expression.transformChildrenVoid(this) + + val oldReturnTarget = expression.returnTarget + val localFunctionData = localFunctions[oldReturnTarget] ?: return expression + val newReturnTarget = localFunctionData.transformedDescriptor + + return IrReturnImpl(expression.startOffset, expression.endOffset, newReturnTarget, expression.value) + } + } + + private fun rewriteFunctionDeclaration(irFunction: IrFunction, localFunctionContext: LocalFunctionContext?) { + irFunction.transformChildrenVoid(FunctionBodiesRewriter(localFunctionContext)) + } + + private fun rewriteBodies() { + localFunctions.values.forEach { + rewriteFunctionDeclaration(it.declaration, it) + } + + rewriteFunctionDeclaration(memberFunction, null) + } + + private fun createNewCall(oldCall: IrCall, newCallee: FunctionDescriptor) = + if (oldCall is IrCallWithShallowCopy) + oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifier) + else + IrCallImpl( + oldCall.startOffset, oldCall.endOffset, + newCallee, + remapTypeArguments(oldCall, newCallee), + oldCall.origin, oldCall.superQualifier + ) + + private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: FunctionDescriptor): Map? { + val oldCallee = oldExpression.descriptor + + return if (oldCallee.typeParameters.isEmpty()) + null + else oldCallee.typeParameters.associateBy( + { newCallee.typeParameters[it.index] }, + { oldExpression.getTypeArgument(it)!! } + ) + } + + private fun transformDescriptors() { + localFunctions.values.forEach { + it.transformedDescriptor = createTransformedDescriptor(it) + } + } + + private fun suggestLocalName(descriptor: DeclarationDescriptor): String { + val localFunctionContext = localFunctions[descriptor] + return if (localFunctionContext != null && localFunctionContext.index >= 0) + "lambda-${localFunctionContext.index}" + else + descriptor.name.asString() + } + + private fun generateNameForLiftedFunction(functionDescriptor: FunctionDescriptor): Name = + Name.identifier( + functionDescriptor.parentsWithSelf + .takeWhile { it is FunctionDescriptor } + .toList().reversed() + .map { suggestLocalName(it) } + .joinToString(separator = "$") + ) + + private fun createTransformedDescriptor(localFunctionContext: LocalFunctionContext): FunctionDescriptor { + val oldDescriptor = localFunctionContext.declaration.descriptor + + val memberOwner = memberFunction.descriptor.containingDeclaration + val newDescriptor = SimpleFunctionDescriptorImpl.create( + memberOwner, + oldDescriptor.annotations, + generateNameForLiftedFunction(oldDescriptor), + CallableMemberDescriptor.Kind.SYNTHESIZED, + oldDescriptor.source + ) + + val closureParametersCount = localFunctionContext.closureParametersCount + val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size + + val newDispatchReceiverParameter = + if (memberOwner is ClassDescriptor && oldDescriptor.dispatchReceiverParameter != null) + memberOwner.thisAsReceiverParameter + else + null + + // Do not substitute type parameters for now. + val newTypeParameters = oldDescriptor.typeParameters + + val newValueParameters = ArrayList(newValueParametersCount).apply { + localFunctionContext.closure.capturedValues.mapIndexedTo(this) { i, capturedValueDescriptor -> + createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValueDescriptor, i).apply { + localFunctionContext.recordRemapped(capturedValueDescriptor, this) + } + } + + oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor -> + createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply { + localFunctionContext.recordRemapped(oldValueParameterDescriptor, this) + } + } + } + + newDescriptor.initialize( + oldDescriptor.extensionReceiverParameter?.type, + newDispatchReceiverParameter, + newTypeParameters, + newValueParameters, + oldDescriptor.returnType, + Modality.FINAL, + Visibilities.PRIVATE + ) + + return newDescriptor + } + + private fun LocalFunctionContext.recordRemapped(oldDescriptor: ValueDescriptor, newDescriptor: ValueParameterDescriptor): ValueParameterDescriptor { + old2new[oldDescriptor] = newDescriptor + new2old[newDescriptor] = oldDescriptor + return newDescriptor + } + + private fun suggestNameForCapturedValueParameter(valueDescriptor: ValueDescriptor): Name = + if (valueDescriptor.name.isSpecial) { + val oldNameStr = valueDescriptor.name.asString() + Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1)) + } + else + valueDescriptor.name + + private fun createUnsubstitutedCapturedValueParameter( + newParameterOwner: CallableMemberDescriptor, + valueDescriptor: ValueDescriptor, + index: Int + ): ValueParameterDescriptor = + ValueParameterDescriptorImpl( + newParameterOwner, null, index, + valueDescriptor.annotations, + suggestNameForCapturedValueParameter(valueDescriptor), + valueDescriptor.type, + false, false, false, false, null, valueDescriptor.source + ) + + private fun createUnsubstitutedParameter( + newParameterOwner: CallableMemberDescriptor, + valueParameterDescriptor: ValueParameterDescriptor, + newIndex: Int + ): ValueParameterDescriptor = + valueParameterDescriptor.copy(newParameterOwner, valueParameterDescriptor.name, newIndex) + + + private fun collectClosures() { + memberFunction.acceptChildrenVoid(object : AbstractClosureAnnotator() { + override fun visitClass(declaration: IrClass) { + // ignore local classes for now + return + } + + override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) { + localFunctions[functionDescriptor]?.closure = closure + } + + override fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure) { + // ignore local classes for now + } + }) + } + + private fun collectLocalFunctions() { + memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid { + var lambdasCount = 0 + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + declaration.acceptChildrenVoid(this) + val localFunctionContext = LocalFunctionContext(declaration) + localFunctions[declaration.descriptor] = localFunctionContext + if (declaration.descriptor.name.isSpecial) { + localFunctionContext.index = lambdasCount++ + } + } + + override fun visitClass(declaration: IrClass) { + // ignore local classes for now + } + }) + } + } + +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt new file mode 100644 index 00000000000..af886b3b1eb --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/SharedVariablesLowering.kt @@ -0,0 +1,131 @@ +/* + * 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.jvm.lower + +import org.jetbrains.kotlin.backend.jvm.FunctionLoweringPass +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +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.* + +class SharedVariablesLowering(val context: JvmBackendContext) : FunctionLoweringPass { + override fun lower(irFunction: IrFunction) { + SharedVariablesTransformer(irFunction).lowerSharedVariables() + } + + private inner class SharedVariablesTransformer(val irFunction: IrFunction) { + val sharedVariables = HashSet() + + fun lowerSharedVariables() { + collectSharedVariables() + if (sharedVariables.isEmpty()) return + + rewriteSharedVariables() + } + + private fun collectSharedVariables() { + irFunction.acceptVoid(object : IrElementVisitorVoid { + val declarationsStack = ArrayDeque() + val currentDeclaration: DeclarationDescriptor + get() = declarationsStack.peek().descriptor + + val relevantVars = HashSet() + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + declarationsStack.push(declaration) + declaration.acceptChildrenVoid(this) + declarationsStack.pop() + } + + override fun visitVariable(declaration: IrVariable) { + val variableDescriptor = declaration.descriptor + if (variableDescriptor.isVar) { + relevantVars.add(variableDescriptor) + } + } + + override fun visitVariableAccess(expression: IrValueAccessExpression) { + expression.acceptChildrenVoid(this) + + val descriptor = expression.descriptor + if (descriptor in relevantVars && descriptor.containingDeclaration != currentDeclaration) { + 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