Implement LambdaProxy class
This commit is contained in:
committed by
TeamCityServer
parent
1d0acedc48
commit
96a090f2ab
+19
-59
@@ -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.builtins.*
|
||||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.*
|
import org.jetbrains.kotlin.ir.interpreter.exceptions.*
|
||||||
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
|
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.StackImpl
|
||||||
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.*
|
||||||
@@ -89,62 +93,14 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
internal fun IrFunction.interpret(valueArguments: List<Variable>): Any? {
|
||||||
* calledFromBuiltIns - used to avoid cyclic calls. For example:
|
val returnLabel = stack.newFrame(initPool = valueArguments) {
|
||||||
* override fun toString(): String {
|
this@interpret.interpret()
|
||||||
* 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<Variable>()
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
return when (returnLabel.returnLabel) {
|
||||||
override fun hashCode(): Int {
|
ReturnLabel.REGULAR -> stack.popReturnValue().unwrap(this@IrInterpreter)
|
||||||
val valueArguments = mutableListOf<Variable>()
|
ReturnLabel.EXCEPTION -> throw stack.popReturnValue() as ExceptionState
|
||||||
val hashCodeFun = state.getHashCodeFunction()
|
else -> TODO("$returnLabel not supported as result of interpretation")
|
||||||
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<Variable>()
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +109,8 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
|
|||||||
is ExceptionState -> this
|
is ExceptionState -> this
|
||||||
is Wrapper -> this.value
|
is Wrapper -> this.value
|
||||||
is Primitive<*> -> this.value
|
is Primitive<*> -> this.value
|
||||||
is Common -> Proxy(this, this@IrInterpreter, calledFromBuiltIns)
|
is Common -> CommonProxy(this, this@IrInterpreter, calledFromBuiltIns)
|
||||||
is Lambda -> this // TODO as Proxy
|
is Lambda -> this.asProxy(this@IrInterpreter)
|
||||||
else -> throw AssertionError("${this::class} is unsupported as argument for wrap function")
|
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
|
// dispatch receiver processing
|
||||||
val rawDispatchReceiver = expression.dispatchReceiver
|
val rawDispatchReceiver = expression.dispatchReceiver
|
||||||
rawDispatchReceiver?.interpret()?.check { return it }
|
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
|
// extension receiver processing
|
||||||
val rawExtensionReceiver = expression.extensionReceiver
|
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 extensionReceiver = rawExtensionReceiver?.let { stack.popReturnValue() }?.checkNullability(expression.extensionReceiver?.type)
|
||||||
|
|
||||||
val irFunction = dispatchReceiver?.getIrFunctionByIrCall(expression) ?: expression.symbol.owner
|
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
|
// 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)) } }
|
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 Primitive<*> -> arrayToList(result.value)
|
||||||
is Common -> when {
|
is Common -> when {
|
||||||
result.irClass.defaultType.isUnsignedArray() -> arrayToList((result.fields.single().state as Primitive<*>).value)
|
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)
|
else -> listOf(result)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.exceptions.throwAsUserException
|
||||||
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.proxy.Proxy
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
@@ -57,7 +58,7 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
|
|||||||
|
|
||||||
internal fun Any?.toState(irType: IrType): State {
|
internal fun Any?.toState(irType: IrType): State {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is IrInterpreter.Proxy -> this.state
|
is Proxy -> this.state
|
||||||
is State -> this
|
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 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)
|
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.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
|
internal fun IrType.isTypeParameter() = classifierOrNull is IrTypeParameterSymbol
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.interpreter.builtins
|
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 */
|
/** 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<CompileTimeFunction, Function2<Any?, Any?, Any?>>(
|
|||||||
binaryOperation<Long, Long>("greaterOrEqual", "Long", "Long") { a, b -> a >= b },
|
binaryOperation<Long, Long>("greaterOrEqual", "Long", "Long") { a, b -> a >= b },
|
||||||
binaryOperation<Double, Double>("greaterOrEqual", "Double", "Double") { a, b -> a >= b },
|
binaryOperation<Double, Double>("greaterOrEqual", "Double", "Double") { a, b -> a >= b },
|
||||||
binaryOperation<Any?, Any?>("EQEQ", "Any?", "Any?") { a, b -> a == b },
|
binaryOperation<Any?, Any?>("EQEQ", "Any?", "Any?") { a, b -> a == b },
|
||||||
binaryOperation<Any?, Any?>("EQEQEQ", "Any?", "Any?") { a, b -> if (a is IrInterpreter.Proxy && b is IrInterpreter.Proxy) a.state === b.state else a === b },
|
binaryOperation<Any?, Any?>("EQEQEQ", "Any?", "Any?") { a, b -> if (a is Proxy && b is Proxy) a.state === b.state else a === b },
|
||||||
binaryOperation<Float?, Float?>("ieee754equals", "Float?", "Float?") { a, b -> a == b },
|
binaryOperation<Float?, Float?>("ieee754equals", "Float?", "Float?") { a, b -> a == b },
|
||||||
binaryOperation<Double?, Double?>("ieee754equals", "Double?", "Double?") { a, b -> a == b },
|
binaryOperation<Double?, Double?>("ieee754equals", "Double?", "Double?") { a, b -> a == b },
|
||||||
binaryOperation<Boolean, Boolean>("ANDAND", "Boolean", "Boolean") { a, b -> a && b },
|
binaryOperation<Boolean, Boolean>("ANDAND", "Boolean", "Boolean") { a, b -> a && b },
|
||||||
|
|||||||
-1
@@ -19,7 +19,6 @@ internal class IntrinsicEvaluator {
|
|||||||
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.evaluate(irFunction, stack, interpret)
|
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.evaluate(irFunction, stack, interpret)
|
||||||
EnumValues.equalTo(irFunction) -> EnumValues.evaluate(irFunction, stack, interpret)
|
EnumValues.equalTo(irFunction) -> EnumValues.evaluate(irFunction, stack, interpret)
|
||||||
EnumValueOf.equalTo(irFunction) -> EnumValueOf.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)
|
EnumHashCode.equalTo(irFunction) -> EnumHashCode.evaluate(irFunction, stack, interpret)
|
||||||
JsPrimitives.equalTo(irFunction) -> JsPrimitives.evaluate(irFunction, stack, interpret)
|
JsPrimitives.equalTo(irFunction) -> JsPrimitives.evaluate(irFunction, stack, interpret)
|
||||||
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.evaluate(irFunction, stack, interpret)
|
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.evaluate(irFunction, stack, interpret)
|
||||||
|
|||||||
-22
@@ -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<Wrapper>().single().value as Regex
|
|
||||||
val input = states.filterIsInstance<Primitive<*>>().single().asString()
|
|
||||||
val transform = states.filterIsInstance<Lambda>().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() {
|
internal object EnumHashCode : IntrinsicBase() {
|
||||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
|||||||
+57
@@ -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<Variable>()
|
||||||
|
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<Variable>()
|
||||||
|
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<Variable>()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -50,6 +50,7 @@ internal interface Complex: State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
|
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
|
if (!owner.isFakeOverride || owner.body != null || owner.parentAsClass.defaultType.isAny()) return owner
|
||||||
|
|
||||||
val overriddenOwner = owner.overriddenSymbols.singleOrNull { !it.owner.parentAsClass.isInterface }?.owner
|
val overriddenOwner = owner.overriddenSymbols.singleOrNull { !it.owner.parentAsClass.isInterface }?.owner
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
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.nameForIrSerialization
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
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 {
|
internal class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State {
|
||||||
override val fields: MutableList<Variable> = mutableListOf()
|
override val fields: MutableList<Variable> = mutableListOf()
|
||||||
override val typeArguments: MutableList<Variable> = mutableListOf()
|
override val typeArguments: MutableList<Variable> = mutableListOf()
|
||||||
|
val isKFunction = irClass.defaultType.isKFunction()
|
||||||
|
val isFunction = irClass.defaultType.isFunction()
|
||||||
|
|
||||||
private val invokeSymbol = irClass.declarations
|
private val invokeSymbol = irClass.declarations
|
||||||
.single { it.nameForIrSerialization.asString() == "invoke" }
|
.single { it.nameForIrSerialization.asString() == "invoke" }
|
||||||
.cast<IrSimpleFunction>()
|
.cast<IrSimpleFunction>()
|
||||||
.getLastOverridden().symbol
|
.getLastOverridden().symbol
|
||||||
|
|
||||||
|
fun getArity(): Int? {
|
||||||
|
return irClass.name.asString().removePrefix("Function").removePrefix("KFunction").toIntOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||||
return if (invokeSymbol == expression.symbol) irFunction else null
|
return if (invokeSymbol == expression.symbol) irFunction else null
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-5
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.interpreter.state
|
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.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
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
|
//TODO check if primitive array is possible here
|
||||||
return when {
|
return when {
|
||||||
notNullType.isPrimitiveType() || notNullType.isString() -> getPrimitiveClass(notNullType, asObject)!!
|
notNullType.isPrimitiveType() || notNullType.isString() -> getPrimitiveClass(notNullType, asObject)!!
|
||||||
notNullType.isArray() -> if (asObject) Array<Any?>::class.javaObjectType else Array<Any?>::class.java
|
notNullType.isArray() -> {
|
||||||
|
val argumentFqName = (this as IrSimpleType).arguments.single().typeOrNull?.classOrNull?.owner?.fqNameWhenAvailable
|
||||||
|
argumentFqName?.let { Class.forName("[L$it;") } ?: Array<Any?>::class.java
|
||||||
|
}
|
||||||
notNullType.isNothing() -> Nothing::class.java
|
notNullType.isNothing() -> Nothing::class.java
|
||||||
notNullType.isAny() -> Any::class.java
|
notNullType.isAny() -> Any::class.java
|
||||||
|
notNullType.isUnit() -> if (asObject) Void::class.javaObjectType else Void::class.javaPrimitiveType!!
|
||||||
notNullType.isNumber() -> Number::class.java
|
notNullType.isNumber() -> Number::class.java
|
||||||
notNullType.isCharSequence() -> CharSequence::class.java
|
notNullType.isCharSequence() -> CharSequence::class.java
|
||||||
notNullType.isComparable() -> Comparable::class.java
|
notNullType.isComparable() -> Comparable::class.java
|
||||||
notNullType.isThrowable() -> Throwable::class.java
|
notNullType.isThrowable() -> Throwable::class.java
|
||||||
notNullType.isIterable() -> Iterable::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.isKFunction() -> Class.forName("kotlin.reflect.KFunction")
|
notNullType.isFunction() -> {
|
||||||
//notNullType.isFunction() -> Class.forName("kotlin.jvm.functions.Function_TODO")
|
val arity = fqName?.removePrefix("kotlin.Function")?.toIntOrNull()
|
||||||
//notNullType.isSuspendFunction() || notNullType.isKSuspendFunction() -> throw AssertionError()
|
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.Enum" -> Enum::class.java
|
||||||
fqName == "kotlin.collections.Collection" || fqName == "kotlin.collections.MutableCollection" -> Collection::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.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.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.ListIterator" || fqName == "kotlin.collections.MutableListIterator" -> ListIterator::class.java
|
||||||
|
fqName == "kotlin.collections.HashMap" -> HashMap::class.java
|
||||||
|
|
||||||
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue())
|
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue())
|
||||||
fqName == null -> Any::class.java // null if this.isTypeParameter()
|
fqName == null -> Any::class.java // null if this.isTypeParameter()
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ fun generateMap(): String {
|
|||||||
p.println(File("license/COPYRIGHT.txt").readText())
|
p.println(File("license/COPYRIGHT.txt").readText())
|
||||||
p.println("package org.jetbrains.kotlin.ir.interpreter.builtins")
|
p.println("package org.jetbrains.kotlin.ir.interpreter.builtins")
|
||||||
p.println()
|
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()
|
||||||
p.println("/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */")
|
p.println("/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */")
|
||||||
p.println()
|
p.println()
|
||||||
@@ -150,7 +150,7 @@ private fun generateBinaryBody(
|
|||||||
val methodName = "${function.name}"
|
val methodName = "${function.name}"
|
||||||
val methodSymbol = getIrMethodSymbolByName(methodName)
|
val methodSymbol = getIrMethodSymbolByName(methodName)
|
||||||
val body = when (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"
|
else -> "a $methodSymbol b"
|
||||||
}
|
}
|
||||||
" binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> $body }"
|
" binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> $body }"
|
||||||
|
|||||||
Reference in New Issue
Block a user