Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ydoc native image #10783

Merged
merged 23 commits into from
Oct 31, 2024
Merged

Ydoc native image #10783

merged 23 commits into from
Oct 31, 2024

Conversation

4e6
Copy link
Contributor

@4e6 4e6 commented Aug 9, 2024

Pull Request Description

close #10757

Changelog:

  • add: native-image configuration to the ydoc-server project
  • add: native-image overrides for loom executors replacing them with platform threads
  • update: Helidon 4.1.2
  • fix: issues related to the native-image build

Important Notes

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.

@4e6 4e6 added the CI: No changelog needed Do not require a changelog entry for this PR. label Aug 9, 2024
@4e6 4e6 self-assigned this Aug 9, 2024
@hubertp hubertp added the CI: Clean build required CI runners will be cleaned before and after this PR is built. label Aug 9, 2024
@JaroslavTulach
Copy link
Member

JaroslavTulach commented Aug 12, 2024

I tried the latest version and I am getting:

enso$ ./ydoc 
07:40:29.848 [Ydoc executor thread] DEBUG org.enso.ydoc.polyfill.web.Util [text-decoder-decode, utf-8, ArrayBuffer{}, 0, 0]
07:40:29.872 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [new-web-socket-server, localhost, 1234, function bound() { [native code] }]
Exception in thread "main" java.util.concurrent.ExecutionException: org.graalvm.polyglot.PolyglotException: TypeError: execute on org.enso.ydoc.polyfill.web.WebSocket@77bbe348 failed due to: Message not supported.
        at [email protected]/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
        at [email protected]/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073)
        at org.enso.ydoc.Ydoc.start(Ydoc.java:147)
        at org.enso.ydoc.Main.main(Main.java:32)
Caused by: org.graalvm.polyglot.PolyglotException: TypeError: execute on org.enso.ydoc.polyfill.web.WebSocket@77bbe348 failed due to: Message not supported.
        at <js>.WebSocketServer(websocket.js:304)
        at <js>.:program(ydoc.cjs:23803)
        at org.graalvm.polyglot/org.graalvm.polyglot.Context.eval(Context.java:402)
        at org.enso.ydoc.Ydoc.lambda$start$0(Ydoc.java:142)
        at [email protected]/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)

I am not yet sure what's the cause of the error. The message probably comes from here and it is created with following back trace:

#0  com.oracle.truffle.api.interop.UnsupportedMessageException::UnsupportedMessageException() (this=0x7fffe9032fa0)
    at com/oracle/truffle/api/interop/UnsupportedMessageException.java:61
#1  com.oracle.truffle.api.interop.UnsupportedMessageException::create() () at com/oracle/truffle/api/interop/UnsupportedMessageException.java:84
#2  com.oracle.truffle.host.GuestToHostCodeCache$1::executeImpl(java.lang.Object*, java.lang.Object[]*) (this=<optimized out>, proxy=<optimized out>, 
    arguments=<optimized out>) at com/oracle/truffle/host/GuestToHostCodeCache.java:128
#3  0x000055555601fc76 in com.oracle.truffle.host.GuestToHostRootNode::execute(com.oracle.truffle.api.frame.VirtualFrame*) (this=<optimized out>, 
    frame=<optimized out>) at com/oracle/truffle/host/GuestToHostRootNode.java:80
#4  0x0000555557c3a0e2 in com.oracle.truffle.runtime.OptimizedCallTarget::executeRootNode(com.oracle.truffle.api.frame.VirtualFrame*, com.oracle.truffle.runtime.CompilationState*) (this=0x7fffe2323cc8, frame=0x7fffe915a628, tier=0x7ffff50513d0) at com/oracle/truffle/runtime/OptimizedCallTarget.java:745
#5  0x0000555557c3815f in com.oracle.truffle.runtime.OptimizedCallTarget::callInlined(com.oracle.truffle.api.nodes.Node*, java.lang.Object[]*) (
    this=<optimized out>, location=0x7fffe914bef8, arguments=<optimized out>) at com/oracle/truffle/runtime/OptimizedCallTarget.java:550
