Skip to content

Commit e1d20ad

Browse files
committed
chore: laying the groundwork for JITC writers
1 parent 9bfd833 commit e1d20ad

File tree

13 files changed

+273
-84
lines changed

13 files changed

+273
-84
lines changed

core/src/fr/hammons/slinc/Bytes.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package fr.hammons.slinc
22

33
import scala.quoted.{ToExpr, Quotes}
44
import fr.hammons.slinc.types.SizeT
5+
import scala.quoted.FromExpr
6+
import scala.quoted.Expr
57

68
opaque type Bytes = Long
79

@@ -29,3 +31,7 @@ object Bytes:
2931
given Numeric[Bytes] = Numeric.LongIsIntegral
3032
given ToExpr[Bytes] with
3133
def apply(t: Bytes)(using Quotes) = ToExpr.LongToExpr[Long].apply(t)
34+
35+
given FromExpr[Bytes] with
36+
def unapply(x: Expr[Bytes])(using Quotes) =
37+
FromExpr.LongFromExpr[Long].unapply(x)

core/src/fr/hammons/slinc/Ptr.scala

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import scala.reflect.ClassTag
44
import fr.hammons.slinc.modules.DescriptorModule
55
import fr.hammons.slinc.modules.ReadWriteModule
66
import fr.hammons.slinc.fnutils.{Fn, toNativeCompatible}
7+
import fr.hammons.slinc.descriptors.WriterContext
78

89
class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes):
910
inline def `unary_!`(using rwm: ReadWriteModule): A =
@@ -29,7 +30,11 @@ class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes):
2930
r: ReadWriteModule
3031
)(using ClassTag[A]): IArray[A] =
3132
IArray.unsafeFromArray(
32-
r.readArray(mem.resize(DescriptorOf[A].size * size), offset, size)
33+
r.readArray[A](
34+
mem.resize(DescriptorOf[A].size * size),
35+
offset,
36+
size
37+
)
3338
)
3439

3540
def `unary_!_=`(value: A)(using rwM: ReadWriteModule, desc: DescriptorOf[A]) =
@@ -63,7 +68,12 @@ object Ptr:
6368

6469
def copy[A](
6570
a: Array[A]
66-
)(using alloc: Allocator, descriptor: DescriptorOf[A], rwm: ReadWriteModule) =
71+
)(using
72+
alloc: Allocator,
73+
descriptor: DescriptorOf[A],
74+
rwm: ReadWriteModule,
75+
dm: DescriptorModule
76+
) =
6777
val mem = alloc.allocate(DescriptorOf[A], a.size)
6878
rwm.writeArray(mem, Bytes(0), a)
6979
Ptr[A](mem, Bytes(0))
@@ -82,7 +92,12 @@ object Ptr:
8292

8393
def copy(
8494
string: String
85-
)(using Allocator, DescriptorOf[Byte], ReadWriteModule): Ptr[Byte] = copy(
95+
)(using
96+
Allocator,
97+
DescriptorOf[Byte],
98+
ReadWriteModule,
99+
DescriptorModule
100+
): Ptr[Byte] = copy(
86101
string.getBytes("ASCII").nn :+ 0.toByte
87102
)
88103

core/src/fr/hammons/slinc/Struct.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import modules.DescriptorModule
77
import fr.hammons.slinc.modules.TransitionModule
88
import fr.hammons.slinc.modules.ReadWriteModule
99
import fr.hammons.slinc.modules.Reader
10-
import fr.hammons.slinc.modules.Writer
10+
import fr.hammons.slinc.modules.MemWriter
1111

1212
trait Struct[A <: Product] extends DescriptorOf[A]
1313

