forked from kscience/kmath
Delete AsmCompiledExpression abstract class, implement dynamic field generation to reduce quantity of cast instructions, minor refactor and renaming of internal APIs
This commit is contained in:
parent
7ddab0224a
commit
e47ec1aeb9
@ -24,20 +24,20 @@ For example, the following builder:
|
|||||||
package scientifik.kmath.asm.generated;
|
package scientifik.kmath.asm.generated;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import scientifik.kmath.asm.internal.AsmCompiledExpression;
|
import scientifik.kmath.expressions.Expression;
|
||||||
import scientifik.kmath.operations.Algebra;
|
|
||||||
import scientifik.kmath.operations.RealField;
|
import scientifik.kmath.operations.RealField;
|
||||||
|
|
||||||
// The class's name is build with MST's hash-code and collision fixing number.
|
public final class AsmCompiledExpression_1073786867_0 implements Expression<Double> {
|
||||||
public final class AsmCompiledExpression_45045_0 extends AsmCompiledExpression<Double> {
|
private final RealField algebra;
|
||||||
// Plain constructor
|
private final Object[] constants;
|
||||||
public AsmCompiledExpression_45045_0(Algebra algebra, Object[] constants) {
|
|
||||||
super(algebra, constants);
|
public AsmCompiledExpression_1073786867_0(RealField algebra, Object[] constants) {
|
||||||
|
this.algebra = algebra;
|
||||||
|
this.constants = constants;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The actual dynamic code:
|
|
||||||
public final Double invoke(Map<String, ? extends Double> arguments) {
|
public final Double invoke(Map<String, ? extends Double> arguments) {
|
||||||
return (Double)((RealField)super.algebra).add((Double)arguments.get("x"), (Double)2.0D);
|
return (Double)this.algebra.add(((Double)arguments.get("x")).doubleValue(), 2.0D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,6 +6,7 @@ import org.objectweb.asm.Opcodes.RETURN
|
|||||||
import org.objectweb.asm.commons.InstructionAdapter
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
import scientifik.kmath.asm.internal.AsmBuilder.ClassLoader
|
import scientifik.kmath.asm.internal.AsmBuilder.ClassLoader
|
||||||
import scientifik.kmath.ast.MST
|
import scientifik.kmath.ast.MST
|
||||||
|
import scientifik.kmath.expressions.Expression
|
||||||
import scientifik.kmath.operations.Algebra
|
import scientifik.kmath.operations.Algebra
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -36,32 +37,27 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
*/
|
*/
|
||||||
private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader)
|
private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader)
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
private val tAlgebraType: Type = algebra::class.asm
|
||||||
private val T_ALGEBRA_TYPE: Type = algebra::class.asm
|
internal val tType: Type = classOfT.asm
|
||||||
|
private val classType: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!!
|
||||||
@Suppress("PrivatePropertyName")
|
|
||||||
internal val T_TYPE: Type = classOfT.asm
|
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
|
||||||
private val CLASS_TYPE: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!!
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index of `this` variable in invoke method of [AsmCompiledExpression] built subclass.
|
* Index of `this` variable in invoke method of the built subclass.
|
||||||
*/
|
*/
|
||||||
private val invokeThisVar: Int = 0
|
private val invokeThisVar: Int = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index of `arguments` variable in invoke method of [AsmCompiledExpression] built subclass.
|
* Index of `arguments` variable in invoke method of the built subclass.
|
||||||
*/
|
*/
|
||||||
private val invokeArgumentsVar: Int = 1
|
private val invokeArgumentsVar: Int = 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of constants to provide to [AsmCompiledExpression] subclass.
|
* List of constants to provide to the subclass.
|
||||||
*/
|
*/
|
||||||
private val constants: MutableList<Any> = mutableListOf()
|
private val constants: MutableList<Any> = mutableListOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method visitor of `invoke` method of [AsmCompiledExpression] subclass.
|
* Method visitor of `invoke` method of the subclass.
|
||||||
*/
|
*/
|
||||||
private lateinit var invokeMethodVisitor: InstructionAdapter
|
private lateinit var invokeMethodVisitor: InstructionAdapter
|
||||||
internal var primitiveMode = false
|
internal var primitiveMode = false
|
||||||
@ -72,78 +68,92 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
@Suppress("PropertyName")
|
@Suppress("PropertyName")
|
||||||
internal var PRIMITIVE_MASK_BOXED: Type = OBJECT_TYPE
|
internal var PRIMITIVE_MASK_BOXED: Type = OBJECT_TYPE
|
||||||
private val typeStack = Stack<Type>()
|
private val typeStack = Stack<Type>()
|
||||||
internal val expectationStack = Stack<Type>().apply { push(T_TYPE) }
|
internal val expectationStack: Stack<Type> = Stack<Type>().apply { push(tType) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cache of [AsmCompiledExpression] subclass built by this builder.
|
* The cache for instance built by this builder.
|
||||||
*/
|
*/
|
||||||
private var generatedInstance: AsmCompiledExpression<T>? = null
|
private var generatedInstance: Expression<T>? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses, loads and instantiates the [AsmCompiledExpression] for given parameters.
|
* Subclasses, loads and instantiates [Expression] for given parameters.
|
||||||
*
|
*
|
||||||
* The built instance is cached.
|
* The built instance is cached.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun getInstance(): AsmCompiledExpression<T> {
|
fun getInstance(): Expression<T> {
|
||||||
generatedInstance?.let { return it }
|
generatedInstance?.let { return it }
|
||||||
|
|
||||||
if (SIGNATURE_LETTERS.containsKey(classOfT.java)) {
|
if (SIGNATURE_LETTERS.containsKey(classOfT)) {
|
||||||
primitiveMode = true
|
primitiveMode = true
|
||||||
PRIMITIVE_MASK = SIGNATURE_LETTERS.getValue(classOfT.java)
|
PRIMITIVE_MASK = SIGNATURE_LETTERS.getValue(classOfT)
|
||||||
PRIMITIVE_MASK_BOXED = T_TYPE
|
PRIMITIVE_MASK_BOXED = tType
|
||||||
}
|
}
|
||||||
|
|
||||||
val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
||||||
visit(
|
visit(
|
||||||
Opcodes.V1_8,
|
Opcodes.V1_8,
|
||||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_SUPER,
|
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL or Opcodes.ACC_SUPER,
|
||||||
CLASS_TYPE.internalName,
|
classType.internalName,
|
||||||
"L${ASM_COMPILED_EXPRESSION_TYPE.internalName}<${T_TYPE.descriptor}>;",
|
"${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;",
|
||||||
ASM_COMPILED_EXPRESSION_TYPE.internalName,
|
OBJECT_TYPE.internalName,
|
||||||
arrayOf()
|
arrayOf(EXPRESSION_TYPE.internalName)
|
||||||
|
)
|
||||||
|
|
||||||
|
visitField(
|
||||||
|
access = Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL,
|
||||||
|
name = "algebra",
|
||||||
|
descriptor = tAlgebraType.descriptor,
|
||||||
|
signature = null,
|
||||||
|
value = null,
|
||||||
|
block = FieldVisitor::visitEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
visitField(
|
||||||
|
access = Opcodes.ACC_PRIVATE or Opcodes.ACC_FINAL,
|
||||||
|
name = "constants",
|
||||||
|
descriptor = OBJECT_ARRAY_TYPE.descriptor,
|
||||||
|
signature = null,
|
||||||
|
value = null,
|
||||||
|
block = FieldVisitor::visitEnd
|
||||||
)
|
)
|
||||||
|
|
||||||
visitMethod(
|
visitMethod(
|
||||||
Opcodes.ACC_PUBLIC,
|
Opcodes.ACC_PUBLIC,
|
||||||
"<init>",
|
"<init>",
|
||||||
Type.getMethodDescriptor(Type.VOID_TYPE, ALGEBRA_TYPE, OBJECT_ARRAY_TYPE),
|
Type.getMethodDescriptor(Type.VOID_TYPE, tAlgebraType, OBJECT_ARRAY_TYPE),
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
).instructionAdapter {
|
).instructionAdapter {
|
||||||
val thisVar = 0
|
val thisVar = 0
|
||||||
val algebraVar = 1
|
val algebraVar = 1
|
||||||
val constantsVar = 2
|
val constantsVar = 2
|
||||||
val l0 = Label()
|
val l0 = label()
|
||||||
visitLabel(l0)
|
load(thisVar, classType)
|
||||||
load(thisVar, CLASS_TYPE)
|
invokespecial(OBJECT_TYPE.internalName, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), false)
|
||||||
load(algebraVar, ALGEBRA_TYPE)
|
label()
|
||||||
|
load(thisVar, classType)
|
||||||
|
load(algebraVar, tAlgebraType)
|
||||||
|
putfield(classType.internalName, "algebra", tAlgebraType.descriptor)
|
||||||
|
label()
|
||||||
|
load(thisVar, classType)
|
||||||
load(constantsVar, OBJECT_ARRAY_TYPE)
|
load(constantsVar, OBJECT_ARRAY_TYPE)
|
||||||
|
putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor)
|
||||||
invokespecial(
|
label()
|
||||||
ASM_COMPILED_EXPRESSION_TYPE.internalName,
|
|
||||||
"<init>",
|
|
||||||
Type.getMethodDescriptor(Type.VOID_TYPE, ALGEBRA_TYPE, OBJECT_ARRAY_TYPE),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
val l1 = Label()
|
|
||||||
visitLabel(l1)
|
|
||||||
visitInsn(RETURN)
|
visitInsn(RETURN)
|
||||||
val l2 = Label()
|
val l4 = label()
|
||||||
visitLabel(l2)
|
visitLocalVariable("this", classType.descriptor, null, l0, l4, thisVar)
|
||||||
visitLocalVariable("this", CLASS_TYPE.descriptor, null, l0, l2, thisVar)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
visitLocalVariable(
|
||||||
"algebra",
|
"algebra",
|
||||||
ALGEBRA_TYPE.descriptor,
|
tAlgebraType.descriptor,
|
||||||
"L${ALGEBRA_TYPE.internalName}<${T_TYPE.descriptor}>;",
|
null,
|
||||||
l0,
|
l0,
|
||||||
l2,
|
l4,
|
||||||
algebraVar
|
algebraVar
|
||||||
)
|
)
|
||||||
|
|
||||||
visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l2, constantsVar)
|
visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, constantsVar)
|
||||||
visitMaxs(0, 3)
|
visitMaxs(0, 3)
|
||||||
visitEnd()
|
visitEnd()
|
||||||
}
|
}
|
||||||
@ -151,22 +161,20 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
visitMethod(
|
visitMethod(
|
||||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
||||||
"invoke",
|
"invoke",
|
||||||
Type.getMethodDescriptor(T_TYPE, MAP_TYPE),
|
Type.getMethodDescriptor(tType, MAP_TYPE),
|
||||||
"(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${T_TYPE.descriptor}>;)${T_TYPE.descriptor}",
|
"(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}",
|
||||||
null
|
null
|
||||||
).instructionAdapter {
|
).instructionAdapter {
|
||||||
invokeMethodVisitor = this
|
invokeMethodVisitor = this
|
||||||
visitCode()
|
visitCode()
|
||||||
val l0 = Label()
|
val l0 = label()
|
||||||
visitLabel(l0)
|
|
||||||
invokeLabel0Visitor()
|
invokeLabel0Visitor()
|
||||||
areturn(T_TYPE)
|
areturn(tType)
|
||||||
val l1 = Label()
|
val l1 = label()
|
||||||
visitLabel(l1)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
visitLocalVariable(
|
||||||
"this",
|
"this",
|
||||||
CLASS_TYPE.descriptor,
|
classType.descriptor,
|
||||||
null,
|
null,
|
||||||
l0,
|
l0,
|
||||||
l1,
|
l1,
|
||||||
@ -176,7 +184,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
visitLocalVariable(
|
visitLocalVariable(
|
||||||
"arguments",
|
"arguments",
|
||||||
MAP_TYPE.descriptor,
|
MAP_TYPE.descriptor,
|
||||||
"L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${T_TYPE.descriptor}>;",
|
"L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;",
|
||||||
l0,
|
l0,
|
||||||
l1,
|
l1,
|
||||||
invokeArgumentsVar
|
invokeArgumentsVar
|
||||||
@ -196,18 +204,16 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
val thisVar = 0
|
val thisVar = 0
|
||||||
val argumentsVar = 1
|
val argumentsVar = 1
|
||||||
visitCode()
|
visitCode()
|
||||||
val l0 = Label()
|
val l0 = label()
|
||||||
visitLabel(l0)
|
|
||||||
load(thisVar, OBJECT_TYPE)
|
load(thisVar, OBJECT_TYPE)
|
||||||
load(argumentsVar, MAP_TYPE)
|
load(argumentsVar, MAP_TYPE)
|
||||||
invokevirtual(CLASS_TYPE.internalName, "invoke", Type.getMethodDescriptor(T_TYPE, MAP_TYPE), false)
|
invokevirtual(classType.internalName, "invoke", Type.getMethodDescriptor(tType, MAP_TYPE), false)
|
||||||
areturn(T_TYPE)
|
areturn(tType)
|
||||||
val l1 = Label()
|
val l1 = label()
|
||||||
visitLabel(l1)
|
|
||||||
|
|
||||||
visitLocalVariable(
|
visitLocalVariable(
|
||||||
"this",
|
"this",
|
||||||
CLASS_TYPE.descriptor,
|
classType.descriptor,
|
||||||
null,
|
null,
|
||||||
l0,
|
l0,
|
||||||
l1,
|
l1,
|
||||||
@ -225,7 +231,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
.defineClass(className, classWriter.toByteArray())
|
.defineClass(className, classWriter.toByteArray())
|
||||||
.constructors
|
.constructors
|
||||||
.first()
|
.first()
|
||||||
.newInstance(algebra, constants.toTypedArray()) as AsmCompiledExpression<T>
|
.newInstance(algebra, constants.toTypedArray()) as Expression<T>
|
||||||
|
|
||||||
generatedInstance = new
|
generatedInstance = new
|
||||||
return new
|
return new
|
||||||
@ -235,21 +241,21 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
* Loads a constant from
|
* Loads a constant from
|
||||||
*/
|
*/
|
||||||
internal fun loadTConstant(value: T) {
|
internal fun loadTConstant(value: T) {
|
||||||
if (classOfT.java in INLINABLE_NUMBERS) {
|
if (classOfT in INLINABLE_NUMBERS) {
|
||||||
val expectedType = expectationStack.pop()!!
|
val expectedType = expectationStack.pop()!!
|
||||||
val mustBeBoxed = expectedType.sort == Type.OBJECT
|
val mustBeBoxed = expectedType.sort == Type.OBJECT
|
||||||
loadNumberConstant(value as Number, mustBeBoxed)
|
loadNumberConstant(value as Number, mustBeBoxed)
|
||||||
if (mustBeBoxed) typeStack.push(T_TYPE) else typeStack.push(PRIMITIVE_MASK)
|
if (mustBeBoxed) typeStack.push(tType) else typeStack.push(PRIMITIVE_MASK)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConstant(value as Any, T_TYPE)
|
loadConstant(value as Any, tType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun box(): Unit = invokeMethodVisitor.invokestatic(
|
private fun box(): Unit = invokeMethodVisitor.invokestatic(
|
||||||
T_TYPE.internalName,
|
tType.internalName,
|
||||||
"valueOf",
|
"valueOf",
|
||||||
Type.getMethodDescriptor(T_TYPE, PRIMITIVE_MASK),
|
Type.getMethodDescriptor(tType, PRIMITIVE_MASK),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -263,16 +269,16 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
private fun loadConstant(value: Any, type: Type): Unit = invokeMethodVisitor.run {
|
private fun loadConstant(value: Any, type: Type): Unit = invokeMethodVisitor.run {
|
||||||
val idx = if (value in constants) constants.indexOf(value) else constants.apply { add(value) }.lastIndex
|
val idx = if (value in constants) constants.indexOf(value) else constants.apply { add(value) }.lastIndex
|
||||||
loadThis()
|
loadThis()
|
||||||
getfield(CLASS_TYPE.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor)
|
getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor)
|
||||||
iconst(idx)
|
iconst(idx)
|
||||||
visitInsn(AALOAD)
|
visitInsn(AALOAD)
|
||||||
checkcast(type)
|
checkcast(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, CLASS_TYPE)
|
private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Either loads a numeric constant [value] from [AsmCompiledExpression] constants field or boxes a primitive
|
* Either loads a numeric constant [value] from the class's constants field or boxes a primitive
|
||||||
* constant from the constant pool (some numbers with special opcodes like [Opcodes.ICONST_0] aren't even loaded
|
* constant from the constant pool (some numbers with special opcodes like [Opcodes.ICONST_0] aren't even loaded
|
||||||
* from it).
|
* from it).
|
||||||
*/
|
*/
|
||||||
@ -292,7 +298,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
|
|
||||||
if (mustBeBoxed) {
|
if (mustBeBoxed) {
|
||||||
box()
|
box()
|
||||||
invokeMethodVisitor.checkcast(T_TYPE)
|
invokeMethodVisitor.checkcast(tType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -300,11 +306,11 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
|
|
||||||
loadConstant(value, boxed)
|
loadConstant(value, boxed)
|
||||||
if (!mustBeBoxed) unbox()
|
if (!mustBeBoxed) unbox()
|
||||||
else invokeMethodVisitor.checkcast(T_TYPE)
|
else invokeMethodVisitor.checkcast(tType)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a variable [name] from [AsmCompiledExpression.invoke] [Map] parameter. The [defaultValue] may be provided.
|
* Loads a variable [name] arguments [Map] parameter of [Expression.invoke]. The [defaultValue] may be provided.
|
||||||
*/
|
*/
|
||||||
internal fun loadVariable(name: String, defaultValue: T? = null): Unit = invokeMethodVisitor.run {
|
internal fun loadVariable(name: String, defaultValue: T? = null): Unit = invokeMethodVisitor.run {
|
||||||
load(invokeArgumentsVar, OBJECT_ARRAY_TYPE)
|
load(invokeArgumentsVar, OBJECT_ARRAY_TYPE)
|
||||||
@ -319,7 +325,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE)
|
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE)
|
||||||
)
|
)
|
||||||
|
|
||||||
invokeMethodVisitor.checkcast(T_TYPE)
|
invokeMethodVisitor.checkcast(tType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,11 +337,11 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE)
|
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE)
|
||||||
)
|
)
|
||||||
|
|
||||||
invokeMethodVisitor.checkcast(T_TYPE)
|
invokeMethodVisitor.checkcast(tType)
|
||||||
val expectedType = expectationStack.pop()!!
|
val expectedType = expectationStack.pop()!!
|
||||||
|
|
||||||
if (expectedType.sort == Type.OBJECT)
|
if (expectedType.sort == Type.OBJECT)
|
||||||
typeStack.push(T_TYPE)
|
typeStack.push(tType)
|
||||||
else {
|
else {
|
||||||
unbox()
|
unbox()
|
||||||
typeStack.push(PRIMITIVE_MASK)
|
typeStack.push(PRIMITIVE_MASK)
|
||||||
@ -343,15 +349,11 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads algebra from according field of [AsmCompiledExpression] and casts it to class of [algebra] provided.
|
* Loads algebra from according field of the class and casts it to class of [algebra] provided.
|
||||||
*/
|
*/
|
||||||
internal fun loadAlgebra() {
|
internal fun loadAlgebra() {
|
||||||
loadThis()
|
loadThis()
|
||||||
|
invokeMethodVisitor.getfield(classType.internalName, "algebra", tAlgebraType.descriptor)
|
||||||
invokeMethodVisitor.run {
|
|
||||||
getfield(ASM_COMPILED_EXPRESSION_TYPE.internalName, "algebra", ALGEBRA_TYPE.descriptor)
|
|
||||||
checkcast(T_ALGEBRA_TYPE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -368,7 +370,12 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
tArity: Int,
|
tArity: Int,
|
||||||
opcode: Int = Opcodes.INVOKEINTERFACE
|
opcode: Int = Opcodes.INVOKEINTERFACE
|
||||||
) {
|
) {
|
||||||
repeat(tArity) { if (!typeStack.empty()) typeStack.pop() }
|
run loop@{
|
||||||
|
repeat(tArity) {
|
||||||
|
if (typeStack.empty()) return@loop
|
||||||
|
typeStack.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
invokeMethodVisitor.visitMethodInsn(
|
invokeMethodVisitor.visitMethodInsn(
|
||||||
opcode,
|
opcode,
|
||||||
@ -378,12 +385,12 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
opcode == Opcodes.INVOKEINTERFACE
|
opcode == Opcodes.INVOKEINTERFACE
|
||||||
)
|
)
|
||||||
|
|
||||||
invokeMethodVisitor.checkcast(T_TYPE)
|
invokeMethodVisitor.checkcast(tType)
|
||||||
val isLastExpr = expectationStack.size == 1
|
val isLastExpr = expectationStack.size == 1
|
||||||
val expectedType = expectationStack.pop()!!
|
val expectedType = expectationStack.pop()!!
|
||||||
|
|
||||||
if (expectedType.sort == Type.OBJECT || isLastExpr)
|
if (expectedType.sort == Type.OBJECT || isLastExpr)
|
||||||
typeStack.push(T_TYPE)
|
typeStack.push(tType)
|
||||||
else {
|
else {
|
||||||
unbox()
|
unbox()
|
||||||
typeStack.push(PRIMITIVE_MASK)
|
typeStack.push(PRIMITIVE_MASK)
|
||||||
@ -399,27 +406,18 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
/**
|
/**
|
||||||
* Maps JVM primitive numbers boxed types to their letters of JVM signature convention.
|
* Maps JVM primitive numbers boxed types to their letters of JVM signature convention.
|
||||||
*/
|
*/
|
||||||
private val SIGNATURE_LETTERS: Map<Class<out Any>, Type> by lazy {
|
private val SIGNATURE_LETTERS: Map<KClass<out Any>, Type> by lazy {
|
||||||
hashMapOf(
|
hashMapOf(
|
||||||
java.lang.Byte::class.java to Type.BYTE_TYPE,
|
java.lang.Byte::class to Type.BYTE_TYPE,
|
||||||
java.lang.Short::class.java to Type.SHORT_TYPE,
|
java.lang.Short::class to Type.SHORT_TYPE,
|
||||||
java.lang.Integer::class.java to Type.INT_TYPE,
|
java.lang.Integer::class to Type.INT_TYPE,
|
||||||
java.lang.Long::class.java to Type.LONG_TYPE,
|
java.lang.Long::class to Type.LONG_TYPE,
|
||||||
java.lang.Float::class.java to Type.FLOAT_TYPE,
|
java.lang.Float::class to Type.FLOAT_TYPE,
|
||||||
java.lang.Double::class.java to Type.DOUBLE_TYPE
|
java.lang.Double::class to Type.DOUBLE_TYPE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val BOXED_TO_PRIMITIVES: Map<Type, Type> by lazy {
|
private val BOXED_TO_PRIMITIVES: Map<Type, Type> by lazy { SIGNATURE_LETTERS.mapKeys { (k, _) -> k.asm } }
|
||||||
hashMapOf(
|
|
||||||
java.lang.Byte::class.asm to Type.BYTE_TYPE,
|
|
||||||
java.lang.Short::class.asm to Type.SHORT_TYPE,
|
|
||||||
java.lang.Integer::class.asm to Type.INT_TYPE,
|
|
||||||
java.lang.Long::class.asm to Type.LONG_TYPE,
|
|
||||||
java.lang.Float::class.asm to Type.FLOAT_TYPE,
|
|
||||||
java.lang.Double::class.asm to Type.DOUBLE_TYPE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val NUMBER_CONVERTER_METHODS: Map<Type, String> by lazy {
|
private val NUMBER_CONVERTER_METHODS: Map<Type, String> by lazy {
|
||||||
hashMapOf(
|
hashMapOf(
|
||||||
@ -435,15 +433,15 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
/**
|
/**
|
||||||
* Provides boxed number types values of which can be stored in JVM bytecode constant pool.
|
* Provides boxed number types values of which can be stored in JVM bytecode constant pool.
|
||||||
*/
|
*/
|
||||||
private val INLINABLE_NUMBERS: Set<Class<out Any>> by lazy { SIGNATURE_LETTERS.keys }
|
private val INLINABLE_NUMBERS: Set<KClass<out Any>> by lazy { SIGNATURE_LETTERS.keys }
|
||||||
internal val ASM_COMPILED_EXPRESSION_TYPE: Type = AsmCompiledExpression::class.asm
|
internal val EXPRESSION_TYPE: Type by lazy { Expression::class.asm }
|
||||||
internal val NUMBER_TYPE: Type = java.lang.Number::class.asm
|
internal val NUMBER_TYPE: Type by lazy { java.lang.Number::class.asm }
|
||||||
internal val MAP_TYPE: Type = java.util.Map::class.asm
|
internal val MAP_TYPE: Type by lazy { java.util.Map::class.asm }
|
||||||
internal val OBJECT_TYPE: Type = java.lang.Object::class.asm
|
internal val OBJECT_TYPE: Type by lazy { java.lang.Object::class.asm }
|
||||||
|
|
||||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "RemoveRedundantQualifierName")
|
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "RemoveRedundantQualifierName")
|
||||||
internal val OBJECT_ARRAY_TYPE: Type = Array<java.lang.Object>::class.asm
|
internal val OBJECT_ARRAY_TYPE: Type by lazy { Array<java.lang.Object>::class.asm }
|
||||||
internal val ALGEBRA_TYPE: Type = Algebra::class.asm
|
internal val ALGEBRA_TYPE: Type by lazy { Algebra::class.asm }
|
||||||
internal val STRING_TYPE: Type = java.lang.String::class.asm
|
internal val STRING_TYPE: Type by lazy { java.lang.String::class.asm }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
package scientifik.kmath.asm.internal
|
|
||||||
|
|
||||||
import scientifik.kmath.expressions.Expression
|
|
||||||
import scientifik.kmath.operations.Algebra
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [Expression] partial implementation to have it subclassed by actual implementations. Provides unified storage for
|
|
||||||
* objects needed to implement the expression.
|
|
||||||
*
|
|
||||||
* @property algebra the algebra to delegate calls.
|
|
||||||
* @property constants the constants array to have persistent objects to reference in [invoke].
|
|
||||||
*/
|
|
||||||
internal abstract class AsmCompiledExpression<T> internal constructor(
|
|
||||||
@JvmField protected val algebra: Algebra<T>,
|
|
||||||
@JvmField protected val constants: Array<Any>
|
|
||||||
) : Expression<T> {
|
|
||||||
abstract override fun invoke(arguments: Map<String, T>): T
|
|
||||||
}
|
|
@ -1,9 +1,10 @@
|
|||||||
package scientifik.kmath.asm.internal
|
package scientifik.kmath.asm.internal
|
||||||
|
|
||||||
import scientifik.kmath.ast.MST
|
import scientifik.kmath.ast.MST
|
||||||
|
import scientifik.kmath.expressions.Expression
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a class name for [AsmCompiledExpression] subclassed to implement [mst] provided.
|
* Creates a class name for [Expression] subclassed to implement [mst] provided.
|
||||||
*
|
*
|
||||||
* This methods helps to avoid collisions of class name to prevent loading several classes with the same name. If there
|
* This methods helps to avoid collisions of class name to prevent loading several classes with the same name. If there
|
||||||
* is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively.
|
* is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively.
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package scientifik.kmath.asm.internal
|
package scientifik.kmath.asm.internal
|
||||||
|
|
||||||
import org.objectweb.asm.ClassWriter
|
import org.objectweb.asm.ClassWriter
|
||||||
|
import org.objectweb.asm.FieldVisitor
|
||||||
import org.objectweb.asm.MethodVisitor
|
import org.objectweb.asm.MethodVisitor
|
||||||
|
|
||||||
internal inline fun ClassWriter(flags: Int, block: ClassWriter.() -> Unit): ClassWriter = ClassWriter(flags).apply(block)
|
internal inline fun ClassWriter(flags: Int, block: ClassWriter.() -> Unit): ClassWriter =
|
||||||
|
ClassWriter(flags).apply(block)
|
||||||
|
|
||||||
internal inline fun ClassWriter.visitMethod(
|
internal inline fun ClassWriter.visitField(
|
||||||
access: Int,
|
access: Int,
|
||||||
name: String,
|
name: String,
|
||||||
descriptor: String,
|
descriptor: String,
|
||||||
signature: String?,
|
signature: String?,
|
||||||
exceptions: Array<String>?,
|
value: Any?,
|
||||||
block: MethodVisitor.() -> Unit
|
block: FieldVisitor.() -> Unit
|
||||||
): MethodVisitor = visitMethod(access, name, descriptor, signature, exceptions).apply(block)
|
): FieldVisitor = visitField(access, name, descriptor, signature, value).apply(block)
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package scientifik.kmath.asm.internal
|
||||||
|
|
||||||
|
import org.objectweb.asm.Label
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
|
internal fun InstructionAdapter.label(): Label {
|
||||||
|
val l = Label()
|
||||||
|
visitLabel(l)
|
||||||
|
return l
|
||||||
|
}
|
@ -3,7 +3,7 @@ package scientifik.kmath.asm.internal
|
|||||||
import org.objectweb.asm.MethodVisitor
|
import org.objectweb.asm.MethodVisitor
|
||||||
import org.objectweb.asm.commons.InstructionAdapter
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
fun MethodVisitor.instructionAdapter(): InstructionAdapter = InstructionAdapter(this)
|
internal fun MethodVisitor.instructionAdapter(): InstructionAdapter = InstructionAdapter(this)
|
||||||
|
|
||||||
fun MethodVisitor.instructionAdapter(block: InstructionAdapter.() -> Unit): InstructionAdapter =
|
internal fun MethodVisitor.instructionAdapter(block: InstructionAdapter.() -> Unit): InstructionAdapter =
|
||||||
instructionAdapter().apply(block)
|
instructionAdapter().apply(block)
|
||||||
|
@ -22,7 +22,7 @@ internal fun <T> AsmBuilder<T>.buildExpectationStack(context: Algebra<T>, name:
|
|||||||
val aName = methodNameAdapters[name] ?: name
|
val aName = methodNameAdapters[name] ?: name
|
||||||
|
|
||||||
val hasSpecific = context.javaClass.methods.find { it.name == aName && it.parameters.size == arity } != null
|
val hasSpecific = context.javaClass.methods.find { it.name == aName && it.parameters.size == arity } != null
|
||||||
val t = if (primitiveMode && hasSpecific) PRIMITIVE_MASK else T_TYPE
|
val t = if (primitiveMode && hasSpecific) PRIMITIVE_MASK else tType
|
||||||
repeat(arity) { expectationStack.push(t) }
|
repeat(arity) { expectationStack.push(t) }
|
||||||
|
|
||||||
return hasSpecific
|
return hasSpecific
|
||||||
|
Loading…
Reference in New Issue
Block a user