From c6f16c542f03e1be17005d74e88c4c9695b8d881 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 18 Aug 2024 13:49:35 +0200 Subject: [PATCH 01/35] Towards 0.5.6 --- docs/conf.py | 2 +- nir/src/main/scala/scala/scalanative/nir/Versions.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 6afbe9afaf..07e732c4c9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -71,7 +71,7 @@ def generateScalaNativeCurrentYear(): # The short X.Y version. version = u'0.5' # The full version, including alpha/beta/rc tags. -release = u'0.5.5' +release = u'0.5.6-SNAPSHOT' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/nir/src/main/scala/scala/scalanative/nir/Versions.scala b/nir/src/main/scala/scala/scalanative/nir/Versions.scala index 878aaaaf03..75cf769b60 100644 --- a/nir/src/main/scala/scala/scalanative/nir/Versions.scala +++ b/nir/src/main/scala/scala/scalanative/nir/Versions.scala @@ -26,7 +26,7 @@ object Versions { case class Version(compat: Int, revision: Int) /* Current public release version of Scala Native. */ - final val current: String = "0.5.5" + final val current: String = "0.5.6-SNAPSHOT" final val currentBinaryVersion: String = binaryVersion(current) private object FullVersion { From 4a5c1d1f3f49c83ab171cad692cad6cbc5b1f045 Mon Sep 17 00:00:00 2001 From: unarist Date: Mon, 19 Aug 2024 23:00:38 +0900 Subject: [PATCH 02/35] Fix `unsafe.toCWideString` was returning a double pointer to a string (#4029) --- .../src/main/scala/scala/scalanative/unsafe/package.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nativelib/src/main/scala/scala/scalanative/unsafe/package.scala b/nativelib/src/main/scala/scala/scalanative/unsafe/package.scala index ac60ee7f4c..42402285fc 100644 --- a/nativelib/src/main/scala/scala/scalanative/unsafe/package.scala +++ b/nativelib/src/main/scala/scala/scalanative/unsafe/package.scala @@ -206,7 +206,7 @@ package object unsafe extends unsafe.UnsafePackageCompat { @alwaysinline def toCWideString(str: String, charset: Charset = StandardCharsets.UTF_16LE)( implicit z: Zone - ): Ptr[CWideString] = { + ): CWideString = { toCWideStringImpl(str, charset, WideCharSize) } @@ -241,7 +241,7 @@ package object unsafe extends unsafe.UnsafePackageCompat { !(cstrEnd + c) = 0.toByte c += 1 } - cstr.asInstanceOf[Ptr[CWideString]] + cstr.asInstanceOf[CWideString] } } From 9dba2f40581c73a62dd9abc6f534421c70d1710d Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 19 Aug 2024 16:01:47 +0200 Subject: [PATCH 03/35] [chore] Fix formatting of ./scripts/changelog.scala --- scripts/changelog.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/changelog.scala b/scripts/changelog.scala index af0740cb67..94e3bf68aa 100644 --- a/scripts/changelog.scala +++ b/scripts/changelog.scala @@ -76,7 +76,8 @@ def main( } { foundPRs += prNumber val login = pr.getUser().getLogin() - val formattedPR =s"- ${pr.getTitle()} [#${pr.getNumber()}](${pr.getHtmlUrl()}) ([$login](https://github.com/$login))" + val formattedPR = + s"- ${pr.getTitle()} [#${pr.getNumber()}](${pr.getHtmlUrl()}) ([$login](https://github.com/$login))" mergedPRs += formattedPR } From fa098cb5b0e09d0b78a947a040386755aa47bbf1 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 20 Aug 2024 01:40:25 +0300 Subject: [PATCH 04/35] feature [nativelib]: implement `ThreadMXBean` (#4031) * feature [nativelib]: implement `ThreadMXBean` * ci: increase timeout to 30 minutes for the 'Test GC compilation' step --- .github/workflows/run-tests-linux.yml | 2 +- .github/workflows/run-tests-macos.yml | 2 +- .github/workflows/run-tests-windows.yml | 2 +- .../lang/management/ManagementFactory.scala | 13 +- .../java/lang/management/ThreadInfo.scala | 74 ++++++++ .../java/lang/management/ThreadMXBean.scala | 166 ++++++++++++++++++ .../scalanative/runtime/NativeThread.scala | 9 + .../management/ManagementFactoryTest.scala | 26 +++ 8 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 javalib/src/main/scala/java/lang/management/ThreadInfo.scala create mode 100644 javalib/src/main/scala/java/lang/management/ThreadMXBean.scala diff --git a/.github/workflows/run-tests-linux.yml b/.github/workflows/run-tests-linux.yml index 38cd912e07..7af805178a 100644 --- a/.github/workflows/run-tests-linux.yml +++ b/.github/workflows/run-tests-linux.yml @@ -86,7 +86,7 @@ jobs: with: scala-version: ${{matrix.scala}} - name: Test GC compilation - timeout-minutes: 15 + timeout-minutes: 30 run: sbt "test-gc ${{ matrix.scala }}" - name: Run tests timeout-minutes: 45 diff --git a/.github/workflows/run-tests-macos.yml b/.github/workflows/run-tests-macos.yml index 456439e81c..81d307762b 100644 --- a/.github/workflows/run-tests-macos.yml +++ b/.github/workflows/run-tests-macos.yml @@ -31,7 +31,7 @@ jobs: - name: Prepare for GC tests run: brew install bdw-gc - name: Test GC compilation - timeout-minutes: 15 + timeout-minutes: 30 run: sbt "test-gc ${{ matrix.scala }}" - name: Run tests diff --git a/.github/workflows/run-tests-windows.yml b/.github/workflows/run-tests-windows.yml index 5605f1622f..6e3335548f 100644 --- a/.github/workflows/run-tests-windows.yml +++ b/.github/workflows/run-tests-windows.yml @@ -32,7 +32,7 @@ jobs: scala-version: ${{matrix.scala}} - name: Test GC - timeout-minutes: 15 + timeout-minutes: 30 env: SCALANATIVE_INCLUDE_DIRS: ${{steps.setup.outputs.vcpkg-dir}}\include SCALANATIVE_LIB_DIRS: ${{steps.setup.outputs.vcpkg-dir}}\lib diff --git a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala index 8ac1c1b377..d211fce37d 100644 --- a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala +++ b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala @@ -3,12 +3,13 @@ package java.lang.management object ManagementFactory { private lazy val MemoryBean = MemoryMXBean() + private lazy val ThreadBean = ThreadMXBean() /** Returns the memory-specific bean. * * @example * {{{ - * val memoryBean = getMemoryMXBean() + * val memoryBean = ManagementFactory.getMemoryMXBean() * println(s"current heap: $${memoryBean.getHeapMemoryUsage().getUsed()}") * * val list = List.fill(Short.MaxValue)(0) // allocate memory @@ -17,4 +18,14 @@ object ManagementFactory { */ def getMemoryMXBean(): MemoryMXBean = MemoryBean + /** Returns the thread-specific bean. + * + * @example + * {{{ + * val threadBean = ManagementFactory.getThreadMXBean() + * println(s"total threads: $${threadBean.getThreadCount()}") + * }}} + */ + def getThreadMXBean(): ThreadMXBean = ThreadBean + } diff --git a/javalib/src/main/scala/java/lang/management/ThreadInfo.scala b/javalib/src/main/scala/java/lang/management/ThreadInfo.scala new file mode 100644 index 0000000000..dd0d50df96 --- /dev/null +++ b/javalib/src/main/scala/java/lang/management/ThreadInfo.scala @@ -0,0 +1,74 @@ +package java.lang.management + +import scala.scalanative.runtime.NativeThread + +/** A snapshot of a thread. + */ +trait ThreadInfo { + + /** The id of the thread. + */ + def getThreadId(): Long + + /** The name of the thread. + */ + def getThreadName(): String + + /** The state of the thread. + */ + def getThreadState(): Thread.State + + /** Whether the thread is daemon. + */ + def isDaemon(): Boolean + + /** The priority of the thread. + */ + def getPriority(): Int + +} + +object ThreadInfo { + + /** Creates a thread info using the given native thread. + * + * @note + * the stacktrace will be empty if the `maxDepth` is `0`. + * + * @param nativeThread + * the thread to create an info from + */ + @annotation.nowarn // Thread.getId is deprecated since JDK 19 + private[management] def apply(nativeThread: NativeThread): ThreadInfo = { + val thread = nativeThread.thread + + new Impl( + thread.getId(), + thread.getName(), + thread.getState(), + thread.isDaemon(), + thread.getPriority() + ) + } + + private final class Impl( + threadId: Long, + threadName: String, + threadState: Thread.State, + daemon: Boolean, + priority: Int + ) extends ThreadInfo { + + def getThreadId(): Long = threadId + def getThreadName(): String = threadName + def getThreadState(): Thread.State = threadState + def isDaemon(): Boolean = daemon + def getPriority(): Int = priority + + override def toString(): String = { + val daemon = if (isDaemon()) " daemon" else "" + s""""$threadName"$daemon prio=$priority Id=$threadId $threadState""" + } + } + +} diff --git a/javalib/src/main/scala/java/lang/management/ThreadMXBean.scala b/javalib/src/main/scala/java/lang/management/ThreadMXBean.scala new file mode 100644 index 0000000000..61f9c2178b --- /dev/null +++ b/javalib/src/main/scala/java/lang/management/ThreadMXBean.scala @@ -0,0 +1,166 @@ +package java.lang.management + +import scala.scalanative.runtime.NativeThread + +trait ThreadMXBean { + + /** Returns the current number of threads. + */ + def getThreadCount(): Int + + /** Returns the current number of daemon threads. + */ + def getDaemonThreadCount(): Int + + /** Returns IDs of all threads. + */ + def getAllThreadIds(): Array[Long] + + /** Returns a [[ThreadInfo]] for a thread with the given `id`. Returns `null` + * if the info is unavailable for the given id (thread doesn't exist). + * + * An equivalent of `getThreadInfo(id, 0)`. + * + * @param id + * the id of the thread + */ + def getThreadInfo(id: Long): ThreadInfo + + /** Returns a [[ThreadInfo]] for threads with corresponding ids. Returns + * `null` for the corresponding array element if the info is unavailable for + * the given id (thread doesn't exist). + * + * An equivalent of `getThreadInfo(ids, 0)`. + * + * @param ids + * the IDs of the threads, each id must be positive (> 0). + */ + def getThreadInfo(ids: Array[Long]): Array[ThreadInfo] + + /** Returns a [[ThreadInfo]] for the given thread id. Returns `null` if the + * info is unavailable for the given id (thread doesn't exist). + * + * @param id + * the id of the thread, must be positive (> 0) + * + * @param maxDepth + * the max depth of a stacktrace, must be non-negative (>= 0). it has no + * effect currently + */ + def getThreadInfo(id: Long, maxDepth: Int): ThreadInfo + + /** Returns ThreadInfo for the given thread ids. Returns `null` for the + * corresponding array element if the info is unavailable for the given id + * (thread doesn't exist). + * + * @param ids + * the IDs of the threads, each id must be positive (> 0) + * + * @param maxDepth + * the max depth of a stacktrace, must be non-negative (>= 0). it has no + * effect currently + */ + def getThreadInfo(ids: Array[Long], maxDepth: Int): Array[ThreadInfo] + + /** Returns a [[ThreadInfo]] for every available thread. + * + * An equivalent of `dumpAllThread(lockedMonitors, lockedSynchronizers, 0)`. + * + * @note + * the stacktrace will not be filled. Use overloaded alternative with the + * `maxDepth` parameter to get the stacktrace. + * + * @param lockedMonitors + * whether to dump locked monitors. it has no effect currently + * + * @param lockedSynchronizers + * whether to dump locked synchronizers. it has no effect currently + */ + def dumpAllThreads( + lockedMonitors: Boolean, + lockedSynchronizers: Boolean + ): Array[ThreadInfo] + + /** Returns a [[ThreadInfo]] for every available thread. + * + * @param lockedMonitors + * whether to dump locked monitors. it has no effect currently + * + * @param lockedSynchronizers + * whether to dump locked synchronizers. it has no effect currently + * + * @param maxDepth + * the max depth of a stacktrace, must be non-negative (>= 0). it has no + * effect currently + */ + def dumpAllThreads( + lockedMonitors: Boolean, + lockedSynchronizers: Boolean, + maxDepth: Int + ): Array[ThreadInfo] +} + +object ThreadMXBean { + + private[management] def apply(): ThreadMXBean = + new Impl + + private class Impl extends ThreadMXBean { + def getThreadCount(): Int = + aliveThreads.size + + def getDaemonThreadCount(): Int = + aliveThreads.count(_.thread.isDaemon()) + + @annotation.nowarn // Thread.getId is deprecated since JDK 19 + def getAllThreadIds(): Array[Long] = + aliveThreads.map(_.thread.getId()).toArray + + def getThreadInfo(id: Long): ThreadInfo = + getThreadInfo(id, 0) + + def getThreadInfo(ids: Array[Long]): Array[ThreadInfo] = + getThreadInfo(ids, 0) + + def getThreadInfo(id: Long, maxDepth: Int): ThreadInfo = { + checkThreadId(id) + checkMaxDepth(maxDepth) + + NativeThread.Registry.getById(id).map(t => ThreadInfo(t)).orNull + } + + def getThreadInfo(ids: Array[Long], maxDepth: Int): Array[ThreadInfo] = { + checkMaxDepth(maxDepth) + + ids.map { id => + checkThreadId(id) + NativeThread.Registry.getById(id).map(t => ThreadInfo(t)).orNull + } + } + + def dumpAllThreads( + lockedMonitors: Boolean, + lockedSynchronizers: Boolean + ): Array[ThreadInfo] = + dumpAllThreads(lockedMonitors, lockedSynchronizers, 0) + + def dumpAllThreads( + lockedMonitors: Boolean, + lockedSynchronizers: Boolean, + maxDepth: Int + ): Array[ThreadInfo] = { + checkMaxDepth(maxDepth) + aliveThreads.map(thread => ThreadInfo(thread)).toArray + } + + @inline private def aliveThreads: Iterable[NativeThread] = + NativeThread.Registry.aliveThreads + + @inline private def checkThreadId(id: Long): Unit = + require(id > 0, s"Invalid thread ID parameter: $id") + + @inline private def checkMaxDepth(depth: Int): Unit = + require(depth >= 0, s"Invalid maxDepth parameter: $depth") + } + +} diff --git a/nativelib/src/main/scala/scala/scalanative/runtime/NativeThread.scala b/nativelib/src/main/scala/scala/scalanative/runtime/NativeThread.scala index 33c4729fb2..a8dc4ebc45 100644 --- a/nativelib/src/main/scala/scala/scalanative/runtime/NativeThread.scala +++ b/nativelib/src/main/scala/scala/scalanative/runtime/NativeThread.scala @@ -119,6 +119,15 @@ object NativeThread { _aliveThreads.remove(thread.thread.getId(): @nowarn) } + /** Returns `Some` when a thread with the given id is present in the + * registry and `None` otherwise. + * + * @param id + * the id of the thread to find + */ + def getById(id: Long): Option[NativeThread] = + Option(_aliveThreads.get(id)) + @nowarn def aliveThreads: Iterable[NativeThread] = { import scala.collection.JavaConverters._ diff --git a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala index 6da4697eeb..c5e8752c10 100644 --- a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala +++ b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala @@ -5,6 +5,8 @@ import java.lang.management._ import org.junit.Test import org.junit.Assert._ +import org.scalanative.testsuite.utils.AssertThrows.assertThrows + class ManagementFactoryTest { @Test def getMemoryMXBean(): Unit = { @@ -17,4 +19,28 @@ class ManagementFactoryTest { assertTrue(memoryUsage.getMax() >= 0L) } + @Test def getThreadMXBean(): Unit = { + val bean = ManagementFactory.getThreadMXBean + + assertTrue(bean.getThreadCount() >= 0) + assertTrue(bean.getDaemonThreadCount() >= 0) + assertTrue(bean.getAllThreadIds().length >= 0) + assertTrue(bean.dumpAllThreads(false, false).length >= 0) + assertTrue(bean.dumpAllThreads(true, true).length >= 0) + } + + @Test def threadMXBeanFailOnInvalidInput(): Unit = { + val bean = ManagementFactory.getThreadMXBean + + assertThrows( + classOf[java.lang.IllegalArgumentException], + bean.getThreadInfo(-1L) + ) + + assertThrows( + classOf[java.lang.IllegalArgumentException], + bean.getThreadInfo(1L, -1) + ) + } + } From e3e44066cbd81dbf6684a0172f92c5793713e0ef Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Fri, 23 Aug 2024 23:49:27 +0300 Subject: [PATCH 05/35] feature [nativelib]: implement `java.lang.management..OperatingSystemMXBean` (#4033) --- .../lang/management/ManagementFactory.scala | 11 ++++ .../management/OperatingSystemMXBean.scala | 54 +++++++++++++++++++ .../management/ManagementFactoryTest.scala | 12 +++++ 3 files changed, 77 insertions(+) create mode 100644 javalib/src/main/scala/java/lang/management/OperatingSystemMXBean.scala diff --git a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala index d211fce37d..3ba38614d2 100644 --- a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala +++ b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala @@ -4,6 +4,7 @@ object ManagementFactory { private lazy val MemoryBean = MemoryMXBean() private lazy val ThreadBean = ThreadMXBean() + private lazy val OperatingSystemBean = OperatingSystemMXBean() /** Returns the memory-specific bean. * @@ -28,4 +29,14 @@ object ManagementFactory { */ def getThreadMXBean(): ThreadMXBean = ThreadBean + /** Returns the OS-specific bean. + * + * @example + * {{{ + * val osBean = ManagementFactory.getOperatingSystemMXBean() + * println(s"OS: $${osBean.getName()}") + * }}} + */ + def getOperatingSystemMXBean(): OperatingSystemMXBean = OperatingSystemBean + } diff --git a/javalib/src/main/scala/java/lang/management/OperatingSystemMXBean.scala b/javalib/src/main/scala/java/lang/management/OperatingSystemMXBean.scala new file mode 100644 index 0000000000..6efd836c9a --- /dev/null +++ b/javalib/src/main/scala/java/lang/management/OperatingSystemMXBean.scala @@ -0,0 +1,54 @@ +package java.lang.management + +trait OperatingSystemMXBean { + + /** Returns the name of the operating system. + * + * The equivalent of `sys.props("os.name")`. + */ + def getName(): String + + /** Returns the architecture of the operating system. + * + * The equivalent of `sys.props("os.arch")`. + */ + def getArch(): String + + /** Returns the version of the operating system. + * + * The equivalent of `sys.props("os.version")`. + * + * @note + * the `null` will be returned on Windows and MacOS platforms + */ + def getVersion(): String + + /** Returns the number of processors available to the process, never smaller + * than one. + * + * The equivalent of `Runtime.getRuntime().availableProcessors()`. + */ + def getAvailableProcessors(): Int + +} + +object OperatingSystemMXBean { + + private[management] def apply(): OperatingSystemMXBean = + new Impl + + private class Impl extends OperatingSystemMXBean { + def getName(): String = + System.getProperty("os.name") + + def getArch(): String = + System.getProperty("os.arch") + + def getVersion(): String = + System.getProperty("os.version") + + def getAvailableProcessors(): Int = + Runtime.getRuntime().availableProcessors() + } + +} diff --git a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala index c5e8752c10..7e1b9d21f0 100644 --- a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala +++ b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala @@ -43,4 +43,16 @@ class ManagementFactoryTest { ) } + @Test def getOperatingSystemMXBean(): Unit = { + val bean = ManagementFactory.getOperatingSystemMXBean + + assertEquals(bean.getArch(), System.getProperty("os.arch")) + assertEquals(bean.getName(), System.getProperty("os.name")) + assertEquals(bean.getVersion(), System.getProperty("os.version")) + assertEquals( + bean.getAvailableProcessors(), + Runtime.getRuntime().availableProcessors() + ) + } + } From f813b8e47d856189f8f12eb0adc34de6b827f521 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Wed, 28 Aug 2024 16:23:26 +0300 Subject: [PATCH 06/35] feature [nativelib]: partially implement `RuntimeMXBean` (#4034) 1) Extend `scalanative.runtime`: add `uptime` and `startTime`, record process start time 2) Partially implement `RuntimeMXBean` --- .../lang/management/ManagementFactory.scala | 11 ++ .../java/lang/management/RuntimeMXBean.scala | 131 ++++++++++++++++++ .../scala/scalanative/runtime/package.scala | 3 + .../scalanative/runtime/package.state.scala | 1 + .../management/ManagementFactoryTest.scala | 20 +++ 5 files changed, 166 insertions(+) create mode 100644 javalib/src/main/scala/java/lang/management/RuntimeMXBean.scala diff --git a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala index 3ba38614d2..0de4a72b1b 100644 --- a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala +++ b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala @@ -5,6 +5,7 @@ object ManagementFactory { private lazy val MemoryBean = MemoryMXBean() private lazy val ThreadBean = ThreadMXBean() private lazy val OperatingSystemBean = OperatingSystemMXBean() + private lazy val RuntimeBean = RuntimeMXBean() /** Returns the memory-specific bean. * @@ -39,4 +40,14 @@ object ManagementFactory { */ def getOperatingSystemMXBean(): OperatingSystemMXBean = OperatingSystemBean + /** Returns the runtime-specific bean. + * + * @example + * {{{ + * val runtimeBean = ManagementFactory.getRuntimeMXBean() + * println(s"pid: $${runtimeBean.getPid()}") + * }}} + */ + def getRuntimeMXBean(): RuntimeMXBean = RuntimeBean + } diff --git a/javalib/src/main/scala/java/lang/management/RuntimeMXBean.scala b/javalib/src/main/scala/java/lang/management/RuntimeMXBean.scala new file mode 100644 index 0000000000..90efd22485 --- /dev/null +++ b/javalib/src/main/scala/java/lang/management/RuntimeMXBean.scala @@ -0,0 +1,131 @@ +package java.lang.management + +trait RuntimeMXBean { + + /** Returns the process ID of the running virtual machine (process). + * + * @since 10 + */ + def getPid(): Long + + /** Returns the name of the running virtual machine (process). + */ + def getName(): String + + /** Returns the name of the virtual machine implementation. + * + * The equivalent of `sys.props("java.vm.name")`. + */ + def getVmName(): String + + /** Returns the vendor of the virtual machine implementation. + * + * The equivalent of `sys.props("java.vm.vendor")`. + */ + def getVmVendor(): String + + /** Returns the version of the virtual machine implementation. + * + * The equivalent of `sys.props("java.vm.version")`. + */ + def getVmVersion(): String + + /** Returns the name of the virtual machine specification. + * + * The equivalent of `sys.props("java.vm.specification.name")`. + */ + def getSpecName(): String + + /** Returns the vendor of the virtual machine specification. + * + * The equivalent of `sys.props("java.vm.specification.vendor")`. + */ + def getSpecVendor(): String + + /** Returns the version of the virtual machine specification. + * + * The equivalent of `sys.props("java.vm.specification.version")`. + */ + def getSpecVersion(): String + + /** Returns the uptime of the virtual machine (process) in milliseconds. + */ + def getUptime(): Long + + /** Returns the start time of the virtual machine (process) in milliseconds. + */ + def getStartTime(): Long + + /** Returns a map of names and values of the system properties whose name and + * value is represented as a string. + */ + def getSystemProperties(): java.util.Map[String, String] +} + +object RuntimeMXBean { + + private[management] def apply(): RuntimeMXBean = + new Impl + + private class Impl extends RuntimeMXBean { + import scala.scalanative.unsafe._ + import scala.scalanative.posix._ + import scala.scalanative.unsigned._ + + def getPid(): Long = + unistd.getpid() + + def getName(): String = { + val pid = getPid() + + // InetAddress.getLocalHost returns IP (e.g. /127.0.0.1) while we need the name + val hostname = { + val hostNameLength = unistd._SC_HOST_NAME_MAX.toCSize + val hostName = stackalloc[Byte](hostNameLength) + if (unistd.gethostname(hostName, hostNameLength) == 0) { + fromCString(hostName) + } else { + "localhost" + } + } + + pid + "@" + hostname + } + + def getVmName(): String = + System.getProperty("java.vm.name") + + def getVmVendor(): String = + System.getProperty("java.vm.vendor") + + def getVmVersion(): String = + System.getProperty("java.vm.version") + + def getSpecName(): String = + System.getProperty("java.vm.specification.name") + + def getSpecVendor(): String = + System.getProperty("java.vm.specification.vendor") + + def getSpecVersion(): String = + System.getProperty("java.vm.specification.version") + + def getUptime(): Long = + scalanative.runtime.uptime + + def getStartTime(): Long = + scalanative.runtime.startTime + + def getSystemProperties(): java.util.Map[String, String] = { + val result = new java.util.HashMap[String, String]() + System.getProperties().forEach { (key, value) => + (key, value) match { + case (k: String, v: String) => result.put(k, v) + case _ => + } + } + result + } + } + +} diff --git a/nativelib/src/main/scala/scala/scalanative/runtime/package.scala b/nativelib/src/main/scala/scala/scalanative/runtime/package.scala index aab6d08778..1972887df1 100644 --- a/nativelib/src/main/scala/scala/scalanative/runtime/package.scala +++ b/nativelib/src/main/scala/scala/scalanative/runtime/package.scala @@ -11,6 +11,8 @@ import java.util.concurrent.locks.LockSupport package object runtime { def filename = ExecInfo.filename + def startTime: Long = ExecInfo.startTime + def uptime: Long = System.currentTimeMillis() - startTime /** Used as a stub right hand of intrinsified methods. */ private[scalanative] def intrinsic: Nothing = throwUndefined() @@ -73,6 +75,7 @@ package object runtime { } ExecInfo.filename = fromCString(argv(0)) + ExecInfo.startTime = System.currentTimeMillis() args } diff --git a/nativelib/src/main/scala/scala/scalanative/runtime/package.state.scala b/nativelib/src/main/scala/scala/scalanative/runtime/package.state.scala index 9648f99b6e..47a82b94c9 100644 --- a/nativelib/src/main/scala/scala/scalanative/runtime/package.state.scala +++ b/nativelib/src/main/scala/scala/scalanative/runtime/package.state.scala @@ -22,4 +22,5 @@ private[scalanative] object MainThreadShutdownContext { private object ExecInfo { var filename: String = null + var startTime: Long = 0L } diff --git a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala index 7e1b9d21f0..b7d78d66f4 100644 --- a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala +++ b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala @@ -55,4 +55,24 @@ class ManagementFactoryTest { ) } + @Test def getRuntimeMXBean(): Unit = { + val bean = ManagementFactory.getRuntimeMXBean + + assertEquals(bean.getVmName(), sys.props("java.vm.name")) + assertEquals(bean.getVmVendor(), sys.props("java.vm.vendor")) + assertEquals(bean.getVmVersion(), sys.props("java.vm.version")) + assertEquals(bean.getSpecName(), sys.props("java.vm.specification.name")) + assertEquals( + bean.getSpecVendor(), + sys.props("java.vm.specification.vendor") + ) + assertEquals( + bean.getSpecVersion(), + sys.props("java.vm.specification.version") + ) + assertTrue(bean.getUptime() > 0L) + assertTrue(bean.getStartTime() > 0L) + assertTrue(bean.getSystemProperties().size() > 0) + } + } From 288cfd641a277ec66ecb9b5a2d9ce6f1f8370a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BE=AA?= Date: Thu, 29 Aug 2024 01:31:37 +1200 Subject: [PATCH 07/35] Fix compilation error of _CS_PATH for Termux on Android (#4037) --- posixlib/src/main/resources/scala-native/unistd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/posixlib/src/main/resources/scala-native/unistd.c b/posixlib/src/main/resources/scala-native/unistd.c index 1d2be7b4f6..90adeab205 100644 --- a/posixlib/src/main/resources/scala-native/unistd.c +++ b/posixlib/src/main/resources/scala-native/unistd.c @@ -35,6 +35,11 @@ #define _SC_TRACE_USER_EVENT_MAX 0 #endif // __FreeBSD__ || __OpenBSD__ || __NetBSD__ +#if defined(__ANDROID__) && !defined(_CS_PATH) +// Termux does not define _CS_PATH. We follow the same approach as BSD. +#define _CS_PATH 0 +#endif + long scalanative__posix_version() { return _POSIX_VERSION; } int scalanative__xopen_version() { return _XOPEN_VERSION; } From 4f707259a8d027eb00573fe0641a65bb63ed1adc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:33:03 +0200 Subject: [PATCH 08/35] build(deps): bump VirtusLab/scala-cli-setup from 1.4 to 1.5 (#4038) Bumps [VirtusLab/scala-cli-setup](https://github.com/virtuslab/scala-cli-setup) from 1.4 to 1.5. - [Release notes](https://github.com/virtuslab/scala-cli-setup/releases) - [Commits](https://github.com/virtuslab/scala-cli-setup/compare/v1.4...v1.5) --- updated-dependencies: - dependency-name: VirtusLab/scala-cli-setup dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/run-tests-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests-linux.yml b/.github/workflows/run-tests-linux.yml index 7af805178a..d3d13eb59c 100644 --- a/.github/workflows/run-tests-linux.yml +++ b/.github/workflows/run-tests-linux.yml @@ -245,7 +245,7 @@ jobs: # Make sure that Scala partest denylisted tests contain only valid test names - name: Setup Scala-cli - uses: VirtusLab/scala-cli-setup@v1.4 + uses: VirtusLab/scala-cli-setup@v1.5 - name: Check partest disabled tests list # No partests support for Scala 3 From 7948b7bd37af601f579a5dfd97da24c6e2656bca Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Wed, 28 Aug 2024 16:33:20 +0300 Subject: [PATCH 09/35] feature [windowslib]: add `GetProcessTimes` to the `ProcessThreadsApi` (#4035) --- .../windowslib/ProcessThreadsApiTest.scala | 41 +++++++++++++++++++ .../windows/ProcessThreadsApi.scala | 10 +++++ 2 files changed, 51 insertions(+) create mode 100644 unit-tests/native/src/test/scala/org/scalanative/testsuite/windowslib/ProcessThreadsApiTest.scala diff --git a/unit-tests/native/src/test/scala/org/scalanative/testsuite/windowslib/ProcessThreadsApiTest.scala b/unit-tests/native/src/test/scala/org/scalanative/testsuite/windowslib/ProcessThreadsApiTest.scala new file mode 100644 index 0000000000..4eeff69843 --- /dev/null +++ b/unit-tests/native/src/test/scala/org/scalanative/testsuite/windowslib/ProcessThreadsApiTest.scala @@ -0,0 +1,41 @@ +package org.scalanative.testsuite.windowslib + +import org.junit.Test +import org.junit.Assert._ + +import scala.scalanative.meta.LinktimeInfo.isWindows +import scala.scalanative.unsafe._ +import scala.scalanative.windows.MinWinBaseApi.FileTimeStruct +import scala.scalanative.windows.MinWinBaseApiOps._ +import scala.scalanative.windows.ProcessThreadsApi + +class ProcessThreadsApiTest { + + @Test def testGetProcessTimes(): Unit = if (isWindows) { + val creationTime = stackalloc[FileTimeStruct]() + val exitTime = stackalloc[FileTimeStruct]() + val kernelTime = stackalloc[FileTimeStruct]() + val userTime = stackalloc[FileTimeStruct]() + + val result = ProcessThreadsApi.GetProcessTimes( + ProcessThreadsApi.GetCurrentProcess(), + creationTime, + exitTime, + kernelTime, + userTime + ) + + assertTrue("result is false", result) + + assertTrue( + s"kernelTime [${kernelTime.fileTime}] < 0", + kernelTime.fileTime.toLong >= 0L + ) + + assertTrue( + s"userTime [${userTime.fileTime}] < 0", + userTime.fileTime.toLong >= 0L + ) + } + +} diff --git a/windowslib/src/main/scala/scala/scalanative/windows/ProcessThreadsApi.scala b/windowslib/src/main/scala/scala/scalanative/windows/ProcessThreadsApi.scala index a9ebb55b56..f3f5439ce7 100644 --- a/windowslib/src/main/scala/scala/scalanative/windows/ProcessThreadsApi.scala +++ b/windowslib/src/main/scala/scala/scalanative/windows/ProcessThreadsApi.scala @@ -3,6 +3,7 @@ package scala.scalanative.windows import scala.scalanative.unsafe.{Word => _, _} import scalanative.unsigned._ import HandleApi.Handle +import MinWinBaseApi.FileTimeStruct import WinBaseApi.SecurityAttributes @link("advapi32") @@ -59,6 +60,15 @@ object ProcessThreadsApi { extern def GetProcessId(handle: Handle): DWord = extern + + def GetProcessTimes( + handle: Handle, + creationTime: Ptr[FileTimeStruct], + exitTime: Ptr[FileTimeStruct], + kernelTime: Ptr[FileTimeStruct], + userTime: Ptr[FileTimeStruct] + ): Boolean = extern + def OpenThreadToken( thread: Handle, desiredAccess: DWord, From b16ed264fe059bff8997ad3010a781528d9ca3ac Mon Sep 17 00:00:00 2001 From: Eric K Richardson Date: Mon, 2 Sep 2024 02:21:40 -0700 Subject: [PATCH 10/35] [docs] Update source debug docs (#4041) --- docs/user/testing.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/user/testing.md b/docs/user/testing.md index ec7802c45b..470f66b905 100644 --- a/docs/user/testing.md +++ b/docs/user/testing.md @@ -48,10 +48,12 @@ LLVM optimizers can remove some of the optimized out debug informations. For best experience run with disabled optimizations: ```scala -nativeConfig ~= { - .withSourceLevelDebuggingConfig(_.enableAll) // enable generation of debug informations +import scala.scalanative.build._ + +nativeConfig ~= { c => + c.withSourceLevelDebuggingConfig(_.enableAll) // enable generation of debug information .withOptimize(false) // disable Scala Native optimizer - .withMode(scalanative.build.Mode.debug) // compile using LLVM without optimizations + .withMode(Mode.debug) // compile using LLVM without optimizations } ``` From 4e09773c45099dc2fe8bd208040179c4c228185d Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Tue, 3 Sep 2024 23:06:14 +0200 Subject: [PATCH 11/35] [chore] Add Scala 2.12.20 to the build (#4043) --- project/ScalaVersions.scala | 2 +- .../resources/2.12.20/DenylistedTests.txt | 192 +++ .../scalanative/2.12.20/DenylistedTests.txt | 1089 +++++++++++++++++ .../scalanative/2.12.20/neg/t11952b.check | 17 + .../2.12.20/neg/t6446-additional.check | 29 + .../scalanative/2.12.20/neg/t6446-list.check | 2 + .../2.12.20/neg/t6446-missing.check | 29 + .../2.12.20/neg/t6446-show-phases.check | 28 + .../2.12.20/neg/t7494-no-options.check | 30 + .../scalanative/2.12.20/run/classof.check | 22 + .../2.12.20/run/classtags_contextbound.check | 1 + .../2.12.20/run/classtags_multi.check | 5 + .../2.12.20/run/getClassTest-valueClass.check | 2 + ...interop_classtags_are_classmanifests.check | 3 + .../scalanative/2.12.20/run/t4753.check | 1 + .../scalanative/2.12.20/run/t5568.check | 9 + .../scalanative/2.12.20/run/t5923b.check | 3 + .../2.12.20/run/t6318_primitives.check | 54 + 18 files changed, 1517 insertions(+), 1 deletion(-) create mode 100644 scala-partest-junit-tests/src/test/resources/2.12.20/DenylistedTests.txt create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/DenylistedTests.txt create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t11952b.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-additional.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-list.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-missing.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-show-phases.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t7494-no-options.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classof.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_contextbound.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_multi.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/getClassTest-valueClass.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/interop_classtags_are_classmanifests.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t4753.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5568.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5923b.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t6318_primitives.check diff --git a/project/ScalaVersions.scala b/project/ScalaVersions.scala index d386ebd1f4..45a131249e 100644 --- a/project/ScalaVersions.scala +++ b/project/ScalaVersions.scala @@ -18,7 +18,7 @@ package build object ScalaVersions { // Versions of Scala used for publishing compiler plugins - val crossScala212 = crossScalaVersions("2.12", 14 to 19) + val crossScala212 = crossScalaVersions("2.12", 14 to 20) val crossScala213 = crossScalaVersions("2.13", 8 to 14) val crossScala3 = List( extraCrossScalaVersion("3.").toList, diff --git a/scala-partest-junit-tests/src/test/resources/2.12.20/DenylistedTests.txt b/scala-partest-junit-tests/src/test/resources/2.12.20/DenylistedTests.txt new file mode 100644 index 0000000000..5f98f3e80f --- /dev/null +++ b/scala-partest-junit-tests/src/test/resources/2.12.20/DenylistedTests.txt @@ -0,0 +1,192 @@ +## Do not compile +scala/lang/annotations/BytecodeTest.scala +scala/lang/annotations/RunTest.scala +scala/lang/traits/BytecodeTest.scala +scala/lang/traits/RunTest.scala +scala/lang/primitives/NaNTest.scala +scala/lang/primitives/BoxUnboxTest.scala +scala/lang/stringinterpol/StringContextTest.scala +scala/collection/SeqTest.scala +scala/collection/Sizes.scala +scala/collection/SetMapConsistencyTest.scala +scala/collection/mutable/OpenHashMapTest.scala +scala/collection/immutable/ListTest.scala +scala/collection/immutable/ListMapTest.scala +scala/collection/immutable/HashMapTest.scala +scala/collection/immutable/HashSetTest.scala +scala/collection/immutable/MapHashcodeTest.scala +scala/collection/immutable/SetTest.scala +scala/collection/immutable/SeqTest.scala +scala/collection/immutable/SmallMapTest.scala +scala/collection/immutable/SortedMapTest.scala +scala/collection/immutable/SortedSetTest.scala +scala/collection/immutable/TreeMapTest.scala +scala/collection/immutable/TreeSetTest.scala +scala/reflect/ClassOfTest.scala +scala/reflect/QTest.scala +scala/reflect/io/AbstractFileTest.scala +scala/reflect/io/ZipArchiveTest.scala +scala/reflect/internal/util/AbstractFileClassLoaderTest.scala +scala/reflect/internal/util/FileUtilsTest.scala +scala/reflect/internal/util/SourceFileTest.scala +scala/reflect/internal/util/StringOpsTest.scala +scala/reflect/internal/util/WeakHashSetTest.scala +scala/reflect/internal/LongNamesTest.scala +scala/reflect/internal/MirrorsTest.scala +scala/reflect/internal/NamesTest.scala +scala/reflect/internal/PositionsTest.scala +scala/reflect/internal/PrintersTest.scala +scala/reflect/internal/ScopeTest.scala +scala/reflect/internal/TreeGenTest.scala +scala/reflect/internal/TypesTest.scala +scala/reflect/runtime/ReflectionUtilsShowTest.scala +scala/reflect/runtime/ThreadSafetyTest.scala +scala/tools/cmd/CommandLineParserTest.scala +scala/tools/nsc/Build.scala +scala/tools/nsc/DeterminismTest.scala +scala/tools/nsc/DeterminismTester.scala +scala/tools/nsc/FileUtils.scala +scala/tools/nsc/GlobalCustomizeClassloaderTest.scala +scala/tools/nsc/PickleWriteTest.scala +scala/tools/nsc/PipelineMainTest.scala +scala/tools/nsc/async/AnnotationDrivenAsync.scala +scala/tools/nsc/async/CustomFuture.scala +scala/tools/nsc/backend/jvm/ClassfileParserTest.scala +scala/tools/nsc/backend/jvm/PerRunInitTest.scala +scala/tools/nsc/backend/jvm/BTypesTest.scala +scala/tools/nsc/backend/jvm/BytecodeTest.scala +scala/tools/nsc/backend/jvm/DefaultMethodTest.scala +scala/tools/nsc/backend/jvm/DirectCompileTest.scala +scala/tools/nsc/backend/jvm/GenericSignaturesTest.scala +scala/tools/nsc/backend/jvm/IndyLambdaTest.scala +scala/tools/nsc/backend/jvm/IndySammyTest.scala +scala/tools/nsc/backend/jvm/InnerClassAttributeTest.scala +scala/tools/nsc/backend/jvm/NestedClassesCollectorTest.scala +scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala +scala/tools/nsc/backend/jvm/StringConcatTest.scala +scala/tools/nsc/backend/jvm/IndyLambdaDirectTest.scala +scala/tools/nsc/backend/jvm/LineNumberTest.scala +scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala +scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala +scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala +scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala +scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala +scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala +scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala +scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala +scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala +scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala +scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala +scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala +scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala +scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala +scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +scala/tools/nsc/backend/jvm/opt/InlineSourceMatcherTest.scala +scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala +scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala +scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala +scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala +scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala +scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala +scala/tools/nsc/ScriptRunnerTest.scala +scala/tools/nsc/classpath/AggregateClassPathTest.scala +scala/tools/nsc/classpath/JrtClassPathTest.scala +scala/tools/nsc/classpath/MultiReleaseJarTest.scala +scala/tools/nsc/classpath/PathResolverBaseTest.scala +scala/tools/nsc/classpath/VirtualDirectoryClassPathTest.scala +scala/tools/nsc/classpath/ZipAndJarFileLookupFactoryTest.scala +scala/tools/nsc/doc/html/HtmlDocletTest.scala +scala/tools/nsc/interpreter/CompletionTest.scala +scala/tools/nsc/interpreter/ScriptedTest.scala +scala/tools/nsc/interpreter/TabulatorTest.scala +scala/tools/nsc/parser/ParserTest.scala +scala/tools/nsc/reporters/ConsoleReporterTest.scala +scala/tools/nsc/reporters/WConfTest.scala +scala/tools/nsc/settings/ScalaVersionTest.scala +scala/tools/nsc/settings/SettingsTest.scala +scala/tools/nsc/settings/TargetTest.scala +scala/tools/nsc/symtab/CannotHaveAttrsTest.scala +scala/tools/nsc/symtab/FlagsTest.scala +scala/tools/nsc/symtab/FreshNameExtractorTest.scala +scala/tools/nsc/symtab/StdNamesTest.scala +scala/tools/nsc/symtab/SymbolLoadersAssociatedFileTest.scala +scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +scala/tools/nsc/symtab/SymbolTableTest.scala +scala/tools/nsc/symtab/classfile/PicklerTest.scala +scala/tools/nsc/transform/MixinTest.scala +scala/tools/nsc/transform/SpecializationTest.scala +scala/tools/nsc/transform/ThicketTransformerTest.scala +scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala +scala/tools/nsc/transform/patmat/SolvingTest.scala +scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala +scala/tools/nsc/typechecker/Implicits.scala +scala/tools/nsc/typechecker/NamerTest.scala +scala/tools/nsc/typechecker/ParamAliasTest.scala +scala/tools/nsc/typechecker/TypedTreeTest.scala +scala/tools/nsc/typechecker/TreeAttachmentTest.scala +scala/tools/nsc/util/StackTraceTest.scala +scala/tools/testing/AllocationTest.scala +scala/tools/testing/BytecodeTesting.scala +scala/tools/testing/JOL.scala +scala/tools/testing/RunTesting.scala +scala/tools/testing/VirtualCompilerTesting.scala +scala/runtime/BooleanBoxingTest.scala +scala/runtime/ByteBoxingTest.scala +scala/runtime/CharBoxingTest.scala +scala/runtime/ShortBoxingTest.scala +scala/runtime/IntBoxingTest.scala +scala/runtime/LongBoxingTest.scala +scala/runtime/DoubleBoxingTest.scala +scala/runtime/FloatBoxingTest.scala + +#============== +## Do not link +# Defines stubs +scala/collection/mutable/AnyRefMapTest.scala + + +#j.l.reflect.Modifier +scala/reflect/macros/AttachmentsTest.scala +scala/collection/IteratorTest.scala +scala/collection/immutable/StringLikeTest.scala +scala/collection/immutable/VectorTest.scala +scala/collection/immutable/ListSetTest.scala +scala/collection/mutable/MutableListTest.scala +scala/collection/mutable/ArrayBufferTest.scala +scala/concurrent/FutureTest.scala +scala/util/SpecVersionTest.scala +scala/tools/testing/AssertUtil.scala +scala/tools/testing/AssertUtilTest.scala +scala/tools/testing/AssertThrowsTest.scala + +#j.i.ObjectStream +scala/PartialFunctionSerializationTest.scala +scala/MatchErrorSerializationTest.scala +scala/concurrent/duration/SerializationTest.scala +scala/collection/convert/WrapperSerializationTest.scala +scala/collection/immutable/RedBlackTreeSerialFormat.scala +scala/collection/mutable/PriorityQueueTest.scala + +#j.io.Piped{Input,Output}Stream +#j.u.c.LinkedBlockingQueue +scala/sys/process/PipedProcessTest.scala + + +# Concurrency primitives +scala/io/SourceTest.scala +scala/sys/process/ProcessTest.scala + +#============ +## Tests fail + +scala/collection/immutable/StreamTest.scala + +### Deadlocks maybe needs j.u.c.ConcurrentLinkedQueue +scala/concurrent/impl/DefaultPromiseTest.scala +scala/collection/parallel/TaskTest.scala +scala/collection/NewBuilderTest.scala + +#===== +## Assumes JUnit 4.12 +scala/collection/immutable/RangeTest.scala +scala/util/matching/RegexTest.scala \ No newline at end of file diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/DenylistedTests.txt b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/DenylistedTests.txt new file mode 100644 index 0000000000..32229d95e3 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/DenylistedTests.txt @@ -0,0 +1,1089 @@ +# Ported from Scala.js, might not be exhaustive enough (some Denylisted tests may actually work in SN) + +# +# POS +# + +# Spuriously fails too often, and causes other subsequent tests to fail too +# Note that this test, by design, stress-tests type checking +pos/t6367.scala + +# +# NEG +# + +# Uses .java files +run/t9200 +run/noInlineUnknownIndy + +# +# RUN +# + +# Tests that ClassTags are cached, which we do not do in Scala.js +# (our ClassTags are better stack-allocated than cached) +run/classtags-cached.scala + +# Relies on the exact toString() representation of Floats/Doubles +run/t2378.scala + +# Using parts of the javalib we don't plan to support + +run/t5018.scala +run/t2417.scala +run/lazy-concurrent.scala +run/t3667.scala +run/t3038d.scala +run/shutdownhooks.scala +run/t5590.scala +run/t3895b.scala +run/t5974.scala +run/t5262.scala +run/serialize-stream.scala +run/lambda-serialization-gc.scala +run/t9390.scala +run/t9390b.scala +run/t9390c.scala +run/trait-defaults-super.scala +run/t2849.scala +run/t10488.scala +run/various-flat-classpath-types.scala + +# Uses j.l.Class stubs +run/t12002.scala +run/t5676.scala + +# Uses java.math.BigDecimal / BigInteger : but failures not due to them +run/is-valid-num.scala + +# Documented semantic difference on String.split(x: Array[Char]) +run/t0325.scala + +# Using Threads +run/inner-obj-auto.scala +run/predef-cycle.scala +run/synchronized.scala +run/sd409.scala + +# Uses java.security +run/t2318.scala + +# Tries to catch java.lang.StackOverflowError +run/t6154.scala + +# Tries to catch java.lang.OutOfMemoryError +run/t7880.scala + +# Requires too much memory (on the JVM, extra memory is given to this test) +run/t11272.scala + +# Taking too much time >60sec + +run/t3989.scala +run/t6253a.scala +run/t6253b.scala +run/t6253c.scala +run/numbereq.scala + +# Using partest properties +run/tailcalls.scala +run/t4294.scala + +# Using IO + +run/t6488.scala +run/t6988.scala + +# Object{Output|Input}Streams +run/defaults-serizaliable-no-forwarders.scala +run/defaults-serizaliable-with-forwarders.scala +run/lambda-serialization-meth-ref.scala +run/red-black-tree-serial +run/red-black-tree-serial-new +run/t6935.scala +run/t8188.scala +run/t9375.scala +run/t9365.scala +run/inlineAddDeserializeLambda.scala +run/sammy_seriazable.scala +run/lambda-serialization-security.scala +run/t10232.scala +run/t10233.scala +run/t10244.scala +run/t10522.scala +run/t11255 +run/transient-object.scala + +# Using System.getProperties + +run/t4426.scala + +# Using Await + +run/t7336.scala +run/t7775.scala +run/t10513.scala +run/future-flatmap-exec-count.scala + +# Using detailed stack trace + +run/t6308.scala + +# Using reflection +run/t6063 + +run/mixin-bridge-methods.scala +run/t5125.scala +run/outertest.scala +run/t6223.scala +run/t5652b +run/elidable-opt.scala +run/nullable-lazyvals.scala +run/t4794.scala +run/t5652 +run/t5652c +run/getClassTest-old.scala +run/t8960.scala +run/t7965.scala +run/t8087.scala +run/t8931.scala +run/t8445.scala +run/t12038a +run/t12038b +run/lambda-serialization.scala + +run/reflection-repl-classes.scala +run/t5256e.scala +run/typetags_core.scala +run/reflection-constructormirror-toplevel-badpath.scala +run/t5276_1b.scala +run/reflection-sorted-decls.scala +run/toolbox_typecheck_implicitsdisabled.scala +run/t5418b.scala +run/toolbox_typecheck_macrosdisabled2.scala +run/abstypetags_serialize.scala +run/all-overridden.scala +run/showraw_tree_kinds.scala +run/showraw_tree_types_ids.scala +run/showraw_tree_types_typed.scala +run/showraw_tree_ids.scala +run/showraw_tree_ultimate.scala +run/t5266_2.scala +run/t5274_1.scala +run/t5224.scala +run/reflection-sanitychecks.scala +run/t6086-vanilla.scala +run/t5277_2.scala +run/reflection-methodsymbol-params.scala +run/reflection-valueclasses-standard.scala +run/t5274_2.scala +run/t5423.scala +run/reflection-modulemirror-toplevel-good.scala +run/t5419.scala +run/t5271_3.scala +run/reflection-enclosed-nested-basic.scala +run/reflection-enclosed-nested-nested-basic.scala +run/fail-non-value-types.scala +run/exprs_serialize.scala +run/t5258a.scala +run/typetags_without_scala_reflect_manifest_lookup.scala +run/t4110-new.scala +run/t5273_2b_newpatmat.scala +run/t6277.scala +run/t5335.scala +run/toolbox_typecheck_macrosdisabled.scala +run/reflection-modulemirror-inner-good.scala +run/t5229_2.scala +run/typetags_multi.scala +run/typetags_without_scala_reflect_typetag_manifest_interop.scala +run/reflection-constructormirror-toplevel-good.scala +run/reflection-magicsymbols-invoke.scala +run/t6392b.scala +run/t5229_1.scala +run/reflection-magicsymbols-vanilla.scala +run/t5225_2.scala +run/runtimeEval1.scala +run/reflection-enclosed-nested-inner-basic.scala +run/reflection-fieldmirror-ctorparam.scala +run/t6181.scala +run/reflection-magicsymbols-repl.scala +run/t5272_2_newpatmat.scala +run/t5270.scala +run/t5418a.scala +run/t5276_2b.scala +run/t5256f.scala +run/reflection-enclosed-basic.scala +run/reflection-constructormirror-inner-badpath.scala +run/interop_typetags_are_manifests.scala +run/newTags.scala +run/t5273_1_newpatmat.scala +run/reflection-constructormirror-nested-good.scala +run/t2236-new.scala +run/existentials3-new.scala +run/t6323b.scala +run/t5943a1.scala +run/reflection-fieldmirror-getsetval.scala +run/t5272_1_oldpatmat.scala +run/t5256h.scala +run/t1195-new.scala +run/t5840.scala +run/reflection-methodsymbol-returntype.scala +run/reflection-fieldmirror-accessorsareokay.scala +run/reflection-sorted-members.scala +run/reflection-allmirrors-tostring.scala +run/valueclasses-typetag-existential.scala +run/toolbox_console_reporter.scala +run/reflection-enclosed-inner-inner-basic.scala +run/t5256b.scala +run/bytecodecs.scala +run/elidable.scala +run/freetypes_false_alarm1.scala +run/freetypes_false_alarm2.scala +run/getClassTest-new.scala +run/idempotency-extractors.scala +run/idempotency-case-classes.scala +run/idempotency-this.scala +run/idempotency-labels.scala +run/idempotency-lazy-vals.scala +run/interop_manifests_are_abstypetags.scala +run/interop_manifests_are_typetags.scala +run/abstypetags_core.scala +run/macro-reify-abstypetag-notypeparams +run/macro-reify-abstypetag-typeparams-tags +run/macro-reify-abstypetag-typeparams-notags +run/macro-reify-abstypetag-usetypetag +run/macro-reify-freevars +run/macro-reify-splice-outside-reify +run/macro-reify-tagless-a +run/macro-reify-type +run/macro-reify-typetag-typeparams-tags +run/macro-reify-typetag-notypeparams +run/macro-undetparams-implicitval +run/manifests-new.scala +run/manifests-old.scala +run/no-pickle-skolems +run/position-val-def.scala +run/reflect-priv-ctor.scala +run/primitive-sigs-2-new.scala +run/primitive-sigs-2-old.scala +run/reflection-enclosed-inner-basic.scala +run/reflection-enclosed-inner-nested-basic.scala +run/reflection-constructormirror-inner-good.scala +run/reflection-constructormirror-nested-badpath.scala +run/reflection-fancy-java-classes +run/reflection-fieldsymbol-navigation.scala +run/reflection-fieldmirror-nmelocalsuffixstring.scala +run/reflection-fieldmirror-getsetvar.scala +run/reflection-fieldmirror-privatethis.scala +run/reflection-implicit.scala +run/reflection-mem-glbs.scala +run/reflection-mem-tags.scala +run/reflection-java-annotations +run/reflection-java-crtp +run/reflection-methodsymbol-typeparams.scala +run/reflection-modulemirror-nested-badpath.scala +run/reflection-modulemirror-inner-badpath.scala +run/reflection-modulemirror-nested-good.scala +run/reflection-modulemirror-toplevel-badpath.scala +run/reflection-sync-subtypes.scala +run/reflinit.scala +run/reflection-valueclasses-derived.scala +run/reflection-valueclasses-magic.scala +run/resetattrs-this.scala +run/runtimeEval2.scala +run/showraw_aliases.scala +run/showraw_mods.scala +run/shortClass.scala +run/showraw_nosymbol.scala +run/showraw_tree.scala +run/showraw_tree_types_untyped.scala +run/t1167.scala +run/t2577.scala +run/t2873.scala +run/t2886.scala +run/t3346j.scala +run/t3507-new.scala +run/t3569.scala +run/t5125b.scala +run/t5225_1.scala +run/t3425b +run/t5256a.scala +run/t5230.scala +run/t5256c.scala +run/t5256g.scala +run/t5266_1.scala +run/t5269.scala +run/t5271_1.scala +run/t5271_2.scala +run/t5271_4.scala +run/t5272_1_newpatmat.scala +run/t5272_2_oldpatmat.scala +run/t5273_1_oldpatmat.scala +run/t5273_2a_newpatmat.scala +run/t5273_2a_oldpatmat.scala +run/t5275.scala +run/t5276_1a.scala +run/t5276_2a.scala +run/t5277_1.scala +run/t5279.scala +run/t5334_1.scala +run/t5334_2.scala +run/t5415.scala +run/t5418.scala +run/t5704.scala +run/t5710-1.scala +run/t5710-2.scala +run/t5770.scala +run/t5894.scala +run/t5816.scala +run/t5824.scala +run/t5912.scala +run/t5942.scala +run/t5943a2.scala +run/t6023.scala +run/t6113.scala +run/t6175.scala +run/t6178.scala +run/t6199-mirror.scala +run/t6199-toolbox.scala +run/t6240-universe-code-gen.scala +run/t6221 +run/t6260b.scala +run/t6259.scala +run/t6287.scala +run/t6344.scala +run/t6392a.scala +run/t6591_1.scala +run/t6591_2.scala +run/t6591_3.scala +run/t6591_5.scala +run/t6591_6.scala +run/t6591_7.scala +run/t6608.scala +run/t6677.scala +run/t6687.scala +run/t6715.scala +run/t6719.scala +run/t6793.scala +run/t6860.scala +run/t6793b.scala +run/t6793c.scala +run/t7045.scala +run/t7046.scala +run/t7008-scala-defined +run/t7120b.scala +run/t7151.scala +run/t7214.scala +run/t7235.scala +run/t7331a.scala +run/t7331b.scala +run/t7331c.scala +run/t7558.scala +run/t7556 +run/t7779.scala +run/t7868b.scala +run/toolbox_current_run_compiles.scala +run/toolbox_default_reporter_is_silent.scala +run/toolbox_parse_package.scala +run/toolbox_silent_reporter.scala +run/toolbox_typecheck_inferimplicitvalue.scala +run/typetags_serialize.scala +run/valueclasses-typetag-basic.scala +run/WeakHashSetTest.scala +run/valueclasses-typetag-generic.scala +run/t4023.scala +run/t4024.scala +run/t6380.scala +run/t5273_2b_oldpatmat.scala +run/t8104 +run/t8047.scala +run/t6992 +run/var-arity-class-symbol.scala +run/typetags_symbolof_x.scala +run/typecheck +run/t8190.scala +run/t8192 +run/t8177f.scala +run/t7932.scala +run/t7700.scala +run/t7570c.scala +run/t7570b.scala +run/t7533.scala +run/t7570a.scala +run/t7044 +run/t7328.scala +run/t6733.scala +run/t6554.scala +run/t6732.scala +run/t6379 +run/t6411b.scala +run/t6411a.scala +run/t6260c.scala +run/t6260-delambdafy.scala +run/showdecl +run/reflection-sync-potpourri.scala +run/reflection-tags.scala +run/reflection-companiontype.scala +run/reflection-scala-annotations.scala +run/reflection-idtc.scala +run/macro-reify-nested-b2 +run/mixin-signatures.scala +run/reflection-companion.scala +run/macro-reify-nested-b1 +run/macro-reify-nested-a2 +run/macro-reify-nested-a1 +run/macro-reify-chained2 +run/macro-reify-chained1 +run/inferred-type-constructors.scala +run/mirror_symbolof_x.scala +run/t8196.scala +run/t8549b.scala +run/t8574.scala +run/t8637.scala +run/t6622.scala +run/toolbox_expand_macro.scala +run/toolbox-varargs +run/t9252.scala +run/t9182.scala +run/t9102.scala +run/t720.scala +run/t9408.scala +run/t10527.scala +run/t10650 +run/trait-default-specialize.scala +run/lazy-locals-2.scala +run/t5294.scala +run/trait_fields_final.scala +run/trait_fields_bytecode.scala +run/trait_fields_volatile.scala +run/junitForwarders +run/reflect-java-param-names +run/t2251b.scala +run/t8253.scala +run/t9027.scala + +run/reify_classfileann_a.scala +run/reify_classfileann_b.scala +run/reify_newimpl_29.scala +run/reify_magicsymbols.scala +run/reify_inheritance.scala +run/reify_newimpl_12.scala +run/reify_typerefs_2b.scala +run/reify_csv.scala +run/reify_inner2.scala +run/reify_maps_oldpatmat.scala +run/reify_newimpl_43.scala +run/reify_nested_inner_refers_to_local.scala +run/reify_closure7.scala +run/reify_closure8b.scala +run/reify_typerefs_3b.scala +run/reify_newimpl_44.scala +run/reify_newimpl_06.scala +run/reify_newimpl_05.scala +run/reify_newimpl_20.scala +run/reify_newimpl_23.scala +run/reify_metalevel_breach_-1_refers_to_1.scala +run/reify_newimpl_41.scala +run/reify-repl-fail-gracefully.scala +run/reify_fors_oldpatmat.scala +run/reify_inner3.scala +run/reify_closure8a.scala +run/reify_closures10.scala +run/reify_ann2a.scala +run/reify_newimpl_51.scala +run/reify_newimpl_47.scala +run/reify_extendbuiltins.scala +run/reify_newimpl_30.scala +run/reify_newimpl_38.scala +run/reify_closure2a.scala +run/reify_newimpl_45.scala +run/reify_closure1.scala +run/reify_generic2.scala +run/reify_printf.scala +run/reify_closure6.scala +run/reify_newimpl_37.scala +run/reify_newimpl_35.scala +run/reify_typerefs_3a.scala +run/reify_newimpl_25.scala +run/reify_ann4.scala +run/reify_typerefs_1b.scala +run/reify_newimpl_22.scala +run/reify_this.scala +run/reify_typerefs_2a.scala +run/reify_newimpl_03.scala +run/reify_newimpl_48.scala +run/reify_varargs.scala +run/reify_newimpl_42.scala +run/reify_newimpl_15.scala +run/reify_nested_inner_refers_to_global.scala +run/reify_newimpl_02.scala +run/reify_newimpl_01.scala +run/reify_fors_newpatmat.scala +run/reify_nested_outer_refers_to_local.scala +run/reify_newimpl_13.scala +run/reify_closure5a.scala +run/reify_inner4.scala +run/reify_sort.scala +run/reify_ann1a.scala +run/reify_closure4a.scala +run/reify_newimpl_33.scala +run/reify_sort1.scala +run/reify_properties.scala +run/reify_generic.scala +run/reify_newimpl_27.scala +run/reify-aliases.scala +run/reify_ann3.scala +run/reify-staticXXX.scala +run/reify_ann1b.scala +run/reify_ann5.scala +run/reify_anonymous.scala +run/reify-each-node-type.scala +run/reify_copypaste2.scala +run/reify_closure3a.scala +run/reify_copypaste1.scala +run/reify_complex.scala +run/reify_for1.scala +run/reify_getter.scala +run/reify_implicits-new.scala +run/reify_inner1.scala +run/reify_implicits-old.scala +run/reify_lazyunit.scala +run/reify_lazyevaluation.scala +run/reify_maps_newpatmat.scala +run/reify_metalevel_breach_+0_refers_to_1.scala +run/reify_metalevel_breach_-1_refers_to_0_a.scala +run/reify_metalevel_breach_-1_refers_to_0_b.scala +run/reify_nested_outer_refers_to_global.scala +run/reify_newimpl_04.scala +run/reify_newimpl_14.scala +run/reify_newimpl_11.scala +run/reify_newimpl_18.scala +run/reify_newimpl_19.scala +run/reify_newimpl_31.scala +run/reify_newimpl_21.scala +run/reify_newimpl_36.scala +run/reify_newimpl_39.scala +run/reify_newimpl_40.scala +run/reify_newimpl_49.scala +run/reify_newimpl_50.scala +run/reify_newimpl_52.scala +run/reify_renamed_term_basic.scala +run/reify_renamed_term_local_to_reifee.scala +run/reify_renamed_term_overloaded_method.scala +run/reify_renamed_type_basic.scala +run/reify_renamed_type_local_to_reifee.scala +run/reify_renamed_type_spliceable.scala +run/reify_typerefs_1a.scala +run/reify_timeofday.scala +run/reify_renamed_term_t5841.scala + +run/t7521b.scala +run/t8575b.scala +run/t8575c.scala +run/t8944c.scala +run/t9535.scala +run/t9437a +run/t9814.scala +run/t10009.scala +run/t10075.scala +run/t10075b + +run/t8756.scala +run/inferred-type-constructors-hou.scala +run/trait-static-forwarder +run/SD-235.scala +run/t10026.scala +run/checkinit.scala +run/reflection-clinit +run/reflection-clinit-nested +run/t10487.scala + +run/typetags_caching.scala +run/type-tag-leak.scala +run/t10856.scala + +# Uses reflection indirectly through +# scala.runtime.ScalaRunTime.replStringOf +run/t6634.scala + +# Using reflection to invoke macros. These tests actually don't require +# or test reflection, but use it to separate compilation units nicely. +# It's a pity we cannot use them + +run/macro-abort-fresh +run/macro-expand-varargs-explicit-over-nonvarargs-bad +run/macro-invalidret-doesnt-conform-to-def-rettype +run/macro-invalidret-nontypeable +run/macro-invalidusage-badret +run/macro-invalidusage-partialapplication +run/macro-invalidusage-partialapplication-with-tparams +run/macro-reflective-ma-normal-mdmi +run/macro-reflective-mamd-normal-mi + +# Using macros, but indirectly creating calls to reflection +run/macro-reify-unreify + +# Using Enumeration in a way we cannot fix + +run/enums.scala +run/t3719.scala +run/t8611b.scala + +# Expecting exceptions that are linking errors in Scala.js (e.g. NoSuchMethodException) +run/t10334.scala + +# Playing with classfile format + +run/classfile-format-51.scala +run/classfile-format-52.scala + +# Concurrent collections (TrieMap) +# has too much stuff implemented in *.java, so no support +run/triemap-hash.scala + +# Using parallel collections +run/hashset.scala +run/t8549.scala +run/t5375.scala +run/t4894.scala +run/ctries-new +run/collection-conversions.scala +run/concurrent-map-conversions.scala +run/t4761.scala +run/t7498.scala +run/t6448.scala +run/ctries-old +run/map_java_conversions.scala +run/parmap-ops.scala +run/pc-conversions.scala +run/t4459.scala +run/t4608.scala +run/t4723.scala +run/t4895.scala +run/t6052.scala +run/t6410.scala +run/t6467.scala +run/t6908.scala +run/t8955.scala + +# Using scala.xml + +run/t4124.scala + +# Using Swing + +run/t3613.scala + +# Using the REPL + +run/t4285.scala +run/constant-type.scala +run/repl-bare-expr.scala +run/repl-parens.scala +run/repl-assign.scala +run/t5583.scala +run/treePrint.scala +run/constrained-types.scala +run/repl-power.scala +run/t4710.scala +run/repl-paste.scala +run/repl-reset.scala +run/repl-paste-3.scala +run/t6329_repl.scala +run/t6273.scala +run/repl-paste-2.scala +run/t5655.scala +run/t5072.scala +run/repl-colon-type.scala +run/repl-trim-stack-trace.scala +run/t4594-repl-settings.scala +run/repl-save.scala +run/repl-paste-raw.scala +run/repl-paste-4.scala +run/t7801.scala +run/repl-backticks.scala +run/t6633.scala +run/repl-inline.scala +run/repl-class-based-term-macros.scala +run/repl-always-use-instance.scala +run/repl-class-based-implicit-import.scala +run/repl-class-based-value-class.scala +run/repl-deadlock.scala +run/repl-class-based-outer-pointers.scala +run/repl-class-based-escaping-reads.scala + +# Using the Repl (scala.tools.partest.ReplTest) +run/class-symbol-contravariant.scala +run/lub-visibility.scala +run/macro-bundle-repl.scala +run/macro-repl-basic.scala +run/macro-repl-dontexpand.scala +run/macro-system-properties.scala +run/reflection-equality.scala +run/reflection-repl-elementary.scala +run/reify_newimpl_26.scala +run/repl-out-dir.scala +run/repl-term-macros.scala +run/repl-transcript.scala +run/repl-type-verbose.scala +run/t3376.scala +run/t4025.scala +run/t4172.scala +run/t4216.scala +run/t4542.scala +run/t4671.scala +run/t5256d.scala +run/t5535.scala +run/t5537.scala +run/t5789.scala +run/t6086-repl.scala +run/t6146b.scala +run/t6187.scala +run/t6320.scala +run/t6381.scala +run/t6434.scala +run/t6439.scala +run/t6507.scala +run/t6549.scala +run/t6937.scala +run/t7185.scala +run/t7319.scala +run/t7482a.scala +run/t7634.scala +run/t7747-repl.scala +run/t7805-repl-i.scala +run/tpeCache-tyconCache.scala +run/repl-empty-package +run/repl-javap-def.scala +run/repl-javap-mem.scala +run/repl-javap-outdir +run/repl-javap.scala +run/t6329_repl_bug.scala +run/t4950.scala +run/xMigration.scala +run/t6541-option.scala +run/repl-serialization.scala +run/t9174.scala +run/repl-paste-5.scala +run/repl-no-uescape.scala +run/repl-no-imports-no-predef-classbased.scala +run/repl-implicits-nopredef.scala +run/repl-classbased.scala +run/repl-no-imports-no-predef-power.scala +run/repl-paste-b.scala +run/repl-paste-6.scala +run/repl-implicits.scala +run/repl-no-imports-no-predef.scala +run/repl-paste-raw-b.scala +run/repl-paste-raw-c.scala +run/t9749-repl-dot.scala +run/trait_fields_repl.scala +run/t7139 +run/t9689 +run/trailing-commas.scala +run/t4700.scala +run/t9880-9881.scala +run/repl-kind.scala +run/t10284.scala +run/t9016.scala +run/repl-completions.scala +run/t10956.scala +run/t11564.scala +run/t11402.scala + +# Using Scala Script (partest.ScriptTest) + +run/t7711-script-args.scala +run/t4625.scala +run/t4625c.scala +run/t4625b.scala + +# Using the compiler API + +run/t2512.scala +run/analyzerPlugins.scala +run/compiler-asSeenFrom.scala +run/t5603.scala +run/t6440.scala +run/t5545.scala +run/existentials-in-compiler.scala +run/global-showdef.scala +run/stream_length.scala +run/annotatedRetyping.scala +run/imain.scala +run/existential-rangepos.scala +run/delambdafy_uncurry_byname_inline.scala +run/delambdafy_uncurry_byname_method.scala +run/delambdafy_uncurry_inline.scala +run/delambdafy_t6555.scala +run/delambdafy_uncurry_method.scala +run/delambdafy_t6028.scala +run/memberpos.scala +run/programmatic-main.scala +run/reflection-names.scala +run/settings-parse.scala +run/sm-interpolator.scala +run/t1501.scala +run/t1500.scala +run/sammy_java8.scala +run/t1618.scala +run/t2464 +run/t4072.scala +run/t5064.scala +run/t5385.scala +run/t5699.scala +run/t5717.scala +run/t5940.scala +run/t6028.scala +run/t6194.scala +run/t6669.scala +run/t6745-2.scala +run/t7096.scala +run/t7271.scala +run/t7337.scala +run/t7398.scala +run/t7569.scala +run/t7852.scala +run/t7817-tree-gen.scala +run/t7825.scala + +# partest.ParserTest +run/t3368.scala +run/t3368-b.scala +run/t3368-c.scala +run/t3368-d.scala +run/t9944.scala + +# partest.DirectTest +run/maxerrs.scala +run/t6288.scala +run/t6331.scala +run/t6440b.scala +run/t6555.scala +run/t7876.scala +run/typetags_without_scala_reflect_typetag_lookup.scala +run/dynamic-updateDynamic.scala +run/dynamic-selectDynamic.scala +run/dynamic-applyDynamic.scala +run/dynamic-applyDynamicNamed.scala +run/t4841-isolate-plugins +run/large_code.scala +run/macroPlugins-namerHooks.scala +run/t4841-no-plugin.scala +run/t4332.scala +run/t8029.scala +run/t8046 +run/t5905-features.scala +run/t5905b-features.scala +run/large_class.scala +run/t8708_b +run/icode-reader-dead-code.scala +run/t5938.scala +run/t8502.scala +run/t6502.scala +run/t8907.scala +run/t9097.scala +run/macroPlugins-enterStats.scala +run/sbt-icode-interface.scala +run/t8502b.scala +run/repl-paste-parse.scala +run/t5463.scala +run/t8433.scala +run/sd275.scala +run/sd275-java +run/t10471.scala +run/t6130.scala +run/t9437b.scala +run/t10552 +run/sd187.scala +run/patmat-origtp-switch.scala +run/indyLambdaKinds +run/indy-via-macro-class-constant-bsa +run/indy-via-macro-method-type-bsa +run/indy-via-macro-reflector +run/t11802-pluginsdir +run/t12019 + +# Using partest.SessionTest +run/t12354.scala + +# Using partest.StoreReporterDirectTest +run/t10171 + +# partest.StubErrorMessageTest +run/StubErrorBInheritsFromA.scala +run/StubErrorComplexInnerClass.scala +run/StubErrorHK.scala +run/StubErrorReturnTypeFunction.scala +run/StubErrorReturnTypeFunction2.scala +run/StubErrorReturnTypePolyFunction.scala +run/StubErrorSubclasses.scala +run/StubErrorTypeclass.scala +run/StubErrorTypeDef.scala + +# partest.CompilerTest +run/t8852a.scala +run/t12062.scala + +# partest.ASMConverters +run/t9403 + +# partest.BytecodeTest +run/t7106 +run/t7974 +run/t8601-closure-elim.scala +run/t4788 +run/t4788-separate-compilation + +# partest.SessionTest +run/t8843-repl-xlat.scala +run/t9206.scala +run/t9170.scala +run/t8918-unary-ids.scala +run/t1931.scala +run/t8935-class.scala +run/t8935-object.scala + +# partest.JavapTest +run/t8608-no-format.scala + +# Using .java source files + +run/t4317 +run/t4238 +run/t2296c +run/t4119 +run/t4283 +run/t4891 +run/t6168 +run/t6168b +run/t6240a +run/t6240b +run/t6548 +run/t6989 +run/t7008 +run/t7246 +run/t7246b +run/t7359 +run/t7439 +run/t7455 +run/t7510 +run/t7582-private-within +run/t7582 +run/t7582b +run/t3897 +run/t7374 +run/t3452e +run/t3452g +run/t3452d +run/t3452b +run/t3452a +run/t1430 +run/t4729 +run/t8442 +run/t8601e +run/t9298 +run/t9298b +run/t9359 +run/t7741a +run/t7741b +run/bcodeInlinerMixed +run/t9268 +run/t9489 +run/t9915 +run/t10059 +run/t1459 +run/t1459generic +run/t3236 +run/t9013 +run/t10231 +run/t10067 +run/t10249 +run/sd143 +run/t4283b +run/t7936 +run/t7936b +run/t9937 +run/t10368 +run/t10334b +run/sd304 +run/t10450 +run/t10042 +run/t10699 +run/t11109 +run/t9529 +run/t9529-types +run/t10490 +run/t10490-2 +run/t10889 +run/t3899 +run/t11373 +run/t8928 +run/indy-meth-refs-j + +# Using scala-script +run/t7791-script-linenums.scala + +# Using scalap +run/scalapInvokedynamic.scala + +# Using Manifests (which use Class.getInterfaces) +run/valueclasses-manifest-existential.scala +run/existentials3-old.scala +run/t2236-old.scala +run/interop_manifests_are_classtags.scala +run/valueclasses-manifest-generic.scala +run/valueclasses-manifest-basic.scala +run/t1195-old.scala +run/t3758-old.scala +run/t4110-old.scala +run/t6246.scala + +# Using ScalaRunTime.stringOf +run/value-class-extractor-seq.scala +run/t3493.scala + +# Custom invoke dynamic node +run/indy-via-macro +run/indy-via-macro-with-dynamic-args + +### Bugs +run/classtags_core.scala +run/classmanifests_new_core.scala +run/classmanifests_new_alias.scala + +## Compiler +run/anyval-box-types.scala +run/structural.scala +run/t266.scala +run/t8601b.scala +run/t8601d.scala +run/t10069b.scala + +## JVM compliance +run/try-catch-unify.scala +run/t2755.scala +run/java-erasure.scala + +## Fails +run/t5680.scala +run/t5914.scala + +## Build mode dependent +run/t6443.scala +run/t8888.scala +run/delambdafy-dependent-on-param-subst.scala +run/lisp.scala +run/number-parsing.scala + +## Check not passing +run/t4300.scala +run/t3361.scala +run/t8017 +run/t8334.scala +run/t8803.scala +run/t9697.scala +run/t10290.scala + +## Other +run/richs.scala \ No newline at end of file diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t11952b.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t11952b.check new file mode 100644 index 0000000000..a5211b1337 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t11952b.check @@ -0,0 +1,17 @@ +[running phase parser on t11952b.scala] +[running phase namer on t11952b.scala] +[running phase packageobjects on t11952b.scala] +[running phase typer on t11952b.scala] +[running phase nativeinterop on t11952b.scala] +[running phase patmat on t11952b.scala] +[running phase superaccessors on t11952b.scala] +[running phase extmethods on t11952b.scala] +[running phase pickler on t11952b.scala] +[running phase refchecks on t11952b.scala] +t11952b.scala:9: error: overriding method f in class C of type => String; + method f cannot override final member; + found : => scala.this.Int + required: => String + override def f: Int = 42 + ^ +one error found diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-additional.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-additional.check new file mode 100644 index 0000000000..8b89521070 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-additional.check @@ -0,0 +1,29 @@ + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + nativeinterop 5 prepare ASTs for Native interop + patmat 6 translate match expressions +superaccessors 7 add super accessors in traits and nested classes + extmethods 8 add extension methods for inline classes + pickler 9 serialize symbol tables + refchecks 10 reference/override checking, translate nested objects + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition + nir 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + ploogin 26 A sample phase that does so many things it's kind of hard... + terminal 27 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-list.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-list.check new file mode 100644 index 0000000000..eba706333b --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-list.check @@ -0,0 +1,2 @@ +ploogin - A sample plugin for testing. +nir - Compile to Scala Native IR (NIR) diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-missing.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-missing.check new file mode 100644 index 0000000000..a82e833901 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-missing.check @@ -0,0 +1,29 @@ +Error: unable to load class: t6446.Ploogin + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + nativeinterop 5 prepare ASTs for Native interop + patmat 6 translate match expressions +superaccessors 7 add super accessors in traits and nested classes + extmethods 8 add extension methods for inline classes + pickler 9 serialize symbol tables + refchecks 10 reference/override checking, translate nested objects + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition + nir 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + terminal 26 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-show-phases.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-show-phases.check new file mode 100644 index 0000000000..5fe052ad3f --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t6446-show-phases.check @@ -0,0 +1,28 @@ + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + nativeinterop 5 prepare ASTs for Native interop + patmat 6 translate match expressions +superaccessors 7 add super accessors in traits and nested classes + extmethods 8 add extension methods for inline classes + pickler 9 serialize symbol tables + refchecks 10 reference/override checking, translate nested objects + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition + nir 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + terminal 26 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t7494-no-options.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t7494-no-options.check new file mode 100644 index 0000000000..803585d330 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/neg/t7494-no-options.check @@ -0,0 +1,30 @@ +error: Error: ploogin takes no options + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees +packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees + nativeinterop 5 prepare ASTs for Native interop + patmat 6 translate match expressions +superaccessors 7 add super accessors in traits and nested classes + extmethods 8 add extension methods for inline classes + pickler 9 serialize symbol tables + refchecks 10 reference/override checking, translate nested objects + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition + nir 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + ploogin 26 A sample phase that does so many things it's kind of hard... + terminal 27 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classof.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classof.check new file mode 100644 index 0000000000..21bf4cfb41 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classof.check @@ -0,0 +1,22 @@ +Value types: +class scala.scalanative.runtime.PrimitiveUnit +class scala.scalanative.runtime.PrimitiveBoolean +class scala.scalanative.runtime.PrimitiveByte +class scala.scalanative.runtime.PrimitiveShort +class scala.scalanative.runtime.PrimitiveChar +class scala.scalanative.runtime.PrimitiveInt +class scala.scalanative.runtime.PrimitiveLong +class scala.scalanative.runtime.PrimitiveFloat +class scala.scalanative.runtime.PrimitiveDouble +Class types +class SomeClass +class scala.collection.immutable.List +class scala.Tuple2 +Arrays: +class scala.scalanative.runtime.ObjectArray +class scala.scalanative.runtime.IntArray +class scala.scalanative.runtime.DoubleArray +class scala.scalanative.runtime.ObjectArray +Functions: +interface scala.Function2 +interface scala.Function1 diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_contextbound.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_contextbound.check new file mode 100644 index 0000000000..5d3106c9bc --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_contextbound.check @@ -0,0 +1 @@ +class scala.scalanative.runtime.IntArray diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_multi.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_multi.check new file mode 100644 index 0000000000..ab1c14e439 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/classtags_multi.check @@ -0,0 +1,5 @@ +Int +Array[scala.scalanative.runtime.PrimitiveInt] +Array[java.lang.Object] +Array[java.lang.Object] +Array[java.lang.Object] diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/getClassTest-valueClass.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/getClassTest-valueClass.check new file mode 100644 index 0000000000..cee2875fff --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/getClassTest-valueClass.check @@ -0,0 +1,2 @@ +class scala.scalanative.runtime.PrimitiveInt +class V diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/interop_classtags_are_classmanifests.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/interop_classtags_are_classmanifests.check new file mode 100644 index 0000000000..5ef5b7138c --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/interop_classtags_are_classmanifests.check @@ -0,0 +1,3 @@ +Int +java.lang.String +Array[scala.scalanative.runtime.PrimitiveInt] diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t4753.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t4753.check new file mode 100644 index 0000000000..9a020c1ead --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t4753.check @@ -0,0 +1 @@ +class scala.scalanative.runtime.PrimitiveBoolean diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5568.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5568.check new file mode 100644 index 0000000000..0018046644 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5568.check @@ -0,0 +1,9 @@ +class scala.scalanative.runtime.PrimitiveUnit +class scala.scalanative.runtime.PrimitiveInt +class scala.runtime.BoxedUnit +class scala.runtime.BoxedUnit +class java.lang.Integer +class java.lang.Integer +5 +5 +5 diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5923b.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5923b.check new file mode 100644 index 0000000000..a4885c883f --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t5923b.check @@ -0,0 +1,3 @@ +class scala.scalanative.runtime.ObjectArray +class scala.scalanative.runtime.ObjectArray +class scala.scalanative.runtime.ObjectArray diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t6318_primitives.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t6318_primitives.check new file mode 100644 index 0000000000..1b64e046c7 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.12.20/run/t6318_primitives.check @@ -0,0 +1,54 @@ +Checking if class scala.scalanative.runtime.PrimitiveByte matches class scala.scalanative.runtime.PrimitiveByte +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveByte matches class scala.scalanative.runtime.PrimitiveShort +None +Checking if class java.lang.Byte matches class scala.scalanative.runtime.PrimitiveByte +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveShort matches class scala.scalanative.runtime.PrimitiveShort +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveShort matches class scala.scalanative.runtime.PrimitiveChar +None +Checking if class java.lang.Short matches class scala.scalanative.runtime.PrimitiveShort +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveChar matches class scala.scalanative.runtime.PrimitiveChar +Some() +Checking if class scala.scalanative.runtime.PrimitiveChar matches class scala.scalanative.runtime.PrimitiveInt +None +Checking if class java.lang.Character matches class scala.scalanative.runtime.PrimitiveChar +Some() +Checking if class scala.scalanative.runtime.PrimitiveInt matches class scala.scalanative.runtime.PrimitiveInt +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveInt matches class scala.scalanative.runtime.PrimitiveLong +None +Checking if class java.lang.Integer matches class scala.scalanative.runtime.PrimitiveInt +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveLong matches class scala.scalanative.runtime.PrimitiveLong +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveLong matches class scala.scalanative.runtime.PrimitiveFloat +None +Checking if class java.lang.Long matches class scala.scalanative.runtime.PrimitiveLong +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveFloat matches class scala.scalanative.runtime.PrimitiveFloat +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveFloat matches class scala.scalanative.runtime.PrimitiveDouble +None +Checking if class java.lang.Float matches class scala.scalanative.runtime.PrimitiveFloat +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveDouble matches class scala.scalanative.runtime.PrimitiveDouble +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveDouble matches class scala.scalanative.runtime.PrimitiveBoolean +None +Checking if class java.lang.Double matches class scala.scalanative.runtime.PrimitiveDouble +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveBoolean matches class scala.scalanative.runtime.PrimitiveBoolean +Some(true) +Checking if class scala.scalanative.runtime.PrimitiveBoolean matches class scala.scalanative.runtime.PrimitiveUnit +None +Checking if class java.lang.Boolean matches class scala.scalanative.runtime.PrimitiveBoolean +Some(true) +Checking if class scala.scalanative.runtime.PrimitiveUnit matches class scala.scalanative.runtime.PrimitiveUnit +Some(()) +Checking if class scala.scalanative.runtime.PrimitiveUnit matches class scala.scalanative.runtime.PrimitiveByte +None +Checking if class scala.scalanative.runtime.BoxedUnit$ matches class scala.scalanative.runtime.PrimitiveUnit +Some(()) From 9f8e0c41ea8796d93dd4dbba6442c7151b272675 Mon Sep 17 00:00:00 2001 From: Corey O'Connor Date: Tue, 3 Sep 2024 14:06:45 -0700 Subject: [PATCH 12/35] add references to third party tools and libraries to docs (#4042) * add links to scala-java-time and scala-java-locales * add links to samply and hotspot * add reference to sbt-tzdb * add link to sjavatime * Update docs/user/profiling.md Co-authored-by: Anton Sviridov * Update docs/user/profiling.md Co-authored-by: Anton Sviridov --------- Co-authored-by: Anton Sviridov --- docs/lib/javalib.md | 30 +++++++++++++++++++++++++++--- docs/user/profiling.md | 16 ++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/docs/lib/javalib.md b/docs/lib/javalib.md index 24c85225fb..06845056ae 100644 --- a/docs/lib/javalib.md +++ b/docs/lib/javalib.md @@ -1,11 +1,35 @@ # Java Standard Library -Scala Native supports a subset of the JDK core libraries reimplemented +Scala Native includes a subset of the JDK core libraries reimplemented in Scala. -## Supported classes +Third-party libraries, like `scala-java-time` and `scala-java-locales`, +provide more complete implementations for some JDK packages. -For list of currently supported Java Standard Library types and methods refer to [scaladoc package](https://www.javadoc.io/doc/org.scala-native/javalib_native0.5_2.13/latest/index.html) or consult [javalib sources](https://github.com/scala-native/scala-native/tree/main/javalib/src/main/scala/java) for details. +## Included JDK Implementation + +For list of currently supported Java Standard Library types and methods refer to [scaladoc +package](https://www.javadoc.io/doc/org.scala-native/javalib_native0.5_2.13/latest/index.html) or consult +[javalib sources](https://github.com/scala-native/scala-native/tree/main/javalib/src/main/scala/java) for +details. + +## `java.time` + +[scala-java-time](https://github.com/cquiroz/scala-java-time) provides a native, JVM and JS implementation of +the `java.time` packages + +[sjavatime](https://github.com/ekrich/sjavatime) provides a native and JS implementation of the `java.time` +API. While not yet as full features as `scala-java-time` this is useful if a minimal implementation is +required. + +The full timezone database required for `java.time` can be too large for some applications. The +[sbt-tzdb](https://github.com/cquiroz/sbt-tzdb) `sbt` plugin can build a custom version of tzdb, which has +the minimal data your application needs; reducing the size of the application. + +## `java.util.Locale` + +[scala-java-locales](https://github.com/cquiroz/scala-java-locales) provides a native, JVM and JS +implementation of `java.util.Locale` ## Regular expressions (java.util.regex) diff --git a/docs/user/profiling.md b/docs/user/profiling.md index 94bf2a2dd5..d1b45ec69f 100644 --- a/docs/user/profiling.md +++ b/docs/user/profiling.md @@ -3,6 +3,9 @@ In this section you can find some tips on how to profile your Scala Native binary in Linux. +Scala Native binaries are regular executables. Tools that works with native executables will work with Scala +Native executables. That includes the Linux `perf` performance analysis tool. + ## Measuring execution time and memory - With the `time` command you can measure execution time: @@ -53,6 +56,19 @@ Exit status: 0 A [flamegraph](http://www.brendangregg.com/flamegraphs.html) is a visualization of the most frequent code-paths of a program. You can use flamegraphs to see where your program spends most of its CPU time. + +### Use samply + +[samply](https://github.com/mstange/samply) is a command line CPU profiler which uses the Firefox profiler as +its UI. Samply has support for de-mangling Scala Native symbols. + +### Use hotspot + +[hotspot](https://github.com/KDAB/hotspot) is a GUI for `perf` which provides a flamegraph view. As of this +writing, hotspot does not de-mangle Scala Native symbols. + +### Using using `perf` and `FlameGraph` + Follow these steps: - You need to install the `perf` command if you haven't got it From 07b46b1b60561239ee9f16afeff9a6a5ebf3cb9e Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Thu, 5 Sep 2024 21:13:54 +0200 Subject: [PATCH 13/35] fix[compiler-plugin] Intrinisic ClassFieldRawPtr should always mangle symbol names when comparing symbols (#4045) * Fix genClassFieldRawPtr. Always mangle symbol names when comparing them with target fieldName * Fix compilation on Scala 2 --- .../scala/scalanative/nscplugin/NirGenExpr.scala | 2 +- .../scala/scalanative/nscplugin/NirGenExpr.scala | 2 +- .../test/scala/scala/scalanative/NIRCompilerTest.scala | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala index ebee933527..f0fff87993 100644 --- a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala +++ b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala @@ -2541,7 +2541,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => val classInfo = target.tpe.finalResultType val classInfoSym = classInfo.typeSymbol.asClass def matchesName(f: Symbol) = { - f.nameString == TermName(fieldNameId).toString() + f.nameString == fieldNameId } val candidates = diff --git a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala index 9f141b6495..ea3ae8e438 100644 --- a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala +++ b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala @@ -2650,7 +2650,7 @@ trait NirGenExpr(using Context) { val classInfo = target.tpe.finalResultType val classInfoSym = classInfo.typeSymbol.asClass def matchesName(f: SingleDenotation) = - f.name.mangled == termName(fieldNameId).mangled + f.name.mangledString == fieldNameId def isImmutableField(f: SymDenotation) = { // If `val` was defined in trait it would be internally mutable, but with stable accessors !f.is(Mutable) || classInfoSym.parentSyms.exists(s => diff --git a/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala b/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala index 53bf810219..ffb3869fab 100644 --- a/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala +++ b/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala @@ -782,4 +782,14 @@ class NIRCompilerTest { ) } + @Test def issue4044(): Unit = { + // Unable to compile lazy val in trait + NIRCompiler(_.compile(""" + |trait Source { + | lazy val (lineStarts, charCount, lineCount) = (1, 2, 3) + |} + | + |class StringSource extends Source + |""".stripMargin)) + } } From 2400fef4f92ef2de5fe6e4772c326c440df02204 Mon Sep 17 00:00:00 2001 From: LeeTibbert Date: Tue, 10 Sep 2024 05:47:34 -0400 Subject: [PATCH 14/35] feaure [javalib]: Port JSR-166 ConcurrentLinkedDeque to Scala Native (#4046) * feaure [javalib]: Port JSR-166 ConcurrentLinkedDeque to Scala Native * Fix scaladoc problem children --- .../concurrent/ConcurrentLinkedDeque.scala | 1534 +++++++++++++++++ .../ConcurrentLinkedDequeTest.scala | 982 +++++++++++ 2 files changed, 2516 insertions(+) create mode 100644 javalib/src/main/scala/java/util/concurrent/ConcurrentLinkedDeque.scala create mode 100644 unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/util/concurrent/ConcurrentLinkedDequeTest.scala diff --git a/javalib/src/main/scala/java/util/concurrent/ConcurrentLinkedDeque.scala b/javalib/src/main/scala/java/util/concurrent/ConcurrentLinkedDeque.scala new file mode 100644 index 0000000000..5ab520352e --- /dev/null +++ b/javalib/src/main/scala/java/util/concurrent/ConcurrentLinkedDeque.scala @@ -0,0 +1,1534 @@ +/* + * Written by Doug Lea and Martin Buchholz with assistance from members of + * JCP JSR-166 Expert Group and released to the public domain, as explained + * at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent + +/* Ported to Scala Native + * + * Note on code style: + * + * The objective of this port was to match the behavior of the Java JSR-166 + * code, where matching is defined as passing the corresponding + * JSR-166 ConcurrentLinkedDequeTest.scala. + * + * The plentiful use of Java idioms such as assignments within while + * condition clauses and 'break' and 'continue' statements leads to some + * just plain ugly non-idiomatic Scala code. + * + * In particular the 'skipDeletedPredecessors()' and + * 'skipDeletedSuccessors()' methods use Finite State Machines (FSM) to + * translate Java nested loops with both 'continue' and 'break' statements. + * + * When you are repulsed by the coding style, have a moment of compassion + * for the wretched translator. + * + * Once correctness has been established, perhaps future Evolutions can + * move through the file going from method to method and making the + * code style more pleasant to eyes accustomed to idiomatic Scala. + */ + +import java.util + +import java.util.Objects +import java.util.Iterator +import java.util.{Spliterator, Spliterators} + +import java.util.function.Consumer + +import scala.scalanative.unsafe._ +import scala.scalanative.runtime.fromRawPtr +import scala.scalanative.runtime.Intrinsics.classFieldRawPtr +import scala.scalanative.libc.stdatomic.{AtomicRef, PtrToAtomicRef} +import scala.scalanative.annotation.alwaysinline +import scala.scalanative.libc.stdatomic.memory_order.memory_order_relaxed + +/** An unbounded concurrent {@linkplain Deque deque} based on linked nodes. + * Concurrent insertion, removal, and access operations execute safely across + * multiple threads. A {@code ConcurrentLinkedDeque} is an appropriate choice + * when many threads will share access to a common collection. Like most other + * concurrent collection implementations, this class does not permit the use of + * {@code null} elements. + * + *

Iterators and spliterators are weakly consistent. + * + *

Beware that, unlike in most collections, the {@code size} method is + * NOT a constant-time operation. Because of the asynchronous nature + * of these deques, determining the current number of elements requires a + * traversal of the elements, and so may report inaccurate results if this + * collection is modified during traversal. Additionally, the bulk operations + * {@code addAll}, {@code removeAll}, {@code retainAll}, {@code containsAll}, + * {@code equals}, and {@code toArray} are not guaranteed to be + * performed atomically. For example, an iterator operating concurrently with + * an {@code addAll} operation might view only some of the added elements. + * + *

This class and its iterator implement all of the optional + * methods of the {@link Deque} and {@link Iterator} interfaces. + * + *

Memory consistency effects: As with other concurrent collections, actions + * in a thread prior to placing an object into a {@code ConcurrentLinkedDeque} + * happen-before + * actions subsequent to the access or removal of that element from the {@code + * ConcurrentLinkedDeque} in another thread. + * + *

This class is a member of the Java Collections + * Framework. + * + * @since 1.7 + * @author + * Doug Lea + * @author + * Martin Buchholz + * @param < + * E> the type of elements held in this deque + */ +@SerialVersionUID(876323262645176354L) +object ConcurrentLinkedDeque { + private val PREV_TERMINATOR: Node[AnyRef] = new Node[AnyRef](null) + PREV_TERMINATOR.next = PREV_TERMINATOR + + private val NEXT_TERMINATOR: Node[AnyRef] = new Node[AnyRef](null) + NEXT_TERMINATOR.prev = NEXT_TERMINATOR + + final private[concurrent] class Node[E <: AnyRef] private[concurrent] { + // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR + @volatile private[concurrent] var prev: Node[E] = null + @volatile private[concurrent] var item: E = null.asInstanceOf[E] + @volatile private[concurrent] var next: Node[E] = null + + @alwaysinline private[ConcurrentLinkedDeque] def PREV: AtomicRef[Node[E]] = + fromRawPtr[Node[E]](classFieldRawPtr(this, "prev")).atomic + @alwaysinline private[ConcurrentLinkedDeque] def ITEM: AtomicRef[E] = + fromRawPtr[E](classFieldRawPtr(this, "item")).atomic + @alwaysinline private[ConcurrentLinkedDeque] def NEXT: AtomicRef[Node[E]] = + fromRawPtr[Node[E]](classFieldRawPtr(this, "next")).atomic + + /** Constructs a new node. Uses relaxed write because item can only be seen + * after publication via casNext or casPrev. + */ + def this(item: E) = { + this() + ITEM.store(item, memory_order_relaxed) + } + + private[concurrent] def appendRelaxed(next: Node[E]): Unit = { + // assert next != null; + // assert this.next == null; + NEXT.store(next, memory_order_relaxed) + } + + private[concurrent] def casItem(cmp: E, `val`: E): Boolean = { + // assert item == cmp || item == null; + // assert cmp != null; + // assert val == null; + ITEM.compareExchangeStrong(cmp, `val`) + } + + private[concurrent] def lazySetNext(`val`: Node[E]): Unit = { + this.next = `val` + } + + private[concurrent] def casNext(cmp: Node[E], `val`: Node[E]): Boolean = { + // assert next == cmp || next == null; + // assert cmp != null; + // assert val == null; + NEXT.compareExchangeStrong(cmp, `val`) + } + + private[concurrent] def lazySetPrev(`val`: Node[E]): Unit = { + this.prev = `val` + } + + private[concurrent] def casPrev(cmp: Node[E], `val`: Node[E]): Boolean = { + // assert prev == cmp || prev == null; + // assert cmp != null; + // assert val == null; + PREV.compareExchangeStrong(cmp, `val`) + } + } + + private val HOPS = 2 + + /** A customized variant of Spliterators.IteratorSpliterator */ + private[concurrent] object CLDSpliterator { + private[concurrent] val MAX_BATCH = 1 << 25 // max batch array size; + } + + final private[concurrent] class CLDSpliterator[ + E <: AnyRef + ] private[concurrent] ( + private[concurrent] + val queue: ConcurrentLinkedDeque[E] + ) extends Spliterator[E] { + private[concurrent] var current: Node[E] = + null // current node; null until initialized + private[concurrent] var batch = 0 // batch size for splits + private[concurrent] var exhausted = false // true when no more nodes + + override def trySplit(): Spliterator[E] = { + var p: Node[E] = null + val q = this.queue + val b = batch + val n = + if (b <= 0) 1 + else if (b >= CLDSpliterator.MAX_BATCH) CLDSpliterator.MAX_BATCH + else b + 1 + if (!exhausted && ({ p = current; p } != null || { + p = q.first; p + } != null)) { + if (p.item == null && (p eq { p = p.next; p })) current = { + p = q.first; p + } + if (p != null && p.next != null) { + val a = new Array[AnyRef](n) + var i = 0 + + while (p != null && i < n) { + if ({ a(i) = p.item; a(i) } != null) i += 1 + if (p eq { p = p.next; p }) p = q.first + } + + if ({ current = p; current } == null) exhausted = true + if (i > 0) { + batch = i + return Spliterators.spliterator[E]( + a, + 0, + i, + Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.CONCURRENT + ) + } + } + } + null + } + + override def forEachRemaining(action: Consumer[_ >: E]): Unit = { + var p: Node[E] = null + if (action == null) throw new NullPointerException + val q = this.queue + if (!exhausted && ({ p = current; p } != null) || ({ + p = q.first; p + } != null)) { + exhausted = true + while (p != null) { + val e = p.item + if (p eq { p = p.next; p }) p = q.first + if (e != null) action.accept(e) + } + } + } + + override def tryAdvance(action: Consumer[_ >: E]): Boolean = { + var p: Node[E] = null + if (action == null) throw new NullPointerException + val q = this.queue + if (!exhausted && ({ p = current; p } != null) || ({ + p = q.first; p + } != null)) { + var e: E = null.asInstanceOf[E] + + while (e == null && p != null) { + e = p.item + if (p eq { p = p.next; p }) p = q.first + } + + if ({ current = p; current } == null) exhausted = true + if (e != null) { + action.accept(e) + return true + } + } + false + } + + override def estimateSize(): Long = java.lang.Long.MAX_VALUE + + override def characteristics(): Int = + Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.CONCURRENT + } +} + +@SerialVersionUID(876323262645176354L) +class ConcurrentLinkedDeque[E <: AnyRef] +/** Constructs an empty deque. + */ + extends util.AbstractCollection[E] + with util.Deque[E] + with Serializable { + + import ConcurrentLinkedDeque._ + + /** A node from which the first node on list (that is, the unique node p with + * p.prev == null && p.next != p) can be reached in O(1) time. Invariants: + * - the first node is always O(1) reachable from head via prev links + * - all live nodes are reachable from the first node via succ() + * - head != null + * - (tmp = head).next != tmp || tmp != head + * - head is never gc-unlinked (but may be unlinked) Non-invariants: + * - head.item may or may not be null + * - head may not be reachable from the first or last node, or from tail + */ + @volatile + @transient private var head: Node[E] = new Node[E] + + /** A node from which the last node on list (that is, the unique node p with + * p.next == null && p.prev != p) can be reached in O(1) time. Invariants: + * - the last node is always O(1) reachable from tail via next links + * - all live nodes are reachable from the last node via pred() + * - tail != null + * - tail is never gc-unlinked (but may be unlinked) Non-invariants: + * - tail.item may or may not be null + * - tail may not be reachable from the first or last node, or from head + */ + @volatile + @transient private var tail: Node[E] = head + + @alwaysinline private def HEAD: AtomicRef[Node[E]] = + fromRawPtr[Node[E]](classFieldRawPtr(this, "head")).atomic + @alwaysinline private def TAIL: AtomicRef[Node[E]] = + fromRawPtr[Node[E]](classFieldRawPtr(this, "tail")).atomic + + private[concurrent] def prevTerminator = PREV_TERMINATOR.asInstanceOf[Node[E]] + + private[concurrent] def nextTerminator = NEXT_TERMINATOR.asInstanceOf[Node[E]] + + /** Links e as first element. + */ + private def linkFirst(e: E): Unit = { + val newNode = new Node[E](Objects.requireNonNull(e)) + + while (true) { + var restart = false + while (!restart) { + restart = false + + var h = head + var p = h + var q: Node[E] = null + // Check for head updates every other hop. + while (true) + if ({ q = p.prev; q } != null && { p = q; q = p.prev; q } != null) + // If p == q, we are sure to follow head instead. + p = + if (h ne { h = head; h }) h + else q + else if (p.next eq p) // PREV_TERMINATOR + restart = true + else { + // p is first node + newNode.lazySetNext(p) // CAS piggyback + if (p.casPrev(null, newNode)) { + // Successful CAS is the linearization point + // for e to become an element of this deque, + // and for newNode to become "live". + if (p ne h) + casHead(h, newNode) // Failure is OK.// hop two nodes at a time + return + } + } + } + } + } + + /** Links e as last element. + */ + private def linkLast(e: E): Unit = { + + val newNode = new ConcurrentLinkedDeque.Node[E](Objects.requireNonNull(e)) + + var restartFromTail = false + while (!restartFromTail) { + restartFromTail = false + + while (true) { + var t = tail + var p = t + var q: ConcurrentLinkedDeque.Node[E] = null + while (true) { + // Check for tail updates every other hop. + if (({ q = p.next; q } != null) && ({ p = q; q = p.next; q } != null)) + // If p == q, we are sure to follow tail instead. + p = + if (t ne { t = tail; t }) t + else q + else if (p.prev eq p) // NEXT_TERMINATOR + restartFromTail = true + else { + // p is last node + newNode.lazySetPrev(p) // CAS piggyback + + if (p.casNext(null, newNode)) { + // Successful CAS is the linearization point + // for e to become an element of this deque, + // and for newNode to become "live". + + // hop two nodes at a time + if (p ne t) + casTail(t, newNode) // Failure is OK. + + return + } + } + } + } + } + } + + private[concurrent] def unlink(x: Node[E]): Unit = { + // assert x != null; + // assert x.item == null; + // assert x != PREV_TERMINATOR; + // assert x != NEXT_TERMINATOR; + + val prev = x.prev + val next = x.next + if (prev == null) { + unlinkFirst(x, next) + } else if (next == null) { + unlinkLast(x, prev) + } else { + // Unlink interior node. + // + // This is the common case, since a series of polls at the + // same end will be "interior" removes, except perhaps for + // the first one, since end nodes cannot be unlinked. + // + // At any time, all active nodes are mutually reachable by + // following a sequence of either next or prev pointers. + // + // Our strategy is to find the unique active predecessor + // and successor of x. Try to fix up their links so that + // they point to each other, leaving x unreachable from + // active nodes. If successful, and if x has no live + // predecessor/successor, we additionally try to gc-unlink, + // leaving active nodes unreachable from x, by rechecking + // that the status of predecessor and successor are + // unchanged and ensuring that x is not reachable from + // tail/head, before setting x's prev/next links to their + // logical approximate replacements, self/TERMINATOR. + + var activePred: Node[E] = null + var activeSucc: Node[E] = null + var isFirst = false + var isLast = false + var hops = 1 + + // Find active predecessor + var p = prev + var breakNow = false + + while (!breakNow) { + if (p.item != null) { + activePred = p + isFirst = false + breakNow = true + } + + if (!breakNow) { + val q = p.prev + + if (q == null) { + if (p.next eq p) + return + + activePred = p + isFirst = true + breakNow = true + } else if (p eq q) { + return + } else { + p = q + } + + if (!breakNow) + hops += 1 + } + } + + // Find active successor + var p2 = next + breakNow = false + while (!breakNow) { + if (p2.item != null) { + activeSucc = p2 + isLast = false + breakNow = true + } else { + val q = p2.next + if (q == null) { + if (p2.prev eq p2) + return + + activeSucc = p2 + isLast = true + breakNow = true + } else if (p2 eq q) { + return + } else { + p2 = q + } + } + + if (!breakNow) + hops += 1 + } + + // TODO: better HOP heuristics + if (hops < HOPS && (isFirst | isLast)) + return + + // Squeeze out deleted nodes between activePred and + // activeSucc, including x. + + skipDeletedSuccessors(activePred) + skipDeletedPredecessors(activeSucc) + + // Try to gc-unlink, if possible + if ((isFirst | isLast) && + // Recheck expected state of predecessor and successor + (activePred.next eq activeSucc) && (activeSucc.prev eq activePred) + && (if (isFirst) + activePred.prev == null + else + activePred.item != null) && (if (isLast) + activeSucc.next == null + else + activeSucc.item != null)) { + + updateHead() // Ensure x is not reachable from head + updateTail() // Ensure x is not reachable from tail + + // Finally, actually gc-unlink + x.lazySetPrev( + if (isFirst) prevTerminator + else x + ) + x.lazySetNext( + if (isLast) nextTerminator + else x + ) + } + } + } + + /** Unlinks non-null first node. + */ + private def unlinkFirst(first: Node[E], next: Node[E]): Unit = { + // assert first != null; + // assert next != null; + // assert first.item == null; + var o: Node[E] = null + var p = next + var q: Node[E] = null + + while (true) + if (p.item != null || { q = p.next; q } == null) { + if (o != null && (p.prev ne p) && first.casNext(next, p)) { + skipDeletedPredecessors(p) + if (first.prev == null && (p.next == null || p.item != null) && + (p.prev eq first)) { + updateHead() // Ensure o is not reachable from head + updateTail() // Ensure o is not reachable from tail + + // Finally, actually gc-unlink + o.lazySetNext(o) + o.lazySetPrev(prevTerminator) + } + } + return + } else if (p eq q) return + else { + o = p + p = q + } + } + + /** Unlinks non-null last node. + */ + private def unlinkLast(last: Node[E], prev: Node[E]): Unit = { + // assert last != null; + // assert prev != null; + // assert last.item == null; + var o: Node[E] = null + var p = prev + var q: Node[E] = null + while (true) { + if (p.item != null || { q = p.prev; q } == null) { + if (o != null && (p.next ne p) && last.casPrev(prev, p)) { + skipDeletedSuccessors(p) + + if (last.next == null && (p.prev == null || p.item != null) && + (p.next eq last)) { + updateHead() // Ensure o is not reachable from head + updateTail() // Ensure o is not reachable from tail + + // Finally, actually gc-unlink + o.lazySetPrev(o) + o.lazySetNext(nextTerminator) + } + } + return + } else if (p eq q) return + else { + o = p + p = q + } + } + } + + /** Guarantees that any node which was unlinked before a call to this method + * will be unreachable from head after it returns. Does not guarantee to + * eliminate slack, only that head will point to a node that was active while + * this method was running. + */ + final private def updateHead(): Unit = { + // Either head already points to an active node, or we keep + // trying to cas it to the first node until it does. + + var h, p, q = null.asInstanceOf[Node[E]] + + var restartFromHead = true + + while (restartFromHead) { + restartFromHead = false + + while ({ h = head; h }.item == null && { p = h.prev; p } != null) { + while (!restartFromHead) { + if ({ q = p.prev; q } == null || { p = q; q = p.prev; q } == null) { + // It is possible that p is PREV_TERMINATOR, + // but if so, the CAS is guaranteed to fail. + if (casHead(h, p)) return + else restartFromHead = true + } else if (h ne head) { + restartFromHead = true + } else { + p = q + } + } + } + } + } + + final private def updateTail(): Unit = { + // Either tail already points to an active node, or we keep + // trying to cas it to the last node until it does. + + var t, p, q = null.asInstanceOf[Node[E]] + + var restartFromTail = true + + while (restartFromTail) { + restartFromTail = false + + while ({ t = tail; t }.item == null && { p = t.next; p } != null) + while (true) + if ({ q = p.next; q } == null || { p = q; q = p.next; q } == null) { + // It is possible that p is NEXT_TERMINATOR, + // but if so, the CAS is guaranteed to fail. + if (casTail(t, p)) return + else restartFromTail = true + } else if (t ne tail) restartFromTail = true + else p = q + } + } + + private object SkipDeletedStates { + final val State_BEGIN = 1 + final val State_WHILE_ACTIVE = 2 + final val State_FIND_ACTIVE = 3 + + final val State_WHILE_ACTIVE_TEST = 98 + final val State_DONE = 99 + } + + private def skipDeletedPredecessors(x: Node[E]): Unit = { + import SkipDeletedStates._ + + // A Finite State Machine (FSM) to closely follow Java break/continue logic + var state = State_BEGIN + while (state != State_DONE) { + var prev = x.prev + var p = prev // Dummy value, will get overwritten. + + state match { + case State_BEGIN => + val prev = x.prev + // assert next != null; + // assert x != NEXT_TERMINATOR; + // assert x != PREV_TERMINATOR; + + p = prev + state = State_FIND_ACTIVE + + case State_FIND_ACTIVE => + var findActive = true + + while (findActive) { + findActive = true + if (p.item != null) { + findActive = false // state stays State_FIND_ACTIVE + } else { + val q = p.prev + if (q == null) { + findActive = false + + if (p.next eq p) + state = State_WHILE_ACTIVE + } else if (p eq q) { + findActive = false + state = State_WHILE_ACTIVE + } else { + p = q + } + + // found active CAS target + if (state != State_WHILE_ACTIVE) { + if (prev == p || x.casPrev(prev, p)) + return + } + + state = State_WHILE_ACTIVE_TEST + } + } + + case State_WHILE_ACTIVE_TEST => + state = + if ((x.item != null || x.next == null)) State_WHILE_ACTIVE_TEST + else State_DONE + + case unknown => + state = State_DONE + } + } + } + + private def skipDeletedSuccessors(x: Node[E]): Unit = { + import SkipDeletedStates._ + + // A Finite State Machine (FSM) to closely follow Java break/continue logic + var state = State_BEGIN + while (state != State_DONE) { + var next = x.next + var p = next // Dummy value, will get overwritten. Avoid Scala 2/3 quirks + + state match { + case State_BEGIN => + val next = x.next + // assert next != null; + // assert x != NEXT_TERMINATOR; + // assert x != PREV_TERMINATOR; + + p = next + state = State_FIND_ACTIVE + + case State_FIND_ACTIVE => + var findActive = true + + while (findActive) { + findActive = true + if (p.item != null) { + findActive = false // state stays State_FIND_ACTIVE + } else { + val q = p.next + if (q == null) { + findActive = false + + if (p.next eq p) + state = State_WHILE_ACTIVE + } else if (p eq q) { + findActive = false + state = State_WHILE_ACTIVE + } else { + p = q + } + + // found active CAS target + if (state != State_WHILE_ACTIVE) { + if (next == p || x.casNext(next, p)) + return + } + + state = State_WHILE_ACTIVE_TEST + } + } + + case State_WHILE_ACTIVE_TEST => + state = + if ((x.item != null || x.prev == null)) State_WHILE_ACTIVE_TEST + else State_DONE + + case unknown => + state = State_DONE + } + } + } + + /** Returns the successor of p, or the first node if p.next has been linked to + * self, which will only be true if traversing with a stale pointer that is + * now off the list. + */ + final private[concurrent] def succ(p: Node[E]) = { + // TODO: should we skip deleted nodes here? + val q = p.next + if (p eq q) first + else q + } + + /** Returns the predecessor of p, or the last node if p.prev has been linked + * to self, which will only be true if traversing with a stale pointer that + * is now off the list. + */ + final private[concurrent] def pred(p: Node[E]): Node[E] = { + val q = p.prev + if (p eq q) last + else q + } + + /** Returns the first node, the unique node p for which: p.prev == null && + * p.next != p The returned node may or may not be logically deleted. + * Guarantees that head is set to the returned node. + */ + + private[concurrent] def first: Node[E] = { + while (true) { + var restartFromHead = true + + while (restartFromHead) { + restartFromHead = false + + var h = head + var p = h + var q: ConcurrentLinkedDeque.Node[E] = null + + while (true) { + // Check for head updates every other hop. + if (({ q = p.prev; q } != null) && ({ p = q; q = p.prev; q } != null)) + // If p == q, we are sure to follow head instead. + p = + if (h ne { h = head; h }) h + else q + else if ((p eq h) || casHead(h, p)) return p + else restartFromHead = true + } + } + } + // unreachable + null + } + + /** Returns the last node, the unique node p for which: p.next == null && + * p.prev != p The returned node may or may not be logically deleted. + * Guarantees that tail is set to the returned node. + */ + private[concurrent] def last: Node[E] = { + + while (true) { + var restart = false + + while (!restart) { + var t = tail + var p = t + var q: Node[E] = null + // Check for tail updates every other hop. + + while (true) + if ({ q = p.next; q } != null && { p = q; q = p.next; q } != null) + // If p == q, we are sure to follow tail instead. + p = + if (t ne { t = tail; t }) t + else q + else if ((p eq t) || casTail(t, p)) return p + else restart = true + } + } + + // unreachable + null + } + + /** Returns element unless it is null, in which case throws + * NoSuchElementException. + * + * @param v + * the element + * @return + * the element + */ + // Minor convenience utilities + private def screenNullResult(v: E) = { + if (v == null) + throw new NoSuchElementException + v + } + + /** Constructs a deque initially containing the elements of the given + * collection, added in traversal order of the collection's iterator. + * + * @param c + * the collection of elements to initially contain throws + * NullPointerException if the specified collection or any of its elements + * are null + */ + + def this(c: util.Collection[_ <: E]) = { + this() + var h, t: Node[E] = null + + c.forEach { e => + { + val newNode = new Node[E](Objects.requireNonNull(e)) + + if (h == null) { + h = newNode + t = newNode + } else { + t.lazySetNext(newNode) + newNode.lazySetPrev(t) + t = newNode + } + } + } + + initHeadTail(h, t) + } + + /** Initializes head and tail, ensuring invariants hold. + */ + private def initHeadTail(_h: Node[E], _t: Node[E]): Unit = { + var h = _h + var t = _t + + if (h == t) { + if (h == null) { + h = new Node[E]() + t = h + } else { + // Avoid edge case of a single Node with non-null item. + val newNode = new Node[E]() + t.lazySetNext(newNode) + newNode.lazySetPrev(t) + t = newNode + } + } + head = h + tail = t + } + + /** Inserts the specified element at the front of this deque. As the deque is + * unbounded, this method will never throw IllegalStateException. + * + * throws NullPointerException if the specified element is null + */ + override def addFirst(e: E): Unit = + linkFirst(e) + + /** Inserts the specified element at the end of this deque. As the deque is + * unbounded, this method will never throw IllegalStateException. + * + *

This method is equivalent to add(). + * + * throws NullPointerException if the specified element is null + */ + override def addLast(e: E): Unit = + linkLast(e) + + /** Inserts the specified element at the front of this deque. As the deque is + * unbounded, this method will never return {@code false}. + * + * @return + * {@code true} (as specified by {@link Deque# offerFirst}) throws + * NullPointerException if the specified element is null + */ + override def offerFirst(e: E): Boolean = { + linkFirst(e) + true + } + + /** Inserts the specified element at the end of this deque. As the deque is + * unbounded, this method will never return {@code false}. + * + *

This method is equivalent to add(). + * + * @return + * {@code true} (as specified by {@link Deque# offerLast}) throws + * NullPointerException if the specified element is null + */ + override def offerLast(e: E): Boolean = { + linkLast(e) + true + } + + override def peekFirst(): E = { + var p = first + while (p != null) { + val item = p.item + if (item != null) return item + p = succ(p) + } + null.asInstanceOf[E] + } + + override def peekLast(): E = { + var p = last + while (p != null) { + val item = p.item + if (item != null) return item + p = pred(p) + } + null.asInstanceOf[E] + } + + /** throws NoSuchElementException + */ + override def getFirst(): E = screenNullResult(peekFirst()) + + /** throws NoSuchElementException + */ + override def getLast(): E = screenNullResult(peekLast()) + + override def pollFirst(): E = { + var p = first + + while (p != null) { + val item = p.item + + if (item != null && p.casItem(item, null.asInstanceOf[E])) { + unlink(p) + return item + } + + p = succ(p) + } + + null.asInstanceOf[E] + } + + override def pollLast(): E = { + var p = last + + while (p != null) { + val item = p.item + if (item != null && p.casItem(item, null.asInstanceOf[E])) { + unlink(p) + return item + } + + p = pred(p) + } + + null.asInstanceOf[E] + } + + /** throws NoSuchElementException + */ + override def removeFirst(): E = screenNullResult(pollFirst()) + + /** throws NoSuchElementException + */ + override def removeLast(): E = screenNullResult(pollLast()) + + /** Inserts the specified element at the tail of this deque. As the deque is + * unbounded, this method will never return {@code false}. + * + * @return + * {@code true} (as specified by {@link Queue# offer}) throws + * NullPointerException if the specified element is null + */ + // *** Queue and stack methods *** + override def offer(e: E): Boolean = offerLast(e) + + /** Inserts the specified element at the tail of this deque. As the deque is + * unbounded, this method will never throw IllegalStateException or return + * {@code false}. + * + * @return + * {@code true} (as specified by {@link Collection# add}) throws + * NullPointerException if the specified element is null + */ + override def add(e: E): Boolean = offerLast(e) + + override def poll(): E = pollFirst() + + override def peek(): E = peekFirst() + + /** @throws NoSuchElementException + */ + override def remove(): E = removeFirst() + + /** @throws NoSuchElementException + */ + override def pop(): E = removeFirst() + + /** @throws NoSuchElementException + */ + override def element(): E = getFirst() + + /** throws NullPointerException + */ + override def push(e: E): Unit = addFirst(e) + + /** Removes the first occurrence of the specified element from this deque. If + * the deque does not contain the element, it is unchanged. More formally, + * removes the first element {@code e} such that {@code o.equals(e)} (if such + * an element exists). Returns {@code true} if this deque contained the + * specified element (or equivalently, if this deque changed as a result of + * the call). + * + * @param o + * element to be removed from this deque, if present + * @return + * {@code true} if the deque contained the specified element throws + * NullPointerException if the specified element is null + */ + override def removeFirstOccurrence(o: Any): Boolean = { + Objects.requireNonNull(o) + var p = first + while (p != null) { + val item = p.item + if (item != null && o == item && p.casItem(item, null.asInstanceOf[E])) { + unlink(p) + return true + } + p = succ(p) + } + false + } + + /** Removes the last occurrence of the specified element from this deque. If + * the deque does not contain the element, it is unchanged. More formally, + * removes the last element {@code e} such that {@code o.equals(e)} (if such + * an element exists). Returns {@code true} if this deque contained the + * specified element (or equivalently, if this deque changed as a result of + * the call). + * + * @param o + * element to be removed from this deque, if present + * @return + * {@code true} if the deque contained the specified element throws + * NullPointerException if the specified element is null + */ + override def removeLastOccurrence(o: Any): Boolean = { + Objects.requireNonNull(o) + var p = last + while (p != null) { + val item = p.item + if (item != null && o == item && p.casItem(item, null.asInstanceOf[E])) { + unlink(p) + return true + } + p = pred(p) + } + false + } + + /** Returns {@code true} if this deque contains the specified element. More + * formally, returns {@code true} if and only if this deque contains at least + * one element {@code e} such that {@code o.equals(e)}. + * + * @param o + * element whose presence in this deque is to be tested + * @return + * {@code true} if this deque contains the specified element + */ + override def contains(o: Any): Boolean = { + if (o != null) { + var p = first + while (p != null) { + val item = p.item + if (item != null && o == item) return true + p = succ(p) + } + } + false + } + + /** Returns {@code true} if this collection contains no elements. + * + * @return + * {@code true} if this collection contains no elements + */ + override def isEmpty(): Boolean = + peekFirst() == null + + /** Returns the number of elements in this deque. If this deque contains more + * than {@code Integer.MAX_VALUE} elements, it returns {@code + * Integer.MAX_VALUE}. + * + *

Beware that, unlike in most collections, this method is NOT a + * constant-time operation. Because of the asynchronous nature of these + * deques, determining the current number of elements requires traversing + * them all to count them. Additionally, it is possible for the size to + * change during execution of this method, in which case the returned result + * will be inaccurate. Thus, this method is typically not very useful in + * concurrent applications. + * + * @return + * the number of elements in this deque + */ + override def size(): Int = { + while (true) { + var count = 0 + var p = first + var restart = false + while (p != null && !restart) { + if (p.item != null) { + count += 1 + // @see Collection.size() + if (count == Integer.MAX_VALUE) return count + } + if (p eq { p = p.next; p }) restart = true + } + if (!restart) return count + } + // unreachable + -1 + } + + /** Removes the first occurrence of the specified element from this deque. If + * the deque does not contain the element, it is unchanged. More formally, + * removes the first element {@code e} such that {@code o.equals(e)} (if such + * an element exists). Returns {@code true} if this deque contained the + * specified element (or equivalently, if this deque changed as a result of + * the call). + * + *

This method is equivalent to removeFirstOccurrence(Object)}. + * + * @param o + * element to be removed from this deque, if present + * @return + * {@code true} if the deque contained the specified element throws + * NullPointerException if the specified element is null + */ + override def remove(o: Any): Boolean = removeFirstOccurrence(o) + + /** Appends all of the elements in the specified collection to the end of this + * deque, in the order that they are returned by the specified collection's + * iterator. Attempts to {@code addAll} of a deque to itself result in {@code + * IllegalArgumentException}. + * + * @param c + * the elements to be inserted into this deque + * @return + * {@code true} if this deque changed as a result of the call throws + * NullPointerException if the specified collection or any of its elements + * are null throws IllegalArgumentException if the collection is this deque + */ + override def addAll(c: util.Collection[_ <: E]): Boolean = { + if (c eq this) + throw new IllegalArgumentException // As historically specified in AbstractQueue#addAll + // Copy c into a private chain of Nodes + var beginningOfTheEnd: Node[E] = null + var last: Node[E] = null + + c.forEach { e => + val newNode = new Node[E](Objects.requireNonNull(e)) + if (beginningOfTheEnd == null) beginningOfTheEnd = { + last = newNode; last + } + else { + last.lazySetNext(newNode) + newNode.lazySetPrev(last) + last = newNode + } + } + if (beginningOfTheEnd == null) return false + // Atomically append the chain at the tail of this collection + var restart = false + while (!restart) { + restart = false + + var t = tail + var p = t + var q: Node[E] = null + // Check for tail updates every other hop. + while (true) + if ({ q = p.next; q } != null && { p = q; q = p.next; q } != null) + // If p == q, we are sure to follow tail instead. + p = + if (t ne { t = tail; t }) t + else q + else if (p.prev eq p) // NEXT_TERMINATOR + restart = true + else { + // p is last node + beginningOfTheEnd.lazySetPrev(p) // CAS piggyback + if (p.casNext(null, beginningOfTheEnd)) { + // Successful CAS is the linearization point + // for all elements to be added to this deque. + if (!casTail(t, last)) { + // Try a little harder to update tail, + // since we may be adding many elements. + t = tail + if (last.next == null) casTail(t, last) + } + return true + } + } + } + + // unreachable + false + } + + /** Removes all of the elements from this deque. + */ + override def clear(): Unit = { + while (pollFirst() != null) {} + } + + override def toString: String = { + var a: Array[String] = null + while (true) { + var charLength = 0 + var size = 0 + var p = first + var restart = false + while (p != null && !restart) { + val item = p.item + if (item != null) { + if (a == null) a = new Array[String](4) + else if (size == a.length) a = util.Arrays.copyOf(a, 2 * size) + val s = item.toString + a({ + size += 1; size - 1 + }) = s + charLength += s.length + } + if (p eq { p = p.next; p }) restart = true + } + if (!restart) { + if (size == 0) return "[]" + return Helpers.toString(a.asInstanceOf[Array[AnyRef]], size, charLength) + } + } + // unreachable + null + } + + private def toArrayInternal(a: Array[AnyRef]): Array[AnyRef] = { + var x = a + var restartFromHead = true + while (true) { + var size = 0 + var p = first + restartFromHead = false + while (p != null && !restartFromHead) { + val item = p.item + if (item != null) { + if (x == null) x = new Array[AnyRef](4) + else if (size == x.length) x = util.Arrays.copyOf(x, 2 * (size + 4)) + x(size) = item + size += 1 + } + if (p eq { p = p.next; p }) restartFromHead = true + } + if (!restartFromHead) { + if (x == null) return new Array[AnyRef](0) + else if (a != null && size <= a.length) { + if (a ne x) System.arraycopy(x, 0, a, 0, size) + if (size < a.length) a(size) = null + return a + } + return if (size == x.length) x + else util.Arrays.copyOf(x, size) + } + } + a // unreachable, but compiler requires a return value. + } + + /** Returns an array containing all of the elements in this deque, in proper + * sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this deque. (In other words, this method must allocate a new + * array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return + * an array containing all of the elements in this deque + */ + override def toArray(): Array[AnyRef] = toArrayInternal(null) + + /** Returns an array containing all of the elements in this deque, in proper + * sequence (from first to last element); the runtime type of the returned + * array is that of the specified array. If the deque fits in the specified + * array, it is returned therein. Otherwise, a new array is allocated with + * the runtime type of the specified array and the size of this deque. + * + *

If this deque fits in the specified array with room to spare (i.e., the + * array has more elements than this deque), the element in the array + * immediately following the end of the deque is set to {@code null}. + * + *

Like the toArray() method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows precise + * control over the runtime type of the output array, and may, under certain + * circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a deque known to contain only strings. The + * following code can be used to dump the deque into a newly allocated array + * of {@code String}: + * + *

 {@code String[] y = x.toArray(new String[0]);}
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a + * the array into which the elements of the deque are to be stored, if it + * is big enough; otherwise, a new array of the same runtime type is + * allocated for this purpose + * @return + * an array containing all of the elements in this deque throws + * ArrayStoreException if the runtime type of the specified array is not a + * supertype of the runtime type of every element in this deque throws + * NullPointerException if the specified array is null + */ + + override def toArray[T <: AnyRef](a: Array[T]): Array[T] = { + Objects.requireNonNull(a) + toArrayInternal(a.asInstanceOf[Array[AnyRef]]).asInstanceOf[Array[T]] + } + + /** Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * + *

The returned iterator is weakly consistent. + * + * @return + * an iterator over the elements in this deque in proper sequence + */ + + override def iterator(): Iterator[E] = + new Itr() + + /** Returns an iterator over the elements in this deque in reverse sequential + * order. The elements will be returned in order from last (tail) to first + * (head). + * + *

The returned iterator is weakly consistent. + * + * @return + * an iterator over the elements in this deque in reverse order + */ + override def descendingIterator(): Iterator[E] = + new DescendingItr + + abstract private class AbstractItr() extends Iterator[E] { + + /** Next node to return item for. + */ + private var nextNode: Node[E] = null + + /** nextItem holds on to item fields because once we claim that an element + * exists in hasNext(), we must return it in the following next() call even + * if it was in the process of being removed when hasNext() was called. + */ + private var nextItem: E = null.asInstanceOf[E] + + /** Node returned by most recent call to next. Needed by remove. Reset to + * null if this element is deleted by a call to remove. + */ + private var lastRet: Node[E] = null + + private[concurrent] def startNode: Node[E] + + private[concurrent] def nextNode(p: Node[E]): Node[E] + + advance() // customize vars after constructor has initially set them. + + /** Sets nextNode and nextItem to next valid node, or to null if no such. + */ + private def advance(): Unit = { + lastRet = nextNode + var p = + if (nextNode == null) startNode + else nextNode(nextNode) + + var breakNow = false + while (!breakNow) { + if (p == null) { + // might be at active end or TERMINATOR node; both are OK + nextNode = null.asInstanceOf[Node[E]] + nextItem = null.asInstanceOf[E] + breakNow = true + } else { + val item = p.item + if (item != null) { + nextNode = p + nextItem = item + breakNow = true + } + p = nextNode(p) + } + } + } + + override def hasNext(): Boolean = + nextItem != null + + override def next(): E = { + val item = nextItem + if (item == null) throw new NoSuchElementException + advance() + item + } + + override def remove(): Unit = { + val l = lastRet + if (l == null) throw new IllegalStateException + l.item = null.asInstanceOf[E] + unlink(l) + lastRet = null.asInstanceOf[Node[E]] + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr with Iterator[E] { + override private[concurrent] def startNode = first + + override private[concurrent] def nextNode(p: Node[E]) = succ(p) + } + + /** Descending iterator */ +// private class DescendingItr[E] extends ConcurrentLinkedDeque.AbstractItr[E] { + private class DescendingItr extends AbstractItr with Iterator[E] { + + override private[concurrent] def startNode: Node[E] = last + + override private[concurrent] def nextNode(p: Node[E]): Node[E] = pred(p) + } + + /** Returns a Spliterator over the elements in this deque. + * + *

The returned spliterator is weakly consistent. + * + *

The {@code Spliterator} reports Spliterator#CONCURRENT, + * Spliterator#ORDERED, and Spliterator#NONNULL . + * + * Implementation Note: The {@code Spliterator} implements {@code trySplit} + * to permit limited parallelism. + * @return + * a {@code Spliterator} over the elements in this deque + * @since 1.8 + */ + override def spliterator() = new CLDSpliterator[E](this) + + private def casHead(cmp: Node[E], `val`: Node[E]): Boolean = + HEAD.compareExchangeStrong(cmp, `val`) + + private def casTail(cmp: Node[E], `val`: Node[E]): Boolean = + TAIL.compareExchangeStrong(cmp, `val`) + +// No support for ObjectInputStream in Scala Native +// private def writeObject(s: ObjectOutputStream): Unit +// private def readObject(s: ObjectInputStream): Unit +} diff --git a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/util/concurrent/ConcurrentLinkedDequeTest.scala b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/util/concurrent/ConcurrentLinkedDequeTest.scala new file mode 100644 index 0000000000..8595826d61 --- /dev/null +++ b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/util/concurrent/ConcurrentLinkedDequeTest.scala @@ -0,0 +1,982 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +/* Lightly modified for Scala Native. + */ + +package org.scalanative.testsuite.javalib.util.concurrent + +import java.util +import java.util.{Arrays, Collection, NoSuchElementException} +import java.util.{Random} +import java.util.concurrent.ConcurrentLinkedDeque + +import org.junit.Test +import org.junit.Assert._ +import org.junit.Ignore + +class ConcurrentLinkedDequeTest extends JSR166Test { + import JSR166Test._ + + /** Returns a new deque of given size containing consecutive Integers 0 ... n. + */ + private def populatedDeque(n: Int) = { + val q = new ConcurrentLinkedDeque[Integer] + assertTrue(q.isEmpty) + for (i <- 0 until n) { + assertTrue(q.offer(new Integer(i))) + } + assertFalse(q.isEmpty) + assertEquals(n, q.size) + q + } + + private def populatedDequeOfItem(n: Int) = { + val q = new ConcurrentLinkedDeque[Item] + assertTrue(q.isEmpty) + for (i <- 0 until n) { + assertTrue(q.offer(new Item(i))) + } + assertFalse(q.isEmpty) + assertEquals(n, q.size) + q + } + + /** new deque is empty + */ + @Test def testConstructor1(): Unit = { + assertTrue(new ConcurrentLinkedDeque[AnyRef]().isEmpty) + assertEquals(0, new ConcurrentLinkedDeque[AnyRef]().size) + } + + /** Initializing from null Collection throws NPE + */ + @Test def testConstructor3(): Unit = { + try { + new ConcurrentLinkedDeque[AnyRef](null.asInstanceOf[Collection[AnyRef]]) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** Initializing from Collection of null elements throws NPE + */ + @Test def testConstructor4(): Unit = { + try { + new ConcurrentLinkedDeque[AnyRef]( + Arrays.asList(new Array[AnyRef](SIZE): _*) + ) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** Initializing from Collection with some null elements throws NPE + */ + @Test def testConstructor5(): Unit = { + val items: Array[Item] = new Array[Item](5) + items(0) = zero + try { + new ConcurrentLinkedDeque[Item](Arrays.asList(items: _*)) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** Deque contains all elements of collection used to initialize + */ + @Test def testConstructor6(): Unit = { + val items: Array[Item] = defaultItems + val q: ConcurrentLinkedDeque[Item] = + new ConcurrentLinkedDeque( + Arrays.asList(items: _*) + ) + + val expectedSize = SIZE // SIZE is defined in JSR166Test.scala as 20 + + assertEquals(s"q.size() expect: ${expectedSize}", expectedSize, q.size()) + } + + /** isEmpty is true before add, false after + */ + @Test def testEmpty(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + assertTrue(q.isEmpty) + q.add(one) + assertFalse(q.isEmpty) + q.add(two) + q.remove + q.remove + assertTrue(q.isEmpty) + } + + /** size() changes when elements added and removed + */ + @Test def testSize(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(SIZE - i, q.size) + q.remove + + i += 1 + } + + i = 0 + while (i < SIZE) { + assertEquals(i, q.size) + q.add(new Integer(i)) + + i += 1 + } + } + + /** push(null) throws NPE + */ + @Test def testPushNull(): Unit = { + val q = new ConcurrentLinkedDeque[AnyRef] + try { + q.push(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** peekFirst() returns element inserted with push + */ + @Test def testPush(): Unit = { + val q = populatedDeque(3) + q.pollLast + q.push(four) + assertSame(four, q.peekFirst) + } + + /** pop() removes first element, or throws NSEE if empty + */ + @Test def testPop(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.pop) + + i += 1 + } + try { + q.pop + shouldThrow() + } catch { + case success: NoSuchElementException => + } + } + + /** offer(null) throws NPE + */ + @Test def testOfferNull(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.offer(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** offerFirst(null) throws NPE + */ + @Test def testOfferFirstNull(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.offerFirst(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** offerLast(null) throws NPE + */ + @Test def testOfferLastNull(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.offerLast(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** offer(x) succeeds + */ + @Test def testOffer(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + assertTrue(q.offer(zero)) + assertTrue(q.offer(one)) + assertSame(zero, q.peekFirst().intValue) + assertSame(one, q.peekLast().intValue) + } + + /** offerFirst(x) succeeds + */ + @Test def testOfferFirst(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + assertTrue(q.offerFirst(zero)) + assertTrue(q.offerFirst(one)) + assertSame(one, q.peekFirst().intValue) + assertSame(zero, q.peekLast().intValue) + } + + /** offerLast(x) succeeds + */ + @Test def testOfferLast(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + assertTrue(q.offerLast(zero)) + assertTrue(q.offerLast(one)) + assertSame(zero, q.peekFirst().intValue) + assertSame(one, q.peekLast().intValue) + } + + /** add(null) throws NPE + */ + @Test def testAddNull(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.add(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** addFirst(null) throws NPE + */ + @Test def testAddFirstNull(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.addFirst(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** addLast(null) throws NPE + */ + @Test def testAddLastNull(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.addLast(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** add(x) succeeds + */ + @Test def testAdd(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + assertTrue(q.add(zero)) + assertTrue(q.add(one)) + assertSame(zero, q.peekFirst().intValue) + assertSame(one, q.peekLast().intValue) + } + + /** addFirst(x) succeeds + */ + @Test def testAddFirst(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + q.addFirst(zero) + q.addFirst(one) + assertSame(one, q.peekFirst().intValue) + assertSame(zero, q.peekLast().intValue) + } + + /** addLast(x) succeeds + */ + @Test def testAddLast(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + q.addLast(zero) + q.addLast(one) + assertSame(zero, q.peekFirst().intValue) + assertSame(one, q.peekLast().intValue) + } + + /** addAll(null) throws NPE + */ + @Test def testAddAll1(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.addAll(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** addAll(this) throws IAE + */ + @Test def testAddAllSelf(): Unit = { + val q = populatedDeque(SIZE) + try { + q.addAll(q) + shouldThrow() + } catch { + case success: IllegalArgumentException => + } + } + + /** addAll of a collection with null elements throws NPE + */ + @Test def testAddAll2(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + try { + q.addAll(Arrays.asList(new Array[Item](SIZE): _*)) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** addAll of a collection with any null elements throws NPE after possibly + * adding some elements + */ + @Test def testAddAll3(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + val items = new Array[Item](SIZE) + items(0) = zero + try { + q.addAll(Arrays.asList(items: _*)) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** Deque contains all elements, in traversal order, of successful addAll + */ + @Test def testAddAll5(): Unit = { + val empty: Array[Item] = new Array[Item](0) + val items: Array[Item] = defaultItems + + val q = new ConcurrentLinkedDeque[Item] + assertFalse(q.addAll(Arrays.asList(empty: _*))) + assertTrue(q.addAll(Arrays.asList(items: _*))) + + var i = 0 + while (i < SIZE) { + assertEquals(items(i), q.poll) + i += 1 + } + } + + /** pollFirst() succeeds unless empty + */ + @Test def testPollFirst(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.pollFirst) + i += 1 + } + assertNull(q.pollFirst()) + } + + /** pollLast() succeeds unless empty + */ + @Test def testPollLast(): Unit = { + val q = populatedDeque(SIZE) + for (i <- SIZE - 1 to 0 by -1) { + assertEquals(i, q.pollLast().intValue) + } + assertNull(q.pollLast()) + } + + /** poll() succeeds unless empty + */ + @Test def testPoll(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.poll().intValue) + i += 1 + } + assertNull(q.poll) + } + + /** peek() returns next element, or null if empty + */ + @Test def testPeek(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.peek) + assertEquals(i, q.poll) + assertTrue(q.peek == null || !(q.peek == i)) + + i += 1 + } + assertNull(q.peek) + } + + /** element() returns first element, or throws NSEE if empty + */ + @Test def testElement(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.element) + assertEquals(i, q.poll) + + i += 1 + } + try { + q.element + shouldThrow() + } catch { + case success: NoSuchElementException => + } + } + + /** remove() removes next element, or throws NSEE if empty + */ + @Test def testRemove(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.remove) + + i += 1 + } + try { + q.remove + shouldThrow() + } catch { + case success: NoSuchElementException => + } + } + + /** remove(x) removes x and returns true if present + */ + @Test def testRemoveElement(): Unit = { + val q = populatedDeque(SIZE) + var i = 1 + while (i < SIZE) { + assertTrue(q.contains(i)) + assertTrue(q.remove(i)) + assertFalse(q.contains(i)) + assertTrue(q.contains(i - 1)) + + i += 2 + } + + i = 0 + while (i < SIZE) { + assertTrue(q.contains(i)) + assertTrue(q.remove(i)) + assertFalse(q.contains(i)) + assertFalse(q.remove(i + 1)) + assertFalse(q.contains(i + 1)) + + i += 2 + } + assertTrue(q.isEmpty) + } + + /** peekFirst() returns next element, or null if empty + */ + @Test def testPeekFirst(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.peekFirst) + assertEquals(i, q.pollFirst) + assertTrue(q.peekFirst == null || !(q.peekFirst == i)) + + i += 1 + } + assertNull(q.peekFirst) + } + + /** peekLast() returns next element, or null if empty + */ + @Test def testPeekLast(): Unit = { + val q = populatedDeque(SIZE) + for (i <- SIZE - 1 to 0 by -1) { + assertEquals(i, q.peekLast) + assertEquals(i, q.pollLast) + assertTrue(q.peekLast == null || !(q.peekLast == i)) + } + assertNull(q.peekLast) + } + + /** getFirst() returns first element, or throws NSEE if empty + */ + @Test def testFirstElement(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.getFirst) + assertEquals(i, q.pollFirst) + + i += 1 + } + try { + q.getFirst + shouldThrow() + } catch { + case success: NoSuchElementException => + } + } + + /** getLast() returns last element, or throws NSEE if empty + */ + @Test def testLastElement(): Unit = { + val q = populatedDeque(SIZE) + for (i <- SIZE - 1 to 0 by -1) { + assertEquals(i, q.getLast) + assertEquals(i, q.pollLast) + } + try { + q.getLast + shouldThrow() + } catch { + case success: NoSuchElementException => + } + assertNull(q.peekLast) + } + + /** removeFirst() removes first element, or throws NSEE if empty + */ + @Test def testRemoveFirst(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertEquals(i, q.removeFirst) + + i += 1 + } + try { + q.removeFirst + shouldThrow() + } catch { + case success: NoSuchElementException => + } + assertNull(q.peekFirst) + } + + /** removeLast() removes last element, or throws NSEE if empty + */ + @Test def testRemoveLast(): Unit = { + val q = populatedDeque(SIZE) + for (i <- SIZE - 1 to 0 by -1) { + assertEquals(i, q.removeLast) + } + try { + q.removeLast + shouldThrow() + } catch { + case success: NoSuchElementException => + } + assertNull(q.peekLast) + } + + /** removeFirstOccurrence(x) removes x and returns true if present + */ + @Test def testRemoveFirstOccurrence(): Unit = { + val q = populatedDeque(SIZE) + var i = 1 + while (i < SIZE) { + assertTrue(q.removeFirstOccurrence(new Integer(i))) + + i += 2 + } + + i = 0 + while (i < SIZE) { + assertTrue(q.removeFirstOccurrence(new Integer(i))) + assertFalse(q.removeFirstOccurrence(new Integer(i + 1))) + + i += 2 + } + assertTrue(q.isEmpty) + } + + /** removeLastOccurrence(x) removes x and returns true if present + */ + @Test def testRemoveLastOccurrence(): Unit = { + val q = populatedDeque(SIZE) + var i = 1 + while (i < SIZE) { + assertTrue(q.removeLastOccurrence(new Integer(i))) + + i += 2 + } + + i = 0 + while (i < SIZE) { + assertTrue(q.removeLastOccurrence(new Integer(i))) + assertFalse(q.removeLastOccurrence(new Integer(i + 1))) + + i += 2 + } + assertTrue(q.isEmpty) + } + + /** contains(x) reports true when elements added but not yet removed + */ + @Test def testContains(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + assertTrue(q.contains(new Integer(i))) + q.poll + assertFalse(q.contains(new Integer(i))) + + i += 1 + } + } + + /** clear() removes all elements + */ + @Test def testClear(): Unit = { + val q = populatedDeque(SIZE) + q.clear() + assertTrue(q.isEmpty) + assertEquals(0, q.size) + q.add(one) + assertFalse(q.isEmpty) + q.clear() + assertTrue(q.isEmpty) + } + + /** containsAll(c) is true when c contains a subset of elements + */ + @Test def testContainsAll(): Unit = { + val q = populatedDequeOfItem(SIZE) + val p = new ConcurrentLinkedDeque[Item] + var i = 0 + while (i < SIZE) { + assertTrue(q.containsAll(p)) + assertFalse(p.containsAll(q)) + p.add(new Integer(i)) + + i += 1 + } + assertTrue(p.containsAll(q)) + } + + /** retainAll(c) retains only those elements of c and reports true if change + */ + @Test def testRetainAll(): Unit = { + val q = populatedDeque(SIZE) + val p = populatedDeque(SIZE) + var i = 0 + while (i < SIZE) { + val changed = q.retainAll(p) + if (i == 0) assertFalse(changed) + else assertTrue(changed) + assertTrue(q.containsAll(p)) + assertEquals(SIZE - i, q.size) + p.remove + + i += 1 + } + } + + /** removeAll(c) removes only those elements of c and reports true if changed + */ + @Test def testRemoveAll(): Unit = { + var i = 1 + while (i < SIZE) { + val q = populatedDeque(SIZE) + val p = populatedDeque(i) + assertTrue(q.removeAll(p)) + assertEquals(SIZE - i, q.size) + for (j <- 0 until i) { + val x = p.remove.asInstanceOf[Integer] + assertFalse(q.contains(x)) + } + + i += 1 + } + } + + /** toArray() contains all elements in FIFO order + */ + @Test def testToArray(): Unit = { + val q = populatedDeque(SIZE) + val o = q.toArray + for (i <- 0 until o.length) { + assertSame(o(i), q.poll) + } + } + + /** toArray(a) contains all elements in FIFO order + */ + @Test def testToArray2(): Unit = { + val q = populatedDeque(SIZE) + val ints = new Array[Integer](SIZE) + val array = q.toArray(ints) + assertSame(ints, array) + for (i <- 0 until ints.length) { + assertSame(ints(i), q.poll) + } + } + + /** toArray(null) throws NullPointerException + */ + @Test def testToArray_NullArg(): Unit = { + val q = populatedDeque(SIZE) + try { + q.toArray(null) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + + /** toArray(incompatible array type) throws ArrayStoreException + */ + // Lack of ArrayStoreExeption in Scala Native is a known defect/insufficiency + @Ignore("No distinguishment in Array component types in Scala Native") + @Test def testToArray1_BadArg(): Unit = { + val q = populatedDeque(SIZE) + try { + q.toArray(new Array[String](10)) + shouldThrow() + } catch { + case success: ArrayStoreException => + } + } + + /** Iterator iterates through all elements + */ + @Test def testIterator(): Unit = { + val q = populatedDeque(SIZE) + val it = q.iterator + var i = 0 + i = 0 + while (it.hasNext) { + assertTrue(q.contains(it.next)) + i += 1 + } + assertEquals(i, SIZE) + assertIteratorExhausted(it) + } + + /** iterator of empty collection has no elements + */ + @Test def testEmptyIterator(): Unit = { + val c = new ConcurrentLinkedDeque[Item] + assertIteratorExhausted(c.iterator) + assertIteratorExhausted(c.descendingIterator) + } + + /** Iterator ordering is FIFO + */ + @Test def testIteratorOrdering(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + q.add(one) + q.add(two) + q.add(three) + var k = 0 + val it = q.iterator + while (it.hasNext) + assertEquals( + { + k += 1; k + }, + it.next.intValue + ) + assertEquals(3, k) + } + + /** Modifications do not cause iterators to fail + */ + @Test def testWeaklyConsistentIteration(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + q.add(one) + q.add(two) + q.add(three) + val it = q.iterator + while (it.hasNext) { + q.remove + it.next + } + assertEquals("deque should be empty again", 0, q.size) + } + + /** iterator.remove() removes current element + */ + @Test def testIteratorRemove(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + val rng = new Random + for (iters <- 0 until 100) { + val max = rng.nextInt(5) + 2 + val split = rng.nextInt(max - 1) + 1 + for (j <- 1 to max) { + q.add(new Integer(j)) + } + var it = q.iterator + for (j <- 1 to split) { + assertEquals(it.next, new Item(j)) + } + it.remove() + assertEquals(it.next, new Item(split + 1)) + for (j <- 1 to split) { + q.remove(new Item(j)) + } + it = q.iterator + for (j <- split + 1 to max) { + assertEquals(it.next, new Item(j)) + it.remove() + } + assertFalse(it.hasNext) + assertTrue(q.isEmpty) + } + } + + /** Descending iterator iterates through all elements + */ + @Test def testDescendingIterator(): Unit = { + val q = populatedDeque(SIZE) + var i = 0 + val it = q.descendingIterator + while (it.hasNext) { + assertTrue(q.contains(it.next)) + i += 1 + } + assertEquals(i, SIZE) + assertFalse(it.hasNext) + try { + it.next + shouldThrow() + } catch { + case success: NoSuchElementException => + } + } + + /** Descending iterator ordering is reverse FIFO + */ + @Test def testDescendingIteratorOrdering(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + for (iters <- 0 until 100) { + q.add(new Item(3)) + q.add(new Item(2)) + q.add(new Item(1)) + var k = 0 + val it = q.descendingIterator + while (it.hasNext) + assertEquals( + { + k += 1; k + }, + it.next.intValue + ) + assertEquals(3, k) + q.remove + q.remove + q.remove + } + } + + /** descendingIterator.remove() removes current element + */ + @Test def testDescendingIteratorRemove(): Unit = { + val q = new ConcurrentLinkedDeque[Item] + val rng = new Random + for (iters <- 0 until 100) { + val max = rng.nextInt(5) + 2 + val split = rng.nextInt(max - 1) + 1 + for (j <- max to 1 by -1) { + q.add(new Item(j)) + } + var it = q.descendingIterator + for (j <- 1 to split) { + assertEquals(it.next, new Item(j)) + } + it.remove() + assertEquals(it.next, new Item(split + 1)) + for (j <- 1 to split) { + q.remove(new Item(j)) + } + it = q.descendingIterator + for (j <- split + 1 to max) { + assertEquals(it.next, new Item(j)) + it.remove() + } + assertFalse(it.hasNext) + assertTrue(q.isEmpty) + } + } + + /** toString() contains toStrings of elements + */ + @Test def testToString(): Unit = { + val q = populatedDeque(SIZE) + val s = q.toString + var i = 0 + while (i < SIZE) { + assertTrue(s.contains(String.valueOf(i))) + + i += 1 + } + } + + // /** + // * A deserialized serialized deque has same elements in same order + // * UNSUPPORTED + // */ + // @throws[Exception] + // @Test def testSerialization(): Unit = { + // val x = populatedDeque(SIZE) + // val y = serialClone(x) + // assertNotSame(x, y) + // assertEquals(x.size, y.size) + // assertEquals(x.toString, y.toString) + // assertTrue(util.Arrays.equals(x.toArray, y.toArray)) + // while (!x.isEmpty) { + // assertFalse(y.isEmpty) + // assertEquals(x.remove, y.remove) + // } + // assertTrue(y.isEmpty) + // } + + /** contains(null) always return false. remove(null) always throws + * NullPointerException. + */ + @Test def testNeverContainsNull(): Unit = { + val qs = Array(new ConcurrentLinkedDeque[AnyRef], populatedDeque(2)) + for (q <- qs) { + assertFalse(q.contains(null)) + try { + assertFalse(q.remove(null)) + shouldThrow() + } catch { + case success: NullPointerException => + } + try { + assertFalse(q.removeFirstOccurrence(null)) + shouldThrow() + } catch { + case success: NullPointerException => + } + try { + assertFalse(q.removeLastOccurrence(null)) + shouldThrow() + } catch { + case success: NullPointerException => + } + } + } + +} From fbfb3858f73ba715fea49e7d5f0a7190a0b607d5 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 16 Sep 2024 17:17:37 +0200 Subject: [PATCH 15/35] fix [immix/commix/none gc]: Revert using free memory size instead of total memory size to control size of the heap (#4047) * [immix/commix/none gc] Revert using free memory size instead of total memory size to control size of the heap * [immix/commix GC] Show error when failing to allocate heap space * Limit GC hepa size in emulated runs * [none gc] Improve logging when failed to allocate or grow heap * Don't call madive if mmap failed * [none gc] Use GC_THREAD_HEAP_BLOCK_SIZE to control size of allocate heap chunks in multithreaded execution. --- ci-docker/run-test-gha.sh | 1 + docs/user/runtime.md | 6 ++- .../resources/scala-native/gc/commix/Heap.c | 14 +++++-- .../resources/scala-native/gc/immix/Heap.c | 14 +++++-- .../main/resources/scala-native/gc/none/gc.c | 37 ++++++++++++------- .../scala-native/gc/shared/MemoryMap.c | 18 ++++++--- project/Commands.scala | 2 +- 7 files changed, 63 insertions(+), 29 deletions(-) diff --git a/ci-docker/run-test-gha.sh b/ci-docker/run-test-gha.sh index 20e746e627..20930edef4 100755 --- a/ci-docker/run-test-gha.sh +++ b/ci-docker/run-test-gha.sh @@ -62,4 +62,5 @@ docker run --rm \ -e SCALANATIVE_LTO="${SCALANATIVE_LTO:-none}" \ -e SCALANATIVE_TEST_DEBUG_SIGNALS=1 \ -e SCALANATIVE_TEST_PREFETCH_DEBUG_INFO=1 \ + -e GC_MAXIMUM_HEAP_SIZE=1G \ -i "${FULL_IMAGE_NAME}" diff --git a/docs/user/runtime.md b/docs/user/runtime.md index bd2288cc7b..ca8ec977ad 100644 --- a/docs/user/runtime.md +++ b/docs/user/runtime.md @@ -18,8 +18,10 @@ go from 1 MB to the system memory maximum or up to about 512 GB. The size is in bytes, kilobytes(k or K), megabytes(m or M), or gigabytes(g or G). Examples: 1024k, 1M, or 1G etc. -- GC_INITIAL_HEAP_SIZE changes the minimum heap size. -- GC_MAXIMUM_HEAP_SIZE changes the maximum heap size. +- GC_INITIAL_HEAP_SIZE changes the minimum heap size. +- GC_MAXIMUM_HEAP_SIZE changes the maximum heap size. + +The `GC_INITIAL_HEAP_SIZE` and `GC_MAXIMUM_HEAP_SIZE` are ignored by None GC when multithreading is enabled. When using this pseudo-GC implementation `GC_THREAD_HEAP_BLOCK_SIZE` env variable can be set to control the granuality of allocted heap memory blocks for each of the threads (defaults to 64MB). This env variable is ignored in sigle-threaded execution. The plan is to add more GC settings in the future using the Boehm setting names where applicable. diff --git a/nativelib/src/main/resources/scala-native/gc/commix/Heap.c b/nativelib/src/main/resources/scala-native/gc/commix/Heap.c index fa5482c889..e1b6ffdf41 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/Heap.c +++ b/nativelib/src/main/resources/scala-native/gc/commix/Heap.c @@ -34,9 +34,7 @@ bool Heap_isGrowingPossible(Heap *heap, uint32_t incrementInBlocks) { } size_t Heap_getMemoryLimit() { - size_t memorySize = getFreeMemorySize(); - if (memorySize == 0) - memorySize = getMemorySize(); + size_t memorySize = getMemorySize(); if ((uint64_t)memorySize > MAX_HEAP_SIZE) { return (size_t)MAX_HEAP_SIZE; } else { @@ -169,6 +167,16 @@ void Heap_Init(Heap *heap, size_t minHeapSize, size_t maxHeapSize) { // Init heap for small objects word_t *heapStart = Heap_mapAndAlign(maxHeapSize, BLOCK_TOTAL_SIZE); + if (!heapStart) { + fprintf( + stderr, + "[Scala Native Commix GC] Failed to allocate heap space, " + "requested size=%.2fMB, available memory=%.2fMB. Consider setting " + "GC_MAXIMUM_HEAP_SIZE env variable to limit maximal heap size", + maxHeapSize / (1024.0 * 1024.0), + getFreeMemorySize() / (1024.0 * 1024.0)); + exit(1); + } heap->heapSize = minHeapSize; heap->heapStart = heapStart; heap->heapEnd = heapStart + minHeapSize / WORD_SIZE; diff --git a/nativelib/src/main/resources/scala-native/gc/immix/Heap.c b/nativelib/src/main/resources/scala-native/gc/immix/Heap.c index 169c488395..3ee44e1975 100644 --- a/nativelib/src/main/resources/scala-native/gc/immix/Heap.c +++ b/nativelib/src/main/resources/scala-native/gc/immix/Heap.c @@ -28,9 +28,7 @@ bool Heap_isGrowingPossible(Heap *heap, uint32_t incrementInBlocks) { } size_t Heap_getMemoryLimit() { - size_t memorySize = getFreeMemorySize(); - if (memorySize == 0) - memorySize = getMemorySize(); + size_t memorySize = getMemorySize(); if ((uint64_t)memorySize > MAX_HEAP_SIZE) { return (size_t)MAX_HEAP_SIZE; } else { @@ -125,6 +123,16 @@ void Heap_Init(Heap *heap, size_t minHeapSize, size_t maxHeapSize) { // Init heap for small objects word_t *heapStart = Heap_mapAndAlign(maxHeapSize, BLOCK_TOTAL_SIZE); + if (!heapStart) { + fprintf( + stderr, + "[Scala Native Immix GC] Failed to allocate heap space, " + "requested size=%.2fMB, available memory=%.2fMB. Consider setting " + "GC_MAXIMUM_HEAP_SIZE env variable to limit maximal heap size", + maxHeapSize / (1024.0 * 1024.0), + getFreeMemorySize() / (1024.0 * 1024.0)); + exit(1); + } heap->heapSize = minHeapSize; heap->heapStart = heapStart; heap->heapEnd = heapStart + minHeapSize / WORD_SIZE; diff --git a/nativelib/src/main/resources/scala-native/gc/none/gc.c b/nativelib/src/main/resources/scala-native/gc/none/gc.c index 5964d2464d..047e14ca43 100644 --- a/nativelib/src/main/resources/scala-native/gc/none/gc.c +++ b/nativelib/src/main/resources/scala-native/gc/none/gc.c @@ -17,13 +17,7 @@ #include // Dummy GC that maps chunks of memory and allocates but never frees. -#ifdef _WIN32 -// On Windows we need to commit memory in relatively small chunks - this way -// process would not use too much resources. #define DEFAULT_CHUNK_SIZE "64M" -#else -#define DEFAULT_CHUNK_SIZE "1G" -#endif #if defined(__has_feature) #if __has_feature(address_sanitizer) @@ -51,7 +45,7 @@ size_t scalanative_GC_get_init_heapsize() { } size_t scalanative_GC_get_max_heapsize() { - return Parse_Env_Or_Default("GC_MAXIMUM_HEAP_SIZE", getFreeMemorySize()); + return Parse_Env_Or_Default("GC_MAXIMUM_HEAP_SIZE", getMemorySize()); } size_t scalanative_GC_get_used_heapsize() { return TOTAL_ALLOCATED; } @@ -60,19 +54,25 @@ void Prealloc_Or_Default() { if (TO_NORMAL_MMAP == 1L) { // Check if we have prealloc env varible // or execute default mmap settings - size_t memorySize = getFreeMemorySize(); - if (memorySize == 0) - memorySize = getMemorySize(); - assert(memorySize > 0); + size_t memorySize = getMemorySize(); - DEFAULT_CHUNK = // Default Maximum allocation Map 1GB +#if defined(SCALANATIVE_MULTITHREADING_ENABLED) + // Every starting thread would want to allocate chunk of memory. + // We want to limit their size to prevent OOM errors. + DEFAULT_CHUNK = + Choose_IF(Parse_Env_Or_Default_String("GC_THREAD_HEAP_BLOCK_SIZE", + DEFAULT_CHUNK_SIZE), + Less_OR_Equal, memorySize); + // Preallocation not support in multithreading mode +#else + DEFAULT_CHUNK = Choose_IF(Parse_Env_Or_Default_String("GC_MAXIMUM_HEAP_SIZE", DEFAULT_CHUNK_SIZE), Less_OR_Equal, memorySize); - PREALLOC_CHUNK = // Preallocation Choose_IF(Parse_Env_Or_Default("GC_INITIAL_HEAP_SIZE", 0L), Less_OR_Equal, DEFAULT_CHUNK); +#endif if (PREALLOC_CHUNK == 0L) { // no prealloc settings. CHUNK = DEFAULT_CHUNK; @@ -97,7 +97,16 @@ void scalanative_GC_init() { Prealloc_Or_Default(); current = memoryMapPrealloc(CHUNK, DO_PREALLOC); if (current == NULL) { - exitWithOutOfMemory(); + const float bytesToMB = 1024.0 * 1024.0; + fprintf(stderr, + "[Scala Native None GC] Failed to allocate or grow heap space, " + "requested size=%.2fMB, available memory=%.2fMB, already " + "allocated=%.2fMB, should preallocate=%s. Consider setting " + "GC_MAXIMUM_HEAP_SIZE env variable to limit maximal heap size", + CHUNK / bytesToMB, getFreeMemorySize() / bytesToMB, + TOTAL_ALLOCATED / bytesToMB, + DO_PREALLOC == 0 ? "false" : "true"); + exit(1); } end = current + CHUNK; #ifdef _WIN32 diff --git a/nativelib/src/main/resources/scala-native/gc/shared/MemoryMap.c b/nativelib/src/main/resources/scala-native/gc/shared/MemoryMap.c index 9340c7d09e..a63e831707 100644 --- a/nativelib/src/main/resources/scala-native/gc/shared/MemoryMap.c +++ b/nativelib/src/main/resources/scala-native/gc/shared/MemoryMap.c @@ -44,8 +44,11 @@ word_t *memoryMap(size_t memorySize) { // supports only 32-bit address space and is in most cases not recommended. return VirtualAlloc(NULL, memorySize, MEM_RESERVE, PAGE_NOACCESS); #else // Unix - return mmap(NULL, memorySize, HEAP_MEM_PROT, HEAP_MEM_FLAGS, HEAP_MEM_FD, - HEAP_MEM_FD_OFFSET); + word_t *addr = mmap(NULL, memorySize, HEAP_MEM_PROT, HEAP_MEM_FLAGS, + HEAP_MEM_FD, HEAP_MEM_FD_OFFSET); + if (addr == MAP_FAILED) + return NULL; + return addr; #endif } @@ -65,15 +68,18 @@ word_t *memoryMapPrealloc(size_t memorySize, size_t doPrealloc) { if (!doPrealloc) { return memoryMap(memorySize); } - word_t *res = mmap(NULL, memorySize, HEAP_MEM_PROT, HEAP_MEM_FLAGS_PREALLOC, - HEAP_MEM_FD, HEAP_MEM_FD_OFFSET); + word_t *addr = + mmap(NULL, memorySize, HEAP_MEM_PROT, HEAP_MEM_FLAGS_PREALLOC, + HEAP_MEM_FD, HEAP_MEM_FD_OFFSET); + if (addr == MAP_FAILED) + return NULL; #ifndef __linux__ // if we are not on linux the next best thing we can do is to mark the pages // as MADV_WILLNEED but only if doPrealloc is enabled. - madvise(res, memorySize, MADV_WILLNEED); + madvise(addr, memorySize, MADV_WILLNEED); #endif // __linux__ - return res; + return addr; #endif // !_WIN32 } diff --git a/project/Commands.scala b/project/Commands.scala index 32162b6ee3..36a1181abf 100644 --- a/project/Commands.scala +++ b/project/Commands.scala @@ -31,7 +31,7 @@ object Commands { import scala.scalanative.build.GC val runs = for { - gc <- List(GC.immix, GC.commix, GC.boehm, GC.none) + gc <- List(GC.none, GC.immix, GC.commix, GC.boehm) (project, command) <- Map( sandbox -> "run", testInterface -> "test", From c557777af3a60b12ee182a27fb69434beeb93dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Costa?= Date: Mon, 16 Sep 2024 16:45:19 +0100 Subject: [PATCH 16/35] [improvement] Optimize `java.lang.Integer::toString` (#4048) * Optimize Integer#toString --- .../src/main/scala/java/lang/Integer.scala | 129 +++--------------- 1 file changed, 19 insertions(+), 110 deletions(-) diff --git a/javalib/src/main/scala/java/lang/Integer.scala b/javalib/src/main/scala/java/lang/Integer.scala index b4a739af53..b10492ce89 100644 --- a/javalib/src/main/scala/java/lang/Integer.scala +++ b/javalib/src/main/scala/java/lang/Integer.scala @@ -168,18 +168,11 @@ final class Integer(val _value: scala.Int) protected def %(x: scala.Double): scala.Double = _value % x } -private[lang] object IntegerDecimalScale { - private[lang] val decimalScale: Array[scala.Int] = Array(1000000000, - 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1) -} - private[lang] object IntegerCache { private[lang] val cache = new Array[java.lang.Integer](256) } object Integer { - import IntegerDecimalScale.decimalScale - final val TYPE = scala.Predef.classOf[scala.scalanative.runtime.PrimitiveInt] final val MIN_VALUE = -2147483648 final val MAX_VALUE = 2147483647 @@ -425,113 +418,29 @@ object Integer { } def toString(i: scala.Int): String = { - if (i == 0) { - "0" - } else { + if (i == 0) { "0" } + else if (i == java.lang.Integer.MIN_VALUE) { "-2147483648" } + else if (i == java.lang.Integer.MAX_VALUE) { "2147483647" } + else { val negative = i < 0 + val bufferSize = if (i < 1000 && i > -1000) 4 else 11 + val buffer = new Array[Char](bufferSize) + var positiveValue = Math.abs(i) + var offset = bufferSize - 1 + while (positiveValue != 0 && offset > 0) { + val next = positiveValue / 10 + buffer(offset) = ((positiveValue - next * 10) + '0').toChar + offset = offset - 1 + positiveValue = next + } - if (i < 1000 && i > -1000) { - val buffer = new Array[Char](4) - val positive_value = - if (negative) -i - else i - var first_digit = 0 - if (negative) { - buffer(0) = '-' - first_digit += 1 - } - - var last_digit = first_digit - var quot = positive_value - while ({ - val res = quot / 10 - var digit_value = quot - ((res << 3) + (res << 1)) - digit_value += '0' - buffer(last_digit) = digit_value.toChar - last_digit += 1 - quot = res - quot != 0 - }) () - - val count = last_digit - last_digit -= 1 - while ({ - val tmp = buffer(last_digit) - buffer(last_digit) = buffer(first_digit) - last_digit -= 1 - buffer(first_digit) = tmp - first_digit += 1 - first_digit < last_digit - }) () - - new String(buffer, 0, count) - } else if (i == MIN_VALUE) { - "-2147483648" + if (negative) { + buffer(offset) = '-' } else { - val buffer = new Array[Char](11) - var positive_value = if (negative) -i else i - var first_digit = 0 - if (negative) { - buffer(0) = '-' - first_digit += 1 - } - - var last_digit = first_digit - var count = 0 - var number = 0 - var start = false - var k = 0 - while (k < 9) { - count = 0 - number = decimalScale(k) - - if (positive_value < number) { - if (start) { - buffer(last_digit) = '0' - last_digit += 1 - } - } else { - if (k > 0) { - number = decimalScale(k) << 3 - if (positive_value >= number) { - positive_value -= number - count += 8 - } - - number = decimalScale(k) << 2 - if (positive_value >= number) { - positive_value -= number - count += 4 - } - } - number = decimalScale(k) << 1 - if (positive_value >= number) { - positive_value -= number - count += 2 - } - if (positive_value >= decimalScale(k)) { - positive_value -= decimalScale(k) - count += 1 - } - if (count > 0 && !start) { - start = true - } - if (start) { - buffer(last_digit) = (count + '0').toChar - last_digit += 1 - } - } - - k += 1 - } - - buffer(last_digit) = (positive_value + '0').toChar - last_digit += 1 - count = last_digit - last_digit -= 1 - - new String(buffer, 0, count) + offset = offset + 1 } + + new String(buffer, offset, bufferSize - offset) } } From f5d7c5d419c11f04bb01eb11f17e34e8fa0ec3d3 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 16 Sep 2024 19:50:47 +0200 Subject: [PATCH 17/35] [fix/sbt-plugin] Always override default build target in Test scope to `application` (#4050) --- .../scala/scalanative/sbtplugin/ScalaNativePluginInternal.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/sbt-scala-native/src/main/scala/scala/scalanative/sbtplugin/ScalaNativePluginInternal.scala b/sbt-scala-native/src/main/scala/scala/scalanative/sbtplugin/ScalaNativePluginInternal.scala index 95314f9680..1f14bf5916 100644 --- a/sbt-scala-native/src/main/scala/scala/scalanative/sbtplugin/ScalaNativePluginInternal.scala +++ b/sbt-scala-native/src/main/scala/scala/scalanative/sbtplugin/ScalaNativePluginInternal.scala @@ -346,6 +346,7 @@ object ScalaNativePluginInternal { scalaNativeConfigSettings(true) ++ Seq( mainClass := Some("scala.scalanative.testinterface.TestMain"), + nativeConfig ~= { _.withBuildTarget(build.BuildTarget.application) }, loadedTestFrameworks := { val configName = configuration.value.name From a1a48ef80d62a6772cb9f3a6b5dee2fe60720375 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Thu, 19 Sep 2024 22:23:39 +0900 Subject: [PATCH 18/35] Fix #4026 Fix negative byte to hex conversion in LLVM IR codegen (#4052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we generated invalid LLVM IR code for `CString` that contained non-ASCII characters. For instance, the UTF-8 representation of the character "本" (which means "book" in Japanese) is `e6 9c ac`. The byte `0xe6` in an 8-bit signed value (Byte) is `-26`. When this byte (`-26`) is widened to an integer for the `toHexString` method, it applies sign extension, filling the upper 24 bits with 1s to preserve the negative value. This results in the 32-bit integer `0xffffffe6`. This commit updates the `genByteString` method in `AbstractCodeGen` to mask the byte to its lowest 8 bits. This ensures that the signed byte is correctly converted to its unsigned equivalent in the range of 0-255. --- .../scala/scalanative/codegen/llvm/AbstractCodeGen.scala | 2 +- .../scala/scala/scalanative/unsafe/CStringTest.scala | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/src/main/scala/scala/scalanative/codegen/llvm/AbstractCodeGen.scala b/tools/src/main/scala/scala/scalanative/codegen/llvm/AbstractCodeGen.scala index 4d36b01d46..0d08cd377f 100644 --- a/tools/src/main/scala/scala/scalanative/codegen/llvm/AbstractCodeGen.scala +++ b/tools/src/main/scala/scala/scalanative/codegen/llvm/AbstractCodeGen.scala @@ -607,7 +607,7 @@ private[codegen] abstract class AbstractCodeGen( bytes.foreach { case '\\' => str("\\\\") case c if c < 0x20 || c == '"' || c >= 0x7f => - val hex = Integer.toHexString(c) + val hex = Integer.toHexString(c & 0xff) str { if (hex.length < 2) "\\0" + hex else "\\" + hex diff --git a/unit-tests/native/src/test/scala/scala/scalanative/unsafe/CStringTest.scala b/unit-tests/native/src/test/scala/scala/scalanative/unsafe/CStringTest.scala index 26356d6c4c..77c57982e2 100644 --- a/unit-tests/native/src/test/scala/scala/scalanative/unsafe/CStringTest.scala +++ b/unit-tests/native/src/test/scala/scala/scalanative/unsafe/CStringTest.scala @@ -136,4 +136,13 @@ class CStringTest { assertEquals(!(cstr1 + 5), 0) } } + + @Test def cStringNonASCII(): Unit = { + // note: `fromCString` is needed to trigger compilation errors against malformed literals + fromCString(c"日本語") + fromCString(c"język polski") + fromCString(c"한국어") + + fromCString(c"🚂🚀🚁🍔") + } } From 0fbce90623ec3d7b964ca94e2d24d0e737394f13 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Thu, 19 Sep 2024 15:23:51 +0200 Subject: [PATCH 19/35] [improve/nativelib] Better detection of `LinktimeInfo.isMac` (#4051) * Improve detection of isMac - support alternative 'macosx` os naming convention. Handle `unknown` vendor for custom builds * Require vendor == 'apple' for valid `isMac` linktime value --- .../src/main/scala/scala/scalanative/meta/LinktimeInfo.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala b/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala index 5d5d9cee7b..45fd5a4cf7 100644 --- a/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala +++ b/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala @@ -20,7 +20,9 @@ object LinktimeInfo { def isLinux: Boolean = target.os == "linux" @resolvedAtLinktime - def isMac: Boolean = target.vendor == "apple" && target.os == "darwin" + def isMac: Boolean = + target.vendor == "apple" && + (target.os == "darwin" || target.os == "macosx") @resolvedAtLinktime def isFreeBSD: Boolean = target.os == "freebsd" From 167f921f44ded9b4633177d1ee88e58835910952 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Fri, 20 Sep 2024 12:19:03 +0200 Subject: [PATCH 20/35] Add Scala 3.5.1 to the build. (#4054) Update supported Scala 3 RC versions --- project/ScalaVersions.scala | 6 +- .../scala/runtime/LazyVals.scala.patch | 168 ++++++++++++++++++ 2 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 scalalib/overrides-3.5.2/scala/runtime/LazyVals.scala.patch diff --git a/project/ScalaVersions.scala b/project/ScalaVersions.scala index 45a131249e..a47fcc2a30 100644 --- a/project/ScalaVersions.scala +++ b/project/ScalaVersions.scala @@ -28,14 +28,14 @@ object ScalaVersions { crossScalaVersions("3.2", 0 to 2), crossScalaVersions("3.3", 0 to 3), crossScalaVersions("3.4", 0 to 3), - crossScalaVersions("3.5", 0 to 0) + crossScalaVersions("3.5", 0 to 1) ).flatten.distinct // Tested in scheduled nightly CI to check compiler plugins // List maintains only upcoming releases, removed from the list after reaching stable status lazy val scala3RCVersions = List( - 1.to(1).map(v => s"3.3.4-RC$v"), - 1.to(2).map(v => s"3.5.1-RC$v") + 1.to(4).map(v => s"3.3.4-RC$v"), + 1.to(1).map(v => s"3.5.2-RC$v") ).flatten // Scala versions used for publishing libraries diff --git a/scalalib/overrides-3.5.2/scala/runtime/LazyVals.scala.patch b/scalalib/overrides-3.5.2/scala/runtime/LazyVals.scala.patch new file mode 100644 index 0000000000..76baa09a4d --- /dev/null +++ b/scalalib/overrides-3.5.2/scala/runtime/LazyVals.scala.patch @@ -0,0 +1,168 @@ +--- 3.5.2-RC1/scala/runtime/LazyVals.scala ++++ overrides-3.5.2/scala/runtime/LazyVals.scala +@@ -4,44 +4,14 @@ + + import scala.annotation.* + ++import scala.scalanative.runtime.* ++import scala.scalanative.meta.LinktimeInfo.isMultithreadingEnabled ++ + /** + * Helper methods used in thread-safe lazy vals. + */ + object LazyVals { +- @nowarn +- private val unsafe: sun.misc.Unsafe = { +- def throwInitializationException() = +- throw new ExceptionInInitializerError( +- new IllegalStateException("Can't find instance of sun.misc.Unsafe") +- ) +- try +- val unsafeField = classOf[sun.misc.Unsafe].getDeclaredField("theUnsafe").nn +- if unsafeField.getType == classOf[sun.misc.Unsafe] then +- unsafeField.setAccessible(true) +- unsafeField.get(null).asInstanceOf[sun.misc.Unsafe] +- else +- throwInitializationException() +- catch case _: NoSuchFieldException => +- throwInitializationException() +- } +- +- private val base: Int = { +- val processors = java.lang.Runtime.getRuntime.nn.availableProcessors() +- 8 * processors * processors +- } +- +- private val monitors: Array[Object] = +- Array.tabulate(base)(_ => new Object) +- +- private def getMonitor(obj: Object, fieldId: Int = 0) = { +- var id = (java.lang.System.identityHashCode(obj) + fieldId) % base +- +- if (id < 0) id += base +- monitors(id) +- } +- + private final val LAZY_VAL_MASK = 3L +- private final val debug = false + + /* ------------- Start of public API ------------- */ + +@@ -63,6 +33,8 @@ + * correct. + */ + private def writeReplace(): Any = null ++ override def countDown(): Unit = if(isMultithreadingEnabled) super.countDown() ++ override def await(): Unit = if(isMultithreadingEnabled) super.await() + } + + /** +@@ -86,94 +58,47 @@ + + def STATE(cur: Long, ord: Int): Long = { + val r = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK +- if (debug) +- println(s"STATE($cur, $ord) = $r") + r + } + + def CAS(t: Object, offset: Long, e: Long, v: Int, ord: Int): Boolean = { +- if (debug) +- println(s"CAS($t, $offset, $e, $v, $ord)") +- val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL) +- val n = (e & mask) | (v.toLong << (ord * BITS_PER_LAZY_VAL)) +- unsafe.compareAndSwapLong(t, offset, e, n) ++ unexpectedUsage() + } + + def objCAS(t: Object, offset: Long, exp: Object, n: Object): Boolean = { +- if (debug) +- println(s"objCAS($t, $exp, $n)") +- unsafe.compareAndSwapObject(t, offset, exp, n) ++ unexpectedUsage() + } + + def setFlag(t: Object, offset: Long, v: Int, ord: Int): Unit = { +- if (debug) +- println(s"setFlag($t, $offset, $v, $ord)") +- var retry = true +- while (retry) { +- val cur = get(t, offset) +- if (STATE(cur, ord) == 1) retry = !CAS(t, offset, cur, v, ord) +- else { +- // cur == 2, somebody is waiting on monitor +- if (CAS(t, offset, cur, v, ord)) { +- val monitor = getMonitor(t, ord) +- monitor.synchronized { +- monitor.notifyAll() +- } +- retry = false +- } +- } +- } ++ unexpectedUsage() + } + + def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int): Unit = { +- if (debug) +- println(s"wait4Notification($t, $offset, $cur, $ord)") +- var retry = true +- while (retry) { +- val cur = get(t, offset) +- val state = STATE(cur, ord) +- if (state == 1) CAS(t, offset, cur, 2, ord) +- else if (state == 2) { +- val monitor = getMonitor(t, ord) +- monitor.synchronized { +- if (STATE(get(t, offset), ord) == 2) // make sure notification did not happen yet. +- monitor.wait() +- } +- } +- else retry = false +- } ++ unexpectedUsage() + } + + def get(t: Object, off: Long): Long = { +- if (debug) +- println(s"get($t, $off)") +- unsafe.getLongVolatile(t, off) ++ unexpectedUsage() + } + + // kept for backward compatibility + def getOffset(clz: Class[?], name: String): Long = { +- @nowarn +- val r = unsafe.objectFieldOffset(clz.getDeclaredField(name)) +- if (debug) +- println(s"getOffset($clz, $name) = $r") +- r ++ unexpectedUsage() + } + + def getStaticFieldOffset(field: java.lang.reflect.Field): Long = { +- @nowarn +- val r = unsafe.staticFieldOffset(field) +- if (debug) +- println(s"getStaticFieldOffset(${field.getDeclaringClass}, ${field.getName}) = $r") +- r ++ unexpectedUsage() + } + + def getOffsetStatic(field: java.lang.reflect.Field) = +- @nowarn +- val r = unsafe.objectFieldOffset(field) +- if (debug) +- println(s"getOffset(${field.getDeclaringClass}, ${field.getName}) = $r") +- r ++ unexpectedUsage() + ++ private def unexpectedUsage() = { ++ throw new IllegalStateException( ++ "Unexpected usage of scala.runtime.LazyVals method, " + ++ "in Scala Native lazy vals use overriden version of this class" ++ ) ++ } + + object Names { + final val state = "STATE" From 6dc8d4a681ce91afd1769a3ef4b7c91c9116948f Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sat, 21 Sep 2024 16:31:31 +0200 Subject: [PATCH 21/35] [chore] Add Scala 2.13.15 to the build (#4058) --- project/ScalaVersions.scala | 2 +- .../DenylistedTests-require-threads.txt | 2 + .../resources/2.13.15/DenylistedTests.txt | 253 ++++ .../scalanative/2.13.15/DenylistedTests.txt | 1110 +++++++++++++++++ .../neg/macro-bundle-need-qualifier.check | 4 + .../scalanative/2.13.15/neg/t11952b.check | 16 + .../scalanative/2.13.15/neg/t12494.check | 165 +++ .../2.13.15/neg/t6446-additional.check | 29 + .../scalanative/2.13.15/neg/t6446-list.check | 2 + .../2.13.15/neg/t6446-missing.check | 29 + .../2.13.15/neg/t6446-show-phases.check | 28 + .../2.13.15/neg/t7494-no-options.check | 30 + .../scalanative/2.13.15/run/classof.check | 22 + .../2.13.15/run/classtags_contextbound.check | 1 + .../2.13.15/run/classtags_multi.check | 5 + .../2.13.15/run/getClassTest-valueClass.check | 2 + ...interop_classtags_are_classmanifests.check | 3 + .../scalanative/2.13.15/run/t4753.check | 1 + .../scalanative/2.13.15/run/t5568.check | 9 + .../scalanative/2.13.15/run/t5923b.check | 3 + .../2.13.15/run/t6318_primitives.check | 54 + 21 files changed, 1769 insertions(+), 1 deletion(-) create mode 100644 scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests-require-threads.txt create mode 100644 scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests.txt create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/DenylistedTests.txt create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/macro-bundle-need-qualifier.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t11952b.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t12494.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-additional.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-list.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-missing.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-show-phases.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t7494-no-options.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classof.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_contextbound.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_multi.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/getClassTest-valueClass.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/interop_classtags_are_classmanifests.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t4753.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5568.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5923b.check create mode 100644 scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t6318_primitives.check diff --git a/project/ScalaVersions.scala b/project/ScalaVersions.scala index a47fcc2a30..4107c7e643 100644 --- a/project/ScalaVersions.scala +++ b/project/ScalaVersions.scala @@ -19,7 +19,7 @@ package build object ScalaVersions { // Versions of Scala used for publishing compiler plugins val crossScala212 = crossScalaVersions("2.12", 14 to 20) - val crossScala213 = crossScalaVersions("2.13", 8 to 14) + val crossScala213 = crossScalaVersions("2.13", 8 to 15) val crossScala3 = List( extraCrossScalaVersion("3.").toList, scala3RCVersions, diff --git a/scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests-require-threads.txt b/scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests-require-threads.txt new file mode 100644 index 0000000000..bf57d81f24 --- /dev/null +++ b/scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests-require-threads.txt @@ -0,0 +1,2 @@ +scala/collection/convert/MapWrapperTest.scala +scala/collection/concurrent/TrieMapTest.scala \ No newline at end of file diff --git a/scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests.txt b/scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests.txt new file mode 100644 index 0000000000..744f6f66a8 --- /dev/null +++ b/scala-partest-junit-tests/src/test/resources/2.13.15/DenylistedTests.txt @@ -0,0 +1,253 @@ +## Do not compile +scala/ExtractorTest.scala +scala/OptionTest.scala +scala/SerializationStabilityTest.scala +scala/StringTest.scala +scala/collection/FactoriesTest.scala +scala/collection/LazyZipOpsTest.scala +scala/collection/SeqTest.scala +scala/collection/immutable/HashMapTest.scala +scala/collection/immutable/HashSetTest.scala +scala/collection/immutable/IndexedSeqTest.scala +scala/collection/immutable/IntMapTest.scala +scala/collection/immutable/ListMapTest.scala +scala/collection/immutable/LongMapTest.scala +scala/collection/immutable/MapHashcodeTest.scala +scala/collection/immutable/SeqTest.scala +scala/collection/immutable/SmallMapTest.scala +scala/collection/immutable/SortedMapTest.scala +scala/collection/immutable/SortedSetTest.scala +scala/collection/immutable/TreeMapTest.scala +scala/collection/immutable/TreeSetTest.scala +scala/collection/mutable/ArrayBufferTest.scala +scala/collection/mutable/LongMapTest.scala +scala/lang/annotations/BytecodeTest.scala +scala/lang/annotations/RunTest.scala +scala/lang/traits/BytecodeTest.scala +scala/lang/traits/RunTest.scala +scala/lang/primitives/NaNTest.scala +scala/math/PartialOrderingTest.scala +scala/reflect/ClassOfTest.scala +scala/reflect/FieldAccessTest.scala +scala/reflect/QTest.scala +scala/reflect/io/ZipArchiveTest.scala +scala/reflect/internal/InferTest.scala +scala/reflect/internal/LongNamesTest.scala +scala/reflect/internal/MirrorsTest.scala +scala/reflect/internal/NamesTest.scala +scala/reflect/internal/PositionsTest.scala +scala/reflect/internal/PrintersTest.scala +scala/reflect/internal/ScopeTest.scala +scala/reflect/internal/TreeGenTest.scala +scala/reflect/internal/TypesTest.scala +scala/reflect/internal/util/AbstractFileClassLoaderTest.scala +scala/reflect/internal/util/FileUtilsTest.scala +scala/reflect/internal/util/SourceFileTest.scala +scala/reflect/internal/util/StringOpsTest.scala +scala/reflect/internal/SubstMapTest.scala +scala/reflect/internal/util/WeakHashSetTest.scala +scala/reflect/io/AbstractFileTest.scala +scala/reflect/runtime/ThreadSafetyTest.scala +scala/reflect/runtime/ReflectionUtilsShowTest.scala +scala/tools/nsc/Build.scala +scala/tools/nsc/DeterminismTest.scala +scala/tools/nsc/DeterminismTester.scala +scala/tools/nsc/FileUtils.scala +scala/tools/nsc/GlobalCustomizeClassloaderTest.scala +scala/tools/nsc/PhaseAssemblyTest.scala +scala/tools/nsc/PickleWriteTest.scala +scala/tools/nsc/PipelineMainTest.scala +scala/tools/nsc/ScriptRunnerTest.scala +scala/tools/nsc/MainRunnerTest.scala +scala/tools/nsc/async/AnnotationDrivenAsyncTest.scala +scala/tools/nsc/async/CustomFuture.scala +scala/tools/nsc/backend/jvm/ClassfileParserTest.scala +scala/tools/nsc/backend/jvm/BTypesTest.scala +scala/tools/nsc/backend/jvm/BytecodeTest.scala +scala/tools/nsc/backend/jvm/DefaultMethodTest.scala +scala/tools/nsc/backend/jvm/DirectCompileTest.scala +scala/tools/nsc/backend/jvm/GenericSignaturesTest.scala +scala/tools/nsc/backend/jvm/IndyLambdaTest.scala +scala/tools/nsc/backend/jvm/IndySammyTest.scala +scala/tools/nsc/backend/jvm/InnerClassAttributeTest.scala +scala/tools/nsc/backend/jvm/LineNumberTest.scala +scala/tools/nsc/backend/jvm/NestedClassesCollectorTest.scala +scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala +scala/tools/nsc/backend/jvm/PerRunInitTest.scala +scala/tools/nsc/backend/jvm/StringConcatTest.scala +scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala +scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala +scala/tools/nsc/backend/jvm/analysis/TypeFlowAnalyzerTest.scala +scala/tools/nsc/backend/jvm/opt/AnalyzerTest.scala +scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala +scala/tools/nsc/backend/jvm/opt/BoxUnboxTest.scala +scala/tools/nsc/backend/jvm/opt/BoxUnboxAndInlineTest.scala +scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala +scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala +scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala +scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala +scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala +scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala +scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala +scala/tools/nsc/backend/jvm/opt/InlinerSeparateCompilationTest.scala +scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +scala/tools/nsc/backend/jvm/opt/InlineSourceMatcherTest.scala +scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala +scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala +scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala +scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala +scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala +scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala +scala/tools/nsc/classpath/AggregateClassPathTest.scala +scala/tools/nsc/classpath/JrtClassPathTest.scala +scala/tools/nsc/classpath/MultiReleaseJarTest.scala +scala/tools/nsc/classpath/PathResolverBaseTest.scala +scala/tools/nsc/classpath/VirtualDirectoryClassPathTest.scala +scala/tools/nsc/classpath/ZipAndJarFileLookupFactoryTest.scala +scala/tools/nsc/doc/html/HtmlDocletTest.scala +scala/tools/nsc/doc/html/StringLiteralTest.scala +scala/tools/nsc/doc/html/ModelFactoryTest.scala +scala/tools/nsc/interpreter/CompletionTest.scala +scala/tools/nsc/interpreter/ScriptedTest.scala +scala/tools/nsc/interpreter/TabulatorTest.scala +scala/tools/nsc/parser/ParserTest.scala +scala/tools/nsc/reporters/ConsoleReporterTest.scala +scala/tools/nsc/reporters/PositionFilterTest.scala +scala/tools/nsc/reporters/WConfTest.scala +scala/tools/nsc/settings/ScalaVersionTest.scala +scala/tools/nsc/settings/SettingsTest.scala +scala/tools/nsc/settings/TargetTest.scala +scala/tools/nsc/symtab/CannotHaveAttrsTest.scala +scala/tools/nsc/symtab/FlagsTest.scala +scala/tools/nsc/symtab/FreshNameExtractorTest.scala +scala/tools/nsc/symtab/StdNamesTest.scala +scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +scala/tools/nsc/symtab/SymbolTableTest.scala +scala/tools/nsc/symtab/classfile/PicklerTest.scala +scala/tools/nsc/transform/ErasureTest.scala +scala/tools/nsc/transform/MixinTest.scala +scala/tools/nsc/transform/ReleaseFenceTest.scala +scala/tools/nsc/transform/SpecializationTest.scala +scala/tools/nsc/transform/ThicketTransformerTest.scala +scala/tools/nsc/transform/UncurryTest.scala +scala/tools/nsc/transform/delambdafy/DelambdafyTest.scala +scala/tools/nsc/transform/patmat/SolvingTest.scala +scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala +scala/tools/nsc/typechecker/ConstantFolderTest.scala +scala/tools/nsc/typechecker/ImplicitsTest.scala +scala/tools/nsc/typechecker/InferencerTest.scala +scala/tools/nsc/typechecker/NamerTest.scala +scala/tools/nsc/typechecker/OverridingPairsTest.scala +scala/tools/nsc/typechecker/ParamAliasTest.scala +scala/tools/nsc/typechecker/TypedTreeTest.scala +scala/tools/nsc/typechecker/TreeAttachmentTest.scala +scala/tools/nsc/util/StackTraceTest.scala +scala/tools/nsc/QuickfixTest.scala +scala/tools/nsc/reporters/AbstractCodeActionTest.scala +scala/tools/nsc/reporters/CodeActionTest.scala +scala/tools/nsc/reporters/CodeActionXsource3Test.scala +scala/tools/xsbt/BridgeTesting.scala +scala/tools/xsbt/BasicBridgeTest.scala +scala/tools/xsbt/CodeActionTest.scala +scala/tools/xsbt/DependencyTest.scala +scala/tools/xsbt/ExtractUsedNamesTest.scala +scala/tools/xsbt/InteractiveConsoleInterfaceTest.scala +scala/tools/xsbt/TestCallback.scala +scala/tools/xsbt/ClassNameTest.scala +scala/tools/xsbt/ExtractAPITest.scala +scala/tools/xsbt/SameAPI.scala +scala/util/ChainingOpsTest.scala +scala/sys/process/ProcessTest.scala +scala/collection/mutable/OpenHashMapTest.scala +scala/collection/immutable/ListTest.scala +scala/collection/immutable/LazyListTest.scala +scala/collection/MapTest.scala +scala/collection/Sizes.scala +scala/runtime/BooleanBoxingTest.scala +scala/runtime/ByteBoxingTest.scala +scala/runtime/CharBoxingTest.scala +scala/runtime/ShortBoxingTest.scala +scala/runtime/IntBoxingTest.scala +scala/runtime/LongBoxingTest.scala +scala/runtime/FloatBoxingTest.scala +scala/runtime/DoubleBoxingTest.scala + +## Do not link +scala/jdk/DurationConvertersTest.scala +scala/jdk/OptionConvertersTest.scala +scala/jdk/StreamConvertersTest.scala +scala/jdk/StreamConvertersTypingTest.scala + +# Uses stubs +scala/collection/mutable/AnyRefMapTest.scala +scala/collection/mutable/ListBufferTest.scala +scala/collection/immutable/ChampMapSmokeTest.scala +scala/collection/immutable/ChampSetSmokeTest.scala +scala/sys/process/ProcessBuilderTest.scala + +#j.l.reflect.Modifier / testkit.AssertUtil +scala/reflect/macros/AttachmentsTest.scala +scala/collection/IteratorTest.scala +scala/collection/immutable/StringLikeTest.scala +scala/concurrent/FutureTest.scala +scala/util/SpecVersionTest.scala +scala/tools/testkit/AssertUtilTest.scala +scala/tools/testkit/ReflectUtilTest.scala + +#j.u.stream.* +scala/jdk/StepperConversionTest.scala +scala/jdk/StepperTest.scala + +#j.i.Object{Input,Output}Stream +scala/PartialFunctionSerializationTest.scala +scala/MatchErrorSerializationTest.scala +scala/collection/convert/WrapperSerializationTest.scala +scala/collection/mutable/PriorityQueueTest.scala +scala/collection/mutable/SerializationTest.scala +scala/collection/immutable/SerializationTest.scala +scala/collection/immutable/LazyListLazinessTest.scala +scala/concurrent/duration/SerializationTest.scala +scala/jdk/FunctionConvertersTest.scala + +#j.io.Piped{Input,Output}Stream / j.u.c.LinkedBlockingQueue +scala/sys/process/PipedProcessTest.scala + +#j.u.c.ConcurrentSkipListMap +scala/collection/convert/JConcurrentMapWrapperTest.scala + +#j.t.LocalDate +scala/math/OrderingTest.scala + +#j.l.Class.getDeclaredField +scala/collection/immutable/VectorTest.scala + +#j.l.Thread contextClassloader +scala/io/SourceTest.scala +scala/lang/stringinterpol/StringContextTest.scala + +# Needs newer JUnit version +scala/util/matching/RegexTest.scala +scala/collection/immutable/RangeTest.scala +scala/collection/mutable/BitSetTest.scala + +## Tests fail +scala/ArrayTest.scala +scala/collection/ArrayOpsTest.scala +scala/collection/StringParsersTest.scala +scala/collection/StringOpsTest.scala +scala/collection/convert/JSetWrapperTest.scala +scala/collection/immutable/ArraySeqTest.scala +scala/collection/immutable/LazyListGCTest.scala +scala/collection/immutable/StreamTest.scala +scala/collection/immutable/VectorTest.scala +scala/math/EquivTest.scala +scala/sys/process/ParserTest.scala +scala/util/TryTest.scala +# https://github.com/scala-native/scala-native/issues/2897 +scala/math/BigIntTest.scala +### deadlocks maybe needs j.u.c.ConcurrentLinkedQueue +scala/concurrent/impl/DefaultPromiseTest.scala + +# Object monitors locking issue #3594 +scala/collection/convert/MapWrapperTest.scala + diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/DenylistedTests.txt b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/DenylistedTests.txt new file mode 100644 index 0000000000..c2502d4f24 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/DenylistedTests.txt @@ -0,0 +1,1110 @@ +# Ported from Scala.js, might not be exhaustive enough (some Denylisted tests may actually work in SN) + +# +# POS +# + +# Spuriously fails too often, and causes other subsequent tests to fail too +# Note that this test, by design, stress-tests type checking +pos/t6367.scala + +# +# NEG +# + +# Does not create tasty.jar +neg/t12134 + +# Not deterministic order of warnings +neg/case-collision.scala + +# +# RUN +# + +# Uses .java files +run/t12195 +run/t12380 +run/t9200 +run/t8348 +run/noInlineUnknownIndy +run/specialize-functional-interface + +## Uses testkit java files +run/small-seq-apply.scala + +# Using parts of the javalib we don't plan to support + +run/t5018.scala +run/t3667.scala +run/t3038d.scala +run/shutdownhooks.scala +run/t5590.scala +run/t3895b.scala +run/t5974.scala +run/t5262.scala +run/serialize-stream.scala +run/lambda-serialization-gc.scala +run/t9390.scala +run/t9390b.scala +run/t9390c.scala +run/t2849.scala +run/t10488.scala +run/various-flat-classpath-types.scala + +# Uses j.l.Class stubs +run/t9437a.scala +run/t12002.scala +run/BoxUnboxTest.scala +run/module-serialization-proxy-class-unload.scala +run/t12481.scala + +# Uses java.math.BigDecimal / BigInteger : but failures not due to them +run/is-valid-num.scala + +# Documented semantic difference on String.split(x: Array[Char]) +run/t0325.scala + +# Uses java.security +run/t2318.scala + +# Tries to catch java.lang.StackOverflowError +run/t6154.scala + +# Using java.util.Locale +run/f-interpolator-unit.scala + +# Using java.util.concurrent.ConcurrentSkipListMap() + java.util.Timer +run/t12572.scala + +# Using java.util.concurrent.CompletionStage + java.util.concurrent.CompletableFuture +run/t12918.scala + +# Taking too much time >60sec +run/t2417.scala +run/t3989.scala + +# Using IO + +run/t6488.scala +run/t6988.scala + +# Object{Output|Input}Streams +run/t12774.scala +run/defaults-serizaliable-no-forwarders.scala +run/defaults-serizaliable-with-forwarders.scala +run/t6935.scala +run/t8188.scala +run/t9375.scala +run/t9365.scala +run/inlineAddDeserializeLambda.scala +run/sammy_seriazable.scala +run/lambda-serialization-security.scala +run/t10232.scala +run/t10233.scala +run/t10244.scala +run/t10522.scala +run/t11255 +run/transient-object.scala + +# Using System.getProperties + +run/t4426.scala + +# Using Await + +run/t7336.scala +run/t7775.scala + +# Using detailed stack trace +run/t6308.scala +run/t10277.scala +run/t10277b.scala + +# Using reflection +##java.lang.SuppressWarnings + java.lang.Deprecated +run/t9400.scala + +run/t12799 +run/reflection-package-name-conflict +run/sip23-toolbox-eval.scala +run/t6063 +run/t9644.scala +run/t12038a +run/t12038b + +run/mixin-bridge-methods.scala +run/t5125.scala +run/outertest.scala +run/t6223.scala +run/t5652b +run/elidable-opt.scala +run/nullable-lazyvals.scala +run/t4794.scala +run/t5652 +run/t5652c +run/getClassTest-old.scala +run/t8960.scala +run/t7965.scala +run/t8087.scala +run/t8931.scala +run/t8445.scala +run/lambda-serialization.scala + +run/reflection-repl-classes.scala +run/t5256e.scala +run/typetags_core.scala +run/reflection-constructormirror-toplevel-badpath.scala +run/t5276_1b.scala +run/reflection-sorted-decls.scala +run/toolbox_typecheck_implicitsdisabled.scala +run/t5418b.scala +run/toolbox_typecheck_macrosdisabled2.scala +run/abstypetags_serialize.scala +run/all-overridden.scala +run/showraw_tree_kinds.scala +run/showraw_tree_types_ids.scala +run/showraw_tree_types_typed.scala +run/showraw_tree_ids.scala +run/showraw_tree_ultimate.scala +run/t5266_2.scala +run/t5274_1.scala +run/t5224.scala +run/reflection-sanitychecks.scala +run/t6086-vanilla.scala +run/t5277_2.scala +run/reflection-methodsymbol-params.scala +run/reflection-valueclasses-standard.scala +run/t5274_2.scala +run/t5423.scala +run/reflection-modulemirror-toplevel-good.scala +run/t5419.scala +run/t5271_3.scala +run/reflection-enclosed-nested-basic.scala +run/reflection-enclosed-nested-nested-basic.scala +run/fail-non-value-types.scala +run/exprs_serialize.scala +run/t5258a.scala +run/typetags_without_scala_reflect_manifest_lookup.scala +run/t4110-new.scala +run/t5273_2b_newpatmat.scala +run/t6277.scala +run/t5335.scala +run/toolbox_typecheck_macrosdisabled.scala +run/reflection-modulemirror-inner-good.scala +run/t5229_2.scala +run/typetags_multi.scala +run/typetags_without_scala_reflect_typetag_manifest_interop.scala +run/reflection-constructormirror-toplevel-good.scala +run/reflection-magicsymbols-invoke.scala +run/t6392b.scala +run/t5229_1.scala +run/reflection-magicsymbols-vanilla.scala +run/t5225_2.scala +run/runtimeEval1.scala +run/reflection-enclosed-nested-inner-basic.scala +run/reflection-fieldmirror-ctorparam.scala +run/t6181.scala +run/reflection-magicsymbols-repl.scala +run/t5272_2_newpatmat.scala +run/t5270.scala +run/t5418a.scala +run/t5276_2b.scala +run/t5256f.scala +run/reflection-enclosed-basic.scala +run/reflection-constructormirror-inner-badpath.scala +run/interop_typetags_are_manifests.scala +run/newTags.scala +run/t5273_1_newpatmat.scala +run/reflection-constructormirror-nested-good.scala +run/t2236-new.scala +run/existentials3-new.scala +run/t6323b.scala +run/t5943a1.scala +run/reflection-fieldmirror-getsetval.scala +run/t5272_1_oldpatmat.scala +run/t5256h.scala +run/t1195-new.scala +run/t5840.scala +run/reflection-methodsymbol-returntype.scala +run/reflection-fieldmirror-accessorsareokay.scala +run/reflection-sorted-members.scala +run/reflection-allmirrors-tostring.scala +run/valueclasses-typetag-existential.scala +run/toolbox_console_reporter.scala +run/reflection-enclosed-inner-inner-basic.scala +run/t5256b.scala +run/bytecodecs.scala +run/elidable.scala +run/freetypes_false_alarm1.scala +run/freetypes_false_alarm2.scala +run/getClassTest-new.scala +run/idempotency-extractors.scala +run/idempotency-case-classes.scala +run/idempotency-this.scala +run/idempotency-labels.scala +run/idempotency-lazy-vals.scala +run/interop_manifests_are_abstypetags.scala +run/interop_manifests_are_typetags.scala +run/abstypetags_core.scala +run/macro-reify-abstypetag-notypeparams +run/macro-reify-abstypetag-typeparams-tags +run/macro-reify-abstypetag-typeparams-notags +run/macro-reify-abstypetag-usetypetag +run/macro-reify-freevars +run/macro-reify-splice-outside-reify +run/macro-reify-tagless-a +run/macro-reify-type +run/macro-reify-typetag-typeparams-tags +run/macro-reify-typetag-notypeparams +run/macro-undetparams-implicitval +run/manifests-new.scala +run/manifests-old.scala +run/no-pickle-skolems +run/position-val-def.scala +run/reflect-priv-ctor.scala +run/primitive-sigs-2-new.scala +run/primitive-sigs-2-old.scala +run/reflection-enclosed-inner-basic.scala +run/reflection-enclosed-inner-nested-basic.scala +run/reflection-constructormirror-inner-good.scala +run/reflection-constructormirror-nested-badpath.scala +run/reflection-fancy-java-classes +run/reflection-fieldsymbol-navigation.scala +run/reflection-fieldmirror-nmelocalsuffixstring.scala +run/reflection-fieldmirror-getsetvar.scala +run/reflection-fieldmirror-privatethis.scala +run/reflection-implicit.scala +run/reflection-mem-glbs.scala +run/reflection-mem-tags.scala +run/reflection-java-annotations +run/reflection-java-crtp +run/reflection-methodsymbol-typeparams.scala +run/reflection-modulemirror-nested-badpath.scala +run/reflection-modulemirror-inner-badpath.scala +run/reflection-modulemirror-nested-good.scala +run/reflection-modulemirror-toplevel-badpath.scala +run/reflection-sync-subtypes.scala +run/reflinit.scala +run/reflection-valueclasses-derived.scala +run/reflection-valueclasses-magic.scala +run/resetattrs-this.scala +run/runtimeEval2.scala +run/showraw_aliases.scala +run/showraw_mods.scala +run/shortClass.scala +run/showraw_nosymbol.scala +run/showraw_tree.scala +run/showraw_tree_types_untyped.scala +run/t1167.scala +run/t2577.scala +run/t2873.scala +run/t2886.scala +run/t3346j.scala +run/t3507-new.scala +run/t3569.scala +run/t5125b.scala +run/t5225_1.scala +run/t3425b +run/t5256a.scala +run/t5230.scala +run/t5256c.scala +run/t5256g.scala +run/t5266_1.scala +run/t5269.scala +run/t5271_1.scala +run/t5271_2.scala +run/t5271_4.scala +run/t5272_1_newpatmat.scala +run/t5272_2_oldpatmat.scala +run/t5273_1_oldpatmat.scala +run/t5273_2a_newpatmat.scala +run/t5273_2a_oldpatmat.scala +run/t5275.scala +run/t5276_1a.scala +run/t5276_2a.scala +run/t5277_1.scala +run/t5279.scala +run/t5334_1.scala +run/t5334_2.scala +run/t5415.scala +run/t5418.scala +run/t5704.scala +run/t5710-1.scala +run/t5710-2.scala +run/t5770.scala +run/t5894.scala +run/t5816.scala +run/t5824.scala +run/t5912.scala +run/t5942.scala +run/t5943a2.scala +run/t6023.scala +run/t6113.scala +run/t6175.scala +run/t6178.scala +run/t6199-mirror.scala +run/t6199-toolbox.scala +run/t6240-universe-code-gen.scala +run/t6221 +run/t6260b.scala +run/t6259.scala +run/t6287.scala +run/t6344.scala +run/t6392a.scala +run/t6591_1.scala +run/t6591_2.scala +run/t6591_3.scala +run/t6591_5.scala +run/t6591_6.scala +run/t6591_7.scala +run/t6608.scala +run/t6677.scala +run/t6687.scala +run/t6715.scala +run/t6719.scala +run/t6793.scala +run/t6860.scala +run/t6793b.scala +run/t6793c.scala +run/t7045.scala +run/t7046.scala +run/t7008-scala-defined +run/t7120b.scala +run/t7151.scala +run/t7214.scala +run/t7235.scala +run/t7331a.scala +run/t7331b.scala +run/t7331c.scala +run/t7558.scala +run/t7556 +run/t7779.scala +run/t7868b.scala +run/toolbox_current_run_compiles.scala +run/toolbox_default_reporter_is_silent.scala +run/toolbox_parse_package.scala +run/toolbox_silent_reporter.scala +run/toolbox_typecheck_inferimplicitvalue.scala +run/typetags_serialize.scala +run/valueclasses-typetag-basic.scala +run/WeakHashSetTest.scala +run/valueclasses-typetag-generic.scala +run/t4023.scala +run/t4024.scala +run/t6380.scala +run/t5273_2b_oldpatmat.scala +run/t8104 +run/t8047.scala +run/t6992 +run/var-arity-class-symbol.scala +run/typetags_symbolof_x.scala +run/typecheck +run/t8190.scala +run/t8192 +run/t8177f.scala +run/t7932.scala +run/t7700.scala +run/t7570c.scala +run/t7570b.scala +run/t7533.scala +run/t7570a.scala +run/t7044 +run/t7328.scala +run/t6733.scala +run/t6554.scala +run/t6732.scala +run/t6379 +run/t6411b.scala +run/t6411a.scala +run/t6260c.scala +run/t6260-delambdafy.scala +run/showdecl +run/reflection-sync-potpourri.scala +run/reflection-tags.scala +run/reflection-companiontype.scala +run/reflection-scala-annotations.scala +run/reflection-idtc.scala +run/macro-reify-nested-b2 +run/mixin-signatures.scala +run/reflection-companion.scala +run/macro-reify-nested-b1 +run/macro-reify-nested-a2 +run/macro-reify-nested-a1 +run/macro-reify-chained2 +run/macro-reify-chained1 +run/inferred-type-constructors.scala +run/mirror_symbolof_x.scala +run/t8196.scala +run/t8549b.scala +run/t8574.scala +run/t8637.scala +run/t6622.scala +run/toolbox_expand_macro.scala +run/toolbox-varargs +run/t9252.scala +run/t9182.scala +run/t9102.scala +run/t720.scala +run/t9408.scala +run/t10527.scala +run/trait-default-specialize.scala +run/lazy-locals-2.scala +run/t5294.scala +run/trait_fields_final.scala +run/trait_fields_bytecode.scala +run/trait_fields_volatile.scala +run/junitForwarders +run/reflect-java-param-names + +run/reify_ann2b.scala +run/reify_classfileann_a +run/reify_classfileann_b +run/reify_newimpl_29.scala +run/reify_magicsymbols.scala +run/reify_inheritance.scala +run/reify_newimpl_12.scala +run/reify_typerefs_2b.scala +run/reify_csv.scala +run/reify_inner2.scala +run/reify_maps_oldpatmat.scala +run/reify_newimpl_43.scala +run/reify_nested_inner_refers_to_local.scala +run/reify_closure7.scala +run/reify_closure8b.scala +run/reify_typerefs_3b.scala +run/reify_newimpl_44.scala +run/reify_newimpl_06.scala +run/reify_newimpl_05.scala +run/reify_newimpl_20.scala +run/reify_newimpl_23.scala +run/reify_metalevel_breach_-1_refers_to_1.scala +run/reify_newimpl_41.scala +run/reify-repl-fail-gracefully.scala +run/reify_fors_oldpatmat.scala +run/reify_inner3.scala +run/reify_closure8a.scala +run/reify_closures10.scala +run/reify_ann2a.scala +run/reify_newimpl_51.scala +run/reify_newimpl_47.scala +run/reify_extendbuiltins.scala +run/reify_newimpl_30.scala +run/reify_newimpl_38.scala +run/reify_closure2a.scala +run/reify_newimpl_45.scala +run/reify_closure1.scala +run/reify_generic2.scala +run/reify_printf.scala +run/reify_closure6.scala +run/reify_newimpl_37.scala +run/reify_newimpl_35.scala +run/reify_typerefs_3a.scala +run/reify_newimpl_25.scala +run/reify_ann4.scala +run/reify_typerefs_1b.scala +run/reify_newimpl_22.scala +run/reify_this.scala +run/reify_typerefs_2a.scala +run/reify_newimpl_03.scala +run/reify_newimpl_48.scala +run/reify_varargs.scala +run/reify_newimpl_42.scala +run/reify_newimpl_15.scala +run/reify_nested_inner_refers_to_global.scala +run/reify_newimpl_02.scala +run/reify_newimpl_01.scala +run/reify_fors_newpatmat.scala +run/reify_nested_outer_refers_to_local.scala +run/reify_newimpl_13.scala +run/reify_closure5a.scala +run/reify_inner4.scala +run/reify_sort.scala +run/reify_ann1a.scala +run/reify_closure4a.scala +run/reify_newimpl_33.scala +run/reify_sort1.scala +run/reify_properties.scala +run/reify_generic.scala +run/reify_newimpl_27.scala +run/reify-aliases.scala +run/reify_ann3.scala +run/reify-staticXXX.scala +run/reify_ann1b.scala +run/reify_ann5.scala +run/reify_anonymous.scala +run/reify-each-node-type.scala +run/reify_copypaste2.scala +run/reify_closure3a.scala +run/reify_copypaste1.scala +run/reify_complex.scala +run/reify_for1.scala +run/reify_getter.scala +run/reify_implicits-new.scala +run/reify_inner1.scala +run/reify_implicits-old.scala +run/reify_lazyunit.scala +run/reify_lazyevaluation.scala +run/reify_maps_newpatmat.scala +run/reify_metalevel_breach_+0_refers_to_1.scala +run/reify_metalevel_breach_-1_refers_to_0_a.scala +run/reify_metalevel_breach_-1_refers_to_0_b.scala +run/reify_nested_outer_refers_to_global.scala +run/reify_newimpl_04.scala +run/reify_newimpl_14.scala +run/reify_newimpl_11.scala +run/reify_newimpl_18.scala +run/reify_newimpl_19.scala +run/reify_newimpl_31.scala +run/reify_newimpl_21.scala +run/reify_newimpl_36.scala +run/reify_newimpl_39.scala +run/reify_newimpl_40.scala +run/reify_newimpl_49.scala +run/reify_newimpl_50.scala +run/reify_newimpl_52.scala +run/reify_renamed_term_basic.scala +run/reify_renamed_term_local_to_reifee.scala +run/reify_renamed_term_overloaded_method.scala +run/reify_renamed_type_basic.scala +run/reify_renamed_type_local_to_reifee.scala +run/reify_renamed_type_spliceable.scala +run/reify_typerefs_1a.scala +run/reify_timeofday.scala +run/reify_renamed_term_t5841.scala + +run/t7521b.scala +run/t8575b.scala +run/t8575c.scala +run/t8944c.scala +run/t9535.scala +run/t9814.scala +run/t10009.scala +run/t10075.scala +run/t10075b + +run/t8756.scala +run/inferred-type-constructors-hou.scala +run/trait-static-forwarder +run/SD-235.scala +run/t10026.scala +run/checkinit.scala +run/reflection-clinit +run/reflection-clinit-nested +run/t10487.scala + +run/typetags_caching.scala +run/type-tag-leak.scala +run/t10856.scala +run/module-static.scala +run/dotty-i11332.scala +run/dotty-i11332b.scala +run/dotty-t12348.scala +run/t12348.scala + +# Uses reflection indirectly through +# scala.runtime.ScalaRunTime.replStringOf +run/t6634.scala + +# Using reflection to invoke macros. These tests actually don't require +# or test reflection, but use it to separate compilation units nicely. +# It's a pity we cannot use them + +run/macro-abort-fresh +run/macro-expand-varargs-explicit-over-nonvarargs-bad +run/macro-invalidret-doesnt-conform-to-def-rettype +run/macro-invalidret-nontypeable +run/macro-invalidusage-badret +run/macro-invalidusage-partialapplication +run/macro-invalidusage-partialapplication-with-tparams +run/macro-reflective-ma-normal-mdmi +run/macro-reflective-mamd-normal-mi + +# Using macros, but indirectly creating calls to reflection +run/macro-reify-unreify + +# Using Enumeration in a way we cannot fix + +run/enums.scala +run/t3719.scala +run/t8611b.scala + +# Expecting exceptions that are linking errors in Scala.js (e.g. NoSuchMethodException) +run/t10334.scala + +# Playing with classfile format + +run/classfile-format-51.scala +run/classfile-format-52.scala + + +# Using Swing + +run/t3613.scala + +# Using the REPL + +run/repl-type.scala +run/repl-replay.scala +run/repl-errors.scala +run/repl-any-error.scala +run/repl-paste-error.scala +run/repl-previous-result.scala +run/repl-trace-elided-more.scala +run/t4285.scala +run/constant-type.scala +run/repl-bare-expr.scala +run/repl-parens.scala +run/repl-assign.scala +run/t5583.scala +run/treePrint.scala +run/constrained-types.scala +run/repl-power.scala +run/t4710.scala +run/repl-paste.scala +run/repl-reset.scala +run/repl-paste-3.scala +run/t6329_repl.scala +run/t6273.scala +run/repl-paste-2.scala +run/t5655.scala +run/t5072.scala +run/repl-colon-type.scala +run/repl-trim-stack-trace.scala +run/t4594-repl-settings.scala +run/repl-save.scala +run/repl-paste-raw.scala +run/repl-paste-4.scala +run/t7801.scala +run/repl-backticks.scala +run/t6633.scala +run/repl-inline.scala +run/repl-class-based-term-macros.scala +run/repl-always-use-instance.scala +run/repl-class-based-implicit-import.scala +run/repl-class-based-value-class.scala +run/repl-deadlock.scala +run/repl-class-based-outer-pointers.scala +run/repl-class-based-escaping-reads.scala + +# Using the Repl (scala.tools.partest.ReplTest) +run/t11991.scala +run/t11915.scala +run/t11899.scala +run/t11897.scala +run/t11838.scala +run/t11402.scala +run/t11064.scala +run/t10768.scala +run/class-symbol-contravariant.scala +run/macro-bundle-repl.scala +run/macro-repl-basic.scala +run/macro-repl-dontexpand.scala +run/macro-system-properties.scala +run/reflection-equality.scala +run/reflection-repl-elementary.scala +run/reify_newimpl_26.scala +run/repl-out-dir.scala +run/repl-term-macros.scala +run/repl-transcript.scala +run/repl-type-verbose.scala +run/t3376.scala +run/t4025.scala +run/t4172.scala +run/t4216.scala +run/t4542.scala +run/t4671.scala +run/t5256d.scala +run/t5535.scala +run/t5537.scala +run/t5789.scala +run/t6086-repl.scala +run/t6146b.scala +run/t6187.scala +run/t6320.scala +run/t6381.scala +run/t6434.scala +run/t6439.scala +run/t6507.scala +run/t6549.scala +run/t6937.scala +run/t7185.scala +run/t7319.scala +run/t7482a.scala +run/t7634.scala +run/t7747-repl.scala +run/tpeCache-tyconCache.scala +run/repl-empty-package +run/repl-javap-def.scala +run/repl-javap-mem.scala +run/repl-javap-outdir +run/repl-javap.scala +run/t6329_repl_bug.scala +run/t4950.scala +run/xMigration.scala +run/t6541-option.scala +run/repl-serialization.scala +run/t9174.scala +run/repl-paste-5.scala +run/repl-no-uescape.scala +run/repl-no-imports-no-predef-classbased.scala +run/repl-implicits-nopredef.scala +run/repl-classbased.scala +run/repl-no-imports-no-predef-power.scala +run/repl-paste-b.scala +run/repl-paste-6.scala +run/repl-implicits.scala +run/repl-no-imports-no-predef.scala +run/repl-paste-raw-b.scala +run/repl-paste-raw-c.scala +run/t9749-repl-dot.scala +run/trait_fields_repl.scala +run/t7139 +run/t9689 +run/trailing-commas.scala +run/t4700.scala +run/t9880-9881.scala +run/repl-kind.scala +run/t10284.scala +run/t9016.scala +run/repl-completions.scala +run/t10956.scala +run/t11564.scala +run/invalid-lubs.scala +run/constAnnArgs.scala +run/interpolation-repl.scala +run/t12292.scala +run/t12276.scala +run/t10943.scala +run/StringConcat.scala +run/repl-release.scala +run/t10016.scala +run/t10655.scala +run/t12390.scala + +# Using Scala Script (partest.ScriptTest) + +run/t7711-script-args.scala +run/t4625.scala +run/t4625c.scala +run/t4625b.scala + +# Using the compiler API +run/sd409.scala +run/t8465.scala +run/t9644b +run/nowarn.scala +run/t9944.scala +run/t3368.scala +run/t3368-b.scala +run/t2512.scala +run/analyzerPlugins.scala +run/compiler-asSeenFrom.scala +run/t5603.scala +run/t6440.scala +run/t5545.scala +run/existentials-in-compiler.scala +run/global-showdef.scala +run/stream_length.scala +run/annotatedRetyping.scala +run/imain.scala +run/existential-rangepos.scala +run/delambdafy_uncurry_byname_inline.scala +run/delambdafy_uncurry_byname_method.scala +run/delambdafy_uncurry_inline.scala +run/delambdafy_t6555.scala +run/delambdafy_uncurry_method.scala +run/delambdafy_t6028.scala +run/memberpos.scala +run/programmatic-main.scala +run/reflection-names.scala +run/settings-parse.scala +run/sm-interpolator.scala +run/t1501.scala +run/t1500.scala +run/t1618.scala +run/t2464 +run/t4072.scala +run/t5064.scala +run/t5385.scala +run/t5699.scala +run/t5717.scala +run/t5940.scala +run/t6028.scala +run/t6194.scala +run/t6669.scala +run/t6745-2.scala +run/t7096.scala +run/t7271.scala +run/t7337.scala +run/t7569.scala +run/t7852.scala +run/t7817-tree-gen.scala +run/extend-global.scala +run/t12062.scala + + +# partest.DirectTest +run/t7324.scala +run/repl-suspended-warnings.scala +run/t1406.scala +run/t12405.scala +run/t12490.scala +run/t12597.scala +run/t12705.scala +run/t12757.scala +run/t12757b.scala +run/t12757c.scala +run/t12019 +run/t11815.scala +run/t11746.scala +run/t11385.scala +run/t10819.scala +run/t10751.scala +run/t10641.scala +run/t10344.scala +run/t10203.scala +run/string-switch-pos.scala +run/patmat-seq.scala +run/maxerrs.scala +run/t6288.scala +run/t6331.scala +run/t6440b.scala +run/t6555.scala +run/t7876.scala +run/typetags_without_scala_reflect_typetag_lookup.scala +run/dynamic-updateDynamic.scala +run/dynamic-selectDynamic.scala +run/dynamic-applyDynamic.scala +run/dynamic-applyDynamicNamed.scala +run/t4841-isolate-plugins +run/large_code.scala +run/macroPlugins-namerHooks.scala +run/t4841-no-plugin.scala +run/t8029.scala +run/t8046 +run/t5905-features.scala +run/t5905b-features.scala +run/large_class.scala +run/t8708_b +run/icode-reader-dead-code.scala +run/t5938.scala +run/t8502.scala +run/t6502.scala +run/t8907.scala +run/t9097.scala +run/macroPlugins-enterStats.scala +run/sbt-icode-interface.scala +run/t8502b.scala +run/t5463.scala +run/t8433.scala +run/sd275.scala +run/sd275-java +run/t10471.scala +run/t6130.scala +run/t9437b.scala +run/t10552 +run/sd187.scala +run/patmat-origtp-switch.scala +run/indyLambdaKinds +run/t11802-pluginsdir +run/literals-parsing.scala +run/patmat-no-inline-isEmpty.scala +run/patmat-no-inline-unapply.scala +run/splain-tree.scala +run/splain-truncrefined.scala +run/splain.scala +run/eta-dependent.scala +run/infix-rangepos.scala +run/infixPostfixAttachments.scala +run/print-args.scala + + +# Using partest.StoreReporterDirectTest +run/t10171 +run/argfile.scala +run/badout.scala +run/debug-type-error.scala +run/package-object-stale-decl.scala +run/package-object-toolbox.scala +run/package-object-with-inner-class-in-ancestor.scala +run/package-object-with-inner-class-in-ancestor-simpler.scala +run/package-object-with-inner-class-in-ancestor-simpler-still.scala +run/smallseq.scala + + +# partest.StubErrorMessageTest +run/StubErrorBInheritsFromA.scala +run/StubErrorComplexInnerClass.scala +run/StubErrorHK.scala +run/StubErrorReturnTypeFunction.scala +run/StubErrorReturnTypeFunction2.scala +run/StubErrorReturnTypePolyFunction.scala +run/StubErrorSubclasses.scala +run/StubErrorTypeclass.scala +run/StubErrorTypeDef.scala + +# partest.ASMConverters +run/t9403 + +# partest.BytecodeTest +run/staticQualifier +run/nonfatal.scala +run/t7106 +run/t7974 +run/t8601-closure-elim.scala +run/t4788 +run/t4788-separate-compilation + +# partest.SessionTest +run/t8843-repl-xlat.scala +run/t9206.scala +run/t9170.scala +run/t8918-unary-ids.scala +run/t1931.scala +run/t8935-class.scala +run/t8935-object.scala + +# partest.JavapTest +run/t8608-no-format.scala + +# Using .java source files +run/t9714 +run/t12523 +run/t4317 +run/t4238 +run/t2296c +run/t4119 +run/t4283 +run/t4891 +run/t6168 +run/t6168b +run/t6240a +run/t6240b +run/t6548 +run/t6989 +run/t7008 +run/t7246 +run/t7246b +run/t7359 +run/t7439 +run/t7455 +run/t7510 +run/t7582-private-within +run/t7582 +run/t7582b +run/t3897 +run/t7374 +run/t3452e +run/t3452g +run/t3452d +run/t3452b +run/t3452a +run/t1430 +run/t4729 +run/t8442 +run/t8601e +run/t9298 +run/t9298b +run/t9359 +run/t7741a +run/t7741b +run/bcodeInlinerMixed +run/t9268 +run/t9489 +run/t9915 +run/t10059 +run/t1459 +run/t1459generic +run/t3236 +run/t9013 +run/t10231 +run/t10067 +run/t10249 +run/sd143 +run/t4283b +run/t7936 +run/t7936b +run/t9937 +run/t10368 +run/t10334b +run/sd304 +run/t10450 +run/t10042 +run/t10699 +run/t9529 +run/t9529-types +run/t10490 +run/t10490-2 +run/t10889 +run/t3899 +run/t11373 +run/t8928 + + +# Using partest.Properties (nest.Runner) +run/t4294.scala +run/tailcalls.scala + +# Using scala-script +run/t7791-script-linenums.scala + +# Using scalap +run/scalapInvokedynamic.scala + +# Not a valid main method +run/t7448.scala + +# Using Manifests (which use Class.getInterfaces) +run/valueclasses-manifest-existential.scala +run/existentials3-old.scala +run/t2236-old.scala +run/interop_manifests_are_classtags.scala +run/valueclasses-manifest-generic.scala +run/valueclasses-manifest-basic.scala +run/t1195-old.scala +run/t3758-old.scala +run/t4110-old.scala +run/t6246.scala + + +# Using ScalaRunTime.stringOf +run/value-class-extractor-seq.scala + +# Custom invoke dynamic node + uses .java sources +run/indy-via-macro +run/indy-via-macro-with-dynamic-args +run/indy-via-macro-class-constant-bsa +run/indy-via-macro-method-type-bsa +run/indy-via-macro-reflector + +# TODO: +### Bugs +## Compiler +run/anyval-box-types.scala +run/structural.scala +run/t8601d.scala +run/t10069b.scala +run/t11665.scala + +## JVM compliance +run/t5680.scala +run/t2755.scala + + +## Fails +run/classtags-cached.scala +run/sip23-cast-1.scala + +# Infinite loop +run/stream-gc.scala + +## Check not passing +run/t266.scala +run/t4300.scala +run/t8334.scala +run/t8803.scala +run/t9697.scala +run/t10290.scala + + diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/macro-bundle-need-qualifier.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/macro-bundle-need-qualifier.check new file mode 100644 index 0000000000..017490e9b6 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/macro-bundle-need-qualifier.check @@ -0,0 +1,4 @@ +macro-bundle-need-qualifier.scala:10: error: package java.lang.impl is not a value + def foo: Any = macro impl + ^ +1 error diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t11952b.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t11952b.check new file mode 100644 index 0000000000..32ae086039 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t11952b.check @@ -0,0 +1,16 @@ +[running phase parser on t11952b.scala] +[running phase namer on t11952b.scala] +[running phase packageobjects on t11952b.scala] +[running phase typer on t11952b.scala] +[running phase scalanative-prepareInterop on t11952b.scala] +[running phase superaccessors on t11952b.scala] +[running phase extmethods on t11952b.scala] +[running phase pickler on t11952b.scala] +[running phase refchecks on t11952b.scala] +t11952b.scala:9: error: cannot override final member: + final def f: String (defined in class C); + found : scala.this.Int + required: String + override def f: Int = 42 + ^ +1 error diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t12494.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t12494.check new file mode 100644 index 0000000000..5fe7cddcba --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t12494.check @@ -0,0 +1,165 @@ +[running phase parser on t12494.scala] +[running phase namer on t12494.scala] +[running phase packageobjects on t12494.scala] +[running phase typer on t12494.scala] +[running phase scalanative-prepareInterop on t12494.scala] +[running phase superaccessors on t12494.scala] +[log superaccessors] [context] ++ t12494.scala / Import(value ) +[log superaccessors] [context] ++ t12494.scala / Import(value ) +[log superaccessors] [context] ++ t12494.scala / Import(value ) +[log superaccessors] [context] ++ t12494.scala / EmptyTree +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / Ident() +[log superaccessors] [context] ++ t12494.scala / Ident() +[log superaccessors] [context] ++ t12494.scala / term X +[log superaccessors] [context] ++ t12494.scala / term X +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term m +[log superaccessors] [context] ++ t12494.scala / term m +[log superaccessors] [context] ++ t12494.scala / type C +[log superaccessors] [context] ++ t12494.scala / type C +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term C +[log superaccessors] [context] ++ t12494.scala / term C +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / type C2 +[log superaccessors] [context] ++ t12494.scala / type C2 +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term test +[log superaccessors] [context] ++ t12494.scala / term test +[log superaccessors] [context] ++ t12494.scala / term Y +[log superaccessors] [context] ++ t12494.scala / term Y +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term n +[log superaccessors] [context] ++ t12494.scala / term n +[log superaccessors] [context] ++ t12494.scala / type C +[log superaccessors] [context] ++ t12494.scala / type C +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / type X +[log superaccessors] [context] ++ t12494.scala / type X +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term x +[log superaccessors] [context] ++ t12494.scala / term x +[log superaccessors] [context] ++ t12494.scala / term X +[log superaccessors] [context] ++ t12494.scala / term X +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term y +[log superaccessors] [context] ++ t12494.scala / term y +[log superaccessors] [context] ++ t12494.scala / term y +[log superaccessors] [context] ++ t12494.scala / term y +[log superaccessors] [context] ++ t12494.scala / term C +[log superaccessors] [context] ++ t12494.scala / term C +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / type C2 +[log superaccessors] [context] ++ t12494.scala / type C2 +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term test +[log superaccessors] [context] ++ t12494.scala / term test +[log superaccessors] In trait Base, renaming g -> Base$$g +[log superaccessors] Expanded 'g' to 'Base$$g' in trait Base +[log superaccessors] In trait Base, renaming h -> Base$$h +[log superaccessors] Expanded 'h' to 'Base$$h' in trait Base +[log superaccessors] In trait Base, renaming p -> Base$$p +[log superaccessors] Expanded 'p' to 'Base$$p' in trait Base +[log superaccessors] [context] ++ t12494.scala / type Base +[log superaccessors] [context] ++ t12494.scala / type Base +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term g +[log superaccessors] [context] ++ t12494.scala / term g +[log superaccessors] [context] ++ t12494.scala / term h +[log superaccessors] [context] ++ t12494.scala / term h +[log superaccessors] [context] ++ t12494.scala / term p +[log superaccessors] [context] ++ t12494.scala / term p +[log superaccessors] [context] ++ t12494.scala / term Base +[log superaccessors] [context] ++ t12494.scala / term Base +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / type Child +[log superaccessors] [context] ++ t12494.scala / type Child +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / Template(value ) +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term f +[log superaccessors] [context] ++ t12494.scala / term g +[log superaccessors] [context] ++ t12494.scala / term g +[log superaccessors] [context] ++ t12494.scala / term h +[log superaccessors] [context] ++ t12494.scala / term h +[log superaccessors] [context] ++ t12494.scala / term p +[log superaccessors] [context] ++ t12494.scala / term p +[running phase extmethods on t12494.scala] +[running phase pickler on t12494.scala] +[running phase refchecks on t12494.scala] +t12494.scala:9: error: weaker access privileges in overriding + protected[trait C] def f: scala.this.Int (defined in trait C) + override should at least be protected[C]; + found : scala.this.Int + required: scala.this.Int + protected[C] def f: Int = 42 // no, limitation + ^ +t12494.scala:28: error: weaker access privileges in overriding + protected[trait C] def f: scala.this.Int (defined in trait C) + override should at least be protected[C]; + found : scala.this.Int + required: scala.this.Int + protected[C] def f: Int = 42 // no + ^ +t12494.scala:47: error: class Child needs to be abstract. +Missing implementations for 3 members of trait Base. + private[trait Base] def g: scala.this.Int = ??? + private[trait Base] def h: scala.this.Int = ??? + private[trait Base] def p: scala.this.Int = ??? + + class Child extends Base { + ^ +t12494.scala:50: error: method g overrides nothing + override private[Base] def g: Int = 42 // ok, companion + ^ +t12494.scala:51: error: method h overrides nothing + override protected[Base] def h: Int = 42 // ok, private[C] widens to protected[C] + ^ +t12494.scala:52: error: method p overrides nothing + override protected def p: Int = 42 // error, protected only overrides protected + ^ +6 errors diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-additional.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-additional.check new file mode 100644 index 0000000000..bf96f9fafc --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-additional.check @@ -0,0 +1,29 @@ + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees + packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees +scalanative-p... 5 prepare ASTs for Native interop + superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + patmat 10 translate match expressions + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition +scalanative-g... 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + ploogin 26 A sample phase that does so many things it's kind of ha... + terminal 27 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-list.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-list.check new file mode 100644 index 0000000000..26dced07fa --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-list.check @@ -0,0 +1,2 @@ +ploogin - A sample plugin for testing. +scalanative - Compile to Scala Native IR (NIR) diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-missing.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-missing.check new file mode 100644 index 0000000000..9cd79b24d9 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-missing.check @@ -0,0 +1,29 @@ +Error: unable to load class: t6446.Ploogin + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees + packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees +scalanative-p... 5 prepare ASTs for Native interop + superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + patmat 10 translate match expressions + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition +scalanative-g... 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + terminal 26 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-show-phases.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-show-phases.check new file mode 100644 index 0000000000..7a1e78d562 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t6446-show-phases.check @@ -0,0 +1,28 @@ + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees + packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees +scalanative-p... 5 prepare ASTs for Native interop + superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + patmat 10 translate match expressions + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition +scalanative-g... 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + terminal 26 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t7494-no-options.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t7494-no-options.check new file mode 100644 index 0000000000..4a09716485 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/neg/t7494-no-options.check @@ -0,0 +1,30 @@ +error: Error: ploogin takes no options + phase name id description + ---------- -- ----------- + parser 1 parse source into ASTs, perform simple desugaring + namer 2 resolve names, attach symbols to named trees + packageobjects 3 load package objects + typer 4 the meat and potatoes: type the trees +scalanative-p... 5 prepare ASTs for Native interop + superaccessors 6 add super accessors in traits and nested classes + extmethods 7 add extension methods for inline classes + pickler 8 serialize symbol tables + refchecks 9 reference/override checking, translate nested objects + patmat 10 translate match expressions + uncurry 11 uncurry, translate function values to anonymous classes + fields 12 synthesize accessors and fields, add bitmaps for lazy vals + tailcalls 13 replace tail calls by jumps + specialize 14 @specialized-driven class and method specialization + explicitouter 15 this refs to outer pointers + erasure 16 erase types, add interfaces for traits + posterasure 17 clean up erased inline classes + lambdalift 18 move nested functions to top level + constructors 19 move field definitions into constructors + flatten 20 eliminate inner classes + mixin 21 mixin composition +scalanative-g... 22 + cleanup 23 platform-specific cleanups, generate reflective calls + delambdafy 24 remove lambdas + jvm 25 generate JVM bytecode + ploogin 26 A sample phase that does so many things it's kind of ha... + terminal 27 the last phase during a compilation run diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classof.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classof.check new file mode 100644 index 0000000000..21bf4cfb41 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classof.check @@ -0,0 +1,22 @@ +Value types: +class scala.scalanative.runtime.PrimitiveUnit +class scala.scalanative.runtime.PrimitiveBoolean +class scala.scalanative.runtime.PrimitiveByte +class scala.scalanative.runtime.PrimitiveShort +class scala.scalanative.runtime.PrimitiveChar +class scala.scalanative.runtime.PrimitiveInt +class scala.scalanative.runtime.PrimitiveLong +class scala.scalanative.runtime.PrimitiveFloat +class scala.scalanative.runtime.PrimitiveDouble +Class types +class SomeClass +class scala.collection.immutable.List +class scala.Tuple2 +Arrays: +class scala.scalanative.runtime.ObjectArray +class scala.scalanative.runtime.IntArray +class scala.scalanative.runtime.DoubleArray +class scala.scalanative.runtime.ObjectArray +Functions: +interface scala.Function2 +interface scala.Function1 diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_contextbound.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_contextbound.check new file mode 100644 index 0000000000..5d3106c9bc --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_contextbound.check @@ -0,0 +1 @@ +class scala.scalanative.runtime.IntArray diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_multi.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_multi.check new file mode 100644 index 0000000000..ab1c14e439 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/classtags_multi.check @@ -0,0 +1,5 @@ +Int +Array[scala.scalanative.runtime.PrimitiveInt] +Array[java.lang.Object] +Array[java.lang.Object] +Array[java.lang.Object] diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/getClassTest-valueClass.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/getClassTest-valueClass.check new file mode 100644 index 0000000000..cee2875fff --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/getClassTest-valueClass.check @@ -0,0 +1,2 @@ +class scala.scalanative.runtime.PrimitiveInt +class V diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/interop_classtags_are_classmanifests.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/interop_classtags_are_classmanifests.check new file mode 100644 index 0000000000..5ef5b7138c --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/interop_classtags_are_classmanifests.check @@ -0,0 +1,3 @@ +Int +java.lang.String +Array[scala.scalanative.runtime.PrimitiveInt] diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t4753.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t4753.check new file mode 100644 index 0000000000..9a020c1ead --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t4753.check @@ -0,0 +1 @@ +class scala.scalanative.runtime.PrimitiveBoolean diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5568.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5568.check new file mode 100644 index 0000000000..0018046644 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5568.check @@ -0,0 +1,9 @@ +class scala.scalanative.runtime.PrimitiveUnit +class scala.scalanative.runtime.PrimitiveInt +class scala.runtime.BoxedUnit +class scala.runtime.BoxedUnit +class java.lang.Integer +class java.lang.Integer +5 +5 +5 diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5923b.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5923b.check new file mode 100644 index 0000000000..a4885c883f --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t5923b.check @@ -0,0 +1,3 @@ +class scala.scalanative.runtime.ObjectArray +class scala.scalanative.runtime.ObjectArray +class scala.scalanative.runtime.ObjectArray diff --git a/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t6318_primitives.check b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t6318_primitives.check new file mode 100644 index 0000000000..1b64e046c7 --- /dev/null +++ b/scala-partest-tests/src/test/resources/scala/tools/partest/scalanative/2.13.15/run/t6318_primitives.check @@ -0,0 +1,54 @@ +Checking if class scala.scalanative.runtime.PrimitiveByte matches class scala.scalanative.runtime.PrimitiveByte +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveByte matches class scala.scalanative.runtime.PrimitiveShort +None +Checking if class java.lang.Byte matches class scala.scalanative.runtime.PrimitiveByte +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveShort matches class scala.scalanative.runtime.PrimitiveShort +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveShort matches class scala.scalanative.runtime.PrimitiveChar +None +Checking if class java.lang.Short matches class scala.scalanative.runtime.PrimitiveShort +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveChar matches class scala.scalanative.runtime.PrimitiveChar +Some() +Checking if class scala.scalanative.runtime.PrimitiveChar matches class scala.scalanative.runtime.PrimitiveInt +None +Checking if class java.lang.Character matches class scala.scalanative.runtime.PrimitiveChar +Some() +Checking if class scala.scalanative.runtime.PrimitiveInt matches class scala.scalanative.runtime.PrimitiveInt +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveInt matches class scala.scalanative.runtime.PrimitiveLong +None +Checking if class java.lang.Integer matches class scala.scalanative.runtime.PrimitiveInt +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveLong matches class scala.scalanative.runtime.PrimitiveLong +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveLong matches class scala.scalanative.runtime.PrimitiveFloat +None +Checking if class java.lang.Long matches class scala.scalanative.runtime.PrimitiveLong +Some(1) +Checking if class scala.scalanative.runtime.PrimitiveFloat matches class scala.scalanative.runtime.PrimitiveFloat +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveFloat matches class scala.scalanative.runtime.PrimitiveDouble +None +Checking if class java.lang.Float matches class scala.scalanative.runtime.PrimitiveFloat +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveDouble matches class scala.scalanative.runtime.PrimitiveDouble +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveDouble matches class scala.scalanative.runtime.PrimitiveBoolean +None +Checking if class java.lang.Double matches class scala.scalanative.runtime.PrimitiveDouble +Some(1.0) +Checking if class scala.scalanative.runtime.PrimitiveBoolean matches class scala.scalanative.runtime.PrimitiveBoolean +Some(true) +Checking if class scala.scalanative.runtime.PrimitiveBoolean matches class scala.scalanative.runtime.PrimitiveUnit +None +Checking if class java.lang.Boolean matches class scala.scalanative.runtime.PrimitiveBoolean +Some(true) +Checking if class scala.scalanative.runtime.PrimitiveUnit matches class scala.scalanative.runtime.PrimitiveUnit +Some(()) +Checking if class scala.scalanative.runtime.PrimitiveUnit matches class scala.scalanative.runtime.PrimitiveByte +None +Checking if class scala.scalanative.runtime.BoxedUnit$ matches class scala.scalanative.runtime.PrimitiveUnit +Some(()) From f8aa78248cc92dce1c1d8b3c02c821ec8656033a Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Thu, 26 Sep 2024 11:52:08 +0200 Subject: [PATCH 22/35] [chore] Add Scala 3.3.4 to the build (#4062) --- project/ScalaVersions.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/ScalaVersions.scala b/project/ScalaVersions.scala index 4107c7e643..1a30dc3489 100644 --- a/project/ScalaVersions.scala +++ b/project/ScalaVersions.scala @@ -26,7 +26,7 @@ object ScalaVersions { // windowslib fails to compile with 3.1.{0-1} crossScalaVersions("3.1", 2 to 3), crossScalaVersions("3.2", 0 to 2), - crossScalaVersions("3.3", 0 to 3), + crossScalaVersions("3.3", 0 to 4), crossScalaVersions("3.4", 0 to 3), crossScalaVersions("3.5", 0 to 1) ).flatten.distinct @@ -34,7 +34,7 @@ object ScalaVersions { // Tested in scheduled nightly CI to check compiler plugins // List maintains only upcoming releases, removed from the list after reaching stable status lazy val scala3RCVersions = List( - 1.to(4).map(v => s"3.3.4-RC$v"), + // 1.to(1).map(v => s"3.3.5-RC$v"), 1.to(1).map(v => s"3.5.2-RC$v") ).flatten From 0cc7ed839ff450aecf7cbb21eac635718d59574c Mon Sep 17 00:00:00 2001 From: LeeTibbert Date: Thu, 26 Sep 2024 09:09:39 -0400 Subject: [PATCH 23/35] [improve/build] Remove two FreeBSD build defects (#4059) --- .../scala-native/gc/shared/MemoryInfo.h | 23 +++++++- .../testsuite/posixlib/sys/StatTest.scala | 52 ++++++++++++++----- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/nativelib/src/main/resources/scala-native/gc/shared/MemoryInfo.h b/nativelib/src/main/resources/scala-native/gc/shared/MemoryInfo.h index e616a32c95..6b9535fbb9 100644 --- a/nativelib/src/main/resources/scala-native/gc/shared/MemoryInfo.h +++ b/nativelib/src/main/resources/scala-native/gc/shared/MemoryInfo.h @@ -119,9 +119,30 @@ size_t getFreeMemorySize() { GlobalMemoryStatusEx(&status); return (size_t)status.ullAvailPhys; +#elif defined(__FreeBSD__) + /* FreeBSD uses a different paging model. It documents that it tries + * to keep the number of free pages low; basically zero plus a few + * guard pages intended for its own use. + * + * The concept of _SC_AVPHYS_PAGES makes little to no sense on FreeBSD + * so it does not have that sysconf parameter, causing a build failure + * without this #elif. + * + * An approximation of that parameter can be calculated from + * a detailed knowledge of FreeBSD practices, but those are subject to + * change. + * + * This function is currently used to provide values for informational + * messages, where the "remaining" is likely to be close to zero, in + * the Linux sense, already. Return the "close to zero" limit 0L. + * No sense in calculating a better approximation. + */ + + return 0L; + #elif (defined(__unix__) || defined(__unix) || defined(unix) || \ (defined(__APPLE__) && defined(__MACH__)) && defined(_SC_AVPHYS_PAGES)) - /* UNIX variants. ------------------------------------------- */ + /* UNIX variants; yes NetBSD, but not FreeBSD --------------------- */ long pages = sysconf(_SC_AVPHYS_PAGES); long page_size = sysconf(_SC_PAGESIZE); if (pages == -1 || page_size == -1) diff --git a/unit-tests/native/src/test/scala/org/scalanative/testsuite/posixlib/sys/StatTest.scala b/unit-tests/native/src/test/scala/org/scalanative/testsuite/posixlib/sys/StatTest.scala index ce7b33f457..bffadd7366 100644 --- a/unit-tests/native/src/test/scala/org/scalanative/testsuite/posixlib/sys/StatTest.scala +++ b/unit-tests/native/src/test/scala/org/scalanative/testsuite/posixlib/sys/StatTest.scala @@ -83,16 +83,37 @@ class StatTest { statFromFd.st_rdev ) - val expectedRdev = - if (!LinktimeInfo.isFreeBSD && !LinktimeInfo.isNetBSD) - 0.toUSize // Linux, macOS - else ULong.MaxValue.toUSize + val expectedRdev = 0.toUSize + + if (LinktimeInfo.isFreeBSD || LinktimeInfo.isOpenBSD) { + /* The important test is above: + * "st_ino from path and from fd must be the same". + * + * Bypass this test on FreeBSD because the complexity of dealing + * with different expected st_rdev values on different FreeBSD + * version does not yield value worth the cost. + * + * On FreeBSD 14.1-RELEASE-p5, and probably earlier, the + * expected rt_dev is 0, same as Linux & macOS. + * command line: "stat -s /etc" yields (edited) "st_rdev=0" + * + * From examining the history of this test, it appears that + * FreeBSD 13.n expected ULong.MaxValue.toUSize. + * + * This maintainer has no ready access to a NetBSD system. + * In an abundance of caution, skip this test there also. + */ + + () // Do Nothing + + } else { // Linux, macOS, etc + assertEquals( + s"st_rdev must be ${expectedRdev} for regular file", + expectedRdev, + statFromPath.st_rdev + ) + } - assertEquals( - s"st_rdev must be ${expectedRdev} for regular file", - expectedRdev, - statFromPath.st_rdev - ) assertEquals( "st_ino from path and from fd must be the same", statFromPath.st_ino, @@ -254,9 +275,16 @@ class StatTest { stat.S_ISDIR(dirStatFromPath.st_mode) ) - /* OpenBSD returns some vlaue as st_rdev for directory, - * which seems to be related to inode => we can't predict it */ - if (!LinktimeInfo.isOpenBSD) { + if (LinktimeInfo.isFreeBSD || LinktimeInfo.isOpenBSD) { + /* Bypass + * - FreeBSD see the discussion in this Test of rt_dev and why it + * is bypassed when testing a file rt_dev. + * + * - OpenBSD returns some value as st_rdev for directory, + * which seems to be related to inode => we can't predict it. + */ + () // Do Nothing + } else { // Linux, macOS, etc assertEquals( s"st_rdev must be ${expectedRdev} for dir file", expectedRdev, From a0a8df06af99c7c0550d486b3071b56b89dace2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Costa?= Date: Tue, 1 Oct 2024 16:00:25 +0100 Subject: [PATCH 24/35] Improve interflow inliner log messages (#4055) * Improve interflow inliner log messages --- .../scala/scala/scalanative/interflow/Inline.scala | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/src/main/scala/scala/scalanative/interflow/Inline.scala b/tools/src/main/scala/scala/scalanative/interflow/Inline.scala index dc8c3c27c6..5e48889f5a 100644 --- a/tools/src/main/scala/scala/scalanative/interflow/Inline.scala +++ b/tools/src/main/scala/scala/scalanative/interflow/Inline.scala @@ -58,11 +58,19 @@ private[interflow] trait Inline { self: Interflow => if (shall) { if (shallNot) { logger(s"not inlining ${name.show}, because:") + if (noOpt) logger("* has noopt attr") if (noInline) logger("* has noinline attr") if (isRecursive) logger("* is recursive") if (isDenylisted) logger("* is denylisted") - if (callerTooBig) logger("* caller is too big") - if (calleeTooBig) logger("* callee is too big") + if (calleeTooBig) + logger( + s"* callee is too big (${defn.insts.size} > $maxCalleeSize)" + ) + if (callerTooBig) + logger( + s"* caller is too big (${mergeProcessor.currentSize()} > $maxCallerSize)" + ) + if (isExtern) logger("* is an extern method") if (inlineDepthLimitExceeded) logger("* inline depth limit exceeded") } From ac7fb0e27d2fc7f7cb60b8130485573e4453187b Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Tue, 1 Oct 2024 20:52:04 +0200 Subject: [PATCH 25/35] [fix] Teach NIR subtyping to treat `scala.runtime.Nothing$` in the same way a `nir.Type.Nothing` (#4065) * Add reproducer for issue #4039 * Teach subtyping to treat runtime.Nothing$ and runtime.Null$ as NIR null / nothing * Short circuit Ident when refering to Nothing type - throw error instead * Fixes corercion and casting operations * Fix Scala3 desugared select positions --- .../scala/scala/scalanative/nir/Types.scala | 19 ++++++ .../scalanative/nscplugin/NirGenExpr.scala | 49 +++++++++---- .../scalanative/nscplugin/NirGenType.scala | 1 + .../scalanative/nscplugin/NirGenExpr.scala | 68 +++++++++++-------- .../scalanative/nscplugin/NirGenType.scala | 1 + .../scala/scala/scalanative/linker/Sub.scala | 25 ++++--- .../scala/scalanative/linker/IssuesSpec.scala | 10 +++ 7 files changed, 121 insertions(+), 52 deletions(-) diff --git a/nir/src/main/scala/scala/scalanative/nir/Types.scala b/nir/src/main/scala/scala/scalanative/nir/Types.scala index ac904b3c58..674e2c2383 100644 --- a/nir/src/main/scala/scala/scalanative/nir/Types.scala +++ b/nir/src/main/scala/scala/scalanative/nir/Types.scala @@ -233,6 +233,25 @@ object Type { def isUnsignedType(ty: Type): Boolean = unsigned.values.contains(normalize(ty)) + object NothingType { + def unapply(v: nir.Type): Option[nir.Type] = + if (isNothing(v)) Some(v) else None + } + def isNothing(ty: Type): Boolean = ty match { + case nir.Type.Nothing => true + case nir.Type.Ref(name, _, _) => name == nir.Rt.RuntimeNothing.name + case _ => false + } + object NullType { + def unapply(v: nir.Type): Option[nir.Type] = + if (isNull(v)) Some(v) else None + } + def isNull(ty: Type): Boolean = ty match { + case nir.Type.Null => true + case nir.Type.Ref(name, _, _) => name == nir.Rt.RuntimeNull.name + case _ => false + } + def normalize(ty: Type): Type = ty match { case ArrayValue(ty, n) => ArrayValue(normalize(ty), n) case StructValue(tys) => StructValue(tys.map(normalize)) diff --git a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala index f0fff87993..dea09f63f8 100644 --- a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala +++ b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenExpr.scala @@ -703,13 +703,20 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => val sym = tree.symbol implicit val pos: nir.SourcePosition = tree.pos.orElse(fallbackSourcePosition) - if (curMethodInfo.mutableVars.contains(sym)) { + val value = if (curMethodInfo.mutableVars.contains(sym)) { buf.varload(curMethodEnv.resolve(sym), unwind) } else if (sym.isModule) { genModule(sym) } else { curMethodEnv.resolve(sym) } + if (nir.Type.isNothing(value.ty)) { + // Short circuit the generated code for phantom value + // scala.runtime.Nothing$ extends Throwable so it's safe to throw + buf.raise(value, unwind) + buf.unreachable(unwind) + } + value } def genSelect(tree: Select): nir.Val = { @@ -842,15 +849,14 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => // enclosing class `this` reference + capture symbols val captureSymsWithEnclThis = curClassSym.get +: captureSyms - val captureTypes = captureSymsWithEnclThis.map(sym => genType(sym.tpe)) - val captureNames = + val (captureTypes, captureNames) = captureSymsWithEnclThis.zipWithIndex.map { case (sym, idx) => val name = anonName.member(nir.Sig.Field("capture" + idx)) val ty = genType(sym.tpe) statBuf += nir.Defn.Var(nir.Attrs.None, name, ty, nir.Val.Zero(ty)) - name - } + (ty, name) + }.unzip // Generate an anonymous class constructor that initializes all the fields. @@ -927,7 +933,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => case ErasedValueType(valueClazz, underlying) => val unboxMethod = valueClazz.derivedValueClassUnbox val casted = - buf.genCastOp(value.ty, genType(valueClazz), value) + buf.genCastOp(value.ty, genRefType(valueClazz), value) val unboxed = buf.genApplyMethod( sym = unboxMethod, statically = false, @@ -937,13 +943,21 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => if (unboxMethod.tpe.resultType == underlying) unboxed else - buf.genCastOp(unboxed.ty, genType(underlying), unboxed) + buf.genCastOp( + unboxed.ty, + genRefType(underlying), + unboxed + ) case _ => val unboxed = buf.unboxValue(sym.tpe, partial = true, value) if (unboxed == value) // no need to or cannot unbox, we should cast - buf.genCastOp(genType(sym.tpe), genType(arg.tpe), value) + buf.genCastOp( + genRefType(sym.tpe), + genRefType(arg.tpe), + value + ) else unboxed } curMethodEnv.enter(sym, result) @@ -1050,7 +1064,8 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => case tpe: ErasedValueType => val valueClass = tpe.valueClazz val unboxMethod = treeInfo.ValueClass.valueUnbox(tpe) - val castedValue = buf.genCastOp(value.ty, genType(valueClass), value) + val castedValue = + buf.genCastOp(value.ty, genRefType(valueClass), value) buf.genApplyMethod( sym = unboxMethod, statically = false, @@ -1061,7 +1076,11 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => case tpe => val unboxed = buf.unboxValue(tpe, partial = true, value) if (unboxed == value) // no need to or cannot unbox, we should cast - buf.genCastOp(genType(tpeEnteringPosterasure), genType(tpe), value) + buf.genCastOp( + genRefType(tpeEnteringPosterasure), + genRefType(tpe), + value + ) else unboxed } } @@ -2367,7 +2386,9 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => def genCastOp(fromty: nir.Type, toty: nir.Type, value: nir.Val)(implicit pos: nir.SourcePosition ): nir.Val = - castConv(fromty, toty).fold(value)(buf.conv(_, toty, value, unwind)) + castConv(fromty, toty) + .orElse(castConv(value.ty, toty)) + .fold(value)(buf.conv(_, toty, value, unwind)) private lazy val optimizedFunctions = { // Included functions should be pure, and should not not narrow the result type @@ -2682,9 +2703,9 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] => def genCoercion(value: nir.Val, fromty: nir.Type, toty: nir.Type)(implicit pos: nir.SourcePosition ): nir.Val = { - if (fromty == toty) { - value - } else { + if (fromty == toty) value + else if (nir.Type.isNothing(fromty) || nir.Type.isNothing(toty)) value + else { val conv = (fromty, toty) match { case (nir.Type.Ptr, _: nir.Type.RefKind) => nir.Conv.Bitcast diff --git a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenType.scala b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenType.scala index b3ab376db0..6641187065 100644 --- a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenType.scala +++ b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/NirGenType.scala @@ -134,6 +134,7 @@ trait NirGenType[G <: Global with Singleton] { self: NirGenPhase[G] => case UnitClass => nir.Type.Unit case BoxedUnitClass => nir.Rt.BoxedUnit case NullClass => genRefType(RuntimeNullClass) + case NothingClass => genRefType(RuntimeNothingClass) case ArrayClass => nir.Type.Array(genType(st.targs.head)) case _ if st.isStruct => genStruct(st) case _ if deconstructValueTypes => diff --git a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala index ea3ae8e438..56e9070652 100644 --- a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala +++ b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala @@ -151,10 +151,10 @@ trait NirGenExpr(using Context) { val Assign(lhsp, rhsp) = tree given nir.SourcePosition = tree.span - desugarTree(lhsp) match { - case sel @ Select(qualp, _) => + lhsp match { + case DesugaredSelect(qualp, _) => def rhs = genExpr(rhsp) - val sym = sel.symbol + val sym = lhsp.symbol val name = genFieldName(sym) if (sym.isExtern) { // Ignore intrinsic call to extern in class constructor @@ -164,14 +164,14 @@ trait NirGenExpr(using Context) { rhsp.symbol == defnNir.UnsafePackage_extern if (shouldIgnoreAssign) nir.Val.Unit else { - val externTy = genExternType(sel.tpe) + val externTy = genExternType(lhsp.tpe) genStoreExtern(externTy, sym, rhs) } } else { val qual = if (sym.isStaticMember) genModule(qualp.symbol) else genExpr(qualp) - val ty = genType(sel.tpe) + val ty = genType(lhsp.tpe) buf.fieldstore(ty, qual, name, rhs, unwind) } @@ -448,19 +448,23 @@ trait NirGenExpr(using Context) { } def genIdent(tree: Ident): nir.Val = - desugarIdent(tree) match { - case Ident(_) => + tree match { + case DesugaredSelect(_, _) => + genSelect(DesugaredSelect.desugared.withSpan(tree.span)) + case _ => val sym = tree.symbol given nir.SourcePosition = tree.span - if (curMethodInfo.mutableVars.contains(sym)) - buf.varload(curMethodEnv.resolve(sym), unwind) - else if (sym.is(Module)) - genModule(sym) - else curMethodEnv.resolve(sym) - case desuagred: Select => - genSelect(desuagred.withSpan(tree.span)) - case tree => - throw FatalError(s"Unsupported desugared ident tree: $tree") + val value = + if sym.is(Module) then genModule(sym) + else if (curMethodInfo.mutableVars.contains(sym)) + buf.varload(curMethodEnv.resolve(sym), unwind) + else curMethodEnv.resolve(sym) + if nir.Type.isNothing(value.ty) then + // Short circuit the generated code for phantom value + // scala.runtime.Nothing$ extends Throwable so it's safe to throw + buf.raise(value, unwind) + buf.unreachable(unwind) + value } def genIf(tree: If): nir.Val = { @@ -1101,8 +1105,7 @@ trait NirGenExpr(using Context) { import NirPrimitives._ import dotty.tools.backend.ScalaPrimitivesOps._ given nir.SourcePosition = app.span - val Apply(fun, args) = app - val Select(receiver, _) = desugarTree(fun): @unchecked + val Apply(fun @ DesugaredSelect(receiver, _), args) = app: @unchecked val sym = app.symbol val code = nirPrimitives.getPrimitive(app, receiver.tpe) @@ -1181,8 +1184,10 @@ trait NirGenExpr(using Context) { } private def genApplyTypeApply(app: Apply): nir.Val = { - val Apply(tApply @ TypeApply(fun, targs), argsp) = app: @unchecked - val Select(receiverp, _) = desugarTree(fun): @unchecked + val Apply( + tApply @ TypeApply(fun @ DesugaredSelect(receiverp, _), targs), + argsp + ) = app: @unchecked given nir.SourcePosition = app.span val funSym = fun.symbol @@ -1381,7 +1386,7 @@ trait NirGenExpr(using Context) { s"Too many arguments for primitive function: $app", app.sourcePos ) - nir.Val.Null + nir.Val.Zero(retty) } } @@ -1467,7 +1472,7 @@ trait NirGenExpr(using Context) { s"Unknown floating point type binary operation code: $code", right.sourcePos ) - nir.Val.Null + nir.Val.Zero(retty) } case nir.Type.Bool | _: nir.Type.I => code match { @@ -1498,7 +1503,7 @@ trait NirGenExpr(using Context) { s"Unknown integer type binary operation code: $code", right.sourcePos ) - nir.Val.Null + nir.Val.Zero(retty) } case _: nir.Type.RefKind => def genEquals(ref: Boolean, negated: Boolean) = (left, right) match { @@ -1521,7 +1526,7 @@ trait NirGenExpr(using Context) { s"Unknown reference type binary operation code: $code", right.sourcePos ) - nir.Val.Null + nir.Val.Zero(retty) } case nir.Type.Ptr => code match { @@ -1533,7 +1538,7 @@ trait NirGenExpr(using Context) { s"Unknown binary operation type: $ty", right.sourcePos ) - nir.Val.Null + nir.Val.Zero(retty) } genCoercion(binres, binres.ty, retty)(using right.span) @@ -2044,7 +2049,9 @@ trait NirGenExpr(using Context) { def genCastOp(from: nir.Type, to: nir.Type, value: nir.Val)(using nir.SourcePosition ): nir.Val = - castConv(from, to).fold(value)(buf.conv(_, to, value, unwind)) + castConv(from, to) + .orElse(castConv(value.ty, to)) + .fold(value)(buf.conv(_, to, value, unwind)) private def genCoercion(app: Apply, receiver: Tree, code: Int): nir.Val = { given nir.SourcePosition = app.span @@ -2244,7 +2251,8 @@ trait NirGenExpr(using Context) { case ErasedValueType(valueClass, _) => val boxedClass = valueClass.typeSymbol.asClass val unboxMethod = ValueClasses.valueClassUnbox(boxedClass) - val castedValue = buf.genCastOp(value.ty, genType(valueClass), value) + val castedValue = + buf.genCastOp(value.ty, genRefType(valueClass), value) buf.genApplyMethod( sym = unboxMethod, statically = false, @@ -2255,7 +2263,11 @@ trait NirGenExpr(using Context) { case tpe => val unboxed = buf.unboxValue(tpe, partial = true, value) if (unboxed == value) // no need to or cannot unbox, we should cast - buf.genCastOp(genType(tpeEnteringPosterasure), genType(tpe), value) + buf.genCastOp( + genRefType(tpeEnteringPosterasure), + genRefType(tpe), + value + ) else unboxed } } diff --git a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenType.scala b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenType.scala index a4bdd1a742..77be14acb1 100644 --- a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenType.scala +++ b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenType.scala @@ -211,6 +211,7 @@ trait NirGenType(using Context) { else if (sym == defn.UnitClass) nir.Type.Unit else if (sym == defn.BoxedUnitClass) nir.Rt.BoxedUnit else if (sym == defn.NullClass) nir.Rt.RuntimeNull + else if (sym == defn.NothingClass) nir.Rt.RuntimeNothing else if (sym == defn.ArrayClass) nir.Type.Array(genType(targs.head)) else if (sym.isStruct) genStruct(st) else if (deconstructValueTypes) { diff --git a/tools/src/main/scala/scala/scalanative/linker/Sub.scala b/tools/src/main/scala/scala/scalanative/linker/Sub.scala index 6b6b42cfe4..537c7148f1 100644 --- a/tools/src/main/scala/scala/scalanative/linker/Sub.scala +++ b/tools/src/main/scala/scala/scalanative/linker/Sub.scala @@ -39,16 +39,21 @@ object Sub { (l, r) match { case (l, r) if l == r => true - case (nir.Type.Null, (nir.Type.Ptr | _: nir.Type.RefKind)) => + case (nir.Type.NullType(_), (nir.Type.Ptr | _: nir.Type.RefKind)) => true - case (nir.Type.Nothing, (_: nir.Type.ValueKind | _: nir.Type.RefKind)) => + case ( + nir.Type.NothingType(_), + (_: nir.Type.ValueKind | _: nir.Type.RefKind) + ) => true case (_: nir.Type.RefKind, nir.Rt.Object) => true case (ScopeRef(linfo), ScopeRef(rinfo)) => linfo.is(rinfo) - case _ => - false + // FIXME: Workaround for method/return types not being defined as scala.runtime.Nothing$|Null$ + case (nir.Type.NothingType(_), nir.Type.NothingType(_)) => true + case (nir.Type.NullType(_), nir.Type.NullType(_)) => true + case _ => false } } @@ -80,17 +85,17 @@ object Sub { (lty, rty) match { case _ if lty == rty => lty - case (ty, nir.Type.Nothing) => + case (ty, nir.Type.NothingType(_)) => ty - case (nir.Type.Nothing, ty) => + case (nir.Type.NothingType(_), ty) => ty - case (nir.Type.Ptr, nir.Type.Null) => + case (nir.Type.Ptr, nir.Type.NullType(_)) => nir.Type.Ptr - case (nir.Type.Null, nir.Type.Ptr) => + case (nir.Type.NullType(_), nir.Type.Ptr) => nir.Type.Ptr - case (refty: nir.Type.RefKind, nir.Type.Null) => + case (refty: nir.Type.RefKind, nir.Type.NullType(_)) => nir.Type.Ref(refty.className, refty.isExact, nullable = true) - case (nir.Type.Null, refty: nir.Type.RefKind) => + case (nir.Type.NullType(_), refty: nir.Type.RefKind) => nir.Type.Ref(refty.className, refty.isExact, nullable = true) case (lty: nir.Type.RefKind, rty: nir.Type.RefKind) => val ScopeRef(linfo) = lty: @unchecked diff --git a/tools/src/test/scala/scala/scalanative/linker/IssuesSpec.scala b/tools/src/test/scala/scala/scalanative/linker/IssuesSpec.scala index 0206d7a680..ab5230573b 100644 --- a/tools/src/test/scala/scala/scalanative/linker/IssuesSpec.scala +++ b/tools/src/test/scala/scala/scalanative/linker/IssuesSpec.scala @@ -174,4 +174,14 @@ class IssuesSpec extends LinkerSpec { } } + // https://github.com/scala-native/scala-native/issues/4039 + @Test def issue4039(): Unit = checkNoLinkageErrors { + """ + |object Test { + | def main(args: Array[String]): Unit = { + | Seq.empty[Nothing].forall(_ == Int.box(0)) + | } + |} + |""" + } } From fa40ec98626538a04f4db56c0425ce2dfcceb945 Mon Sep 17 00:00:00 2001 From: Eric K Richardson Date: Tue, 1 Oct 2024 11:53:14 -0700 Subject: [PATCH 26/35] Update source debug docs (#4063) From 7dfd5ae98738cc63424a6735a87f44d3e33e9419 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Mon, 7 Oct 2024 12:28:02 +0300 Subject: [PATCH 27/35] feature [nativelib]: partially implement `GarbageCollectorMXBean` (#4066) * feature [nativelib]: partially implement `GarbageCollectorMXBean` 1) Extend `LinktimeInfo`: add `garbageCollector` 2) Extend `GC`: add `getStatsCollectionTotal` and `getStatsCollectionDurationTotal` 3) Partially implement `GarbageCollectorMXBean` 4) Move `Time.c` and `Time.h` to `gc/shared` * feature [nativelib]: partially implement `GarbageCollectorMXBean` 1) Add `jmx.h` 2) Immix GC: measure collection duration inside `Heap_Collect` --- .../management/GarbageCollectorMXBean.scala | 37 +++++++++++++++++++ .../lang/management/ManagementFactory.scala | 23 ++++++++++++ .../lang/management/MemoryManagerMXBean.scala | 17 +++++++++ .../main/resources/scala-native/gc/boehm/gc.c | 17 ++++++++- .../scala-native/gc/commix/CommixGC.c | 9 +++++ .../resources/scala-native/gc/commix/Heap.c | 3 +- .../resources/scala-native/gc/commix/Heap.h | 4 +- .../resources/scala-native/gc/commix/Phase.c | 6 ++- .../resources/scala-native/gc/commix/Stats.c | 2 +- .../resources/scala-native/gc/commix/Stats.h | 2 +- .../resources/scala-native/gc/immix/Heap.c | 10 ++--- .../resources/scala-native/gc/immix/ImmixGC.c | 9 +++++ .../main/resources/scala-native/gc/none/gc.c | 4 ++ .../scala-native/gc/shared/ScalaNativeGC.h | 5 +++ .../gc/{immix_commix/utils => shared}/Time.c | 6 ++- .../gc/{immix_commix/utils => shared}/Time.h | 0 .../resources/scala-native/gc/shared/jmx.c | 24 ++++++++++++ .../resources/scala-native/gc/shared/jmx.h | 10 +++++ .../scala/scalanative/meta/LinktimeInfo.scala | 5 +++ .../scala/scala/scalanative/runtime/GC.scala | 7 ++++ .../linker/LinktimeValueResolver.scala | 1 + .../management/ManagementFactoryTest.scala | 12 ++++++ 22 files changed, 200 insertions(+), 13 deletions(-) create mode 100644 javalib/src/main/scala/java/lang/management/GarbageCollectorMXBean.scala create mode 100644 javalib/src/main/scala/java/lang/management/MemoryManagerMXBean.scala rename nativelib/src/main/resources/scala-native/gc/{immix_commix/utils => shared}/Time.c (96%) rename nativelib/src/main/resources/scala-native/gc/{immix_commix/utils => shared}/Time.h (100%) create mode 100644 nativelib/src/main/resources/scala-native/gc/shared/jmx.c create mode 100644 nativelib/src/main/resources/scala-native/gc/shared/jmx.h diff --git a/javalib/src/main/scala/java/lang/management/GarbageCollectorMXBean.scala b/javalib/src/main/scala/java/lang/management/GarbageCollectorMXBean.scala new file mode 100644 index 0000000000..d7ece82dec --- /dev/null +++ b/javalib/src/main/scala/java/lang/management/GarbageCollectorMXBean.scala @@ -0,0 +1,37 @@ +package java.lang.management + +import scala.scalanative.meta.LinktimeInfo +import scala.scalanative.runtime.GC + +trait GarbageCollectorMXBean extends MemoryManagerMXBean { + + /** Returns the total number of garbage collections that have occurred. + * + * Returns `-1` when the collection count is undefined for this collector. + */ + def getCollectionCount(): Long + + /** Returns the approximate accumulated elapsed time in milliseconds. + * + * Returns `-1` if the collection elapsed time is undefined for this + * collector. + */ + def getCollectionTime(): Long +} + +object GarbageCollectorMXBean { + private val NanosPerMilli = 1000000 + + private[management] def apply(): GarbageCollectorMXBean = + new Impl + + private class Impl extends GarbageCollectorMXBean { + def getName(): String = LinktimeInfo.garbageCollector + def isValid(): Boolean = true + def getMemoryPoolNames(): Array[String] = Array.empty + def getCollectionCount(): Long = GC.getStatsCollectionTotal().toLong + def getCollectionTime(): Long = + GC.getStatsCollectionDurationTotal().toLong / NanosPerMilli + } + +} diff --git a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala index 0de4a72b1b..d7a4b0a702 100644 --- a/javalib/src/main/scala/java/lang/management/ManagementFactory.scala +++ b/javalib/src/main/scala/java/lang/management/ManagementFactory.scala @@ -6,6 +6,7 @@ object ManagementFactory { private lazy val ThreadBean = ThreadMXBean() private lazy val OperatingSystemBean = OperatingSystemMXBean() private lazy val RuntimeBean = RuntimeMXBean() + private lazy val GarbageCollectorBean = GarbageCollectorMXBean() /** Returns the memory-specific bean. * @@ -50,4 +51,26 @@ object ManagementFactory { */ def getRuntimeMXBean(): RuntimeMXBean = RuntimeBean + /** Returns a list of [[MemoryManagerMXBean]]. + * + * @example + * {{{ + * val mmBean = ManagementFactory.getMemoryManagerMXBeans().get(0) + * println(s"Memory manager: $${mmBean.getName()}") + * }}} + */ + def getMemoryManagerMXBeans(): java.util.List[MemoryManagerMXBean] = + java.util.Collections.singletonList(GarbageCollectorBean) + + /** Returns a list of [[GarbageCollectorMXBean]]. + * + * @example + * {{{ + * val gcBean = ManagementFactory.getGarbageCollectorMXBeans().get(0) + * println(s"Total collection time (ms): $${gcBean.getCollectionTime()}") + * }}} + */ + def getGarbageCollectorMXBeans(): java.util.List[GarbageCollectorMXBean] = + java.util.Collections.singletonList(GarbageCollectorBean) + } diff --git a/javalib/src/main/scala/java/lang/management/MemoryManagerMXBean.scala b/javalib/src/main/scala/java/lang/management/MemoryManagerMXBean.scala new file mode 100644 index 0000000000..8661aa8d34 --- /dev/null +++ b/javalib/src/main/scala/java/lang/management/MemoryManagerMXBean.scala @@ -0,0 +1,17 @@ +package java.lang.management + +trait MemoryManagerMXBean { + + /** Returns the name of this memory manager. + */ + def getName(): String + + /** Returns `true` when the memory manager is valid and `false` otherwise. + */ + def isValid(): Boolean + + /** Returns the name of the managed memory pools. + */ + def getMemoryPoolNames(): Array[String] + +} diff --git a/nativelib/src/main/resources/scala-native/gc/boehm/gc.c b/nativelib/src/main/resources/scala-native/gc/boehm/gc.c index f93da84684..4ec588a9e6 100644 --- a/nativelib/src/main/resources/scala-native/gc/boehm/gc.c +++ b/nativelib/src/main/resources/scala-native/gc/boehm/gc.c @@ -9,6 +9,8 @@ #include #include #include "shared/Parsing.h" +#include "shared/Time.h" +#include "shared/jmx.h" // At the moment we rely on the conservative // mode of Boehm GC as our garbage collector. @@ -69,7 +71,20 @@ size_t scalanative_GC_get_used_heapsize() { return heap_sz - unmapped_bytes; } -void scalanative_GC_collect() { GC_gcollect(); } +size_t scalanative_GC_stats_collection_total() { + return jmx_stats_get_collection_total(); +} + +size_t scalanative_GC_stats_collection_duration_total() { + return jmx_stats_get_collection_duration_total(); +} + +void scalanative_GC_collect() { + size_t start_ns = Time_current_nanos(); + GC_gcollect(); + size_t end_ns = Time_current_nanos(); + jmx_stats_record_collection(start_ns, end_ns); +} void scalanative_GC_set_weak_references_collected_callback( WeakReferencesCollectedCallback callback) {} diff --git a/nativelib/src/main/resources/scala-native/gc/commix/CommixGC.c b/nativelib/src/main/resources/scala-native/gc/commix/CommixGC.c index 61cf47bcb4..a21ba6dd03 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/CommixGC.c +++ b/nativelib/src/main/resources/scala-native/gc/commix/CommixGC.c @@ -17,6 +17,7 @@ #include "WeakReferences.h" #include "Sweeper.h" #include "immix_commix/Synchronizer.h" +#include "shared/jmx.h" #include "shared/Parsing.h" @@ -114,6 +115,14 @@ size_t scalanative_GC_get_max_heapsize() { size_t scalanative_GC_get_used_heapsize() { return Heap_getMemoryUsed(&heap); } +size_t scalanative_GC_stats_collection_total() { + return jmx_stats_get_collection_total(); +} + +size_t scalanative_GC_stats_collection_duration_total() { + return jmx_stats_get_collection_duration_total(); +} + void scalanative_GC_add_roots(void *addr_low, void *addr_high) { AddressRange range = {addr_low, addr_high}; GC_Roots_Add(customRoots, range); diff --git a/nativelib/src/main/resources/scala-native/gc/commix/Heap.c b/nativelib/src/main/resources/scala-native/gc/commix/Heap.c index e1b6ffdf41..a54bbddfc5 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/Heap.c +++ b/nativelib/src/main/resources/scala-native/gc/commix/Heap.c @@ -1,4 +1,4 @@ -#include "immix_commix/utils/Time.h" +#include "shared/Time.h" #if defined(SCALANATIVE_GC_COMMIX) #include @@ -253,6 +253,7 @@ void Heap_Collect(Heap *heap) { GC_MutatorThreadState_Unmanaged); assert(Sweeper_IsSweepDone(heap)); #endif + heap->gcCollectionStart_ns = Time_current_nanos(); Stats *stats = Stats_OrNull(heap->stats); Stats_CollectionStarted(stats); #ifdef GC_ASSERTIONS diff --git a/nativelib/src/main/resources/scala-native/gc/commix/Heap.h b/nativelib/src/main/resources/scala-native/gc/commix/Heap.h index f49c126ae6..927e17407a 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/Heap.h +++ b/nativelib/src/main/resources/scala-native/gc/commix/Heap.h @@ -11,7 +11,7 @@ #include #include "shared/ThreadUtil.h" #include -#include "immix_commix/utils/Time.h" +#include "shared/Time.h" typedef struct { word_t *blockMetaStart; @@ -27,6 +27,8 @@ typedef struct { uint32_t maxBlockCount; double maxMarkTimeRatio; double minFreeRatio; + // The timestamp when the GC collection has started + size_t gcCollectionStart_ns; struct { semaphore_t startWorkers; semaphore_t startMaster; diff --git a/nativelib/src/main/resources/scala-native/gc/commix/Phase.c b/nativelib/src/main/resources/scala-native/gc/commix/Phase.c index 76ad516845..da4379af50 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/Phase.c +++ b/nativelib/src/main/resources/scala-native/gc/commix/Phase.c @@ -14,7 +14,8 @@ #ifndef _WIN32 #include #endif -#include "immix_commix/utils/Time.h" +#include "shared/Time.h" +#include "shared/jmx.h" /* If in OSX, sem_open cannot create a semaphore whose name is longer than @@ -181,6 +182,9 @@ void Phase_SweepDone(Heap *heap, Stats *stats) { Stats_RecordEvent(stats, event_collection, heap->stats->collection_start_ns, end_ns); + jmx_stats_record_collection(heap->gcCollectionStart_ns, + Time_current_nanos()); + heap->sweep.postSweepDone = true; atomic_thread_fence(memory_order_release); } diff --git a/nativelib/src/main/resources/scala-native/gc/commix/Stats.c b/nativelib/src/main/resources/scala-native/gc/commix/Stats.c index 6b33543f99..bf88e1001a 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/Stats.c +++ b/nativelib/src/main/resources/scala-native/gc/commix/Stats.c @@ -9,7 +9,7 @@ #include "shared/GCTypes.h" #include #include -#include "immix_commix/utils/Time.h" +#include "shared/Time.h" #ifdef ENABLE_GC_STATS const char *const Stats_eventNames[] = { diff --git a/nativelib/src/main/resources/scala-native/gc/commix/Stats.h b/nativelib/src/main/resources/scala-native/gc/commix/Stats.h index 32fdb63629..5246145d03 100644 --- a/nativelib/src/main/resources/scala-native/gc/commix/Stats.h +++ b/nativelib/src/main/resources/scala-native/gc/commix/Stats.h @@ -5,7 +5,7 @@ #include #include #include -#include "immix_commix/utils/Time.h" +#include "shared/Time.h" #define MUTATOR_THREAD_ID -1 diff --git a/nativelib/src/main/resources/scala-native/gc/immix/Heap.c b/nativelib/src/main/resources/scala-native/gc/immix/Heap.c index 3ee44e1975..3b3afa5224 100644 --- a/nativelib/src/main/resources/scala-native/gc/immix/Heap.c +++ b/nativelib/src/main/resources/scala-native/gc/immix/Heap.c @@ -8,11 +8,12 @@ #include "Allocator.h" #include "Marker.h" #include "State.h" -#include "immix_commix/utils/Time.h" #include "immix_commix/StackTrace.h" #include "Settings.h" #include "shared/MemoryInfo.h" #include "shared/MemoryMap.h" +#include "shared/Time.h" +#include "shared/jmx.h" #include #include "WeakReferences.h" #include "immix_commix/Synchronizer.h" @@ -178,9 +179,7 @@ void Heap_Collect(Heap *heap, Stack *stack) { printf("\nCollect\n"); fflush(stdout); #endif - if (stats != NULL) { - start_ns = Time_current_nanos(); - } + start_ns = Time_current_nanos(); Marker_MarkRoots(heap, stack); if (stats != NULL) { nullify_start_ns = Time_current_nanos(); @@ -190,8 +189,9 @@ void Heap_Collect(Heap *heap, Stack *stack) { sweep_start_ns = Time_current_nanos(); } Heap_Recycle(heap); + end_ns = Time_current_nanos(); + jmx_stats_record_collection(start_ns, end_ns); if (stats != NULL) { - end_ns = Time_current_nanos(); Stats_RecordCollection(stats, start_ns, nullify_start_ns, sweep_start_ns, end_ns); } diff --git a/nativelib/src/main/resources/scala-native/gc/immix/ImmixGC.c b/nativelib/src/main/resources/scala-native/gc/immix/ImmixGC.c index 1389b8d3c0..c41dd7326c 100644 --- a/nativelib/src/main/resources/scala-native/gc/immix/ImmixGC.c +++ b/nativelib/src/main/resources/scala-native/gc/immix/ImmixGC.c @@ -11,6 +11,7 @@ #include "WeakReferences.h" #include "Settings.h" #include "shared/Parsing.h" +#include "shared/jmx.h" #ifdef SCALANATIVE_MULTITHREADING_ENABLED #include "immix_commix/Synchronizer.h" #endif @@ -99,6 +100,14 @@ size_t scalanative_GC_get_max_heapsize() { size_t scalanative_GC_get_used_heapsize() { return Heap_getMemoryUsed(&heap); } +size_t scalanative_GC_stats_collection_total() { + return jmx_stats_get_collection_total(); +} + +size_t scalanative_GC_stats_collection_duration_total() { + return jmx_stats_get_collection_duration_total(); +} + void scalanative_GC_add_roots(void *addr_low, void *addr_high) { AddressRange range = {addr_low, addr_high}; GC_Roots_Add(customRoots, range); diff --git a/nativelib/src/main/resources/scala-native/gc/none/gc.c b/nativelib/src/main/resources/scala-native/gc/none/gc.c index 047e14ca43..f460c3ca84 100644 --- a/nativelib/src/main/resources/scala-native/gc/none/gc.c +++ b/nativelib/src/main/resources/scala-native/gc/none/gc.c @@ -50,6 +50,10 @@ size_t scalanative_GC_get_max_heapsize() { size_t scalanative_GC_get_used_heapsize() { return TOTAL_ALLOCATED; } +size_t scalanative_GC_stats_collection_total() { return -1L; } + +size_t scalanative_GC_stats_collection_duration_total() { return -1L; } + void Prealloc_Or_Default() { if (TO_NORMAL_MMAP == 1L) { // Check if we have prealloc env varible diff --git a/nativelib/src/main/resources/scala-native/gc/shared/ScalaNativeGC.h b/nativelib/src/main/resources/scala-native/gc/shared/ScalaNativeGC.h index 64d2102dab..91461c4468 100644 --- a/nativelib/src/main/resources/scala-native/gc/shared/ScalaNativeGC.h +++ b/nativelib/src/main/resources/scala-native/gc/shared/ScalaNativeGC.h @@ -39,6 +39,11 @@ size_t scalanative_GC_get_init_heapsize(); size_t scalanative_GC_get_max_heapsize(); size_t scalanative_GC_get_used_heapsize(); +// The total (accumulated) number of GC runs +size_t scalanative_GC_stats_collection_total(); +// The total (accumulated) elapsed time in nanos of GC runs +size_t scalanative_GC_stats_collection_duration_total(); + // Functions used to create a new thread supporting multithreading support in // the garbage collector. Would execute a proxy startup routine to register // newly created thread upon startup and unregister it from the GC upon diff --git a/nativelib/src/main/resources/scala-native/gc/immix_commix/utils/Time.c b/nativelib/src/main/resources/scala-native/gc/shared/Time.c similarity index 96% rename from nativelib/src/main/resources/scala-native/gc/immix_commix/utils/Time.c rename to nativelib/src/main/resources/scala-native/gc/shared/Time.c index a7793783a5..8bf673c0f1 100644 --- a/nativelib/src/main/resources/scala-native/gc/immix_commix/utils/Time.c +++ b/nativelib/src/main/resources/scala-native/gc/shared/Time.c @@ -1,4 +1,5 @@ -#if defined(SCALANATIVE_GC_IMMIX) || defined(SCALANATIVE_GC_COMMIX) +#if defined(SCALANATIVE_GC_IMMIX) || defined(SCALANATIVE_GC_COMMIX) || \ + defined(SCALANATIVE_GC_BOEHM) #include "Time.h" #include @@ -97,4 +98,5 @@ long long Time_current_nanos() { return nano_time; } -#endif // defined(SCALANATIVE_GC_IMMIX) || defined(SCALANATIVE_GC_COMMIX) +#endif // defined(SCALANATIVE_GC_IMMIX) || defined(SCALANATIVE_GC_COMMIX) || + // defined(SCALANATIVE_GC_BOEHM) diff --git a/nativelib/src/main/resources/scala-native/gc/immix_commix/utils/Time.h b/nativelib/src/main/resources/scala-native/gc/shared/Time.h similarity index 100% rename from nativelib/src/main/resources/scala-native/gc/immix_commix/utils/Time.h rename to nativelib/src/main/resources/scala-native/gc/shared/Time.h diff --git a/nativelib/src/main/resources/scala-native/gc/shared/jmx.c b/nativelib/src/main/resources/scala-native/gc/shared/jmx.c new file mode 100644 index 0000000000..41c2785ab0 --- /dev/null +++ b/nativelib/src/main/resources/scala-native/gc/shared/jmx.c @@ -0,0 +1,24 @@ +#if defined(SCALANATIVE_GC_IMMIX) || defined(SCALANATIVE_GC_COMMIX) || \ + defined(SCALANATIVE_GC_BOEHM) + +#include + +// The total (accumulated) number of GC runs +static size_t GC_STATS_COLLECTION_TOTAL = 0L; + +// The total (accumulated) elapsed time in nanos of GC runs +static size_t GC_STATS_COLLECTION_DURATION_TOTAL = 0L; + +size_t jmx_stats_get_collection_total() { return GC_STATS_COLLECTION_TOTAL; } + +size_t jmx_stats_get_collection_duration_total() { + return GC_STATS_COLLECTION_DURATION_TOTAL; +} + +void jmx_stats_record_collection(size_t start_ns, size_t end_ns) { + GC_STATS_COLLECTION_TOTAL++; + GC_STATS_COLLECTION_DURATION_TOTAL += (end_ns - start_ns); +} + +#endif // defined(SCALANATIVE_GC_IMMIX) || defined(SCALANATIVE_GC_COMMIX) || + // defined(SCALANATIVE_GC_BOEHM) \ No newline at end of file diff --git a/nativelib/src/main/resources/scala-native/gc/shared/jmx.h b/nativelib/src/main/resources/scala-native/gc/shared/jmx.h new file mode 100644 index 0000000000..29575bb05a --- /dev/null +++ b/nativelib/src/main/resources/scala-native/gc/shared/jmx.h @@ -0,0 +1,10 @@ +#ifndef GC_JMX_H +#define GC_JMX_H + +#include + +size_t jmx_stats_get_collection_total(); +size_t jmx_stats_get_collection_duration_total(); +void jmx_stats_record_collection(size_t start_ns, size_t end_ns); + +#endif \ No newline at end of file diff --git a/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala b/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala index 45fd5a4cf7..c64b708e38 100644 --- a/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala +++ b/nativelib/src/main/scala/scala/scalanative/meta/LinktimeInfo.scala @@ -68,6 +68,11 @@ object LinktimeInfo { ) def runtimeVersion: String = resolved + @resolvedAtLinktime( + "scala.scalanative.meta.linktimeinfo.garbageCollector" + ) + def garbageCollector: String = resolved + object target { @resolvedAtLinktime("scala.scalanative.meta.linktimeinfo.target.arch") def arch: String = resolved diff --git a/nativelib/src/main/scala/scala/scalanative/runtime/GC.scala b/nativelib/src/main/scala/scala/scalanative/runtime/GC.scala index 695496ab76..3fbba65f48 100644 --- a/nativelib/src/main/scala/scala/scalanative/runtime/GC.scala +++ b/nativelib/src/main/scala/scala/scalanative/runtime/GC.scala @@ -43,6 +43,13 @@ object GC { @name("scalanative_GC_get_used_heapsize") def getUsedHeapSize(): CSize = extern + // The total (cumulative) number of GC runs + @name("scalanative_GC_stats_collection_total") + def getStatsCollectionTotal(): CSize = extern + // The total (cumulative) time in nanos spent on GC runs + @name("scalanative_GC_stats_collection_duration_total") + def getStatsCollectionDurationTotal(): CSize = extern + /* Multithreading awareness for GC Every implementation of GC supported in * ScalaNative needs to register a given thread The main thread is * automatically registered. Every additional thread needs to explicitly diff --git a/tools/src/main/scala/scala/scalanative/linker/LinktimeValueResolver.scala b/tools/src/main/scala/scala/scalanative/linker/LinktimeValueResolver.scala index 51f230a86f..16d461c6ad 100644 --- a/tools/src/main/scala/scala/scalanative/linker/LinktimeValueResolver.scala +++ b/tools/src/main/scala/scala/scalanative/linker/LinktimeValueResolver.scala @@ -34,6 +34,7 @@ private[linker] trait LinktimeValueResolver { self: Reach => s"$linktimeInfo.isMsys" -> Platform.isMsys, s"$linktimeInfo.isCygwin" -> Platform.isCygwin, s"$linktimeInfo.runtimeVersion" -> nir.Versions.current, + s"$linktimeInfo.garbageCollector" -> conf.gc.name, s"$linktimeInfo.target.arch" -> triple.arch, s"$linktimeInfo.target.vendor" -> triple.vendor, s"$linktimeInfo.target.os" -> triple.os, diff --git a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala index b7d78d66f4..517c27313f 100644 --- a/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala +++ b/unit-tests/shared/src/test/scala/org/scalanative/testsuite/javalib/lang/management/ManagementFactoryTest.scala @@ -75,4 +75,16 @@ class ManagementFactoryTest { assertTrue(bean.getSystemProperties().size() > 0) } + @Test def getGarbageCollectorMXBeans(): Unit = { + val beans = ManagementFactory.getGarbageCollectorMXBeans + + assert(beans.size() > 0) + } + + @Test def getMemoryManagerMXBeans(): Unit = { + val beans = ManagementFactory.getMemoryManagerMXBeans + + assert(beans.size() > 0) + } + } From dde22890036ee39ebd4353956b8b91fca85d3abb Mon Sep 17 00:00:00 2001 From: LeeTibbert Date: Wed, 9 Oct 2024 04:16:40 -0400 Subject: [PATCH 28/35] [Build]: Update sbt to 1.10.2 (#4070) * Improvement [Build]: Update sbt to 1.10.2 * Do not forget ScalaVersion.scala --- project/ScalaVersions.scala | 2 +- project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/ScalaVersions.scala b/project/ScalaVersions.scala index 1a30dc3489..274c01007c 100644 --- a/project/ScalaVersions.scala +++ b/project/ScalaVersions.scala @@ -59,7 +59,7 @@ object ScalaVersions { // 1.10.0 Latest sbt version. // 1.10.1 Latest sbt version. - val sbt10Version: String = "1.10.1" + val sbt10Version: String = "1.10.2" val sbt10ScalaVersion: String = scala212 val libCrossScalaVersions: Seq[String] = diff --git a/project/build.properties b/project/build.properties index 136f452e0d..23f7d97938 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version = 1.10.1 +sbt.version = 1.10.2 From aad8f0af0292bc794c71e10108a133b0568ff7bf Mon Sep 17 00:00:00 2001 From: LeeTibbert Date: Wed, 9 Oct 2024 04:17:32 -0400 Subject: [PATCH 29/35] Fix [javalib]: POSIX readAttributes() now links (#4069) * Fix [javalib]: POSIX readAttributes() now links --- .../attribute/PosixFileAttributeView.scala | 1 + .../PosixFileAttributeViewImpl.scala | 5 +- .../PosixFileAttributeViewTestOnJDK11.scala | 54 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 unit-tests/shared/src/test/require-jdk11/org/scalanative/testsuite/javalib/nio/file/attribute/PosixFileAttributeViewTestOnJDK11.scala diff --git a/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeView.scala b/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeView.scala index 86bd1bfc8a..049a3891d4 100644 --- a/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeView.scala +++ b/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeView.scala @@ -6,6 +6,7 @@ trait PosixFileAttributeView extends BasicFileAttributeView with FileOwnerAttributeView { def name(): String + def readAttributes(): PosixFileAttributes def setGroup(group: GroupPrincipal): Unit def setPermissions(perms: Set[PosixFilePermission]): Unit } diff --git a/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeViewImpl.scala b/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeViewImpl.scala index 307ea30260..daa414fc5f 100644 --- a/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeViewImpl.scala +++ b/javalib/src/main/scala/java/nio/file/attribute/PosixFileAttributeViewImpl.scala @@ -85,7 +85,10 @@ final class PosixFileAttributeViewImpl(path: Path, options: Array[LinkOption]) } } - override def readAttributes(): BasicFileAttributes = attributes +// override def readAttributes(): BasicFileAttributes = attributes +// override def readAttributes(): PosixFileAttributes = attributes + + def readAttributes(): PosixFileAttributes = attributes private class PosixFileKey(deviceId: stat.dev_t, inodeNumber: stat.ino_t) { diff --git a/unit-tests/shared/src/test/require-jdk11/org/scalanative/testsuite/javalib/nio/file/attribute/PosixFileAttributeViewTestOnJDK11.scala b/unit-tests/shared/src/test/require-jdk11/org/scalanative/testsuite/javalib/nio/file/attribute/PosixFileAttributeViewTestOnJDK11.scala new file mode 100644 index 0000000000..344d9537ca --- /dev/null +++ b/unit-tests/shared/src/test/require-jdk11/org/scalanative/testsuite/javalib/nio/file/attribute/PosixFileAttributeViewTestOnJDK11.scala @@ -0,0 +1,54 @@ +package org.scalanative.testsuite.javalib.nio.file.attribute + +import java.nio.file.Files +import java.nio.file.Path + +import java.nio.file.attribute.PosixFileAttributes +import java.nio.file.attribute.PosixFileAttributeView +import java.nio.file.attribute.PosixFilePermission + +import org.junit.Test +import org.junit.Assert._ +import org.junit.Assume._ +import org.junit.BeforeClass + +import org.scalanative.testsuite.utils.Platform + +/* The code under test should work on Java 8 through latest (currently 23). + * It is tested on JDK11 because that version introduces "Path.of()". + * In some later JVM versions, "Paths.get()" becomes deprecated. No sense + * writing new code which uses it. + */ + +object PosixFileAttributeViewTestOnJDK11 { + + @BeforeClass def posixOnly(): Unit = { + assumeTrue("Not implemented in Windows", !Platform.isWindows) + } +} + +class PosixFileAttributeViewTestOnJDK11 { + + // Issue 4067 + @Test def readPosixFileAttributes(): Unit = { + val path = Path.of(".") + + val posixAttrView = + Files.getFileAttributeView(path, classOf[PosixFileAttributeView]) + + val posixAttrs = posixAttrView.readAttributes() + + assertNotNull("unexpected Null POSIX file attributes", posixAttrs) + + // Permissions is a POSIX attribute; + val permissions = posixAttrs.permissions() + assertTrue("expected number of permissons > 0", permissions.size() > 0) + + // quick consistency check. + assertTrue( + "dot should have at least owner:read permission", + permissions.contains(PosixFilePermission.OWNER_READ) + ) + } + +} From 3c4bb57a3ccc785d53f7656ee140a0ac851c2f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Costa?= Date: Thu, 24 Oct 2024 09:40:42 +0100 Subject: [PATCH 30/35] [improve] ZLib error messages in the inflater (#4074) * Improve Inflater error messages * Extract zlib error message --- .../main/scala/java/util/zip/Inflater.scala | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/javalib/src/main/scala/java/util/zip/Inflater.scala b/javalib/src/main/scala/java/util/zip/Inflater.scala index 68fb629502..69b1e252e9 100644 --- a/javalib/src/main/scala/java/util/zip/Inflater.scala +++ b/javalib/src/main/scala/java/util/zip/Inflater.scala @@ -5,6 +5,7 @@ import scala.scalanative.unsafe._ import scala.scalanative.libc._ import scala.scalanative.ffi.zlib import scala.scalanative.ffi.zlibOps._ +import java.nio.charset.StandardCharsets // Ported from Apache Harmony @@ -179,7 +180,14 @@ class Inflater(noHeader: Boolean) { val totalOut = stream.totalOut (totalOut - sout).toInt } else { - throw new DataFormatException(err.toString) + throw new DataFormatException( + Inflater.zlibStatusToString( + err, + Option(stream.msg) + .map(cstr => fromCString(cstr, StandardCharsets.UTF_8)) + .filter(_.nonEmpty) + ) + ) } } else { val totalIn = stream.totalIn @@ -209,4 +217,24 @@ private object Inflater { } stream } + + private[Inflater] def zlibStatusToString( + status: Int, + msg: Option[String] + ): String = { + val errorName = + if (status == zlib.Z_OK) " (Z_OK)" + else if (status == zlib.Z_STREAM_END) " (Z_STREAM_END)" + else if (status == zlib.Z_NEED_DICT) " (Z_NEED_DICT)" + else if (status == zlib.Z_ERRNO) " (Z_ERRNO)" + else if (status == zlib.Z_STREAM_ERROR) " (Z_STREAM_ERROR)" + else if (status == zlib.Z_DATA_ERROR) " (Z_DATA_ERROR)" + else if (status == zlib.Z_MEM_ERROR) " (Z_MEM_ERROR)" + else if (status == zlib.Z_BUF_ERROR) " (Z_BUF_ERROR)" + else if (status == zlib.Z_VERSION_ERROR) " (Z_VERSION_ERROR)" + else "" + val fullMsg = msg.map(m => s" - $m").getOrElse("") + s"zlib status $status$errorName$fullMsg" + } + } From a9536c2e78ff605fb98048b35186544722782d16 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Tue, 12 Nov 2024 19:30:09 +0100 Subject: [PATCH 31/35] Nullify WeakReference.postGCHandler once it is used (#4080) --- javalib/src/main/scala/java/lang/ref/WeakReferenceRegistry.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/javalib/src/main/scala/java/lang/ref/WeakReferenceRegistry.scala b/javalib/src/main/scala/java/lang/ref/WeakReferenceRegistry.scala index 81b457aa1d..1aa2fbd07a 100644 --- a/javalib/src/main/scala/java/lang/ref/WeakReferenceRegistry.scala +++ b/javalib/src/main/scala/java/lang/ref/WeakReferenceRegistry.scala @@ -40,6 +40,7 @@ private[java] object WeakReferenceRegistry { current.enqueue() val handler = current.postGCHandler if (handler != null) { + current.postGCHandler = null try handler() catch { case NonFatal(err) => From 8af378fde64f5274a86facad1bdef3310f526a57 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Tue, 12 Nov 2024 22:12:14 +0100 Subject: [PATCH 32/35] Don't allow to define CFuncPtr lambda closing over `this` (#4079) * Don't allow to define CFuncPtr lambda closing over `this` * Don't use fewer-braces syntax to allow compilation on Scala 3.2- versions * Repalce `collectSubTree` not available in Scala 3.1 with `foreachSubTree` --- .../src/main/scala/java/lang/Runtime.scala | 12 ++++---- .../nscplugin/PrepNativeInterop.scala | 16 +++++++++++ .../scalanative/nscplugin/NirGenExpr.scala | 7 ++++- .../nscplugin/PostInlineNativeInterop.scala | 13 ++++++++- .../scala/scalanative/NIRCompilerTest.scala | 28 +++++++++++++++++++ 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/javalib/src/main/scala/java/lang/Runtime.scala b/javalib/src/main/scala/java/lang/Runtime.scala index d510001643..86d1969fc1 100644 --- a/javalib/src/main/scala/java/lang/Runtime.scala +++ b/javalib/src/main/scala/java/lang/Runtime.scala @@ -31,12 +31,6 @@ class Runtime private () { signal.signal(signal.SIGTERM, handleSignal(_)) } - private def handleSignal(sig: CInt): Unit = { - Proxy.disableGracefullShutdown() - Runtime.getRuntime().runHooks() - exit(128 + sig) - } - private def ensureCanModify(hook: Thread): Unit = if (shutdownStarted) { throw new IllegalStateException( s"Shutdown sequence started, cannot add/remove hook $hook" @@ -172,6 +166,12 @@ private object ShutdownHookUncaughtExceptionHandler object Runtime extends Runtime() { def getRuntime(): Runtime = this + private def handleSignal(sig: CInt): Unit = { + Proxy.disableGracefullShutdown() + Runtime.getRuntime().runHooks() + exit(128 + sig) + } + private implicit class ProcessBuilderOps(val pb: ProcessBuilder) extends AnyVal { def setEnv(envp: Array[String]): ProcessBuilder = { diff --git a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/PrepNativeInterop.scala b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/PrepNativeInterop.scala index 16dde82eb0..c7c44ffb81 100644 --- a/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/PrepNativeInterop.scala +++ b/nscplugin/src/main/scala-2/scala/scalanative/nscplugin/PrepNativeInterop.scala @@ -250,6 +250,22 @@ abstract class PrepNativeInterop[G <: Global with Singleton]( widenDealiasType(tree.tpe.finalResultType) tree.updateAttachment(NonErasedTypes(paramTypes)) + case Apply(fun, List(lambda)) + if CFuncPtrFromFunctionMethods.contains(fun.symbol) => + lambda + .collect { + case tree @ Select(This(_), _) + if !tree.symbol.owner.isStaticOwner => + tree + } + .foreach { selfRef => + reporter.error( + selfRef.pos, + s"CFuncPtr lambda can only refer to statically reachable symbols, but it's using ${show(selfRef.symbol)}" + ) + } + tree + case _ => super.transform(tree) } diff --git a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala index 56e9070652..4d683b65a2 100644 --- a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala +++ b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/NirGenExpr.scala @@ -2982,7 +2982,12 @@ trait NirGenExpr(using Context) { if (funSym.isStaticInNIR) buf.genApplyStaticMethod(funSym, NoSymbol, argsp) else - val owner = buf.genModule(funSym.owner) + val owner = + if funSym.owner.companionModule.exists then + buf.genModule(funSym.owner) + else + // Safe becouse usage of This is guarded in NativeInterop + nir.Val.Null val selfp = ValTree(funTree)(owner) buf.genApplyMethod(funSym, statically = true, selfp, argsp) diff --git a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/PostInlineNativeInterop.scala b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/PostInlineNativeInterop.scala index 8e9e4d9372..67f71287b2 100644 --- a/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/PostInlineNativeInterop.scala +++ b/nscplugin/src/main/scala-3/scala/scalanative/nscplugin/PostInlineNativeInterop.scala @@ -49,9 +49,20 @@ class PostInlineNativeInterop extends PluginPhase with NativeInteropUtil { // Attach exact type information to the AST to preserve the type information // during the type erase phase and refer to it in the NIR generation phase. tree match - case app @ Apply(TypeApply(fun, tArgs), _) + case app @ Apply(TypeApply(fun, tArgs), List(lambda)) if defnNir.CFuncPtr_fromScalaFunction.contains(fun.symbol) => val tys = tArgs.map(t => dealiasTypeMapper(t.tpe)) + lambda + .foreachSubTree { + case tree @ Select(This(_), _) + if !tree.symbol.owner.isStaticOwner => + report.error( + s"CFuncPtr lambda can only refer to statically reachable symbols, but it's using ${tree.symbol.showLocated}", + tree.srcPos + ) + case _ => () + } + app.withAttachment(NirDefinitions.NonErasedTypes, tys) case Apply(fun, args) if defnNir.CFuncPtr_apply.contains(fun.symbol) => diff --git a/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala b/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala index ffb3869fab..343794217c 100644 --- a/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala +++ b/nscplugin/src/test/scala/scala/scalanative/NIRCompilerTest.scala @@ -516,6 +516,34 @@ class NIRCompilerTest { ) } + @Test def cFuncPtrWithLocalState2(): Unit = { + val err = assertThrows( + classOf[CompilationFailedException], + () => NIRCompiler(_.compile(""" + |import scalanative.unsafe._ + | + |object Test { + | def main(args: Array[String]) = new Bug() + |} + |class Bug(){ + | def accessor: Int = data.## + | var data: Option[String] = None + | val nativeFunc = CFuncPtr1.fromScalaFunction{ + | (ptr: CString) => + | data = Some(fromCString(ptr)) + | println(s"native: $ptr - $accessor") + | } + |}""".stripMargin)) + ) + assertTrue( + err + .getMessage() + .contains( + "CFuncPtr lambda can only refer to statically reachable symbols, but it's using" + ) + ) + } + @Test def exportModuleMethod(): Unit = { try NIRCompiler( From bfe899a830e2078d798840fd2cc6a47060f081fe Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Wed, 13 Nov 2024 23:13:01 +0100 Subject: [PATCH 33/35] chore: Add Scala 3.6.1 support (#4081) * Add Scala 3.6.1 to cross cross versions as RC version. Adapt usages of syntax affected by Named Tuples * Fix linting * Keep using Scala 3.5 as default version --- javalib/src/main/scala/java/util/Spliterators.scala | 8 ++++---- project/ScalaVersions.scala | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/javalib/src/main/scala/java/util/Spliterators.scala b/javalib/src/main/scala/java/util/Spliterators.scala index cc5967e4b8..c8bc1b7106 100644 --- a/javalib/src/main/scala/java/util/Spliterators.scala +++ b/javalib/src/main/scala/java/util/Spliterators.scala @@ -364,7 +364,7 @@ object Spliterators { def hasNext(): Boolean = { if (cached.nonEmpty) true else { - spliterator.tryAdvance((e: Double) => (cached = Some(e))) + spliterator.tryAdvance { (e: Double) => cached = Some(e) } cached.nonEmpty } } @@ -391,7 +391,7 @@ object Spliterators { def hasNext(): Boolean = { if (cached.nonEmpty) true else { - spliterator.tryAdvance((e: Int) => (cached = Some(e))) + spliterator.tryAdvance { (e: Int) => cached = Some(e) } cached.nonEmpty } } @@ -418,7 +418,7 @@ object Spliterators { def hasNext(): Boolean = { if (cached.nonEmpty) true else { - spliterator.tryAdvance((e: Long) => (cached = Some(e))) + spliterator.tryAdvance { (e: Long) => cached = Some(e) } cached.nonEmpty } } @@ -445,7 +445,7 @@ object Spliterators { def hasNext(): Boolean = { if (cached.nonEmpty) true else { - spliterator.tryAdvance((e: T) => (cached = Some(e))) + spliterator.tryAdvance { (e: T) => cached = Some(e) } cached.nonEmpty } } diff --git a/project/ScalaVersions.scala b/project/ScalaVersions.scala index 274c01007c..77c1567a63 100644 --- a/project/ScalaVersions.scala +++ b/project/ScalaVersions.scala @@ -26,17 +26,19 @@ object ScalaVersions { // windowslib fails to compile with 3.1.{0-1} crossScalaVersions("3.1", 2 to 3), crossScalaVersions("3.2", 0 to 2), - crossScalaVersions("3.3", 0 to 4), + crossScalaVersions("3.3", 0 to 4), // LTS crossScalaVersions("3.4", 0 to 3), - crossScalaVersions("3.5", 0 to 1) + crossScalaVersions("3.5", 0 to 2), + crossScalaVersions("3.6", 1 to 1) // First official release would be 3.6.2 ).flatten.distinct // Tested in scheduled nightly CI to check compiler plugins // List maintains only upcoming releases, removed from the list after reaching stable status lazy val scala3RCVersions = List( - // 1.to(1).map(v => s"3.3.5-RC$v"), - 1.to(1).map(v => s"3.5.2-RC$v") - ).flatten + // Hack to make Scala 3.5 the default version until Scala 2.13.16 is relased. (required by scripted tests) + // Also 3.6.1 is treated as 3.6.0-RC1 becouse of broken release. Scala 3.6.2 would be the first official release + "3.6.1" + ) // Scala versions used for publishing libraries val scala212: String = crossScala212.last From 003f05e1c740d47cacb038184295add21f4777af Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Wed, 13 Nov 2024 14:01:59 +0100 Subject: [PATCH 34/35] Add changelog for 0.5.6 --- docs/changelog/0.5.x/0.5.6.md | 117 +++++++++++++++++++++++++++++++++ docs/changelog/0.5.x/index.rst | 1 + scripts/changelog.scala | 12 ++-- 3 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 docs/changelog/0.5.x/0.5.6.md diff --git a/docs/changelog/0.5.x/0.5.6.md b/docs/changelog/0.5.x/0.5.6.md new file mode 100644 index 0000000000..906fe616ca --- /dev/null +++ b/docs/changelog/0.5.x/0.5.6.md @@ -0,0 +1,117 @@ + +# 0.5.6 (2024-11-13) + +We're happy to announce the release of Scala Native 0.5.6! + + +## Supported Scala versions + + Scala Binary Version | Supported Scala Versions | + -------------------- | ------------------------ | + 2.12 | 2.12.14 ... 2.12.20 | + 2.13 | 2.13.8 ... 2.13.15 | + 3 | 3.1.2 ... 3.1.3
3.2.0 ... 3.2.2
3.3.0 ... 3.3.4
3.4.0 ... 3.4.3
3.5.2 ... 3.5.2 | + +> Upon release of new Scala version (stable, or Scala 3 RC) version dependent artifacts would be published without a new release. + + + + + + + + + + + + + + + + +
Commits since last release32
Merged PRs30
Contributors10
+ +## Contributors + +Big thanks to everybody who contributed to this release or reported an issue! + +``` +$ git shortlog -sn --no-merges v0.5.5..v0.5.6 + 15 Wojciech Mazur + 5 Maksym Ochenashko + 4 LeeTibbert + 3 João Costa + 2 Eric K Richardson + 1 Corey O'Connor + 1 Rikito Taniguchi + 1 dependabot[bot] + 1 unarist + 1 澪 +``` + +## Merged PRs + +## [0.5.6](https://github.com/scala-native/scala-native/tree/v0.5.6) (2024-11-13) + +[Full Changelog](https://github.com/scala-native/scala-native/compare/v0.5.5...v0.5.6) + +**Merged pull requests:** + +## Java Standard Library + +- feature [nativelib]: implement `ThreadMXBean` [#4031](https://github.com/scala-native/scala-native/pull/4031) ([iRevive](https://github.com/iRevive)) +- feature [nativelib]: partially implement `OperatingSystemMXBean` [#4033](https://github.com/scala-native/scala-native/pull/4033) ([iRevive](https://github.com/iRevive)) +- feature [nativelib]: partially implement `RuntimeMXBean` [#4034](https://github.com/scala-native/scala-native/pull/4034) ([iRevive](https://github.com/iRevive)) +- feature [nativelib]: partially implement `GarbageCollectorMXBean` [#4066](https://github.com/scala-native/scala-native/pull/4066) ([iRevive](https://github.com/iRevive)) +- feaure [javalib]: Port JSR-166 ConcurrentLinkedDeque to Scala Native [#4046](https://github.com/scala-native/scala-native/pull/4046) ([LeeTibbert](https://github.com/LeeTibbert)) +- Optimize Integer.toString [#4048](https://github.com/scala-native/scala-native/pull/4048) ([JD557](https://github.com/JD557)) +- Fix [javalib]: POSIX readAttributes() now links [#4069](https://github.com/scala-native/scala-native/pull/4069) ([LeeTibbert](https://github.com/LeeTibbert)) +- Improve ZLib error messages in the inflater [#4074](https://github.com/scala-native/scala-native/pull/4074) ([JD557](https://github.com/JD557)) +- Nullify WeakReference.postGCHandler once it is used [#4080](https://github.com/scala-native/scala-native/pull/4080) ([WojciechMazur](https://github.com/WojciechMazur)) + +## Scala Native Library + +- Fix `unsafe.toCWideString` was returning a double pointer to a string [#4029](https://github.com/scala-native/scala-native/pull/4029) ([unarist](https://github.com/unarist)) + +## Scala Native Runtime + +- fix [immix/commix/none gc]: Revert using free memory size instead of total memory size to control size of the heap [#4047](https://github.com/scala-native/scala-native/pull/4047) ([WojciechMazur](https://github.com/WojciechMazur)) +- [improve/build] Remove two FreeBSD 14.1 build defects [#4059](https://github.com/scala-native/scala-native/pull/4059) ([LeeTibbert](https://github.com/LeeTibbert)) + +## Scala Native Toolchain + +- Fix #4026 Fix negative byte to hex conversion in LLVM IR codegen [#4052](https://github.com/scala-native/scala-native/pull/4052) ([tanishiking](https://github.com/tanishiking)) +- [improve/nativelib] Better detection of `LinktimeInfo.isMac` [#4051](https://github.com/scala-native/scala-native/pull/4051) ([WojciechMazur](https://github.com/WojciechMazur)) +- Improve interflow inliner log messages [#4055](https://github.com/scala-native/scala-native/pull/4055) ([JD557](https://github.com/JD557)) +- [fix] Teach NIR subtyping to treat `scala.runtime.Nothing$` in the same way a `nir.Type.Nothing` [#4065](https://github.com/scala-native/scala-native/pull/4065) ([WojciechMazur](https://github.com/WojciechMazur)) + +## Scala Standard Library + +- [chore] Add Scala 2.12.20 to the build [#4043](https://github.com/scala-native/scala-native/pull/4043) ([WojciechMazur](https://github.com/WojciechMazur)) +- [chore] Add Scala 3.5.1 to the build. [#4054](https://github.com/scala-native/scala-native/pull/4054) ([WojciechMazur](https://github.com/WojciechMazur)) +- [chore] Add Scala 2.13.15 to the build [#4058](https://github.com/scala-native/scala-native/pull/4058) ([WojciechMazur](https://github.com/WojciechMazur)) +- [chore] Add Scala 3.3.4 to the build [#4062](https://github.com/scala-native/scala-native/pull/4062) ([WojciechMazur](https://github.com/WojciechMazur)) +- [chore] Add Scala 3.6.1 to the build. [#4081](https://github.com/scala-native/scala-native/pull/4081) ([WojciechMazur](https://github.com/WojciechMazur)) + +## POSIX bindings + +- Fix compilation error of _CS_PATH for Termux on Android [#4037](https://github.com/scala-native/scala-native/pull/4037) ([mio-19](https://github.com/mio-19)) + +## Windows API Bindings + +- feature [windowslib]: add `GetProcessTimes` to the `ProcessThreadsApi` [#4035](https://github.com/scala-native/scala-native/pull/4035) ([iRevive](https://github.com/iRevive)) + +## Documentations + +- Update source debug docs [#4041](https://github.com/scala-native/scala-native/pull/4041) ([ekrich](https://github.com/ekrich)) +- Update test source debug docs [#4063](https://github.com/scala-native/scala-native/pull/4063) ([ekrich](https://github.com/ekrich)) +- Add references to third party tools and libraries to docs [#4042](https://github.com/scala-native/scala-native/pull/4042) ([coreyoconnor](https://github.com/coreyoconnor)) + +## Scala Native Compiler Plugin + +- fix[compiler-plugin] Intrinisic ClassFieldRawPtr should always mangle symbol names when comparing symbols [#4045](https://github.com/scala-native/scala-native/pull/4045) ([WojciechMazur](https://github.com/WojciechMazur)) +- Don't allow to define CFuncPtr lambda closing over `this` [#4079](https://github.com/scala-native/scala-native/pull/4079) ([WojciechMazur](https://github.com/WojciechMazur)) + +## Scala Native sbt plugin + +- [fix/sbt-plugin] Always override default build target in Test scope to `application` [#4050](https://github.com/scala-native/scala-native/pull/4050) ([WojciechMazur](https://github.com/WojciechMazur)) diff --git a/docs/changelog/0.5.x/index.rst b/docs/changelog/0.5.x/index.rst index d19f2e7ee5..dc777b1579 100644 --- a/docs/changelog/0.5.x/index.rst +++ b/docs/changelog/0.5.x/index.rst @@ -6,6 +6,7 @@ .. toctree:: :maxdepth: 1 + 0.5.6 0.5.5 0.5.4 0.5.3 diff --git a/scripts/changelog.scala b/scripts/changelog.scala index 94e3bf68aa..8538d33c82 100644 --- a/scripts/changelog.scala +++ b/scripts/changelog.scala @@ -21,7 +21,7 @@ def main( ) = { val author = os.proc(List("git", "config", "user.name")).call().out.trim() val commits = os - .proc(List("git", "rev-list", s"${firstTag}..${lastTag}")) + .proc(List("git", "rev-list", s"${firstTag}...")) .call() .out .trim() @@ -30,7 +30,7 @@ def main( val contributors = os .proc( - List("git", "shortlog", "-sn", "--no-merges", s"${firstTag}..${lastTag}") + List("git", "shortlog", "-sn", "--no-merges", s"${firstTag}..") ) .call() .out @@ -41,7 +41,7 @@ def main( val command = List( "git", "log", - s"$firstTag..$lastTag", + s"$firstTag..", "--first-parent", "main", "--pretty=format:%H" @@ -120,9 +120,9 @@ def template( | | Scala Binary Version | Supported Scala Versions | | -------------------- | ------------------------ | - | 2.12 | 2.12.14 ... 2.12.19 | - | 2.13 | 2.13.8 ... 2.13.14 | - | 3 | 3.1.2 ... 3.1.3
3.2.0 ... 3.2.2
3.3.0 ... 3.3.3
3.4.0 ... 3.4.3
3.5.0 | + | 2.12 | 2.12.14 ... 2.12.20 | + | 2.13 | 2.13.8 ... 2.13.15 | + | 3 | 3.1.2 ... 3.1.3
3.2.0 ... 3.2.2
3.3.0 ... 3.3.4
3.4.0 ... 3.4.3
3.5.0 ... 3.5.2 | | |> Upon release of new Scala version (stable, or Scala 3 RC) version dependent artifacts would be published without a new release. | From 3f5eeda73b1e135cc340d3ca67dc04c732ca6cf4 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Wed, 13 Nov 2024 23:16:46 +0100 Subject: [PATCH 35/35] Release 0.5.6 --- docs/conf.py | 2 +- nir/src/main/scala/scala/scalanative/nir/Versions.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 07e732c4c9..6153315c0c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -71,7 +71,7 @@ def generateScalaNativeCurrentYear(): # The short X.Y version. version = u'0.5' # The full version, including alpha/beta/rc tags. -release = u'0.5.6-SNAPSHOT' +release = u'0.5.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/nir/src/main/scala/scala/scalanative/nir/Versions.scala b/nir/src/main/scala/scala/scalanative/nir/Versions.scala index 75cf769b60..f363202924 100644 --- a/nir/src/main/scala/scala/scalanative/nir/Versions.scala +++ b/nir/src/main/scala/scala/scalanative/nir/Versions.scala @@ -26,7 +26,7 @@ object Versions { case class Version(compat: Int, revision: Int) /* Current public release version of Scala Native. */ - final val current: String = "0.5.6-SNAPSHOT" + final val current: String = "0.5.6" final val currentBinaryVersion: String = binaryVersion(current) private object FullVersion {