Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Mem.readAddress #24

Merged
merged 1 commit into from
Nov 17, 2022
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
6 changes: 6 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import com.github.lolgab.mill.mima._

import $ivy.`de.tototec::de.tobiasroeser.mill.jacoco_mill0.10:0.0.2`
import de.tobiasroeser.mill.jacoco.JacocoTestModule
import de.tobiasroeser.mill.jacoco.JacocoReportModule

object Jacoco extends Module with JacocoReportModule {
override lazy val jacocoVersion = T.input("0.8.8")
}

object v {
val munit = "1.0.0-M6"
Expand Down Expand Up @@ -46,6 +51,7 @@ trait BaseModule extends ScalaModule with ScalafmtModule {
)

trait BaseTest extends Tests with TestModule.Munit with JacocoTestModule with ScalafmtModule {
override val jacocoReportModule = Jacoco
def ivyDeps = Agg(
ivy"org.scalameta::munit:$munitVersion",
ivy"org.scalameta::munit-scalacheck:$munitVersion"
Expand Down
2 changes: 1 addition & 1 deletion core/src/fr/hammons/slinc/Mem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ trait Mem:
def readInt(offset: Bytes): Int
def readFloat(offset: Bytes): Float
def readByte(offset: Bytes): Byte
def readMem(offset: Bytes): Mem
def readAddress(offset: Bytes): Mem
def readShort(offset: Bytes): Short
def readLong(offset: Bytes): Long
def readDouble(offset: Bytes): Double
Expand Down
8 changes: 5 additions & 3 deletions core/src/fr/hammons/slinc/Ptr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,24 @@ class Ptr[A](private[slinc] val mem: Mem, private[slinc] val offset: Bytes):
def asArray(size: Int)(using
ClassTag[A]
)(using l: LayoutOf[A], r: ReceiveBulk[A]) =
r.from(mem, offset, size)
r.from(mem.resize(Bytes(l.layout.size.toLong * 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 l: LayoutOf[A]) =
Ptr[A](mem, offset + (l.layout.size * index))

def castTo[A]: Ptr[A] = this.asInstanceOf[Ptr[A]]
private[slinc] def resize(toBytes: Bytes) = Ptr[A](mem.resize(toBytes), offset)

object Ptr:
extension (p: Ptr[Byte])
def copyIntoString(maxSize: Int)(using LayoutOf[Byte]) =
var i = 0
while !p(i) != 0 do i += 1
val resizedPtr = p.resize(Bytes(maxSize))
while (i < maxSize && !resizedPtr(i) != 0) do i += 1

String(p.asArray(i).unsafeArray, "ASCII")
String(resizedPtr.asArray(i).unsafeArray, "ASCII")
def blank[A](using layout: LayoutOf[A], alloc: Allocator): Ptr[A] =
this.blankArray[A](1)

Expand Down
6 changes: 5 additions & 1 deletion core/src/fr/hammons/slinc/Receive.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ object Receive:
given Receive[Short] with
def from(mem: Mem, offset: Bytes): Short = mem.readShort(offset)

given [A]: Receive[Ptr[A]] with
def from(mem: Mem, offset: Bytes): Ptr[A] =
Ptr[A](mem.readAddress(offset), Bytes(0))

def staged[A <: Product](
layout: StructLayout
): JitCompiler => Receive[A] =
Expand Down Expand Up @@ -97,7 +101,7 @@ object Receive:
case _: ShortLayout =>
'{ $mem.readShort($structOffset) }
case _: PointerLayout =>
'{ $mem.readMem($structOffset) }
'{ $mem.readAddress($structOffset) }
case u: UnionLayout =>
???
case structLayout @ StructLayout(_, _, children) =>
Expand Down
2 changes: 2 additions & 0 deletions core/src/fr/hammons/slinc/types/TypesI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class TypesI protected[slinc] (
type CShort = Int16
type CInt = Int32
type CLongLong = Int64
type CFloat = Float
type CDouble = Double

/** Type representing C's long type
* @note
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package fr.hammons.slinc

import fr.hammons.slinc.BindingsSpec.div_t
import fr.hammons.slinc.StdlibSpec.{div_t, ldiv_t, lldiv_t}
import scala.util.Random
import munit.ScalaCheckSuite
import org.scalacheck.Prop.*
import org.scalacheck.Gen
import org.scalacheck.Arbitrary
import fr.hammons.slinc.types.OS

trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite:
trait StdlibSpec(val slinc: Slinc) extends ScalaCheckSuite:
import slinc.{given, *}

object Cstd derives Library:
def abs(a: Int): Int = Library.binding
def labs(l: CLong): CLong = Library.binding
def div(a: Int, b: Int): div_t = Library.binding
//def ldiv(a: Long, b: Long): ldiv_t = Library.binding
//def lldiv(a: Long, b: Long): lldiv_t = Library.binding
def rand(): Int = Library.binding
def qsort[A](
array: Ptr[A],
Expand All @@ -24,6 +26,9 @@ trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite:
): Unit = Library.binding
def sprintf(ret: Ptr[Byte], string: Ptr[Byte], args: Variadic*): Unit =
Library.binding
def atof(str: Ptr[Byte]): CDouble = Library.binding
def strtod(str: Ptr[Byte], endptr: Ptr[Ptr[Byte]]): CDouble =
Library.binding

given Struct[div_t] = Struct.derived

Expand Down Expand Up @@ -73,6 +78,15 @@ trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite:
assertEquals(Cstd.div(5, 2), div_t(2, 1))
}

/*
test("ldiv") {
assertEquals(Cstd.ldiv(5L, 2L), ldiv_t(2L, 1L))
}

test("lldiv") {
assertEquals(Cstd.lldiv(5L, 2L), lldiv_t(2L, 1L))
}
*/
test("rand") {
assertNotEquals(Cstd.rand(), Cstd.rand())
}
Expand Down Expand Up @@ -167,5 +181,53 @@ trait BindingsSpec(val slinc: Slinc) extends ScalaCheckSuite:
)
}

object BindingsSpec:
property("atof convert strings to floats") {
forAll { (d: Double) =>
Scope.confined {
val pStr = Ptr.copy(f"$d%f")
assertEqualsDouble(Cstd.atof(pStr), d, 0.1)
}
}
}

property("strtod convert doubles from string") {
forAll {(d: Double) =>
Scope.confined {
val input = f"$d%f $d%f"
val maxSize = input.length()
val pStr0 = Ptr.copy(input)

val ans1 = Ptr.blank[Ptr[Byte]]
val a1 = Cstd.strtod(pStr0, ans1)
assertEqualsDouble(a1, d, 0.1)
val pStr1 = !ans1
val r1 = pStr1.copyIntoString(maxSize)
assertEquals(r1, f" $d%f")

val ans2 = Ptr.blank[Ptr[Byte]]
val a2 = Cstd.strtod(pStr1, ans2)
assertEqualsDouble(a2, d, 0.1)
assertEquals(!(!ans2), 0.toByte)
}
}
}

test("strtod convert bad string") {
Scope.confined {
val input = "notPossible"
val maxSize = input.length()
val pStr0 = Ptr.copy(input)

val ans1 = Ptr.blank[Ptr[Byte]]
val a = Cstd.strtod(pStr0, ans1)
assertEqualsDouble(a, 0.0d, 0.1)
val pStr1 = !ans1
val r1 = pStr1.copyIntoString(maxSize)
assertEquals(r1, input)
}
}

object StdlibSpec:
case class div_t(quot: Int, rem: Int)
case class ldiv_t(quot: Long, rem: Long)
case class lldiv_t(quot: Long, rem: Long)
27 changes: 23 additions & 4 deletions j17/src/fr/hammons/slinc/Mem17.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package fr.hammons.slinc

import jdk.incubator.foreign.MemorySegment
import jdk.incubator.foreign.MemoryAccess
import jdk.incubator.foreign.CLinker.C_POINTER
import jdk.incubator.foreign.ResourceScope
import jdk.incubator.foreign.CLinker.{C_CHAR, C_INT}

class Mem17(private[slinc] val mem: MemorySegment) extends Mem:
override def readDouble(offset: Bytes): Double =
Expand All @@ -20,7 +21,18 @@ class Mem17(private[slinc] val mem: MemorySegment) extends Mem:
mem,
offset.toLong
)
override def readMem(offset: Bytes): Mem = ???

override def readAddress(offset: Bytes): Mem =
Mem17(
MemoryAccess
.getAddressAtOffset(
mem,
offset.toLong
).nn.asSegment(
C_CHAR.nn.byteSize(),
ResourceScope.globalScope()
).nn
)

override def writeInt(v: Int, offset: Bytes): Unit =
MemoryAccess.setIntAtOffset(mem, offset.toLong, v)
Expand Down Expand Up @@ -55,9 +67,16 @@ class Mem17(private[slinc] val mem: MemorySegment) extends Mem:

def asBase: Object = mem
def resize(bytes: Bytes): Mem =
Mem17(mem.address().nn.asSegment(bytes.toLong, mem.scope().nn).nn)
Mem17(resizeSegment(bytes))

def resizeSegment(to: Bytes): MemorySegment =
if to.toLong == 0 then
mem
else
mem.address().nn.asSegment(to.toLong, mem.scope().nn).nn

def readIntArray(offset: Bytes, size: Int): Array[Int] =
val arr = Array.ofDim[Int](size)
MemorySegment.ofArray(arr).nn.copyFrom(mem)
val resizedMem = resizeSegment(Bytes(size * C_INT.nn.byteSize()))
MemorySegment.ofArray(arr).nn.copyFrom(resizedMem)
arr
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package fr.hammons.slinc
import Slinc17.default.{given, *}
import scala.util.Random

class Bindings17 extends BindingsSpec(Slinc17.default)
class StdlibSpec17 extends StdlibSpec(Slinc17.default)
19 changes: 16 additions & 3 deletions j19/src/fr/hammons/slinc/Mem19.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package fr.hammons.slinc

import java.lang.foreign.MemorySegment
import java.lang.foreign.MemorySession
import java.lang.foreign.ValueLayout, ValueLayout.*

object Mem19:
val javaShort = JAVA_SHORT.nn.withBitAlignment(8)
val javaInt = JAVA_INT.nn.withBitAlignment(8)
val javaChar = JAVA_CHAR.nn.withBitAlignment(8)
val javaLong = JAVA_LONG.nn.withBitAlignment(8)
val javaFloat = JAVA_FLOAT.nn.withBitAlignment(8)
val javaDouble = JAVA_DOUBLE.nn.withBitAlignment(8)
val javaByte = JAVA_BYTE.nn.withBitAlignment(8)
val javaAddress = ADDRESS.nn.withBitAlignment(8)

class Mem19(private[slinc] val mem: MemorySegment) extends Mem:
import Mem19.*
Expand Down Expand Up @@ -41,12 +44,21 @@ class Mem19(private[slinc] val mem: MemorySegment) extends Mem:
override def readFloat(offset: Bytes): Float =
mem.get(javaFloat, offset.toLong)

override def readMem(offset: Bytes): Mem = ???
override def readAddress(offset: Bytes): Mem = Mem19(
MemorySegment.ofAddress(
mem.get(javaAddress, offset.toLong).nn,
javaChar.nn.byteSize(),
MemorySession.global()
).nn
)

override def resize(bytes: Bytes): Mem = Mem19(
MemorySegment.ofAddress(mem.address().nn, bytes.toLong, mem.session()).nn
resizeSegment(bytes)
)

def resizeSegment(to: Bytes): MemorySegment =
MemorySegment.ofAddress(mem.address().nn, to.toLong, mem.session()).nn

override def readByte(offset: Bytes): Byte = mem.get(javaByte, offset.toLong)

override def writeFloat(v: Float, offset: Bytes): Unit =
Expand All @@ -66,5 +78,6 @@ class Mem19(private[slinc] val mem: MemorySegment) extends Mem:

override def readIntArray(offset: Bytes, size: Int): Array[Int] =
val arr = Array.ofDim[Int](size)
MemorySegment.ofArray(arr).nn.copyFrom(mem)
val resizedMem = resizeSegment(Bytes(size * javaInt.nn.byteSize()))
MemorySegment.ofArray(arr).nn.copyFrom(resizedMem)
arr
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import java.lang.foreign.SymbolLookup
import java.lang.foreign.FunctionDescriptor
import java.lang.foreign.ValueLayout.*

class Bindings19 extends BindingsSpec(Slinc19.default)
class StdlibSpec19 extends StdlibSpec(Slinc19.default)
2 changes: 1 addition & 1 deletion runtime/test/src/fr/hammons/slinc/Bindings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ object Mytest derives Library:

val x = println(Mytest.abs(3))

class Bindings extends BindingsSpec(slinc)
class Bindings extends StdlibSpec(slinc)