diff --git a/core/src/fr/hammons/slinc/Fn.scala b/core/src/fr/hammons/slinc/Fn.scala index 7e86bf31..39d7a832 100644 --- a/core/src/fr/hammons/slinc/Fn.scala +++ b/core/src/fr/hammons/slinc/Fn.scala @@ -5,6 +5,8 @@ import scala.quoted.* import scala.util.TupledFunction import scala.annotation.experimental import scala.util.chaining.* +import fr.hammons.slinc.modules.TransitionModule +import java.lang.invoke.TypeDescriptor trait Fn[F, Inputs <: Tuple, Output]: type Function = F @@ -26,12 +28,15 @@ object Fn: toNativeCompatibleImpl('a) } - def toNativeCompatibleImpl[A](a: Expr[A])(using Quotes, Type[A]) = + def toNativeCompatibleImpl[A](a: Expr[A])(using Quotes, Type[A]): Expr[A] = import quotes.reflect.* val typeArgs = TypeRepr.of[A].typeArgs val inputTypes = typeArgs.init val outputType = typeArgs.last val names = LazyList.continually("zzzzz") + val tm = Expr + .summon[TransitionModule] + .getOrElse(report.errorAndAbort(s"Need transition module!")) val select = Select(a.asTerm, TypeRepr.of[A].typeSymbol.declaredMethod("apply").head) val lambda = Lambda( @@ -45,19 +50,45 @@ object Fn: .map(_.asExpr) .zip(inputTypes.map(_.asType)) .map { case (p, '[a]) => - NativeOutCompatible.handleOutput[a](p).asTerm + val desc = Expr + .summon[DescriptorOf[a]] + .getOrElse( + report.errorAndAbort( + s"Could not find descriptor for ${Type.show[a]}" + ) + ) + '{ + $tm.functionArgument[a]($desc.descriptor, $p.asInstanceOf[Object]) + }.asTerm } .pipe { terms => outputType.asType match + case '[Unit] => + '{ + ${ Expr.betaReduce(Apply(select, terms).asExpr) } + () + }.asTerm.changeOwner(meth) case '[r] => - NativeInCompatible - .handleInput( - Expr.betaReduce(Apply(select, terms).asExprOf[r]) + val desc = Expr + .summon[DescriptorOf[r]] + .getOrElse( + report.errorAndAbort( + s"Couldn't find descriptor for ${Type.show[r]}" + ) ) - .asTerm - .changeOwner(meth) + '{ + $tm + .functionReturn[r]( + $desc.descriptor, + ${ Expr.betaReduce(Apply(select, terms).asExprOf[r]) }, + null.asInstanceOf[Allocator] + ) + .asInstanceOf[r] + }.asTerm.changeOwner(meth) } - ).asExpr + ).asExprOf[A] + + report.info(lambda.show) Expr.betaReduce(lambda) diff --git a/core/src/fr/hammons/slinc/InAllocatingTransitionNeeded.scala b/core/src/fr/hammons/slinc/InAllocatingTransitionNeeded.scala deleted file mode 100644 index 96d05918..00000000 --- a/core/src/fr/hammons/slinc/InAllocatingTransitionNeeded.scala +++ /dev/null @@ -1,4 +0,0 @@ -package fr.hammons.slinc - -trait InAllocatingTransitionNeeded[A] extends NativeInCompatible[A]: - def in(a: A)(using Allocator): Object diff --git a/core/src/fr/hammons/slinc/InTransitionNeeded.scala b/core/src/fr/hammons/slinc/InTransitionNeeded.scala deleted file mode 100644 index cd0a373d..00000000 --- a/core/src/fr/hammons/slinc/InTransitionNeeded.scala +++ /dev/null @@ -1,4 +0,0 @@ -package fr.hammons.slinc - -trait InTransitionNeeded[A] extends NativeInCompatible[A]: - def in(a: A): Object diff --git a/core/src/fr/hammons/slinc/LibraryI.scala b/core/src/fr/hammons/slinc/LibraryI.scala index 97ad0a20..9906407d 100644 --- a/core/src/fr/hammons/slinc/LibraryI.scala +++ b/core/src/fr/hammons/slinc/LibraryI.scala @@ -2,8 +2,8 @@ package fr.hammons.slinc import scala.quoted.* import java.lang.invoke.MethodHandle -import NativeInCompatible.PossiblyNeedsAllocator import scala.annotation.nowarn +import fr.hammons.slinc.modules.TransitionModule class LibraryI(platformSpecific: LibraryI.PlatformSpecific): trait Library[+L]: @@ -58,7 +58,7 @@ object LibraryI: () case '[a] => Expr - .summon[NativeInCompatible[a]] + .summon[MethodCompatible[a]] .map(_ => ()) .getOrElse( report.errorAndAbort( @@ -73,7 +73,7 @@ object LibraryI: case '[Unit] => () case '[a] => Expr - .summon[NativeOutCompatible[a]] + .summon[MethodCompatible[a]] .map(_ => ()) .getOrElse( report.errorAndAbort( @@ -98,19 +98,10 @@ object LibraryI: getReturnType(s).asType match case '[r & Product] => - Expr.summon[InAllocatingTransitionNeeded[r & Product]].isDefined + true case _ => false - def makeAllTakeAlloc( - exprs: List[PossiblyNeedsAllocator] - )(using Quotes): List[Expr[Allocator => Any]] = - exprs.map { exp => - if exp.isExprOf[Allocator => Any] then exp.asExprOf[Allocator => Any] - else '{ (_: Allocator) => $exp } - } - - def bindingImpl[R, L[_] <: LibraryI#Library[?]](using - Quotes, + def bindingImpl[R, L[_] <: LibraryI#Library[?]](using q: Quotes)(using Type[R], Type[L] ) = @@ -133,12 +124,13 @@ object LibraryI: val address = '{ $library.addresses($methodPositionExpr) } checkMethodIsCompatible(methodSymbol) - val prefix: List[PossiblyNeedsAllocator] = + val transitionModule = Expr + .summon[TransitionModule] + .getOrElse(report.errorAndAbort("Need transition module!!")) + val prefix: List[Expr[Allocator => Any]] = if needsAllocator(methodSymbol) then - val summonAlloc = - Expr.summon[InTransitionNeeded[Allocator]].getOrElse(???) List( - '{ (a: Allocator) => $summonAlloc.in(a) } + '{ (a: Allocator) => $transitionModule.methodArgument(a) } ) else Nil @@ -147,49 +139,70 @@ object LibraryI: .getInputsAndOutputType(methodSymbol) ._1 - val mappedInputs = inputs - .map(NativeInCompatible.handleInput) - .filter(!_.isExprOf[Seq[Variadic]]) - - val allocationlessInputs = - mappedInputs.filter(!_.isExprOf[Allocator => Object]).map(_.asExprOf[Any]) + val standardInputs: List[Expr[Allocator => Any]] = + prefix ++ MacroHelpers + .getInputsAndOutputType(methodSymbol) + ._1 + .filter(!_.isExprOf[Seq[Variadic]]) + .map { case '{ $e: t } => + TypeRepr.of[t].widen.asType match + case '[widened] => + e -> Expr + .summon[DescriptorOf[widened]] + .getOrElse( + report.errorAndAbort( + s"No descriptor found for ${Type.show[widened]}" + ) + ) + } + .map { case (expr, desc) => + '{ (alloc: Allocator) => + $transitionModule.methodArgument($desc.descriptor, $expr, alloc) + } + } - val allocInputs = makeAllTakeAlloc(mappedInputs) + val rTransition: Expr[Object | Null => R] = Type.of[R] match + case '[Unit] => + '{ (obj: Object | Null) => () }.asExprOf[Object | Null => R] + case '[r] => + Expr + .summon[DescriptorOf[R]] + .map(e => + '{ (obj: Object | Null) => + $transitionModule.methodReturn[R]($e.descriptor, obj.nn) + } + ) + .getOrElse( + report.errorAndAbort( + s"No descriptor found for return type ${Type.show[R]}" + ) + ) val code: Expr[R] = - if inputs.size == mappedInputs.size then - if allocationlessInputs == mappedInputs && !needsAllocator(methodSymbol) - then - val invokation = - MethodHandleTools.invokeArguments[R]( - methodHandle, - allocationlessInputs - ) - NativeOutCompatible.handleOutput[R](invokation).asExprOf[R] - else - val methodInvoke = - '{ (a: Allocator) => - ${ - MethodHandleTools.invokeArguments[R]( - methodHandle, - allocInputs.map(exp => '{ $exp(a) }).map(Expr.betaReduce) - ) - } + if inputs.size == standardInputs.size then + val methodInvoke = + '{ (a: Allocator) => + ${ + MethodHandleTools.invokeArguments[R]( + methodHandle, + standardInputs.map(exp => '{ $exp(a) }).map(Expr.betaReduce) + ) } - - val scopeThing = Expr - .summon[TempScope] - .getOrElse(report.errorAndAbort("need temp allocator in scope")) - val subCode = '{ - Scope.temp(using $scopeThing)((a: Allocator) ?=> - ${ - NativeOutCompatible.handleOutput[R](Expr.betaReduce('{ - $methodInvoke(a) - })) - } - ) } - subCode + + val scopeThing = Expr + .summon[TempScope] + .getOrElse(report.errorAndAbort("need temp allocator in scope")) + + Expr + .summon[DescriptorOf[R]] + .map(e => '{ $transitionModule.methodReturn[R]($e.descriptor, _) }) + val subCode = '{ + Scope.temp(using $scopeThing)((a: Allocator) ?=> + $rTransition($methodInvoke(a)) + ) + } + subCode else val varargs = inputs.last.asExprOf[Seq[Variadic]] val scopeThing = Expr @@ -198,32 +211,32 @@ object LibraryI: '{ Scope.temp(using $scopeThing)((a: Allocator) ?=> ${ - val normalInputs = Expr.ofSeq(allocInputs.map(e => '{ $e(a) })) + val normalInputs = Expr.ofSeq(standardInputs.map(e => '{ $e(a) })) val totalInputs = '{ - $normalInputs ++ MethodHandleTools.getVariadicExprs($varargs) + $normalInputs ++ MethodHandleTools.getVariadicExprs($varargs)( + using $transitionModule + ) } - NativeOutCompatible.handleOutput[R]( - MethodHandleTools.invokeVariadicArguments( - methodHandleGen, - totalInputs, - '{ MethodHandleTools.getVariadicContext($varargs) } + + '{ + $rTransition( + ${ + MethodHandleTools.invokeVariadicArguments( + methodHandleGen, + totalInputs, + '{ MethodHandleTools.getVariadicContext($varargs) } + ) + } ) - ) + } } ) } report.info( - s"""|Binding doesn't need allocator: ${allocationlessInputs == mappedInputs && !needsAllocator( - methodSymbol - )} - |Binding has return that requires allocator: ${needsAllocator( + s"""|Binding has return that requires allocator: ${needsAllocator( methodSymbol )} - |Binding has inputs that require allocation: ${allocationlessInputs != mappedInputs} - |Allocationless inputs: ${allocationlessInputs.map( - _.asTerm.show(using Printer.TreeShortCode) - )} - |Mapped inputs: ${mappedInputs.map( + |Mapped inputs: ${standardInputs.map( _.asTerm.show(using Printer.TreeShortCode) )} |Generated code: ${code.asTerm.show(using diff --git a/core/src/fr/hammons/slinc/MethodCompatible.scala b/core/src/fr/hammons/slinc/MethodCompatible.scala new file mode 100644 index 00000000..ed5707b4 --- /dev/null +++ b/core/src/fr/hammons/slinc/MethodCompatible.scala @@ -0,0 +1,16 @@ +package fr.hammons.slinc + +trait MethodCompatible[A] + +object MethodCompatible: + given MethodCompatible[Byte] with {} + given MethodCompatible[Short] with {} + given MethodCompatible[Int] with {} + given MethodCompatible[Long] with {} + + given MethodCompatible[Float] with {} + given MethodCompatible[Double] with {} + + private val mthdCompatPtr = new MethodCompatible[Ptr[?]] {} + given [A]: MethodCompatible[Ptr[A]] = + mthdCompatPtr.asInstanceOf[MethodCompatible[Ptr[A]]] diff --git a/core/src/fr/hammons/slinc/MethodHandleTools.scala b/core/src/fr/hammons/slinc/MethodHandleTools.scala index 33f343d0..808cc66f 100644 --- a/core/src/fr/hammons/slinc/MethodHandleTools.scala +++ b/core/src/fr/hammons/slinc/MethodHandleTools.scala @@ -4,6 +4,7 @@ import scala.quoted.* import java.lang.invoke.MethodHandle import scala.compiletime.asMatchable import fr.hammons.slinc.modules.DescriptorModule +import fr.hammons.slinc.modules.TransitionModule object MethodHandleTools: def exprNameMapping(expr: Expr[Any])(using Quotes): String = @@ -47,7 +48,7 @@ object MethodHandleTools: )(using Quotes, Type[R] - ) = + ): Expr[Object | Null] = import quotes.reflect.* val arity = exprs.size @@ -65,28 +66,15 @@ object MethodHandleTools: .getOrElse(report.errorAndAbort("This class should exist!!")) .companionModule - val methodSymbol = mod.flatMap( - _.declaredMethods - .find(_.name == callName) - ) - val backupSymbol = backupMod.declaredMethods.find(_.name.endsWith(arity.toString())) - methodSymbol + backupSymbol .map(ms => Apply( - Select(Ident(mod.get.termRef), ms), + Select(Ident(backupMod.termRef), ms), mh.asTerm :: exprs.map(_.asTerm).toList - ).asExpr - ) - .orElse( - backupSymbol.map(ms => - Apply( - Select(Ident(backupMod.termRef), ms), - mh.asTerm :: exprs.map(_.asTerm).toList - ).asExpr - ) + ).asExprOf[Object | Null] ) .getOrElse( '{ MethodHandleFacade.callVariadic($mh, ${ Varargs(exprs) }*) } @@ -95,18 +83,13 @@ object MethodHandleTools: inline def getVariadicContext(s: Seq[Variadic]) = s.map(_.use[DescriptorOf](l ?=> _ => l.descriptor)) - inline def getVariadicExprs(s: Seq[Variadic]) = (alloc: Allocator) ?=> - s.map( - _.use[NativeInCompatible](nic ?=> - d => - nic match - case i: InAllocatingTransitionNeeded[?] => i.in(d) - case i: InTransitionNeeded[?] => i.in(d) - case i: NativeInCompatible[?] => - val res = d.asInstanceOf[Any] - res + def getVariadicExprs(s: Seq[Variadic])(using tm: TransitionModule) = + (alloc: Allocator) ?=> + s.map( + _.use[DescriptorOf](dc ?=> + d => tm.methodArgument(dc.descriptor, d, alloc) + ) ) - ) def calculateMethodHandleImplementation[L]( platformExpr: Expr[LibraryI.PlatformSpecific], @@ -200,9 +183,15 @@ object MethodHandleTools: (meth, params) => retType.asType match case '[r] => - invokeArguments[r]( + val invokeExpr = invokeArguments[r]( methodHandleExpr, params.map(_.asExpr) - ).asTerm + ) + val invokeResultExpr = '{ + val invokeResult = $invokeExpr + if invokeResult == null then ().asInstanceOf[r] + else invokeResult.asInstanceOf[r] + } + invokeResultExpr.asTerm .changeOwner(meth) ).asExprOf[A] diff --git a/core/src/fr/hammons/slinc/NativeInCompatible.scala b/core/src/fr/hammons/slinc/NativeInCompatible.scala deleted file mode 100644 index 7c7780ac..00000000 --- a/core/src/fr/hammons/slinc/NativeInCompatible.scala +++ /dev/null @@ -1,40 +0,0 @@ -package fr.hammons.slinc - -import scala.quoted.* -import container.{ContextProof, *:::, End} - -trait NativeInCompatible[A] - -object NativeInCompatible: - given NativeInCompatible[Int] with {} - given NativeInCompatible[Float] with {} - given NativeInCompatible[Long] with {} - given NativeInCompatible[Double] with {} - given NativeInCompatible[Byte] with {} - given NativeInCompatible[Short] with {} - - given [A](using - c: ContextProof[NativeInCompatible *::: End, A] - ): NativeInCompatible[A] = c.tup.head - - type PossiblyNeedsAllocator = (Expr[Allocator => Any]) | Expr[Any] - def handleInput( - expr: Expr[Any] - )(using q: Quotes): (Expr[Allocator => Any]) | Expr[Any] = - import quotes.reflect.* - expr match - case '{ $exp: a } => - Expr - .summon[InAllocatingTransitionNeeded[a]] - .map(f => - ( - '{ (alloc: Allocator) => $f.in($exp)(using alloc) } - ): PossiblyNeedsAllocator - ) - .orElse { - - Expr - .summon[InTransitionNeeded[a]] - .map(f => '{ $f.in($exp) }: PossiblyNeedsAllocator) - } - .getOrElse(expr: PossiblyNeedsAllocator) diff --git a/core/src/fr/hammons/slinc/NativeOutCompatible.scala b/core/src/fr/hammons/slinc/NativeOutCompatible.scala deleted file mode 100644 index 1855e7fb..00000000 --- a/core/src/fr/hammons/slinc/NativeOutCompatible.scala +++ /dev/null @@ -1,37 +0,0 @@ -package fr.hammons.slinc - -import scala.quoted.* -import container.{ContextProof, *:::, End} - -trait NativeOutCompatible[A] - -object NativeOutCompatible: - given NativeOutCompatible[Byte] with {} - given NativeOutCompatible[Short] with {} - given NativeOutCompatible[Int] with {} - given NativeOutCompatible[Long] with {} - given NativeOutCompatible[Char] with {} - given NativeOutCompatible[Float] with {} - given NativeOutCompatible[Double] with {} - - given [A](using - c: ContextProof[NativeOutCompatible *::: End, A] - ): NativeOutCompatible[A] = c.tup.head - - def handleOutput[R]( - expr: Expr[Any | Null] - )(using Quotes, Type[R]): Expr[R] = - Expr - .summon[OutTransitionNeeded[R]] - .map { fn => - val nExpr = - if expr.isExprOf[Object] then expr.asExprOf[Object] - else '{ $expr.asInstanceOf[Object] } - '{ $fn.out($nExpr) } - } - .getOrElse(Type.of[R] match { - case '[Unit] => '{ $expr; () }.asExprOf[R] - case _ => - if expr.isExprOf[R] then expr.asExprOf[R] - else '{ $expr.asInstanceOf[R] } - }) diff --git a/core/src/fr/hammons/slinc/OutTransitionNeeded.scala b/core/src/fr/hammons/slinc/OutTransitionNeeded.scala deleted file mode 100644 index a5805e00..00000000 --- a/core/src/fr/hammons/slinc/OutTransitionNeeded.scala +++ /dev/null @@ -1,4 +0,0 @@ -package fr.hammons.slinc - -trait OutTransitionNeeded[A] extends NativeOutCompatible[A]: - def out(obj: Object): A diff --git a/core/src/fr/hammons/slinc/Ptr.scala b/core/src/fr/hammons/slinc/Ptr.scala index e871b528..4899d0fd 100644 --- a/core/src/fr/hammons/slinc/Ptr.scala +++ b/core/src/fr/hammons/slinc/Ptr.scala @@ -8,15 +8,15 @@ import scala.reflect.ClassTag import fr.hammons.slinc.modules.DescriptorModule class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes): - def `unary_!`(using receive: Receive[A]) = receive.from(mem, offset) + def `unary_!`(using receive: Receive[A]): A = receive.from(mem, offset) def asArray(size: Int)(using ClassTag[A] )(using DescriptorOf[A], DescriptorModule)(using r: ReceiveBulk[A]) = r.from(mem.resize(DescriptorOf[A].size * size), offset, size) def `unary_!_=`(value: A)(using send: Send[A]) = send.to(mem, offset, value) - def apply(bytes: Bytes) = Ptr[A](mem, offset + bytes) - def apply(index: Int)(using DescriptorOf[A], DescriptorModule) = + def apply(bytes: Bytes): Ptr[A] = Ptr[A](mem, offset + bytes) + def apply(index: Int)(using DescriptorOf[A], DescriptorModule): Ptr[A] = Ptr[A](mem, offset + (DescriptorOf[A].size * index)) def castTo[A]: Ptr[A] = this.asInstanceOf[Ptr[A]] @@ -61,7 +61,7 @@ object Ptr: string.getBytes("ASCII").nn :+ 0.toByte ) - inline def upcall[A](inline a: A)(using alloc: Allocator) = + inline def upcall[A](inline a: A)(using alloc: Allocator): Ptr[A] = val nFn = Fn.toNativeCompatible(a) val descriptor = FunctionDescriptor.fromFunction[A] Ptr[A](alloc.upcall(descriptor, nFn), Bytes(0)) diff --git a/core/src/fr/hammons/slinc/Slinc.scala b/core/src/fr/hammons/slinc/Slinc.scala index c975838c..e421f474 100644 --- a/core/src/fr/hammons/slinc/Slinc.scala +++ b/core/src/fr/hammons/slinc/Slinc.scala @@ -8,22 +8,21 @@ import java.util.concurrent.ThreadFactory import scala.util.chaining.* import java.util.concurrent.atomic.AtomicReference import scala.compiletime.uninitialized -import modules.DescriptorModule +import modules.{DescriptorModule, TransitionModule} trait Slinc: protected def jitManager: JitManager protected def scopePlatformSpecific: ScopeI.PlatformSpecific - protected def transitionsPlatformSpecific: TransitionsI.PlatformSpecific protected def libraryIPlatformSpecific: LibraryI.PlatformSpecific given dm: DescriptorModule + given tm: TransitionModule private val useJit = Option(System.getProperty("sffi-jit")) .flatMap(_.nn.toBooleanOption) .getOrElse(true) - protected val transitionsI = TransitionsI(transitionsPlatformSpecific) - protected val structI = StructI(transitionsI, jitManager) + protected val structI = StructI(jitManager) val typesI = types.TypesI.platformTypes protected val scopeI = ScopeI(scopePlatformSpecific) protected val libraryI = LibraryI(libraryIPlatformSpecific) @@ -33,7 +32,6 @@ trait Slinc: export libraryI.* export Convertible.as export PotentiallyConvertible.maybeAs - export transitionsI.given export structI.Struct export scopeI.given export container.ContextProof.given diff --git a/core/src/fr/hammons/slinc/Struct.scala b/core/src/fr/hammons/slinc/Struct.scala index 9b8b26de..57b2b4e0 100644 --- a/core/src/fr/hammons/slinc/Struct.scala +++ b/core/src/fr/hammons/slinc/Struct.scala @@ -10,11 +10,11 @@ import scala.compiletime.{ import java.util.concurrent.atomic.AtomicReference import scala.reflect.ClassTag import modules.DescriptorModule +import fr.hammons.slinc.modules.TransitionModule class StructI( - transitionI: TransitionsI, jitManager: JitManager -)(using DescriptorModule): +)(using DescriptorModule, TransitionModule): /** Summons up Descriptors for the members of Product A * * @tparam A @@ -41,13 +41,11 @@ class StructI( private inline def memberNames[A](using m: Mirror.ProductOf[A]) = constValueTuple[m.MirroredElemLabels].toArray.map(_.toString()) - import transitionI.given trait Struct[A <: Product] extends DescriptorOf[A], Send[A], Receive[A], - InAllocatingTransitionNeeded[A], - OutTransitionNeeded[A] + MethodCompatible[A] object Struct: inline def derived[A <: Product](using @@ -87,11 +85,17 @@ class StructI( final def from(mem: Mem, offset: Bytes): A = receiver.from(mem, offset).asInstanceOf[A] + summon[TransitionModule].registerMethodArgumentTransition[A]( + this.descriptor, + Allocator ?=> in(_) + ) + summon[TransitionModule] + .registerMethodReturnTransition[A](this.descriptor, out) final def in(a: A)(using alloc: Allocator): Object = val mem = alloc.allocate(this.descriptor, 1) to(mem, Bytes(0), a) - transitionI.structMemIn(mem) + summon[TransitionModule].methodArgument(mem).asInstanceOf[Object] final def out(a: Object): A = - val mem = transitionI.structMemOut(a) + val mem = summon[TransitionModule].memReturn(a) from(mem, Bytes(0)) diff --git a/core/src/fr/hammons/slinc/TransitionsI.scala b/core/src/fr/hammons/slinc/TransitionsI.scala deleted file mode 100644 index 8bbf0a60..00000000 --- a/core/src/fr/hammons/slinc/TransitionsI.scala +++ /dev/null @@ -1,29 +0,0 @@ -package fr.hammons.slinc - -class TransitionsI(platformSpecific: TransitionsI.PlatformSpecific): - private val genPtrInTransition = new InTransitionNeeded[Ptr[Any]]: - def in(a: Ptr[Any]) = - platformSpecific.inPointer.in(a.mem.offset(a.offset)) - - private val genPtrOutTransition = new OutTransitionNeeded[Ptr[Any]]: - def out(a: Object): Ptr[Any] = - Ptr[Any](platformSpecific.outPointer.out(a), Bytes(0)) - - given [A]: InTransitionNeeded[Ptr[A]] = - genPtrInTransition.asInstanceOf[InTransitionNeeded[Ptr[A]]] - - given [A]: OutTransitionNeeded[Ptr[A]] = - genPtrOutTransition.asInstanceOf[OutTransitionNeeded[Ptr[A]]] - given InTransitionNeeded[Allocator] = platformSpecific.allocatorIn - - private[slinc] def structMemIn(mem: Mem)(using Allocator) = - platformSpecific.inMem.in(mem) - private[slinc] def structMemOut(o: Object) = platformSpecific.outMem.out(o) - -object TransitionsI: - trait PlatformSpecific: - val inMem: InTransitionNeeded[Mem] - val outMem: OutTransitionNeeded[Mem] - val inPointer: InTransitionNeeded[Mem] - val outPointer: OutTransitionNeeded[Mem] - val allocatorIn: InTransitionNeeded[Allocator] diff --git a/core/src/fr/hammons/slinc/Variadic.scala b/core/src/fr/hammons/slinc/Variadic.scala index bc610a90..a75c22d7 100644 --- a/core/src/fr/hammons/slinc/Variadic.scala +++ b/core/src/fr/hammons/slinc/Variadic.scala @@ -2,4 +2,4 @@ package fr.hammons.slinc import container.* -type Variadic = Container[DescriptorOf *::: NativeInCompatible *::: End] +type Variadic = Container[DescriptorOf *::: MethodCompatible *::: End] diff --git a/core/src/fr/hammons/slinc/modules/TransitionModule.scala b/core/src/fr/hammons/slinc/modules/TransitionModule.scala new file mode 100644 index 00000000..9c931e06 --- /dev/null +++ b/core/src/fr/hammons/slinc/modules/TransitionModule.scala @@ -0,0 +1,71 @@ +package fr.hammons.slinc.modules + +import fr.hammons.slinc.* + +trait TransitionModule: + /** Transitions a method argument to the appropriate format + * + * @param td + * Type Descriptor of the argument + * @param value + * The argument to transition + * @param alloc + * An allocator for allocating memory + * @return + * The transitioned value + */ + def methodArgument[A](td: TypeDescriptor, value: A, alloc: Allocator): Any + + /** Transitions an allocator into an appropriate format + * + * @param a + * An allocator + * @return + * The transitioned value + */ + def methodArgument(a: Allocator): Any + + def methodArgument(m: Mem): Any + + /** Transitions a return value into the Slinc format + * + * @param td + * Type descriptor of the return + * @param value + * The return value + * @return + * A slinc compatible data object + */ + def methodReturn[A](td: TypeDescriptor, value: Object): A + + def memReturn(value: Object): Mem + + /** Registers a method argument transition + * + * @param td + * The type descriptor of the type to transition + * @param fn + * The method that transitions the argument into the right format + */ + def registerMethodArgumentTransition[A]( + td: TypeDescriptor, + fn: Allocator ?=> A => Any + ): Unit + + /** Registers a method return transition + * + * @param td + * The type descriptor of the return transition + * @param fn + * The method that transitions the return into the right format + */ + def registerMethodReturnTransition[A]( + td: TypeDescriptor, + fn: Object => A + ): Unit + + def functionArgument[A](td: TypeDescriptor, value: Object): A = + methodReturn[A](td, value) + + def functionReturn[A](td: TypeDescriptor, value: A, alloc: Allocator): Any = + methodArgument[A](td, value, alloc) diff --git a/core/src/fr/hammons/slinc/types/TypesI.scala b/core/src/fr/hammons/slinc/types/TypesI.scala index 085f269d..7fd386cb 100644 --- a/core/src/fr/hammons/slinc/types/TypesI.scala +++ b/core/src/fr/hammons/slinc/types/TypesI.scala @@ -82,8 +82,7 @@ object TypesI: type <-:[A] = [B] =>> Convertible[A, B] type :?->[A] = [B] =>> PotentiallyConvertible[B, A] type <-?:[A] = [B] =>> PotentiallyConvertible[A, B] - type StandardCapabilities = DescriptorOf *::: NativeInCompatible *::: - NativeOutCompatible *::: Send *::: Receive *::: End + type StandardCapabilities = DescriptorOf *::: Send *::: Receive *::: End trait PlatformSpecific extends HostDependentTypes: val hostDependentTypes: HostDependentTypes & Singleton @@ -95,6 +94,8 @@ object TypesI: CLong ] + given MethodCompatible[CLong] with {} + given cLongProof: CLongProof type SizeTProof = ContextProof[ @@ -104,6 +105,8 @@ object TypesI: ] val sizeTProof: SizeTProof + given MethodCompatible[SizeT] with {} + type TimeTProof = ContextProof[ :?->[Int] *::: <-?:[Int] *::: :?->[Long] *::: <-?:[Long] *::: StandardCapabilities, @@ -111,6 +114,8 @@ object TypesI: ] val timeTProof: TimeTProof + given MethodCompatible[TimeT] with {} + protected[slinc] val platformTypes: TypesI = val platform = (arch, os) match case (Arch.X64, OS.Linux) => types.x64.Linux() diff --git a/j17/src/fr/hammons/slinc/Slinc17.scala b/j17/src/fr/hammons/slinc/Slinc17.scala index 6aaf3faa..259752ff 100644 --- a/j17/src/fr/hammons/slinc/Slinc17.scala +++ b/j17/src/fr/hammons/slinc/Slinc17.scala @@ -2,15 +2,15 @@ package fr.hammons.slinc import jdk.incubator.foreign.CLinker import fr.hammons.slinc.ScopeI.PlatformSpecific -import fr.hammons.slinc.modules.DescriptorModule +import fr.hammons.slinc.modules.{DescriptorModule, TransitionModule} import fr.hammons.slinc.modules.given class Slinc17(_jitManager: JitManager, linker: CLinker)(using - val dm: DescriptorModule + val dm: DescriptorModule, + val tm: TransitionModule ) extends Slinc: protected def jitManager = _jitManager protected def scopePlatformSpecific = Scope17(linker) - protected def transitionsPlatformSpecific = Transitions17 protected def libraryIPlatformSpecific = Library17(linker) @SlincImpl(17) diff --git a/j17/src/fr/hammons/slinc/Transitions17.scala b/j17/src/fr/hammons/slinc/Transitions17.scala deleted file mode 100644 index 4b43097b..00000000 --- a/j17/src/fr/hammons/slinc/Transitions17.scala +++ /dev/null @@ -1,29 +0,0 @@ -package fr.hammons.slinc - -import jdk.incubator.foreign.{MemorySegment, MemoryAddress, ResourceScope} - -object Transitions17 extends TransitionsI.PlatformSpecific: - - def outStruct(obj: Object, size: Bytes): Mem = Mem17( - obj.asInstanceOf[MemorySegment] - ) - val inMem: InTransitionNeeded[Mem] = new InTransitionNeeded[Mem]: - def in(a: Mem): Object = a.asBase - - val outMem: OutTransitionNeeded[Mem] = new OutTransitionNeeded[Mem]: - def out(obj: Object): Mem = Mem17(obj.asInstanceOf[MemorySegment]) - - val inPointer: InTransitionNeeded[Mem] = new InTransitionNeeded[Mem]: - def in(a: Mem): Object = a.asBase.asInstanceOf[MemorySegment].address().nn - - val outPointer: OutTransitionNeeded[Mem] = new OutTransitionNeeded[Mem]: - import scala.language.unsafeNulls - def out(obj: Object): Mem = Mem17( - MemorySegment - .globalNativeSegment() - .asSlice(obj.asInstanceOf[MemoryAddress]) - ) - - val allocatorIn: InTransitionNeeded[Allocator] = - new InTransitionNeeded[Allocator]: - def in(a: Allocator): Object = a.base diff --git a/j17/src/fr/hammons/slinc/modules/TransitionModule17.scala b/j17/src/fr/hammons/slinc/modules/TransitionModule17.scala new file mode 100644 index 00000000..c7f08314 --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/TransitionModule17.scala @@ -0,0 +1,67 @@ +package fr.hammons.slinc.modules + +import fr.hammons.slinc.TypeDescriptor + +import scala.collection.concurrent.TrieMap +import fr.hammons.slinc.* + +import jdk.incubator.foreign.{MemoryAddress, ResourceScope, MemorySegment} + +given transitionModule17: TransitionModule with + + override def memReturn(value: Object): Mem = Mem17( + value.asInstanceOf[MemorySegment] + ) + + override def methodArgument(m: Mem): Any = m.asBase + + private val maTransition: TrieMap[TypeDescriptor, Allocator ?=> ? => Any] = + TrieMap( + ByteDescriptor -> ((_: Allocator) ?=> (b: Byte) => b), + ShortDescriptor -> ((_: Allocator) ?=> (s: Short) => s), + IntDescriptor -> ((_: Allocator) ?=> (i: Int) => i), + LongDescriptor -> ((_: Allocator) ?=> (l: Long) => l), + FloatDescriptor -> ((_: Allocator) ?=> (f: Float) => f), + DoubleDescriptor -> ((_: Allocator) ?=> (d: Double) => d), + PtrDescriptor -> ((_: Allocator) ?=> (p: Ptr[?]) => p.mem.asAddress) + ) + private val mrTransition: TrieMap[TypeDescriptor, Object => ?] = TrieMap( + ByteDescriptor -> ((b: Object) => b.asInstanceOf[Byte]), + ShortDescriptor -> ((s: Object) => s.asInstanceOf[Short]), + IntDescriptor -> ((i: Object) => i.asInstanceOf[Int]), + LongDescriptor -> ((l: Object) => l.asInstanceOf[Long]), + FloatDescriptor -> ((f: Object) => f.asInstanceOf[Float]), + DoubleDescriptor -> ((d: Object) => d.asInstanceOf[Double]), + PtrDescriptor -> ((p: Object) => + Ptr[Any]( + Mem17( + MemorySegment + .globalNativeSegment() + .nn + .asSlice(p.asInstanceOf[MemoryAddress]) + .nn + ), + Bytes(0) + ) + ) + ) + override def methodArgument(a: Allocator): Any = a.base + + override def methodArgument[A]( + td: TypeDescriptor, + value: A, + alloc: Allocator + ): Any = maTransition(td)(using alloc).asInstanceOf[A => Any](value) + + override def methodReturn[A](td: TypeDescriptor, value: Object): A = + mrTransition(td).asInstanceOf[Object => A](value) + + override def registerMethodArgumentTransition[A]( + td: TypeDescriptor, + fn: (Allocator) ?=> A => Any + ): Unit = maTransition.addOne(td -> fn) + + override def registerMethodReturnTransition[A]( + td: TypeDescriptor, + fn: Object => A + ): Unit = mrTransition.addOne(td -> fn) diff --git a/j19/src/fr/hammons/slinc/Slinc19.scala b/j19/src/fr/hammons/slinc/Slinc19.scala index bffdb2e6..23163070 100644 --- a/j19/src/fr/hammons/slinc/Slinc19.scala +++ b/j19/src/fr/hammons/slinc/Slinc19.scala @@ -4,16 +4,14 @@ import java.lang.foreign.Linker import fr.hammons.slinc.modules.{*, given} class Slinc19(_jitManager: JitManager, linker: Linker)(using - val dm: DescriptorModule + val dm: DescriptorModule, + val tm: TransitionModule ) extends Slinc: protected def jitManager: JitManager = _jitManager protected def scopePlatformSpecific: ScopeI.PlatformSpecific = Scope19(linker) - protected def transitionsPlatformSpecific: TransitionsI.PlatformSpecific = - Transitions19 - protected def libraryIPlatformSpecific: LibraryI.PlatformSpecific = Library19(linker) diff --git a/j19/src/fr/hammons/slinc/Transitions19.scala b/j19/src/fr/hammons/slinc/Transitions19.scala deleted file mode 100644 index 61acc2cc..00000000 --- a/j19/src/fr/hammons/slinc/Transitions19.scala +++ /dev/null @@ -1,29 +0,0 @@ -package fr.hammons.slinc - -import java.lang.foreign.MemorySegment -import java.lang.foreign.MemorySession -import java.lang.foreign.MemoryAddress - -object Transitions19 extends TransitionsI.PlatformSpecific: - val inMem: InTransitionNeeded[Mem] = new InTransitionNeeded[Mem]: - def in(a: Mem): Object = a.asBase - - val outMem: OutTransitionNeeded[Mem] = new OutTransitionNeeded[Mem]: - def out(obj: Object): Mem = Mem19(obj.asInstanceOf[MemorySegment]) - - val inPointer: InTransitionNeeded[Mem] = new InTransitionNeeded[Mem]: - def in(a: Mem): Object = a.asBase.asInstanceOf[MemorySegment].address().nn - - val outPointer: OutTransitionNeeded[Mem] = new OutTransitionNeeded[Mem]: - import scala.language.unsafeNulls - def out(obj: Object): Mem = Mem19( - MemorySegment.ofAddress( - obj.asInstanceOf[MemoryAddress], - Int.MaxValue, - MemorySession.global() - ) - ) - - val allocatorIn: InTransitionNeeded[Allocator] = - new InTransitionNeeded[Allocator]: - def in(a: Allocator): Object = a.base diff --git a/j19/src/fr/hammons/slinc/modules/TransitionModule19.scala b/j19/src/fr/hammons/slinc/modules/TransitionModule19.scala new file mode 100644 index 00000000..69a9cd0b --- /dev/null +++ b/j19/src/fr/hammons/slinc/modules/TransitionModule19.scala @@ -0,0 +1,69 @@ +package fr.hammons.slinc.modules + +import fr.hammons.slinc.* +import scala.collection.concurrent.TrieMap +import java.lang.foreign.MemorySegment +import java.lang.foreign.MemorySession +import java.lang.foreign.MemoryAddress + +given transitionModule19: TransitionModule with + private val maTransition: TrieMap[TypeDescriptor, Allocator ?=> ? => Any] = + TrieMap( + ByteDescriptor -> (_ ?=> (b: Byte) => b), + ShortDescriptor -> (_ ?=> (s: Short) => s), + IntDescriptor -> (_ ?=> (i: Int) => i), + LongDescriptor -> (_ ?=> (l: Long) => l), + FloatDescriptor -> (_ ?=> (f: Float) => f), + DoubleDescriptor -> (_ ?=> (d: Double) => d), + PtrDescriptor -> (_ ?=> (p: Ptr[?]) => p.mem.asAddress) + ) + + private val mrTransition: TrieMap[TypeDescriptor, Object => ?] = TrieMap( + ByteDescriptor -> (_.asInstanceOf[Byte]), + ShortDescriptor -> (_.asInstanceOf[Short]), + IntDescriptor -> (_.asInstanceOf[Int]), + LongDescriptor -> (_.asInstanceOf[Long]), + FloatDescriptor -> (_.asInstanceOf[Float]), + DoubleDescriptor -> (_.asInstanceOf[Double]), + PtrDescriptor -> (p => + Ptr[Any]( + Mem19( + MemorySegment + .ofAddress( + p.asInstanceOf[MemoryAddress], + Int.MaxValue, + MemorySession.global() + ) + .nn + ), + Bytes(0) + ) + ) + ) + + override def methodArgument(a: Allocator): Any = a.base + + override def methodArgument[A]( + td: TypeDescriptor, + value: A, + alloc: Allocator + ): Any = maTransition(td)(using alloc).asInstanceOf[A => Any](value) + + def methodArgument(m: Mem): Any = m.asBase + + override def methodReturn[A](td: TypeDescriptor, value: Object): A = + mrTransition(td).asInstanceOf[Object => A](value) + + override def registerMethodArgumentTransition[A]( + td: TypeDescriptor, + fn: (Allocator) ?=> A => Any + ): Unit = maTransition.addOne(td, fn) + + override def registerMethodReturnTransition[A]( + td: TypeDescriptor, + fn: Object => A + ): Unit = mrTransition.addOne(td, fn) + + override def memReturn(value: Object): Mem = Mem19( + value.asInstanceOf[MemorySegment] + )