From 1d0acedc48ae0544c2ac439b84618a496c8e2a75 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Fri, 28 Aug 2020 21:28:35 +0300 Subject: [PATCH] Rewrite Complex class as interface This change allow ExceptionState to be both: State and Throwable --- .../kotlin/ir/interpreter/IrInterpreter.kt | 6 +-- .../builtins/IrBuiltInsMapGenerated.kt | 5 +-- .../kotlin/ir/interpreter/state/Common.kt | 7 ++-- .../kotlin/ir/interpreter/state/Complex.kt | 17 +++++---- .../ir/interpreter/state/ExceptionState.kt | 38 +++++++++---------- .../kotlin/ir/interpreter/state/State.kt | 2 + .../kotlin/ir/interpreter/state/Wrapper.kt | 21 ++++++---- .../interpreter/GenerateInterpreterMap.kt | 6 +-- 8 files changed, 53 insertions(+), 49 deletions(-) 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 03a17915d28..0ca8f15ad18 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 @@ -150,7 +150,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map internal fun State.wrapAsProxyIfNeeded(calledFromBuiltIns: Boolean = false): Any? { return when (this) { - is ExceptionState -> this.getThisAsCauseForException() + is ExceptionState -> this is Wrapper -> this.value is Primitive<*> -> this.value is Common -> Proxy(this, this@IrInterpreter, calledFromBuiltIns) @@ -812,9 +812,9 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map private fun interpretTry(expression: IrTry): ExecutionResult { try { expression.tryResult.interpret().check(ReturnLabel.EXCEPTION) { return it } // if not exception -> return - val exception = stack.peekReturnValue() as ExceptionState + val exception = stack.peekReturnValue() for (catchBlock in expression.catches) { - if (exception.isSubtypeOf(catchBlock.catchParameter.type.classOrNull!!.owner)) { + if (exception.isSubtypeOf(catchBlock.catchParameter.type)) { catchBlock.interpret().check { return it } return Next } 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 571aa96fe8d..59cb9a08421 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 @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.ir.interpreter.builtins import org.jetbrains.kotlin.ir.interpreter.IrInterpreter -import org.jetbrains.kotlin.ir.interpreter.state.* /** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */ @@ -140,9 +139,7 @@ val unaryFunctions = mapOf>( unaryOperation>("iterator", "Array") { a -> a.iterator() }, unaryOperation("hashCode", "Any") { a -> a.hashCode() }, unaryOperation("toString", "Any") { a -> a.toString() }, - unaryOperation("CHECK_NOT_NULL", "T0?") { a -> a!! }, - unaryOperation("message", "Throwable") { a -> a.getMessage() }, - unaryOperation("cause", "Throwable") { a -> a.getCause() } + unaryOperation("CHECK_NOT_NULL", "T0?") { a -> a!! } ) val binaryFunctions = mapOf>( diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt index 2d66c53cc15..b5fb98d0dfc 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt @@ -9,9 +9,10 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization -internal class Common private constructor( - override val irClass: IrClass, override val fields: MutableList -) : Complex(irClass, fields) { +internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList) : Complex { + override var superWrapperClass: Wrapper? = null + override val typeArguments: MutableList = mutableListOf() + override var outerClass: Variable? = null constructor(irClass: IrClass) : this(irClass, mutableListOf()) 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 4c190ab715a..a75e1d638dc 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 @@ -14,16 +14,15 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.types.classOrNull -import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.isAny import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name -internal abstract class Complex(override val irClass: IrClass, override val fields: MutableList) : State { - var superWrapperClass: Wrapper? = null - override val typeArguments: MutableList = mutableListOf() - var outerClass: Variable? = null +internal interface Complex: State { + var superWrapperClass: Wrapper? + override val typeArguments: MutableList + var outerClass: Variable? fun irClassFqName(): String { return irClass.fqNameForIrSerialization.toString() @@ -34,7 +33,11 @@ internal abstract class Complex(override val irClass: IrClass, override val fiel val propertySetters = this.declarations.filterIsInstance().mapNotNull { it.setter } val functions = this.declarations.filterIsInstance() return (propertyGetters + propertySetters + functions).firstOrNull { - if (it is IrSimpleFunction) it.overrides(symbol.owner as IrSimpleFunction) else it == symbol.owner + val owner = symbol.owner + when { + it is IrSimpleFunction && owner is IrSimpleFunction -> it.overrides(owner) || owner.overrides(it) + else -> it == symbol.owner + } } } @@ -46,7 +49,7 @@ internal abstract class Complex(override val irClass: IrClass, override val fiel } } - protected fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction { + private fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction { 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/ExceptionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt index f8d50924b16..e0dfbcb83fb 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt @@ -17,7 +17,16 @@ import kotlin.math.min internal class ExceptionState private constructor( override val irClass: IrClass, override val fields: MutableList, stackTrace: List -) : Complex(irClass, fields) { +) : Complex, Throwable() { + + override var superWrapperClass: Wrapper? = null + override val typeArguments: MutableList = mutableListOf() + override var outerClass: Variable? = null + + override val message: String? + get() = getState(messageProperty.symbol)?.asStringOrNull() + override val cause: Throwable? + get() = getState(causeProperty.symbol)?.let { if (it is ExceptionState) it else null } private lateinit var exceptionFqName: String private val exceptionHierarchy = mutableListOf() @@ -45,6 +54,7 @@ internal class ExceptionState private constructor( constructor( exception: Throwable, irClass: IrClass, stackTrace: List ) : this(irClass, evaluateFields(exception, irClass, stackTrace), stackTrace + evaluateAdditionalStackTrace(exception)) { + setCause(null) // TODO check this fact if (irClass.name.asString() != exception::class.java.simpleName) { // ir class wasn't found in classpath, a stub was passed => need to save java class hierarchy this.exceptionFqName = exception::class.java.name @@ -54,18 +64,11 @@ internal class ExceptionState private constructor( } } - data class ExceptionData(val state: ExceptionState) : Throwable() { - override val message: String? = state.getMessage() - override fun fillInStackTrace() = this - - override fun toString(): String = state.getMessageWithName() - } - private fun setUpCauseIfNeeded(wrapper: Wrapper?) { - val cause = (wrapper?.value as? Throwable)?.cause as? ExceptionData - setCause(cause?.state) - if (getMessage() == null && cause != null) { - val causeMessage = cause.state.exceptionFqName + (cause.state.getMessage()?.let { ": $it" } ?: "") + val cause = (wrapper?.value as? Throwable)?.cause as? ExceptionState + setCause(cause) + if (message == null && cause != null) { + val causeMessage = cause.exceptionFqName + (cause.message?.let { ": $it" } ?: "") setMessage(causeMessage) } } @@ -85,23 +88,18 @@ internal class ExceptionState private constructor( setField(Variable(causeProperty.symbol, causeValue ?: Primitive(null, causeProperty.getter!!.returnType))) } - fun getMessage(): String? = (getState(messageProperty.symbol) as Primitive<*>).value as String? - private fun getMessageWithName(): String = getMessage()?.let { "$exceptionFqName: $it" } ?: exceptionFqName - - fun getCause(): ExceptionState? = getState(causeProperty.symbol)?.let { if (it is ExceptionState) it else null } - fun getFullDescription(): String { // TODO remainder of the stack trace with "..." - val message = getMessage().let { if (it?.isNotEmpty() == true) ": $it" else "" } + val message = message.let { if (it?.isNotEmpty() == true) ": $it" else "" } val prefix = if (stackTrace.isNotEmpty()) "\n\t" else "" val postfix = if (stackTrace.size > 10) "\n\t..." else "" - val causeMessage = getCause()?.getFullDescription()?.replaceFirst("Exception ", "\nCaused by: ") ?: "" + val causeMessage = (cause as? ExceptionState)?.getFullDescription()?.replaceFirst("Exception ", "\nCaused by: ") ?: "" return "Exception $exceptionFqName$message" + stackTrace.subList(0, min(stackTrace.size, 10)).joinToString(separator = "\n\t", prefix = prefix, postfix = postfix) + causeMessage } - fun getThisAsCauseForException() = ExceptionData(this) + override fun toString(): String = message?.let { "$exceptionFqName: $it" } ?: exceptionFqName companion object { private fun IrClass.getPropertyByName(name: String): IrProperty { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt index fd37cdc0845..6dfe5cfbe9e 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt @@ -45,9 +45,11 @@ internal fun State.asBoolean() = (this as Primitive<*>).value as Boolean internal fun State.asString() = (this as Primitive<*>).value.toString() internal fun State.asBooleanOrNull() = (this as? Primitive<*>)?.value as? Boolean +internal fun State.asStringOrNull() = (this as Primitive<*>).value as? String internal fun State.isSubtypeOf(other: IrType): Boolean { if (this is Primitive<*> && this.value == null) return other.isNullable() + if (this is ExceptionState) return this.isSubtypeOf(other.classOrNull!!.owner) if (this is Primitive<*> && this.type.isArray() && other.isArray()) { val thisClass = this.typeArguments.single().state.irClass.symbol 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 64d60cb528c..596354765aa 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 @@ -9,12 +9,13 @@ import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrField 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.* import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation +import org.jetbrains.kotlin.ir.interpreter.stack.Variable 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.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly @@ -22,11 +23,17 @@ import java.lang.invoke.MethodHandle import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType -internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, mutableListOf()) { +internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex { + override val fields: MutableList = mutableListOf() + + override var superWrapperClass: Wrapper? = null + override val typeArguments: MutableList = mutableListOf() + override var outerClass: Variable? = null - private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe() private val receiverClass = irClass.defaultType.getClass(true) + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null + fun getMethod(irFunction: IrFunction): MethodHandle? { if (irFunction.getEvaluateIntrinsicValue()?.isEmpty() == true) return null // this method will handle IntrinsicEvaluator // if function is actually a getter, then use "get${property.name.capitalize()}" as method name @@ -51,6 +58,10 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex( } } + override fun toString(): String { + return value.toString() + } + companion object { private val companionObjectValue = mapOf("kotlin.text.Regex\$Companion" to Regex.Companion) @@ -184,8 +195,4 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex( return true } } - - override fun toString(): String { - return "Wrapper(obj='$typeFqName', value=$value)" - } } diff --git a/generators/interpreter/GenerateInterpreterMap.kt b/generators/interpreter/GenerateInterpreterMap.kt index 9a22bf0f75a..97ad3eb63e7 100644 --- a/generators/interpreter/GenerateInterpreterMap.kt +++ b/generators/interpreter/GenerateInterpreterMap.kt @@ -40,7 +40,6 @@ fun generateMap(): String { 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.state.*") p.println() p.println("/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */") p.println() @@ -138,10 +137,7 @@ private fun generateUnaryBody(unaryOperationsMap: Map a.$methodName$parentheses }" - } + - " unaryOperation(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type.originalKotlinType}\") { a -> a!! },\n" + - " unaryOperation(\"message\", \"Throwable\") { a -> a.getMessage() },\n" + - " unaryOperation(\"cause\", \"Throwable\") { a -> a.getCause() }" + } + " unaryOperation(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type.originalKotlinType}\") { a -> a!! }" } private fun generateBinaryBody(