#6  0x0000555557c7a6d0 in com.oracle.truffle.runtime.OptimizedRuntimeSupport::callInlined(com.oracle.truffle.api.nodes.Node*, com.oracle.truffle.api.CallTarget*, java.lang.Object[]*) (this=<optimized out>, callNode=0x7fffe914bef8, target=<optimized out>, arguments=<optimized out>)
    at com/oracle/truffle/runtime/OptimizedRuntimeSupport.java:250
#7  0x000055555601ffcc in com.oracle.truffle.host.GuestToHostRootNode::guestToHostCall(com.oracle.truffle.api.nodes.Node*, com.oracle.truffle.api.CallTarget*, java.lang.Object[]*) (node=<optimized out>, target=<optimized out>, arguments=<optimized out>) at com/oracle/truffle/host/GuestToHostRootNode.java:102
#8  0x0000555556129cc5 in com.oracle.truffle.host.HostProxy::execute(java.lang.Object[]*, com.oracle.truffle.api.interop.InteropLibrary*, com.oracle.truffle.host.GuestToHostCodeCache*) (this=0x7ffff0857228, arguments=<optimized out>, library=0x7fffe914bef8, cache=<optimized out>)
    at com/oracle/truffle/host/HostProxy.java:139
#9  0x000055555613359f in com.oracle.truffle.host.HostProxyGen$InteropLibraryExports$Cached::executeNode_AndSpecialize(com.oracle.truffle.host.HostProxy*, java.lang.Object[]*) (this=<optimized out>, arg0Value=<optimized out>, arg1Value=<optimized out>) at com/oracle/truffle/host/HostProxyGen.java:401
#10 0x00005555561334a5 in com.oracle.truffle.host.HostProxyGen$InteropLibraryExports$Cached::execute(java.lang.Object*, java.lang.Object[]*) (
    this=<optimized out>, arg0Value_=<optimized out>, arg1Value=<optimized out>) at com/oracle/truffle/host/HostProxyGen.java:377
#11 0x0000555555e1d243 in com.oracle.truffle.api.interop.InteropLibraryGen$CachedDispatch::execute(java.lang.Object*, java.lang.Object[]*) (
    this=<optimized out>, receiver_=<optimized out>, arguments=<optimized out>) at com/oracle/truffle/api/interop/InteropLibraryGen.java:7952
#12 0x00005555571d178d in com.oracle.truffle.js.nodes.function.JSFunctionCallNode$ForeignExecuteNode::executeCall(java.lang.Object[]*) (
    this=0x7fffe914bd08, arguments=<optimized out>) at com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java:1539
#13 0x00005555571de05a in com.oracle.truffle.js.nodes.function.JSFunctionCallNode::executeAndSpecialize(java.lang.Object[]*) (this=<optimized out>, 

@JaroslavTulach
Copy link
Member

JaroslavTulach commented Aug 15, 2024

The UnsupportedMessageException is thrown because of another java.util.UnsupportedOperationException:


Thread 3 "executor thread" hit Breakpoint 1, java.lang.UnsupportedOperationException::UnsupportedOperationException(java.lang.String*) (this=<optimized out>, message=<optimized out>) at java/lang/UnsupportedOperationException.java:52
52              super(message);
(gdb) bt
#0  java.lang.UnsupportedOperationException::UnsupportedOperationException(java.lang.String*) (this=<optimized out>, message=<optimized out>)
    at java/lang/UnsupportedOperationException.java:52
#1  jdk.internal.misc.PreviewFeatures::ensureEnabled() () at jdk/internal/misc/PreviewFeatures.java:49
#2  java.lang.Thread::ofVirtual() () at com/oracle/svm/core/thread/Target_java_lang_Thread.java:680
#3  0x0000555558083585 in java.util.concurrent.Executors::newVirtualThreadPerTaskExecutor() () at java/util/concurrent/Executors.java:269
#4  io.helidon.webserver.LoomServer::LoomServer(io.helidon.webserver.WebServerConfig*) (this=0x7fffe9033430, serverConfig=0x7fffe9032fa0)
    at io/helidon/webserver/LoomServer.java:74
