Create and implement ExecutionResult interface to use as return status
This is replacement for Code enum class that was returned from methods of interpreter earlier
This commit is contained in:
+130
-169
@@ -22,10 +22,6 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import java.lang.invoke.MethodHandle
|
import java.lang.invoke.MethodHandle
|
||||||
|
|
||||||
enum class Code(var info: String = "") {
|
|
||||||
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val MAX_STACK_SIZE = 10_000
|
private const val MAX_STACK_SIZE = 10_000
|
||||||
|
|
||||||
class IrInterpreter(irModule: IrModuleFragment) {
|
class IrInterpreter(irModule: IrModuleFragment) {
|
||||||
@@ -55,38 +51,23 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun Code.check(toCheck: Code = Code.NEXT, returnBlock: (Code) -> Unit): Code {
|
|
||||||
if (this != toCheck) returnBlock(this)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun Code.checkForReturn(newFrame: Frame, oldFrame: Frame, returnBlock: (Code) -> Unit): Code {
|
|
||||||
if (this != Code.NEXT) {
|
|
||||||
if ((this == Code.RETURN || this == Code.EXCEPTION) && newFrame.hasReturnValue()) {
|
|
||||||
oldFrame.pushReturnValue(newFrame)
|
|
||||||
}
|
|
||||||
returnBlock(this)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interpret(expression: IrExpression): IrExpression {
|
fun interpret(expression: IrExpression): IrExpression {
|
||||||
val data = InterpreterFrame()
|
val data = InterpreterFrame()
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
return@runBlocking when (val code = withContext(this.coroutineContext) { expression.interpret(data) }) {
|
return@runBlocking when (val returnLabel = withContext(this.coroutineContext) { expression.interpret(data).returnLabel }) {
|
||||||
Code.NEXT -> data.popReturnValue().toIrExpression(expression)
|
ReturnLabel.NEXT -> data.popReturnValue().toIrExpression(expression)
|
||||||
Code.EXCEPTION -> {
|
ReturnLabel.EXCEPTION -> {
|
||||||
val message = (data.popReturnValue() as ExceptionState).getFullDescription()
|
val message = (data.popReturnValue() as ExceptionState).getFullDescription()
|
||||||
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + message)
|
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + message)
|
||||||
}
|
}
|
||||||
else -> TODO("$code not supported as result of interpretation")
|
else -> TODO("$returnLabel not supported as result of interpretation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun IrElement.interpret(data: Frame): Code {
|
private suspend fun IrElement.interpret(data: Frame): ExecutionResult {
|
||||||
try {
|
try {
|
||||||
val code = when (this) {
|
val executionResult = when (this) {
|
||||||
is IrFunctionImpl -> interpretFunction(this, data)
|
is IrFunctionImpl -> interpretFunction(this, data)
|
||||||
is IrCall -> interpretCall(this, data)
|
is IrCall -> interpretCall(this, data)
|
||||||
is IrConstructorCall -> interpretConstructorCall(this, data)
|
is IrConstructorCall -> interpretConstructorCall(this, data)
|
||||||
@@ -123,28 +104,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
else -> TODO("${this.javaClass} not supported")
|
else -> TODO("${this.javaClass} not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (code) { // TODO move to label class
|
return executionResult.getNextLabel(this, data) { runBlocking { this@getNextLabel.interpret(it) } }
|
||||||
Code.RETURN -> when (this) {
|
|
||||||
is IrCall -> if (code.info == this.symbol.descriptor.toString()) Code.NEXT else code
|
|
||||||
is IrReturnableBlock -> if (code.info == this.symbol.descriptor.toString()) Code.NEXT else code
|
|
||||||
is IrFunctionImpl -> if (code.info == this.descriptor.toString()) Code.NEXT else code
|
|
||||||
else -> code
|
|
||||||
}
|
|
||||||
Code.BREAK_WHEN -> when (this) {
|
|
||||||
is IrWhen -> Code.NEXT
|
|
||||||
else -> code
|
|
||||||
}
|
|
||||||
Code.BREAK_LOOP -> when (this) {
|
|
||||||
is IrWhileLoop -> if ((this.label ?: "") == code.info) Code.NEXT else code
|
|
||||||
else -> code
|
|
||||||
}
|
|
||||||
Code.CONTINUE -> when (this) {
|
|
||||||
is IrWhileLoop -> if ((this.label ?: "") == code.info) this.interpret(data) else code
|
|
||||||
else -> code
|
|
||||||
}
|
|
||||||
Code.EXCEPTION -> Code.EXCEPTION
|
|
||||||
Code.NEXT -> Code.NEXT
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
// catch exception from JVM such as: ArithmeticException, StackOverflowError and others
|
// catch exception from JVM such as: ArithmeticException, StackOverflowError and others
|
||||||
val exceptionName = e::class.java.simpleName
|
val exceptionName = e::class.java.simpleName
|
||||||
@@ -159,12 +119,12 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.pushReturnValue(exceptionState)
|
data.pushReturnValue(exceptionState)
|
||||||
return Code.EXCEPTION
|
return Exception
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method is used to get stack trace after exception
|
// this method is used to get stack trace after exception
|
||||||
private suspend fun interpretFunction(irFunction: IrFunctionImpl, data: Frame): Code {
|
private suspend fun interpretFunction(irFunction: IrFunctionImpl, data: Frame): ExecutionResult {
|
||||||
return try {
|
return try {
|
||||||
yield()
|
yield()
|
||||||
|
|
||||||
@@ -189,15 +149,15 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun MethodHandle?.invokeMethod(irFunction: IrFunction, data: Frame): Code {
|
private suspend fun MethodHandle?.invokeMethod(irFunction: IrFunction, data: Frame): ExecutionResult {
|
||||||
this ?: return handleIntrinsicMethods(irFunction, data)
|
this ?: return handleIntrinsicMethods(irFunction, data)
|
||||||
val result = this.invokeWithArguments(irFunction.getArgsForMethodInvocation(data))
|
val result = this.invokeWithArguments(irFunction.getArgsForMethodInvocation(data))
|
||||||
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
||||||
|
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleIntrinsicMethods(irFunction: IrFunction, data: Frame): Code {
|
private suspend fun handleIntrinsicMethods(irFunction: IrFunction, data: Frame): ExecutionResult {
|
||||||
when (irFunction.name.asString()) {
|
when (irFunction.name.asString()) {
|
||||||
"emptyArray" -> {
|
"emptyArray" -> {
|
||||||
val result = emptyArray<Any?>()
|
val result = emptyArray<Any?>()
|
||||||
@@ -233,7 +193,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
if (enumEntry == null) {
|
if (enumEntry == null) {
|
||||||
val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName"
|
val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName"
|
||||||
data.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stackTrace))
|
data.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stackTrace))
|
||||||
return Code.EXCEPTION
|
return Exception
|
||||||
} else {
|
} else {
|
||||||
enumEntry.interpret(data).check { return it }
|
enumEntry.interpret(data).check { return it }
|
||||||
}
|
}
|
||||||
@@ -262,10 +222,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
else -> throw AssertionError("Unsupported intrinsic ${irFunction.name}")
|
else -> throw AssertionError("Unsupported intrinsic ${irFunction.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun calculateAbstract(irFunction: IrFunction, data: Frame): Code {
|
private suspend fun calculateAbstract(irFunction: IrFunction, data: Frame): ExecutionResult {
|
||||||
if (irFunction.body == null) {
|
if (irFunction.body == null) {
|
||||||
val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex
|
val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex
|
||||||
val instance = receiver.getOriginal()
|
val instance = receiver.getOriginal()
|
||||||
@@ -281,7 +241,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
return irFunction.body!!.interpret(data)
|
return irFunction.body!!.interpret(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun calculateOverridden(owner: IrSimpleFunction, data: Frame): Code {
|
private suspend fun calculateOverridden(owner: IrSimpleFunction, data: Frame): ExecutionResult {
|
||||||
val variableDescriptor = owner.symbol.getReceiver()!!
|
val variableDescriptor = owner.symbol.getReceiver()!!
|
||||||
val superQualifier = (data.getVariableState(variableDescriptor) as? Complex)?.superClass
|
val superQualifier = (data.getVariableState(variableDescriptor) as? Complex)?.superClass
|
||||||
if (superQualifier == null) {
|
if (superQualifier == null) {
|
||||||
@@ -303,7 +263,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}.apply { data.pushReturnValue(newStates) }
|
}.apply { data.pushReturnValue(newStates) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun calculateBuiltIns(irFunction: IrFunction, data: Frame): Code {
|
private suspend fun calculateBuiltIns(irFunction: IrFunction, data: Frame): ExecutionResult {
|
||||||
val descriptor = irFunction.descriptor
|
val descriptor = irFunction.descriptor
|
||||||
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
|
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
|
||||||
null -> descriptor.name.asString()
|
null -> descriptor.name.asString()
|
||||||
@@ -339,10 +299,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun calculateRangeTo(type: IrType, data: Frame): Code {
|
private suspend fun calculateRangeTo(type: IrType, data: Frame): ExecutionResult {
|
||||||
val constructor = type.classOrNull!!.owner.constructors.first()
|
val constructor = type.classOrNull!!.owner.constructors.first()
|
||||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||||
|
|
||||||
@@ -354,20 +314,18 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
||||||
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
||||||
|
|
||||||
val code = constructorCall.interpret(newFrame)
|
return constructorCall.interpret(newFrame).apply { data.pushReturnValue(newFrame) }
|
||||||
data.pushReturnValue(newFrame)
|
|
||||||
return code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code {
|
private suspend fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): ExecutionResult {
|
||||||
val defaultValues = (parametersContainer.symbol.owner as IrFunction).valueParameters.map { it.defaultValue }
|
val defaultValues = (parametersContainer.symbol.owner as IrFunction).valueParameters.map { it.defaultValue }
|
||||||
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
|
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
|
||||||
(parametersContainer.getValueArgument(i)?.interpret(data) ?: defaultValues[i]!!.expression.interpret(data)).check { return it }
|
(parametersContainer.getValueArgument(i)?.interpret(data) ?: defaultValues[i]!!.expression.interpret(data)).check { return it }
|
||||||
}
|
}
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretCall(expression: IrCall, data: Frame): Code {
|
private suspend fun interpretCall(expression: IrCall, data: Frame): ExecutionResult {
|
||||||
val newFrame = InterpreterFrame()
|
val newFrame = InterpreterFrame()
|
||||||
|
|
||||||
// dispatch receiver processing
|
// dispatch receiver processing
|
||||||
@@ -409,7 +367,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
|
|
||||||
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
|
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
|
||||||
val isInterfaceDefaultMethod = irFunction.body != null && (irFunction.parent as? IrClass)?.isInterface == true
|
val isInterfaceDefaultMethod = irFunction.body != null && (irFunction.parent as? IrClass)?.isInterface == true
|
||||||
val code = when {
|
val executionResult = when {
|
||||||
isWrapper && !isInterfaceDefaultMethod -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame)
|
isWrapper && !isInterfaceDefaultMethod -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame)
|
||||||
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, newFrame)
|
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, newFrame)
|
||||||
irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
|
irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
|
||||||
@@ -418,10 +376,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
else -> irFunction.interpret(newFrame)
|
else -> irFunction.interpret(newFrame)
|
||||||
}
|
}
|
||||||
data.pushReturnValue(newFrame)
|
data.pushReturnValue(newFrame)
|
||||||
return code
|
return executionResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall, data: Frame): Code {
|
private suspend fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall, data: Frame): ExecutionResult {
|
||||||
val irClass = call.classSymbol.owner
|
val irClass = call.classSymbol.owner
|
||||||
|
|
||||||
val classProperties = irClass.declarations.filterIsInstance<IrProperty>()
|
val classProperties = irClass.declarations.filterIsInstance<IrProperty>()
|
||||||
@@ -435,10 +393,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
val anonymousInitializer = irClass.declarations.filterIsInstance<IrAnonymousInitializer>().filter { !it.isStatic }
|
val anonymousInitializer = irClass.declarations.filterIsInstance<IrAnonymousInitializer>().filter { !it.isStatic }
|
||||||
anonymousInitializer.forEach { init -> init.body.interpret(data).check { return it } }
|
anonymousInitializer.forEach { init -> init.body.interpret(data).check { return it } }
|
||||||
|
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): Code {
|
private suspend fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): ExecutionResult {
|
||||||
val isPrimary = (constructorCall.symbol.owner as IrConstructor).isPrimary
|
val isPrimary = (constructorCall.symbol.owner as IrConstructor).isPrimary
|
||||||
interpretValueParameters(constructorCall, data).check { return it }
|
interpretValueParameters(constructorCall, data).check { return it }
|
||||||
val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList()
|
val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList()
|
||||||
@@ -452,12 +410,12 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
val low = (valueParameters[0].state as Primitive<*>).value as Int
|
val low = (valueParameters[0].state as Primitive<*>).value as Int
|
||||||
val high = (valueParameters[1].state as Primitive<*>).value as Int
|
val high = (valueParameters[1].state as Primitive<*>).value as Int
|
||||||
data.pushReturnValue((high.toLong().shl(32) + low).toState(irBuiltIns.longType))
|
data.pushReturnValue((high.toLong().shl(32) + low).toState(irBuiltIns.longType))
|
||||||
Code.NEXT
|
Next
|
||||||
}
|
}
|
||||||
"kotlin.Char" -> {
|
"kotlin.Char" -> {
|
||||||
val value = (valueParameters.single().state as Primitive<*>).value as Int
|
val value = (valueParameters.single().state as Primitive<*>).value as Int
|
||||||
data.pushReturnValue(value.toChar().toState(irBuiltIns.longType))
|
data.pushReturnValue(value.toChar().toState(irBuiltIns.longType))
|
||||||
Code.NEXT
|
Next
|
||||||
}
|
}
|
||||||
else -> Wrapper.getConstructorMethod(owner).invokeMethod(owner, newFrame).apply { data.pushReturnValue(newFrame) }
|
else -> Wrapper.getConstructorMethod(owner).invokeMethod(owner, newFrame).apply { data.pushReturnValue(newFrame) }
|
||||||
}
|
}
|
||||||
@@ -476,7 +434,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
val indexDescriptor = initLambda.irFunction.valueParameters.single().descriptor
|
val indexDescriptor = initLambda.irFunction.valueParameters.single().descriptor
|
||||||
for (i in 0 until size) {
|
for (i in 0 until size) {
|
||||||
val lambdaFrame = InterpreterFrame(mutableListOf(Variable(indexDescriptor, i.toState(irBuiltIns.intType))))
|
val lambdaFrame = InterpreterFrame(mutableListOf(Variable(indexDescriptor, i.toState(irBuiltIns.intType))))
|
||||||
initLambda.irFunction.body!!.interpret(lambdaFrame).check(Code.RETURN) { return it }
|
initLambda.irFunction.body!!.interpret(lambdaFrame).check(ReturnLabel.RETURN) { return it }
|
||||||
arrayValue[i] = lambdaFrame.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }
|
arrayValue[i] = lambdaFrame.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,7 +452,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
} as Primitive<*>
|
} as Primitive<*>
|
||||||
|
|
||||||
data.pushReturnValue(array)
|
data.pushReturnValue(array)
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
val state = Common(parent)
|
val state = Common(parent)
|
||||||
@@ -502,28 +460,28 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
constructorCall.getBody()?.interpret(newFrame)?.checkForReturn(newFrame, data) { return it }
|
constructorCall.getBody()?.interpret(newFrame)?.checkForReturn(newFrame, data) { return it }
|
||||||
val returnedState = newFrame.popReturnValue() as Complex
|
val returnedState = newFrame.popReturnValue() as Complex
|
||||||
data.pushReturnValue(if (isPrimary) state.apply { this.setSuperClassInstance(returnedState) } else returnedState.apply { setStatesFrom(state) })
|
data.pushReturnValue(if (isPrimary) state.apply { this.setSuperClassInstance(returnedState) } else returnedState.apply { setStatesFrom(state) })
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code {
|
private suspend fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): ExecutionResult {
|
||||||
return interpretConstructor(constructorCall, data)
|
return interpretConstructor(constructorCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, data: Frame): Code {
|
private suspend fun interpretEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, data: Frame): ExecutionResult {
|
||||||
return interpretConstructor(enumConstructorCall, data)
|
return interpretConstructor(enumConstructorCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code {
|
private suspend fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): ExecutionResult {
|
||||||
if (delegatingConstructorCall.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) {
|
if (delegatingConstructorCall.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) {
|
||||||
val anyAsStateObject = Common(irBuiltIns.anyClass.owner)
|
val anyAsStateObject = Common(irBuiltIns.anyClass.owner)
|
||||||
data.pushReturnValue(anyAsStateObject)
|
data.pushReturnValue(anyAsStateObject)
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return interpretConstructor(delegatingConstructorCall, data)
|
return interpretConstructor(delegatingConstructorCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretConst(expression: IrConst<*>, data: Frame): Code {
|
private suspend fun interpretConst(expression: IrConst<*>, data: Frame): ExecutionResult {
|
||||||
fun getSignedType(unsignedClassName: String): IrType {
|
fun getSignedType(unsignedClassName: String): IrType {
|
||||||
return when (unsignedClassName) {
|
return when (unsignedClassName) {
|
||||||
"UByte" -> irBuiltIns.byteType
|
"UByte" -> irBuiltIns.byteType
|
||||||
@@ -543,107 +501,110 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
constructorCall.interpret(data)
|
constructorCall.interpret(data)
|
||||||
} else {
|
} else {
|
||||||
data.pushReturnValue(expression.toPrimitive())
|
data.pushReturnValue(expression.toPrimitive())
|
||||||
Code.NEXT
|
Next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretStatements(statements: List<IrStatement>, data: Frame): Code {
|
private suspend fun interpretStatements(statements: List<IrStatement>, data: Frame): ExecutionResult {
|
||||||
var code = Code.NEXT
|
var executionResult: ExecutionResult = Next
|
||||||
val iterator = statements.iterator()
|
val iterator = statements.iterator()
|
||||||
while (code == Code.NEXT && iterator.hasNext()) {
|
while (executionResult.returnLabel == ReturnLabel.NEXT && iterator.hasNext()) {
|
||||||
code = iterator.next().interpret(data)
|
executionResult = iterator.next().interpret(data)
|
||||||
}
|
}
|
||||||
return code
|
return executionResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretBlock(block: IrBlock, data: Frame): Code {
|
private suspend fun interpretBlock(block: IrBlock, data: Frame): ExecutionResult {
|
||||||
val newFrame = data.copy()
|
val newFrame = data.copy()
|
||||||
return interpretStatements(block.statements, newFrame).apply { data.pushReturnValue(newFrame) }
|
return interpretStatements(block.statements, newFrame).apply { data.pushReturnValue(newFrame) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretBody(body: IrBody, data: Frame): Code {
|
private suspend fun interpretBody(body: IrBody, data: Frame): ExecutionResult {
|
||||||
val newFrame = data.copy()
|
val newFrame = data.copy()
|
||||||
return interpretStatements(body.statements, newFrame).apply { data.pushReturnValue(newFrame) }
|
return interpretStatements(body.statements, newFrame).apply { data.pushReturnValue(newFrame) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretReturn(expression: IrReturn, data: Frame): Code {
|
private suspend fun interpretReturn(expression: IrReturn, data: Frame): ExecutionResult {
|
||||||
val code = expression.value.interpret(data)
|
val executionResult = expression.value.interpret(data)
|
||||||
return if (code == Code.NEXT) Code.RETURN.apply { this.info = expression.returnTargetSymbol.descriptor.toString() } else code
|
return when (executionResult.returnLabel) {
|
||||||
|
ReturnLabel.NEXT -> Return.addInfo(expression.returnTargetSymbol.descriptor.toString())
|
||||||
|
else -> executionResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretWhile(expression: IrWhileLoop, data: Frame): Code {
|
private suspend fun interpretWhile(expression: IrWhileLoop, data: Frame): ExecutionResult {
|
||||||
var code = Code.NEXT
|
var executionResult: ExecutionResult = Next
|
||||||
while (code == Code.NEXT) {
|
while (executionResult.returnLabel == ReturnLabel.NEXT) {
|
||||||
code = expression.condition.interpret(data)
|
executionResult = expression.condition.interpret(data)
|
||||||
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) {
|
if (executionResult.returnLabel == ReturnLabel.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) {
|
||||||
code = expression.body?.interpret(data) ?: Code.NEXT
|
executionResult = expression.body?.interpret(data) ?: Next
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code
|
return executionResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretWhen(expression: IrWhen, data: Frame): Code {
|
private suspend fun interpretWhen(expression: IrWhen, data: Frame): ExecutionResult {
|
||||||
var code = Code.NEXT
|
var executionResult: ExecutionResult = Next
|
||||||
val iterator = expression.branches.asSequence().iterator()
|
val iterator = expression.branches.asSequence().iterator()
|
||||||
while (code == Code.NEXT && iterator.hasNext()) {
|
while (executionResult.returnLabel == ReturnLabel.NEXT && iterator.hasNext()) {
|
||||||
code = iterator.next().interpret(data)
|
executionResult = iterator.next().interpret(data)
|
||||||
}
|
}
|
||||||
return code
|
return executionResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretBranch(expression: IrBranch, data: Frame): Code {
|
private suspend fun interpretBranch(expression: IrBranch, data: Frame): ExecutionResult {
|
||||||
var code = expression.condition.interpret(data)
|
var executionResult = expression.condition.interpret(data)
|
||||||
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) {
|
if (executionResult.returnLabel == ReturnLabel.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) {
|
||||||
code = expression.result.interpret(data)
|
executionResult = expression.result.interpret(data)
|
||||||
if (code == Code.NEXT) return Code.BREAK_WHEN
|
if (executionResult.returnLabel == ReturnLabel.NEXT) return BreakWhen
|
||||||
}
|
}
|
||||||
return code
|
return executionResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretBreak(breakStatement: IrBreak, data: Frame): Code {
|
private suspend fun interpretBreak(breakStatement: IrBreak, data: Frame): ExecutionResult {
|
||||||
return Code.BREAK_LOOP.apply { info = breakStatement.label ?: "" }
|
return BreakLoop.addInfo(breakStatement.label ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretContinue(continueStatement: IrContinue, data: Frame): Code {
|
private suspend fun interpretContinue(continueStatement: IrContinue, data: Frame): ExecutionResult {
|
||||||
return Code.CONTINUE.apply { info = continueStatement.label ?: "" }
|
return Continue.addInfo(continueStatement.label ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretSetField(expression: IrSetField, data: Frame): Code {
|
private suspend fun interpretSetField(expression: IrSetField, data: Frame): ExecutionResult {
|
||||||
val code = expression.value.interpret(data)
|
val executionResult = expression.value.interpret(data)
|
||||||
if (code != Code.NEXT) return code
|
if (executionResult.returnLabel != ReturnLabel.NEXT) return executionResult
|
||||||
|
|
||||||
val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor
|
val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor
|
||||||
data.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, data.popReturnValue()))
|
data.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, data.popReturnValue()))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretGetField(expression: IrGetField, data: Frame): Code {
|
private suspend fun interpretGetField(expression: IrGetField, data: Frame): ExecutionResult {
|
||||||
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields
|
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields
|
||||||
val result = receiver?.let { data.getVariableState(receiver).getState(expression.symbol.descriptor)?.copy() }
|
val result = receiver?.let { data.getVariableState(receiver).getState(expression.symbol.descriptor)?.copy() }
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return expression.symbol.owner.initializer?.expression?.interpret(data) ?: Code.NEXT
|
return expression.symbol.owner.initializer?.expression?.interpret(data) ?: Next
|
||||||
}
|
}
|
||||||
data.pushReturnValue(result)
|
data.pushReturnValue(result)
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretGetValue(expression: IrGetValue, data: Frame): Code {
|
private suspend fun interpretGetValue(expression: IrGetValue, data: Frame): ExecutionResult {
|
||||||
data.pushReturnValue(data.getVariableState(expression.symbol.descriptor).copy())
|
data.pushReturnValue(data.getVariableState(expression.symbol.descriptor).copy())
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretVariable(expression: IrVariable, data: Frame): Code {
|
private suspend fun interpretVariable(expression: IrVariable, data: Frame): ExecutionResult {
|
||||||
val code = expression.initializer?.interpret(data)
|
val executionResult = expression.initializer?.interpret(data)
|
||||||
if (code != Code.NEXT) return code ?: Code.NEXT
|
if (executionResult?.returnLabel != ReturnLabel.NEXT) return executionResult ?: Next
|
||||||
data.addVar(Variable(expression.descriptor, data.popReturnValue()))
|
data.addVar(Variable(expression.descriptor, data.popReturnValue()))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretSetVariable(expression: IrSetVariable, data: Frame): Code {
|
private suspend fun interpretSetVariable(expression: IrSetVariable, data: Frame): ExecutionResult {
|
||||||
val code = expression.value.interpret(data)
|
val executionResult = expression.value.interpret(data)
|
||||||
if (code != Code.NEXT) return code
|
if (executionResult.returnLabel != ReturnLabel.NEXT) return executionResult
|
||||||
|
|
||||||
if (data.contains(expression.symbol.descriptor)) {
|
if (data.contains(expression.symbol.descriptor)) {
|
||||||
val variable = data.getVariableState(expression.symbol.descriptor)
|
val variable = data.getVariableState(expression.symbol.descriptor)
|
||||||
@@ -651,24 +612,24 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
} else {
|
} else {
|
||||||
data.addVar(Variable(expression.symbol.descriptor, data.popReturnValue()))
|
data.addVar(Variable(expression.symbol.descriptor, data.popReturnValue()))
|
||||||
}
|
}
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretGetObjectValue(expression: IrGetObjectValue, data: Frame): Code {
|
private suspend fun interpretGetObjectValue(expression: IrGetObjectValue, data: Frame): ExecutionResult {
|
||||||
val owner = expression.symbol.owner
|
val owner = expression.symbol.owner
|
||||||
if (owner.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
if (owner.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
||||||
data.pushReturnValue(Wrapper.getCompanionObject(owner))
|
data.pushReturnValue(Wrapper.getCompanionObject(owner))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
val objectState = Common(owner)
|
val objectState = Common(owner)
|
||||||
data.pushReturnValue(objectState)
|
data.pushReturnValue(objectState)
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretGetEnumValue(expression: IrGetEnumValue, data: Frame): Code {
|
private suspend fun interpretGetEnumValue(expression: IrGetEnumValue, data: Frame): ExecutionResult {
|
||||||
val enumEntry = expression.symbol.owner
|
val enumEntry = expression.symbol.owner
|
||||||
val enumSignature = Pair(enumEntry.parentAsClass, enumEntry.name.asString())
|
val enumSignature = Pair(enumEntry.parentAsClass, enumEntry.name.asString())
|
||||||
mapOfEnums[enumSignature]?.let { return Code.NEXT.apply { data.pushReturnValue(it) } }
|
mapOfEnums[enumSignature]?.let { return Next.apply { data.pushReturnValue(it) } }
|
||||||
|
|
||||||
val enumClass = enumEntry.symbol.owner.parentAsClass
|
val enumClass = enumEntry.symbol.owner.parentAsClass
|
||||||
if (enumClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
if (enumClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
||||||
@@ -676,17 +637,17 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
val enumName = Variable(valueOfFun.valueParameters.first().descriptor, enumEntry.name.asString().toState(irBuiltIns.stringType))
|
val enumName = Variable(valueOfFun.valueParameters.first().descriptor, enumEntry.name.asString().toState(irBuiltIns.stringType))
|
||||||
val newFrame = InterpreterFrame(mutableListOf(enumName))
|
val newFrame = InterpreterFrame(mutableListOf(enumName))
|
||||||
return Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, newFrame).apply {
|
return Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, newFrame).apply {
|
||||||
if (this == Code.NEXT) mapOfEnums[enumSignature] = newFrame.peekReturnValue() as Wrapper
|
if (this.returnLabel == ReturnLabel.NEXT) mapOfEnums[enumSignature] = newFrame.peekReturnValue() as Wrapper
|
||||||
data.pushReturnValue(newFrame)
|
data.pushReturnValue(newFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return interpretEnumEntry(enumEntry, data).apply {
|
return interpretEnumEntry(enumEntry, data).apply {
|
||||||
if (this == Code.NEXT) mapOfEnums[enumSignature] = data.peekReturnValue() as Common
|
if (this.returnLabel == ReturnLabel.NEXT) mapOfEnums[enumSignature] = data.peekReturnValue() as Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretEnumEntry(enumEntry: IrEnumEntry, data: Frame): Code {
|
private suspend fun interpretEnumEntry(enumEntry: IrEnumEntry, data: Frame): ExecutionResult {
|
||||||
val enumClass = enumEntry.symbol.owner.parentAsClass
|
val enumClass = enumEntry.symbol.owner.parentAsClass
|
||||||
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
|
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||||
|
|
||||||
@@ -698,27 +659,27 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
enumSuperCall.mapValueParameters { valueArguments[it.index] }
|
enumSuperCall.mapValueParameters { valueArguments[it.index] }
|
||||||
}
|
}
|
||||||
|
|
||||||
val code = enumEntry.initializerExpression?.interpret(data)?.check { return it }
|
val executionResult = enumEntry.initializerExpression?.interpret(data)?.check { return it }
|
||||||
enumSuperCall?.mapValueParameters { null }
|
enumSuperCall?.mapValueParameters { null }
|
||||||
data.pushReturnValue((data.popReturnValue() as Complex))
|
data.pushReturnValue((data.popReturnValue() as Complex))
|
||||||
return code ?: throw AssertionError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null")
|
return executionResult ?: throw AssertionError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall, data: Frame): Code {
|
private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall, data: Frame): ExecutionResult {
|
||||||
val code = expression.argument.interpret(data).check { return it }
|
val executionResult = expression.argument.interpret(data).check { return it }
|
||||||
|
|
||||||
return when (expression.operator) {
|
return when (expression.operator) {
|
||||||
// coercion to unit means that return value isn't used
|
// coercion to unit means that return value isn't used
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> code
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> executionResult
|
||||||
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
||||||
if (!data.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
if (!data.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
||||||
val convertibleClassName = data.popReturnValue().irClass.fqNameForIrSerialization
|
val convertibleClassName = data.popReturnValue().irClass.fqNameForIrSerialization
|
||||||
val castClassName = expression.type.classOrNull?.owner?.fqNameForIrSerialization
|
val castClassName = expression.type.classOrNull?.owner?.fqNameForIrSerialization
|
||||||
val message = "$convertibleClassName cannot be cast to $castClassName"
|
val message = "$convertibleClassName cannot be cast to $castClassName"
|
||||||
data.pushReturnValue(ExceptionState(ClassCastException(message), classCastException, stackTrace))
|
data.pushReturnValue(ExceptionState(ClassCastException(message), classCastException, stackTrace))
|
||||||
Code.EXCEPTION
|
Exception
|
||||||
} else {
|
} else {
|
||||||
code
|
executionResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrTypeOperator.SAFE_CAST -> {
|
IrTypeOperator.SAFE_CAST -> {
|
||||||
@@ -726,26 +687,26 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
data.popReturnValue()
|
data.popReturnValue()
|
||||||
data.pushReturnValue(null.toState(irBuiltIns.nothingType))
|
data.pushReturnValue(null.toState(irBuiltIns.nothingType))
|
||||||
}
|
}
|
||||||
code
|
executionResult
|
||||||
}
|
}
|
||||||
IrTypeOperator.INSTANCEOF -> {
|
IrTypeOperator.INSTANCEOF -> {
|
||||||
val isInstance = data.popReturnValue().irClass.defaultType.isSubtypeOf(expression.typeOperand, irBuiltIns)
|
val isInstance = data.popReturnValue().irClass.defaultType.isSubtypeOf(expression.typeOperand, irBuiltIns)
|
||||||
data.pushReturnValue(isInstance.toState(irBuiltIns.nothingType))
|
data.pushReturnValue(isInstance.toState(irBuiltIns.nothingType))
|
||||||
code
|
executionResult
|
||||||
}
|
}
|
||||||
IrTypeOperator.NOT_INSTANCEOF -> {
|
IrTypeOperator.NOT_INSTANCEOF -> {
|
||||||
val isInstance = data.popReturnValue().irClass.defaultType.isSubtypeOf(expression.typeOperand, irBuiltIns)
|
val isInstance = data.popReturnValue().irClass.defaultType.isSubtypeOf(expression.typeOperand, irBuiltIns)
|
||||||
data.pushReturnValue((!isInstance).toState(irBuiltIns.nothingType))
|
data.pushReturnValue((!isInstance).toState(irBuiltIns.nothingType))
|
||||||
code
|
executionResult
|
||||||
}
|
}
|
||||||
else -> TODO("${expression.operator} not implemented")
|
else -> TODO("${expression.operator} not implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private suspend fun interpretVararg(expression: IrVararg, data: Frame): Code {
|
private suspend fun interpretVararg(expression: IrVararg, data: Frame): ExecutionResult {
|
||||||
val args = expression.elements.map {
|
val args = expression.elements.map {
|
||||||
it.interpret(data).apply { if (this != Code.NEXT) return this }
|
it.interpret(data).apply { if (this.returnLabel != ReturnLabel.NEXT) return this }
|
||||||
data.popReturnValue()
|
data.popReturnValue()
|
||||||
}
|
}
|
||||||
val type = expression.type
|
val type = expression.type
|
||||||
@@ -762,31 +723,31 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
data.pushReturnValue(array)
|
data.pushReturnValue(array)
|
||||||
|
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretTry(expression: IrTry, data: Frame): Code {
|
private suspend fun interpretTry(expression: IrTry, data: Frame): ExecutionResult {
|
||||||
var code = expression.tryResult.interpret(data)
|
var executionResult = expression.tryResult.interpret(data)
|
||||||
if (code == Code.EXCEPTION) {
|
if (executionResult.returnLabel == ReturnLabel.EXCEPTION) {
|
||||||
val exception = data.peekReturnValue() as ExceptionState
|
val exception = data.peekReturnValue() as ExceptionState
|
||||||
for (catchBlock in expression.catches) {
|
for (catchBlock in expression.catches) {
|
||||||
if (exception.isSubtypeOf(catchBlock.catchParameter.type.classOrNull!!.owner)) {
|
if (exception.isSubtypeOf(catchBlock.catchParameter.type.classOrNull!!.owner)) {
|
||||||
code = catchBlock.interpret(data)
|
executionResult = catchBlock.interpret(data)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO check flow correctness; should I return finally result code if in catch there was an exception?
|
// TODO check flow correctness; should I return finally result code if in catch there was an exception?
|
||||||
return expression.finallyExpression?.interpret(data) ?: code
|
return expression.finallyExpression?.interpret(data) ?: executionResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretCatch(expression: IrCatch, data: Frame): Code {
|
private suspend fun interpretCatch(expression: IrCatch, data: Frame): ExecutionResult {
|
||||||
val newFrame = InterpreterFrame(data.getAll().toMutableList())
|
val newFrame = InterpreterFrame(data.getAll().toMutableList())
|
||||||
newFrame.addVar(Variable(expression.parameter, data.popReturnValue()))
|
newFrame.addVar(Variable(expression.parameter, data.popReturnValue()))
|
||||||
return expression.result.interpret(newFrame).apply { data.pushReturnValue(newFrame) }
|
return expression.result.interpret(newFrame).apply { data.pushReturnValue(newFrame) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretThrow(expression: IrThrow, data: Frame): Code {
|
private suspend fun interpretThrow(expression: IrThrow, data: Frame): ExecutionResult {
|
||||||
expression.value.interpret(data).check { return it }
|
expression.value.interpret(data).check { return it }
|
||||||
when (val exception = data.popReturnValue()) {
|
when (val exception = data.popReturnValue()) {
|
||||||
is Common -> data.pushReturnValue(ExceptionState(exception, stackTrace))
|
is Common -> data.pushReturnValue(ExceptionState(exception, stackTrace))
|
||||||
@@ -794,13 +755,13 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
is ExceptionState -> data.pushReturnValue(exception)
|
is ExceptionState -> data.pushReturnValue(exception)
|
||||||
else -> throw AssertionError("${exception::class} cannot be used as exception state")
|
else -> throw AssertionError("${exception::class} cannot be used as exception state")
|
||||||
}
|
}
|
||||||
return Code.EXCEPTION
|
return Exception
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretStringConcatenation(expression: IrStringConcatenation, data: Frame): Code {
|
private suspend fun interpretStringConcatenation(expression: IrStringConcatenation, data: Frame): ExecutionResult {
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
expression.arguments.forEach {
|
expression.arguments.forEach {
|
||||||
it.interpret(data).check { code -> return code }
|
it.interpret(data).check { executionResult -> return executionResult }
|
||||||
result.append(
|
result.append(
|
||||||
when (val returnValue = data.popReturnValue()) {
|
when (val returnValue = data.popReturnValue()) {
|
||||||
is Primitive<*> -> returnValue.value.toString()
|
is Primitive<*> -> returnValue.value.toString()
|
||||||
@@ -808,8 +769,8 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
is Common -> {
|
is Common -> {
|
||||||
val toStringFun = returnValue.getToStringFunction()
|
val toStringFun = returnValue.getToStringFunction()
|
||||||
val newFrame = InterpreterFrame(mutableListOf(Variable(toStringFun.symbol.getReceiver()!!, returnValue)))
|
val newFrame = InterpreterFrame(mutableListOf(Variable(toStringFun.symbol.getReceiver()!!, returnValue)))
|
||||||
val code = toStringFun.body?.let { toStringFun.interpret(newFrame) } ?: calculateOverridden(toStringFun, newFrame)
|
val executionResult = toStringFun.body?.let { toStringFun.interpret(newFrame) } ?: calculateOverridden(toStringFun, newFrame)
|
||||||
if (code != Code.NEXT) return code
|
if (executionResult.returnLabel != ReturnLabel.NEXT) return executionResult
|
||||||
(newFrame.popReturnValue() as Primitive<*>).value.toString()
|
(newFrame.popReturnValue() as Primitive<*>).value.toString()
|
||||||
}
|
}
|
||||||
else -> throw AssertionError("$returnValue cannot be used in StringConcatenation expression")
|
else -> throw AssertionError("$returnValue cannot be used in StringConcatenation expression")
|
||||||
@@ -818,20 +779,20 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.pushReturnValue(result.toString().toState(expression.type))
|
data.pushReturnValue(result.toString().toState(expression.type))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretFunctionExpression(expression: IrFunctionExpression, data: Frame): Code {
|
private suspend fun interpretFunctionExpression(expression: IrFunctionExpression, data: Frame): ExecutionResult {
|
||||||
data.pushReturnValue(Lambda(expression.function, expression.type.classOrNull!!.owner))
|
data.pushReturnValue(Lambda(expression.function, expression.type.classOrNull!!.owner))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretFunctionReference(reference: IrFunctionReference, data: Frame): Code {
|
private suspend fun interpretFunctionReference(reference: IrFunctionReference, data: Frame): ExecutionResult {
|
||||||
data.pushReturnValue(Lambda(reference.symbol.owner, reference.type.classOrNull!!.owner))
|
data.pushReturnValue(Lambda(reference.symbol.owner, reference.type.classOrNull!!.owner))
|
||||||
return Code.NEXT
|
return Next
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun interpretComposite(expression: IrComposite, data: Frame): Code {
|
private suspend fun interpretComposite(expression: IrComposite, data: Frame): ExecutionResult {
|
||||||
return when (expression.origin) {
|
return when (expression.origin) {
|
||||||
IrStatementOrigin.DESTRUCTURING_DECLARATION -> interpretStatements(expression.statements, data)
|
IrStatementOrigin.DESTRUCTURING_DECLARATION -> interpretStatements(expression.statements, data)
|
||||||
else -> TODO("${expression.origin} not implemented")
|
else -> TODO("${expression.origin} not implemented")
|
||||||
|
|||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.common.interpreter
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Frame
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
|
||||||
|
|
||||||
|
enum class ReturnLabel {
|
||||||
|
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExecutionResult {
|
||||||
|
val returnLabel: ReturnLabel
|
||||||
|
|
||||||
|
fun getNextLabel(irElement: IrElement, data: Frame, interpret: IrElement.(Frame) -> ExecutionResult): ExecutionResult
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun ExecutionResult.check(toCheckLabel: ReturnLabel = ReturnLabel.NEXT, returnBlock: (ExecutionResult) -> Unit): ExecutionResult {
|
||||||
|
if (this.returnLabel != toCheckLabel) returnBlock(this)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun ExecutionResult.checkForReturn(newFrame: Frame, oldFrame: Frame, returnBlock: (ExecutionResult) -> Unit): ExecutionResult {
|
||||||
|
if (this.returnLabel != ReturnLabel.NEXT) {
|
||||||
|
if ((this.returnLabel == ReturnLabel.RETURN || this.returnLabel == ReturnLabel.EXCEPTION) && newFrame.hasReturnValue()) {
|
||||||
|
oldFrame.pushReturnValue(newFrame)
|
||||||
|
}
|
||||||
|
returnBlock(this)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ExecutionResultWithoutInfo(override val returnLabel: ReturnLabel): ExecutionResult {
|
||||||
|
override fun getNextLabel(irElement: IrElement, data: Frame, interpret: IrElement.(Frame) -> ExecutionResult): ExecutionResult {
|
||||||
|
return when (returnLabel) {
|
||||||
|
ReturnLabel.RETURN -> this
|
||||||
|
ReturnLabel.BREAK_WHEN -> when (irElement) {
|
||||||
|
is IrWhen -> Next
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
ReturnLabel.BREAK_LOOP -> this
|
||||||
|
ReturnLabel.CONTINUE -> this
|
||||||
|
ReturnLabel.EXCEPTION -> this
|
||||||
|
ReturnLabel.NEXT -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addInfo(info: String): ExecutionResultWithInfo {
|
||||||
|
return ExecutionResultWithInfo(returnLabel, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecutionResultWithInfo(override val returnLabel: ReturnLabel, val info: String): ExecutionResultWithoutInfo(returnLabel) {
|
||||||
|
override fun getNextLabel(irElement: IrElement, data: Frame, interpret: IrElement.(Frame) -> ExecutionResult): ExecutionResult {
|
||||||
|
return when (returnLabel) {
|
||||||
|
ReturnLabel.RETURN -> when (irElement) {
|
||||||
|
is IrCall -> if (info == irElement.symbol.descriptor.toString()) Next else this
|
||||||
|
is IrReturnableBlock -> if (info == irElement.symbol.descriptor.toString()) Next else this
|
||||||
|
is IrFunctionImpl -> if (info == irElement.descriptor.toString()) Next else this
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
ReturnLabel.BREAK_WHEN -> when (irElement) {
|
||||||
|
is IrWhen -> Next
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
ReturnLabel.BREAK_LOOP -> when (irElement) {
|
||||||
|
is IrWhileLoop -> if ((irElement.label ?: "") == info) Next else this
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
ReturnLabel.CONTINUE -> when (irElement) {
|
||||||
|
is IrWhileLoop -> if ((irElement.label ?: "") == info) irElement.interpret(data) else this
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
ReturnLabel.EXCEPTION -> Exception
|
||||||
|
ReturnLabel.NEXT -> Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Next : ExecutionResultWithoutInfo(ReturnLabel.NEXT)
|
||||||
|
object Return : ExecutionResultWithoutInfo(ReturnLabel.RETURN)
|
||||||
|
object BreakLoop : ExecutionResultWithoutInfo(ReturnLabel.BREAK_LOOP)
|
||||||
|
object BreakWhen : ExecutionResultWithoutInfo(ReturnLabel.BREAK_WHEN)
|
||||||
|
object Continue : ExecutionResultWithoutInfo(ReturnLabel.CONTINUE)
|
||||||
|
object Exception : ExecutionResultWithoutInfo(ReturnLabel.EXCEPTION)
|
||||||
Reference in New Issue
Block a user