@@ -35,7 +35,7 @@ object Struct:
3535
m: Mirror.ProductOf[A],
3636
rwm: ReadWriteModule,
3737
dm: DescriptorModule
38-
): Writer[A] =
38+
): MemWriter[A] =
3939
val offsets = dm.memberOffsets(memberDescriptors[A])
4040
(mem, offset, value) =>
4141
writeGenHelper(

core/src/fr/hammons/slinc/TypeDescriptor.scala

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import modules.DescriptorModule
44
import fr.hammons.slinc.modules.{
55
ReadWriteModule,
66
Reader,
7-
Writer,
87
ArrayReader,
98
readWriteModule
109
}
@@ -14,6 +13,7 @@ import fr.hammons.slinc.modules.TransitionModule
1413
import fr.hammons.slinc.modules.{ArgumentTransition, ReturnTransition}
1514
import scala.NonEmptyTuple
1615
import scala.language.implicitConversions
16+
import fr.hammons.slinc.modules.MemWriter
1717

1818
/** Describes types used by C interop
1919
*/
@@ -28,7 +28,7 @@ sealed trait TypeDescriptor:
2828
dm.toCarrierType(this)
2929

3030
val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner]
31-
val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner]
31+
val writer: (ReadWriteModule, DescriptorModule) ?=> MemWriter[Inner]
3232
val argumentTransition: (
3333
TransitionModule,
3434
ReadWriteModule,
@@ -55,7 +55,7 @@ sealed trait TypeDescriptor:
5555
}
5656

5757
val arrayWriter
58-
: (ReadWriteModule, DescriptorModule) ?=> Writer[Array[Inner]] =
58+
: (ReadWriteModule, DescriptorModule) ?=> MemWriter[Array[Inner]] =
5959
val writer = this.writer
6060
val size = this.size
6161
(mem, offset, a) =>
@@ -167,7 +167,7 @@ case class AliasDescriptor[A](val real: TypeDescriptor) extends TypeDescriptor:
167167
val reader: (ReadWriteModule, DescriptorModule) ?=> Reader[Inner] =
168168
(rwm, _) ?=> (mem, bytes) => rwm.read(mem, bytes, real)
169169

170-
val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner] =
170+
val writer: (ReadWriteModule, DescriptorModule) ?=> MemWriter[Inner] =
171171
(rwm, _) ?=> (mem, bytes, a) => rwm.write(mem, bytes, real, a)
172172

173173
override val argumentTransition =
@@ -191,7 +191,8 @@ case object VaListDescriptor extends TypeDescriptor:
191191
Inner
192192
] = _.mem.asAddress
193193

194-
override val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner] =
194+
override val writer
195+
: (ReadWriteModule, DescriptorModule) ?=> MemWriter[Inner] =
195196
(mem, offset, value) =>
196197
summon[ReadWriteModule].memWriter(mem, offset, value.mem)
197198

@@ -216,7 +217,8 @@ case class CUnionDescriptor(possibleTypes: Set[TypeDescriptor])
216217
Inner
217218
] = (i: Inner) => i.mem.asBase
218219

219-
override val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner] =
220+
override val writer
221+
: (ReadWriteModule, DescriptorModule) ?=> MemWriter[Inner] =
220222
summon[ReadWriteModule].unionWriter(this)
221223

