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.
This commit is contained in:
Ivan Kylchik
2021-06-19 00:23:00 +03:00
committed by TeamCityServer
parent d41c6e900a
commit 7852d01da6
4 changed files with 42 additions and 39 deletions
@@ -60,7 +60,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
) )
return interpreter.withNewCallStack(irCall) { return interpreter.withNewCallStack(irCall) {
this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(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) }.wrap(this@DefaultCallInterceptor, remainArraysAsIs = false, extendFrom = expectedResultClass)
} }
@@ -157,31 +157,34 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callSt
val valueParametersSymbols = irFunction.valueParameters.map { it.symbol } 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 // evaluate arguments
(expression.valueArgumentsCount - 1 downTo 0).forEach { (expression.valueArgumentsCount - 1 downTo 0).forEach { index ->
callStack.addInstruction(CompoundInstruction(expression.getValueArgument(it))) 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) { private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceInitializerCall, callStack: CallStack) {
@@ -378,7 +381,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
val toStringCall = state.createToStringIrCall() val toStringCall = state.createToStringIrCall()
callStack.newSubFrame(toStringCall) callStack.newSubFrame(toStringCall)
callStack.addInstruction(SimpleInstruction(toStringCall)) callStack.addInstruction(SimpleInstruction(toStringCall))
callStack.addVariable(Variable(toStringCall.symbol.owner.dispatchReceiverParameter!!.symbol, state)) callStack.pushState(state)
} }
} }
} }
@@ -164,6 +164,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
// outer classes can be used in default args evaluation // outer classes can be used in default args evaluation
if (isReceiver() && state is Complex) state.loadOuterClassesInto(callStack) if (isReceiver() && state is Complex) state.loadOuterClassesInto(callStack)
callStack.pushState(state)
} }
private fun interpretCall(call: IrCall) { private fun interpretCall(call: IrCall) {
@@ -176,9 +177,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val owner = call.symbol.owner val owner = call.symbol.owner
// 1. load evaluated arguments from stack // 1. load evaluated arguments from stack
val dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getState(it) } val valueArguments = owner.valueParameters.map { callStack.popState() }.reversed().toMutableList()
val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getState(it) } val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.popState() }
val valueArguments = owner.valueParameters.map { callStack.getState(it.symbol) }.toMutableList() val dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.popState() }
// 2. get correct function for interpretation // 2. get correct function for interpretation
val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner 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) // 4. store arguments in memory (remap args on actual names)
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> callStack.addVariable(Variable(it, receiver)) } } 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())) } irFunction.valueParameters.forEach { callStack.addVariable(Variable(it.symbol, valueArguments.removeFirst())) }
// 5. store reified type parameters // 5. store reified type parameters
@@ -240,7 +241,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) { private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) {
val constructor = constructorCall.symbol.owner 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 irClass = constructor.parentAsClass
val receiverSymbol = constructor.dispatchReceiverParameter?.symbol val receiverSymbol = constructor.dispatchReceiverParameter?.symbol
@@ -255,7 +256,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
} }
if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure) if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
val outerClass = receiverSymbol?.let { callStack.getState(it) } val outerClass = receiverSymbol?.let { callStack.popState() }
callStack.dropSubFrame() callStack.dropSubFrame()
callStack.newFrame(constructor) callStack.newFrame(constructor)
@@ -603,8 +604,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretFunctionReference(reference: IrFunctionReference) { private fun interpretFunctionReference(reference: IrFunctionReference) {
val irFunction = reference.symbol.owner val irFunction = reference.symbol.owner
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getState(irFunction.getDispatchReceiver()!!) } val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() }
val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) } val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() }
callStack.dropSubFrame() callStack.dropSubFrame()
@@ -618,10 +619,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
} }
private fun interpretPropertyReference(propertyReference: IrPropertyReference) { 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) // it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null)
val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver) val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver)
?.let { callStack.getState(receiverSymbol!!) } ?.let { callStack.popState() }
callStack.dropSubFrame() callStack.dropSubFrame()
val propertyState = KPropertyState(propertyReference, receiver) val propertyState = KPropertyState(propertyReference, receiver)
@@ -83,13 +83,13 @@ internal class KFunctionState(
val dispatchParameter = irFunction.dispatchReceiverParameter val dispatchParameter = irFunction.dispatchReceiverParameter
val extensionParameter = irFunction.extensionReceiverParameter val extensionParameter = irFunction.extensionReceiverParameter
if (dispatchParameter != null && getField(dispatchParameter.symbol) == null) { if (dispatchParameter != null) {
dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchParameter.type, dispatchParameter.symbol) 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) 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 { irFunction.valueParameters.forEach {
putArgument(it, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, it.symbol)) putArgument(it, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, it.symbol))