Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions core/src/fr/hammons/slinc/Fn.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -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)

Expand Down
4 changes: 0 additions & 4 deletions core/src/fr/hammons/slinc/InAllocatingTransitionNeeded.scala

This file was deleted.

4 changes: 0 additions & 4 deletions core/src/fr/hammons/slinc/InTransitionNeeded.scala

This file was deleted.

159 changes: 86 additions & 73 deletions core/src/fr/hammons/slinc/LibraryI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down Expand Up @@ -58,7 +58,7 @@ object LibraryI:
()
case '[a] =>
Expr
.summon[NativeInCompatible[a]]
.summon[MethodCompatible[a]]
.map(_ => ())
.getOrElse(
report.errorAndAbort(
Expand All @@ -73,7 +73,7 @@ object LibraryI:
case '[Unit] => ()
case '[a] =>
Expr
.summon[NativeOutCompatible[a]]
.summon[MethodCompatible[a]]
.map(_ => ())
.getOrElse(
report.errorAndAbort(
Expand All @@ -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]
) =
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down
16 changes: 16 additions & 0 deletions core/src/fr/hammons/slinc/MethodCompatible.scala
Original file line number Diff line number Diff line change
@@ -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]]]
Loading