From e90c3d98d07ba892a5b02c6b3af04b8c36a27f2e Mon Sep 17 00:00:00 2001 From: Mark Hammons Date: Tue, 16 May 2023 11:02:53 +0200 Subject: [PATCH] feat: Create Java_ layouts for Java 17 Fixes #160 --- core/src/fr/hammons/slinc/Bytes.scala | 1 + .../slinc/modules/DescriptorSpec.scala | 37 +++++++++++ .../slinc/modules/DescriptorModule17.scala | 63 ++++++++----------- .../slinc/modules/platform/Platform.scala | 11 ++++ .../modules/platform/aarch64/Darwin.scala | 20 ++++++ .../modules/platform/aarch64/Linux.scala | 20 ++++++ .../slinc/modules/platform/x64/Darwin.scala | 19 ++++++ .../slinc/modules/platform/x64/Linux.scala | 3 + .../slinc/modules/platform/x64/Windows.scala | 20 ++++++ .../src/fr/hammons/slinc/LayoutSpec.scala | 3 + .../slinc/modules/DescriptorModule19.scala | 39 +++--------- 11 files changed, 169 insertions(+), 67 deletions(-) create mode 100644 j17/src/fr/hammons/slinc/modules/platform/Platform.scala create mode 100644 j17/src/fr/hammons/slinc/modules/platform/aarch64/Darwin.scala create mode 100644 j17/src/fr/hammons/slinc/modules/platform/aarch64/Linux.scala create mode 100644 j17/src/fr/hammons/slinc/modules/platform/x64/Darwin.scala create mode 100644 j17/src/fr/hammons/slinc/modules/platform/x64/Linux.scala create mode 100644 j17/src/fr/hammons/slinc/modules/platform/x64/Windows.scala create mode 100644 j17/test/src/fr/hammons/slinc/LayoutSpec.scala diff --git a/core/src/fr/hammons/slinc/Bytes.scala b/core/src/fr/hammons/slinc/Bytes.scala index 96584dd..481420c 100644 --- a/core/src/fr/hammons/slinc/Bytes.scala +++ b/core/src/fr/hammons/slinc/Bytes.scala @@ -15,6 +15,7 @@ object Bytes: inline def %(b: Bytes): Bytes = a % b inline def -(b: Bytes): Bytes = a - b inline def >(b: Bytes): Boolean = a > b + inline def >=(b: Bytes): Boolean = a >= b inline def toLong: Long = a inline def toBits: Long = a * 8 def toSizeT = SizeT diff --git a/core/test/src/fr/hammons/slinc/modules/DescriptorSpec.scala b/core/test/src/fr/hammons/slinc/modules/DescriptorSpec.scala index 6b99383..1ad6703 100644 --- a/core/test/src/fr/hammons/slinc/modules/DescriptorSpec.scala +++ b/core/test/src/fr/hammons/slinc/modules/DescriptorSpec.scala @@ -7,6 +7,13 @@ import fr.hammons.slinc.types.CInt import fr.hammons.slinc.types.CFloat import fr.hammons.slinc.CUnion import fr.hammons.slinc.Struct +import fr.hammons.slinc.ByteDescriptor +import fr.hammons.slinc.Bytes +import fr.hammons.slinc.ShortDescriptor +import fr.hammons.slinc.IntDescriptor +import fr.hammons.slinc.LongDescriptor +import fr.hammons.slinc.FloatDescriptor +import fr.hammons.slinc.DoubleDescriptor trait DescriptorSpec(val slinc: Slinc) extends munit.FunSuite: import slinc.dm @@ -23,3 +30,33 @@ trait DescriptorSpec(val slinc: Slinc) extends munit.FunSuite: DescriptorOf[CUnion[(CInt, A, CFloat)]].alignment, DescriptorOf[A].alignment ) + + test("ByteDescriptor is 1 byte in size"): + assertEquals(ByteDescriptor.size, Bytes(1)) + + test("ShortDescriptor is 2 bytes in size"): + assertEquals(ShortDescriptor.size, Bytes(2)) + + test("IntDescriptor is 4 bytes in size"): + assertEquals(IntDescriptor.size, Bytes(4)) + + test("LongDescriptor is 8 bytes in size"): + assertEquals(LongDescriptor.size, Bytes(8)) + + test("FloatDescriptor is 4 bytes in size"): + assertEquals(FloatDescriptor.size, Bytes(4)) + + test("DoubleDescriptor is 8 bytes in size"): + assertEquals(DoubleDescriptor.size, Bytes(8)) + + test("StructDescriptor.alignment is the max of the member elements"): + assertEquals(DescriptorOf[A].alignment, Bytes(8)) + + test("StructDescriptor.size is a multiple of alignment"): + + assertEquals(DescriptorOf[A].size % DescriptorOf[A].alignment, Bytes(0)) + assert( + DescriptorOf[A].size >= (DescriptorOf[CInt].size * 3 + DescriptorOf[ + CLongLong + ].size * 2) + ) diff --git a/j17/src/fr/hammons/slinc/modules/DescriptorModule17.scala b/j17/src/fr/hammons/slinc/modules/DescriptorModule17.scala index 0e3f0fe..440fdf3 100644 --- a/j17/src/fr/hammons/slinc/modules/DescriptorModule17.scala +++ b/j17/src/fr/hammons/slinc/modules/DescriptorModule17.scala @@ -2,23 +2,17 @@ package fr.hammons.slinc.modules import fr.hammons.slinc.* -import jdk.incubator.foreign.CLinker.{ - C_CHAR, - C_SHORT, - C_INT, - C_DOUBLE, - C_FLOAT, - C_LONG_LONG, - C_POINTER -} import jdk.incubator.foreign.{ MemoryLayout, MemoryAddress, MemorySegment, GroupLayout, - CLinker -} + CLinker, + ValueLayout +}, CLinker.C_POINTER import scala.collection.concurrent.TrieMap +import fr.hammons.slinc.types.{arch, os, OS, Arch} +import fr.hammons.slinc.modules.platform.* given descriptorModule17: DescriptorModule with val chm: TrieMap[StructDescriptor, GroupLayout] = TrieMap.empty @@ -69,26 +63,13 @@ given descriptorModule17: DescriptorModule with else Seq.empty ) - override def sizeOf(td: TypeDescriptor): Bytes = td match - case ByteDescriptor => Bytes(1) - case ShortDescriptor => Bytes(2) - case IntDescriptor => Bytes(4) - case LongDescriptor => Bytes(8) - case FloatDescriptor => Bytes(4) - case DoubleDescriptor => Bytes(8) - case PtrDescriptor => Bytes(toMemoryLayout(PtrDescriptor).byteSize()) - case sd: StructDescriptor => - Bytes(toGroupLayout(sd).byteSize()) - case VaListDescriptor => Bytes(toMemoryLayout(VaListDescriptor).byteSize()) - case ad: AliasDescriptor[?] => sizeOf(ad.real) - case CUnionDescriptor(possibleTypes) => possibleTypes.map(sizeOf).max + override def sizeOf(td: TypeDescriptor): Bytes = Bytes( + toMemoryLayout(td).byteSize() + ) - override def alignmentOf(td: TypeDescriptor): Bytes = td match - case s: StructDescriptor => - s.members.view.map(_.descriptor).map(alignmentOf).max - case CUnionDescriptor(possibleTypes) => - possibleTypes.view.map(alignmentOf).max - case _ => sizeOf(td) + override def alignmentOf(td: TypeDescriptor): Bytes = Bytes( + toMemoryLayout(td).byteAlignment + ) override def memberOffsets(sd: List[TypeDescriptor]): IArray[Bytes] = offsets.getOrElseUpdate( @@ -117,13 +98,21 @@ given descriptorModule17: DescriptorModule with } ) + val platform = (os, arch) match + case (OS.Linux, Arch.X64) => x64.Linux + case (OS.Darwin, Arch.X64) => x64.Darwin + case (OS.Windows, Arch.X64) => x64.Windows + case (OS.Linux, Arch.AArch64) => aarch64.Linux + case (OS.Darwin, Arch.AArch64) => aarch64.Darwin + case _ => throw Error("Unsupported platform!") + def toMemoryLayout(td: TypeDescriptor): MemoryLayout = td match - case ByteDescriptor => C_CHAR.nn - case ShortDescriptor => C_SHORT.nn - case IntDescriptor => C_INT.nn - case LongDescriptor => C_LONG_LONG.nn - case FloatDescriptor => C_FLOAT.nn - case DoubleDescriptor => C_DOUBLE.nn + case ByteDescriptor => platform.jByte + case ShortDescriptor => platform.jShort + case IntDescriptor => platform.jInt + case LongDescriptor => platform.jLong + case FloatDescriptor => platform.jFloat + case DoubleDescriptor => platform.jDouble case PtrDescriptor => C_POINTER.nn case VaListDescriptor => C_POINTER.nn case sd: StructDescriptor => toGroupLayout(sd) @@ -138,7 +127,7 @@ given descriptorModule17: DescriptorModule with chm.getOrElseUpdate( sd, { val originalMembers = sd.members.map(toMemoryLayout) - val alignment = alignmentOf(sd) + val alignment = Bytes(originalMembers.view.map(_.byteAlignment()).max) MemoryLayout .structLayout(genLayoutList(originalMembers, alignment)*) .nn diff --git a/j17/src/fr/hammons/slinc/modules/platform/Platform.scala b/j17/src/fr/hammons/slinc/modules/platform/Platform.scala new file mode 100644 index 0000000..c47471c --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/platform/Platform.scala @@ -0,0 +1,11 @@ +package fr.hammons.slinc.modules.platform + +import jdk.incubator.foreign.ValueLayout +trait Platform { + val jByte: ValueLayout + val jShort: ValueLayout + val jInt: ValueLayout + val jLong: ValueLayout + val jFloat: ValueLayout + val jDouble: ValueLayout +} diff --git a/j17/src/fr/hammons/slinc/modules/platform/aarch64/Darwin.scala b/j17/src/fr/hammons/slinc/modules/platform/aarch64/Darwin.scala new file mode 100644 index 0000000..a285c94 --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/platform/aarch64/Darwin.scala @@ -0,0 +1,20 @@ +package fr.hammons.slinc.modules.platform.aarch64 + +import fr.hammons.slinc.modules.platform.Platform +import jdk.incubator.foreign.CLinker.{ + C_CHAR, + C_DOUBLE, + C_FLOAT, + C_INT, + C_LONG, + C_SHORT +} +import jdk.incubator.foreign.ValueLayout + +object Darwin extends Platform: + val jByte: ValueLayout = C_CHAR.nn + val jShort: ValueLayout = C_SHORT.nn + val jInt: ValueLayout = C_INT.nn + val jLong: ValueLayout = C_LONG.nn + val jFloat: ValueLayout = C_FLOAT.nn + val jDouble: ValueLayout = C_DOUBLE.nn diff --git a/j17/src/fr/hammons/slinc/modules/platform/aarch64/Linux.scala b/j17/src/fr/hammons/slinc/modules/platform/aarch64/Linux.scala new file mode 100644 index 0000000..c536d04 --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/platform/aarch64/Linux.scala @@ -0,0 +1,20 @@ +package fr.hammons.slinc.modules.platform.aarch64 + +import fr.hammons.slinc.modules.platform.Platform +import jdk.incubator.foreign.CLinker.{ + C_CHAR, + C_INT, + C_SHORT, + C_LONG, + C_FLOAT, + C_DOUBLE +} +import jdk.incubator.foreign.ValueLayout + +object Linux extends Platform: + val jByte: ValueLayout = C_CHAR.nn + val jShort: ValueLayout = C_SHORT.nn + val jInt: ValueLayout = C_INT.nn + val jLong: ValueLayout = C_LONG.nn + val jFloat: ValueLayout = C_FLOAT.nn + val jDouble: ValueLayout = C_DOUBLE.nn diff --git a/j17/src/fr/hammons/slinc/modules/platform/x64/Darwin.scala b/j17/src/fr/hammons/slinc/modules/platform/x64/Darwin.scala new file mode 100644 index 0000000..e0cf00b --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/platform/x64/Darwin.scala @@ -0,0 +1,19 @@ +package fr.hammons.slinc.modules.platform.x64 + +import fr.hammons.slinc.modules.platform.Platform +import jdk.incubator.foreign.CLinker.{ + C_CHAR, + C_DOUBLE, + C_FLOAT, + C_INT, + C_LONG, + C_SHORT +} + +object Darwin extends Platform: + val jByte = C_CHAR.nn + val jShort = C_SHORT.nn + val jInt = C_INT.nn + val jLong = C_LONG.nn + val jFloat = C_FLOAT.nn + val jDouble = C_DOUBLE.nn diff --git a/j17/src/fr/hammons/slinc/modules/platform/x64/Linux.scala b/j17/src/fr/hammons/slinc/modules/platform/x64/Linux.scala new file mode 100644 index 0000000..24d2e15 --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/platform/x64/Linux.scala @@ -0,0 +1,3 @@ +package fr.hammons.slinc.modules.platform.x64 + +val Linux = Darwin diff --git a/j17/src/fr/hammons/slinc/modules/platform/x64/Windows.scala b/j17/src/fr/hammons/slinc/modules/platform/x64/Windows.scala new file mode 100644 index 0000000..2b30da7 --- /dev/null +++ b/j17/src/fr/hammons/slinc/modules/platform/x64/Windows.scala @@ -0,0 +1,20 @@ +package fr.hammons.slinc.modules.platform.x64 + +import fr.hammons.slinc.modules.platform.Platform +import jdk.incubator.foreign.CLinker.{ + C_CHAR, + C_SHORT, + C_INT, + C_LONG_LONG, + C_FLOAT, + C_DOUBLE +} +import jdk.incubator.foreign.ValueLayout + +object Windows extends Platform: + val jByte: ValueLayout = C_CHAR.nn + val jShort: ValueLayout = C_SHORT.nn + val jInt: ValueLayout = C_INT.nn + val jLong: ValueLayout = C_LONG_LONG.nn + val jFloat: ValueLayout = C_FLOAT.nn + val jDouble: ValueLayout = C_DOUBLE.nn diff --git a/j17/test/src/fr/hammons/slinc/LayoutSpec.scala b/j17/test/src/fr/hammons/slinc/LayoutSpec.scala new file mode 100644 index 0000000..4359ad9 --- /dev/null +++ b/j17/test/src/fr/hammons/slinc/LayoutSpec.scala @@ -0,0 +1,3 @@ +package fr.hammons.slinc + +class LayoutSpec {} diff --git a/j19/src/fr/hammons/slinc/modules/DescriptorModule19.scala b/j19/src/fr/hammons/slinc/modules/DescriptorModule19.scala index ecad5a4..56efe37 100644 --- a/j19/src/fr/hammons/slinc/modules/DescriptorModule19.scala +++ b/j19/src/fr/hammons/slinc/modules/DescriptorModule19.scala @@ -36,7 +36,9 @@ given descriptorModule19: DescriptorModule with .structLayout( genLayoutList( sd.members.map(toMemoryLayout), - alignmentOf(sd) + Bytes( + sd.members.view.map(toMemoryLayout).map(_.byteAlignment()).max + ) )* ) .nn @@ -115,33 +117,10 @@ given descriptorModule19: DescriptorModule with } ) - override def sizeOf(td: TypeDescriptor): Bytes = td match - case ByteDescriptor => Bytes(1) - case ShortDescriptor => Bytes(2) - case IntDescriptor => Bytes(4) - case LongDescriptor => Bytes(8) - case FloatDescriptor => Bytes(4) - case DoubleDescriptor => Bytes(8) - case PtrDescriptor => Bytes(ValueLayout.ADDRESS.nn.byteSize()) - case VaListDescriptor => Bytes(ValueLayout.ADDRESS.nn.byteSize()) - case sd: StructDescriptor => Bytes(toGroupLayout(sd).byteSize()) - case ad: AliasDescriptor[?] => sizeOf(ad.real) - case CUnionDescriptor(possibleTypes) => possibleTypes.view.map(sizeOf).max + override def sizeOf(td: TypeDescriptor): Bytes = Bytes( + toMemoryLayout(td).byteSize() + ) - override def alignmentOf(td: TypeDescriptor): Bytes = - import java.lang.foreign.ValueLayout - td match - case ByteDescriptor => Bytes(1) - case ShortDescriptor => Bytes(2) - case IntDescriptor => Bytes(4) - case LongDescriptor => Bytes(8) - case FloatDescriptor => Bytes(4) - case DoubleDescriptor => Bytes(8) - case PtrDescriptor => Bytes(ValueLayout.ADDRESS.nn.byteAlignment()) - case VaListDescriptor => Bytes(ValueLayout.ADDRESS.nn.byteSize()) - case sd: StructDescriptor => - sd.members.view.map(_.descriptor).map(alignmentOf).max - case ad: AliasDescriptor[?] => - alignmentOf(ad.real) - case CUnionDescriptor(possibleTypes) => - possibleTypes.view.map(alignmentOf).max + override def alignmentOf(td: TypeDescriptor): Bytes = Bytes( + toMemoryLayout(td).byteAlignment() + )