Dev #127

Merged
altavir merged 214 commits from dev into master 2020-08-11 08:33:21 +03:00
4 changed files with 72 additions and 71 deletions
Showing only changes of commit d3d348620a - Show all commits

View File

@ -1,12 +1,13 @@
package scientifik.kmath.asm package scientifik.kmath.asm
import scientifik.kmath.asm.internal.AsmGenerationContext
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
import scientifik.kmath.operations.* import scientifik.kmath.operations.*
@PublishedApi @PublishedApi
internal fun buildName(expression: AsmExpression<*>, collision: Int = 0): String { internal fun buildName(expression: AsmNode<*>, collision: Int = 0): String {
val name = "scientifik.kmath.expressions.generated.AsmCompiledExpression_${expression.hashCode()}_$collision" val name = "scientifik.kmath.expressions.generated.AsmCompiledExpression_${expression.hashCode()}_$collision"
try { try {
@ -19,15 +20,16 @@ internal fun buildName(expression: AsmExpression<*>, collision: Int = 0): String
} }
@PublishedApi @PublishedApi
internal inline fun <reified T> AsmExpression<T>.compile(algebra: Algebra<T>): Expression<T> { internal inline fun <reified T> AsmNode<T>.compile(algebra: Algebra<T>): Expression<T> {
val ctx = AsmGenerationContext(T::class.java, algebra, buildName(this)) val ctx =
AsmGenerationContext(T::class.java, algebra, buildName(this))
compile(ctx) compile(ctx)
return ctx.generate() 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,
block: E.() -> AsmExpression<T> block: E.() -> AsmNode<T>
): Expression<T> = expressionAlgebra.block().compile(expressionAlgebra.algebra) ): Expression<T> = expressionAlgebra.block().compile(expressionAlgebra.algebra)
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(
@ -35,19 +37,19 @@ inline fun <reified T, A : NumericAlgebra<T>, E : AsmExpressionAlgebra<T, A>> A.
ast: MST ast: MST
): Expression<T> = asm(expressionAlgebra) { evaluate(ast) } ): Expression<T> = asm(expressionAlgebra) { evaluate(ast) }
inline fun <reified T, A> A.asmSpace(block: AsmExpressionSpace<T, A>.() -> AsmExpression<T>): Expression<T> where A : NumericAlgebra<T>, A : Space<T> = inline fun <reified T, A> A.asmSpace(block: AsmExpressionSpace<T, A>.() -> AsmNode<T>): Expression<T> where A : NumericAlgebra<T>, A : Space<T> =
AsmExpressionSpace(this).let { it.block().compile(it.algebra) } AsmExpressionSpace(this).let { it.block().compile(it.algebra) }
inline fun <reified T, A> A.asmSpace(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Space<T> = inline fun <reified T, A> A.asmSpace(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Space<T> =
asmSpace { evaluate(ast) } asmSpace { evaluate(ast) }
inline fun <reified T, A> A.asmRing(block: AsmExpressionRing<T, A>.() -> AsmExpression<T>): Expression<T> where A : NumericAlgebra<T>, A : Ring<T> = inline fun <reified T, A> A.asmRing(block: AsmExpressionRing<T, A>.() -> AsmNode<T>): Expression<T> where A : NumericAlgebra<T>, A : Ring<T> =
AsmExpressionRing(this).let { it.block().compile(it.algebra) } AsmExpressionRing(this).let { it.block().compile(it.algebra) }
inline fun <reified T, A> A.asmRing(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Ring<T> = inline fun <reified T, A> A.asmRing(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Ring<T> =
asmRing { evaluate(ast) } asmRing { evaluate(ast) }
inline fun <reified T, A> A.asmField(block: AsmExpressionField<T, A>.() -> AsmExpression<T>): Expression<T> where A : NumericAlgebra<T>, A : Field<T> = inline fun <reified T, A> A.asmField(block: AsmExpressionField<T, A>.() -> AsmNode<T>): Expression<T> where A : NumericAlgebra<T>, A : Field<T> =
AsmExpressionField(this).let { it.block().compile(it.algebra) } AsmExpressionField(this).let { it.block().compile(it.algebra) }
inline fun <reified T, A> A.asmField(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Field<T> = inline fun <reified T, A> A.asmField(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Field<T> =

View File

@ -1,5 +1,6 @@
package scientifik.kmath.asm package scientifik.kmath.asm
import scientifik.kmath.asm.internal.AsmGenerationContext
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
@ -12,25 +13,26 @@ import scientifik.kmath.operations.*
* *
* @param T the type the stored function returns. * @param T the type the stored function returns.
*/ */
interface AsmExpression<T> { abstract class AsmNode<T> internal constructor() {
/** /**
* Tries to evaluate this function without its variables. This method is intended for optimization. * Tries to evaluate this function without its variables. This method is intended for optimization.
* *
* @return `null` if the function depends on its variables, the value if the function is a constant. * @return `null` if the function depends on its variables, the value if the function is a constant.
*/ */
fun tryEvaluate(): T? = null internal open fun tryEvaluate(): T? = null
/** /**
* Compiles this declaration. * Compiles this declaration.
* *
* @param gen the target [AsmGenerationContext]. * @param gen the target [AsmGenerationContext].
*/ */
fun compile(gen: AsmGenerationContext<T>) @PublishedApi
internal abstract fun compile(gen: AsmGenerationContext<T>)
} }
internal class AsmUnaryOperation<T>(private val context: Algebra<T>, private val name: String, expr: AsmExpression<T>) : internal class AsmUnaryOperation<T>(private val context: Algebra<T>, private val name: String, expr: AsmNode<T>) :
AsmExpression<T> { AsmNode<T>() {
private val expr: AsmExpression<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: AsmGenerationContext<T>) {
@ -57,11 +59,11 @@ internal class AsmUnaryOperation<T>(private val context: Algebra<T>, private val
internal class AsmBinaryOperation<T>( internal class AsmBinaryOperation<T>(
private val context: Algebra<T>, private val context: Algebra<T>,
private val name: String, private val name: String,
first: AsmExpression<T>, first: AsmNode<T>,
second: AsmExpression<T> second: AsmNode<T>
) : AsmExpression<T> { ) : AsmNode<T>() {
private val first: AsmExpression<T> = first.optimize() private val first: AsmNode<T> = first.optimize()
private val second: AsmExpression<T> = second.optimize() private val second: AsmNode<T> = second.optimize()
override fun tryEvaluate(): T? = context { override fun tryEvaluate(): T? = context {
binaryOperation( binaryOperation(
@ -95,23 +97,22 @@ internal class AsmBinaryOperation<T>(
} }
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) :
AsmExpression<T> { AsmNode<T>() {
override fun compile(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromVariables(name, default) override fun compile(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromVariables(name, default)
} }
internal class AsmConstantExpression<T>(private val value: T) : internal class AsmConstantExpression<T>(private val value: T) :
AsmExpression<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: AsmGenerationContext<T>): Unit = gen.visitLoadFromConstants(value)
} }
internal class AsmConstProductExpression<T>( internal class AsmConstProductExpression<T>(
private val context: Space<T>, private val context: Space<T>,
expr: AsmExpression<T>, expr: AsmNode<T>,
private val const: Number private val const: Number
) : ) : AsmNode<T>() {
AsmExpression<T> { private val expr: AsmNode<T> = expr.optimize()
private val expr: AsmExpression<T> = expr.optimize()
override fun tryEvaluate(): T? = context { (expr.tryEvaluate() ?: return@context null) * const } override fun tryEvaluate(): T? = context { (expr.tryEvaluate() ?: return@context null) * const }
@ -131,7 +132,7 @@ internal class AsmConstProductExpression<T>(
} }
internal class AsmNumberExpression<T>(private val context: NumericAlgebra<T>, private val value: Number) : internal class AsmNumberExpression<T>(private val context: NumericAlgebra<T>, private val value: Number) :
AsmExpression<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: AsmGenerationContext<T>): Unit = gen.visitNumberConstant(value)
@ -145,10 +146,10 @@ internal abstract class FunctionalCompiledExpression<T> internal constructor(
} }
/** /**
* A context class for [AsmExpression] construction. * A context class for [AsmNode] construction.
*/ */
interface AsmExpressionAlgebra<T, A : NumericAlgebra<T>> : NumericAlgebra<AsmExpression<T>>, interface AsmExpressionAlgebra<T, A : NumericAlgebra<T>> : NumericAlgebra<AsmNode<T>>,
ExpressionAlgebra<T, AsmExpression<T>> { ExpressionAlgebra<T, AsmNode<T>> {
/** /**
* The algebra to provide for AsmExpressions built. * The algebra to provide for AsmExpressions built.
*/ */
@ -157,108 +158,108 @@ interface AsmExpressionAlgebra<T, A : NumericAlgebra<T>> : NumericAlgebra<AsmExp
/** /**
* Builds an AsmExpression to wrap a number. * Builds an AsmExpression to wrap a number.
*/ */
override fun number(value: Number): AsmExpression<T> = AsmNumberExpression(algebra, value) override fun number(value: Number): AsmNode<T> = AsmNumberExpression(algebra, value)
/** /**
* Builds an AsmExpression of constant expression which does not depend on arguments. * Builds an AsmExpression of constant expression which does not depend on arguments.
*/ */
override fun const(value: T): AsmExpression<T> = AsmConstantExpression(value) override fun const(value: T): AsmNode<T> = AsmConstantExpression(value)
/** /**
* Builds an AsmExpression to access a variable. * Builds an AsmExpression to access a variable.
*/ */
override fun variable(name: String, default: T?): AsmExpression<T> = AsmVariableExpression(name, default) override fun variable(name: String, default: T?): AsmNode<T> = AsmVariableExpression(name, default)
/** /**
* Builds an AsmExpression of dynamic call of binary operation [operation] on [left] and [right]. * Builds an AsmExpression of dynamic call of binary operation [operation] on [left] and [right].
*/ */
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> = override fun binaryOperation(operation: String, left: AsmNode<T>, right: AsmNode<T>): AsmNode<T> =
AsmBinaryOperation(algebra, operation, left, right) AsmBinaryOperation(algebra, operation, left, right)
/** /**
* Builds an AsmExpression of dynamic call of unary operation with name [operation] on [arg]. * Builds an AsmExpression of dynamic call of unary operation with name [operation] on [arg].
*/ */
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> = override fun unaryOperation(operation: String, arg: AsmNode<T>): AsmNode<T> =
AsmUnaryOperation(algebra, operation, arg) AsmUnaryOperation(algebra, operation, arg)
} }
/** /**
* A context class for [AsmExpression] construction for [Space] algebras. * A context class for [AsmNode] construction for [Space] algebras.
*/ */
open class AsmExpressionSpace<T, A>(override val algebra: A) : AsmExpressionAlgebra<T, A>, open class AsmExpressionSpace<T, A>(override val algebra: A) : AsmExpressionAlgebra<T, A>,
Space<AsmExpression<T>> where A : Space<T>, A : NumericAlgebra<T> { Space<AsmNode<T>> where A : Space<T>, A : NumericAlgebra<T> {
override val zero: AsmExpression<T> override val zero: AsmNode<T>
get() = const(algebra.zero) get() = const(algebra.zero)
/** /**
* Builds an AsmExpression of addition of two another expressions. * Builds an AsmExpression of addition of two another expressions.
*/ */
override fun add(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> = override fun add(a: AsmNode<T>, b: AsmNode<T>): AsmNode<T> =
AsmBinaryOperation(algebra, SpaceOperations.PLUS_OPERATION, a, b) AsmBinaryOperation(algebra, SpaceOperations.PLUS_OPERATION, a, b)
/** /**
* Builds an AsmExpression of multiplication of expression by number. * Builds an AsmExpression of multiplication of expression by number.
*/ */
override fun multiply(a: AsmExpression<T>, k: Number): AsmExpression<T> = AsmConstProductExpression(algebra, a, k) override fun multiply(a: AsmNode<T>, k: Number): AsmNode<T> = AsmConstProductExpression(algebra, a, k)
operator fun AsmExpression<T>.plus(arg: T): AsmExpression<T> = this + const(arg) operator fun AsmNode<T>.plus(arg: T): AsmNode<T> = this + const(arg)
operator fun AsmExpression<T>.minus(arg: T): AsmExpression<T> = this - const(arg) operator fun AsmNode<T>.minus(arg: T): AsmNode<T> = this - const(arg)
operator fun T.plus(arg: AsmExpression<T>): AsmExpression<T> = arg + this operator fun T.plus(arg: AsmNode<T>): AsmNode<T> = arg + this
operator fun T.minus(arg: AsmExpression<T>): AsmExpression<T> = arg - this operator fun T.minus(arg: AsmNode<T>): AsmNode<T> = arg - this
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> = override fun unaryOperation(operation: String, arg: AsmNode<T>): AsmNode<T> =
super<AsmExpressionAlgebra>.unaryOperation(operation, arg) super<AsmExpressionAlgebra>.unaryOperation(operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> = override fun binaryOperation(operation: String, left: AsmNode<T>, right: AsmNode<T>): AsmNode<T> =
super<AsmExpressionAlgebra>.binaryOperation(operation, left, right) super<AsmExpressionAlgebra>.binaryOperation(operation, left, right)
} }
/** /**
* A context class for [AsmExpression] construction for [Ring] algebras. * A context class for [AsmNode] construction for [Ring] algebras.
*/ */
open class AsmExpressionRing<T, A>(override val algebra: A) : AsmExpressionSpace<T, A>(algebra), open class AsmExpressionRing<T, A>(override val algebra: A) : AsmExpressionSpace<T, A>(algebra),
Ring<AsmExpression<T>> where A : Ring<T>, A : NumericAlgebra<T> { Ring<AsmNode<T>> where A : Ring<T>, A : NumericAlgebra<T> {
override val one: AsmExpression<T> override val one: AsmNode<T>
get() = const(algebra.one) get() = const(algebra.one)
/** /**
* Builds an AsmExpression of multiplication of two expressions. * Builds an AsmExpression of multiplication of two expressions.
*/ */
override fun multiply(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> = override fun multiply(a: AsmNode<T>, b: AsmNode<T>): AsmNode<T> =
AsmBinaryOperation(algebra, RingOperations.TIMES_OPERATION, a, b) AsmBinaryOperation(algebra, RingOperations.TIMES_OPERATION, a, b)
operator fun AsmExpression<T>.times(arg: T): AsmExpression<T> = this * const(arg) operator fun AsmNode<T>.times(arg: T): AsmNode<T> = this * const(arg)
operator fun T.times(arg: AsmExpression<T>): AsmExpression<T> = arg * this operator fun T.times(arg: AsmNode<T>): AsmNode<T> = arg * this
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> = override fun unaryOperation(operation: String, arg: AsmNode<T>): AsmNode<T> =
super<AsmExpressionSpace>.unaryOperation(operation, arg) super<AsmExpressionSpace>.unaryOperation(operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> = override fun binaryOperation(operation: String, left: AsmNode<T>, right: AsmNode<T>): AsmNode<T> =
super<AsmExpressionSpace>.binaryOperation(operation, left, right) super<AsmExpressionSpace>.binaryOperation(operation, left, right)
override fun number(value: Number): AsmExpression<T> = super<AsmExpressionSpace>.number(value) override fun number(value: Number): AsmNode<T> = super<AsmExpressionSpace>.number(value)
} }
/** /**
* A context class for [AsmExpression] construction for [Field] algebras. * A context class for [AsmNode] construction for [Field] algebras.
*/ */
open class AsmExpressionField<T, A>(override val algebra: A) : open class AsmExpressionField<T, A>(override val algebra: A) :
AsmExpressionRing<T, A>(algebra), AsmExpressionRing<T, A>(algebra),
Field<AsmExpression<T>> where A : Field<T>, A : NumericAlgebra<T> { Field<AsmNode<T>> where A : Field<T>, A : NumericAlgebra<T> {
/** /**
* Builds an AsmExpression of division an expression by another one. * Builds an AsmExpression of division an expression by another one.
*/ */
override fun divide(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> = override fun divide(a: AsmNode<T>, b: AsmNode<T>): AsmNode<T> =
AsmBinaryOperation(algebra, FieldOperations.DIV_OPERATION, a, b) AsmBinaryOperation(algebra, FieldOperations.DIV_OPERATION, a, b)
operator fun AsmExpression<T>.div(arg: T): AsmExpression<T> = this / const(arg) operator fun AsmNode<T>.div(arg: T): AsmNode<T> = this / const(arg)
operator fun T.div(arg: AsmExpression<T>): AsmExpression<T> = arg / this operator fun T.div(arg: AsmNode<T>): AsmNode<T> = arg / this
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> = override fun unaryOperation(operation: String, arg: AsmNode<T>): AsmNode<T> =
super<AsmExpressionRing>.unaryOperation(operation, arg) super<AsmExpressionRing>.unaryOperation(operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> = override fun binaryOperation(operation: String, left: AsmNode<T>, right: AsmNode<T>): AsmNode<T> =
super<AsmExpressionRing>.binaryOperation(operation, left, right) super<AsmExpressionRing>.binaryOperation(operation, left, right)
override fun number(value: Number): AsmExpression<T> = super<AsmExpressionRing>.number(value) override fun number(value: Number): AsmNode<T> = super<AsmExpressionRing>.number(value)
} }

View File

@ -1,17 +1,15 @@
package scientifik.kmath.asm package scientifik.kmath.asm.internal
import org.objectweb.asm.ClassWriter import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Label import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import scientifik.kmath.asm.AsmGenerationContext.ClassLoader import scientifik.kmath.asm.FunctionalCompiledExpression
import scientifik.kmath.asm.internal.visitLdcOrDConstInsn import scientifik.kmath.asm.internal.AsmGenerationContext.ClassLoader
import scientifik.kmath.asm.internal.visitLdcOrFConstInsn
import scientifik.kmath.asm.internal.visitLdcOrIConstInsn
import scientifik.kmath.operations.Algebra import scientifik.kmath.operations.Algebra
/** /**
* AsmGenerationContext is a structure that abstracts building a class that unwraps [AsmExpression] to plain Java * 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 * expression. This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new
* class. * class.
* *
@ -19,7 +17,8 @@ import scientifik.kmath.operations.Algebra
* @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.
*/ */
class AsmGenerationContext<T> @PublishedApi internal constructor( @PublishedApi
internal class AsmGenerationContext<T> @PublishedApi internal constructor(
private val classOfT: Class<*>, private val classOfT: Class<*>,
private val algebra: Algebra<T>, private val algebra: Algebra<T>,
private val className: String private val className: String

View File

@ -2,8 +2,7 @@ package scientifik.kmath.asm.internal
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import scientifik.kmath.asm.AsmConstantExpression import scientifik.kmath.asm.AsmConstantExpression
import scientifik.kmath.asm.AsmExpression import scientifik.kmath.asm.AsmNode
import scientifik.kmath.asm.AsmGenerationContext
import scientifik.kmath.operations.Algebra import scientifik.kmath.operations.Algebra
private val methodNameAdapters: Map<String, String> = mapOf("+" to "add", "*" to "multiply", "/" to "divide") private val methodNameAdapters: Map<String, String> = mapOf("+" to "add", "*" to "multiply", "/" to "divide")
@ -44,7 +43,7 @@ internal fun <T> AsmGenerationContext<T>.tryInvokeSpecific(context: Algebra<T>,
} }
@PublishedApi @PublishedApi
internal fun <T> AsmExpression<T>.optimize(): AsmExpression<T> { internal fun <T> AsmNode<T>.optimize(): AsmNode<T> {
val a = tryEvaluate() val a = tryEvaluate()
return if (a == null) this else AsmConstantExpression(a) return if (a == null) this else AsmConstantExpression(a)
} }