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.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@@ -35,10 +36,10 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
|
||||
null -> return
|
||||
is IrSimpleFunction -> unfoldFunction(element, environment)
|
||||
is IrConstructor -> unfoldConstructor(element, callStack)
|
||||
is IrCall -> unfoldValueParameters(element, callStack)
|
||||
is IrConstructorCall -> unfoldValueParameters(element, callStack)
|
||||
is IrEnumConstructorCall -> unfoldValueParameters(element, callStack)
|
||||
is IrDelegatingConstructorCall -> unfoldValueParameters(element, callStack)
|
||||
is IrCall -> unfoldValueParameters(element, environment)
|
||||
is IrConstructorCall -> unfoldValueParameters(element, environment)
|
||||
is IrEnumConstructorCall -> unfoldValueParameters(element, environment)
|
||||
is IrDelegatingConstructorCall -> unfoldValueParameters(element, environment)
|
||||
is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack)
|
||||
is IrField -> unfoldField(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 }
|
||||
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
|
||||
val actualParameters = MutableList<IrValueDeclaration?>(expression.valueArgumentsCount) { null }
|
||||
val ownerWithDefaults = expression.getFunctionThatContainsDefaults()
|
||||
|
||||
val visibility = when (expression) {
|
||||
is IrEnumConstructorCall, is IrDelegatingConstructorCall -> DescriptorVisibilities.LOCAL
|
||||
else -> ownerWithDefaults.visibility
|
||||
@@ -128,14 +135,20 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callSt
|
||||
this.dispatchReceiverParameter = ownerWithDefaults.dispatchReceiverParameter?.deepCopyWithSymbols(this)
|
||||
this.extensionReceiverParameter = ownerWithDefaults.extensionReceiverParameter?.deepCopyWithSymbols(this)
|
||||
(0 until expression.valueArgumentsCount).forEach { index ->
|
||||
val parameter = ownerWithDefaults.valueParameters[index]
|
||||
actualParameters[index] = if (expression.getValueArgument(index) != null) {
|
||||
parameter.deepCopyWithSymbols(this).also { this.valueParameters += it }
|
||||
} else {
|
||||
parameter.createTempVariable().apply variable@{
|
||||
this@variable.initializer = parameter.getDefaultWithActualParameters(this@apply, actualParameters)
|
||||
?: expression.getVarargType(index)?.let { null.toIrConst(it) } // if parameter is vararg and it is missing
|
||||
val originalParameter = ownerWithDefaults.valueParameters[index]
|
||||
val copiedParameter = originalParameter.deepCopyWithSymbols(this)
|
||||
this.valueParameters += copiedParameter
|
||||
actualParameters[index] = if (copiedParameter.defaultValue != null) {
|
||||
copiedParameter.type = copiedParameter.type.makeNullable() // make nullable type to keep consistency; parameter can be null if it is missing
|
||||
val irGetParameter = copiedParameter.createGetValue()
|
||||
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()) }
|
||||
defaultFun.body = (actualParameters.filterIsInstance<IrVariable>() + defaultFun.createReturn(callWithAllArgs)).wrapWithBlockBody()
|
||||
|
||||
environment.cachedFunctionsWithDefaults[ownerWithDefaults.symbol] = defaultFun.symbol
|
||||
val callToDefault = defaultFun.createCall().apply { expression.copyArgsInto(this) }
|
||||
callStack.addInstruction(CompoundInstruction(callToDefault))
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.interpreter
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
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.interpreter.stack.CallStack
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.Common
|
||||
@@ -24,6 +23,7 @@ class IrInterpreterEnvironment(
|
||||
internal val irExceptions = mutableListOf<IrClass>()
|
||||
internal var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
|
||||
internal var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
|
||||
internal var cachedFunctionsWithDefaults = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
||||
internal var cachedLambdasAndReferences = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
||||
|
||||
init {
|
||||
|
||||
+23
-5
@@ -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
|
||||
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 {
|
||||
@@ -166,9 +166,27 @@ internal fun IrFunctionAccessExpression.shallowCopy(copyTypeArguments: Boolean =
|
||||
}
|
||||
|
||||
internal fun IrFunctionAccessExpression.copyArgsInto(newCall: IrFunctionAccessExpression) {
|
||||
val symbol = this.symbol.owner
|
||||
newCall.dispatchReceiver = this.dispatchReceiver
|
||||
newCall.extensionReceiver = this.extensionReceiver
|
||||
(0 until this.valueArgumentsCount)
|
||||
.mapNotNull { this.getValueArgument(it) }
|
||||
.forEachIndexed { i, arg -> newCall.putValueArgument(i, arg) }
|
||||
}
|
||||
.map { this.getValueArgument(it) }
|
||||
.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