From 4fdfdb9b4c5271cadbb4c03233ec0c2be5d58dfe Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Wed, 10 Jun 2020 19:16:09 +0300 Subject: [PATCH] Implement StringBuilder interpretation --- .../common/interpreter/IrInterpreter.kt | 27 +++- .../backend/common/interpreter/Utils.kt | 37 ++++-- .../backend/common/interpreter/stack/State.kt | 122 ++++++++---------- 3 files changed, 98 insertions(+), 88 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index 7cafcc89e16..63cd533fe57 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -21,9 +21,7 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.statements -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType +import java.lang.invoke.MethodHandle enum class Code(var info: String = "") { NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION @@ -112,6 +110,14 @@ class IrInterpreter(irModule: IrModuleFragment) { return irFunction.body?.interpret(data) ?: throw AssertionError("Ir function must be with body") } + private fun MethodHandle.invokeMethod(irFunction: IrFunction, data: Frame): Code { + // TODO try catch + val result = this.invokeWithArguments(irFunction.getArgsForMethodInvocation(data)) + data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) + + return Code.NEXT + } + private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code { if (irFunction.body == null) { val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex @@ -232,8 +238,8 @@ class IrInterpreter(irModule: IrModuleFragment) { val isWrapper = (dispatchReceiver is Wrapper && rawExtensionReceiver == null) || (extensionReceiver is Wrapper && rawDispatchReceiver == null) val code = when { - isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).invoke(irFunction as IrFunctionImpl, newFrame) - irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.invokeStatic(irFunction as IrFunctionImpl, newFrame) + isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame) + irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, newFrame) irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) irFunction.body == null -> calculateBuiltIns(irFunction, newFrame) @@ -247,7 +253,14 @@ class IrInterpreter(irModule: IrModuleFragment) { interpretValueParameters(constructorCall, data).also { if (it != Code.NEXT) return it } val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList() val newFrame = InterpreterFrame(valueParameters) - val state = Complex(constructorCall.symbol.owner.parent as IrClass, mutableListOf()) + + val owner = constructorCall.symbol.owner + val parent = owner.parent as IrClass + if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) { + return Wrapper.getConstructorMethod(owner).invokeMethod(owner, newFrame).apply { data.pushReturnValue(newFrame) } + } + + val state = Complex(parent, mutableListOf()) newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT if (newFrame.hasReturnValue()) { @@ -419,7 +432,7 @@ class IrInterpreter(irModule: IrModuleFragment) { "kotlin.FloatArray" -> Primitive(args.map { (it as Primitive).value }.toFloatArray(), type) "kotlin.DoubleArray" -> Primitive(args.map { (it as Primitive).value }.toDoubleArray(), type) "kotlin.BooleanArray" -> Primitive(args.map { (it as Primitive).value }.toBooleanArray(), type) - else -> Primitive>(args.toTypedArray(), type) + else -> Primitive>(args.map { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }.toTypedArray(), type) } data.pushReturnValue(array) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index fe534b6c800..fef32e3c688 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -5,24 +5,23 @@ package org.jetbrains.kotlin.backend.common.interpreter +import org.jetbrains.kotlin.backend.common.interpreter.builtins.evaluateIntrinsicAnnotation +import org.jetbrains.kotlin.backend.common.interpreter.stack.Frame import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive import org.jetbrains.kotlin.backend.common.interpreter.stack.State import org.jetbrains.kotlin.backend.common.interpreter.stack.Wrapper import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer +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.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.classOrNull -import org.jetbrains.kotlin.ir.types.isArray -import org.jetbrains.kotlin.ir.types.isPrimitiveType +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.isFakeOverride -import org.jetbrains.kotlin.ir.util.isPrimitiveArray import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver @@ -102,7 +101,7 @@ fun Any?.toState(irType: IrType): State { is State -> this is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double -> Primitive(this, irType) null -> Primitive(this, irType) - else -> Wrapper(irType.classOrNull!!.owner, this) + else -> Wrapper(this, irType.classOrNull!!.owner) } } @@ -126,7 +125,8 @@ fun IrConst.toPrimitive(): Primitive { return Primitive(this.value, this.type) } -fun IrAnnotationContainer.hasAnnotation(annotation: FqName): Boolean { +fun IrAnnotationContainer?.hasAnnotation(annotation: FqName): Boolean { + this ?: return false if (this.annotations.isNotEmpty()) { return this.annotations.any { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } } @@ -134,7 +134,13 @@ fun IrAnnotationContainer.hasAnnotation(annotation: FqName): Boolean { } fun IrAnnotationContainer.getAnnotation(annotation: FqName): IrConstructorCall { - return this.annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } + return this.annotations.firstOrNull { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } + ?: ((this as IrFunction).parent as IrClass).annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } +} + +fun IrAnnotationContainer.getEvaluateIntrinsicValue(): String? { + if (!this.hasAnnotation(evaluateIntrinsicAnnotation)) return null + return (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString() } fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { @@ -156,6 +162,17 @@ fun IrType.getFqName(): String? { return this.classOrNull?.owner?.fqNameForIrSerialization?.asString() } -fun IrType?.isPrimitiveState(): Boolean { - return this?.isPrimitiveType() == true || this?.isArray() == true || this?.isPrimitiveArray() == true +fun IrFunction.getArgsForMethodInvocation(data: Frame): List { + val argsValues = data.getAll().map { (it.state as? Wrapper)?.value ?: (it.state as Primitive<*>).value }.toMutableList() + + // TODO if vararg isn't last parameter + // must convert vararg array into separated elements for correct invoke + if (this.valueParameters.lastOrNull()?.varargElementType != null) { + argsValues.removeAt(argsValues.size - 1) + val varargState = data.getVariableState(this.valueParameters.last().descriptor) + val varargValue = (varargState as? Wrapper)?.value ?: (varargState as Primitive<*>).value + argsValues.addAll(varargValue as Array) + } + + return argsValues } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt index b5224fbefd0..acf151e1d5b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt @@ -17,11 +17,13 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.IrConst -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.isTypeParameter import org.jetbrains.kotlin.name.FqNameUnsafe +import java.lang.invoke.MethodHandle import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType @@ -37,8 +39,8 @@ interface State { fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? } -open class Primitive(var value: T, val type: IrType) : State { - final override val fields: MutableList = mutableListOf() +class Primitive(var value: T, val type: IrType) : State { + override val fields: MutableList = mutableListOf() init { val properties = type.classOrNull!!.owner.declarations.filterIsInstance() @@ -132,79 +134,55 @@ open class Complex(private var type: IrClass, override val fields: MutableList).value.toString()) - val methodType = irFunction.getMethodType(withExtensionReceiver = true) - val method = MethodHandles.lookup().findStatic(jvmFileName, irFunction.name.asString(), methodType) - - val result = method.invokeWithArguments(irFunction.getArgs(data)) - data.pushReturnValue(result.toState(irFunction.returnType)) - - return Code.NEXT + val methodType = irFunction.getMethodType() + return MethodHandles.lookup().findStatic(jvmFileName, irFunction.name.asString(), methodType) } - private fun IrFunctionImpl.getMethodType(withExtensionReceiver: Boolean = false): MethodType { - val returnClass = this.returnType.getClass(this.isReturnTypePrimitiveAsObject()) + private fun IrFunction.getMethodType(): MethodType { val argsClasses = this.valueParameters.map { it.type.getClass(this.isValueParameterPrimitiveAsObject(it.index)) } + return if (this is IrFunctionImpl) { + // for regular methods and functions + val returnClass = this.returnType.getClass(this.isReturnTypePrimitiveAsObject()) + val extensionClass = this.extensionReceiverParameter?.type?.getClass(this.isExtensionReceiverPrimitive()) - val extensionClass = when { - withExtensionReceiver -> this.extensionReceiverParameter?.type?.getClass(this.isExtensionReceiverPrimitiveAsObject()) - else -> null + MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses) + } else { + // for constructors + MethodType.methodType(Void::class.javaPrimitiveType, argsClasses) } - - return MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses) - } - - private fun IrFunctionImpl.getArgs(data: Frame): List { - val argsValues = data.getAll().map { (it.state as? Wrapper)?.wrapperValue ?: (it.state as? Any) }.toMutableList() - - if (this.extensionReceiverParameter?.type.isPrimitiveState()) { - val varargState = data.getVariableState(this.symbol.getExtensionReceiver()!!) - argsValues[0] = (varargState as Primitive<*>).value - } - - for ((index, valueParameter) in this.valueParameters.withIndex().reversed()) { - if (valueParameter.type.isPrimitiveState()) { - argsValues[argsValues.size - 1 - index] = (argsValues[argsValues.size - 1 - index] as Primitive<*>).value - } - } - - // TODO if vararg isn't last parameter - // must convert vararg array into separated elements for correct invoke - if (this.valueParameters.lastOrNull()?.varargElementType != null) { - argsValues.removeAt(argsValues.size - 1) - val varargState = data.getVariableState(this.valueParameters.last().descriptor) - val varargValue = (varargState as? Wrapper)?.wrapperValue ?: (varargState as Primitive<*>).value - argsValues.addAll(varargValue as Array) - } - - return argsValues } private fun IrType.getClass(asObject: Boolean): Class { val fqName = this.getFqName() + val owner = this.classOrNull?.owner return when { + owner?.hasAnnotation(evaluateIntrinsicAnnotation) == true -> Class.forName(owner.getEvaluateIntrinsicValue()) this.isPrimitiveType() -> getPrimitiveClass(fqName!!, asObject) this.isArray() -> if (asObject) Array::class.javaObjectType else Array::class.java //TODO primitive array @@ -213,16 +191,18 @@ class Wrapper(private val type: IrClass, private val wrapperValue: Any) : Comple } ?: Class.forName(fqName) } - private fun IrFunctionImpl.getOriginalOverriddenSymbols(): MutableList { - val overriddenSymbols = mutableListOf() - val pool = this.overriddenSymbols.toMutableList() - val iterator = pool.listIterator() - for (symbol in iterator) { - if (symbol.owner.overriddenSymbols.isEmpty()) { - overriddenSymbols += symbol - iterator.remove() - } else { - symbol.owner.overriddenSymbols.forEach { iterator.add(it) } + private fun IrFunction.getOriginalOverriddenSymbols(): MutableList { + val overriddenSymbols = mutableListOf() + if (this is IrFunctionImpl) { + val pool = this.overriddenSymbols.toMutableList() + val iterator = pool.listIterator() + for (symbol in iterator) { + if (symbol.owner.overriddenSymbols.isEmpty()) { + overriddenSymbols += symbol + iterator.remove() + } else { + symbol.owner.overriddenSymbols.forEach { iterator.add(it) } + } } } @@ -230,11 +210,11 @@ class Wrapper(private val type: IrClass, private val wrapperValue: Any) : Comple return overriddenSymbols } - private fun IrFunctionImpl.isExtensionReceiverPrimitiveAsObject(): Boolean { + private fun IrFunction.isExtensionReceiverPrimitive(): Boolean { return this.extensionReceiverParameter?.type?.isPrimitiveType() == false } - private fun IrFunctionImpl.isReturnTypePrimitiveAsObject(): Boolean { + private fun IrFunction.isReturnTypePrimitiveAsObject(): Boolean { for (symbol in getOriginalOverriddenSymbols()) { if (!symbol.owner.returnType.isTypeParameter() && !symbol.owner.returnType.isNullable()) { return false @@ -243,7 +223,7 @@ class Wrapper(private val type: IrClass, private val wrapperValue: Any) : Comple return true } - private fun IrFunctionImpl.isValueParameterPrimitiveAsObject(index: Int): Boolean { + private fun IrFunction.isValueParameterPrimitiveAsObject(index: Int): Boolean { for (symbol in getOriginalOverriddenSymbols()) { if (!symbol.owner.valueParameters[index].type.isTypeParameter() && !symbol.owner.valueParameters[index].type.isNullable()) { return false @@ -254,10 +234,10 @@ class Wrapper(private val type: IrClass, private val wrapperValue: Any) : Comple } override fun copy(): State { - return Wrapper(type, wrapperValue) + return Wrapper(value, type) } override fun toString(): String { - return "Wrapper(obj='$typeFqName', value=$wrapperValue)" + return "Wrapper(obj='$typeFqName', value=$value)" } }