Dev #127
@ -18,6 +18,7 @@ import kotlin.reflect.KClass
|
|||||||
* @param T the type of AsmExpression to unwrap.
|
* @param T the type of AsmExpression to unwrap.
|
||||||
* @param algebra the algebra the applied AsmExpressions use.
|
* @param algebra the algebra the applied AsmExpressions use.
|
||||||
* @param className the unique class name of new loaded class.
|
* @param className the unique class name of new loaded class.
|
||||||
|
* @param invokeLabel0Visitor the function to apply to this object when generating invoke method, label 0.
|
||||||
*/
|
*/
|
||||||
internal class AsmBuilder<T> internal constructor(
|
internal class AsmBuilder<T> internal constructor(
|
||||||
private val classOfT: KClass<*>,
|
private val classOfT: KClass<*>,
|
||||||
@ -37,8 +38,19 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
*/
|
*/
|
||||||
private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader)
|
private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM Type for [algebra]
|
||||||
|
*/
|
||||||
private val tAlgebraType: Type = algebra::class.asm
|
private val tAlgebraType: Type = algebra::class.asm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [T]
|
||||||
|
*/
|
||||||
internal val tType: Type = classOfT.asm
|
internal val tType: Type = classOfT.asm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for new class
|
||||||
|
*/
|
||||||
private val classType: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!!
|
private val classType: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,14 +72,30 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
* Method visitor of `invoke` method of the subclass.
|
* Method visitor of `invoke` method of the subclass.
|
||||||
*/
|
*/
|
||||||
private lateinit var invokeMethodVisitor: InstructionAdapter
|
private lateinit var invokeMethodVisitor: InstructionAdapter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State if [T] a primitive type, so [AsmBuilder] may generate direct primitive calls.
|
||||||
|
*/
|
||||||
internal var primitiveMode = false
|
internal var primitiveMode = false
|
||||||
|
|
||||||
@Suppress("PropertyName")
|
/**
|
||||||
internal var PRIMITIVE_MASK: Type = OBJECT_TYPE
|
* Primitive type to apple for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode].
|
||||||
|
*/
|
||||||
|
internal var primitiveMask: Type = OBJECT_TYPE
|
||||||
|
|
||||||
@Suppress("PropertyName")
|
/**
|
||||||
internal var PRIMITIVE_MASK_BOXED: Type = OBJECT_TYPE
|
* Boxed primitive type to apple for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode].
|
||||||
|
*/
|
||||||
|
internal var primitiveMaskBoxed: Type = OBJECT_TYPE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack of useful objects types on stack to verify types.
|
||||||
|
*/
|
||||||
private val typeStack = Stack<Type>()
|
private val typeStack = Stack<Type>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack of useful objects types on stack expected by algebra calls.
|
||||||
|
*/
|
||||||
internal val expectationStack: Stack<Type> = Stack<Type>().apply { push(tType) }
|
internal val expectationStack: Stack<Type> = Stack<Type>().apply { push(tType) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,8 +114,8 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
|
|
||||||
if (SIGNATURE_LETTERS.containsKey(classOfT)) {
|
if (SIGNATURE_LETTERS.containsKey(classOfT)) {
|
||||||
primitiveMode = true
|
primitiveMode = true
|
||||||
PRIMITIVE_MASK = SIGNATURE_LETTERS.getValue(classOfT)
|
primitiveMask = SIGNATURE_LETTERS.getValue(classOfT)
|
||||||
PRIMITIVE_MASK_BOXED = tType
|
primitiveMaskBoxed = tType
|
||||||
}
|
}
|
||||||
|
|
||||||
val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
||||||
@ -238,34 +266,43 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a constant from
|
* Loads a [T] constant from [constants].
|
||||||
*/
|
*/
|
||||||
internal fun loadTConstant(value: T) {
|
internal fun loadTConstant(value: T) {
|
||||||
if (classOfT 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(tType) else typeStack.push(PRIMITIVE_MASK)
|
if (mustBeBoxed) typeStack.push(tType) else typeStack.push(primitiveMask)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConstant(value as Any, tType)
|
loadConstant(value as Any, tType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boxes the current value and pushes it.
|
||||||
|
*/
|
||||||
private fun box(): Unit = invokeMethodVisitor.invokestatic(
|
private fun box(): Unit = invokeMethodVisitor.invokestatic(
|
||||||
tType.internalName,
|
tType.internalName,
|
||||||
"valueOf",
|
"valueOf",
|
||||||
Type.getMethodDescriptor(tType, PRIMITIVE_MASK),
|
Type.getMethodDescriptor(tType, primitiveMask),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unboxes the current boxed value and pushes it.
|
||||||
|
*/
|
||||||
private fun unbox(): Unit = invokeMethodVisitor.invokevirtual(
|
private fun unbox(): Unit = invokeMethodVisitor.invokevirtual(
|
||||||
NUMBER_TYPE.internalName,
|
NUMBER_TYPE.internalName,
|
||||||
NUMBER_CONVERTER_METHODS.getValue(PRIMITIVE_MASK),
|
NUMBER_CONVERTER_METHODS.getValue(primitiveMask),
|
||||||
Type.getMethodDescriptor(PRIMITIVE_MASK),
|
Type.getMethodDescriptor(primitiveMask),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads [java.lang.Object] constant from constants.
|
||||||
|
*/
|
||||||
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()
|
||||||
@ -275,6 +312,9 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
checkcast(type)
|
checkcast(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads this variable.
|
||||||
|
*/
|
||||||
private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType)
|
private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -344,7 +384,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
typeStack.push(tType)
|
typeStack.push(tType)
|
||||||
else {
|
else {
|
||||||
unbox()
|
unbox()
|
||||||
typeStack.push(PRIMITIVE_MASK)
|
typeStack.push(primitiveMask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +433,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
typeStack.push(tType)
|
typeStack.push(tType)
|
||||||
else {
|
else {
|
||||||
unbox()
|
unbox()
|
||||||
typeStack.push(PRIMITIVE_MASK)
|
typeStack.push(primitiveMask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +444,7 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
|
|
||||||
internal companion object {
|
internal companion object {
|
||||||
/**
|
/**
|
||||||
* Maps JVM primitive numbers boxed types to their letters of JVM signature convention.
|
* Maps JVM primitive numbers boxed types to their primitive ASM types.
|
||||||
*/
|
*/
|
||||||
private val SIGNATURE_LETTERS: Map<KClass<out Any>, Type> by lazy {
|
private val SIGNATURE_LETTERS: Map<KClass<out Any>, Type> by lazy {
|
||||||
hashMapOf(
|
hashMapOf(
|
||||||
@ -417,8 +457,14 @@ internal class AsmBuilder<T> internal constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps JVM primitive numbers boxed ASM types to their primitive ASM types.
|
||||||
|
*/
|
||||||
private val BOXED_TO_PRIMITIVES: Map<Type, Type> by lazy { SIGNATURE_LETTERS.mapKeys { (k, _) -> k.asm } }
|
private val BOXED_TO_PRIMITIVES: Map<Type, Type> by lazy { SIGNATURE_LETTERS.mapKeys { (k, _) -> k.asm } }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps primitive ASM types to [Number] functions unboxing them.
|
||||||
|
*/
|
||||||
private val NUMBER_CONVERTER_METHODS: Map<Type, String> by lazy {
|
private val NUMBER_CONVERTER_METHODS: Map<Type, String> by lazy {
|
||||||
hashMapOf(
|
hashMapOf(
|
||||||
Type.BYTE_TYPE to "byteValue",
|
Type.BYTE_TYPE to "byteValue",
|
||||||
@ -434,14 +480,41 @@ 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<KClass<out Any>> by lazy { SIGNATURE_LETTERS.keys }
|
private val INLINABLE_NUMBERS: Set<KClass<out Any>> by lazy { SIGNATURE_LETTERS.keys }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [Expression].
|
||||||
|
*/
|
||||||
internal val EXPRESSION_TYPE: Type by lazy { Expression::class.asm }
|
internal val EXPRESSION_TYPE: Type by lazy { Expression::class.asm }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [java.lang.Number].
|
||||||
|
*/
|
||||||
internal val NUMBER_TYPE: Type by lazy { java.lang.Number::class.asm }
|
internal val NUMBER_TYPE: Type by lazy { java.lang.Number::class.asm }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [java.util.Map].
|
||||||
|
*/
|
||||||
internal val MAP_TYPE: Type by lazy { java.util.Map::class.asm }
|
internal val MAP_TYPE: Type by lazy { java.util.Map::class.asm }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [java.lang.Object].
|
||||||
|
*/
|
||||||
internal val OBJECT_TYPE: Type by lazy { java.lang.Object::class.asm }
|
internal val OBJECT_TYPE: Type by lazy { java.lang.Object::class.asm }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for array of [java.lang.Object].
|
||||||
|
*/
|
||||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "RemoveRedundantQualifierName")
|
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "RemoveRedundantQualifierName")
|
||||||
internal val OBJECT_ARRAY_TYPE: Type by lazy { Array<java.lang.Object>::class.asm }
|
internal val OBJECT_ARRAY_TYPE: Type by lazy { Array<java.lang.Object>::class.asm }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [Algebra].
|
||||||
|
*/
|
||||||
internal val ALGEBRA_TYPE: Type by lazy { Algebra::class.asm }
|
internal val ALGEBRA_TYPE: Type by lazy { Algebra::class.asm }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM type for [java.lang.String].
|
||||||
|
*/
|
||||||
internal val STRING_TYPE: Type by lazy { java.lang.String::class.asm }
|
internal val STRING_TYPE: Type by lazy { java.lang.String::class.asm }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package scientifik.kmath.asm.internal
|
|||||||
|
|
||||||
import org.objectweb.asm.ClassWriter
|
import org.objectweb.asm.ClassWriter
|
||||||
import org.objectweb.asm.FieldVisitor
|
import org.objectweb.asm.FieldVisitor
|
||||||
import org.objectweb.asm.MethodVisitor
|
|
||||||
|
|
||||||
internal inline fun ClassWriter(flags: Int, block: ClassWriter.() -> Unit): ClassWriter =
|
internal inline fun ClassWriter(flags: Int, block: ClassWriter.() -> Unit): ClassWriter =
|
||||||
ClassWriter(flags).apply(block)
|
ClassWriter(flags).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 tType
|
val t = if (primitiveMode && hasSpecific) primitiveMask else tType
|
||||||
repeat(arity) { expectationStack.push(t) }
|
repeat(arity) { expectationStack.push(t) }
|
||||||
|
|
||||||
return hasSpecific
|
return hasSpecific
|
||||||
@ -52,7 +52,7 @@ internal fun <T> AsmBuilder<T>.tryInvokeSpecific(context: Algebra<T>, name: Stri
|
|||||||
invokeAlgebraOperation(
|
invokeAlgebraOperation(
|
||||||
owner = owner,
|
owner = owner,
|
||||||
method = aName,
|
method = aName,
|
||||||
descriptor = Type.getMethodDescriptor(PRIMITIVE_MASK_BOXED, *Array(arity) { PRIMITIVE_MASK }),
|
descriptor = Type.getMethodDescriptor(primitiveMaskBoxed, *Array(arity) { primitiveMask }),
|
||||||
tArity = arity,
|
tArity = arity,
|
||||||
opcode = Opcodes.INVOKEVIRTUAL
|
opcode = Opcodes.INVOKEVIRTUAL
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user