Skip to content

Commit

Permalink
Move native Resource configuration from Feature to json
Browse files Browse the repository at this point in the history
Follow up to #29886
  • Loading branch information
zakkak committed Feb 20, 2023
1 parent 7abe8ae commit b7f49dd
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 303 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* Globs passed to the {@code includeGlob*()} methods of the {@link Builder} are transformed to regular expressions
* internally. See {@link NativeConfig.ResourcesConfig#includes} for the supported glob syntax.
* <p>
* The patterns are passed to the native image builder using the {@code com.oracle.svm.hosted.ResourcesFeature} API.
* The patterns are passed to the native image builder using {@code resource-config.json}.
* The same mechanism (and regular expression syntax) is used by {@code native-image}'s
* {@code -H:ResourceConfigurationFiles}, {@code -H:IncludeResources} and {@code -H:ExcludeResources} (since
* GraalVM 20.3.0) command line options.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import io.quarkus.maven.dependency.ResolvedDependency;
import io.quarkus.runtime.LocalesBuildTimeConfig;
import io.quarkus.runtime.graal.DisableLoggingFeature;
import io.quarkus.runtime.graal.ResourcesFeature;

public class NativeImageBuildStep {

Expand Down Expand Up @@ -80,16 +79,9 @@ public class NativeImageBuildStep {
private static final String MOVED_TRUST_STORE_NAME = "trustStore";
public static final String APP_SOURCES = "app-sources";

@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
void addExportsToNativeImage(BuildProducer<JPMSExportBuildItem> exports) {
// Needed by io.quarkus.runtime.ResourceHelper.registerResources
exports.produce(new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.jdk"));
}

@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
void nativeImageFeatures(BuildProducer<NativeImageFeatureBuildItem> features) {
features.produce(new NativeImageFeatureBuildItem(NativeImageFeatureStep.GRAAL_FEATURE));
features.produce(new NativeImageFeatureBuildItem(ResourcesFeature.class));
features.produce(new NativeImageFeatureBuildItem(DisableLoggingFeature.class));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,32 @@
import static io.quarkus.gizmo.MethodDescriptor.ofMethod;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.util.List;

import org.graalvm.home.Version;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.GeneratedNativeImageClassBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.JPMSExportBuildItem;
import io.quarkus.deployment.builditem.nativeimage.JniRuntimeAccessBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedPackageBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.UnsafeAccessedFieldBuildItem;
import io.quarkus.deployment.pkg.steps.GraalVM;
import io.quarkus.gizmo.AssignableResultHandle;
import io.quarkus.gizmo.BranchResult;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.CatchBlockCreator;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.gizmo.TryBlock;
import io.quarkus.runtime.NativeImageFeatureUtils;
import io.quarkus.runtime.ResourceHelper;
import io.quarkus.runtime.graal.ResourcesFeature;

public class NativeImageFeatureStep {

public static final String GRAAL_FEATURE = "io.quarkus.runner.Feature";
private static final MethodDescriptor VERSION_CURRENT = ofMethod(Version.class, "getCurrent", Version.class);
private static final MethodDescriptor VERSION_COMPARE_TO = ofMethod(Version.class, "compareTo", int.class, int[].class);

private static final MethodDescriptor IMAGE_SINGLETONS_LOOKUP = ofMethod(ImageSingletons.class, "lookup", Object.class,
Class.class);
Expand All @@ -61,51 +43,12 @@ public class NativeImageFeatureStep {
RUNTIME_CLASS_INITIALIZATION_SUPPORT,
"rerunInitialization", void.class, Class.class, String.class);

public static final String CONFIGURATION_CONDITION = "org.graalvm.nativeimage.impl.ConfigurationCondition";
private static final MethodDescriptor CONFIGURATION_ALWAYS_TRUE = ofMethod(
CONFIGURATION_CONDITION,
"alwaysTrue", CONFIGURATION_CONDITION);

private static final MethodDescriptor LOOKUP_METHOD = ofMethod(
NativeImageFeatureUtils.class,
"lookupMethod", Method.class, Class.class, String.class, Class[].class);

private static final MethodDescriptor FIND_MODULE_METHOD = ofMethod(
NativeImageFeatureUtils.class,
"findModule", Module.class, String.class);
private static final MethodDescriptor INVOKE = ofMethod(
Method.class, "invoke", Object.class, Object.class, Object[].class);
static final String BEFORE_ANALYSIS_ACCESS = Feature.BeforeAnalysisAccess.class.getName();
static final String LOCALIZATION_FEATURE = "com.oracle.svm.core.jdk.localization.LocalizationFeature";
static final String RUNTIME_RESOURCE_SUPPORT = "org.graalvm.nativeimage.impl.RuntimeResourceSupport";

@BuildStep
GeneratedResourceBuildItem generateNativeResourcesList(List<NativeImageResourceBuildItem> resources,
BuildProducer<NativeImageResourcePatternsBuildItem> resourcePatternsBuildItemBuildProducer) {
StringBuilder sb = new StringBuilder();
for (NativeImageResourceBuildItem i : resources) {
for (String r : i.getResources()) {
sb.append(r);
sb.append("\n");
}
}
//we don't want this file in the final image
resourcePatternsBuildItemBuildProducer.produce(NativeImageResourcePatternsBuildItem.builder()
.excludePattern(ResourcesFeature.META_INF_QUARKUS_NATIVE_RESOURCES_TXT).build());
return new GeneratedResourceBuildItem(ResourcesFeature.META_INF_QUARKUS_NATIVE_RESOURCES_TXT,
sb.toString().getBytes(StandardCharsets.UTF_8));
}

@BuildStep
void addExportsToNativeImage(BuildProducer<JPMSExportBuildItem> features,
List<JniRuntimeAccessBuildItem> jniRuntimeAccessibleClasses) {
// required in order to access org.graalvm.nativeimage.impl.RuntimeSerializationSupport and org.graalvm.nativeimage.impl.ConfigurationCondition
void addExportsToNativeImage(BuildProducer<JPMSExportBuildItem> features) {
// required in order to access org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport
features.produce(new JPMSExportBuildItem("org.graalvm.sdk", "org.graalvm.nativeimage.impl"));
// required in order to access com.oracle.svm.core.jni.JNIRuntimeAccess in GraalVM 22.2.x
if (jniRuntimeAccessibleClasses != null && !jniRuntimeAccessibleClasses.isEmpty()) {
features.produce(new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.jni",
null, GraalVM.Version.VERSION_22_3_0));
}
}

@BuildStep
Expand All @@ -114,9 +57,6 @@ void generateFeature(BuildProducer<GeneratedNativeImageClassBuildItem> nativeIma
List<RuntimeInitializedClassBuildItem> runtimeInitializedClassBuildItems,
List<RuntimeInitializedPackageBuildItem> runtimeInitializedPackageBuildItems,
List<RuntimeReinitializedClassBuildItem> runtimeReinitializedClassBuildItems,
List<NativeImageResourcePatternsBuildItem> resourcePatterns,
List<NativeImageResourceBundleBuildItem> resourceBundles,
List<ServiceProviderBuildItem> serviceProviderBuildItems,
List<UnsafeAccessedFieldBuildItem> unsafeAccessedFields) {
ClassCreator file = new ClassCreator(new ClassOutput() {
@Override
Expand Down Expand Up @@ -234,155 +174,6 @@ public void write(String s, byte[] bytes) {
overallCatch.invokeStaticMethod(runtimeReinitializedClasses.getMethodDescriptor());
}

/* Resource includes and excludes */
if (!resourcePatterns.isEmpty()) {
MethodCreator resourceIncludesExcludes = file
.getMethodCreator("resourceIncludesExcludes", void.class)
.setModifiers(Modifier.PRIVATE | Modifier.STATIC);

// Needed to access com.oracle.svm.core.configure.ResourcesRegistry.* in GraalVM 22.2
exports.produce(new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.configure",
null, GraalVM.Version.VERSION_22_3_0));

TryBlock tc = resourceIncludesExcludes.tryBlock();

ResultHandle resourcesArgTypes = tc.marshalAsArray(Class.class, tc.loadClassFromTCCL(CONFIGURATION_CONDITION),
tc.loadClassFromTCCL(String.class));
AssignableResultHandle resourcesArgs = tc.createVariable(Object[].class);
tc.assign(resourcesArgs,
tc.marshalAsArray(Object.class, tc.invokeStaticMethod(CONFIGURATION_ALWAYS_TRUE), tc.loadNull()));

AssignableResultHandle ignoreResourcesMethod = tc.createVariable(Method.class);
AssignableResultHandle addResourcesMethod = tc.createVariable(Method.class);
AssignableResultHandle resourcesSingleton = tc.createVariable(Object.class);

BranchResult graalVm22_3Test = tc.ifGreaterEqualZero(tc.invokeVirtualMethod(VERSION_COMPARE_TO,
tc.invokeStaticMethod(VERSION_CURRENT),
tc.marshalAsArray(int.class, tc.load(22), tc.load(3))));
/* GraalVM >= 22.3 */
try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) {

ResultHandle runtimeResourceSupportClass = greaterThan22_2.loadClassFromTCCL(RUNTIME_RESOURCE_SUPPORT);

greaterThan22_2.assign(resourcesSingleton, greaterThan22_2.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP,
runtimeResourceSupportClass));

greaterThan22_2.assign(ignoreResourcesMethod, greaterThan22_2.invokeStaticMethod(LOOKUP_METHOD,
runtimeResourceSupportClass, greaterThan22_2.load("ignoreResources"), resourcesArgTypes));
greaterThan22_2.assign(addResourcesMethod, greaterThan22_2.invokeStaticMethod(LOOKUP_METHOD,
runtimeResourceSupportClass, greaterThan22_2.load("addResources"), resourcesArgTypes));
}

/* GraalVM < 22.3 */
try (BytecodeCreator smallerThan22_3 = graalVm22_3Test.falseBranch()) {

ResultHandle resourceRegistryClass = smallerThan22_3
.loadClassFromTCCL("com.oracle.svm.core.configure.ResourcesRegistry");
smallerThan22_3.assign(resourcesSingleton, smallerThan22_3.invokeStaticMethod(IMAGE_SINGLETONS_LOOKUP,
resourceRegistryClass));

smallerThan22_3.assign(ignoreResourcesMethod, smallerThan22_3.invokeStaticMethod(LOOKUP_METHOD,
resourceRegistryClass, smallerThan22_3.load("ignoreResources"), resourcesArgTypes));
smallerThan22_3.assign(addResourcesMethod, smallerThan22_3.invokeStaticMethod(LOOKUP_METHOD,
resourceRegistryClass, smallerThan22_3.load("addResources"), resourcesArgTypes));
}

ResultHandle indexOne = tc.load(1);

for (NativeImageResourcePatternsBuildItem resourcePatternsItem : resourcePatterns) {
for (String pattern : resourcePatternsItem.getExcludePatterns()) {
tc.writeArrayValue(resourcesArgs, indexOne, tc.load(pattern));
tc.invokeVirtualMethod(INVOKE, ignoreResourcesMethod, resourcesSingleton, resourcesArgs);
}
for (String pattern : resourcePatternsItem.getIncludePatterns()) {
tc.writeArrayValue(resourcesArgs, indexOne, tc.load(pattern));
tc.invokeVirtualMethod(INVOKE, addResourcesMethod, resourcesSingleton, resourcesArgs);
}
}
CatchBlockCreator cc = tc.addCatch(Throwable.class);
cc.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), cc.getCaughtException());

resourceIncludesExcludes.returnVoid();
overallCatch.invokeStaticMethod(resourceIncludesExcludes.getMethodDescriptor());
}

MethodCreator registerServiceProviders = file
.getMethodCreator("registerServiceProviders", void.class)
.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
for (ServiceProviderBuildItem i : serviceProviderBuildItems) {
registerServiceProviders.invokeStaticMethod(
ofMethod(ResourceHelper.class, "registerResources", void.class, String.class),
registerServiceProviders.load(i.serviceDescriptorFile()));
}
registerServiceProviders.returnVoid();
overallCatch.invokeStaticMethod(registerServiceProviders.getMethodDescriptor());

if (!resourceBundles.isEmpty()) {
MethodCreator registerResourceBundles = file
.getMethodCreator("registerResourceBundles", void.class)
.setModifiers(Modifier.PRIVATE | Modifier.STATIC);

// Needed to access LOCALIZATION_FEATURE
exports.produce(
new JPMSExportBuildItem("org.graalvm.nativeimage.builder", "com.oracle.svm.core.jdk.localization",
null, GraalVM.Version.VERSION_22_3_0));

BranchResult graalVm22_3Test = registerResourceBundles
.ifGreaterEqualZero(registerResourceBundles.invokeVirtualMethod(VERSION_COMPARE_TO,
registerResourceBundles.invokeStaticMethod(VERSION_CURRENT),
registerResourceBundles.marshalAsArray(int.class, registerResourceBundles.load(22),
registerResourceBundles.load(3))));
/* GraalVM >= 22.3 */
try (BytecodeCreator greaterThan22_2 = graalVm22_3Test.trueBranch()) {

MethodDescriptor addResourceBundle = ofMethod("org.graalvm.nativeimage.hosted.RuntimeResourceAccess",
"addResourceBundle", void.class, Module.class, String.class);

for (NativeImageResourceBundleBuildItem i : resourceBundles) {
TryBlock tc = greaterThan22_2.tryBlock();

String moduleName = i.getModuleName();
ResultHandle moduleNameHandle;
if (moduleName == null) {
moduleNameHandle = tc.loadNull();
} else {
moduleNameHandle = tc.load(moduleName);
}
ResultHandle module = tc.invokeStaticMethod(FIND_MODULE_METHOD, moduleNameHandle);
tc.invokeStaticMethod(addResourceBundle, module, tc.load(i.getBundleName()));
CatchBlockCreator c = tc.addCatch(Throwable.class);
//c.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), c.getCaughtException());
}
}

/* GraalVM < 22.3 */
try (BytecodeCreator smallerThan22_3 = graalVm22_3Test.falseBranch()) {

ResultHandle locClass = smallerThan22_3.loadClassFromTCCL(LOCALIZATION_FEATURE);
ResultHandle newParams = smallerThan22_3.marshalAsArray(Class.class,
smallerThan22_3.loadClassFromTCCL(String.class));
ResultHandle registerMethod = smallerThan22_3.invokeStaticMethod(
LOOKUP_METHOD,
locClass, smallerThan22_3.load("prepareBundle"), newParams);

ResultHandle locSupport = smallerThan22_3.invokeStaticMethod(
IMAGE_SINGLETONS_LOOKUP,
locClass);

for (NativeImageResourceBundleBuildItem i : resourceBundles) {
TryBlock et = smallerThan22_3.tryBlock();

et.invokeVirtualMethod(ofMethod(Method.class, "invoke", Object.class, Object.class, Object[].class),
registerMethod, locSupport, et.marshalAsArray(Object.class, et.load(i.getBundleName())));
CatchBlockCreator c = et.addCatch(Throwable.class);
//c.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), c.getCaughtException());
}
}

registerResourceBundles.returnVoid();
overallCatch.invokeStaticMethod(registerResourceBundles.getMethodDescriptor());
}

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

Expand Down
Loading

0 comments on commit b7f49dd

Please sign in to comment.