Rewrite Complex class as interface

This change allow ExceptionState to be both: State and Throwable
This commit is contained in:
Ivan Kylchik
2020-08-28 21:28:35 +03:00
committed by TeamCityServer
parent 6808151af7
commit 1d0acedc48
8 changed files with 53 additions and 49 deletions
@@ -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
}
@@ -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<CompileTimeFunction, Function1<Any?, Any?>>(
unaryOperation<Array<Any?>>("iterator", "Array") { a -> a.iterator() },
unaryOperation<Any>("hashCode", "Any") { a -> a.hashCode() },
unaryOperation<Any>("toString", "Any") { a -> a.toString() },
unaryOperation<Any?>("CHECK_NOT_NULL", "T0?") { a -> a!! },
unaryOperation<ExceptionState>("message", "Throwable") { a -> a.getMessage() },
unaryOperation<ExceptionState>("cause", "Throwable") { a -> a.getCause() }
unaryOperation<Any?>("CHECK_NOT_NULL", "T0?") { a -> a!! }
)
val binaryFunctions = mapOf<CompileTimeFunction, Function2<Any?, Any?, Any?>>(
@@ -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<Variable>
) : Complex(irClass, fields) {
internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList<Variable>) : Complex {
override var superWrapperClass: Wrapper? = null
override val typeArguments: MutableList<Variable> = mutableListOf()
override var outerClass: Variable? = null
constructor(irClass: IrClass) : this(irClass, mutableListOf())
@@ -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<Variable>) : State {
var superWrapperClass: Wrapper? = null
override val typeArguments: MutableList<Variable> = mutableListOf()
var outerClass: Variable? = null
internal interface Complex: State {
var superWrapperClass: Wrapper?
override val typeArguments: MutableList<Variable>
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<IrProperty>().mapNotNull { it.setter }
val functions = this.declarations.filterIsInstance<IrFunction>()
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
@@ -17,7 +17,16 @@ import kotlin.math.min
internal class ExceptionState private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>
) : Complex(irClass, fields) {
) : Complex, Throwable() {
override var superWrapperClass: Wrapper? = null
override val typeArguments: MutableList<Variable> = 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<String>()
@@ -45,6 +54,7 @@ internal class ExceptionState private constructor(
constructor(
exception: Throwable, irClass: IrClass, stackTrace: List<String>
) : 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<Throwable?>(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 {
@@ -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
@@ -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<Variable> = mutableListOf()
override var superWrapperClass: Wrapper? = null
override val typeArguments: MutableList<Variable> = 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<String, Any>("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)"
}
}
@@ -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<CallableDescriptor, Pair<S
val methodName = "${function.name}"
val parentheses = if (function is FunctionDescriptor) "()" else ""
" unaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a -> a.$methodName$parentheses }"
} +
" unaryOperation<Any?>(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type.originalKotlinType}\") { a -> a!! },\n" +
" unaryOperation<ExceptionState>(\"message\", \"Throwable\") { a -> a.getMessage() },\n" +
" unaryOperation<ExceptionState>(\"cause\", \"Throwable\") { a -> a.getCause() }"
} + " unaryOperation<Any?>(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type.originalKotlinType}\") { a -> a!! }"
}
private fun generateBinaryBody(