#5  0x0000555558099d05 in io.helidon.webserver.WebServer::create(io.helidon.webserver.WebServerConfig*) (serverConfig=<optimized out>)
    at io/helidon/webserver/WebServer.java:45
#6  io.helidon.webserver.WebServerConfig$Builder::build() (this=<optimized out>) at io/helidon/webserver/WebServerConfig.java:662
#7  0x0000555558955b6a in org.enso.ydoc.polyfill.web.WebSocket::execute(org.graalvm.polyglot.Value[]*) (this=<optimized out>, arguments=<optimized out>)
    at org/enso/ydoc/polyfill/web/WebSocket.java:153
#8  0x0000555558f144f3 in org.graalvm.polyglot.Engine$APIAccessImpl::callProxyExecutableExecute(java.lang.Object*, java.lang.Object[]*) (
    this=<optimized out>, proxy=<optimized out>, objects=<optimized out>) at org/graalvm/polyglot/Engine.java:1370
#9  0x000055555601817f in com.oracle.truffle.host.GuestToHostCodeCache$1::executeImpl(java.lang.Object*, java.lang.Object[]*) (this=<optimized out>, 
    proxy=<optimized out>, arguments=<optimized out>) at com/oracle/truffle/host/GuestToHostCodeCache.java:126
#10 0x000055555601fbc6 in com.oracle.truffle.host.GuestToHostRootNode::execute(com.oracle.truffle.api.frame.VirtualFrame*) (this=<optimized out>, 
    frame=<optimized out>) at com/oracle/truffle/host/GuestToHostRootNode.java:80
#11 0x0000555557c3a032 in com.oracle.truffle.runtime.OptimizedCallTarget::executeRootNode(com.oracle.truffle.api.frame.VirtualFrame*, com.oracle.truffle.runtime.CompilationState*) (this=0x7fffe2325178, frame=0x7fffe915b790, tier=0x7ffff5050bc8) at com/oracle/truffle/runtime/OptimizedCallTarget.java:745
#12 0x0000555557c380af in com.oracle.truffle.runtime.OptimizedCallTarget::callInlined(com.oracle.truffle.api.nodes.Node*, java.lang.Object[]*) (
    this=<optimized out>, location=0x7fffe914d180, arguments=<optimized out>) at com/oracle/truffle/runtime/OptimizedCallTarget.java:550
#13 0x0000555557c7a620 in com.oracle.truffle.runtime.OptimizedRuntimeSupport::callInlined(com.oracle.truffle.api.nodes.Node*, com.oracle.truffle.api.CallTarget*, java.lang.Object[]*) (this=<optimized out>, callNode=0x7fffe914d180, target=<optimized out>, arguments=<optimized out>)
    at com/oracle/truffle/runtime/OptimizedRuntimeSupport.java:250
#14 0x000055555601ff1c in com.oracle.truffle.host.GuestToHostRootNode::guestToHostCall(com.oracle.truffle.api.nodes.Node*, com.oracle.truffle.api.CallTarget*, java.lang.Object[]*) (node=<optimized out>, target=<optimized out>, arguments=<optimized out>) at com/oracle/truffle/host/GuestToHostRootNode.java:102
#15 0x0000555556129c15 in com.oracle.truffle.host.HostProxy::execute(java.lang.Object[]*, com.oracle.truffle.api.interop.InteropLibrary*, com.oracle.truffle.host.GuestToHostCodeCache*) (this=0x7ffff0857310, arguments=<optimized out>, library=0x7fffe914d180, cache=<optimized out>)
    at com/oracle/truffle/host/HostProxy.java:139
