[IR] Rewrite how interpreter works with the Unit result
This way interpreter works in more correct way. Every expression produces some result, and if we don't need it, the interpreter will discard it.
This commit is contained in:
+5
-7
@@ -18,15 +18,12 @@ import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
|
|||||||
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
|
||||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
internal fun IrExpression.handleAndDropResult(callStack: CallStack, dropOnlyUnit: Boolean = false) {
|
internal fun IrExpression.handleAndDropResult(callStack: CallStack) {
|
||||||
val dropResult = fun() {
|
val dropResult = fun() { callStack.popState() }
|
||||||
if (!dropOnlyUnit && !this.type.isUnit() || callStack.peekState().isUnit()) callStack.popState()
|
|
||||||
}
|
|
||||||
callStack.pushInstruction(CustomInstruction(dropResult))
|
callStack.pushInstruction(CustomInstruction(dropResult))
|
||||||
callStack.pushCompoundInstruction(this)
|
callStack.pushCompoundInstruction(this)
|
||||||
}
|
}
|
||||||
@@ -212,6 +209,7 @@ private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceIni
|
|||||||
val toInitialize = irClass.declarations.filter { it is IrProperty || it is IrAnonymousInitializer }
|
val toInitialize = irClass.declarations.filter { it is IrProperty || it is IrAnonymousInitializer }
|
||||||
val state = irClass.thisReceiver?.symbol?.let { callStack.loadState(it) } // try to avoid recalculation of properties
|
val state = irClass.thisReceiver?.symbol?.let { callStack.loadState(it) } // try to avoid recalculation of properties
|
||||||
|
|
||||||
|
callStack.pushSimpleInstruction(instanceInitializerCall)
|
||||||
toInitialize.reversed().forEach {
|
toInitialize.reversed().forEach {
|
||||||
when {
|
when {
|
||||||
it is IrAnonymousInitializer -> callStack.pushCompoundInstruction(it.body)
|
it is IrAnonymousInitializer -> callStack.pushCompoundInstruction(it.body)
|
||||||
@@ -258,7 +256,7 @@ private fun unfoldStatements(statements: List<IrStatement>, callStack: CallStack
|
|||||||
is IrExpression ->
|
is IrExpression ->
|
||||||
when {
|
when {
|
||||||
i.isLastIndex() -> callStack.pushCompoundInstruction(statement)
|
i.isLastIndex() -> callStack.pushCompoundInstruction(statement)
|
||||||
else -> statement.handleAndDropResult(callStack, dropOnlyUnit = true)
|
else -> statement.handleAndDropResult(callStack)
|
||||||
}
|
}
|
||||||
else -> callStack.pushCompoundInstruction(statement)
|
else -> callStack.pushCompoundInstruction(statement)
|
||||||
}
|
}
|
||||||
@@ -435,7 +433,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
|
|||||||
private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
||||||
when (element.origin) {
|
when (element.origin) {
|
||||||
IrStatementOrigin.DESTRUCTURING_DECLARATION, IrStatementOrigin.DO_WHILE_LOOP, null -> // is null for body of do while loop
|
IrStatementOrigin.DESTRUCTURING_DECLARATION, IrStatementOrigin.DO_WHILE_LOOP, null -> // is null for body of do while loop
|
||||||
element.statements.reversed().forEach { callStack.pushCompoundInstruction(it) }
|
unfoldStatements(element.statements, callStack)
|
||||||
else -> TODO("${element.origin} not implemented")
|
else -> TODO("${element.origin} not implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-10
@@ -63,7 +63,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
callStack.popInstruction().handle()
|
callStack.popInstruction().handle()
|
||||||
}
|
}
|
||||||
|
|
||||||
return environment.stateToIrExpression(callStack.popState(), expression).apply { callStack.dropFrame() }
|
return environment.stateToIrExpression(extractResultAndAssertThatStackIsEmpty(), expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun withNewCallStack(call: IrCall, init: IrInterpreter.() -> Any?): State {
|
internal fun withNewCallStack(call: IrCall, init: IrInterpreter.() -> Any?): State {
|
||||||
@@ -75,10 +75,17 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
callStack.popInstruction().handle()
|
callStack.popInstruction().handle()
|
||||||
}
|
}
|
||||||
|
|
||||||
callStack.popState().apply { callStack.dropFrame() }
|
extractResultAndAssertThatStackIsEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun extractResultAndAssertThatStackIsEmpty(): State {
|
||||||
|
val result = callStack.popState()
|
||||||
|
assert(callStack.peekState() == null)
|
||||||
|
callStack.dropFrame()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private fun interpret(element: IrElement) {
|
private fun interpret(element: IrElement) {
|
||||||
when (element) {
|
when (element) {
|
||||||
is IrSimpleFunction -> interpretFunction(element)
|
is IrSimpleFunction -> interpretFunction(element)
|
||||||
@@ -87,6 +94,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
is IrConstructorCall -> interpretConstructorCall(element)
|
is IrConstructorCall -> interpretConstructorCall(element)
|
||||||
is IrEnumConstructorCall -> interpretEnumConstructorCall(element)
|
is IrEnumConstructorCall -> interpretEnumConstructorCall(element)
|
||||||
is IrDelegatingConstructorCall -> interpretDelegatingConstructorCall(element)
|
is IrDelegatingConstructorCall -> interpretDelegatingConstructorCall(element)
|
||||||
|
is IrInstanceInitializerCall -> callStack.pushState(getUnitState())
|
||||||
is IrValueParameter -> interpretValueParameter(element)
|
is IrValueParameter -> interpretValueParameter(element)
|
||||||
is IrField -> interpretField(element)
|
is IrField -> interpretField(element)
|
||||||
is IrBody -> interpretBody(element)
|
is IrBody -> interpretBody(element)
|
||||||
@@ -98,13 +106,13 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
is IrGetEnumValue -> interpretGetEnumValue(element)
|
is IrGetEnumValue -> interpretGetEnumValue(element)
|
||||||
is IrEnumEntry -> interpretEnumEntry(element)
|
is IrEnumEntry -> interpretEnumEntry(element)
|
||||||
is IrConst<*> -> interpretConst(element)
|
is IrConst<*> -> interpretConst(element)
|
||||||
is IrVariable -> callStack.storeState(element.symbol, callStack.popState())
|
is IrVariable -> interpretVariable(element)
|
||||||
is IrSetValue -> callStack.rewriteState(element.symbol, callStack.popState())
|
is IrSetValue -> interpretSetValue(element)
|
||||||
is IrTypeOperatorCall -> interpretTypeOperatorCall(element)
|
is IrTypeOperatorCall -> interpretTypeOperatorCall(element)
|
||||||
is IrBranch -> interpretBranch(element)
|
is IrBranch -> interpretBranch(element)
|
||||||
is IrWhileLoop -> interpretWhile(element)
|
is IrWhileLoop -> interpretWhile(element)
|
||||||
is IrDoWhileLoop -> interpretDoWhile(element)
|
is IrDoWhileLoop -> interpretDoWhile(element)
|
||||||
is IrWhen -> callStack.dropSubFrame()
|
is IrWhen -> interpretWhen(element)
|
||||||
is IrVararg -> interpretVararg(element)
|
is IrVararg -> interpretVararg(element)
|
||||||
is IrTry -> interpretTry(element)
|
is IrTry -> interpretTry(element)
|
||||||
is IrThrow -> interpretThrow(element)
|
is IrThrow -> interpretThrow(element)
|
||||||
@@ -198,15 +206,13 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
receiverState.setField(field.correspondingPropertySymbol!!, callStack.popState())
|
receiverState.setField(field.correspondingPropertySymbol!!, callStack.popState())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
private fun interpretBody(body: IrBody) {
|
private fun interpretBody(body: IrBody) {
|
||||||
if (callStack.peekState() == null) callStack.pushState(getUnitState()) // implicit Unit result
|
if (body.statements.isEmpty()) callStack.pushState(getUnitState()) // implicit Unit result
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
private fun interpretBlock(block: IrBlock) {
|
private fun interpretBlock(block: IrBlock) {
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
if (callStack.peekState() == null) callStack.pushState(getUnitState()) // implicit Unit result
|
if (block.statements.isEmpty()) callStack.pushState(getUnitState()) // implicit Unit result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretConstructor(constructor: IrConstructor) {
|
private fun interpretConstructor(constructor: IrConstructor) {
|
||||||
@@ -267,6 +273,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
callInterceptor.interceptConstructor(constructorCall, valueArguments) {
|
callInterceptor.interceptConstructor(constructorCall, valueArguments) {
|
||||||
callStack.pushCompoundInstruction(constructor)
|
callStack.pushCompoundInstruction(constructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callStack.pushState(getUnitState())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretDelegatingConstructorCall(constructorCall: IrDelegatingConstructorCall) {
|
private fun interpretDelegatingConstructorCall(constructorCall: IrDelegatingConstructorCall) {
|
||||||
@@ -300,6 +308,16 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
callStack.pushState(expression.toPrimitive())
|
callStack.pushState(expression.toPrimitive())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun interpretVariable(variable: IrVariable) {
|
||||||
|
callStack.storeState(variable.symbol, callStack.popState())
|
||||||
|
callStack.pushState(getUnitState())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun interpretSetValue(expression: IrSetValue) {
|
||||||
|
callStack.rewriteState(expression.symbol, callStack.popState())
|
||||||
|
callStack.pushState(getUnitState())
|
||||||
|
}
|
||||||
|
|
||||||
private fun interpretReturn(expression: IrReturn) {
|
private fun interpretReturn(expression: IrReturn) {
|
||||||
callStack.returnFromFrameWithResult(expression)
|
callStack.returnFromFrameWithResult(expression)
|
||||||
}
|
}
|
||||||
@@ -326,10 +344,18 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
private fun interpretWhen(whenExpression: IrWhen) {
|
||||||
|
// This method is reachable only if none of the branches were selected.
|
||||||
|
// In that case, we just return `Unit` result that will be dropped later.
|
||||||
|
callStack.dropSubFrame()
|
||||||
|
callStack.pushState(getUnitState())
|
||||||
|
}
|
||||||
|
|
||||||
private fun interpretBranch(branch: IrBranch) {
|
private fun interpretBranch(branch: IrBranch) {
|
||||||
val result = callStack.popState().asBoolean()
|
val result = callStack.popState().asBoolean()
|
||||||
if (result) {
|
if (result) {
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame() // drop entire `when` expression from frame
|
||||||
callStack.pushCompoundInstruction(branch.result)
|
callStack.pushCompoundInstruction(branch.result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,6 +364,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
val receiver = (expression.receiver as IrDeclarationReference).symbol
|
val receiver = (expression.receiver as IrDeclarationReference).symbol
|
||||||
val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!!
|
val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!!
|
||||||
callStack.loadState(receiver).apply { this.setField(propertySymbol, callStack.popState()) }
|
callStack.loadState(receiver).apply { this.setField(propertySymbol, callStack.popState()) }
|
||||||
|
callStack.pushState(getUnitState())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretGetField(expression: IrGetField) {
|
private fun interpretGetField(expression: IrGetField) {
|
||||||
|
|||||||
+1
-4
@@ -1,9 +1,7 @@
|
|||||||
@CompileTimeCalculation
|
@CompileTimeCalculation
|
||||||
class A {
|
class A {
|
||||||
const val a = <!EVALUATED: `10`!>{ 10 }()<!> // lambda is needed to avoid computions by old frontend
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val static = <!EVALUATED: `-10`!>{ -10 }()<!>
|
const val static = <!EVALUATED: `-10`!>{ -10 }()<!> // lambda is needed to avoid computions by old frontend
|
||||||
|
|
||||||
fun getStaticNumber(): Int {
|
fun getStaticNumber(): Int {
|
||||||
return Int.MAX_VALUE
|
return Int.MAX_VALUE
|
||||||
@@ -21,7 +19,6 @@ object ObjectWithConst {
|
|||||||
fun concat(first: String, second: Any) = "$first$second"
|
fun concat(first: String, second: Any) = "$first$second"
|
||||||
}
|
}
|
||||||
|
|
||||||
const val num = <!EVALUATED: `10`!>A().a<!>
|
|
||||||
const val numStatic = <!EVALUATED: `-10`!>A.static<!>
|
const val numStatic = <!EVALUATED: `-10`!>A.static<!>
|
||||||
const val numStaticFromFun = <!EVALUATED: `2147483647`!>A.getStaticNumber()<!>
|
const val numStaticFromFun = <!EVALUATED: `2147483647`!>A.getStaticNumber()<!>
|
||||||
const val valFromObject = <!EVALUATED: `Value in a: 100`!>ObjectWithConst.b<!>
|
const val valFromObject = <!EVALUATED: `Value in a: 100`!>ObjectWithConst.b<!>
|
||||||
|
|||||||
Reference in New Issue
Block a user