Rewrite unfoldValueParameters to take into account recursive calls
The workflow of evaluation value arguments is now like this: 1. Calculate not null arguments 2. Add them into intermediate stack 3. Calculate defaults for those parameters that have no argument This flow allow us to avoid early addition of variable onto stack.
This commit is contained in:
committed by
TeamCityServer
parent
6411d09579
commit
b4463b948c
+48
-66
@@ -83,84 +83,67 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack)
|
||||
}
|
||||
|
||||
private fun unfoldCall(call: IrCall, callStack: CallStack) {
|
||||
val function = call.symbol.owner
|
||||
// new sub frame is used to store value arguments, in case then they are used in default args evaluation
|
||||
callStack.newSubFrame(call, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(call))
|
||||
unfoldValueParameters(call, callStack)
|
||||
|
||||
// must save receivers in memory in case then they are used in default args evaluation
|
||||
call.extensionReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
call.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, callStack: CallStack) {
|
||||
val constructor = constructorCall.symbol.owner
|
||||
callStack.newSubFrame(constructorCall, listOf()) // used to store value arguments, in case then they are use as default args
|
||||
unfoldValueParameters(constructorCall, callStack)
|
||||
// this variable is used to create object once
|
||||
callStack.addVariable(Variable(constructorCall.getThisReceiver(), Common(constructor.parentAsClass)))
|
||||
callStack.addInstruction(SimpleInstruction(constructorCall))
|
||||
unfoldValueParameters(constructorCall, callStack)
|
||||
|
||||
constructorCall.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(constructor.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, callStack: CallStack) {
|
||||
callStack.newSubFrame(enumConstructorCall, listOf()) // used to store value arguments, in case then they are use as default args
|
||||
callStack.addInstruction(SimpleInstruction(enumConstructorCall))
|
||||
unfoldValueParameters(enumConstructorCall, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctionAccessExpression, callStack: CallStack) {
|
||||
callStack.newSubFrame(delegatingConstructorCall, listOf()) // used to store value arguments, in case then they are use as default args
|
||||
callStack.addInstruction(SimpleInstruction(delegatingConstructorCall))
|
||||
unfoldValueParameters(delegatingConstructorCall, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
||||
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
||||
return defaultValue
|
||||
?: (this.parent as? IrSimpleFunction)?.overriddenSymbols
|
||||
?.map { it.owner.valueParameters[this.index].getDefault() }
|
||||
?.firstNotNullOfOrNull { it }
|
||||
}
|
||||
val irFunction = expression.symbol.owner
|
||||
// new sub frame is used to store value arguments, in case then they are used in default args evaluation
|
||||
callStack.newSubFrame(expression, listOf(SimpleInstruction(expression)))
|
||||
|
||||
fun getDefaultForParameterAt(index: Int): IrExpression? {
|
||||
return expression.symbol.owner.valueParameters[index].getDefault()?.expression
|
||||
}
|
||||
|
||||
val irFunction = expression.symbol.owner
|
||||
val valueParametersSymbols = irFunction.valueParameters.map { it.symbol }
|
||||
val valueArguments = (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it) }
|
||||
|
||||
for (i in valueParametersSymbols.indices.reversed()) {
|
||||
callStack.addInstruction(SimpleInstruction(valueParametersSymbols[i].owner))
|
||||
val arg = valueArguments[i] ?: getDefaultForParameterAt(i)
|
||||
when {
|
||||
arg != null -> callStack.addInstruction(CompoundInstruction(arg))
|
||||
else ->
|
||||
// case when value parameter is vararg and it is missing
|
||||
expression.getVarargType(i)?.let {
|
||||
callStack.addInstruction(SimpleInstruction(IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it)))
|
||||
}
|
||||
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
||||
return defaultValue
|
||||
?: (this.parent as? IrSimpleFunction)?.overriddenSymbols
|
||||
?.map { it.owner.valueParameters[this.index].getDefault() }
|
||||
?.firstNotNullOfOrNull { it }
|
||||
}
|
||||
|
||||
return irFunction.valueParameters[index].getDefault()?.expression
|
||||
}
|
||||
|
||||
// hack for extension receiver in lambda
|
||||
if (expression.valueArgumentsCount != irFunction.valueParameters.size) {
|
||||
val extensionReceiver = irFunction.getExtensionReceiver() ?: return
|
||||
callStack.addInstruction(SimpleInstruction(extensionReceiver.owner))
|
||||
valueArguments[0]?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
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.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
expression.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
}
|
||||
|
||||
private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceInitializerCall, callStack: CallStack) {
|
||||
@@ -360,7 +343,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
|
||||
toStringCall.dispatchReceiver = IrConstImpl.constNull(0, 0, receiver.type) // just stub receiver
|
||||
|
||||
callStack.newSubFrame(toStringCall, listOf(SimpleInstruction(toStringCall)))
|
||||
callStack.pushState(state)
|
||||
callStack.addVariable(Variable(receiver.symbol, state))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,22 +365,21 @@ private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
||||
|
||||
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
|
||||
val function = reference.symbol.owner
|
||||
callStack.newSubFrame(reference, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(reference))
|
||||
callStack.newSubFrame(reference, listOf(SimpleInstruction(reference)))
|
||||
|
||||
reference.extensionReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
reference.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) }
|
||||
reference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) }
|
||||
|
||||
reference.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
reference.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
}
|
||||
|
||||
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(propertyReference))
|
||||
callStack.addInstruction(CompoundInstruction(propertyReference.dispatchReceiver))
|
||||
propertyReference.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(propertyReference.getter!!.owner.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
|
||||
|
||||
+12
-11
@@ -163,14 +163,14 @@ class IrInterpreter private constructor(
|
||||
|
||||
//must add value argument in current stack because it can be used later as default argument
|
||||
callStack.addVariable(Variable(valueParameter.symbol, state))
|
||||
callStack.pushState(state)
|
||||
}
|
||||
|
||||
private fun interpretCall(call: IrCall) {
|
||||
val owner = call.symbol.owner
|
||||
// 1. load evaluated arguments from stack
|
||||
val valueArguments = call.symbol.owner.valueParameters.map { callStack.popState() }.reversed()
|
||||
val extensionReceiver = call.extensionReceiver?.let { callStack.popState() }
|
||||
var dispatchReceiver = call.dispatchReceiver?.let { callStack.popState() }
|
||||
var dispatchReceiver = call.dispatchReceiver?.let { callStack.getVariable(owner.getDispatchReceiver()!!) }?.state
|
||||
val extensionReceiver = call.extensionReceiver?.let { callStack.getVariable(owner.getExtensionReceiver()!!) }?.state
|
||||
val valueArguments = owner.valueParameters.map { callStack.getVariable(it.symbol).state }
|
||||
|
||||
// 2. get correct function for interpretation
|
||||
val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner
|
||||
@@ -179,13 +179,13 @@ class IrInterpreter private constructor(
|
||||
else -> dispatchReceiver
|
||||
}
|
||||
|
||||
callStack.dropSubFrame()
|
||||
callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation
|
||||
callStack.newFrame(irFunction, listOf(SimpleInstruction(irFunction)))
|
||||
// TODO: if using KTypeState then it's class must be corresponding
|
||||
// `call.type` is used in check cast and emptyArray
|
||||
callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner)))
|
||||
|
||||
// 3. store arguments in memory
|
||||
// 3. store arguments in memory (remap args on actual names)
|
||||
val args = mutableListOf<Variable>()
|
||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> args.add(Variable(it, receiver)) } }
|
||||
irFunction.getExtensionReceiver()?.let { args.add(Variable(it, extensionReceiver ?: valueArguments.first())) }
|
||||
@@ -241,12 +241,12 @@ class IrInterpreter private constructor(
|
||||
}
|
||||
|
||||
private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) {
|
||||
val valueArguments = constructorCall.symbol.owner.valueParameters.map { callStack.popState() }.reversed()
|
||||
val valueArguments = constructorCall.symbol.owner.valueParameters.map { callStack.getVariable(it.symbol).state }
|
||||
val constructor = constructorCall.symbol.owner
|
||||
val irClass = constructor.parentAsClass
|
||||
val objectVar = callStack.getVariable(constructorCall.getThisReceiver())
|
||||
if (irClass.isLocal) callStack.storeUpValues(objectVar.state as StateWithClosure)
|
||||
val outerClass = if (irClass.isInner) callStack.popState() else null
|
||||
val outerClass = if (irClass.isInner) callStack.getVariable(constructor.dispatchReceiverParameter!!.symbol).state else null
|
||||
|
||||
callStack.dropSubFrame()
|
||||
callStack.newFrame(constructor, listOf(SimpleInstruction(constructor)))
|
||||
@@ -564,8 +564,8 @@ class IrInterpreter private constructor(
|
||||
val function = KFunctionState(reference)
|
||||
val irFunction = function.irFunction
|
||||
|
||||
val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() }
|
||||
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() }
|
||||
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getVariable(irFunction.getDispatchReceiver()!!) }?.state
|
||||
val extensionReceiver = reference.extensionReceiver?.let { callStack.getVariable(irFunction.getExtensionReceiver()!!) }?.state
|
||||
|
||||
callStack.dropSubFrame()
|
||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields.add(Variable(it, receiver)) } }
|
||||
@@ -576,7 +576,8 @@ class IrInterpreter private constructor(
|
||||
}
|
||||
|
||||
private fun interpretPropertyReference(propertyReference: IrPropertyReference) {
|
||||
val dispatchReceiver = propertyReference.dispatchReceiver?.let { callStack.popState() }
|
||||
val dispatchReceiverSymbol = propertyReference.getter?.owner?.getDispatchReceiver()
|
||||
val dispatchReceiver = propertyReference.dispatchReceiver?.let { callStack.getVariable(dispatchReceiverSymbol!!) }?.state
|
||||
// it is impossible to get KProperty2 through ::, so extension receiver is always null
|
||||
val propertyState = KPropertyState(propertyReference, dispatchReceiver)
|
||||
callStack.pushState(propertyState)
|
||||
|
||||
@@ -179,11 +179,6 @@ fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun State?.extractNonLocalDeclarations(): List<Variable> {
|
||||
this ?: return listOf()
|
||||
return this.fields.filter { it.symbol !is IrFieldSymbol }
|
||||
}
|
||||
|
||||
internal fun IrFunction.getCapitalizedFileName() = this.file.name.replace(".kt", "Kt").capitalizeAsciiOnly()
|
||||
|
||||
internal fun IrType.isUnsigned() = this.isUByte() || this.isUShort() || this.isUInt() || this.isULong()
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@ internal class CallStack {
|
||||
}
|
||||
|
||||
fun copyUpValuesFromPreviousFrame() {
|
||||
frames[frames.size - 2].getAll().forEach { addVariable(it) }
|
||||
frames[frames.size - 2].getAll().forEach { if (!containsVariable(it.symbol)) addVariable(it) }
|
||||
}
|
||||
|
||||
fun getStackTrace(): List<String> {
|
||||
|
||||
Reference in New Issue
Block a user