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) {
|
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)
|
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) {
|
private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, callStack: CallStack) {
|
||||||
val constructor = constructorCall.symbol.owner
|
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
|
// this variable is used to create object once
|
||||||
callStack.addVariable(Variable(constructorCall.getThisReceiver(), Common(constructor.parentAsClass)))
|
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) {
|
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)
|
unfoldValueParameters(enumConstructorCall, callStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctionAccessExpression, callStack: 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)
|
unfoldValueParameters(delegatingConstructorCall, callStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
||||||
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
val irFunction = expression.symbol.owner
|
||||||
return defaultValue
|
// new sub frame is used to store value arguments, in case then they are used in default args evaluation
|
||||||
?: (this.parent as? IrSimpleFunction)?.overriddenSymbols
|
callStack.newSubFrame(expression, listOf(SimpleInstruction(expression)))
|
||||||
?.map { it.owner.valueParameters[this.index].getDefault() }
|
|
||||||
?.firstNotNullOfOrNull { it }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDefaultForParameterAt(index: Int): IrExpression? {
|
fun getDefaultForParameterAt(index: Int): IrExpression? {
|
||||||
return expression.symbol.owner.valueParameters[index].getDefault()?.expression
|
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
||||||
}
|
return defaultValue
|
||||||
|
?: (this.parent as? IrSimpleFunction)?.overriddenSymbols
|
||||||
val irFunction = expression.symbol.owner
|
?.map { it.owner.valueParameters[this.index].getDefault() }
|
||||||
val valueParametersSymbols = irFunction.valueParameters.map { it.symbol }
|
?.firstNotNullOfOrNull { it }
|
||||||
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)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return irFunction.valueParameters[index].getDefault()?.expression
|
||||||
}
|
}
|
||||||
|
|
||||||
// hack for extension receiver in lambda
|
val valueParametersSymbols = irFunction.valueParameters.map { it.symbol }
|
||||||
if (expression.valueArgumentsCount != irFunction.valueParameters.size) {
|
|
||||||
val extensionReceiver = irFunction.getExtensionReceiver() ?: return
|
// interpret defaults for null arguments (at the end)
|
||||||
callStack.addInstruction(SimpleInstruction(extensionReceiver.owner))
|
(expression.valueArgumentsCount - 1 downTo 0).forEach { index ->
|
||||||
valueArguments[0]?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
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) {
|
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
|
toStringCall.dispatchReceiver = IrConstImpl.constNull(0, 0, receiver.type) // just stub receiver
|
||||||
|
|
||||||
callStack.newSubFrame(toStringCall, listOf(SimpleInstruction(toStringCall)))
|
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) {
|
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
|
||||||
val function = reference.symbol.owner
|
val function = reference.symbol.owner
|
||||||
callStack.newSubFrame(reference, listOf())
|
callStack.newSubFrame(reference, listOf(SimpleInstruction(reference)))
|
||||||
callStack.addInstruction(SimpleInstruction(reference))
|
|
||||||
|
|
||||||
reference.extensionReceiver?.let {
|
reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) }
|
||||||
callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!))
|
reference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) }
|
||||||
callStack.addInstruction(CompoundInstruction(it))
|
|
||||||
}
|
reference.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||||
reference.dispatchReceiver?.let {
|
reference.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||||
callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!))
|
|
||||||
callStack.addInstruction(CompoundInstruction(it))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
||||||
callStack.addInstruction(SimpleInstruction(propertyReference))
|
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) {
|
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
|
//must add value argument in current stack because it can be used later as default argument
|
||||||
callStack.addVariable(Variable(valueParameter.symbol, state))
|
callStack.addVariable(Variable(valueParameter.symbol, state))
|
||||||
callStack.pushState(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretCall(call: IrCall) {
|
private fun interpretCall(call: IrCall) {
|
||||||
|
val owner = call.symbol.owner
|
||||||
// 1. load evaluated arguments from stack
|
// 1. load evaluated arguments from stack
|
||||||
val valueArguments = call.symbol.owner.valueParameters.map { callStack.popState() }.reversed()
|
var dispatchReceiver = call.dispatchReceiver?.let { callStack.getVariable(owner.getDispatchReceiver()!!) }?.state
|
||||||
val extensionReceiver = call.extensionReceiver?.let { callStack.popState() }
|
val extensionReceiver = call.extensionReceiver?.let { callStack.getVariable(owner.getExtensionReceiver()!!) }?.state
|
||||||
var dispatchReceiver = call.dispatchReceiver?.let { callStack.popState() }
|
val valueArguments = owner.valueParameters.map { callStack.getVariable(it.symbol).state }
|
||||||
|
|
||||||
// 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
|
||||||
@@ -179,13 +179,13 @@ class IrInterpreter private constructor(
|
|||||||
else -> dispatchReceiver
|
else -> dispatchReceiver
|
||||||
}
|
}
|
||||||
|
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation
|
||||||
callStack.newFrame(irFunction, listOf(SimpleInstruction(irFunction)))
|
callStack.newFrame(irFunction, listOf(SimpleInstruction(irFunction)))
|
||||||
// TODO: if using KTypeState then it's class must be corresponding
|
// TODO: if using KTypeState then it's class must be corresponding
|
||||||
// `call.type` is used in check cast and emptyArray
|
// `call.type` is used in check cast and emptyArray
|
||||||
callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner)))
|
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>()
|
val args = mutableListOf<Variable>()
|
||||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> args.add(Variable(it, receiver)) } }
|
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> args.add(Variable(it, receiver)) } }
|
||||||
irFunction.getExtensionReceiver()?.let { args.add(Variable(it, extensionReceiver ?: valueArguments.first())) }
|
irFunction.getExtensionReceiver()?.let { args.add(Variable(it, extensionReceiver ?: valueArguments.first())) }
|
||||||
@@ -241,12 +241,12 @@ class IrInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) {
|
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 constructor = constructorCall.symbol.owner
|
||||||
val irClass = constructor.parentAsClass
|
val irClass = constructor.parentAsClass
|
||||||
val objectVar = callStack.getVariable(constructorCall.getThisReceiver())
|
val objectVar = callStack.getVariable(constructorCall.getThisReceiver())
|
||||||
if (irClass.isLocal) callStack.storeUpValues(objectVar.state as StateWithClosure)
|
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.dropSubFrame()
|
||||||
callStack.newFrame(constructor, listOf(SimpleInstruction(constructor)))
|
callStack.newFrame(constructor, listOf(SimpleInstruction(constructor)))
|
||||||
@@ -564,8 +564,8 @@ class IrInterpreter private constructor(
|
|||||||
val function = KFunctionState(reference)
|
val function = KFunctionState(reference)
|
||||||
val irFunction = function.irFunction
|
val irFunction = function.irFunction
|
||||||
|
|
||||||
val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() }
|
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getVariable(irFunction.getDispatchReceiver()!!) }?.state
|
||||||
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() }
|
val extensionReceiver = reference.extensionReceiver?.let { callStack.getVariable(irFunction.getExtensionReceiver()!!) }?.state
|
||||||
|
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields.add(Variable(it, receiver)) } }
|
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) {
|
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
|
// it is impossible to get KProperty2 through ::, so extension receiver is always null
|
||||||
val propertyState = KPropertyState(propertyReference, dispatchReceiver)
|
val propertyState = KPropertyState(propertyReference, dispatchReceiver)
|
||||||
callStack.pushState(propertyState)
|
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 IrFunction.getCapitalizedFileName() = this.file.name.replace(".kt", "Kt").capitalizeAsciiOnly()
|
||||||
|
|
||||||
internal fun IrType.isUnsigned() = this.isUByte() || this.isUShort() || this.isUInt() || this.isULong()
|
internal fun IrType.isUnsigned() = this.isUByte() || this.isUShort() || this.isUInt() || this.isULong()
|
||||||
|
|||||||
+1
-1
@@ -187,7 +187,7 @@ internal class CallStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun copyUpValuesFromPreviousFrame() {
|
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> {
|
fun getStackTrace(): List<String> {
|
||||||
|
|||||||
Reference in New Issue
Block a user