1 /* 2 * Copyright (c) 2016, 2018, 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 24 25 26 package jdk.tools.jaotc; 27 28 import java.util.ArrayList; 29 import java.util.HashMap; 30 import java.util.Set; 31 32 import jdk.tools.jaotc.AOTDynamicTypeStore.AdapterLocation; 33 import jdk.tools.jaotc.AOTDynamicTypeStore.AppendixLocation; 34 import jdk.tools.jaotc.AOTDynamicTypeStore.Location; 35 import jdk.tools.jaotc.binformat.BinaryContainer; 36 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 37 import jdk.tools.jaotc.binformat.Symbol.Binding; 38 import jdk.tools.jaotc.binformat.Symbol.Kind; 39 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 40 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; 41 import jdk.vm.ci.meta.ResolvedJavaField; 42 import jdk.vm.ci.meta.ResolvedJavaMethod; 43 import jdk.vm.ci.meta.ResolvedJavaType; 44 45 /** 46 * Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods 47 * of a class {@code className} are maintained in an array list. 48 */ 49 final class AOTCompiledClass { 50 51 private static AOTDynamicTypeStore dynoStore; 52 setDynamicTypeStore(AOTDynamicTypeStore s)53 static void setDynamicTypeStore(AOTDynamicTypeStore s) { 54 dynoStore = s; 55 } 56 57 static class AOTKlassData { 58 private int gotIndex; // Index (offset/8) to the got in the .metaspace.got section 59 private int classId; // Unique ID 60 // Offset to compiled methods data in the .methods.offsets section. 61 private int compiledMethodsOffset; 62 // Offset to dependent methods data. 63 private int dependentMethodsOffset; 64 65 private final String metadataName; 66 HotSpotResolvedObjectType type; 67 68 /** 69 * List of dependent compiled methods which have a reference to this class. 70 */ 71 private ArrayList<CompiledMethodInfo> dependentMethods; 72 AOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type, int classId)73 AOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type, int classId) { 74 this.dependentMethods = new ArrayList<>(); 75 this.classId = classId; 76 this.type = type; 77 this.metadataName = type.isAnonymous() ? "anon<" + classId + ">" : type.getName(); 78 this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(metadataName); 79 this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods. 80 this.dependentMethodsOffset = -1; 81 } 82 getMetaspaceNames()83 private String[] getMetaspaceNames() { 84 String name = metadataName; 85 Set<Location> locs = dynoStore.getDynamicClassLocationsForType(type); 86 if (locs == null) { 87 return new String[]{name}; 88 } else { 89 ArrayList<String> names = new ArrayList<>(); 90 names.add(name); 91 for (Location l : locs) { 92 HotSpotResolvedObjectType cpType = l.getHolder(); 93 AOTKlassData data = getAOTKlassData(cpType); 94 // We collect dynamic types at parse time, but late inlining 95 // may record types that don't make it into the final graph. 96 // We can safely ignore those here. 97 if (data == null) { 98 // Not a compiled or inlined method 99 continue; 100 } 101 int cpi = l.getCpi(); 102 String location = "<" + data.classId + ":" + cpi + ">"; 103 if (l instanceof AdapterLocation) { 104 names.add("adapter" + location); 105 AdapterLocation a = (AdapterLocation) l; 106 names.add("adapter:" + a.getMethodId() + location); 107 } else { 108 assert l instanceof AppendixLocation; 109 names.add("appendix" + location); 110 } 111 } 112 return names.toArray(new String[names.size()]); 113 } 114 } 115 getType()116 HotSpotResolvedObjectType getType() { 117 return type; 118 } 119 getMetadataName()120 String getMetadataName() { 121 return metadataName; 122 } 123 124 /** 125 * Add a method to the list of dependent methods. 126 */ addDependentMethod(CompiledMethodInfo cm)127 synchronized boolean addDependentMethod(CompiledMethodInfo cm) { 128 return dependentMethods.add(cm); 129 } 130 131 /** 132 * Return the array list of dependent class methods. 133 * 134 * @return array list of dependent methods 135 */ getDependentMethods()136 ArrayList<CompiledMethodInfo> getDependentMethods() { 137 return dependentMethods; 138 } 139 140 /** 141 * Returns if this class has dependent methods. 142 * 143 * @return true if dependent methods exist, false otherwise 144 */ hasDependentMethods()145 boolean hasDependentMethods() { 146 return !dependentMethods.isEmpty(); 147 } 148 setCompiledMethodsOffset(int offset)149 void setCompiledMethodsOffset(int offset) { 150 compiledMethodsOffset = offset; 151 } 152 putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container)153 protected void putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { 154 int cntDepMethods = dependentMethods.size(); 155 // Create array of dependent methods IDs. First word is count. 156 ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer(); 157 this.dependentMethodsOffset = BinaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer); 158 for (CompiledMethodInfo methodInfo : dependentMethods) { 159 dependenciesContainer.appendInt(methodInfo.getCodeId()); 160 } 161 162 verify(); 163 164 // @formatter:off 165 /* 166 * The offsets layout should match AOTKlassData structure in AOT JVM runtime 167 */ 168 int offset = container.getByteStreamSize(); 169 for (String name : getMetaspaceNames()) { 170 container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name); 171 } 172 // Add index (offset/8) to the got in the .metaspace.got section 173 container.appendInt(gotIndex). 174 // Add unique ID 175 appendInt(classId). 176 // Add the offset to compiled methods data in the .metaspace.offsets section. 177 appendInt(compiledMethodsOffset). 178 // Add the offset to dependent methods data in the .metaspace.offsets section. 179 appendInt(dependentMethodsOffset). 180 // Add fingerprint. 181 appendLong(type.getFingerprint()); 182 183 // @formatter:on 184 } 185 verify()186 private void verify() { 187 String name = type.getName(); 188 assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name; 189 long fingerprint = type.getFingerprint(); 190 assert type.isArray() || fingerprint != 0 : "incorrect fingerprint: " + fingerprint + " for klass: " + name; 191 assert compiledMethodsOffset >= -1 : "incorrect compiledMethodsOffset: " + compiledMethodsOffset + " for klass: " + name; 192 assert dependentMethodsOffset >= -1 : "incorrect dependentMethodsOffset: " + dependentMethodsOffset + " for klass: " + name; 193 assert classId >= 0 : "incorrect classId: " + classId + " for klass: " + name; 194 } 195 196 } 197 198 private final HotSpotResolvedObjectType resolvedJavaType; 199 200 /** 201 * List of all collected class data. 202 */ 203 private static HashMap<String, AOTKlassData> klassData = new HashMap<>(); 204 205 /** 206 * List of all methods to be compiled. 207 */ 208 private ArrayList<ResolvedJavaMethod> methods = new ArrayList<>(); 209 210 /** 211 * List of all compiled class methods. 212 */ 213 private ArrayList<CompiledMethodInfo> compiledMethods; 214 215 /** 216 * If this class represents Graal stub code. 217 */ 218 private final boolean representsStubs; 219 220 /** 221 * Classes count used to generate unique global method id. 222 */ 223 private static int classesCount = 0; 224 225 /** 226 * Construct an object with compiled methods. Intended to be used for code with no corresponding 227 * Java method name in the user application. 228 * 229 * @param compiledMethods AOT compiled methods 230 */ AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods)231 AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) { 232 this.resolvedJavaType = null; 233 this.compiledMethods = compiledMethods; 234 this.representsStubs = true; 235 } 236 237 /** 238 * Construct an object with compiled versions of the named class. 239 */ AOTCompiledClass(ResolvedJavaType resolvedJavaType)240 AOTCompiledClass(ResolvedJavaType resolvedJavaType) { 241 this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType; 242 this.compiledMethods = new ArrayList<>(); 243 this.representsStubs = false; 244 } 245 246 /** 247 * @return the ResolvedJavaType of this class 248 */ getResolvedJavaType()249 ResolvedJavaType getResolvedJavaType() { 250 return resolvedJavaType; 251 } 252 253 /** 254 * Get the list of methods which should be compiled. 255 */ getMethods()256 ArrayList<ResolvedJavaMethod> getMethods() { 257 ArrayList<ResolvedJavaMethod> m = methods; 258 methods = null; // Free - it is not used after that. 259 return m; 260 } 261 262 /** 263 * Get the number of all AOT classes. 264 */ getClassesCount()265 static int getClassesCount() { 266 return classesCount; 267 } 268 269 /** 270 * Get the number of methods which should be compiled. 271 * 272 * @return number of methods which should be compiled 273 */ getMethodCount()274 int getMethodCount() { 275 return methods.size(); 276 } 277 278 /** 279 * Add a method to the list of methods to be compiled. 280 */ addMethod(ResolvedJavaMethod method)281 void addMethod(ResolvedJavaMethod method) { 282 methods.add(method); 283 } 284 285 /** 286 * Returns if this class has methods which should be compiled. 287 * 288 * @return true if this class contains methods which should be compiled, false otherwise 289 */ hasMethods()290 boolean hasMethods() { 291 return !methods.isEmpty(); 292 } 293 294 /** 295 * Add a method to the list of compiled methods. This method needs to be thread-safe. 296 */ addCompiledMethod(CompiledMethodInfo cm)297 synchronized boolean addCompiledMethod(CompiledMethodInfo cm) { 298 return compiledMethods.add(cm); 299 } 300 301 /** 302 * Return the array list of compiled class methods. 303 * 304 * @return array list of compiled methods 305 */ getCompiledMethods()306 ArrayList<CompiledMethodInfo> getCompiledMethods() { 307 return compiledMethods; 308 } 309 310 /** 311 * Returns if this class has successfully compiled methods. 312 * 313 * @return true if methods were compiled, false otherwise 314 */ hasCompiledMethods()315 boolean hasCompiledMethods() { 316 return !compiledMethods.isEmpty(); 317 } 318 319 /** 320 * Add a klass data. 321 */ addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type)322 static synchronized AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { 323 AOTKlassData data = getAOTKlassData(type); 324 if (data == null) { 325 data = new AOTKlassData(binaryContainer, type, classesCount++); 326 klassData.put(type.getName(), data); 327 } 328 return data; 329 } 330 getAOTKlassData(HotSpotResolvedObjectType type)331 static synchronized AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) { 332 String name = type.getName(); 333 AOTKlassData data = klassData.get(name); 334 if (data != null) { 335 HotSpotResolvedObjectType oldType = data.getType(); 336 assert oldType.equals(type) : "duplicate classes for name " + type.getName(); 337 } 338 return data; 339 } 340 addAOTKlassData(BinaryContainer binaryContainer)341 void addAOTKlassData(BinaryContainer binaryContainer) { 342 for (CompiledMethodInfo methodInfo : compiledMethods) { 343 // Record methods holder 344 methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType); 345 // Record inlinee classes 346 ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods(); 347 if (inlinees != null) { 348 for (ResolvedJavaMethod m : inlinees) { 349 methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); 350 } 351 } 352 // Record classes of fields that were accessed 353 ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields(); 354 if (fields != null) { 355 for (ResolvedJavaField f : fields) { 356 methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); 357 } 358 } 359 } 360 } 361 addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type)362 static synchronized AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { 363 if (type.isArray()) { 364 return addAOTKlassData(binaryContainer, type); 365 } 366 assert type.getFingerprint() != 0 : "no fingerprint for " + type.getName(); 367 AOTKlassData old = getAOTKlassData(type); 368 if (old != null) { 369 if (areAssertionsEnabled()) { 370 HotSpotResolvedObjectType s = type.getSuperclass(); 371 if (s != null) { 372 assert getAOTKlassData(s) != null : "fingerprint for super " + s.getName() + " needed for " + type.getName(); 373 } 374 for (HotSpotResolvedObjectType i : type.getInterfaces()) { 375 assert getAOTKlassData(i) != null : "fingerprint for interface " + i.getName() + " needed for " + type.getName(); 376 } 377 } 378 return old; 379 } 380 381 // Fingerprinting requires super classes and super interfaces 382 HotSpotResolvedObjectType s = type.getSuperclass(); 383 if (s != null) { 384 addFingerprintKlassData(binaryContainer, s); 385 } 386 for (HotSpotResolvedObjectType i : type.getInterfaces()) { 387 addFingerprintKlassData(binaryContainer, i); 388 } 389 390 return addAOTKlassData(binaryContainer, type); 391 } 392 393 @SuppressWarnings("all") areAssertionsEnabled()394 private static boolean areAssertionsEnabled() { 395 boolean assertsEnabled = false; 396 // Next assignment will be executed when asserts are enabled. 397 assert assertsEnabled = true; 398 return assertsEnabled; 399 } 400 401 /* 402 * Put methods data to contained. 403 */ putMethodsData(BinaryContainer binaryContainer)404 void putMethodsData(BinaryContainer binaryContainer) { 405 ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer(); 406 int cntMethods = compiledMethods.size(); 407 int startMethods = BinaryContainer.addMethodsCount(cntMethods, container); 408 for (CompiledMethodInfo methodInfo : compiledMethods) { 409 methodInfo.addMethodOffsets(binaryContainer, container); 410 } 411 String name = resolvedJavaType.getName(); 412 AOTKlassData data = getAOTKlassData(resolvedJavaType); 413 assert data != null : "missing data for klass: " + name; 414 int cntDepMethods = data.dependentMethods.size(); 415 assert cntDepMethods > 0 : "no dependent methods for compiled klass: " + name; 416 data.setCompiledMethodsOffset(startMethods); 417 } 418 putAOTKlassData(BinaryContainer binaryContainer)419 static void putAOTKlassData(BinaryContainer binaryContainer) { 420 // record dynamic types 421 Set<HotSpotResolvedObjectType> dynoTypes = dynoStore.getDynamicTypes(); 422 if (dynoTypes != null) { 423 for (HotSpotResolvedObjectType dynoType : dynoTypes) { 424 addFingerprintKlassData(binaryContainer, dynoType); 425 } 426 } 427 428 ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer(); 429 for (AOTKlassData data : klassData.values()) { 430 data.putAOTKlassData(binaryContainer, container); 431 } 432 } 433 getType(Object ref)434 static HotSpotResolvedObjectType getType(Object ref) { 435 return (ref instanceof HotSpotResolvedObjectType) ? (HotSpotResolvedObjectType) ref : ((HotSpotResolvedJavaMethod) ref).getDeclaringClass(); 436 } 437 metadataName(HotSpotResolvedObjectType type)438 static String metadataName(HotSpotResolvedObjectType type) { 439 AOTKlassData data = getAOTKlassData(type); 440 assert data != null : "no data for " + type; 441 return getAOTKlassData(type).getMetadataName(); 442 } 443 metadataName(HotSpotResolvedJavaMethod m)444 private static String metadataName(HotSpotResolvedJavaMethod m) { 445 return metadataName(m.getDeclaringClass()) + "." + m.getName() + m.getSignature().toMethodDescriptor(); 446 } 447 metadataName(Object ref)448 static String metadataName(Object ref) { 449 if (ref instanceof HotSpotResolvedJavaMethod) { 450 HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) ref; 451 return metadataName(m); 452 } else { 453 assert ref instanceof HotSpotResolvedObjectType : "unexpected object type " + ref.getClass().getName(); 454 HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ref; 455 return metadataName(type); 456 } 457 } 458 representsStubs()459 boolean representsStubs() { 460 return representsStubs; 461 } 462 clear()463 void clear() { 464 for (CompiledMethodInfo c : compiledMethods) { 465 c.clear(); 466 } 467 this.compiledMethods = null; 468 this.methods = null; 469 } 470 471 } 472