Move intrinsic handling inside IrInterpreter class

This commit is contained in:
Ivan Kylchik
2020-02-13 00:04:09 +03:00
parent 27e2faa778
commit 4c1727b82e
4 changed files with 56 additions and 48 deletions
@@ -181,32 +181,8 @@ class IrInterpreter(irModule: IrModuleFragment) {
} }
when (val kind = (irFunction.body as? IrSyntheticBody)?.kind) { when (val kind = (irFunction.body as? IrSyntheticBody)?.kind) {
IrSyntheticBodyKind.ENUM_VALUES -> { IrSyntheticBodyKind.ENUM_VALUES -> handleIntrinsicMethods(irFunction, data)
val enumClass = irFunction.parentAsClass IrSyntheticBodyKind.ENUM_VALUEOF -> handleIntrinsicMethods(irFunction, data)
val enumEntries = enumClass.declarations
.filterIsInstance<IrEnumEntry>()
.map { entry ->
entry.interpret(data).also { if (it != Code.NEXT) return it }
data.popReturnValue() as Common
}
data.pushReturnValue(enumEntries.toTypedArray().toState(irBuiltIns.arrayClass.defaultType))
Code.NEXT
}
IrSyntheticBodyKind.ENUM_VALUEOF -> {
val enumClass = irFunction.parentAsClass
val enumEntryName = (data.getAll().single().state as Primitive<*>).value.toString()
val enumEntry = enumClass.declarations
.filterIsInstance<IrEnumEntry>()
.singleOrNull { it.name.asString() == enumEntryName }
if (enumEntry == null) {
val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName"
data.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stackTrace))
Code.EXCEPTION
} else {
enumEntry.interpret(data).also { if (it != Code.NEXT) return it }
Code.NEXT
}
}
null -> irFunction.body?.interpret(data) ?: throw AssertionError("Ir function must be with body") null -> irFunction.body?.interpret(data) ?: throw AssertionError("Ir function must be with body")
else -> throw AssertionError("Unsupported IrSyntheticBodyKind $kind") else -> throw AssertionError("Unsupported IrSyntheticBodyKind $kind")
} }
@@ -215,13 +191,57 @@ class IrInterpreter(irModule: IrModuleFragment) {
} }
} }
private suspend fun MethodHandle.invokeMethod(irFunction: IrFunction, data: Frame): Code { private suspend fun MethodHandle?.invokeMethod(irFunction: IrFunction, data: Frame): Code {
this ?: return handleIntrinsicMethods(irFunction, data)
val result = this.invokeWithArguments(irFunction.getArgsForMethodInvocation(data)) val result = this.invokeWithArguments(irFunction.getArgsForMethodInvocation(data))
data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
return Code.NEXT return Code.NEXT
} }
private suspend fun handleIntrinsicMethods(irFunction: IrFunction, data: Frame): Code {
when (irFunction.name.asString()) {
"emptyArray" -> {
val result = emptyArray<Any?>()
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
}
"arrayOf" -> {
val result = irFunction.getArgsForMethodInvocation(data).toTypedArray()
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
}
"arrayOfNulls" -> {
val result = arrayOfNulls<Any?>(irFunction.getArgsForMethodInvocation(data).first() as Int)
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
}
"values", "enumValues" -> {
val enumClass = irFunction.parentAsClass
val enumEntries = enumClass.declarations
.filterIsInstance<IrEnumEntry>()
.map { entry ->
entry.interpret(data).also { if (it != Code.NEXT) return it }
data.popReturnValue() as Common
}
data.pushReturnValue(enumEntries.toTypedArray().toState(irBuiltIns.arrayClass.defaultType))
}
"valueOf", "enumValueOf" -> {
val enumClass = irFunction.parentAsClass
val enumEntryName = (data.getAll().single().state as Primitive<*>).value.toString()
val enumEntry = enumClass.declarations
.filterIsInstance<IrEnumEntry>()
.singleOrNull { it.name.asString() == enumEntryName }
if (enumEntry == null) {
val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName"
data.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stackTrace))
} else {
enumEntry.interpret(data).also { if (it != Code.NEXT) return it }
}
}
else -> throw AssertionError("Unsupported intrinsic ${irFunction.name}")
}
return Code.NEXT
}
private suspend fun calculateAbstract(irFunction: IrFunction, data: Frame): Code { private suspend fun calculateAbstract(irFunction: IrFunction, data: Frame): Code {
if (irFunction.body == null) { if (irFunction.body == null) {
val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex
@@ -259,6 +279,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
val overriddenOwner = overridden.owner as IrFunctionImpl val overriddenOwner = overridden.owner as IrFunctionImpl
return when { return when {
// TODO figure something better
superQualifier.irClassFqName() == "kotlin.Enum" && owner.name.asString() == "hashCode" -> calculateOverridden(overriddenOwner, newStates) superQualifier.irClassFqName() == "kotlin.Enum" && owner.name.asString() == "hashCode" -> calculateOverridden(overriddenOwner, newStates)
overriddenOwner.body != null -> overriddenOwner.interpret(newStates) overriddenOwner.body != null -> overriddenOwner.interpret(newStates)
superQualifier.superType == null -> calculateBuiltIns(overriddenOwner, newStates) superQualifier.superType == null -> calculateBuiltIns(overriddenOwner, newStates)
@@ -461,7 +482,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
} }
val originalVarToInline = ParallelVisitorForInlineFun() val originalVarToInline = ParallelVisitorForInlineFun()
.apply { this.visitElement(inlineFun.body!!.statements.first(), block.statements.last()) } .apply { this.visitElement(inlineFun.body!!.statements.first(), block.removeBlocks()!!) }
.originalVarToInline .originalVarToInline
val frameForWrapper = InterpreterFrame() val frameForWrapper = InterpreterFrame()
@@ -143,11 +143,9 @@ fun IrAnnotationContainer.getAnnotation(annotation: FqName): IrConstructorCall {
?: ((this as IrFunction).parent as IrClass).annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } ?: ((this as IrFunction).parent as IrClass).annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation }
} }
const val defaultIntrinsicLocation = "org.jetbrains.kotlin.backend.common.interpreter.intrinsic.InterpreterIntrinsicsKt"
fun IrAnnotationContainer.getEvaluateIntrinsicValue(): String? { fun IrAnnotationContainer.getEvaluateIntrinsicValue(): String? {
if (!this.hasAnnotation(evaluateIntrinsicAnnotation)) return null if (!this.hasAnnotation(evaluateIntrinsicAnnotation)) return null
val value = (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString() return (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString()
return if (value.isEmpty()) defaultIntrinsicLocation else value
} }
fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? {
@@ -1,14 +0,0 @@
/*
* 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.
*/
@file:JvmName("InterpreterIntrinsicsKt")
package org.jetbrains.kotlin.backend.common.interpreter.intrinsic
public fun emptyArray(): Array<Any?> = kotlin.emptyArray()
public fun arrayOf(vararg elements: Any?): Array<Any?> = elements as Array<Any?>
public fun arrayOfNulls(size: Int): Array<Any?> = arrayOfNulls<Any?>(size)
@@ -159,7 +159,7 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe() private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe()
private val receiverClass = irClass.defaultType.getClass(true) private val receiverClass = irClass.defaultType.getClass(true)
fun getMethod(irFunction: IrFunction): MethodHandle { fun getMethod(irFunction: IrFunction): MethodHandle? {
// if function is actually a getter, then use property name as method name // if function is actually a getter, then use property name as method name
val property = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner val property = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner
@@ -167,6 +167,7 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
// for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder // for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder
// - use getter for private fields such as detailMessage in java.lang.Throwable // - use getter for private fields such as detailMessage in java.lang.Throwable
val intrinsicName = property?.getEvaluateIntrinsicValue() ?: irFunction.getEvaluateIntrinsicValue() val intrinsicName = property?.getEvaluateIntrinsicValue() ?: irFunction.getEvaluateIntrinsicValue()
if (intrinsicName?.isEmpty() == true) return null
val methodName = intrinsicName ?: (property ?: irFunction).name.toString() val methodName = intrinsicName ?: (property ?: irFunction).name.toString()
val methodType = irFunction.getMethodType() val methodType = irFunction.getMethodType()
@@ -184,8 +185,10 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
return MethodHandles.lookup().findConstructor(irConstructor.returnType.getClass(true), methodType) return MethodHandles.lookup().findConstructor(irConstructor.returnType.getClass(true), methodType)
} }
fun getStaticMethod(irFunction: IrFunction): MethodHandle { fun getStaticMethod(irFunction: IrFunction): MethodHandle? {
val jvmClassName = Class.forName(irFunction.getEvaluateIntrinsicValue()!!) val intrinsicName = irFunction.getEvaluateIntrinsicValue()
if (intrinsicName?.isEmpty() == true) return null
val jvmClassName = Class.forName(intrinsicName!!)
val methodType = irFunction.getMethodType() val methodType = irFunction.getMethodType()
return MethodHandles.lookup().findStatic(jvmClassName, irFunction.name.asString(), methodType) return MethodHandles.lookup().findStatic(jvmClassName, irFunction.name.asString(), methodType)