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) {
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)
}
@@ -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)
}
}
}
@@ -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)
@@ -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))