Skip to content

Commit

Permalink
Unsigned types improvements (#3375)
Browse files Browse the repository at this point in the history
* Add small integer caching for Unsigned and Size integer types

* Apply usage of cached valueOf integer accessor in nativelib

* Adjust UnsigedEqualityTest to be aware of small integer caching

* Add intrinisc unsignedOf method, ensuring the NIR generation emits box literal, instead of ordinar method call

* Seperate Scala 2/3 unsigned package. Optimize Scala 3 by implementing toU conversions as inline defs

* Use Size.valueOf to implement toSize conversions. Use inlined extension for Scala3

* Move UnsafeRich* to common scalanative.unsiged package for cross-compilation gurantees
  • Loading branch information
WojciechMazur committed Jul 5, 2023
1 parent 0290c97 commit f88d789
Show file tree
Hide file tree
Showing 26 changed files with 461 additions and 190 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scala.scalanative.unsafe

import scala.scalanative.runtime._
import scala.scalanative.runtime.Intrinsics.{castRawSizeToInt as toInt}
import scala.scalanative.runtime.Intrinsics.{castRawSizeToInt as toInt, *}

private[scalanative] trait UnsafePackageCompat {
private[scalanative] given reflect.ClassTag[Array[?]] =
Expand Down Expand Up @@ -57,4 +57,27 @@ private[scalanative] trait UnsafePackageCompat {
libc.memset(ptr, 0, size)
ptr
}

/** Scala Native unsafe extensions to the standard Byte. */
extension (inline value: Byte) {
inline def toSize: Size = Size.valueOf(castIntToRawSize(value))
}

/** Scala Native unsafe extensions to the standard Short. */
extension (inline value: Short) {
inline def toSize: Size = Size.valueOf(castIntToRawSize(value))
}

/** Scala Native unsafe extensions to the standard Int. */
extension (inline value: Int) {
inline def toPtr[T]: Ptr[T] = fromRawPtr[T](castIntToRawPtr(value))
inline def toSize: Size = Size.valueOf(castIntToRawSize(value))
}

/** Scala Native unsafe extensions to the standard Long. */
extension (inline value: Long) {
inline def toPtr[T]: Ptr[T] = fromRawPtr[T](castLongToRawPtr(value))
inline def toSize: Size = Size.valueOf(castLongToRawSize(value))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package scala.scalanative.unsigned

import scala.scalanative.runtime.Intrinsics._

/** Scala Native unsigned extensions to the standard Byte. */
extension (inline value: Byte) {
inline def toUByte: UByte = unsignedOf(value)
inline def toUShort: UShort = unsignedOf(value.toShort)
inline def toUInt: UInt = unsignedOf(byteToUInt(value))
inline def toULong: ULong = unsignedOf(byteToULong(value))
}

/** Scala Native unsigned extensions to the standard Short. */
extension (inline value: Short) {
inline def toUByte: UByte = unsignedOf(value.toByte)
inline def toUShort: UShort = unsignedOf(value)
inline def toUInt: UInt = unsignedOf(shortToUInt(value))
inline def toULong: ULong = unsignedOf(shortToULong(value))
}

/** Scala Native unsigned extensions to the standard Int. */
extension (inline value: Int) {
inline def toUByte: UByte = unsignedOf(value.toByte)
inline def toUShort: UShort = unsignedOf(value.toShort)
inline def toUInt: UInt = unsignedOf(value)
inline def toULong: ULong = unsignedOf(intToULong(value))
inline def toUSize: USize = unsignedOf(castIntToRawSizeUnsigned(value))
}

/** Scala Native unsigned extensions to the standard Long. */
extension (inline value: Long) {
inline def toUByte: UByte = unsignedOf(value.toByte)
inline def toUShort: UShort = unsignedOf(value.toShort)
inline def toUInt: UInt = unsignedOf(value.toInt)
inline def toULong: ULong = unsignedOf(value)
inline def toUSize: USize = unsignedOf(castLongToRawSize(value))
}
54 changes: 27 additions & 27 deletions nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ final class BooleanArray private () extends Array[Boolean] {

@inline override def clone(): BooleanArray = {
val arrcls = classOf[BooleanArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 1 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 1 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -189,7 +189,7 @@ object BooleanArray {
}
val arrcls = classOf[BooleanArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 1 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 1)
castRawPtrToObject(arr).asInstanceOf[BooleanArray]
Expand All @@ -211,7 +211,7 @@ object BooleanArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(1 * length))
val size = USize.valueOf(intToUSize(1 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -236,7 +236,7 @@ final class CharArray private () extends Array[Char] {

@inline override def clone(): CharArray = {
val arrcls = classOf[CharArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 2 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 2 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -252,7 +252,7 @@ object CharArray {
}
val arrcls = classOf[CharArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 2 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 2)
castRawPtrToObject(arr).asInstanceOf[CharArray]
Expand All @@ -274,7 +274,7 @@ object CharArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(2 * length))
val size = USize.valueOf(intToUSize(2 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -299,7 +299,7 @@ final class ByteArray private () extends Array[Byte] {

@inline override def clone(): ByteArray = {
val arrcls = classOf[ByteArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 1 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 1 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -315,7 +315,7 @@ object ByteArray {
}
val arrcls = classOf[ByteArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 1 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 1)
castRawPtrToObject(arr).asInstanceOf[ByteArray]
Expand All @@ -337,7 +337,7 @@ object ByteArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(1 * length))
val size = USize.valueOf(intToUSize(1 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -362,7 +362,7 @@ final class ShortArray private () extends Array[Short] {

@inline override def clone(): ShortArray = {
val arrcls = classOf[ShortArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 2 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 2 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -378,7 +378,7 @@ object ShortArray {
}
val arrcls = classOf[ShortArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 2 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 2)
castRawPtrToObject(arr).asInstanceOf[ShortArray]
Expand All @@ -400,7 +400,7 @@ object ShortArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(2 * length))
val size = USize.valueOf(intToUSize(2 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -425,7 +425,7 @@ final class IntArray private () extends Array[Int] {

@inline override def clone(): IntArray = {
val arrcls = classOf[IntArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 4 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 4 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -441,7 +441,7 @@ object IntArray {
}
val arrcls = classOf[IntArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 4 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 4)
castRawPtrToObject(arr).asInstanceOf[IntArray]
Expand All @@ -463,7 +463,7 @@ object IntArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(4 * length))
val size = USize.valueOf(intToUSize(4 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -488,7 +488,7 @@ final class LongArray private () extends Array[Long] {

@inline override def clone(): LongArray = {
val arrcls = classOf[LongArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 8 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 8 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -504,7 +504,7 @@ object LongArray {
}
val arrcls = classOf[LongArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 8 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 8)
castRawPtrToObject(arr).asInstanceOf[LongArray]
Expand All @@ -526,7 +526,7 @@ object LongArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(8 * length))
val size = USize.valueOf(intToUSize(8 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -551,7 +551,7 @@ final class FloatArray private () extends Array[Float] {

@inline override def clone(): FloatArray = {
val arrcls = classOf[FloatArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 4 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 4 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -567,7 +567,7 @@ object FloatArray {
}
val arrcls = classOf[FloatArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 4 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 4)
castRawPtrToObject(arr).asInstanceOf[FloatArray]
Expand All @@ -589,7 +589,7 @@ object FloatArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(4 * length))
val size = USize.valueOf(intToUSize(4 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -614,7 +614,7 @@ final class DoubleArray private () extends Array[Double] {

@inline override def clone(): DoubleArray = {
val arrcls = classOf[DoubleArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + 8 * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + 8 * length))
val arr = GC.alloc_atomic(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -630,7 +630,7 @@ object DoubleArray {
}
val arrcls = classOf[DoubleArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + 8 * length)
val arr = GC.alloc_atomic(arrcls, new USize(arrsize))
val arr = GC.alloc_atomic(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), 8)
castRawPtrToObject(arr).asInstanceOf[DoubleArray]
Expand All @@ -652,7 +652,7 @@ object DoubleArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(8 * length))
val size = USize.valueOf(intToUSize(8 * length))
libc.memcpy(dst, src, size)
arr
}
Expand All @@ -677,7 +677,7 @@ final class ObjectArray private () extends Array[Object] {

@inline override def clone(): ObjectArray = {
val arrcls = classOf[ObjectArray]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + castRawSizeToInt(sizeOfPtr) * length))
val arrsize = USize.valueOf(intToUSize(MemoryLayout.Array.ValuesOffset + castRawSizeToInt(sizeOfPtr) * length))
val arr = GC.alloc(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -693,7 +693,7 @@ object ObjectArray {
}
val arrcls = classOf[ObjectArray]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + castRawSizeToInt(sizeOfPtr) * length)
val arr = GC.alloc(arrcls, new USize(arrsize))
val arr = GC.alloc(arrcls, USize.valueOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), castRawSizeToInt(sizeOfPtr))
castRawPtrToObject(arr).asInstanceOf[ObjectArray]
Expand All @@ -715,7 +715,7 @@ object ObjectArray {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(castRawSizeToInt(sizeOfPtr) * length))
val size = USize.valueOf(intToUSize(castRawSizeToInt(sizeOfPtr) * length))
libc.memcpy(dst, src, size)
arr
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ final class ${T}Array private () extends Array[${T}] {

@inline override def clone(): ${T}Array = {
val arrcls = classOf[${T}Array]
val arrsize = new USize(intToUSize(MemoryLayout.Array.ValuesOffset + ${sizeT} * length))
val arrsize = unsignedOf(intToUSize(MemoryLayout.Array.ValuesOffset + ${sizeT} * length))
val arr = ${allocGC}(arrcls, arrsize)
val src = castObjectToRawPtr(this)
libc.memcpy(arr, src, arrsize)
Expand All @@ -205,7 +205,7 @@ object ${T}Array {
}
val arrcls = classOf[${T}Array]
val arrsize = intToUSize(MemoryLayout.Array.ValuesOffset + ${sizeT} * length)
val arr = ${allocGC}(arrcls, new USize(arrsize))
val arr = ${allocGC}(arrcls, unsignedOf(arrsize))
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.LengthOffset)), length)
storeInt(elemRawPtr(arr, intToUSize(MemoryLayout.Array.StrideOffset)), ${sizeT})
castRawPtrToObject(arr).asInstanceOf[${T}Array]
Expand All @@ -227,7 +227,7 @@ object ${T}Array {
val arr = alloc(length)
val dst = arr.atRaw(0)
val src = data
val size = new USize(intToUSize(${sizeT} * length))
val size = unsignedOf(intToUSize(${sizeT} * length))
libc.memcpy(dst, src, size)
arr
}
Expand Down
12 changes: 6 additions & 6 deletions nativelib/src/main/scala/scala/scalanative/runtime/Boxes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import scalanative.unsigned._
import scalanative.unsafe._

object Boxes {
@inline def boxToSize(v: RawSize): Size = new Size(v)
@inline def boxToUSize(v: RawSize): USize = new USize(v)
@inline def boxToSize(v: RawSize): Size = Size.valueOf(v)
@inline def boxToUSize(v: RawSize): USize = USize.valueOf(v)

@inline def unboxToSize(o: java.lang.Object): RawSize =
if (o == null) Intrinsics.castIntToRawSize(0)
Expand All @@ -41,19 +41,19 @@ object Boxes {
if (o == null) Intrinsics.castIntToRawSize(0)
else o.asInstanceOf[USize].rawSize

@inline def boxToUByte(v: Byte): UByte = new UByte(v)
@inline def boxToUByte(v: Byte): UByte = UByte.valueOf(v)
@inline def unboxToUByte(o: java.lang.Object): Byte =
if (o == null) 0.toByte else o.asInstanceOf[UByte].underlying

@inline def boxToUShort(v: Short): UShort = new UShort(v)
@inline def boxToUShort(v: Short): UShort = UShort.valueOf(v)
@inline def unboxToUShort(o: java.lang.Object): Short =
if (o == null) 0.toShort else o.asInstanceOf[UShort].underlying

@inline def boxToUInt(v: Int): UInt = new UInt(v)
@inline def boxToUInt(v: Int): UInt = UInt.valueOf(v)
@inline def unboxToUInt(o: java.lang.Object): Int =
if (o == null) 0.toInt else o.asInstanceOf[UInt].underlying

@inline def boxToULong(v: Long): ULong = new ULong(v)
@inline def boxToULong(v: Long): ULong = ULong.valueOf(v)
@inline def unboxToULong(o: java.lang.Object): Long =
if (o == null) 0.toLong else o.asInstanceOf[ULong].underlying

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import scalanative.unsigned._
import scalanative.unsafe._

object Boxes {
@inline def boxToSize(v: RawSize): Size = new Size(v)
@inline def boxToUSize(v: RawSize): USize = new USize(v)
@inline def boxToSize(v: RawSize): Size = Size.valueOf(v)
@inline def boxToUSize(v: RawSize): USize = USize.valueOf(v)

@inline def unboxToSize(o: java.lang.Object): RawSize =
if (o == null) Intrinsics.castIntToRawSize(0)
Expand All @@ -50,7 +50,7 @@ object Boxes {
]
}%
% for (U, P) in unsigned:
@inline def boxTo${U}(v: ${P}): ${U} = new ${U}(v)
@inline def boxTo${U}(v: ${P}): ${U} = ${U}.valueOf(v)
@inline def unboxTo${U}(o: java.lang.Object): ${P} =
if (o == null) 0.to${P} else o.asInstanceOf[${U}].underlying

Expand Down

0 comments on commit f88d789

Please sign in to comment.