Skip to content
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

[GR-30205] Extend the agent to collect the locale and classname of resource bundles. #3557

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6b41ba2
extend the agent to collect the locale and classname of resource bundles
d-kozak Jul 7, 2021
3c28aa5
read & use the whole resource bundle parent chain in native image agent
d-kozak Jul 16, 2021
0d2d414
use new locale configuration in the image
d-kozak Jul 19, 2021
7203f73
only include 'locales' and 'classnames' field of a resource bundle co…
d-kozak Jul 26, 2021
b6b7daf
enable tracing to get more debug hints from the gates
d-kozak Jul 27, 2021
e752976
fix style issue - make ResourceConfiguration.printResourceBundle static
d-kozak Jul 27, 2021
62302f9
fix registering class based bundles in Java 8
d-kozak Aug 12, 2021
b24db31
only register bundle in all locales if no specific locales or classna…
d-kozak Aug 12, 2021
ef98bc8
remember the basename of the class based bundle, so that it can be lo…
d-kozak Aug 12, 2021
faf9026
fix another style issue
d-kozak Aug 13, 2021
30715d3
refactoring: changing the naming patterns for localization
d-kozak Aug 13, 2021
165cce3
preprocess class based bundles correctly for OptimizedLocalizationSup…
d-kozak Aug 13, 2021
7ce690b
store the bundles as delayed in BundleContentSubstitutedLocalizationS…
d-kozak Aug 16, 2021
c6b4c08
fix style issues
d-kozak Aug 16, 2021
2fd2a55
fixes after rebase
d-kozak Aug 24, 2021
35dfaff
make the localization related handles in NativeImageAgentJNIHandleSet…
d-kozak Aug 25, 2021
72041ec
fix incorrect bundle analysis in BreakpointInterceptor.extractBundleInfo
d-kozak Aug 26, 2021
913a06f
fix imports in ResourcesFeature
d-kozak Sep 14, 2021
aab0db2
use JSONParserException instead of UserError in ResourceConfiguration…
d-kozak Sep 14, 2021
5cda4fd
fixes after rebase
d-kozak Sep 25, 2021
5d13c71
style issue: add missing override
d-kozak Sep 27, 2021
f87ef4a
localization: code cleanup
d-kozak Sep 28, 2021
860f582
address issues from the review
d-kozak Oct 22, 2021
f1d7dc0
fix formatting issues when printing resource bundle config
d-kozak Oct 22, 2021
8fefd4f
remove static imports for Support.callObjectMethod & Support.newObjectL
d-kozak Nov 1, 2021
f516400
refactoring BreakpointInterceptor
d-kozak Nov 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

import static com.oracle.svm.core.util.VMError.guarantee;
import static com.oracle.svm.jni.JNIObjectHandles.nullHandle;
import static com.oracle.svm.jvmtiagentbase.Support.callObjectMethod;
import static com.oracle.svm.jvmtiagentbase.Support.check;
import static com.oracle.svm.jvmtiagentbase.Support.checkNoException;
import static com.oracle.svm.jvmtiagentbase.Support.clearException;
Expand All @@ -40,7 +39,6 @@
import static com.oracle.svm.jvmtiagentbase.Support.jniFunctions;
import static com.oracle.svm.jvmtiagentbase.Support.jvmtiEnv;
import static com.oracle.svm.jvmtiagentbase.Support.jvmtiFunctions;
import static com.oracle.svm.jvmtiagentbase.Support.newObjectL;
import static com.oracle.svm.jvmtiagentbase.Support.testException;
import static com.oracle.svm.jvmtiagentbase.Support.toCString;
import static com.oracle.svm.jvmtiagentbase.jvmti.JvmtiEvent.JVMTI_EVENT_BREAKPOINT;
Expand Down Expand Up @@ -647,11 +645,14 @@ private static boolean getBundleImplJDK8OrEarlier(JNIEnvironment jni, Breakpoint
JNIObjectHandle loader = getObjectArgument(2);
JNIObjectHandle control = getObjectArgument(3);
JNIObjectHandle result = Support.callStaticObjectMethodLLLL(jni, bp.clazz, bp.method, baseName, locale, loader, control);
BundleInfo bundleInfo = BundleInfo.NONE;
if (clearException(jni)) {
result = nullHandle();
} else {
bundleInfo = extractBundleInfo(jni, result);
}
traceBreakpoint(jni, nullHandle(), nullHandle(), callerClass, "getBundleImplJDK8OrEarlier", result.notEqual(nullHandle()),
state.getFullStackTraceOrNull(), fromJniString(jni, baseName), Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE);
state.getFullStackTraceOrNull(), fromJniString(jni, baseName), Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE, bundleInfo.classNames, bundleInfo.locales);
return true;
}

