ikvmnet / ikvm

A Java Virtual Machine and Bytecode-to-IL Converter for .NET
Other
1.24k stars 116 forks source link

Runtime does not initialize unless object is manually created. #423

Closed trungnt2910 closed 5 months ago

trungnt2910 commented 1 year ago

Suppose that I create a sample IKVM.NET.Sdk project using this Java class:

package sample;

public class Sample {
    public static void main(String... args) {
        System.out.println("Hello World");
    }
}

And, I reference this from a C# console application:

sample.Sample.main(args);

I would encounter an exception like this, when trying to access System.out:

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at sample.Sample.main(String[] args) in Sample.java:line 5
   at Program.<Main>$(String[] args) in Program.cs:line 1

A workaround is to create a dummy object before calling main():

// Use a Java Object to ensure the runtime has been initialized.
var obj = new java.lang.Object();

sample.Sample.main(args);
wasabii commented 1 year ago

So, this is a real problem I've been struggling with for quite awhile: finding the right place to initialize the BCL, without leaving something uncovered, and without causing a bootstrapping issue of some kind.

In real-Java, this is easy. It happens after the VM is initialized, before any user code is run, always, kicked off by java.exe. Since all initialization of the VM goes through this one entry point: java.exe.

But, not the case in IKVM, where people can write plain ol' .NET code, and then randomlly call into java classes without going through a centralized loader. Everything I've tried so far has ended up with some sort of bootstrapper issue. Such as a static getting initialized where it shouldn't, and that static needing other things to be initialized, which end up needing that very first static initialized.

trungnt2910 commented 1 year ago

Maybe making every Java class a child of java.lang.Object and then do something in the java.lang.Object static constructor may help?

Another potential solution is to have a module initializer in the IKVM dll, which is run when the IKVM dll is loaded.

wasabii commented 1 year ago

Module initializer causes an issue because of our cyclic dependency between runtime and Java. Runtime causes Java to be loaded before runtime is ready. This is at least fixable, as it's the current plan to remove the cycle. But not today.

Static ctor on object causes doesn't work because if you start the initialization on one objects static ctor, then it doesn't get called twice to initialize.

wasabii commented 9 months ago

This should be resolved in 8.7.4 which is inprogress.

sergey-tihon commented 6 months ago

Works for me with v8.7.5, thank you