222224
case class SetSizeArrayDescriptor(
@@ -231,7 +233,8 @@ case class SetSizeArrayDescriptor(
231233
summon[ReadWriteModule].readArray[contained.Inner](mem, offset, number)
232234
)
233235

234-
override val writer: (ReadWriteModule, DescriptorModule) ?=> Writer[Inner] =
236+
override val writer
237+
: (ReadWriteModule, DescriptorModule) ?=> MemWriter[Inner] =
235238
(mem, offset, value) =>
236239
summon[ReadWriteModule]
237240
.writeArray[contained.Inner](mem, offset, value.toArray)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package fr.hammons.slinc.descriptors
2+
3+
import fr.hammons.slinc.jitc.OptimizableFn
4+
import fr.hammons.slinc.Mem
5+
import fr.hammons.slinc.Bytes
6+
import fr.hammons.slinc.modules.MemWriter
7+
8+
type Writer[A] = OptimizableFn[MemWriter[A], WriterContext]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package fr.hammons.slinc.descriptors
2+
3+
import fr.hammons.slinc.modules.DescriptorModule
4+
import fr.hammons.slinc.modules.ReadWriteModule
5+
6+
final case class WriterContext(dm: DescriptorModule, rwm: ReadWriteModule)

core/src/fr/hammons/slinc/jitc/Intrumentation.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fr.hammons.slinc.jitc
22

33
import java.util.concurrent.atomic.AtomicInteger
44
import fr.hammons.slinc.fnutils.Fn
5+
import scala.annotation.implicitNotFound
56

67
trait Instrumentation:
78
def getCount(): Int
@@ -12,9 +13,10 @@ trait Instrumentation:
1213
def instrument[A](a: A): Instrumented[A]
1314

1415
def apply[A, B <: Tuple, C, D, E](fn: A)(using
15-
Fn[A, B, C],
16-
C =:= Instrumented[D],
17-
Fn[E, B, D]
16+
@implicitNotFound(
17+
"Could not find Fn[${A}, ${B}, Instrumented[${C}]"
18+
) ev1: Fn[A, B, Instrumented[C]],
19+
ev2: Fn[E, B, C]
1820
): InstrumentedFn[E] =
1921
fn.asInstanceOf[E]
2022

core/src/fr/hammons/slinc/jitc/JitCService.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type JitCompiler = [A] => (
1717
trait JitCService:
1818
def jitC(tag: UUID, c: JitCompiler => Unit): Unit
1919
def processedRecently(tag: UUID): Boolean
20+
def async: Boolean
2021

2122
object JitCService:
2223
lazy val standard = new JitCService:
@@ -90,6 +91,8 @@ object JitCService:
9091
override def processedRecently(tag: ju.UUID): Boolean =
9192
workDone.getOpaque().nn.contains(tag)
9293

94+
override def async: Boolean = true
95+
9396
lazy val synchronous = new JitCService:
9497
private val wdoneCache = 32
9598
given compiler: scala.quoted.staging.Compiler =
@@ -111,3 +114,5 @@ object JitCService:
111114

112115
override def processedRecently(tag: ju.UUID): Boolean =
113116
workDone.getOpaque().nn.contains(tag)
117+
118+
override def async: Boolean = false

core/src/fr/hammons/slinc/jitc/OptimizableFn.scala

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,26 @@ package fr.hammons.slinc.jitc
33
import java.util.concurrent.atomic.AtomicReference
44
import java.util.UUID
55

6-
class OptimizableFn[F](
6+
class OptimizableFn[F, G](
77
optimizer: JitCService,
88
inst: Instrumentation = new CountbasedInstrumentation
99
)(
10-
f: (i: Instrumentation) => i.InstrumentedFn[F],
10+
f: G ?=> (i: Instrumentation) => i.InstrumentedFn[F],
1111
limit: Int
12-
)(optimized: JitCompiler => F):
13-
private val _fn: AtomicReference[F] = AtomicReference(f(inst))
12+
)(optimized: G ?=> JitCompiler => F):
13+
private val _fn: AtomicReference[F] = AtomicReference()
1414
val uuid = UUID.randomUUID().nn
15-
private val _optFn: AtomicReference[F] = AtomicReference(
16-
if inst.getCount() >= limit then
17-
var opt: F | Null = null
18-
optimizer.jitC(uuid, jitCompiler => opt = optimized(jitCompiler))
19-
opt
20-
else null
21-
)
15+
private val _optFn: AtomicReference[F] = AtomicReference()
2216

23-
def get: F =
17+
def get(using G): F =
2418
val optFn = _optFn.getOpaque()
19+
var fn = _fn.getOpaque()
20+
if fn == null then
21+
fn = f(inst)
22+
_fn.set(fn)
23+
2524
if optFn != null then optFn
26-
else
27-
if inst.getCount() >= limit then
25+
else if inst.getCount() >= limit then
2826
optimizer.jitC(
2927
uuid,
3028
jitCompiler =>
@@ -33,13 +31,17 @@ class OptimizableFn[F](
3331
opt
3432
)
3533
)
36-
_fn.getOpaque().nn
37-
34+
if optimizer.async then fn.nn
35+
else
36+
while _optFn.getOpaque() == null do {}
37+
_optFn.getOpaque().nn
38+
else fn.nn
39+
3840
object OptimizableFn:
3941
val modeSetting = "slinc.jitc.mode"
4042
val limitSetting = "slinc.jitc.jit-limit"
41-
def apply[F](optimized: JitCompiler => F)(
42-
unoptimizedFn: (i: Instrumentation) => i.InstrumentedFn[F]
43+
def apply[F, G](optimized: G ?=> JitCompiler => F)(
44+
unoptimizedFn: G ?=> (i: Instrumentation) => i.InstrumentedFn[F]
4345
) =
4446
val mode = sys.props.getOrElseUpdate("slinc.jitc.mode", "standard")
4547
mode match
@@ -49,24 +51,19 @@ object OptimizableFn:
4951
limit match
5052
case None => throw Error("slinc.jitc.jit-limit should be an integer")
5153
case Some(value) =>
52-
new OptimizableFn[F](
54+
new OptimizableFn[F, G](
5355
JitCService.standard,
5456
CountbasedInstrumentation()
5557
)(unoptimizedFn, value)(optimized)
5658

5759
case "never" | "disabled" =>
58-
new OptimizableFn[F](JitCService.synchronous, IgnoreInstrumentation)(
60+
new OptimizableFn[F, G](JitCService.synchronous, IgnoreInstrumentation)(
5961
unoptimizedFn,
6062
1
6163
)(optimized)
6264

6365
case "immediate" =>
64-
new OptimizableFn[F](JitCService.synchronous, IgnoreInstrumentation)(
66+
new OptimizableFn[F, G](JitCService.synchronous, IgnoreInstrumentation)(
6567
unoptimizedFn,
6668
0
6769
)(optimized)
68-
69-
def standard[F](
70-
optimized: JitCompiler => F
71-
)(unoptimizedFn: (i: Instrumentation) => i.InstrumentedFn[F], limit: Int) =
72-
new OptimizableFn[F](JitCService.standard)(unoptimizedFn, limit)(optimized)

core/src/fr/hammons/slinc/modules/ReadWriteModule.scala

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,36 @@ import java.lang.invoke.MethodHandle
55
import scala.reflect.ClassTag
66
import scala.NonEmptyTuple
77
import fr.hammons.slinc.fnutils.Fn
8+
import fr.hammons.slinc.jitc.OptimizableFn
9+
import scala.quoted.Expr
10+
import scala.quoted.Quotes
811

912
type Reader[A] = (Mem, Bytes) => A
10-
type Writer[A] = (Mem, Bytes, A) => Unit
13+
type MemWriter[A] = (Mem, Bytes, A) => Unit
1114
type ArrayReader[A] = (Mem, Bytes, Int) => Array[A]
1215

1316
val readWriteModule = (rwm: ReadWriteModule) ?=> rwm
1417

1518
trait ReadWriteModule:
1619
val byteReader: Reader[Byte]
17-
val byteWriter: Writer[Byte]
20+
val byteWriter: MemWriter[Byte]
1821
val shortReader: Reader[Short]
19-
val shortWriter: Writer[Short]
22+
val shortWriter: MemWriter[Short]
2023
val intReader: Reader[Int]
21-
val intWriter: Writer[Int]
24+
val intWriter: MemWriter[Int]
25+
val intWritingExpr: Quotes ?=> Expr[MemWriter[Int]]
2226
val longReader: Reader[Long]
23-
val longWriter: Writer[Long]
27+
val longWriter: MemWriter[Long]
2428

2529
val floatReader: Reader[Float]
26-
val floatWriter: Writer[Float]
30+
val floatWriter: MemWriter[Float]
2731
val doubleReader: Reader[Double]
28-
val doubleWriter: Writer[Double]
32+
val doubleWriter: MemWriter[Double]
2933

3034
val memReader: Reader[Mem]
31-
val memWriter: Writer[Mem]
35+
val memWriter: MemWriter[Mem]
3236
def unionReader(td: TypeDescriptor): Reader[CUnion[? <: NonEmptyTuple]]
33-
def unionWriter(td: TypeDescriptor): Writer[CUnion[? <: NonEmptyTuple]]
37+
def unionWriter(td: TypeDescriptor): MemWriter[CUnion[? <: NonEmptyTuple]]
3438

3539
def write(
3640
memory: Mem,
@@ -56,3 +60,8 @@ trait ReadWriteModule:
5660
descriptor: CFunctionDescriptor,
5761
fn: => MethodHandle => Mem => A
5862
)(using Fn[A, ?, ?]): A
63+
64+
def writeExpr(td: TypeDescriptor)(using Quotes): Expr[MemWriter[Any]]
65+
def writeArrayExpr(td: TypeDescriptor)(using
66+
Quotes
67+
): Expr[MemWriter[Array[Any]]]

0 commit comments

Comments
 (0)