#16 0x00005555561334ef in com.oracle.truffle.host.HostProxyGen$InteropLibraryExports$Cached::executeNode_AndSpecialize(com.oracle.truffle.host.HostProxy*, j--Type <RET> for more, q to quit, c to continue without paging--
ava.lang.Object[]*) (this=<optimized out>, arg0Value=<optimized out>, arg1Value=<optimized out>) at com/oracle/truffle/host/HostProxyGen.java:401
#17 0x00005555561333f5 in com.oracle.truffle.host.HostProxyGen$InteropLibraryExports$Cached::execute(java.lang.Object*, java.lang.Object[]*) (
    this=<optimized out>, arg0Value_=<optimized out>, arg1Value=<optimized out>) at com/oracle/truffle/host/HostProxyGen.java:377
#18 0x0000555555e1d193 in com.oracle.truffle.api.interop.InteropLibraryGen$CachedDispatch::execute(java.lang.Object*, java.lang.Object[]*) (
    this=<optimized out>, receiver_=<optimized out>, arguments=<optimized out>) at com/oracle/truffle/api/interop/InteropLibraryGen.java:7952
#19 0x00005555571d16dd in com.oracle.truffle.js.nodes.function.JSFunctionCallNode$ForeignExecuteNode::executeCall(java.lang.Object[]*) (
    this=0x7fffe914cf90, arguments=<optimized out>) at com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java:1539
#20 0x00005555571ddfaa in com.oracle.truffle.js.nodes.function.JSFunctionCallNode::executeAndSpecialize(java.lang.Object[]*) (this=<optimized out>, 

@JaroslavTulach
Copy link
Member

JaroslavTulach commented Aug 15, 2024

There is a related discussion at GraalVM Slack. But anyway we might try latest Community GraalVM builds to be sure that the problem will get fixed in the next release of GraalVM. With following changes:

