Akka and Graal’s native image tool

EDIT: I missed this GitHub issue: https://github.com/akka/akka/issues/25090#issuecomment-402205809 - where there’s a workaround the Unsafe issue I ran into.

I played around with this a bit this evening, using a small ping/pong project and subclassing and overriding ActorSystemImpl#createDynamicAccess to statically instantiate everything needed by Akka, mailboxes, etc.

I then used the following command to create a native image with the necessary .conf files:

native-image '-H:IncludeResources=^([^.]+\.conf)$' -jar scala-2.12/akka-ping-pong-assembly-0.1.0-SNAPSHOT.jar

The strategy seems like it will work when dealing with the reflection-related issues, but then I hit the next roadblock which seems to be usage of Unsafe, note in particular the error from native-image below:

~/work/garbage/akka-ping-pong/target#master $ native-image '-H:IncludeResources=^([^.]+\.conf)$'   -jar scala-2.12/akka-ping-pong-assembly-0.1.0-SNAPSHOT.jar
Build on Server(pid: 633, port: 37253)
[akka-ping-pong-assembly-0.1.0-SNAPSHOT:633]    classlist:   3,489.71 ms
[akka-ping-pong-assembly-0.1.0-SNAPSHOT:633]        (cap):     577.37 ms
[akka-ping-pong-assembly-0.1.0-SNAPSHOT:633]        setup:     953.42 ms
Warning: RecomputeFieldValue.FieldOffset automatic substitution failed. The automatic substitution registration was attempted because a call to sun.misc.Unsafe.objectFieldOffset(Field) was detected in the static initializer of akka.actor.LightArrayRevolverScheduler$. Detailed failure reason(s): The field akka.actor.LightArrayRevolverScheduler$.akka$actor$LightArrayRevolverScheduler$$taskOffset, where the value produced by the field offset computation is stored, is not static.
[akka-ping-pong-assembly-0.1.0-SNAPSHOT:633]     analysis:   2,263.75 ms
error: Error encountered while parsing akka.actor.LightArrayRevolverScheduler$TaskHolder.extractTask(java.lang.Runnable) 
Parsing context:
	parsing akka.actor.LightArrayRevolverScheduler$TaskHolder.cancel(LightArrayRevolverScheduler.scala:339)
	parsing akka.actor.LightArrayRevolverScheduler.akka$actor$LightArrayRevolverScheduler$$schedule(LightArrayRevolverScheduler.scala:173)
	parsing akka.actor.LightArrayRevolverScheduler.scheduleOnce(LightArrayRevolverScheduler.scala:134)
	parsing akka.dispatch.MessageDispatcher.akka$dispatch$MessageDispatcher$$scheduleShutdownAction(AbstractDispatcher.scala:174)
	parsing akka.dispatch.MessageDispatcher$$anon$3.run(AbstractDispatcher.scala:224)
	parsing java.lang.Shutdown.runHooks(Shutdown.java:123)
	parsing java.lang.Shutdown.sequence(Shutdown.java:167)
	parsing java.lang.Shutdown.shutdown(Shutdown.java:234)
	parsing com.oracle.svm.core.jdk.RuntimeSupport.shutdown(RuntimeSupport.java:179)
	parsing com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:189)
	parsing com.oracle.svm.core.code.CEntryPointCallStubs.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)
Original error: com.oracle.svm.hosted.analysis.flow.SVMMethodTypeFlowBuilder$UnsafeOffsetError: Field AnalysisField<LightArrayRevolverScheduler$.akka$actor$LightArrayRevolverScheduler$$taskOffset accessed: false reads: true written: false> is used as an offset in an unsafe operation, but no value recomputation found. 
 Wrapped field: HotSpotField<akka.actor.LightArrayRevolverScheduler$.akka$actor$LightArrayRevolverScheduler$$taskOffset long:16>
	at com.oracle.svm.hosted.analysis.flow.SVMMethodTypeFlowBuilder$UnsafeOffsetError.report(SVMMethodTypeFlowBuilder.java:118)
	at com.oracle.svm.hosted.analysis.flow.SVMMethodTypeFlowBuilder.checkUnsafeOffset(SVMMethodTypeFlowBuilder.java:153)
	at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder$NodeIterator.node(MethodTypeFlowBuilder.java:1079)
	at org.graalvm.compiler.phases.graph.PostOrderNodeIterator.apply(PostOrderNodeIterator.java:106)
	at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:404)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:310)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:300)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:107)
	at com.oracle.graal.pointsto.flow.SpecialInvokeTypeFlow.onObservedUpdate(InvokeTypeFlow.java:421)
	at com.oracle.graal.pointsto.flow.TypeFlow.notifyObservers(TypeFlow.java:347)
	at com.oracle.graal.pointsto.flow.TypeFlow.update(TypeFlow.java:389)
	at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:508)
	at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:174)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Error: Processing image build request failed

Not sure about next steps, but just thought I’d further along the discussion. Here’s a link to the project if anyone’s interested: https://github.com/longshorej/garbage/tree/master/akka-ping-pong