From 7852d01da629751df72ef5f47a49333192fe6ff4 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sat, 19 Jun 2021 00:23:00 +0300 Subject: [PATCH] Rewrite interpreter logic around arguments evaluation For now calculated arguments will be stored on stack instead of memory. At first this was done because of problems with default arguments, but in the next commit this problem will be solved. --- .../kotlin/ir/interpreter/CallInterceptor.kt | 2 +- .../ir/interpreter/InstructionsUnfolder.kt | 51 ++++++++++--------- .../kotlin/ir/interpreter/IrInterpreter.kt | 20 ++++---- .../state/reflection/KFunctionState.kt | 8 +-- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index 7835561cabb..facb499a38b 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -60,7 +60,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : ) return interpreter.withNewCallStack(irCall) { this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall)) - valueArguments.forEach { this@withNewCallStack.environment.callStack.addVariable(it) } + valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it.state) } }.wrap(this@DefaultCallInterceptor, remainArraysAsIs = false, extendFrom = expectedResultClass) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index 801edeb039e..d6cbe622c67 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -157,31 +157,34 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callSt val valueParametersSymbols = irFunction.valueParameters.map { it.symbol } - // interpret defaults for null arguments (at the end) - (expression.valueArgumentsCount - 1 downTo 0).forEach { index -> - if (expression.getValueArgument(index) != null) return@forEach - callStack.addInstruction(SimpleInstruction(valueParametersSymbols[index].owner)) - - getDefaultForParameterAt(index) - ?.let { callStack.addInstruction(CompoundInstruction(it)) } - ?: expression.getVarargType(index)?.let { // case when value parameter is vararg and it is missing - callStack.addInstruction(SimpleInstruction(IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it))) - } - } - - // interpret not null arguments (after evaluation of arguments) - expression.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(irFunction.dispatchReceiverParameter!!)) } - expression.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(irFunction.extensionReceiverParameter!!)) } - (0 until expression.valueArgumentsCount).forEach { - if (expression.getValueArgument(it) != null) callStack.addInstruction(SimpleInstruction(irFunction.valueParameters[it])) - } - // evaluate arguments - (expression.valueArgumentsCount - 1 downTo 0).forEach { - callStack.addInstruction(CompoundInstruction(expression.getValueArgument(it))) + (expression.valueArgumentsCount - 1 downTo 0).forEach { index -> + when { + expression.getValueArgument(index) != null -> { + // interpret arguments that were passed + callStack.addInstruction(SimpleInstruction(irFunction.valueParameters[index])) + callStack.addInstruction(CompoundInstruction(expression.getValueArgument(index))) + } + else -> { + // interpret defaults for null arguments + callStack.addInstruction(SimpleInstruction(valueParametersSymbols[index].owner)) + + getDefaultForParameterAt(index) + ?.let { callStack.addInstruction(CompoundInstruction(it)) } + ?: expression.getVarargType(index)?.let { // case when value parameter is vararg and it is missing + callStack.addInstruction(SimpleInstruction(IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it))) + } + } + } + } + expression.extensionReceiver?.let { + callStack.addInstruction(SimpleInstruction(irFunction.extensionReceiverParameter!!)) + callStack.addInstruction(CompoundInstruction(it)) + } + expression.dispatchReceiver?.let { + callStack.addInstruction(SimpleInstruction(irFunction.dispatchReceiverParameter!!)) + callStack.addInstruction(CompoundInstruction(it)) } - expression.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } - expression.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } } private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceInitializerCall, callStack: CallStack) { @@ -378,7 +381,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ val toStringCall = state.createToStringIrCall() callStack.newSubFrame(toStringCall) callStack.addInstruction(SimpleInstruction(toStringCall)) - callStack.addVariable(Variable(toStringCall.symbol.owner.dispatchReceiverParameter!!.symbol, state)) + callStack.pushState(state) } } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 46c183aeef1..f318b1eb95c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -164,6 +164,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal // outer classes can be used in default args evaluation if (isReceiver() && state is Complex) state.loadOuterClassesInto(callStack) + callStack.pushState(state) } private fun interpretCall(call: IrCall) { @@ -176,9 +177,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal val owner = call.symbol.owner // 1. load evaluated arguments from stack - val dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getState(it) } - val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getState(it) } - val valueArguments = owner.valueParameters.map { callStack.getState(it.symbol) }.toMutableList() + val valueArguments = owner.valueParameters.map { callStack.popState() }.reversed().toMutableList() + val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.popState() } + val dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.popState() } // 2. get correct function for interpretation val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner @@ -199,7 +200,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal // 4. store arguments in memory (remap args on actual names) irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> callStack.addVariable(Variable(it, receiver)) } } - irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: valueArguments.removeFirst())) } + irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: callStack.getState(it))) } irFunction.valueParameters.forEach { callStack.addVariable(Variable(it.symbol, valueArguments.removeFirst())) } // 5. store reified type parameters @@ -240,7 +241,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) { val constructor = constructorCall.symbol.owner - val valueArguments = constructor.valueParameters.map { callStack.getState(it.symbol) } + val valueArguments = constructor.valueParameters.map { callStack.popState() }.reversed() val irClass = constructor.parentAsClass val receiverSymbol = constructor.dispatchReceiverParameter?.symbol @@ -255,7 +256,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal } if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure) - val outerClass = receiverSymbol?.let { callStack.getState(it) } + val outerClass = receiverSymbol?.let { callStack.popState() } callStack.dropSubFrame() callStack.newFrame(constructor) @@ -603,8 +604,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal private fun interpretFunctionReference(reference: IrFunctionReference) { val irFunction = reference.symbol.owner - val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getState(irFunction.getDispatchReceiver()!!) } - val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) } + val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() } + val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() } callStack.dropSubFrame() @@ -618,10 +619,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal } private fun interpretPropertyReference(propertyReference: IrPropertyReference) { - val receiverSymbol = propertyReference.getter?.owner?.let { it.getDispatchReceiver() ?: it.getExtensionReceiver() } // it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null) val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver) - ?.let { callStack.getState(receiverSymbol!!) } + ?.let { callStack.popState() } callStack.dropSubFrame() val propertyState = KPropertyState(propertyReference, receiver) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt index 994e91c9dca..4148c48d0ab 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt @@ -83,13 +83,13 @@ internal class KFunctionState( val dispatchParameter = irFunction.dispatchReceiverParameter val extensionParameter = irFunction.extensionReceiverParameter - if (dispatchParameter != null && getField(dispatchParameter.symbol) == null) { + if (dispatchParameter != null) { dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchParameter.type, dispatchParameter.symbol) - (this@impl.valueParameters as MutableList).add(dispatchParameter) + if (getField(dispatchParameter.symbol) == null) (this@impl.valueParameters as MutableList).add(dispatchParameter) } - if (extensionParameter != null && getField(extensionParameter.symbol) == null) { + if (extensionParameter != null) { extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionParameter.type, extensionParameter.symbol) - (this@impl.valueParameters as MutableList).add(extensionParameter) + if (getField(extensionParameter.symbol) == null) (this@impl.valueParameters as MutableList).add(extensionParameter) } irFunction.valueParameters.forEach { putArgument(it, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, it.symbol))