-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Lazily recompute Inet4Address, Inet6Address and CidrAddress fields at runtime #5353
Conversation
For info, PR #5336 contains the same fix and more I guess. |
Thanks for pointing this out @machi1990, I'll take a look at #5336. |
So, it seems @galderz started testing GraalVM 19.3.0 with JDK 11 and faced an issue that is being fixed in #5336. This PR is only about applying patches suggested by @cstancu and see if the current Quarkus Now, I don't know if this PR should be merged or closed as a duplicate of #5336. |
I think we should include all the changes required by @cstansu ASAP. But IIRC there were more suggestions than that in the original issue ? |
@gsmet Yes, there are other suggestions, some are breaking changes (see #5358) and I still have to test others. I submitted this PR because of @cstancu's comment. |
f301b62
to
4107b19
Compare
I added the command-line option suggested by @cstancu as it did not cause any issue locally. Let's see if CI is happy with it. |
core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
Outdated
Show resolved
Hide resolved
I may have to retract the |
Here's the GraalVM error:
If I understand the GraalVM classes initialization logic correctly, there's a conflict between the Even if the error message is not mentioning it, I suspected I'm pretty new to this subject so I might miss something obvious to solve this issue. Is there a way to initialize cc @dmlloyd |
It should be fine to use a class at build time, even though we request it to be initialized at runtime - as long as we don't keep references to such instances around. The error message seems to say something different; are you sure we don't have another feature / BuildItem somewhere which is requesting a different option for the same class? |
I also suspected this, but I didn't find anything. I'll take another look :) |
BTW I don't think the issue relates with when the class is initialized, it's probably about it keeping an instance in the heap. The solution likely requires to defer the conversion from String to address objects, so to not have any such object in the heap yet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initializing Inet
during run time will cause some problems in the not-too-distant future.
I don't think it is a requirement. I didn't find any comments justifying it at any rate. |
@cstancu wrote:
You can find the original ZulipChat conversation here. |
OK the correct fix here would be to recompute the field values rather than initialize at run time. The fields in question are: public final class Inet {
// ...
public static final Inet4Address INET4_ANY = getInet4Address(0, 0, 0, 0);
// ...
public static final Inet4Address INET4_LOOPBACK = getInet4Address(127, 0, 0, 1);
// ...
public static final Inet4Address INET4_BROADCAST = getInet4Address(255, 255, 255, 255);
// ...
public static final Inet6Address INET6_ANY = getInet6Address(0, 0, 0, 0, 0, 0, 0, 0);
// ...
public static final Inet6Address INET6_LOOPBACK = getInet6Address(0, 0, 0, 0, 0, 0, 0, 1); They can each be recomputed using the |
Thanks for the pointers! I'll remove the runtime initialization and see if I can get the field recomputation to work. |
4107b19
to
e4aa525
Compare
I pushed some changes yesterday which didn't break the Quarkus |
e4aa525
to
3746489
Compare
Yes, I mean those objects being reachable from a static field and thus being serialized in the native image heap. If possible I would recommend splitting the original class and extracting the part that needs to be recomputed to another class but being from wildfly that may not be possible. Alternatively, you can use |
You mean, extract it for the purpose of marking the extracted class as runtime-initialized? Or are you saying that analysis treats class boundaries specially?
Thanks for the info. How would |
Yes.
Recomputation via |
Thanks for your answers @cstancu! I just ran a quick test and it seems |
Uh oh. This means that we have some code making some majorly wrong assumptions. Unfortunately the documentation of |
3746489
to
213186b
Compare
I'm pushing an updated version of the PR to see if the Quarkus CI is happy with it, but I'll do another round of tests tomorrow. |
try { | ||
Constructor<CidrAddress> ctor = CidrAddress.class.getDeclaredConstructor(InetAddress.class, int.class); | ||
ctor.setAccessible(true); | ||
result = ctor.newInstance(Inet.INET6_ANY, 0); | ||
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | ||
| IllegalArgumentException | InvocationTargetException e) { | ||
throw new RuntimeException("CidrAddress instanciation failed", e); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dmlloyd Is this acceptable? The CidrAddress
constructor is private
so I need a way to access it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use an alias for the constructor instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried the alias way last night and it didn't work, but it was super late for me so I didn't really try to analyze the reason and decided to test this alternative that I knew would work. I'll replace this with an alias again tonight and see if I can make it work. Thanks.
e558604
to
93a2acc
Compare
public static Inet6Address INET6_LOOPBACK; | ||
} | ||
|
||
class Inet4AnyAccessor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these accessors could be substantially simplified by introducing a new class, which is a run-time initialized class that includes the fields like this:
static final class Inet_RunTime {
public static final Inet4Address INET4_ANY = Inet.getInet4Address(0, 0, 0, 0);
public static final Inet4Address INET4_LOOPBACK = Inet.getInet4Address(127, 0, 0, 1);
public static final Inet4Address INET4_BROADCAST = Inet.getInet4Address(255, 255, 255, 255);
public static final Inet6Address INET6_ANY = Inet.getInet6Address(0, 0, 0, 0, 0, 0, 0, 0);
public static final Inet6Address INET6_LOOPBACK = Inet.getInet6Address(0, 0, 0, 0, 0, 0, 0, 1);
}
Then each accessor only has to look like this (for example):
static Inet4Address get() {
return Inet_RunTime.INET4_LOOPBACK;
}
and that would allow the accessor to be inlined, effectively performing a safe(r) partial class reinitialization at run time of that class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplifying the code is exactly what I was thinking about now that the reflection code is gone :) I'll try your suggestion right away, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems GraalVM doesn't like this:
static final class Inet_RunTime {
public static final Inet4Address INET4_ANY = Inet.getInet4Address(0, 0, 0, 0);
public static final Inet4Address INET4_LOOPBACK = Inet.getInet4Address(127, 0, 0, 1);
public static final Inet4Address INET4_BROADCAST = Inet.getInet4Address(255, 255, 255, 255);
public static final Inet6Address INET6_ANY = Inet.getInet6Address(0, 0, 0, 0, 0, 0, 0, 0);
public static final Inet6Address INET6_LOOPBACK = Inet.getInet6Address(0, 0, 0, 0, 0, 0, 0, 1);
}
It is causing many errors locally including:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of java.net.Inet4Address are allowed in the image heap as this class should be initialized at image runtime. Object has been initialized without the native-image initialization instrumentation and the stack trace can't be tracked.
Trace:
at parsing io.quarkus.runtime.graal.Inet4AnyAccessor.get(InetSubstitutions.java:51)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait, I didn't do anything about initializing the class at runtime. Trying again...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion applied and working.
93a2acc
to
e2c6932
Compare
@dmlloyd Would you please review this PR again? Everything's working fine locally so I think it's ready to be merged into |
Sure, seems better. @gsmet ? |
Gwenneg has tested and validated the changes.
I dismissed my review. Looks like we just have to wait for CI? Adding the tag. |
Thanks you all for your help with this one! |
This PR is related to #4218
It can be merged into master before GraalVM 19.3.0 is available.