Expand All @@ -671,14 +672,80 @@ private static boolean getBundleImplJDK11OrLater(JNIEnvironment jni, Breakpoint
JNIObjectHandle locale = getObjectArgument(3);
JNIObjectHandle control = getObjectArgument(4);
JNIObjectHandle result = Support.callStaticObjectMethodLLLLL(jni, bp.clazz, bp.method, callerModule, module, baseName, locale, control);
BundleInfo bundleInfo = BundleInfo.NONE;
if (clearException(jni)) {
result = nullHandle();
} else {
bundleInfo = extractBundleInfo(jni, result);
}
traceBreakpoint(jni, nullHandle(), nullHandle(), callerClass, "getBundleImplJDK11OrLater", result.notEqual(nullHandle()),
state.getFullStackTraceOrNull(), Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE, fromJniString(jni, baseName), Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE);
state.getFullStackTraceOrNull(), Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE, fromJniString(jni, baseName), Tracer.UNKNOWN_VALUE, Tracer.UNKNOWN_VALUE, bundleInfo.classNames,
bundleInfo.locales);
return true;
}

private static String readLocaleTag(JNIEnvironment jni, JNIObjectHandle locale) {
JNIObjectHandle languageTag = Support.callObjectMethod(jni, locale, agent.handles().getJavaUtilLocaleToLanguageTag(jni));
if (clearException(jni)) {
/*- return root locale */
return "";
}
return fromJniString(jni, languageTag);
}

private static final class BundleInfo {

static final BundleInfo NONE = new BundleInfo(new String[0], new String[0]);

final String[] classNames;
final String[] locales;

BundleInfo(String[] classNames, String[] locales) {
this.classNames = classNames;
this.locales = locales;
}
}

/**
* Traverses the bundle parent chain and collects classnames and locales of all encountered
* bundles.
*
*/
private static BundleInfo extractBundleInfo(JNIEnvironment jni, JNIObjectHandle bundle) {
List<String> locales = new ArrayList<>();
List<String> classNames = new ArrayList<>();
JNIObjectHandle curr = bundle;
while (curr.notEqual(nullHandle())) {
JNIObjectHandle locale = Support.callObjectMethod(jni, curr, agent.handles().getJavaUtilResourceBundleGetLocale(jni));
if (clearException(jni)) {
return BundleInfo.NONE;
}
String localeTag = readLocaleTag(jni, locale);
if (localeTag.equals("und")) {
/*- Root locale is serialized into "und" */
localeTag = "";
}
JNIObjectHandle clazz = Support.callObjectMethod(jni, curr, agent.handles().javaLangObjectGetClass);
if (!clearException(jni)) {
JNIObjectHandle classNameHandle = Support.callObjectMethod(jni, clazz, agent.handles().javaLangClassGetName);
if (!clearException(jni)) {
classNames.add(fromJniString(jni, classNameHandle));
locales.add(localeTag);
}
}
curr = getResourceBundleParent(jni, curr);
}
return new BundleInfo(classNames.toArray(new String[0]), locales.toArray(new String[0]));
}

