Dev #127
@ -1,6 +1,6 @@
|
|||||||
package scientifik.kmath.asm
|
package scientifik.kmath.asm
|
||||||
|
|
||||||
import scientifik.kmath.asm.internal.AsmGenerationContext
|
import scientifik.kmath.asm.internal.AsmGenerator
|
||||||
import scientifik.kmath.ast.MST
|
import scientifik.kmath.ast.MST
|
||||||
import scientifik.kmath.ast.evaluate
|
import scientifik.kmath.ast.evaluate
|
||||||
import scientifik.kmath.expressions.Expression
|
import scientifik.kmath.expressions.Expression
|
||||||
@ -20,12 +20,8 @@ internal fun buildName(expression: AsmNode<*>, collision: Int = 0): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal inline fun <reified T> AsmNode<T>.compile(algebra: Algebra<T>): Expression<T> {
|
internal inline fun <reified T> AsmNode<T>.compile(algebra: Algebra<T>): Expression<T> =
|
||||||
val ctx =
|
AsmGenerator(T::class.java, algebra, buildName(this), this).getInstance()
|
||||||
AsmGenerationContext(T::class.java, algebra, buildName(this))
|
|
||||||
compile(ctx)
|
|
||||||
return ctx.generate()
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T, A : NumericAlgebra<T>, E : AsmExpressionAlgebra<T, A>> A.asm(
|
inline fun <reified T, A : NumericAlgebra<T>, E : AsmExpressionAlgebra<T, A>> A.asm(
|
||||||
expressionAlgebra: E,
|
expressionAlgebra: E,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package scientifik.kmath.asm
|
package scientifik.kmath.asm
|
||||||
|
|
||||||
import scientifik.kmath.asm.internal.AsmGenerationContext
|
import scientifik.kmath.asm.internal.AsmGenerator
|
||||||
import scientifik.kmath.asm.internal.hasSpecific
|
import scientifik.kmath.asm.internal.hasSpecific
|
||||||
import scientifik.kmath.asm.internal.optimize
|
import scientifik.kmath.asm.internal.optimize
|
||||||
import scientifik.kmath.asm.internal.tryInvokeSpecific
|
import scientifik.kmath.asm.internal.tryInvokeSpecific
|
||||||
@ -9,7 +9,7 @@ import scientifik.kmath.expressions.ExpressionAlgebra
|
|||||||
import scientifik.kmath.operations.*
|
import scientifik.kmath.operations.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function declaration that could be compiled to [AsmGenerationContext].
|
* A function declaration that could be compiled to [AsmGenerator].
|
||||||
*
|
*
|
||||||
* @param T the type the stored function returns.
|
* @param T the type the stored function returns.
|
||||||
*/
|
*/
|
||||||
@ -24,10 +24,10 @@ abstract class AsmNode<T> internal constructor() {
|
|||||||
/**
|
/**
|
||||||
* Compiles this declaration.
|
* Compiles this declaration.
|
||||||
*
|
*
|
||||||
* @param gen the target [AsmGenerationContext].
|
* @param gen the target [AsmGenerator].
|
||||||
*/
|
*/
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal abstract fun compile(gen: AsmGenerationContext<T>)
|
internal abstract fun compile(gen: AsmGenerator<T>)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AsmUnaryOperation<T>(private val context: Algebra<T>, private val name: String, expr: AsmNode<T>) :
|
internal class AsmUnaryOperation<T>(private val context: Algebra<T>, private val name: String, expr: AsmNode<T>) :
|
||||||
@ -35,23 +35,23 @@ internal class AsmUnaryOperation<T>(private val context: Algebra<T>, private val
|
|||||||
private val expr: AsmNode<T> = expr.optimize()
|
private val expr: AsmNode<T> = expr.optimize()
|
||||||
override fun tryEvaluate(): T? = context { unaryOperation(name, expr.tryEvaluate() ?: return@context null) }
|
override fun tryEvaluate(): T? = context { unaryOperation(name, expr.tryEvaluate() ?: return@context null) }
|
||||||
|
|
||||||
override fun compile(gen: AsmGenerationContext<T>) {
|
override fun compile(gen: AsmGenerator<T>) {
|
||||||
gen.visitLoadAlgebra()
|
gen.loadAlgebra()
|
||||||
|
|
||||||
if (!hasSpecific(context, name, 1))
|
if (!hasSpecific(context, name, 1))
|
||||||
gen.visitStringConstant(name)
|
gen.loadStringConstant(name)
|
||||||
|
|
||||||
expr.compile(gen)
|
expr.compile(gen)
|
||||||
|
|
||||||
if (gen.tryInvokeSpecific(context, name, 1))
|
if (gen.tryInvokeSpecific(context, name, 1))
|
||||||
return
|
return
|
||||||
|
|
||||||
gen.visitAlgebraOperation(
|
gen.invokeAlgebraOperation(
|
||||||
owner = AsmGenerationContext.ALGEBRA_CLASS,
|
owner = AsmGenerator.ALGEBRA_CLASS,
|
||||||
method = "unaryOperation",
|
method = "unaryOperation",
|
||||||
descriptor = "(L${AsmGenerationContext.STRING_CLASS};" +
|
descriptor = "(L${AsmGenerator.STRING_CLASS};" +
|
||||||
"L${AsmGenerationContext.OBJECT_CLASS};)" +
|
"L${AsmGenerator.OBJECT_CLASS};)" +
|
||||||
"L${AsmGenerationContext.OBJECT_CLASS};"
|
"L${AsmGenerator.OBJECT_CLASS};"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,11 +73,11 @@ internal class AsmBinaryOperation<T>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compile(gen: AsmGenerationContext<T>) {
|
override fun compile(gen: AsmGenerator<T>) {
|
||||||
gen.visitLoadAlgebra()
|
gen.loadAlgebra()
|
||||||
|
|
||||||
if (!hasSpecific(context, name, 2))
|
if (!hasSpecific(context, name, 2))
|
||||||
gen.visitStringConstant(name)
|
gen.loadStringConstant(name)
|
||||||
|
|
||||||
first.compile(gen)
|
first.compile(gen)
|
||||||
second.compile(gen)
|
second.compile(gen)
|
||||||
@ -85,26 +85,26 @@ internal class AsmBinaryOperation<T>(
|
|||||||
if (gen.tryInvokeSpecific(context, name, 2))
|
if (gen.tryInvokeSpecific(context, name, 2))
|
||||||
return
|
return
|
||||||
|
|
||||||
gen.visitAlgebraOperation(
|
gen.invokeAlgebraOperation(
|
||||||
owner = AsmGenerationContext.ALGEBRA_CLASS,
|
owner = AsmGenerator.ALGEBRA_CLASS,
|
||||||
method = "binaryOperation",
|
method = "binaryOperation",
|
||||||
descriptor = "(L${AsmGenerationContext.STRING_CLASS};" +
|
descriptor = "(L${AsmGenerator.STRING_CLASS};" +
|
||||||
"L${AsmGenerationContext.OBJECT_CLASS};" +
|
"L${AsmGenerator.OBJECT_CLASS};" +
|
||||||
"L${AsmGenerationContext.OBJECT_CLASS};)" +
|
"L${AsmGenerator.OBJECT_CLASS};)" +
|
||||||
"L${AsmGenerationContext.OBJECT_CLASS};"
|
"L${AsmGenerator.OBJECT_CLASS};"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AsmVariableExpression<T>(private val name: String, private val default: T? = null) :
|
internal class AsmVariableExpression<T>(private val name: String, private val default: T? = null) :
|
||||||
AsmNode<T>() {
|
AsmNode<T>() {
|
||||||
override fun compile(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromVariables(name, default)
|
override fun compile(gen: AsmGenerator<T>): Unit = gen.loadFromVariables(name, default)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AsmConstantExpression<T>(private val value: T) :
|
internal class AsmConstantExpression<T>(private val value: T) :
|
||||||
AsmNode<T>() {
|
AsmNode<T>() {
|
||||||
override fun tryEvaluate(): T = value
|
override fun tryEvaluate(): T = value
|
||||||
override fun compile(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromConstants(value)
|
override fun compile(gen: AsmGenerator<T>): Unit = gen.loadTConstant(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AsmConstProductExpression<T>(
|
internal class AsmConstProductExpression<T>(
|
||||||
@ -116,17 +116,17 @@ internal class AsmConstProductExpression<T>(
|
|||||||
|
|
||||||
override fun tryEvaluate(): T? = context { (expr.tryEvaluate() ?: return@context null) * const }
|
override fun tryEvaluate(): T? = context { (expr.tryEvaluate() ?: return@context null) * const }
|
||||||
|
|
||||||
override fun compile(gen: AsmGenerationContext<T>) {
|
override fun compile(gen: AsmGenerator<T>) {
|
||||||
gen.visitLoadAlgebra()
|
gen.loadAlgebra()
|
||||||
gen.visitNumberConstant(const)
|
gen.loadNumberConstant(const)
|
||||||
expr.compile(gen)
|
expr.compile(gen)
|
||||||
|
|
||||||
gen.visitAlgebraOperation(
|
gen.invokeAlgebraOperation(
|
||||||
owner = AsmGenerationContext.SPACE_OPERATIONS_CLASS,
|
owner = AsmGenerator.SPACE_OPERATIONS_CLASS,
|
||||||
method = "multiply",
|
method = "multiply",
|
||||||
descriptor = "(L${AsmGenerationContext.OBJECT_CLASS};" +
|
descriptor = "(L${AsmGenerator.OBJECT_CLASS};" +
|
||||||
"L${AsmGenerationContext.NUMBER_CLASS};)" +
|
"L${AsmGenerator.NUMBER_CLASS};)" +
|
||||||
"L${AsmGenerationContext.OBJECT_CLASS};"
|
"L${AsmGenerator.OBJECT_CLASS};"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ internal class AsmNumberExpression<T>(private val context: NumericAlgebra<T>, pr
|
|||||||
AsmNode<T>() {
|
AsmNode<T>() {
|
||||||
override fun tryEvaluate(): T? = context.number(value)
|
override fun tryEvaluate(): T? = context.number(value)
|
||||||
|
|
||||||
override fun compile(gen: AsmGenerationContext<T>): Unit = gen.visitNumberConstant(value)
|
override fun compile(gen: AsmGenerator<T>): Unit = gen.loadNumberConstant(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class FunctionalCompiledExpression<T> internal constructor(
|
internal abstract class FunctionalCompiledExpression<T> internal constructor(
|
||||||
|
@ -1,319 +0,0 @@
|
|||||||
package scientifik.kmath.asm.internal
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassWriter
|
|
||||||
import org.objectweb.asm.Label
|
|
||||||
import org.objectweb.asm.MethodVisitor
|
|
||||||
import org.objectweb.asm.Opcodes
|
|
||||||
import scientifik.kmath.asm.FunctionalCompiledExpression
|
|
||||||
import scientifik.kmath.asm.internal.AsmGenerationContext.ClassLoader
|
|
||||||
import scientifik.kmath.operations.Algebra
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AsmGenerationContext is a structure that abstracts building a class that unwraps [AsmNode] to plain Java
|
|
||||||
* expression. This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new
|
|
||||||
* class.
|
|
||||||
*
|
|
||||||
* @param T the type of AsmExpression to unwrap.
|
|
||||||
* @param algebra the algebra the applied AsmExpressions use.
|
|
||||||
* @param className the unique class name of new loaded class.
|
|
||||||
*/
|
|
||||||
@PublishedApi
|
|
||||||
internal class AsmGenerationContext<T> @PublishedApi internal constructor(
|
|
||||||
private val classOfT: Class<*>,
|
|
||||||
private val algebra: Algebra<T>,
|
|
||||||
private val className: String
|
|
||||||
) {
|
|
||||||
private class ClassLoader(parent: java.lang.ClassLoader) : java.lang.ClassLoader(parent) {
|
|
||||||
internal fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val classLoader: ClassLoader =
|
|
||||||
ClassLoader(javaClass.classLoader)
|
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
|
||||||
private val T_ALGEBRA_CLASS: String = algebra.javaClass.name.replace(oldChar = '.', newChar = '/')
|
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
|
||||||
private val T_CLASS: String = classOfT.name.replace('.', '/')
|
|
||||||
|
|
||||||
private val slashesClassName: String = className.replace(oldChar = '.', newChar = '/')
|
|
||||||
private val invokeThisVar: Int = 0
|
|
||||||
private val invokeArgumentsVar: Int = 1
|
|
||||||
private var maxStack: Int = 0
|
|
||||||
private val constants: MutableList<Any> = mutableListOf()
|
|
||||||
private val asmCompiledClassWriter: ClassWriter = ClassWriter(0)
|
|
||||||
private val invokeMethodVisitor: MethodVisitor
|
|
||||||
private val invokeL0: Label
|
|
||||||
private lateinit var invokeL1: Label
|
|
||||||
private var generatedInstance: FunctionalCompiledExpression<T>? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
asmCompiledClassWriter.visit(
|
|
||||||
Opcodes.V1_8,
|
|
||||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_SUPER,
|
|
||||||
slashesClassName,
|
|
||||||
"L$FUNCTIONAL_COMPILED_EXPRESSION_CLASS<L$T_CLASS;>;",
|
|
||||||
FUNCTIONAL_COMPILED_EXPRESSION_CLASS,
|
|
||||||
arrayOf()
|
|
||||||
)
|
|
||||||
|
|
||||||
asmCompiledClassWriter.run {
|
|
||||||
visitMethod(Opcodes.ACC_PUBLIC, "<init>", "(L$ALGEBRA_CLASS;[L$OBJECT_CLASS;)V", null, null).run {
|
|
||||||
val thisVar = 0
|
|
||||||
val algebraVar = 1
|
|
||||||
val constantsVar = 2
|
|
||||||
val l0 = Label()
|
|
||||||
visitLabel(l0)
|
|
||||||
visitVarInsn(Opcodes.ALOAD, thisVar)
|
|
||||||
visitVarInsn(Opcodes.ALOAD, algebraVar)
|
|
||||||
visitVarInsn(Opcodes.ALOAD, constantsVar)
|
|
||||||
|
|
||||||
visitMethodInsn(
|
|
||||||
Opcodes.INVOKESPECIAL,
|
|
||||||
FUNCTIONAL_COMPILED_EXPRESSION_CLASS,
|
|
||||||
"<init>",
|
|
||||||
"(L$ALGEBRA_CLASS;[L$OBJECT_CLASS;)V",
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
val l1 = Label()
|
|
||||||
visitLabel(l1)
|
|
||||||
visitInsn(Opcodes.RETURN)
|
|
||||||
val l2 = Label()
|
|
||||||
visitLabel(l2)
|
|
||||||
visitLocalVariable("this", "L$slashesClassName;", null, l0, l2, thisVar)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
|
||||||
"algebra",
|
|
||||||
"L$ALGEBRA_CLASS;",
|
|
||||||
"L$ALGEBRA_CLASS<L$T_CLASS;>;",
|
|
||||||
l0,
|
|
||||||
l2,
|
|
||||||
algebraVar
|
|
||||||
)
|
|
||||||
|
|
||||||
visitLocalVariable("constants", "[L$OBJECT_CLASS;", null, l0, l2, constantsVar)
|
|
||||||
visitMaxs(3, 3)
|
|
||||||
visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
invokeMethodVisitor = visitMethod(
|
|
||||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
|
||||||
"invoke",
|
|
||||||
"(L$MAP_CLASS;)L$T_CLASS;",
|
|
||||||
"(L$MAP_CLASS<L$STRING_CLASS;+L$T_CLASS;>;)L$T_CLASS;",
|
|
||||||
null
|
|
||||||
)
|
|
||||||
|
|
||||||
invokeMethodVisitor.run {
|
|
||||||
visitCode()
|
|
||||||
invokeL0 = Label()
|
|
||||||
visitLabel(invokeL0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PublishedApi
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
internal fun generate(): FunctionalCompiledExpression<T> {
|
|
||||||
generatedInstance?.let { return it }
|
|
||||||
|
|
||||||
invokeMethodVisitor.run {
|
|
||||||
visitInsn(Opcodes.ARETURN)
|
|
||||||
invokeL1 = Label()
|
|
||||||
visitLabel(invokeL1)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
|
||||||
"this",
|
|
||||||
"L$slashesClassName;",
|
|
||||||
T_CLASS,
|
|
||||||
invokeL0,
|
|
||||||
invokeL1,
|
|
||||||
invokeThisVar
|
|
||||||
)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
|
||||||
"arguments",
|
|
||||||
"L$MAP_CLASS;",
|
|
||||||
"L$MAP_CLASS<L$STRING_CLASS;+L$T_CLASS;>;",
|
|
||||||
invokeL0,
|
|
||||||
invokeL1,
|
|
||||||
invokeArgumentsVar
|
|
||||||
)
|
|
||||||
|
|
||||||
visitMaxs(maxStack + 1, 2)
|
|
||||||
visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
asmCompiledClassWriter.visitMethod(
|
|
||||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_BRIDGE or Opcodes.ACC_SYNTHETIC,
|
|
||||||
"invoke",
|
|
||||||
"(L$MAP_CLASS;)L$OBJECT_CLASS;",
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
).run {
|
|
||||||
val thisVar = 0
|
|
||||||
visitCode()
|
|
||||||
val l0 = Label()
|
|
||||||
visitLabel(l0)
|
|
||||||
visitVarInsn(Opcodes.ALOAD, 0)
|
|
||||||
visitVarInsn(Opcodes.ALOAD, 1)
|
|
||||||
visitMethodInsn(Opcodes.INVOKEVIRTUAL, slashesClassName, "invoke", "(L$MAP_CLASS;)L$T_CLASS;", false)
|
|
||||||
visitInsn(Opcodes.ARETURN)
|
|
||||||
val l1 = Label()
|
|
||||||
visitLabel(l1)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
|
||||||
"this",
|
|
||||||
"L$slashesClassName;",
|
|
||||||
T_CLASS,
|
|
||||||
l0,
|
|
||||||
l1,
|
|
||||||
thisVar
|
|
||||||
)
|
|
||||||
|
|
||||||
visitMaxs(2, 2)
|
|
||||||
visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
asmCompiledClassWriter.visitEnd()
|
|
||||||
|
|
||||||
val new = classLoader
|
|
||||||
.defineClass(className, asmCompiledClassWriter.toByteArray())
|
|
||||||
.constructors
|
|
||||||
.first()
|
|
||||||
.newInstance(algebra, constants.toTypedArray()) as FunctionalCompiledExpression<T>
|
|
||||||
|
|
||||||
generatedInstance = new
|
|
||||||
return new
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun visitLoadFromConstants(value: T) {
|
|
||||||
if (classOfT in INLINABLE_NUMBERS) {
|
|
||||||
visitNumberConstant(value as Number)
|
|
||||||
visitCastToT()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
visitLoadAnyFromConstants(value as Any, T_CLASS)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitLoadAnyFromConstants(value: Any, type: String) {
|
|
||||||
val idx = if (value in constants) constants.indexOf(value) else constants.apply { add(value) }.lastIndex
|
|
||||||
maxStack++
|
|
||||||
|
|
||||||
invokeMethodVisitor.run {
|
|
||||||
visitLoadThis()
|
|
||||||
visitFieldInsn(Opcodes.GETFIELD, slashesClassName, "constants", "[L$OBJECT_CLASS;")
|
|
||||||
visitLdcOrIConstInsn(idx)
|
|
||||||
visitInsn(Opcodes.AALOAD)
|
|
||||||
invokeMethodVisitor.visitTypeInsn(Opcodes.CHECKCAST, type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitLoadThis(): Unit = invokeMethodVisitor.visitVarInsn(Opcodes.ALOAD, invokeThisVar)
|
|
||||||
|
|
||||||
internal fun visitNumberConstant(value: Number) {
|
|
||||||
maxStack++
|
|
||||||
val clazz = value.javaClass
|
|
||||||
val c = clazz.name.replace('.', '/')
|
|
||||||
val sigLetter = SIGNATURE_LETTERS[clazz]
|
|
||||||
|
|
||||||
if (sigLetter != null) {
|
|
||||||
when (value) {
|
|
||||||
is Int -> invokeMethodVisitor.visitLdcOrIConstInsn(value)
|
|
||||||
is Double -> invokeMethodVisitor.visitLdcOrDConstInsn(value)
|
|
||||||
is Float -> invokeMethodVisitor.visitLdcOrFConstInsn(value)
|
|
||||||
else -> invokeMethodVisitor.visitLdcInsn(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
invokeMethodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, c, "valueOf", "($sigLetter)L${c};", false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
visitLoadAnyFromConstants(value, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun visitLoadFromVariables(name: String, defaultValue: T? = null): Unit = invokeMethodVisitor.run {
|
|
||||||
maxStack += 2
|
|
||||||
visitVarInsn(Opcodes.ALOAD, invokeArgumentsVar)
|
|
||||||
|
|
||||||
if (defaultValue != null) {
|
|
||||||
visitLdcInsn(name)
|
|
||||||
visitLoadFromConstants(defaultValue)
|
|
||||||
|
|
||||||
visitMethodInsn(
|
|
||||||
Opcodes.INVOKEINTERFACE,
|
|
||||||
MAP_CLASS,
|
|
||||||
"getOrDefault",
|
|
||||||
"(L$OBJECT_CLASS;L$OBJECT_CLASS;)L$OBJECT_CLASS;",
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
visitCastToT()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
visitLdcInsn(name)
|
|
||||||
visitMethodInsn(
|
|
||||||
Opcodes.INVOKEINTERFACE,
|
|
||||||
MAP_CLASS, "get", "(L$OBJECT_CLASS;)L$OBJECT_CLASS;", true
|
|
||||||
)
|
|
||||||
visitCastToT()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun visitLoadAlgebra() {
|
|
||||||
maxStack++
|
|
||||||
invokeMethodVisitor.visitVarInsn(Opcodes.ALOAD, invokeThisVar)
|
|
||||||
|
|
||||||
invokeMethodVisitor.visitFieldInsn(
|
|
||||||
Opcodes.GETFIELD,
|
|
||||||
FUNCTIONAL_COMPILED_EXPRESSION_CLASS, "algebra", "L$ALGEBRA_CLASS;"
|
|
||||||
)
|
|
||||||
|
|
||||||
invokeMethodVisitor.visitTypeInsn(Opcodes.CHECKCAST, T_ALGEBRA_CLASS)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun visitAlgebraOperation(
|
|
||||||
owner: String,
|
|
||||||
method: String,
|
|
||||||
descriptor: String,
|
|
||||||
opcode: Int = Opcodes.INVOKEINTERFACE,
|
|
||||||
isInterface: Boolean = true
|
|
||||||
) {
|
|
||||||
maxStack++
|
|
||||||
invokeMethodVisitor.visitMethodInsn(opcode, owner, method, descriptor, isInterface)
|
|
||||||
visitCastToT()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitCastToT(): Unit = invokeMethodVisitor.visitTypeInsn(Opcodes.CHECKCAST, T_CLASS)
|
|
||||||
|
|
||||||
internal fun visitStringConstant(string: String) {
|
|
||||||
invokeMethodVisitor.visitLdcInsn(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal companion object {
|
|
||||||
private val SIGNATURE_LETTERS by lazy {
|
|
||||||
mapOf(
|
|
||||||
java.lang.Byte::class.java to "B",
|
|
||||||
java.lang.Short::class.java to "S",
|
|
||||||
java.lang.Integer::class.java to "I",
|
|
||||||
java.lang.Long::class.java to "J",
|
|
||||||
java.lang.Float::class.java to "F",
|
|
||||||
java.lang.Double::class.java to "D"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val INLINABLE_NUMBERS by lazy { SIGNATURE_LETTERS.keys }
|
|
||||||
|
|
||||||
internal const val FUNCTIONAL_COMPILED_EXPRESSION_CLASS =
|
|
||||||
"scientifik/kmath/asm/FunctionalCompiledExpression"
|
|
||||||
|
|
||||||
internal const val MAP_CLASS = "java/util/Map"
|
|
||||||
internal const val OBJECT_CLASS = "java/lang/Object"
|
|
||||||
internal const val ALGEBRA_CLASS = "scientifik/kmath/operations/Algebra"
|
|
||||||
internal const val SPACE_OPERATIONS_CLASS = "scientifik/kmath/operations/SpaceOperations"
|
|
||||||
internal const val STRING_CLASS = "java/lang/String"
|
|
||||||
internal const val NUMBER_CLASS = "java/lang/Number"
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,311 @@
|
|||||||
|
package scientifik.kmath.asm.internal
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter
|
||||||
|
import org.objectweb.asm.Label
|
||||||
|
import org.objectweb.asm.MethodVisitor
|
||||||
|
import org.objectweb.asm.Opcodes
|
||||||
|
import scientifik.kmath.asm.AsmNode
|
||||||
|
import scientifik.kmath.asm.FunctionalCompiledExpression
|
||||||
|
import scientifik.kmath.asm.internal.AsmGenerator.ClassLoader
|
||||||
|
import scientifik.kmath.operations.Algebra
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM Generator is a structure that abstracts building a class that unwraps [AsmNode] to plain Java expression.
|
||||||
|
* This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class.
|
||||||
|
*
|
||||||
|
* @param T the type of AsmExpression to unwrap.
|
||||||
|
* @param algebra the algebra the applied AsmExpressions use.
|
||||||
|
* @param className the unique class name of new loaded class.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
@PublishedApi
|
||||||
|
internal class AsmGenerator<T> @PublishedApi internal constructor(
|
||||||
|
private val classOfT: Class<*>,
|
||||||
|
private val algebra: Algebra<T>,
|
||||||
|
private val className: String,
|
||||||
|
private val root: AsmNode<T>
|
||||||
|
) {
|
||||||
|
private class ClassLoader(parent: java.lang.ClassLoader) : java.lang.ClassLoader(parent) {
|
||||||
|
internal fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val classLoader: ClassLoader =
|
||||||
|
ClassLoader(javaClass.classLoader)
|
||||||
|
|
||||||
|
@Suppress("PrivatePropertyName")
|
||||||
|
private val T_ALGEBRA_CLASS: String = algebra.javaClass.name.replace(oldChar = '.', newChar = '/')
|
||||||
|
|
||||||
|
@Suppress("PrivatePropertyName")
|
||||||
|
private val T_CLASS: String = classOfT.name.replace('.', '/')
|
||||||
|
|
||||||
|
private val slashesClassName: String = className.replace(oldChar = '.', newChar = '/')
|
||||||
|
private val invokeThisVar: Int = 0
|
||||||
|
private val invokeArgumentsVar: Int = 1
|
||||||
|
private val constants: MutableList<Any> = mutableListOf()
|
||||||
|
private lateinit var invokeMethodVisitor: MethodVisitor
|
||||||
|
private var generatedInstance: FunctionalCompiledExpression<T>? = null
|
||||||
|
|
||||||
|
fun getInstance(): FunctionalCompiledExpression<T> {
|
||||||
|
generatedInstance?.let { return it }
|
||||||
|
|
||||||
|
val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
||||||
|
visit(
|
||||||
|
Opcodes.V1_8,
|
||||||
|
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_SUPER,
|
||||||
|
slashesClassName,
|
||||||
|
"L$FUNCTIONAL_COMPILED_EXPRESSION_CLASS<L$T_CLASS;>;",
|
||||||
|
FUNCTIONAL_COMPILED_EXPRESSION_CLASS,
|
||||||
|
arrayOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
visitMethod(
|
||||||
|
access = Opcodes.ACC_PUBLIC,
|
||||||
|
name = "<init>",
|
||||||
|
descriptor = "(L$ALGEBRA_CLASS;[L$OBJECT_CLASS;)V",
|
||||||
|
signature = null,
|
||||||
|
exceptions = null
|
||||||
|
) {
|
||||||
|
val thisVar = 0
|
||||||
|
val algebraVar = 1
|
||||||
|
val constantsVar = 2
|
||||||
|
val l0 = Label()
|
||||||
|
visitLabel(l0)
|
||||||
|
visitLoadObjectVar(thisVar)
|
||||||
|
visitLoadObjectVar(algebraVar)
|
||||||
|
visitLoadObjectVar(constantsVar)
|
||||||
|
|
||||||
|
visitInvokeSpecial(
|
||||||
|
FUNCTIONAL_COMPILED_EXPRESSION_CLASS,
|
||||||
|
"<init>",
|
||||||
|
"(L$ALGEBRA_CLASS;[L$OBJECT_CLASS;)V"
|
||||||
|
)
|
||||||
|
|
||||||
|
val l1 = Label()
|
||||||
|
visitLabel(l1)
|
||||||
|
visitReturn()
|
||||||
|
val l2 = Label()
|
||||||
|
visitLabel(l2)
|
||||||
|
visitLocalVariable("this", "L$slashesClassName;", null, l0, l2, thisVar)
|
||||||
|
|
||||||
|
visitLocalVariable(
|
||||||
|
"algebra",
|
||||||
|
"L$ALGEBRA_CLASS;",
|
||||||
|
"L$ALGEBRA_CLASS<L$T_CLASS;>;",
|
||||||
|
l0,
|
||||||
|
l2,
|
||||||
|
algebraVar
|
||||||
|
)
|
||||||
|
|
||||||
|
visitLocalVariable("constants", "[L$OBJECT_CLASS;", null, l0, l2, constantsVar)
|
||||||
|
visitMaxs(0, 3)
|
||||||
|
visitEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethodVisitor = visitMethod(
|
||||||
|
access = Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
||||||
|
name = "invoke",
|
||||||
|
descriptor = "(L$MAP_CLASS;)L$T_CLASS;",
|
||||||
|
signature = "(L$MAP_CLASS<L$STRING_CLASS;+L$T_CLASS;>;)L$T_CLASS;",
|
||||||
|
exceptions = null
|
||||||
|
) {}
|
||||||
|
|
||||||
|
invokeMethodVisitor.run {
|
||||||
|
visitCode()
|
||||||
|
val l0 = Label()
|
||||||
|
visitLabel(l0)
|
||||||
|
root.compile(this@AsmGenerator)
|
||||||
|
visitReturnObject()
|
||||||
|
val l1 = Label()
|
||||||
|
visitLabel(l1)
|
||||||
|
|
||||||
|
visitLocalVariable(
|
||||||
|
"this",
|
||||||
|
"L$slashesClassName;",
|
||||||
|
T_CLASS,
|
||||||
|
l0,
|
||||||
|
l1,
|
||||||
|
invokeThisVar
|
||||||
|
)
|
||||||
|
|
||||||
|
visitLocalVariable(
|
||||||
|
"arguments",
|
||||||
|
"L$MAP_CLASS;",
|
||||||
|
"L$MAP_CLASS<L$STRING_CLASS;+L$T_CLASS;>;",
|
||||||
|
l0,
|
||||||
|
l1,
|
||||||
|
invokeArgumentsVar
|
||||||
|
)
|
||||||
|
|
||||||
|
visitMaxs(0, 2)
|
||||||
|
visitEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
visitMethod(
|
||||||
|
access = Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_BRIDGE or Opcodes.ACC_SYNTHETIC,
|
||||||
|
name = "invoke",
|
||||||
|
descriptor = "(L$MAP_CLASS;)L$OBJECT_CLASS;",
|
||||||
|
signature = null,
|
||||||
|
exceptions = null
|
||||||
|
) {
|
||||||
|
val thisVar = 0
|
||||||
|
val argumentsVar = 1
|
||||||
|
visitCode()
|
||||||
|
val l0 = Label()
|
||||||
|
visitLabel(l0)
|
||||||
|
visitLoadObjectVar(thisVar)
|
||||||
|
visitLoadObjectVar(argumentsVar)
|
||||||
|
visitInvokeVirtual(owner = slashesClassName, name = "invoke", descriptor = "(L$MAP_CLASS;)L$T_CLASS;")
|
||||||
|
visitReturnObject()
|
||||||
|
val l1 = Label()
|
||||||
|
visitLabel(l1)
|
||||||
|
|
||||||
|
visitLocalVariable(
|
||||||
|
"this",
|
||||||
|
"L$slashesClassName;",
|
||||||
|
T_CLASS,
|
||||||
|
l0,
|
||||||
|
l1,
|
||||||
|
thisVar
|
||||||
|
)
|
||||||
|
|
||||||
|
visitMaxs(0, 2)
|
||||||
|
visitEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
visitEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
val new = classLoader
|
||||||
|
.defineClass(className, classWriter.toByteArray())
|
||||||
|
.constructors
|
||||||
|
.first()
|
||||||
|
.newInstance(algebra, constants.toTypedArray()) as FunctionalCompiledExpression<T>
|
||||||
|
|
||||||
|
generatedInstance = new
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun loadTConstant(value: T) {
|
||||||
|
if (classOfT in INLINABLE_NUMBERS) {
|
||||||
|
loadNumberConstant(value as Number)
|
||||||
|
invokeMethodVisitor.visitCheckCast(T_CLASS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadConstant(value as Any, T_CLASS)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadConstant(value: Any, type: String) {
|
||||||
|
val idx = if (value in constants) constants.indexOf(value) else constants.apply { add(value) }.lastIndex
|
||||||
|
|
||||||
|
invokeMethodVisitor.run {
|
||||||
|
loadThis()
|
||||||
|
visitGetField(owner = slashesClassName, name = "constants", descriptor = "[L$OBJECT_CLASS;")
|
||||||
|
visitLdcOrIntConstant(idx)
|
||||||
|
visitGetObjectArrayElement()
|
||||||
|
invokeMethodVisitor.visitCheckCast(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadThis(): Unit = invokeMethodVisitor.visitLoadObjectVar(invokeThisVar)
|
||||||
|
|
||||||
|
internal fun loadNumberConstant(value: Number) {
|
||||||
|
val clazz = value.javaClass
|
||||||
|
val c = clazz.name.replace('.', '/')
|
||||||
|
val sigLetter = SIGNATURE_LETTERS[clazz]
|
||||||
|
|
||||||
|
if (sigLetter != null) {
|
||||||
|
when (value) {
|
||||||
|
is Int -> invokeMethodVisitor.visitLdcOrIntConstant(value)
|
||||||
|
is Double -> invokeMethodVisitor.visitLdcOrDoubleConstant(value)
|
||||||
|
is Float -> invokeMethodVisitor.visitLdcOrFloatConstant(value)
|
||||||
|
else -> invokeMethodVisitor.visitLdcInsn(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeMethodVisitor.visitInvokeStatic(c, "valueOf", "($sigLetter)L${c};")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadConstant(value, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun loadFromVariables(name: String, defaultValue: T? = null): Unit = invokeMethodVisitor.run {
|
||||||
|
visitLoadObjectVar(invokeArgumentsVar)
|
||||||
|
|
||||||
|
if (defaultValue != null) {
|
||||||
|
visitLdcInsn(name)
|
||||||
|
loadTConstant(defaultValue)
|
||||||
|
|
||||||
|
visitInvokeInterface(
|
||||||
|
owner = MAP_CLASS,
|
||||||
|
name = "getOrDefault",
|
||||||
|
descriptor = "(L$OBJECT_CLASS;L$OBJECT_CLASS;)L$OBJECT_CLASS;"
|
||||||
|
)
|
||||||
|
|
||||||
|
invokeMethodVisitor.visitCheckCast(T_CLASS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
visitLdcInsn(name)
|
||||||
|
|
||||||
|
visitInvokeInterface(
|
||||||
|
owner = MAP_CLASS,
|
||||||
|
name = "get",
|
||||||
|
descriptor = "(L$OBJECT_CLASS;)L$OBJECT_CLASS;"
|
||||||
|
)
|
||||||
|
|
||||||
|
invokeMethodVisitor.visitCheckCast(T_CLASS)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun loadAlgebra() {
|
||||||
|
loadThis()
|
||||||
|
|
||||||
|
invokeMethodVisitor.visitGetField(
|
||||||
|
owner = FUNCTIONAL_COMPILED_EXPRESSION_CLASS,
|
||||||
|
name = "algebra",
|
||||||
|
descriptor = "L$ALGEBRA_CLASS;"
|
||||||
|
)
|
||||||
|
|
||||||
|
invokeMethodVisitor.visitCheckCast(T_ALGEBRA_CLASS)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun invokeAlgebraOperation(
|
||||||
|
owner: String,
|
||||||
|
method: String,
|
||||||
|
descriptor: String,
|
||||||
|
opcode: Int = Opcodes.INVOKEINTERFACE,
|
||||||
|
isInterface: Boolean = true
|
||||||
|
) {
|
||||||
|
invokeMethodVisitor.visitMethodInsn(opcode, owner, method, descriptor, isInterface)
|
||||||
|
invokeMethodVisitor.visitCheckCast(T_CLASS)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun loadStringConstant(string: String) {
|
||||||
|
invokeMethodVisitor.visitLdcInsn(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal companion object {
|
||||||
|
private val SIGNATURE_LETTERS: Map<Class<out Any>, String> by lazy {
|
||||||
|
mapOf(
|
||||||
|
java.lang.Byte::class.java to "B",
|
||||||
|
java.lang.Short::class.java to "S",
|
||||||
|
java.lang.Integer::class.java to "I",
|
||||||
|
java.lang.Long::class.java to "J",
|
||||||
|
java.lang.Float::class.java to "F",
|
||||||
|
java.lang.Double::class.java to "D"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val INLINABLE_NUMBERS: Set<Class<out Any>> by lazy { SIGNATURE_LETTERS.keys }
|
||||||
|
|
||||||
|
internal const val FUNCTIONAL_COMPILED_EXPRESSION_CLASS =
|
||||||
|
"scientifik/kmath/asm/FunctionalCompiledExpression"
|
||||||
|
|
||||||
|
internal const val MAP_CLASS = "java/util/Map"
|
||||||
|
internal const val OBJECT_CLASS = "java/lang/Object"
|
||||||
|
internal const val ALGEBRA_CLASS = "scientifik/kmath/operations/Algebra"
|
||||||
|
internal const val SPACE_OPERATIONS_CLASS = "scientifik/kmath/operations/SpaceOperations"
|
||||||
|
internal const val STRING_CLASS = "java/lang/String"
|
||||||
|
internal const val NUMBER_CLASS = "java/lang/Number"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package scientifik.kmath.asm.internal
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter
|
||||||
|
import org.objectweb.asm.MethodVisitor
|
||||||
|
|
||||||
|
inline fun ClassWriter(flags: Int, block: ClassWriter.() -> Unit): ClassWriter = ClassWriter(flags).apply(block)
|
||||||
|
|
||||||
|
inline fun ClassWriter.visitMethod(
|
||||||
|
access: Int,
|
||||||
|
name: String,
|
||||||
|
descriptor: String,
|
||||||
|
signature: String?,
|
||||||
|
exceptions: Array<String>?,
|
||||||
|
block: MethodVisitor.() -> Unit
|
||||||
|
): MethodVisitor = visitMethod(access, name, descriptor, signature, exceptions).apply(block)
|
@ -3,7 +3,7 @@ package scientifik.kmath.asm.internal
|
|||||||
import org.objectweb.asm.MethodVisitor
|
import org.objectweb.asm.MethodVisitor
|
||||||
import org.objectweb.asm.Opcodes.*
|
import org.objectweb.asm.Opcodes.*
|
||||||
|
|
||||||
internal fun MethodVisitor.visitLdcOrIConstInsn(value: Int) = when (value) {
|
internal fun MethodVisitor.visitLdcOrIntConstant(value: Int): Unit = when (value) {
|
||||||
-1 -> visitInsn(ICONST_M1)
|
-1 -> visitInsn(ICONST_M1)
|
||||||
0 -> visitInsn(ICONST_0)
|
0 -> visitInsn(ICONST_0)
|
||||||
1 -> visitInsn(ICONST_1)
|
1 -> visitInsn(ICONST_1)
|
||||||
@ -14,15 +14,41 @@ internal fun MethodVisitor.visitLdcOrIConstInsn(value: Int) = when (value) {
|
|||||||
else -> visitLdcInsn(value)
|
else -> visitLdcInsn(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun MethodVisitor.visitLdcOrDConstInsn(value: Double) = when (value) {
|
internal fun MethodVisitor.visitLdcOrDoubleConstant(value: Double): Unit = when (value) {
|
||||||
0.0 -> visitInsn(DCONST_0)
|
0.0 -> visitInsn(DCONST_0)
|
||||||
1.0 -> visitInsn(DCONST_1)
|
1.0 -> visitInsn(DCONST_1)
|
||||||
else -> visitLdcInsn(value)
|
else -> visitLdcInsn(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun MethodVisitor.visitLdcOrFConstInsn(value: Float) = when (value) {
|
internal fun MethodVisitor.visitLdcOrFloatConstant(value: Float): Unit = when (value) {
|
||||||
0f -> visitInsn(FCONST_0)
|
0f -> visitInsn(FCONST_0)
|
||||||
1f -> visitInsn(FCONST_1)
|
1f -> visitInsn(FCONST_1)
|
||||||
2f -> visitInsn(FCONST_2)
|
2f -> visitInsn(FCONST_2)
|
||||||
else -> visitLdcInsn(value)
|
else -> visitLdcInsn(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitInvokeInterface(owner: String, name: String, descriptor: String): Unit =
|
||||||
|
visitMethodInsn(INVOKEINTERFACE, owner, name, descriptor, true)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitInvokeVirtual(owner: String, name: String, descriptor: String): Unit =
|
||||||
|
visitMethodInsn(INVOKEVIRTUAL, owner, name, descriptor, false)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitInvokeStatic(owner: String, name: String, descriptor: String): Unit =
|
||||||
|
visitMethodInsn(INVOKESTATIC, owner, name, descriptor, false)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitInvokeSpecial(owner: String, name: String, descriptor: String): Unit =
|
||||||
|
visitMethodInsn(INVOKESPECIAL, owner, name, descriptor, false)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitCheckCast(type: String): Unit = visitTypeInsn(CHECKCAST, type)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitGetField(owner: String, name: String, descriptor: String): Unit =
|
||||||
|
visitFieldInsn(GETFIELD, owner, name, descriptor)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitLoadObjectVar(`var`: Int) {
|
||||||
|
visitVarInsn(ALOAD, `var`)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitGetObjectArrayElement(): Unit = visitInsn(AALOAD)
|
||||||
|
|
||||||
|
internal fun MethodVisitor.visitReturn(): Unit = visitInsn(RETURN)
|
||||||
|
internal fun MethodVisitor.visitReturnObject(): Unit = visitInsn(ARETURN)
|
||||||
|
@ -16,7 +16,7 @@ internal fun <T> hasSpecific(context: Algebra<T>, name: String, arity: Int): Boo
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T> AsmGenerationContext<T>.tryInvokeSpecific(context: Algebra<T>, name: String, arity: Int): Boolean {
|
internal fun <T> AsmGenerator<T>.tryInvokeSpecific(context: Algebra<T>, name: String, arity: Int): Boolean {
|
||||||
val aName = methodNameAdapters[name] ?: name
|
val aName = methodNameAdapters[name] ?: name
|
||||||
|
|
||||||
context::class.java.methods.find { it.name == aName && it.parameters.size == arity }
|
context::class.java.methods.find { it.name == aName && it.parameters.size == arity }
|
||||||
@ -26,12 +26,12 @@ internal fun <T> AsmGenerationContext<T>.tryInvokeSpecific(context: Algebra<T>,
|
|||||||
|
|
||||||
val sig = buildString {
|
val sig = buildString {
|
||||||
append('(')
|
append('(')
|
||||||
repeat(arity) { append("L${AsmGenerationContext.OBJECT_CLASS};") }
|
repeat(arity) { append("L${AsmGenerator.OBJECT_CLASS};") }
|
||||||
append(')')
|
append(')')
|
||||||
append("L${AsmGenerationContext.OBJECT_CLASS};")
|
append("L${AsmGenerator.OBJECT_CLASS};")
|
||||||
}
|
}
|
||||||
|
|
||||||
visitAlgebraOperation(
|
invokeAlgebraOperation(
|
||||||
owner = owner,
|
owner = owner,
|
||||||
method = aName,
|
method = aName,
|
||||||
descriptor = sig,
|
descriptor = sig,
|
||||||
|
Loading…
Reference in New Issue
Block a user