Implement simple cache for dynamically created wrapper for defaults
This commit is contained in:
committed by
TeamCityServer
parent
09c31b0900
commit
3fc5405d57
+28
-14
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
|||||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
import org.jetbrains.kotlin.ir.types.isUnit
|
||||||
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
@@ -35,10 +36,10 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
|
|||||||
null -> return
|
null -> return
|
||||||
is IrSimpleFunction -> unfoldFunction(element, environment)
|
is IrSimpleFunction -> unfoldFunction(element, environment)
|
||||||
is IrConstructor -> unfoldConstructor(element, callStack)
|
is IrConstructor -> unfoldConstructor(element, callStack)
|
||||||
is IrCall -> unfoldValueParameters(element, callStack)
|
is IrCall -> unfoldValueParameters(element, environment)
|
||||||
is IrConstructorCall -> unfoldValueParameters(element, callStack)
|
is IrConstructorCall -> unfoldValueParameters(element, environment)
|
||||||
is IrEnumConstructorCall -> unfoldValueParameters(element, callStack)
|
is IrEnumConstructorCall -> unfoldValueParameters(element, environment)
|
||||||
is IrDelegatingConstructorCall -> unfoldValueParameters(element, callStack)
|
is IrDelegatingConstructorCall -> unfoldValueParameters(element, environment)
|
||||||
is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack)
|
is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack)
|
||||||
is IrField -> unfoldField(element, callStack)
|
is IrField -> unfoldField(element, callStack)
|
||||||
is IrBody -> unfoldBody(element, callStack)
|
is IrBody -> unfoldBody(element, callStack)
|
||||||
@@ -108,13 +109,19 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, environment: IrInterpreterEnvironment) {
|
||||||
|
val callStack = environment.callStack
|
||||||
val hasDefaults = (0 until expression.valueArgumentsCount).any { expression.getValueArgument(it) == null }
|
val hasDefaults = (0 until expression.valueArgumentsCount).any { expression.getValueArgument(it) == null }
|
||||||
if (hasDefaults) {
|
if (hasDefaults) {
|
||||||
|
val ownerWithDefaults = expression.getFunctionThatContainsDefaults()
|
||||||
|
environment.cachedFunctionsWithDefaults[ownerWithDefaults.symbol]?.let {
|
||||||
|
val callToDefault = it.owner.createCall().apply { expression.copyArgsInto(this) }
|
||||||
|
callStack.addInstruction(CompoundInstruction(callToDefault))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// if some arguments are not defined, then it is necessary to create temp function where defaults will be evaluated
|
// if some arguments are not defined, then it is necessary to create temp function where defaults will be evaluated
|
||||||
val actualParameters = MutableList<IrValueDeclaration?>(expression.valueArgumentsCount) { null }
|
val actualParameters = MutableList<IrValueDeclaration?>(expression.valueArgumentsCount) { null }
|
||||||
val ownerWithDefaults = expression.getFunctionThatContainsDefaults()
|
|
||||||
|
|
||||||
val visibility = when (expression) {
|
val visibility = when (expression) {
|
||||||
is IrEnumConstructorCall, is IrDelegatingConstructorCall -> DescriptorVisibilities.LOCAL
|
is IrEnumConstructorCall, is IrDelegatingConstructorCall -> DescriptorVisibilities.LOCAL
|
||||||
else -> ownerWithDefaults.visibility
|
else -> ownerWithDefaults.visibility
|
||||||
@@ -128,14 +135,20 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callSt
|
|||||||
this.dispatchReceiverParameter = ownerWithDefaults.dispatchReceiverParameter?.deepCopyWithSymbols(this)
|
this.dispatchReceiverParameter = ownerWithDefaults.dispatchReceiverParameter?.deepCopyWithSymbols(this)
|
||||||
this.extensionReceiverParameter = ownerWithDefaults.extensionReceiverParameter?.deepCopyWithSymbols(this)
|
this.extensionReceiverParameter = ownerWithDefaults.extensionReceiverParameter?.deepCopyWithSymbols(this)
|
||||||
(0 until expression.valueArgumentsCount).forEach { index ->
|
(0 until expression.valueArgumentsCount).forEach { index ->
|
||||||
val parameter = ownerWithDefaults.valueParameters[index]
|
val originalParameter = ownerWithDefaults.valueParameters[index]
|
||||||
actualParameters[index] = if (expression.getValueArgument(index) != null) {
|
val copiedParameter = originalParameter.deepCopyWithSymbols(this)
|
||||||
parameter.deepCopyWithSymbols(this).also { this.valueParameters += it }
|
this.valueParameters += copiedParameter
|
||||||
} else {
|
actualParameters[index] = if (copiedParameter.defaultValue != null) {
|
||||||
parameter.createTempVariable().apply variable@{
|
copiedParameter.type = copiedParameter.type.makeNullable() // make nullable type to keep consistency; parameter can be null if it is missing
|
||||||
this@variable.initializer = parameter.getDefaultWithActualParameters(this@apply, actualParameters)
|
val irGetParameter = copiedParameter.createGetValue()
|
||||||
?: expression.getVarargType(index)?.let { null.toIrConst(it) } // if parameter is vararg and it is missing
|
val defaultInitializer = originalParameter.getDefaultWithActualParameters(this@apply, actualParameters)
|
||||||
|
?: expression.getVarargType(index)?.let { null.toIrConst(it) } // if parameter is vararg and it is missing
|
||||||
|
|
||||||
|
copiedParameter.createTempVariable().apply variable@{
|
||||||
|
this@variable.initializer = environment.irBuiltIns.irIfNullThenElse(irGetParameter, defaultInitializer!!, irGetParameter)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
copiedParameter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,6 +159,7 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callSt
|
|||||||
(0 until expression.valueArgumentsCount).forEach { callWithAllArgs.putValueArgument(it, actualParameters[it]?.createGetValue()) }
|
(0 until expression.valueArgumentsCount).forEach { callWithAllArgs.putValueArgument(it, actualParameters[it]?.createGetValue()) }
|
||||||
defaultFun.body = (actualParameters.filterIsInstance<IrVariable>() + defaultFun.createReturn(callWithAllArgs)).wrapWithBlockBody()
|
defaultFun.body = (actualParameters.filterIsInstance<IrVariable>() + defaultFun.createReturn(callWithAllArgs)).wrapWithBlockBody()
|
||||||
|
|
||||||
|
environment.cachedFunctionsWithDefaults[ownerWithDefaults.symbol] = defaultFun.symbol
|
||||||
val callToDefault = defaultFun.createCall().apply { expression.copyArgsInto(this) }
|
val callToDefault = defaultFun.createCall().apply { expression.copyArgsInto(this) }
|
||||||
callStack.addInstruction(CompoundInstruction(callToDefault))
|
callStack.addInstruction(CompoundInstruction(callToDefault))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.interpreter
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.Common
|
import org.jetbrains.kotlin.ir.interpreter.state.Common
|
||||||
@@ -24,6 +23,7 @@ class IrInterpreterEnvironment(
|
|||||||
internal val irExceptions = mutableListOf<IrClass>()
|
internal val irExceptions = mutableListOf<IrClass>()
|
||||||
internal var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
|
internal var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
|
||||||
internal var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
|
internal var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
|
||||||
|
internal var cachedFunctionsWithDefaults = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
||||||
internal var cachedLambdasAndReferences = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
internal var cachedLambdasAndReferences = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
+22
-4
@@ -99,9 +99,9 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrFunction.createCall(): IrCall {
|
internal fun IrFunction.createCall(origin: IrStatementOrigin? = null): IrCall {
|
||||||
this as IrSimpleFunction
|
this as IrSimpleFunction
|
||||||
return IrCallImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, returnType, symbol, typeParameters.size, valueParameters.size)
|
return IrCallImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, returnType, symbol, typeParameters.size, valueParameters.size, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrConstructor.createConstructorCall(): IrConstructorCall {
|
internal fun IrConstructor.createConstructorCall(): IrConstructorCall {
|
||||||
@@ -166,9 +166,27 @@ internal fun IrFunctionAccessExpression.shallowCopy(copyTypeArguments: Boolean =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrFunctionAccessExpression.copyArgsInto(newCall: IrFunctionAccessExpression) {
|
internal fun IrFunctionAccessExpression.copyArgsInto(newCall: IrFunctionAccessExpression) {
|
||||||
|
val symbol = this.symbol.owner
|
||||||
newCall.dispatchReceiver = this.dispatchReceiver
|
newCall.dispatchReceiver = this.dispatchReceiver
|
||||||
newCall.extensionReceiver = this.extensionReceiver
|
newCall.extensionReceiver = this.extensionReceiver
|
||||||
(0 until this.valueArgumentsCount)
|
(0 until this.valueArgumentsCount)
|
||||||
.mapNotNull { this.getValueArgument(it) }
|
.map { this.getValueArgument(it) }
|
||||||
.forEachIndexed { i, arg -> newCall.putValueArgument(i, arg) }
|
.forEachIndexed { i, arg ->
|
||||||
|
newCall.putValueArgument(i, arg ?: IrConstImpl.constNull(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, symbol.valueParameters[i].type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrBuiltIns.irEquals(arg1: IrExpression, arg2: IrExpression): IrCall {
|
||||||
|
val equalsCall = this.eqeqSymbol.owner.createCall(IrStatementOrigin.EQEQ)
|
||||||
|
equalsCall.putValueArgument(0, arg1)
|
||||||
|
equalsCall.putValueArgument(1, arg2)
|
||||||
|
return equalsCall
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun IrBuiltIns.irIfNullThenElse(nullableArg: IrExpression, ifTrue: IrExpression, ifFalse: IrExpression): IrWhen {
|
||||||
|
val nullCondition = this.irEquals(nullableArg, IrConstImpl.constNull(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, this.anyNType))
|
||||||
|
val trueBranch = IrBranchImpl(nullCondition, ifTrue) // use default
|
||||||
|
val elseBranch = IrElseBranchImpl(IrConstImpl.constTrue(0, 0, this.booleanType), ifFalse)
|
||||||
|
|
||||||
|
return IrIfThenElseImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, ifTrue.type).apply { branches += listOf(trueBranch, elseBranch) }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user