46459
|
1 |
/*
|
|
2 |
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
|
7 |
* published by the Free Software Foundation.
|
|
8 |
*
|
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
13 |
* accompanied this code).
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License version
|
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 |
*
|
|
19 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
20 |
* or visit www.oracle.com if you need additional information or have any
|
|
21 |
* questions.
|
|
22 |
*/
|
|
23 |
package org.graalvm.compiler.hotspot;
|
|
24 |
|
46536
|
25 |
import java.lang.ref.Reference;
|
|
26 |
import java.lang.ref.WeakReference;
|
46459
|
27 |
import java.lang.reflect.Field;
|
|
28 |
import java.util.ArrayList;
|
46536
|
29 |
import java.util.Iterator;
|
46459
|
30 |
import java.util.List;
|
46536
|
31 |
import java.util.Objects;
|
|
32 |
import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
|
|
33 |
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
|
34 |
import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
|
|
35 |
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
|
|
36 |
import jdk.vm.ci.meta.MetaUtil;
|
46459
|
37 |
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
46536
|
38 |
import jdk.vm.ci.meta.ResolvedJavaType;
|
|
39 |
import jdk.vm.ci.runtime.JVMCI;
|
46640
|
40 |
|
|
41 |
import org.graalvm.compiler.debug.DebugOptions;
|
46459
|
42 |
import org.graalvm.compiler.options.OptionDescriptor;
|
|
43 |
import org.graalvm.compiler.options.OptionDescriptors;
|
|
44 |
import org.graalvm.compiler.options.OptionKey;
|
|
45 |
import org.graalvm.compiler.options.OptionValues;
|
|
46 |
import org.graalvm.compiler.options.OptionsParser;
|
48861
|
47 |
import org.graalvm.collections.EconomicMap;
|
|
48 |
import org.graalvm.collections.EconomicSet;
|
|
49 |
import org.graalvm.collections.Equivalence;
|
|
50 |
import org.graalvm.collections.UnmodifiableEconomicMap;
|
46459
|
51 |
|
46807
|
52 |
public final class HotSpotGraalMBean implements javax.management.DynamicMBean {
|
46459
|
53 |
private static Object mBeanServerField;
|
46536
|
54 |
private final HotSpotGraalCompiler compiler;
|
46459
|
55 |
private final OptionValues options;
|
|
56 |
private final EconomicMap<OptionKey<?>, Object> changes;
|
46536
|
57 |
private final EconomicSet<Dump> methodDumps;
|
|
58 |
private volatile EconomicSet<Reference<ClassLoader>> loaders;
|
46807
|
59 |
private javax.management.ObjectName registered;
|
46509
|
60 |
private OptionValues cachedOptions;
|
46459
|
61 |
|
46536
|
62 |
private HotSpotGraalMBean(HotSpotGraalCompiler compiler, OptionValues options) {
|
|
63 |
this.compiler = compiler;
|
46459
|
64 |
this.options = options;
|
|
65 |
this.changes = EconomicMap.create();
|
46536
|
66 |
this.methodDumps = EconomicSet.create();
|
|
67 |
EconomicSet<Reference<ClassLoader>> systemLoaderSet = EconomicSet.create(RefEquivalence.INSTANCE);
|
|
68 |
systemLoaderSet.add(new WeakReference<>(ClassLoader.getSystemClassLoader()));
|
|
69 |
this.loaders = systemLoaderSet;
|
46459
|
70 |
}
|
|
71 |
|
|
72 |
private static boolean isMXServerOn() {
|
|
73 |
if (mBeanServerField == null) {
|
|
74 |
try {
|
46807
|
75 |
final Field field = java.lang.management.ManagementFactory.class.getDeclaredField("platformMBeanServer");
|
46459
|
76 |
field.setAccessible(true);
|
|
77 |
mBeanServerField = field;
|
|
78 |
} catch (Exception ex) {
|
46807
|
79 |
mBeanServerField = java.lang.management.ManagementFactory.class;
|
46459
|
80 |
}
|
|
81 |
}
|
|
82 |
if (mBeanServerField instanceof Field) {
|
|
83 |
try {
|
|
84 |
return ((Field) mBeanServerField).get(null) != null;
|
|
85 |
} catch (Exception ex) {
|
|
86 |
return true;
|
|
87 |
}
|
|
88 |
} else {
|
|
89 |
return false;
|
|
90 |
}
|
|
91 |
}
|
|
92 |
|
46536
|
93 |
public static HotSpotGraalMBean create(HotSpotGraalCompiler compiler) {
|
46459
|
94 |
OptionValues options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
|
46536
|
95 |
HotSpotGraalMBean mbean = new HotSpotGraalMBean(compiler, options);
|
46459
|
96 |
return mbean;
|
|
97 |
}
|
|
98 |
|
46807
|
99 |
public javax.management.ObjectName ensureRegistered(boolean check) {
|
46459
|
100 |
for (int cnt = 0;; cnt++) {
|
|
101 |
if (registered != null) {
|
|
102 |
return registered;
|
|
103 |
}
|
|
104 |
if (check && !isMXServerOn()) {
|
|
105 |
return null;
|
|
106 |
}
|
|
107 |
try {
|
46807
|
108 |
javax.management.MBeanServer mbs = java.lang.management.ManagementFactory.getPlatformMBeanServer();
|
|
109 |
javax.management.ObjectName name = new javax.management.ObjectName("org.graalvm.compiler.hotspot:type=Options" + (cnt == 0 ? "" : cnt));
|
46459
|
110 |
mbs.registerMBean(this, name);
|
|
111 |
registered = name;
|
|
112 |
break;
|
46807
|
113 |
} catch (javax.management.MalformedObjectNameException | javax.management.MBeanRegistrationException | javax.management.NotCompliantMBeanException ex) {
|
46459
|
114 |
throw new IllegalStateException(ex);
|
46807
|
115 |
} catch (javax.management.InstanceAlreadyExistsException ex) {
|
46459
|
116 |
continue;
|
|
117 |
}
|
|
118 |
}
|
|
119 |
return registered;
|
|
120 |
}
|
|
121 |
|
46509
|
122 |
public OptionValues optionsFor(OptionValues initialValues, ResolvedJavaMethod forMethod) {
|
46459
|
123 |
ensureRegistered(true);
|
46536
|
124 |
if (forMethod instanceof HotSpotResolvedJavaMethod) {
|
|
125 |
HotSpotResolvedObjectType type = ((HotSpotResolvedJavaMethod) forMethod).getDeclaringClass();
|
|
126 |
if (type instanceof HotSpotResolvedJavaType) {
|
|
127 |
Class<?> clazz = ((HotSpotResolvedJavaType) type).mirror();
|
|
128 |
Reference<ClassLoader> addNewRef = new WeakReference<>(clazz.getClassLoader());
|
|
129 |
if (!loaders.contains(addNewRef)) {
|
|
130 |
EconomicSet<Reference<ClassLoader>> newLoaders = EconomicSet.create(RefEquivalence.INSTANCE, loaders);
|
|
131 |
newLoaders.add(addNewRef);
|
|
132 |
this.loaders = newLoaders;
|
|
133 |
}
|
|
134 |
}
|
|
135 |
}
|
|
136 |
return currentMap(initialValues, forMethod);
|
46509
|
137 |
}
|
|
138 |
|
46536
|
139 |
private OptionValues currentMap(OptionValues initialValues, ResolvedJavaMethod method) {
|
|
140 |
if (changes.isEmpty() && methodDumps.isEmpty()) {
|
46509
|
141 |
return initialValues;
|
46459
|
142 |
}
|
46509
|
143 |
OptionValues current = cachedOptions;
|
|
144 |
if (current == null) {
|
|
145 |
current = new OptionValues(initialValues, changes);
|
|
146 |
cachedOptions = current;
|
|
147 |
}
|
46536
|
148 |
if (method != null) {
|
|
149 |
for (Dump request : methodDumps) {
|
|
150 |
final String clazzName = method.getDeclaringClass().getName();
|
|
151 |
if (method.getName().equals(request.method) && clazzName.equals(request.clazz)) {
|
46640
|
152 |
current = new OptionValues(current, DebugOptions.Dump, request.filter,
|
|
153 |
DebugOptions.PrintGraphHost, request.host,
|
|
154 |
DebugOptions.PrintBinaryGraphPort, request.port);
|
46536
|
155 |
break;
|
|
156 |
}
|
|
157 |
}
|
|
158 |
}
|
46509
|
159 |
return current;
|
46459
|
160 |
}
|
|
161 |
|
|
162 |
@Override
|
|
163 |
public Object getAttribute(String attribute) {
|
46536
|
164 |
UnmodifiableEconomicMap<OptionKey<?>, Object> map = currentMap(options, null).getMap();
|
46509
|
165 |
for (OptionKey<?> k : map.getKeys()) {
|
46459
|
166 |
if (k.getName().equals(attribute)) {
|
46509
|
167 |
return map.get(k);
|
46459
|
168 |
}
|
|
169 |
}
|
|
170 |
return null;
|
|
171 |
}
|
|
172 |
|
|
173 |
@Override
|
46807
|
174 |
public void setAttribute(javax.management.Attribute attribute) throws javax.management.AttributeNotFoundException {
|
|
175 |
javax.management.Attribute newAttr = setImpl(attribute);
|
46509
|
176 |
if (newAttr == null) {
|
46807
|
177 |
throw new javax.management.AttributeNotFoundException();
|
46509
|
178 |
}
|
|
179 |
}
|
|
180 |
|
46807
|
181 |
private javax.management.Attribute setImpl(javax.management.Attribute attribute) {
|
46509
|
182 |
cachedOptions = null;
|
|
183 |
for (OptionDescriptor option : allOptionDescriptors()) {
|
|
184 |
if (option.getName().equals(attribute.getName())) {
|
|
185 |
changes.put(option.getOptionKey(), attribute.getValue());
|
|
186 |
return attribute;
|
|
187 |
}
|
|
188 |
}
|
|
189 |
return null;
|
46459
|
190 |
}
|
|
191 |
|
|
192 |
@Override
|
46807
|
193 |
public javax.management.AttributeList getAttributes(String[] names) {
|
|
194 |
javax.management.AttributeList list = new javax.management.AttributeList();
|
46459
|
195 |
for (String name : names) {
|
|
196 |
Object value = getAttribute(name);
|
|
197 |
if (value != null) {
|
46807
|
198 |
list.add(new javax.management.Attribute(name, value));
|
46459
|
199 |
}
|
|
200 |
}
|
|
201 |
return list;
|
|
202 |
}
|
|
203 |
|
|
204 |
@Override
|
46807
|
205 |
public javax.management.AttributeList setAttributes(javax.management.AttributeList attributes) {
|
|
206 |
javax.management.AttributeList setOk = new javax.management.AttributeList();
|
|
207 |
for (javax.management.Attribute attr : attributes.asList()) {
|
|
208 |
javax.management.Attribute newAttr = setImpl(attr);
|
46509
|
209 |
if (newAttr != null) {
|
|
210 |
setOk.add(newAttr);
|
|
211 |
}
|
|
212 |
}
|
|
213 |
return setOk;
|
46459
|
214 |
}
|
|
215 |
|
|
216 |
@Override
|
46807
|
217 |
public Object invoke(String actionName, Object[] params, String[] signature) throws javax.management.MBeanException, javax.management.ReflectionException {
|
46536
|
218 |
if ("dumpMethod".equals(actionName)) {
|
|
219 |
try {
|
|
220 |
String className = param(params, 0, "className", String.class, null);
|
|
221 |
String methodName = param(params, 1, "methodName", String.class, null);
|
|
222 |
String filter = param(params, 2, "filter", String.class, ":3");
|
|
223 |
String host = param(params, 3, "host", String.class, "localhost");
|
|
224 |
Number port = param(params, 4, "port", Number.class, 4445);
|
|
225 |
dumpMethod(className, methodName, filter, host, port.intValue());
|
|
226 |
} catch (Exception ex) {
|
46807
|
227 |
throw new javax.management.ReflectionException(ex);
|
46536
|
228 |
}
|
|
229 |
}
|
46459
|
230 |
return null;
|
|
231 |
}
|
|
232 |
|
46536
|
233 |
private static <T> T param(Object[] arr, int index, String name, Class<T> type, T defaultValue) {
|
|
234 |
Object value = arr.length > index ? arr[index] : null;
|
|
235 |
if (value == null || (value instanceof String && ((String) value).isEmpty())) {
|
|
236 |
if (defaultValue == null) {
|
|
237 |
throw new IllegalArgumentException(name + " must be specified");
|
|
238 |
}
|
|
239 |
value = defaultValue;
|
|
240 |
}
|
|
241 |
if (type.isInstance(value)) {
|
|
242 |
return type.cast(value);
|
|
243 |
}
|
|
244 |
throw new IllegalArgumentException("Expecting " + type.getName() + " for " + name + " but was " + value);
|
|
245 |
}
|
|
246 |
|
46807
|
247 |
public void dumpMethod(String className, String methodName, String filter, String host, int port) throws javax.management.MBeanException {
|
46536
|
248 |
String jvmName = MetaUtil.toInternalName(className);
|
|
249 |
methodDumps.add(new Dump(host, port, jvmName, methodName, filter));
|
|
250 |
|
|
251 |
ClassNotFoundException last = null;
|
|
252 |
EconomicSet<Class<?>> found = EconomicSet.create();
|
|
253 |
Iterator<Reference<ClassLoader>> it = loaders.iterator();
|
|
254 |
while (it.hasNext()) {
|
|
255 |
Reference<ClassLoader> ref = it.next();
|
|
256 |
ClassLoader loader = ref.get();
|
|
257 |
if (loader == null) {
|
|
258 |
it.remove();
|
|
259 |
continue;
|
|
260 |
}
|
|
261 |
try {
|
|
262 |
Class<?> clazz = Class.forName(className, false, loader);
|
|
263 |
if (found.add(clazz)) {
|
|
264 |
ResolvedJavaType type = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(clazz);
|
|
265 |
if (compiler != null) {
|
|
266 |
for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
|
|
267 |
if (methodName.equals(method.getName()) && method instanceof HotSpotResolvedJavaMethod) {
|
|
268 |
HotSpotResolvedJavaMethod hotSpotMethod = (HotSpotResolvedJavaMethod) method;
|
|
269 |
compiler.compileMethod(new HotSpotCompilationRequest(hotSpotMethod, -1, 0L), false);
|
|
270 |
}
|
|
271 |
}
|
|
272 |
}
|
|
273 |
}
|
|
274 |
} catch (ClassNotFoundException ex) {
|
|
275 |
last = ex;
|
|
276 |
}
|
|
277 |
}
|
|
278 |
if (found.isEmpty()) {
|
46807
|
279 |
throw new javax.management.MBeanException(last, "Cannot find class " + className + " to schedule recompilation");
|
46536
|
280 |
}
|
|
281 |
}
|
|
282 |
|
46459
|
283 |
@Override
|
46807
|
284 |
public javax.management.MBeanInfo getMBeanInfo() {
|
|
285 |
List<javax.management.MBeanAttributeInfo> attrs = new ArrayList<>();
|
47798
|
286 |
for (OptionDescriptor descr : allOptionDescriptors()) {
|
|
287 |
attrs.add(new javax.management.MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
|
46459
|
288 |
}
|
46807
|
289 |
javax.management.MBeanOperationInfo[] ops = {
|
|
290 |
new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{
|
|
291 |
new javax.management.MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
|
|
292 |
new javax.management.MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
|
|
293 |
}, "void", javax.management.MBeanOperationInfo.ACTION),
|
|
294 |
new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{
|
|
295 |
new javax.management.MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
|
|
296 |
new javax.management.MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
|
|
297 |
new javax.management.MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"),
|
|
298 |
}, "void", javax.management.MBeanOperationInfo.ACTION),
|
|
299 |
new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{
|
|
300 |
new javax.management.MBeanParameterInfo("className", "java.lang.String", "Class to observe"),
|
|
301 |
new javax.management.MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"),
|
|
302 |
new javax.management.MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"),
|
|
303 |
new javax.management.MBeanParameterInfo("host", "java.lang.String", "The host where the IGV tool is running at"),
|
|
304 |
new javax.management.MBeanParameterInfo("port", "int", "The port where the IGV tool is listening at"),
|
|
305 |
}, "void", javax.management.MBeanOperationInfo.ACTION)
|
46536
|
306 |
};
|
|
307 |
|
46807
|
308 |
return new javax.management.MBeanInfo(
|
46459
|
309 |
HotSpotGraalMBean.class.getName(),
|
|
310 |
"Graal",
|
46807
|
311 |
attrs.toArray(new javax.management.MBeanAttributeInfo[attrs.size()]),
|
46536
|
312 |
null, ops, null);
|
46459
|
313 |
}
|
|
314 |
|
46509
|
315 |
private static Iterable<OptionDescriptor> allOptionDescriptors() {
|
|
316 |
List<OptionDescriptor> arr = new ArrayList<>();
|
|
317 |
for (OptionDescriptors set : OptionsParser.getOptionsLoader()) {
|
|
318 |
for (OptionDescriptor descr : set) {
|
|
319 |
arr.add(descr);
|
|
320 |
}
|
|
321 |
}
|
|
322 |
return arr;
|
|
323 |
}
|
|
324 |
|
46536
|
325 |
private static final class Dump {
|
|
326 |
final String host;
|
|
327 |
final int port;
|
|
328 |
final String clazz;
|
|
329 |
final String method;
|
|
330 |
final String filter;
|
|
331 |
|
|
332 |
Dump(String host, int port, String clazz, String method, String filter) {
|
|
333 |
this.host = host;
|
|
334 |
this.port = port;
|
|
335 |
this.clazz = clazz;
|
|
336 |
this.method = method;
|
|
337 |
this.filter = filter;
|
|
338 |
}
|
|
339 |
}
|
|
340 |
|
|
341 |
private static final class RefEquivalence extends Equivalence {
|
|
342 |
static final Equivalence INSTANCE = new RefEquivalence();
|
|
343 |
|
|
344 |
private RefEquivalence() {
|
|
345 |
}
|
|
346 |
|
|
347 |
@Override
|
|
348 |
public boolean equals(Object a, Object b) {
|
|
349 |
Reference<?> refA = (Reference<?>) a;
|
|
350 |
Reference<?> refB = (Reference<?>) b;
|
|
351 |
return Objects.equals(refA.get(), refB.get());
|
|
352 |
}
|
|
353 |
|
|
354 |
@Override
|
|
355 |
public int hashCode(Object o) {
|
|
356 |
Reference<?> ref = (Reference<?>) o;
|
|
357 |
Object obj = ref.get();
|
|
358 |
return obj == null ? 0 : obj.hashCode();
|
|
359 |
}
|
|
360 |
|
|
361 |
}
|
46459
|
362 |
}
|