comparison jvmci/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java @ 23393:1d4ce2d19e52

clean up and minimize JVMCI (JDK-8156835)
author Doug Simon <doug.simon@oracle.com>
date Thu, 12 May 2016 20:57:31 +0200
parents 1bbd4a7c274b
children d6bd0b9cd0b6
comparison
equal deleted inserted replaced
23392:b3a816d3b844 23393:1d4ce2d19e52
20 * or visit www.oracle.com if you need additional information or have any 20 * or visit www.oracle.com if you need additional information or have any
21 * questions. 21 * questions.
22 */ 22 */
23 package jdk.vm.ci.meta; 23 package jdk.vm.ci.meta;
24 24
25 import java.io.PrintStream;
26 import java.lang.reflect.Field; 25 import java.lang.reflect.Field;
27 import java.lang.reflect.Modifier; 26 import java.lang.reflect.Modifier;
28 import java.util.ArrayDeque;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Comparator;
32 import java.util.Deque;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Set;
36 27
37 /** 28 /**
38 * Miscellaneous collection of utility methods used by {@code jdk.vm.ci.meta} and its clients. 29 * Miscellaneous collection of utility methods used by {@code jdk.vm.ci.meta} and its clients.
39 */ 30 */
40 public class MetaUtil { 31 public class MetaUtil {
41
42 private static class ClassInfo {
43 public long totalSize;
44 public long instanceCount;
45
46 @Override
47 public String toString() {
48 return "totalSize=" + totalSize + ", instanceCount=" + instanceCount;
49 }
50 }
51
52 /**
53 * Returns the number of bytes occupied by this constant value or constant object and
54 * recursively all values reachable from this value.
55 *
56 * @param constant the constant whose bytes should be measured
57 * @param printTopN print total size and instance count of the top n classes is desired
58 * @return the number of bytes occupied by this constant
59 */
60 public static long getMemorySizeRecursive(MetaAccessProvider access, ConstantReflectionProvider constantReflection, JavaConstant constant, PrintStream out, int printTopN) {
61 Set<JavaConstant> marked = new HashSet<>();
62 Deque<JavaConstant> stack = new ArrayDeque<>();
63 if (constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) {
64 marked.add(constant);
65 }
66 final HashMap<ResolvedJavaType, ClassInfo> histogram = new HashMap<>();
67 stack.push(constant);
68 long sum = 0;
69 while (!stack.isEmpty()) {
70 JavaConstant c = stack.pop();
71 long memorySize = access.getMemorySize(constant);
72 sum += memorySize;
73 if (c.getJavaKind() == JavaKind.Object && c.isNonNull()) {
74 ResolvedJavaType clazz = access.lookupJavaType(c);
75 if (!histogram.containsKey(clazz)) {
76 histogram.put(clazz, new ClassInfo());
77 }
78 ClassInfo info = histogram.get(clazz);
79 info.instanceCount++;
80 info.totalSize += memorySize;
81 ResolvedJavaType type = access.lookupJavaType(c);
82 if (type.isArray()) {
83 if (!type.getComponentType().isPrimitive()) {
84 int length = constantReflection.readArrayLength(c);
85 for (int i = 0; i < length; i++) {
86 JavaConstant value = constantReflection.readArrayElement(c, i);
87 pushConstant(marked, stack, value);
88 }
89 }
90 } else {
91 ResolvedJavaField[] instanceFields = type.getInstanceFields(true);
92 for (ResolvedJavaField f : instanceFields) {
93 if (f.getJavaKind() == JavaKind.Object) {
94 JavaConstant value = constantReflection.readFieldValue(f, c);
95 pushConstant(marked, stack, value);
96 }
97 }
98 }
99 }
100 }
101 ArrayList<ResolvedJavaType> clazzes = new ArrayList<>();
102 clazzes.addAll(histogram.keySet());
103 Collections.sort(clazzes, new Comparator<ResolvedJavaType>() {
104
105 @Override
106 public int compare(ResolvedJavaType o1, ResolvedJavaType o2) {
107 long l1 = histogram.get(o1).totalSize;
108 long l2 = histogram.get(o2).totalSize;
109 if (l1 > l2) {
110 return -1;
111 } else if (l1 == l2) {
112 return 0;
113 } else {
114 return 1;
115 }
116 }
117 });
118
119 int z = 0;
120 for (ResolvedJavaType c : clazzes) {
121 if (z > printTopN) {
122 break;
123 }
124 out.println("Class " + c + ", " + histogram.get(c));
125 ++z;
126 }
127
128 return sum;
129 }
130
131 private static void pushConstant(Set<JavaConstant> marked, Deque<JavaConstant> stack, JavaConstant value) {
132 if (value.isNonNull()) {
133 if (!marked.contains(value)) {
134 marked.add(value);
135 stack.push(value);
136 }
137 }
138 }
139
140 /**
141 * Calls {@link JavaType#resolve(ResolvedJavaType)} on an array of types.
142 */
143 public static ResolvedJavaType[] resolveJavaTypes(JavaType[] types, ResolvedJavaType accessingClass) {
144 ResolvedJavaType[] result = new ResolvedJavaType[types.length];
145 for (int i = 0; i < result.length; i++) {
146 result[i] = types[i].resolve(accessingClass);
147 }
148 return result;
149 }
150 32
151 /** 33 /**
152 * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for 34 * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for
153 * anonymous and local classes. 35 * anonymous and local classes.
154 * 36 *
182 return name; 64 return name;
183 } 65 }
184 return name.substring(index + 1); 66 return name.substring(index + 1);
185 } 67 }
186 68
187 static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { 69 /**
70 * Converts a type name in internal form to an external form.
71 *
72 * @param name the internal name to convert
73 * @param qualified whether the returned name should be qualified with the package name
74 * @param classForNameCompatible specifies if the returned name for array types should be in
75 * {@link Class#forName(String)} format (e.g., {@code "[Ljava.lang.Object;"},
76 * {@code "[[I"}) or in Java source code format (e.g., {@code "java.lang.Object[]"},
77 * {@code "int[][]"} ).
78 */
79 public static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) {
188 switch (name.charAt(0)) { 80 switch (name.charAt(0)) {
189 case 'L': { 81 case 'L': {
190 String result = name.substring(1, name.length() - 1).replace('/', '.'); 82 String result = name.substring(1, name.length() - 1).replace('/', '.');
191 if (!qualified) { 83 if (!qualified) {
192 final int lastDot = result.lastIndexOf('.'); 84 final int lastDot = result.lastIndexOf('.');
205 return JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)).getJavaName(); 97 return JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)).getJavaName();
206 } 98 }
207 } 99 }
208 100
209 /** 101 /**
210 * Turns an class name in internal format into a resolved Java type.
211 */
212 public static ResolvedJavaType classForName(String internal, MetaAccessProvider metaAccess, ClassLoader cl) {
213 JavaKind k = JavaKind.fromTypeString(internal);
214 try {
215 String n = internalNameToJava(internal, true, true);
216 return metaAccess.lookupJavaType(k.isPrimitive() ? k.toJavaClass() : Class.forName(n, true, cl));
217 } catch (ClassNotFoundException cnfe) {
218 throw new IllegalArgumentException("could not instantiate class described by " + internal, cnfe);
219 }
220 }
221
222 /**
223 * Convenient shortcut for calling 102 * Convenient shortcut for calling
224 * {@link #appendLocation(StringBuilder, ResolvedJavaMethod, int)} without having to supply a 103 * {@link #appendLocation(StringBuilder, ResolvedJavaMethod, int)} without having to supply a
225 * {@link StringBuilder} instance and convert the result to a string. 104 * {@link StringBuilder} instance and convert the result to a string.
226 */ 105 */
227 public static String toLocation(ResolvedJavaMethod method, int bci) { 106 public static String toLocation(ResolvedJavaMethod method, int bci) {
335 } 214 }
336 return result.toString(); 215 return result.toString();
337 } 216 }
338 217
339 /** 218 /**
340 * Prepends the String {@code indentation} to every line in String {@code lines}, including a
341 * possibly non-empty line following the final newline.
342 */
343 public static String indent(String lines, String indentation) {
344 if (lines.length() == 0) {
345 return lines;
346 }
347 final String newLine = "\n";
348 if (lines.endsWith(newLine)) {
349 return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine;
350 }
351 return indentation + lines.replace(newLine, newLine + indentation);
352 }
353
354 /**
355 * Gets a string representation of an object based soley on its class and its 219 * Gets a string representation of an object based soley on its class and its
356 * {@linkplain System#identityHashCode(Object) identity hash code}. This avoids and calls to 220 * {@linkplain System#identityHashCode(Object) identity hash code}. This avoids and calls to
357 * virtual methods on the object such as {@link Object#hashCode()}. 221 * virtual methods on the object such as {@link Object#hashCode()}.
358 */ 222 */
359 public static String identityHashCodeString(Object obj) { 223 public static String identityHashCodeString(Object obj) {