Skip to content

Commit

Permalink
No build time init of classes used in UnsafeAccessedFieldBuildItem
Browse files Browse the repository at this point in the history
Use the Feature classloader instead of the default one to prevent
classes being loaded to register fields as unsafe accessed to end up
being build time initialized.

Similarly ensure that the registration is done after class
initialization configuration to prevent classes from being configured
for runtime initialization because of the unsafe access registration.
  • Loading branch information
zakkak committed Apr 2, 2024
1 parent 0f776ad commit d658f77
Showing 1 changed file with 29 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,28 +78,6 @@ public void write(String s, byte[] bytes) {
MethodCreator beforeAn = file.getMethodCreator("beforeAnalysis", "V", BEFORE_ANALYSIS_ACCESS);
TryBlock overallCatch = beforeAn.tryBlock();

ResultHandle beforeAnalysisParam = beforeAn.getMethodParam(0);

MethodCreator registerAsUnsafeAccessed = file
.getMethodCreator("registerAsUnsafeAccessed", void.class, Feature.BeforeAnalysisAccess.class)
.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
for (UnsafeAccessedFieldBuildItem unsafeAccessedField : unsafeAccessedFields) {
TryBlock tc = registerAsUnsafeAccessed.tryBlock();
ResultHandle declaringClassHandle = tc.invokeStaticMethod(
ofMethod(Class.class, "forName", Class.class, String.class),
tc.load(unsafeAccessedField.getDeclaringClass()));
ResultHandle fieldHandle = tc.invokeVirtualMethod(
ofMethod(Class.class, "getDeclaredField", Field.class, String.class), declaringClassHandle,
tc.load(unsafeAccessedField.getFieldName()));
tc.invokeInterfaceMethod(
ofMethod(Feature.BeforeAnalysisAccess.class, "registerAsUnsafeAccessed", void.class, Field.class),
registerAsUnsafeAccessed.getMethodParam(0), fieldHandle);
CatchBlockCreator cc = tc.addCatch(Throwable.class);
cc.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), cc.getCaughtException());
}
registerAsUnsafeAccessed.returnVoid();
overallCatch.invokeStaticMethod(registerAsUnsafeAccessed.getMethodDescriptor(), beforeAnalysisParam);

overallCatch.invokeStaticMethod(BUILD_TIME_INITIALIZATION,
overallCatch.marshalAsArray(String.class, overallCatch.load(""))); // empty string means initialize everything

Expand Down Expand Up @@ -179,6 +157,35 @@ public void write(String s, byte[] bytes) {
overallCatch.invokeStaticMethod(runtimeReinitializedClasses.getMethodDescriptor());
}

// Ensure registration of fields being accessed through unsafe is done last to ensure that the class
// initialization configuration is done first. Registering the fields before configuring class initialization
// may results in classes being marked for runtime initialization even if not explicitly requested.
if (!unsafeAccessedFields.isEmpty()) {
ResultHandle beforeAnalysisParam = beforeAn.getMethodParam(0);
MethodCreator registerAsUnsafeAccessed = file
.getMethodCreator("registerAsUnsafeAccessed", void.class, Feature.BeforeAnalysisAccess.class)
.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
ResultHandle thisClass = registerAsUnsafeAccessed.loadClassFromTCCL(GRAAL_FEATURE);
ResultHandle cl = registerAsUnsafeAccessed
.invokeVirtualMethod(ofMethod(Class.class, "getClassLoader", ClassLoader.class), thisClass);
for (UnsafeAccessedFieldBuildItem unsafeAccessedField : unsafeAccessedFields) {
TryBlock tc = registerAsUnsafeAccessed.tryBlock();
ResultHandle declaringClassHandle = tc.invokeStaticMethod(
ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
tc.load(unsafeAccessedField.getDeclaringClass()), tc.load(false), cl);
ResultHandle fieldHandle = tc.invokeVirtualMethod(
ofMethod(Class.class, "getDeclaredField", Field.class, String.class), declaringClassHandle,
tc.load(unsafeAccessedField.getFieldName()));
tc.invokeInterfaceMethod(
ofMethod(Feature.BeforeAnalysisAccess.class, "registerAsUnsafeAccessed", void.class, Field.class),
registerAsUnsafeAccessed.getMethodParam(0), fieldHandle);
CatchBlockCreator cc = tc.addCatch(Throwable.class);
cc.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), cc.getCaughtException());
}
registerAsUnsafeAccessed.returnVoid();
overallCatch.invokeStaticMethod(registerAsUnsafeAccessed.getMethodDescriptor(), beforeAnalysisParam);
}

CatchBlockCreator print = overallCatch.addCatch(Throwable.class);
print.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), print.getCaughtException());

Expand Down

0 comments on commit d658f77

Please sign in to comment.