private static JNIObjectHandle getResourceBundleParent(JNIEnvironment jni, JNIObjectHandle bundle) {
JNIObjectHandle parent = Support.readObjectField(jni, bundle, agent.handles().getJavaUtilResourceBundleParentField(jni));
if (!clearException(jni)) {
return parent;
}
return nullHandle();
}

private static boolean loadClass(JNIEnvironment jni, Breakpoint bp, InterceptedState state) {
assert experimentalClassLoaderSupport;
/*
Expand Down Expand Up @@ -981,7 +1048,7 @@ private static boolean objectStreamClassConstructor(JNIEnvironment jni, Breakpoi
JNIObjectHandle serializeTargetClass = getObjectArgument(1);
String serializeTargetClassName = getClassNameOrNull(jni, serializeTargetClass);

JNIObjectHandle objectStreamClassInstance = newObjectL(jni, bp.clazz, bp.method, serializeTargetClass);
JNIObjectHandle objectStreamClassInstance = Support.newObjectL(jni, bp.clazz, bp.method, serializeTargetClass);
boolean validObjectStreamClassInstance = nullHandle().notEqual(objectStreamClassInstance);
if (clearException(jni)) {
validObjectStreamClassInstance = false;
Expand All @@ -1001,7 +1068,7 @@ private static boolean objectStreamClassConstructor(JNIEnvironment jni, Breakpoi
* recursively. Call ObjectStreamClass.getClassDataLayout0() can get all of them.
*/
JNIMethodId getClassDataLayout0MId = agent.handles().getJavaIoObjectStreamClassGetClassDataLayout0(jni, bp.clazz);
JNIObjectHandle dataLayoutArray = callObjectMethod(jni, objectStreamClassInstance, getClassDataLayout0MId);
JNIObjectHandle dataLayoutArray = Support.callObjectMethod(jni, objectStreamClassInstance, getClassDataLayout0MId);
if (!clearException(jni) && nullHandle().notEqual(dataLayoutArray)) {
int length = jniFunctions().getGetArrayLength().invoke(jni, dataLayoutArray);
// If only 1 element is got from getClassDataLayout0(). it is base ObjectStreamClass
Expand All @@ -1016,7 +1083,7 @@ private static boolean objectStreamClassConstructor(JNIEnvironment jni, Breakpoi
if (hasData) {
JNIObjectHandle oscInstanceInSlot = jniFunctions().getGetObjectField().invoke(jni, classDataSlot, descFId);
if (!jniFunctions().getIsSameObject().invoke(jni, oscInstanceInSlot, objectStreamClassInstance)) {
JNIObjectHandle oscClazz = callObjectMethod(jni, oscInstanceInSlot, javaIoObjectStreamClassForClassMId);
JNIObjectHandle oscClazz = Support.callObjectMethod(jni, oscInstanceInSlot, javaIoObjectStreamClassForClassMId);
String oscClassName = getClassNameOrNull(jni, oscClazz);
transitiveSerializeTargets.add(oscClassName);
}
Expand Down Expand Up @@ -1062,7 +1129,7 @@ private static boolean customTargetConstructorSerialization(JNIEnvironment jni,
JNIObjectHandle customConstructorObj = getObjectArgument(2);
JNIObjectHandle customConstructorClass = jniFunctions().getGetObjectClass().invoke(jni, customConstructorObj);
JNIMethodId getDeclaringClassNameMethodID = agent.handles().getJavaLangReflectConstructorDeclaringClassName(jni, customConstructorClass);
JNIObjectHandle declaredClassNameObj = callObjectMethod(jni, customConstructorObj, getDeclaringClassNameMethodID);
JNIObjectHandle declaredClassNameObj = Support.callObjectMethod(jni, customConstructorObj, getDeclaringClassNameMethodID);
String customConstructorClassName = fromJniString(jni, declaredClassNameObj);

if (tracer != null) {
Expand Down Expand Up @@ -1261,9 +1328,9 @@ private static void setupClassLoadEvent(JvmtiEnv jvmti, JNIEnvironment jni) {
JNIMethodId getPlatformLoader = agent.handles().getMethodIdOptional(jni, classLoader, "getPlatformClassLoader", "()Ljava/lang/ClassLoader;", true);
JNIMethodId getAppLoader = agent.handles().getMethodIdOptional(jni, classLoader, "getBuiltinAppClassLoader", "()Ljava/lang/ClassLoader;", true);
if (getPlatformLoader.isNonNull() && getAppLoader.isNonNull()) { // only on JDK 9 and later
JNIObjectHandle platformLoader = callObjectMethod(jni, classLoader, getPlatformLoader);
JNIObjectHandle platformLoader = Support.callObjectMethod(jni, classLoader, getPlatformLoader);
checkNoException(jni);
JNIObjectHandle appLoader = callObjectMethod(jni, classLoader, getAppLoader);
JNIObjectHandle appLoader = Support.callObjectMethod(jni, classLoader, getAppLoader);
checkNoException(jni);
guarantee(platformLoader.notEqual(nullHandle()) && appLoader.notEqual(nullHandle()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public class NativeImageAgentJNIHandleSet extends JNIHandleSet {

private JNIMethodId javaLangReflectConstructorDeclaringClassName;

private JNIMethodId javaUtilLocaleToLanguageTag;
private JNIFieldId javaUtilResourceBundleParentField;
private JNIMethodId javaUtilResourceBundleGetLocale;

NativeImageAgentJNIHandleSet(JNIEnvironment env) {
super(env);
javaLangClass = newClassGlobalRef(env, "java/lang/Class");
Expand Down Expand Up @@ -179,4 +183,28 @@ JNIMethodId getJavaLangReflectConstructorDeclaringClassName(JNIEnvironment env,
}
return javaLangReflectConstructorDeclaringClassName;
}

public JNIMethodId getJavaUtilLocaleToLanguageTag(JNIEnvironment env) {
if (javaUtilLocaleToLanguageTag.isNull()) {
JNIObjectHandle javaUtilLocale = findClass(env, "java/util/Locale");
javaUtilLocaleToLanguageTag = getMethodId(env, javaUtilLocale, "toLanguageTag", "()Ljava/lang/String;", false);
}
return javaUtilLocaleToLanguageTag;
}

public JNIFieldId getJavaUtilResourceBundleParentField(JNIEnvironment env) {
if (javaUtilResourceBundleParentField.isNull()) {
JNIObjectHandle javaUtilResourceBundle = findClass(env, "java/util/ResourceBundle");
javaUtilResourceBundleParentField = getFieldId(env, javaUtilResourceBundle, "parent", "Ljava/util/ResourceBundle;", false);
}
return javaUtilResourceBundleParentField;
}

public JNIMethodId getJavaUtilResourceBundleGetLocale(JNIEnvironment env) {
if (javaUtilResourceBundleGetLocale.isNull()) {
JNIObjectHandle javaUtilResourceBundle = findClass(env, "java/util/ResourceBundle");
javaUtilResourceBundleGetLocale = getMethodId(env, javaUtilResourceBundle, "getLocale", "()Ljava/util/Locale;", false);
}
return javaUtilResourceBundleGetLocale;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -28,8 +28,10 @@
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import org.graalvm.nativeimage.impl.ConfigurationCondition;
import org.junit.Assert;
Expand Down Expand Up @@ -99,6 +101,16 @@ public void ignoreResources(ConfigurationCondition condition, String pattern) {
@Override
public void addResourceBundles(ConfigurationCondition condition, String name) {
}

@Override
public void addResourceBundles(ConfigurationCondition condition, String basename, Collection<Locale> locales) {

}

@Override
public void addClassBasedResourceBundle(ConfigurationCondition condition, String basename, String className) {

}
};

ResourceConfigurationParser rcp = new ResourceConfigurationParser(registry, true);
Expand Down
Loading