Dev #127

Merged
altavir merged 214 commits from dev into master 2020-08-11 08:33:21 +03:00
3 changed files with 89 additions and 17 deletions
Showing only changes of commit 23816d3366 - Show all commits

View File

@ -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 }
} }
} }

View File

@ -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)

View File

@ -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
) )