From 96a090f2ab5fa595a486bcf3d4675bd04b279033 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 30 Aug 2020 17:03:05 +0300 Subject: [PATCH] Implement LambdaProxy class --- .../kotlin/ir/interpreter/IrInterpreter.kt | 78 +++++-------------- .../jetbrains/kotlin/ir/interpreter/Utils.kt | 4 +- .../builtins/IrBuiltInsMapGenerated.kt | 4 +- .../intrinsics/IntrinsicEvaluator.kt | 1 - .../intrinsics/IntrinsicImplementations.kt | 22 ------ .../ir/interpreter/proxy/CommonProxy.kt | 57 ++++++++++++++ .../ir/interpreter/proxy/LambdaProxy.kt | 60 ++++++++++++++ .../kotlin/ir/interpreter/proxy/Proxy.kt | 34 ++++++++ .../kotlin/ir/interpreter/state/Complex.kt | 1 + .../kotlin/ir/interpreter/state/Lambda.kt | 9 +++ .../kotlin/ir/interpreter/state/Wrapper.kt | 21 +++-- .../interpreter/GenerateInterpreterMap.kt | 4 +- 12 files changed, 203 insertions(+), 92 deletions(-) create mode 100644 compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt create mode 100644 compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/LambdaProxy.kt create mode 100644 compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 0ca8f15ad18..9fdbe34997a 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -16,6 +16,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl import org.jetbrains.kotlin.ir.interpreter.builtins.* import org.jetbrains.kotlin.ir.interpreter.exceptions.* import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator +import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy +import org.jetbrains.kotlin.ir.interpreter.proxy.LambdaProxy.Companion.asProxy +import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy +import org.jetbrains.kotlin.ir.interpreter.proxy.unwrap import org.jetbrains.kotlin.ir.interpreter.stack.StackImpl import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.* @@ -89,62 +93,14 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map } } - /** - * calledFromBuiltIns - used to avoid cyclic calls. For example: - * override fun toString(): String { - * return super.toString() - * } - */ - internal class Proxy(val state: Common, val interpreter: IrInterpreter, private val calledFromBuiltIns: Boolean = false) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Proxy - - val valueArguments = mutableListOf() - val equalsFun = state.getEqualsFunction() - if (equalsFun.isFakeOverriddenFromAny() || calledFromBuiltIns) return this.state === other.state - - equalsFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } - valueArguments.add(Variable(equalsFun.valueParameters.single().symbol, other.state)) - - return with(interpreter) { - stack.newFrame(initPool = valueArguments) { - equalsFun.interpret() - } - (stack.popReturnValue() as Primitive<*>).value as Boolean - } // TODO check + internal fun IrFunction.interpret(valueArguments: List): Any? { + val returnLabel = stack.newFrame(initPool = valueArguments) { + this@interpret.interpret() } - - override fun hashCode(): Int { - val valueArguments = mutableListOf() - val hashCodeFun = state.getHashCodeFunction() - if (hashCodeFun.isFakeOverriddenFromAny() || calledFromBuiltIns) return System.identityHashCode(state) - - hashCodeFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } - return with(interpreter) { - stack.newFrame(initPool = valueArguments) { - hashCodeFun.interpret() - } - (stack.popReturnValue() as Primitive<*>).value as Int - }// TODO check - } - - override fun toString(): String { - val valueArguments = mutableListOf() - val toStringFun = state.getToStringFunction() - if (toStringFun.isFakeOverriddenFromAny() || calledFromBuiltIns) { - return "${state.irClass.internalName()}@" + hashCode().toString(16).padStart(8, '0') - } - - toStringFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } - return with(interpreter) { - stack.newFrame(initPool = valueArguments) { - toStringFun.interpret() - } - (stack.popReturnValue() as Primitive<*>).value as String - }// TODO check + return when (returnLabel.returnLabel) { + ReturnLabel.REGULAR -> stack.popReturnValue().unwrap(this@IrInterpreter) + ReturnLabel.EXCEPTION -> throw stack.popReturnValue() as ExceptionState + else -> TODO("$returnLabel not supported as result of interpretation") } } @@ -153,8 +109,8 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map is ExceptionState -> this is Wrapper -> this.value is Primitive<*> -> this.value - is Common -> Proxy(this, this@IrInterpreter, calledFromBuiltIns) - is Lambda -> this // TODO as Proxy + is Common -> CommonProxy(this, this@IrInterpreter, calledFromBuiltIns) + is Lambda -> this.asProxy(this@IrInterpreter) else -> throw AssertionError("${this::class} is unsupported as argument for wrap function") } } @@ -350,7 +306,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map // dispatch receiver processing val rawDispatchReceiver = expression.dispatchReceiver rawDispatchReceiver?.interpret()?.check { return it } - val dispatchReceiver = rawDispatchReceiver?.let { stack.popReturnValue() }?.checkNullability(expression.dispatchReceiver?.type) + var dispatchReceiver = rawDispatchReceiver?.let { stack.popReturnValue() }?.checkNullability(expression.dispatchReceiver?.type) // extension receiver processing val rawExtensionReceiver = expression.extensionReceiver @@ -358,6 +314,10 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map val extensionReceiver = rawExtensionReceiver?.let { stack.popReturnValue() }?.checkNullability(expression.extensionReceiver?.type) val irFunction = dispatchReceiver?.getIrFunctionByIrCall(expression) ?: expression.symbol.owner + dispatchReceiver = when (irFunction.parent) { + (dispatchReceiver as? Complex)?.superWrapperClass?.irClass -> dispatchReceiver.superWrapperClass + else -> dispatchReceiver + } // it is important firstly to add receiver, then arguments; this order is used in builtin method call irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> valueArguments.add(Variable(it, receiver)) } } @@ -774,7 +734,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map is Primitive<*> -> arrayToList(result.value) is Common -> when { result.irClass.defaultType.isUnsignedArray() -> arrayToList((result.fields.single().state as Primitive<*>).value) - else -> listOf(Proxy(result, this)) + else -> listOf(CommonProxy(result, this)) } else -> listOf(result) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 0053a503b89..c89b70b6929 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation import org.jetbrains.kotlin.ir.interpreter.exceptions.throwAsUserException import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.* +import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* @@ -57,7 +58,7 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression { internal fun Any?.toState(irType: IrType): State { return when (this) { - is IrInterpreter.Proxy -> this.state + is Proxy -> this.state is State -> this is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double, is Array<*>, is ByteArray, is CharArray, is ShortArray, is IntArray, is LongArray, is FloatArray, is DoubleArray, is BooleanArray -> Primitive(this, irType) @@ -197,6 +198,7 @@ internal fun IrType.isPrimitiveArray(): Boolean { } internal fun IrType.isFunction() = this.getClass()?.fqNameWhenAvailable?.asString()?.startsWith("kotlin.Function") ?: false +internal fun IrType.isKFunction() = this.getClass()?.fqNameWhenAvailable?.asString()?.startsWith("kotlin.reflect.KFunction") ?: false internal fun IrType.isTypeParameter() = classifierOrNull is IrTypeParameterSymbol diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt index 59cb9a08421..b15f31ad8bb 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt @@ -16,7 +16,7 @@ package org.jetbrains.kotlin.ir.interpreter.builtins -import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy /** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */ @@ -447,7 +447,7 @@ val binaryFunctions = mapOf>( binaryOperation("greaterOrEqual", "Long", "Long") { a, b -> a >= b }, binaryOperation("greaterOrEqual", "Double", "Double") { a, b -> a >= b }, binaryOperation("EQEQ", "Any?", "Any?") { a, b -> a == b }, - binaryOperation("EQEQEQ", "Any?", "Any?") { a, b -> if (a is IrInterpreter.Proxy && b is IrInterpreter.Proxy) a.state === b.state else a === b }, + binaryOperation("EQEQEQ", "Any?", "Any?") { a, b -> if (a is Proxy && b is Proxy) a.state === b.state else a === b }, binaryOperation("ieee754equals", "Float?", "Float?") { a, b -> a == b }, binaryOperation("ieee754equals", "Double?", "Double?") { a, b -> a == b }, binaryOperation("ANDAND", "Boolean", "Boolean") { a, b -> a && b }, diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt index a8933526e44..f0811e266b4 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt @@ -19,7 +19,6 @@ internal class IntrinsicEvaluator { ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.evaluate(irFunction, stack, interpret) EnumValues.equalTo(irFunction) -> EnumValues.evaluate(irFunction, stack, interpret) EnumValueOf.equalTo(irFunction) -> EnumValueOf.evaluate(irFunction, stack, interpret) - RegexReplace.equalTo(irFunction) -> RegexReplace.evaluate(irFunction, stack, interpret) EnumHashCode.equalTo(irFunction) -> EnumHashCode.evaluate(irFunction, stack, interpret) JsPrimitives.equalTo(irFunction) -> JsPrimitives.evaluate(irFunction, stack, interpret) ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.evaluate(irFunction, stack, interpret) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index 9bea2d637d8..f73d82f5864 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -105,28 +105,6 @@ internal object EnumValueOf : IntrinsicBase() { } } -internal object RegexReplace : IntrinsicBase() { - override fun equalTo(irFunction: IrFunction): Boolean { - val fqName = irFunction.fqNameWhenAvailable.toString() - return fqName == "kotlin.text.Regex.replace" && irFunction.valueParameters.size == 2 - } - - override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult { - val states = stack.getAll().map { it.state } - val regex = states.filterIsInstance().single().value as Regex - val input = states.filterIsInstance>().single().asString() - val transform = states.filterIsInstance().single().irFunction - val matchResultParameter = transform.valueParameters.single() - val result = regex.replace(input) { - val itAsState = Variable(matchResultParameter.symbol, Wrapper(it, matchResultParameter.type.classOrNull!!.owner)) - stack.newFrame(initPool = listOf(itAsState)) { transform.interpret() }//.check { return it } - stack.popReturnValue().asString() - } - stack.pushReturnValue(result.toState(irFunction.returnType)) - return Next - } -} - internal object EnumHashCode : IntrinsicBase() { override fun equalTo(irFunction: IrFunction): Boolean { val fqName = irFunction.fqNameWhenAvailable.toString() diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt new file mode 100644 index 00000000000..6950576c935 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt @@ -0,0 +1,57 @@ +/* + * 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.ir.interpreter.proxy + +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.getDispatchReceiver +import org.jetbrains.kotlin.ir.interpreter.internalName +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.Common +import org.jetbrains.kotlin.ir.util.isFakeOverriddenFromAny + +/** + * calledFromBuiltIns - used to avoid cyclic calls. For example: + * override fun toString(): String { + * return super.toString() + * } + */ +internal class CommonProxy(override val state: Common, override val interpreter: IrInterpreter, private val calledFromBuiltIns: Boolean = false): Proxy { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as CommonProxy + + val valueArguments = mutableListOf() + val equalsFun = state.getEqualsFunction() + if (equalsFun.isFakeOverriddenFromAny() || calledFromBuiltIns) return this.state === other.state + + equalsFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } + valueArguments.add(Variable(equalsFun.valueParameters.single().symbol, other.state)) + + return with(interpreter) { equalsFun.interpret(valueArguments) } as Boolean + } + + override fun hashCode(): Int { + val valueArguments = mutableListOf() + val hashCodeFun = state.getHashCodeFunction() + if (hashCodeFun.isFakeOverriddenFromAny() || calledFromBuiltIns) return System.identityHashCode(state) + + hashCodeFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } + return with(interpreter) { hashCodeFun.interpret(valueArguments) } as Int + } + + override fun toString(): String { + val valueArguments = mutableListOf() + val toStringFun = state.getToStringFunction() + if (toStringFun.isFakeOverriddenFromAny() || calledFromBuiltIns) { + return "${state.irClass.internalName()}@" + hashCode().toString(16).padStart(8, '0') + } + + toStringFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } + return with(interpreter) { toStringFun.interpret(valueArguments) } as String + } +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/LambdaProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/LambdaProxy.kt new file mode 100644 index 00000000000..800e485cbdb --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/LambdaProxy.kt @@ -0,0 +1,60 @@ +/* + * 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.ir.interpreter.proxy + +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.stack.Variable +import org.jetbrains.kotlin.ir.interpreter.state.Lambda +import org.jetbrains.kotlin.ir.interpreter.toState + +internal class LambdaProxy(override val state: Lambda, override val interpreter: IrInterpreter): Proxy { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as LambdaProxy + + return state == other.state + } + + override fun hashCode(): Int { + return state.hashCode() + } + + override fun toString(): String { + return state.toString() + } + + companion object { + fun Lambda.asProxy(interpreter: IrInterpreter): Any { + val lambdaProxy = LambdaProxy(this, interpreter) + val arity = this.getArity() + val hasBigArity = arity == null || arity >= FunctionInvokeDescriptor.BIG_ARITY + + val functionClass = when { + !hasBigArity && this.isFunction -> Class.forName("kotlin.jvm.functions." + this.irClass.name) + hasBigArity && this.isFunction -> Class.forName("kotlin.jvm.functions.FunctionN") + this.isKFunction -> Class.forName("kotlin.reflect.KFunction") + else -> throw InternalError("Cannot handle lambda $this as proxy") + } + return java.lang.reflect.Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), arrayOf(functionClass)) + { proxy, method, args -> + when { + method.name == "invoke" && method.parameterTypes.single().isObject() -> { + val valueArguments = this.irFunction.valueParameters + .mapIndexed { index, parameter -> Variable(parameter.symbol, args[index].toState(parameter.type)) } + with(interpreter) { lambdaProxy.state.irFunction.interpret(valueArguments) } + } + method.name == "equals" && method.parameterTypes.single().isObject() -> lambdaProxy.equals(args.single()) + method.name == "hashCode" && method.parameterTypes.isEmpty() -> lambdaProxy.hashCode() + method.name == "toString" && method.parameterTypes.isEmpty() -> lambdaProxy.toString() + else -> throw InternalError("Cannot invoke method ${method.name} from lambda $this") + } + } + } + } +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt new file mode 100644 index 00000000000..1f9c75c2aeb --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/Proxy.kt @@ -0,0 +1,34 @@ +/* + * 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.ir.interpreter.proxy + +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.proxy.LambdaProxy.Companion.asProxy +import org.jetbrains.kotlin.ir.interpreter.state.* + +internal interface Proxy { + val state: State + val interpreter: IrInterpreter + + override fun equals(other: Any?): Boolean + override fun hashCode(): Int + override fun toString(): String +} + +internal fun State.unwrap(interpreter: IrInterpreter): Any? { + return when (this) { + is Proxy -> this.state + is Primitive<*> -> this.value + is Common -> CommonProxy(this, interpreter) + is Lambda -> this.asProxy(interpreter) + is Wrapper -> this.value + else -> throw AssertionError("Unsupported state for proxy unwrap: ${this::class.java}") + } +} + +internal fun Class<*>.isObject(): Boolean { + return this.name == "java.lang.Object" +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt index a75e1d638dc..6c22167d808 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt @@ -50,6 +50,7 @@ internal interface Complex: State { } private fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction { + if (owner.parent == superWrapperClass?.irClass) return owner if (!owner.isFakeOverride || owner.body != null || owner.parentAsClass.defaultType.isAny()) return owner val overriddenOwner = owner.overriddenSymbols.singleOrNull { !it.owner.parentAsClass.isInterface }?.owner diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Lambda.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Lambda.kt index 03e881ffed9..26ac2b2be61 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Lambda.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Lambda.kt @@ -11,6 +11,9 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.interpreter.isFunction +import org.jetbrains.kotlin.ir.interpreter.isKFunction +import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.nameForIrSerialization import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.utils.addToStdlib.cast @@ -18,12 +21,18 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast internal class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State { override val fields: MutableList = mutableListOf() override val typeArguments: MutableList = mutableListOf() + val isKFunction = irClass.defaultType.isKFunction() + val isFunction = irClass.defaultType.isFunction() private val invokeSymbol = irClass.declarations .single { it.nameForIrSerialization.asString() == "invoke" } .cast() .getLastOverridden().symbol + fun getArity(): Int? { + return irClass.name.asString().removePrefix("Function").removePrefix("KFunction").toIntOrNull() + } + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { return if (invokeSymbol == expression.symbol) irFunction else null } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt index 596354765aa..651d80e936e 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.interpreter.state +import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrFunction @@ -124,19 +125,28 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex //TODO check if primitive array is possible here return when { notNullType.isPrimitiveType() || notNullType.isString() -> getPrimitiveClass(notNullType, asObject)!! - notNullType.isArray() -> if (asObject) Array::class.javaObjectType else Array::class.java + notNullType.isArray() -> { + val argumentFqName = (this as IrSimpleType).arguments.single().typeOrNull?.classOrNull?.owner?.fqNameWhenAvailable + argumentFqName?.let { Class.forName("[L$it;") } ?: Array::class.java + } notNullType.isNothing() -> Nothing::class.java notNullType.isAny() -> Any::class.java + notNullType.isUnit() -> if (asObject) Void::class.javaObjectType else Void::class.javaPrimitiveType!! notNullType.isNumber() -> Number::class.java notNullType.isCharSequence() -> CharSequence::class.java notNullType.isComparable() -> Comparable::class.java notNullType.isThrowable() -> Throwable::class.java notNullType.isIterable() -> Iterable::class.java - // TODO implement function mapping; all complexity is to map big arity to FunctionN - //notNullType.isKFunction() -> Class.forName("kotlin.reflect.KFunction") - //notNullType.isFunction() -> Class.forName("kotlin.jvm.functions.Function_TODO") - //notNullType.isSuspendFunction() || notNullType.isKSuspendFunction() -> throw AssertionError() + notNullType.isKFunction() -> Class.forName("kotlin.reflect.KFunction") + notNullType.isFunction() -> { + val arity = fqName?.removePrefix("kotlin.Function")?.toIntOrNull() + return when { + arity == null || arity >= BuiltInFunctionArity.BIG_ARITY -> Class.forName("kotlin.jvm.functions.FunctionN") + else -> Class.forName("kotlin.jvm.functions.${fqName.removePrefix("kotlin.")}") + } + } + //notNullType.isSuspendFunction() || notNullType.isKSuspendFunction() -> throw AssertionError() //TODO fqName == "kotlin.Enum" -> Enum::class.java fqName == "kotlin.collections.Collection" || fqName == "kotlin.collections.MutableCollection" -> Collection::class.java @@ -147,6 +157,7 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex fqName == "kotlin.collections.Iterator" || fqName == "kotlin.collections.MutableIterator" -> Iterator::class.java fqName == "kotlin.collections.Map.Entry" || fqName == "kotlin.collections.MutableMap.MutableEntry" -> Map.Entry::class.java fqName == "kotlin.collections.ListIterator" || fqName == "kotlin.collections.MutableListIterator" -> ListIterator::class.java + fqName == "kotlin.collections.HashMap" -> HashMap::class.java owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue()) fqName == null -> Any::class.java // null if this.isTypeParameter() diff --git a/generators/interpreter/GenerateInterpreterMap.kt b/generators/interpreter/GenerateInterpreterMap.kt index 97ad3eb63e7..4872b907cd7 100644 --- a/generators/interpreter/GenerateInterpreterMap.kt +++ b/generators/interpreter/GenerateInterpreterMap.kt @@ -39,7 +39,7 @@ fun generateMap(): String { p.println(File("license/COPYRIGHT.txt").readText()) p.println("package org.jetbrains.kotlin.ir.interpreter.builtins") p.println() - p.println("import org.jetbrains.kotlin.ir.interpreter.IrInterpreter") + p.println("import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy") p.println() p.println("/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */") p.println() @@ -150,7 +150,7 @@ private fun generateBinaryBody( val methodName = "${function.name}" val methodSymbol = getIrMethodSymbolByName(methodName) val body = when (methodName) { - IrBuiltIns.OperatorNames.EQEQEQ -> "if (a is IrInterpreter.Proxy && b is IrInterpreter.Proxy) a.state === b.state else a === b" + IrBuiltIns.OperatorNames.EQEQEQ -> "if (a is Proxy && b is Proxy) a.state === b.state else a === b" else -> "a $methodSymbol b" } " binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> $body }"