PrivateMembersLowering

This commit is contained in:
Anton Bannykh
2019-12-25 14:02:02 +03:00
committed by Anton Bannykh
parent f6d4ea469c
commit 3165556c6b
4 changed files with 132 additions and 123 deletions
@@ -50,8 +50,6 @@ class JsIrBackendContext(
override val lateinitNullableFields
get() = error("Use Mapping.lateInitFieldToNullableField instead")
val memberMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
override val builtIns = module.builtIns
override var inVerbosePhase: Boolean = false
@@ -247,6 +247,12 @@ private val privateMembersLoweringPhase = makeJsModulePhase(
description = "Extract private members from classes"
)
private val privateMemberUsagesLoweringPhase = makeJsModulePhase(
::PrivateMemberBodiesLowering,
name = "PrivateMemberUsagesLowering",
description = "Rewrite the private member usages"
)
private val callableReferenceLoweringPhase = makeJsModulePhase(
::CallableReferenceLowering,
name = "CallableReferenceLowering",
@@ -486,6 +492,7 @@ val jsPhases = namedIrModulePhase(
propertyAccessorInlinerLoweringPhase then
foldConstantLoweringPhase then
privateMembersLoweringPhase then
privateMemberUsagesLoweringPhase then
callableReferenceLoweringPhase then
defaultArgumentStubGeneratorPhase then
defaultArgumentPatchOverridesPhase then
@@ -18,4 +18,5 @@ class JsMapping : DefaultMapping() {
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
val objectToInstanceField = newMapping<IrClass, IrField>()
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
}
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.*
@@ -17,56 +17,143 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {}
class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass {
private val memberMap = context.memberMap
class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
override fun lower(irFile: IrFile) {
transformPrivateDeclarations(irFile)
transformPrivateUseSites(irFile)
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
return when (declaration) {
is IrSimpleFunction -> transformMemberToStaticFunction(declaration)?.let { staticFunction ->
declaration.correspondingStatic = staticFunction
listOf(staticFunction)
}
is IrProperty -> listOf(declaration.apply {
// Detach old function from corresponding property
this.getter = this.getter?.let { g -> transformAccessor(g) }
this.setter = this.setter?.let { s -> transformAccessor(s) }
})
else -> null
}
}
private fun transformPrivateDeclarations(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid(this)
declaration.declarations.transformFlat {
when (it) {
is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction ->
listOf(staticFunction)
}
is IrProperty -> listOf(it.apply {
this.getter = this.getter?.let { g -> transformAccessor(g) }
this.setter = this.setter?.let { s -> transformAccessor(s) }
})
else -> null
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
val descriptor = WrappedSimpleFunctionDescriptor()
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
val staticFunction = function.run {
IrFunctionImpl(
startOffset, endOffset, origin,
symbol, name, visibility, modality,
returnType,
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
isOperator = isOperator
).also {
descriptor.bind(it)
it.parent = parent
it.correspondingPropertySymbol = correspondingPropertySymbol
}
}
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
val thisDesc = WrappedValueParameterDescriptor()
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
staticFunction.valueParameters += IrValueParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
STATIC_THIS_PARAMETER,
thisSymbol,
Name.identifier("\$this"),
0,
function.dispatchReceiverParameter!!.type,
null,
isCrossinline = false,
isNoinline = false
).also {
thisDesc.bind(it)
it.parent = staticFunction
}
function.correspondingStatic = staticFunction
staticFunction.valueParameters += function.valueParameters.map {
// TODO better way to avoid copying default value
it.copyTo(staticFunction, index = it.index + 1, defaultValue = null)
}
val oldParameters =
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
assert(oldParameters.size == newParameters.size)
val parameterMapping = oldParameters.zip(newParameters).toMap()
val parameterTransformer = object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
} ?: expression
}
fun IrBody.copyWithParameters(): IrBody {
return deepCopyWithSymbols(staticFunction).also {
it.transform(parameterTransformer, null)
}
}
function.valueParameters.forEach {
// TODO better way to avoid copying default value
parameterMapping[it]?.apply {
it.defaultValue?.let { originalDefault ->
defaultValue = IrExpressionBodyImpl(it.startOffset, it.endOffset) {
expression = (originalDefault.copyWithParameters() as IrExpressionBody).expression
}
}
return declaration
}
})
}
}
private fun transformPrivateUseSites(irFile: IrFile) {
irFile.transform(object : IrElementTransformerVoid() {
function.body?.let {
staticFunction.body = when (it) {
is IrBlockBody -> IrBlockBodyImpl(it.startOffset, it.endOffset) {
statements += (it.copyWithParameters() as IrBlockBody).statements
}
is IrExpressionBody -> IrExpressionBodyImpl(it.startOffset, it.endOffset) {
expression = (it.copyWithParameters() as IrExpressionBody).expression
}
is IrSyntheticBody -> it
else -> error("Unexpected body kind: ${it.javaClass}")
}
}
return staticFunction
}
}
class PrivateMemberBodiesLowering(val context: JsIrBackendContext) : BodyLoweringPass {
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transform(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression)
return getOrPutStaticFunction(expression.symbol)?.let {
return expression.symbol.owner.correspondingStatic?.let {
transformPrivateToStaticCall(expression, it)
} ?: expression
}
@@ -74,7 +161,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
super.visitFunctionReference(expression)
return getOrPutStaticFunction(expression.symbol)?.let {
return expression.symbol.owner.correspondingStatic?.let {
transformPrivateToStaticReference(expression) {
IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset,
@@ -89,8 +176,8 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
super.visitPropertyReference(expression)
val staticGetter = expression.getter?.let { getOrPutStaticFunction(it) }
val staticSetter = expression.setter?.let { getOrPutStaticFunction(it) }
val staticGetter = expression.getter?.owner?.correspondingStatic
val staticSetter = expression.setter?.owner?.correspondingStatic
return if (staticGetter != null || staticSetter != null) {
transformPrivateToStaticReference(expression) {
@@ -147,88 +234,4 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
}
}, null)
}
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
val staticFunction = getOrPutStaticFunction(function.symbol) ?: return null
// Detach old function from corresponding property
val correspondingProperty = function.correspondingPropertySymbol?.owner
if (correspondingProperty != null) {
when (function) {
correspondingProperty.getter -> correspondingProperty.getter = staticFunction
correspondingProperty.setter -> correspondingProperty.setter = staticFunction
}
}
val oldParameters =
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
assert(oldParameters.size == newParameters.size)
val parameterMapping = oldParameters.zip(newParameters).toMap()
staticFunction.body = function.body?.deepCopyWithSymbols(staticFunction)
staticFunction.transform(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
} ?: expression
}, null)
return staticFunction
}
private fun getOrPutStaticFunction(functionSymbol: IrFunctionSymbol): IrSimpleFunction? {
val function = functionSymbol.owner
if (function !is IrSimpleFunction) return null
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
return memberMap.getOrPut(function.symbol) {
val descriptor = WrappedSimpleFunctionDescriptor()
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
val staticFunction = function.run {
IrFunctionImpl(
startOffset, endOffset, origin,
symbol, name, visibility, modality,
returnType,
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
isOperator = isOperator
).also {
descriptor.bind(it)
it.parent = parent
it.correspondingPropertySymbol = correspondingPropertySymbol
}
}
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
val thisDesc = WrappedValueParameterDescriptor()
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
staticFunction.valueParameters += IrValueParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
STATIC_THIS_PARAMETER,
thisSymbol,
Name.identifier("\$this"),
0,
function.dispatchReceiverParameter!!.type,
null,
isCrossinline = false,
isNoinline = false
).also {
thisDesc.bind(it)
it.parent = staticFunction
}
staticFunction.valueParameters += function.valueParameters.map { it.copyTo(staticFunction, index = it.index + 1) }
staticFunction
}
}
}