Add CallInterceptor interface and implement its default realization
CallInterceptor will handle calls, constructor calls, getting enum entries and objects. It will make a decision for interpreter: this call must be handled as intrinsic or it must be interpreted.
This commit is contained in:
committed by
TeamCityServer
parent
c8b268a789
commit
25d01099d8
+221
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.ir.interpreter
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import java.lang.invoke.MethodHandle
|
||||||
|
|
||||||
|
internal interface CallInterceptor {
|
||||||
|
val environment: IrInterpreterEnvironment
|
||||||
|
val interpreter: IrInterpreter
|
||||||
|
fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>)
|
||||||
|
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>)
|
||||||
|
fun interceptGetObjectValue(expression: IrGetObjectValue)
|
||||||
|
fun interceptEnumEntry(enumEntry: IrEnumEntry)
|
||||||
|
fun interceptJavaStaticField(expression: IrGetField)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : CallInterceptor {
|
||||||
|
override val environment: IrInterpreterEnvironment = interpreter.environment
|
||||||
|
private val callStack: CallStack
|
||||||
|
get() = environment.callStack
|
||||||
|
private val irBuiltIns: IrBuiltIns
|
||||||
|
get() = environment.irBuiltIns
|
||||||
|
private val bodyMap: Map<IdSignature, IrBody>
|
||||||
|
get() = interpreter.bodyMap
|
||||||
|
|
||||||
|
override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>) {
|
||||||
|
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
|
||||||
|
val originalCallName = call.symbol.owner.name.asString()
|
||||||
|
when {
|
||||||
|
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(irFunction).invokeMethod(irFunction, args)
|
||||||
|
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
|
||||||
|
receiver is KFunctionState && originalCallName == "invoke" -> callStack.addInstruction(CompoundInstruction(irFunction))
|
||||||
|
receiver is ReflectionState -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, args)
|
||||||
|
receiver is Primitive<*> -> calculateBuiltIns(irFunction, args) // check for js char, js long and get field for primitives
|
||||||
|
irFunction.body is IrSyntheticBody -> handleIntrinsicMethods(irFunction)
|
||||||
|
irFunction.body == null ->
|
||||||
|
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, args)
|
||||||
|
else -> callStack.addInstruction(CompoundInstruction(irFunction))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>) {
|
||||||
|
val constructor = constructorCall.symbol.owner
|
||||||
|
val irClass = constructor.parentAsClass
|
||||||
|
when {
|
||||||
|
irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
|
||||||
|
Wrapper.getConstructorMethod(constructor).invokeMethod(constructor, args)
|
||||||
|
if (constructorCall !is IrConstructorCall) (receiver as Common).superWrapperClass = callStack.popState() as Wrapper
|
||||||
|
}
|
||||||
|
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
|
||||||
|
// array constructor doesn't have body so must be treated separately
|
||||||
|
callStack.addVariable(Variable(constructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
|
||||||
|
handleIntrinsicMethods(constructor)
|
||||||
|
}
|
||||||
|
irClass.defaultType.isUnsignedType() -> {
|
||||||
|
val propertySymbol = irClass.declarations.single { it is IrProperty }.symbol
|
||||||
|
callStack.pushState(receiver.apply { fields += Variable(propertySymbol, args.single()) })
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
callStack.pushState(receiver)
|
||||||
|
callStack.addInstruction(CompoundInstruction(constructor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun interceptGetObjectValue(expression: IrGetObjectValue) {
|
||||||
|
val objectClass = expression.symbol.owner
|
||||||
|
if (objectClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
||||||
|
val result = Wrapper.getCompanionObject(objectClass)
|
||||||
|
environment.mapOfObjects[expression.symbol] = result
|
||||||
|
callStack.pushState(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun interceptEnumEntry(enumEntry: IrEnumEntry) {
|
||||||
|
val enumClass = enumEntry.symbol.owner.parentAsClass
|
||||||
|
|
||||||
|
when {
|
||||||
|
enumClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
|
||||||
|
val enumEntryName = enumEntry.name.asString().toState(environment.irBuiltIns.stringType)
|
||||||
|
val valueOfFun = enumClass.declarations.single { it.nameForIrSerialization.asString() == "valueOf" } as IrFunction
|
||||||
|
Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, listOf(enumEntryName))
|
||||||
|
environment.mapOfEnums[enumEntry.symbol] = callStack.popState() as Complex
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall)
|
||||||
|
enumSuperCall?.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null
|
||||||
|
callStack.dropSubFrame()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun interceptJavaStaticField(expression: IrGetField) {
|
||||||
|
val field = expression.symbol.owner
|
||||||
|
assert(field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic)
|
||||||
|
assert(field.initializer?.expression !is IrConst<*>)
|
||||||
|
callStack.pushState(Wrapper.getStaticGetter(field)!!.invokeWithArguments().toState(field.type))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
|
||||||
|
this ?: return handleIntrinsicMethods(irFunction)
|
||||||
|
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(interpreter, this.type(), args)
|
||||||
|
withExceptionHandler(environment) {
|
||||||
|
val result = this.invokeWithArguments(argsForMethodInvocation)
|
||||||
|
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleIntrinsicMethods(irFunction: IrFunction) {
|
||||||
|
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
|
||||||
|
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
|
||||||
|
null -> irFunction.name.asString()
|
||||||
|
else -> property.owner.name.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverType = irFunction.dispatchReceiverParameter?.type
|
||||||
|
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
|
||||||
|
val argsValues = args.map { it.wrap(interpreter, calledFromBuiltIns = methodName !in setOf("plus", IrBuiltIns.OperatorNames.EQEQ)) }
|
||||||
|
|
||||||
|
fun IrType.getOnlyName(): String {
|
||||||
|
return when {
|
||||||
|
this.originalKotlinType != null -> this.originalKotlinType.toString()
|
||||||
|
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
|
||||||
|
else -> this.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO replace unary, binary, ternary functions with vararg
|
||||||
|
withExceptionHandler(environment) {
|
||||||
|
val result = when (argsType.size) {
|
||||||
|
1 -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0])
|
||||||
|
2 -> when (methodName) {
|
||||||
|
"rangeTo" -> return calculateRangeTo(irFunction.returnType, args)
|
||||||
|
else -> interpretBinaryFunction(
|
||||||
|
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
3 -> interpretTernaryFunction(
|
||||||
|
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
|
||||||
|
argsValues[0], argsValues[1], argsValues[2]
|
||||||
|
)
|
||||||
|
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
|
||||||
|
}
|
||||||
|
// TODO check "result is Unit"
|
||||||
|
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateRangeTo(type: IrType, args: List<State>) {
|
||||||
|
val constructor = type.classOrNull!!.owner.constructors.first()
|
||||||
|
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||||
|
val constructorValueParameters = constructor.valueParameters.map { it.symbol }
|
||||||
|
|
||||||
|
val primitiveValueParameters = args.map { it as Primitive<*> }
|
||||||
|
primitiveValueParameters.forEachIndexed { index, primitive ->
|
||||||
|
constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type))
|
||||||
|
}
|
||||||
|
|
||||||
|
callStack.addInstruction(CompoundInstruction(constructorCall))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Any?.getType(defaultType: IrType): IrType {
|
||||||
|
return when (this) {
|
||||||
|
is Boolean -> irBuiltIns.booleanType
|
||||||
|
is Char -> irBuiltIns.charType
|
||||||
|
is Byte -> irBuiltIns.byteType
|
||||||
|
is Short -> irBuiltIns.shortType
|
||||||
|
is Int -> irBuiltIns.intType
|
||||||
|
is Long -> irBuiltIns.longType
|
||||||
|
is String -> irBuiltIns.stringType
|
||||||
|
is Float -> irBuiltIns.floatType
|
||||||
|
is Double -> irBuiltIns.doubleType
|
||||||
|
null -> irBuiltIns.nothingNType
|
||||||
|
else -> defaultType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.trySubstituteFunctionBody(): IrElement? {
|
||||||
|
val signature = this.symbol.signature ?: return null
|
||||||
|
this.body = bodyMap[signature] ?: return null
|
||||||
|
callStack.addInstruction(CompoundInstruction(this))
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO fix in FIR2IR; const val getter must have body with IrGetField node
|
||||||
|
private fun IrFunction.tryCalculateLazyConst(): IrExpression? {
|
||||||
|
if (this !is IrSimpleFunction) return null
|
||||||
|
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
|
||||||
|
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-180
@@ -11,38 +11,18 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterTimeOutError
|
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterTimeOutError
|
||||||
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy
|
import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy
|
||||||
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
||||||
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
|
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
|
||||||
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.Complex
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.ExceptionState
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.Primitive
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.asBoolean
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.*
|
import org.jetbrains.kotlin.ir.interpreter.state.reflection.*
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KClassState
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import java.lang.invoke.MethodHandle
|
|
||||||
|
|
||||||
internal interface Instruction {
|
internal interface Instruction {
|
||||||
val element: IrElement?
|
val element: IrElement?
|
||||||
@@ -56,13 +36,13 @@ internal class CustomInstruction(val evaluate: () -> Unit) : Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IrInterpreter private constructor(
|
class IrInterpreter private constructor(
|
||||||
private val bodyMap: Map<IdSignature, IrBody>,
|
internal val bodyMap: Map<IdSignature, IrBody>, internal val environment: IrInterpreterEnvironment
|
||||||
private val environment: IrInterpreterEnvironment
|
|
||||||
) {
|
) {
|
||||||
val irBuiltIns: IrBuiltIns
|
val irBuiltIns: IrBuiltIns
|
||||||
get() = environment.irBuiltIns
|
get() = environment.irBuiltIns
|
||||||
private val callStack: CallStack
|
private val callStack: CallStack
|
||||||
get() = environment.callStack
|
get() = environment.callStack
|
||||||
|
private val callInterceptor: CallInterceptor = DefaultCallInterceptor(this)
|
||||||
private var commandCount = 0
|
private var commandCount = 0
|
||||||
|
|
||||||
constructor(irBuiltIns: IrBuiltIns, bodyMap: Map<IdSignature, IrBody> = emptyMap()) :
|
constructor(irBuiltIns: IrBuiltIns, bodyMap: Map<IdSignature, IrBody> = emptyMap()) :
|
||||||
@@ -78,22 +58,6 @@ class IrInterpreter private constructor(
|
|||||||
if (commandCount >= IrInterpreterEnvironment.MAX_COMMANDS) InterpreterTimeOutError().handleUserException(environment)
|
if (commandCount >= IrInterpreterEnvironment.MAX_COMMANDS) InterpreterTimeOutError().handleUserException(environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Any?.getType(defaultType: IrType): IrType {
|
|
||||||
return when (this) {
|
|
||||||
is Boolean -> irBuiltIns.booleanType
|
|
||||||
is Char -> irBuiltIns.charType
|
|
||||||
is Byte -> irBuiltIns.byteType
|
|
||||||
is Short -> irBuiltIns.shortType
|
|
||||||
is Int -> irBuiltIns.intType
|
|
||||||
is Long -> irBuiltIns.longType
|
|
||||||
is String -> irBuiltIns.stringType
|
|
||||||
is Float -> irBuiltIns.floatType
|
|
||||||
is Double -> irBuiltIns.doubleType
|
|
||||||
null -> irBuiltIns.nothingNType
|
|
||||||
else -> defaultType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getUnitState(): State {
|
private fun getUnitState(): State {
|
||||||
return environment.mapOfObjects.getOrPut(irBuiltIns.unitClass) { Common(irBuiltIns.unitClass.owner) }
|
return environment.mapOfObjects.getOrPut(irBuiltIns.unitClass) { Common(irBuiltIns.unitClass.owner) }
|
||||||
}
|
}
|
||||||
@@ -177,6 +141,11 @@ class IrInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.tryResetFunctionBody() {
|
||||||
|
val signature = this.symbol.signature ?: return
|
||||||
|
if (bodyMap[signature] != null) this.body = null
|
||||||
|
}
|
||||||
|
|
||||||
private fun interpretFunction(function: IrSimpleFunction) {
|
private fun interpretFunction(function: IrSimpleFunction) {
|
||||||
function.tryResetFunctionBody()
|
function.tryResetFunctionBody()
|
||||||
if (function.checkCast(environment)) {
|
if (function.checkCast(environment)) {
|
||||||
@@ -184,71 +153,6 @@ class IrInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
|
|
||||||
this ?: return handleIntrinsicMethods(irFunction)
|
|
||||||
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(this@IrInterpreter, this.type(), args)
|
|
||||||
withExceptionHandler(environment) {
|
|
||||||
val result = this.invokeWithArguments(argsForMethodInvocation)
|
|
||||||
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleIntrinsicMethods(irFunction: IrFunction) {
|
|
||||||
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
|
|
||||||
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
|
|
||||||
null -> irFunction.name.asString()
|
|
||||||
else -> property.owner.name.asString()
|
|
||||||
}
|
|
||||||
|
|
||||||
val receiverType = irFunction.dispatchReceiverParameter?.type
|
|
||||||
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
|
|
||||||
val argsValues = args.map { it.wrap(this, calledFromBuiltIns = methodName !in setOf("plus", IrBuiltIns.OperatorNames.EQEQ)) }
|
|
||||||
|
|
||||||
fun IrType.getOnlyName(): String {
|
|
||||||
return when {
|
|
||||||
this.originalKotlinType != null -> this.originalKotlinType.toString()
|
|
||||||
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
|
|
||||||
else -> this.render()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO replace unary, binary, ternary functions with vararg
|
|
||||||
withExceptionHandler(environment) {
|
|
||||||
val result = when (argsType.size) {
|
|
||||||
1 -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0])
|
|
||||||
2 -> when (methodName) {
|
|
||||||
"rangeTo" -> return calculateRangeTo(irFunction.returnType, args)
|
|
||||||
else -> interpretBinaryFunction(
|
|
||||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
3 -> interpretTernaryFunction(
|
|
||||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
|
|
||||||
argsValues[0], argsValues[1], argsValues[2]
|
|
||||||
)
|
|
||||||
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
|
|
||||||
}
|
|
||||||
// TODO check "result is Unit"
|
|
||||||
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateRangeTo(type: IrType, args: List<State>) {
|
|
||||||
val constructor = type.classOrNull!!.owner.constructors.first()
|
|
||||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
|
||||||
val constructorValueParameters = constructor.valueParameters.map { it.symbol }
|
|
||||||
|
|
||||||
val primitiveValueParameters = args.map { it as Primitive<*> }
|
|
||||||
primitiveValueParameters.forEachIndexed { index, primitive ->
|
|
||||||
constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type))
|
|
||||||
}
|
|
||||||
|
|
||||||
callStack.addInstruction(CompoundInstruction(constructorCall))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun interpretValueParameter(valueParameter: IrValueParameter) {
|
private fun interpretValueParameter(valueParameter: IrValueParameter) {
|
||||||
val irFunction = valueParameter.parent as IrFunction
|
val irFunction = valueParameter.parent as IrFunction
|
||||||
fun isReceiver() = irFunction.dispatchReceiverParameter == valueParameter || irFunction.extensionReceiverParameter == valueParameter
|
fun isReceiver() = irFunction.dispatchReceiverParameter == valueParameter || irFunction.extensionReceiverParameter == valueParameter
|
||||||
@@ -314,39 +218,7 @@ class IrInterpreter private constructor(
|
|||||||
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) }
|
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val states = args.map { it.state }
|
callInterceptor.interceptCall(call, irFunction, dispatchReceiver, args.map { it.state })
|
||||||
// inline only methods are not presented in lookup table, so must be interpreted instead of execution
|
|
||||||
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
|
|
||||||
when {
|
|
||||||
dispatchReceiver is Wrapper && !isInlineOnly -> dispatchReceiver.getMethod(irFunction).invokeMethod(irFunction, states)
|
|
||||||
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, states)
|
|
||||||
dispatchReceiver is KFunctionState && call.symbol.owner.name.asString() == "invoke" -> callStack.addInstruction(CompoundInstruction(irFunction))
|
|
||||||
dispatchReceiver is ReflectionState -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, states)
|
|
||||||
dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction, states) // 'is Primitive' check for js char, js long and get field for primitives
|
|
||||||
irFunction.body is IrSyntheticBody -> handleIntrinsicMethods(irFunction)
|
|
||||||
irFunction.body == null ->
|
|
||||||
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, states)
|
|
||||||
else -> callStack.addInstruction(CompoundInstruction(irFunction))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrFunction.trySubstituteFunctionBody(): IrElement? {
|
|
||||||
val signature = this.symbol.signature ?: return null
|
|
||||||
this.body = bodyMap[signature] ?: return null
|
|
||||||
callStack.addInstruction(CompoundInstruction(this))
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrFunction.tryResetFunctionBody() {
|
|
||||||
val signature = this.symbol.signature ?: return
|
|
||||||
if (bodyMap[signature] != null) this.body = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO fix in FIR2IR; const val getter must have body with IrGetField node
|
|
||||||
private fun IrFunction.tryCalculateLazyConst(): IrExpression? {
|
|
||||||
if (this !is IrSimpleFunction) return null
|
|
||||||
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
|
|
||||||
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall) {
|
private fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall) {
|
||||||
@@ -408,26 +280,7 @@ class IrInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
superReceiver?.let { callStack.addVariable(Variable(it, objectVar.state)) }
|
superReceiver?.let { callStack.addVariable(Variable(it, objectVar.state)) }
|
||||||
|
|
||||||
when {
|
callInterceptor.interceptConstructor(constructorCall, objectVar.state, valueArguments)
|
||||||
irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
|
|
||||||
Wrapper.getConstructorMethod(constructor).invokeMethod(constructor, valueArguments)
|
|
||||||
if (constructorCall !is IrConstructorCall) (objectVar.state as Common).superWrapperClass = callStack.popState() as Wrapper
|
|
||||||
}
|
|
||||||
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
|
|
||||||
// array constructor doesn't have body so must be treated separately
|
|
||||||
callStack.addVariable(Variable(constructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
|
|
||||||
handleIntrinsicMethods(constructor)
|
|
||||||
}
|
|
||||||
irClass.defaultType.isUnsignedType() && valueArguments.size == 1 && constructor.valueParameters.size == 1 -> {
|
|
||||||
callStack.pushState(objectVar.state.apply { fields.add(valueArguments.single()) })
|
|
||||||
callStack.addInstruction(SimpleInstruction(constructor))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
callStack.pushState(objectVar.state)
|
|
||||||
callStack.addInstruction(CompoundInstruction(constructor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretDelegatingConstructorCall(constructorCall: IrDelegatingConstructorCall) {
|
private fun interpretDelegatingConstructorCall(constructorCall: IrDelegatingConstructorCall) {
|
||||||
@@ -507,12 +360,12 @@ class IrInterpreter private constructor(
|
|||||||
private fun interpretGetField(expression: IrGetField) {
|
private fun interpretGetField(expression: IrGetField) {
|
||||||
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol
|
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol
|
||||||
val field = expression.symbol.owner
|
val field = expression.symbol.owner
|
||||||
// for java static variables
|
|
||||||
when {
|
when {
|
||||||
field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic -> {
|
field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic -> {
|
||||||
|
// for java static variables
|
||||||
when (val initializerExpression = field.initializer?.expression) {
|
when (val initializerExpression = field.initializer?.expression) {
|
||||||
is IrConst<*> -> callStack.addInstruction(SimpleInstruction(initializerExpression))
|
is IrConst<*> -> callStack.addInstruction(SimpleInstruction(initializerExpression))
|
||||||
else -> callStack.pushState(Wrapper.getStaticGetter(field)!!.invokeWithArguments().toState(field.type))
|
else -> callInterceptor.interceptJavaStaticField(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
field.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && field.correspondingPropertySymbol?.owner?.isConst == true -> {
|
field.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && field.correspondingPropertySymbol?.owner?.isConst == true -> {
|
||||||
@@ -534,13 +387,7 @@ class IrInterpreter private constructor(
|
|||||||
|
|
||||||
private fun interpretGetObjectValue(expression: IrGetObjectValue) {
|
private fun interpretGetObjectValue(expression: IrGetObjectValue) {
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
|
callInterceptor.interceptGetObjectValue(expression)
|
||||||
val objectClass = expression.symbol.owner
|
|
||||||
if (objectClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
|
||||||
val result = Wrapper.getCompanionObject(objectClass)
|
|
||||||
environment.mapOfObjects[expression.symbol] = result
|
|
||||||
callStack.pushState(result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretGetEnumValue(expression: IrGetEnumValue) {
|
private fun interpretGetEnumValue(expression: IrGetEnumValue) {
|
||||||
@@ -548,21 +395,7 @@ class IrInterpreter private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretEnumEntry(enumEntry: IrEnumEntry) {
|
private fun interpretEnumEntry(enumEntry: IrEnumEntry) {
|
||||||
val enumClass = enumEntry.symbol.owner.parentAsClass
|
callInterceptor.interceptEnumEntry(enumEntry)
|
||||||
|
|
||||||
when {
|
|
||||||
enumClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
|
|
||||||
val enumEntryName = enumEntry.name.asString().toState(environment.irBuiltIns.stringType)
|
|
||||||
val valueOfFun = enumClass.declarations.single { it.nameForIrSerialization.asString() == "valueOf" } as IrFunction
|
|
||||||
Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, listOf(enumEntryName))
|
|
||||||
environment.mapOfEnums[enumEntry.symbol] = callStack.popState() as Complex
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall)
|
|
||||||
enumSuperCall?.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null
|
|
||||||
callStack.dropSubFrame()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretTypeOperatorCall(expression: IrTypeOperatorCall) {
|
private fun interpretTypeOperatorCall(expression: IrTypeOperatorCall) {
|
||||||
|
|||||||
Reference in New Issue
Block a user