diff --git build.sbt build.sbt
index 5d5fa8d769..bd080321d8 100644
--- build.sbt
+++ build.sbt
@@ -1418,6 +1418,15 @@ lazy val `ydoc-server` = project
         includeRuntime = false,
         mainClass      = Some("org.enso.ydoc.Main"),
         additionalOptions = Seq(
+          // "fixes" the problem with:
+          //   Error: Polyglot version compatibility check failed.
+          //   Your Java runtime '24+10-jvmci-b01' with native-image feature version '24.2.0' is incompatible with polyglot version '24.0.0'.
+          //   Update the org.graalvm.polyglot versions to at least '24.2.0' to resolve this.
+          //   To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used.
+          //   It is not recommended to disable version checks.
+          // switching to 24.2.0 Truffle APIs isn't really possible, as they are not available on Maven central yet
+          // and I don't know where they are...
+          "-Dpolyglotimpl.DisableVersionChecks=true",
:...skipping...
diff --git build.sbt build.sbt
index 5d5fa8d769..bd080321d8 100644
--- build.sbt
+++ build.sbt
@@ -1418,6 +1418,15 @@ lazy val `ydoc-server` = project
         includeRuntime = false,
         mainClass      = Some("org.enso.ydoc.Main"),
         additionalOptions = Seq(
+          // "fixes" the problem with:
+          //   Error: Polyglot version compatibility check failed.
+          //   Your Java runtime '24+10-jvmci-b01' with native-image feature version '24.2.0' is incompatible with polyglot version '24.0.0'.
+          //   Update the org.graalvm.polyglot versions to at least '24.2.0' to resolve this.
+          //   To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used.
+          //   It is not recommended to disable version checks.
+          // switching to 24.2.0 Truffle APIs isn't really possible, as they are not available on Maven central yet
+          // and I don't know where they are...
+          "-Dpolyglotimpl.DisableVersionChecks=true",
           // useful perf & debug switches:
           // "-g",
           // "-H:+SourceLevelDebug",
diff --git project/FrgaalJavaCompiler.scala project/FrgaalJavaCompiler.scala
index 1e10363d2f..f73c31e2c8 100644
--- project/FrgaalJavaCompiler.scala
+++ project/FrgaalJavaCompiler.scala
@@ -224,7 +224,7 @@ object FrgaalJavaCompiler {
       val limitModules = Seq(
         "java.base",
         "jdk.zipfs",
-        "jdk.internal.vm.compiler.management",
+        "jdk.graal.compiler.management",
         "java.desktop",
         "java.net.http",
         "java.sql",
diff --git project/GraalVM.scala project/GraalVM.scala
index b6e1957f48..93604522ff 100644
--- project/GraalVM.scala
+++ project/GraalVM.scala
@@ -155,7 +155,7 @@ object GraalVM {
         s"Running on Java version $javaSpecVersion. " +
         s"Expected Java version $javaVersion."
       )
-      return oldState.fail
+      return oldState
     }

and build that identifies itself as

./graalvm-community-openjdk-24+10.1/bin/java --version
openjdk 24 2025-03-18
OpenJDK Runtime Environment GraalVM CE 24-dev+10.1 (build 24+10-jvmci-b01)
OpenJDK 64-Bit Server VM GraalVM CE 24-dev+10.1 (build 24+10-jvmci-b01, mixed mode, sharing)

I managed to successfully finish sbt --java-home ./graalvm-community-openjdk-24+10.1/ ydoc-server/buildNativeImage and then execute ./ydoc:

$ ./ydoc
07:30:44.641 [Ydoc executor thread] DEBUG org.enso.ydoc.polyfill.web.Util [text-decoder-decode, utf-8, ArrayBuffer{}, 0, 0]
07:30:44.665 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [new-web-socket-server, localhost, 1234, function bound() { [native code] }]
07:30:44.668 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [web-socket-server-start, io.helidon.webserver.LoomServer]
Aug 16, 2024 7:30:44 AM io.helidon.common.features.HelidonFeatures features
INFO: Helidon SE 4.0.8 features: [Config, Encoding, Media, WebClient, WebServer, WebSocket]
Aug 16, 2024 7:30:44 AM io.helidon.webserver.ServerListener start
INFO: [0x33253193] http://127.0.0.1:1234 bound for socket '@default'
Aug 16, 2024 7:30:44 AM io.helidon.webserver.LoomServer startIt
INFO: Started all channels in 1 milliseconds. 235 milliseconds since JVM startup. Java 24+10-jvmci-b01

Starts in 235ms.

@JaroslavTulach
Copy link
Member

JaroslavTulach commented Aug 16, 2024

@chumer wrote on:

switching to 24.2.0 Truffle APIs isn't really possible, as they are not available on Maven central yet
and I don't know where they are...
"-Dpolyglotimpl.DisableVersionChecks=true",

At https://github.com/graalvm/graalvm-ce-dev-builds/releases look for maven-resource-bundle-community-dev.tar.gz
Unpack and use like this:
https://github.com/graalvm/polyglot-embedding-demo/blob/main/pom.xml#L14

@JaroslavTulach
Copy link
Member

JaroslavTulach commented Aug 17, 2024

According to @eregon this is the fix that should be backported into GraalVM based on JDK21 to make use of Helidon+Graal.js possible.

as oracle/graal#9516 demonstrates - Benoit was correct. ./ydoc binary is properly running with own "9516" JDK

enso$ sbt --java-home /graal/sdk/mxbuild/linux-amd64/GRAALVM_350A482ABE_JAVA21/graalvm-350a482abe-java21-23.1.3 ydoc-server/buildNativeImage
enso$ ./ydoc 
16:40:34.942 [Ydoc executor thread] DEBUG org.enso.ydoc.polyfill.web.Util [text-decoder-decode, utf-8, ArrayBuffer{}, 0, 0]
16:40:34.962 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [new-web-socket-server, localhost, 1234, function bound() { [native code] }]
16:40:34.964 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [web-socket-server-start, io.helidon.webserver.LoomServer]
Aug 17, 2024 4:40:34 PM io.helidon.common.features.HelidonFeatures features
INFO: Helidon SE 4.0.8 features: [Config, Encoding, Media, WebClient, WebServer, WebSocket]
Aug 17, 2024 4:40:34 PM io.helidon.webserver.ServerListener start
INFO: [0x33ce2dce] http://127.0.0.1:1234 bound for socket '@default'
Aug 17, 2024 4:40:34 PM io.helidon.webserver.LoomServer startIt
INFO: Started all channels in 1 milliseconds. 213 milliseconds since JVM startup. Java 21.0.2+13-jvmci-23.1-b33

e.g. we can stay on JDK21 if the PR gets backported or if we build our own patched JDK.

@JaroslavTulach
Copy link
Member

JaroslavTulach commented Aug 18, 2024

As an alternative immediate workaround @chumer proposes to use older version of Helidon that doesn't require virtual threads. Probably Helidon 3 would do and the APIs might be similar...

Meanwhile an official request in My Oracle Support has been created:

My Oracle Support request

@enso-bot enso-bot bot mentioned this pull request Sep 20, 2024
2 tasks
@JaroslavTulach
Copy link
Member

JaroslavTulach commented Oct 7, 2024

With ee82801 we start in 197ms:

enso$ ./ydoc 
08:51:55.382 [Ydoc executor thread] DEBUG org.enso.ydoc.polyfill.web.Util [text-decoder-decode, utf-8, ArrayBuffer{}, 0, 0]
08:51:55.404 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [new-web-socket-server, localhost, 1234, function bound() { [native code] }]
08:51:55.406 [Ydoc executor thread] DEBUG o.enso.ydoc.polyfill.web.WebSocket [web-socket-server-start, io.helidon.webserver.LoomServer]
Oct 07, 2024 8:51:55 AM io.helidon.common.features.HelidonFeatures features
INFO: Helidon SE 4.1.2 features: [Config, Encoding, Media, WebClient, WebServer, WebSocket]
Oct 07, 2024 8:51:55 AM io.helidon.webserver.ServerListener start
INFO: [0x39561864] http://127.0.0.1:1234 bound for socket '@default'
Oct 07, 2024 8:51:55 AM io.helidon.webserver.LoomServer startIt
INFO: Started all channels in 1 milliseconds. 197 milliseconds since JVM startup. Java 21.0.2+13-jvmci-23.1-b30

@4e6 4e6 marked this pull request as ready for review October 30, 2024 16:33
Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look OK, but how are we doing to test that it all works?

@JaroslavTulach
Copy link
Member

How long it takes to initialize the Y.doc server with native image build? What are the steps to reproduce such measurement? E.g. how do we measure the initliazation of the Y.doc server?

@4e6
Copy link
Contributor Author

4e6 commented Oct 31, 2024

It starts in ~250ms on my machine

INFO: Started all channels in 1 milliseconds. 262 milliseconds since JVM startup. Java 21.0.2+13-jvmci-23.1-b30

I will create a followup PR that will replace nodejs version in the Docker container. Or maybe we can start with bundling it in the GUI package. Again instead of the nodejs version.

@4e6 4e6 added the CI: Ready to merge This PR is eligible for automatic merge label Oct 31, 2024
@mergify mergify bot merged commit 5f52547 into develop Oct 31, 2024
41 of 42 checks passed
@mergify mergify bot deleted the wip/db/10757-ydoc-native-image branch October 31, 2024 19:57
MrFlashAccount pushed a commit that referenced this pull request Nov 1, 2024
close #10757

Changelog:
- add: native-image configuration to the `ydoc-server` project
- add: native-image overrides for loom executors replacing them with platform threads
- update: Helidon `4.1.2`
- fix: issues related to the native-image build
mergify bot pushed a commit that referenced this pull request Nov 5, 2024
#10783 introduced another definition of a buildnativeimage task. Since that time, our CI is transiently failing on out of memory error. This PR ensures that there can be just a single `buildNativeImage` task running at a time.

# Important Notes
Manually tested by running
```
sbt:enso> all engine-runner/buildNativeImage project-manager/buildNativeImage
```
And looking at spawn subprocesses. On develop, I have two `native-image` processes, on this PR, there is just a single one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Clean build required CI runners will be cleaned before and after this PR is built. CI: No changelog needed Do not require a changelog entry for this PR. CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create a native-image from (GraalVM) ydoc implementation
4 participants