/*
 * Copyright (c) 2016, 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.tools.jaotc;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;

import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;

Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods of a class className are maintained in an array list.
/** * Class encapsulating Graal-compiled output of a Java class. The compilation result of all methods * of a class {@code className} are maintained in an array list. */
public class AOTCompiledClass { public static class AOTKlassData { int gotIndex; // Index (offset/8) to the got in the .metaspace.got section int classId; // Unique ID // Offset to compiled methods data in the .methods.offsets section. int compiledMethodsOffset; // Offset to dependent methods data. int dependentMethodsOffset; long fingerprint; // Class fingerprint private final String name; private boolean isArray;
List of dependent compiled methods which have a reference to this class.
/** * List of dependent compiled methods which have a reference to this class. */
private ArrayList<CompiledMethodInfo> dependentMethods; public AOTKlassData(BinaryContainer binaryContainer, String name, long fingerprint, int classId) { this.dependentMethods = new ArrayList<>(); this.classId = classId; this.fingerprint = fingerprint; this.gotIndex = binaryContainer.addTwoSlotMetaspaceSymbol(name); this.compiledMethodsOffset = -1; // Not compiled classes do not have compiled methods. this.dependentMethodsOffset = -1; this.name = name; this.isArray = name.length() > 0 && name.charAt(0) == '['; } public long getFingerprint() { return fingerprint; }
Add a method to the list of dependent methods.
/** * Add a method to the list of dependent methods. */
public synchronized boolean addDependentMethod(CompiledMethodInfo cm) { return dependentMethods.add(cm); }
Return the array list of dependent class methods.
Returns:array list of dependent methods
/** * Return the array list of dependent class methods. * * @return array list of dependent methods */
public ArrayList<CompiledMethodInfo> getDependentMethods() { return dependentMethods; }
Returns if this class has dependent methods.
Returns:true if dependent methods exist, false otherwise
/** * Returns if this class has dependent methods. * * @return true if dependent methods exist, false otherwise */
public boolean hasDependentMethods() { return !dependentMethods.isEmpty(); } public void setCompiledMethodsOffset(int offset) { compiledMethodsOffset = offset; } protected void putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { int cntDepMethods = dependentMethods.size(); // Create array of dependent methods IDs. First word is count. ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer(); this.dependentMethodsOffset = binaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer); for (CompiledMethodInfo methodInfo : dependentMethods) { dependenciesContainer.appendInt(methodInfo.getCodeId()); } verify(); // @formatter:off /* * The offsets layout should match AOTKlassData structure in AOT JVM runtime */ int offset = container.getByteStreamSize(); container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name); // Add index (offset/8) to the got in the .metaspace.got section container.appendInt(gotIndex). // Add unique ID appendInt(classId). // Add the offset to compiled methods data in the .metaspace.offsets section. appendInt(compiledMethodsOffset). // Add the offset to dependent methods data in the .metaspace.offsets section. appendInt(dependentMethodsOffset). // Add fingerprint. appendLong(fingerprint); // @formatter:on } private void verify() { assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name; assert isArray || fingerprint != 0 : "incorrect fingerprint: " + fingerprint + " for klass: " + name; assert compiledMethodsOffset >= -1 : "incorrect compiledMethodsOffset: " + compiledMethodsOffset + " for klass: " + name; assert dependentMethodsOffset >= -1 : "incorrect dependentMethodsOffset: " + dependentMethodsOffset + " for klass: " + name; assert classId >= 0 : "incorrect classId: " + classId + " for klass: " + name; } } private final HotSpotResolvedObjectType resolvedJavaType;
List of all collected class data.
/** * List of all collected class data. */
private static Map<String, AOTKlassData> klassData = new HashMap<>();
List of all methods to be compiled.
/** * List of all methods to be compiled. */
private ArrayList<ResolvedJavaMethod> methods = new ArrayList<>();
List of all compiled class methods.
/** * List of all compiled class methods. */
private ArrayList<CompiledMethodInfo> compiledMethods;
If this class represents Graal stub code.
/** * If this class represents Graal stub code. */
private final boolean representsStubs;
Classes count used to generate unique global method id.
/** * Classes count used to generate unique global method id. */
private static int classesCount = 0;
Construct an object with compiled methods. Intended to be used for code with no corresponding Java method name in the user application.
Params:
  • compiledMethods – AOT compiled methods
/** * Construct an object with compiled methods. Intended to be used for code with no corresponding * Java method name in the user application. * * @param compiledMethods AOT compiled methods */
public AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) { this.resolvedJavaType = null; this.compiledMethods = compiledMethods; this.representsStubs = true; }
Construct an object with compiled versions of the named class.
/** * Construct an object with compiled versions of the named class. */
public AOTCompiledClass(ResolvedJavaType resolvedJavaType) { this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType; this.compiledMethods = new ArrayList<>(); this.representsStubs = false; }
Returns:the ResolvedJavaType of this class
/** * @return the ResolvedJavaType of this class */
public ResolvedJavaType getResolvedJavaType() { return resolvedJavaType; }
Get the list of methods which should be compiled.
/** * Get the list of methods which should be compiled. */
public ArrayList<ResolvedJavaMethod> getMethods() { ArrayList<ResolvedJavaMethod> m = methods; methods = null; // Free - it is not used after that. return m; }
Get the number of all AOT classes.
/** * Get the number of all AOT classes. */
public static int getClassesCount() { return classesCount; }
Get the number of methods which should be compiled.
Returns:number of methods which should be compiled
/** * Get the number of methods which should be compiled. * * @return number of methods which should be compiled */
public int getMethodCount() { return methods.size(); }
Add a method to the list of methods to be compiled.
/** * Add a method to the list of methods to be compiled. */
public void addMethod(ResolvedJavaMethod method) { methods.add(method); }
Returns if this class has methods which should be compiled.
Returns:true if this class contains methods which should be compiled, false otherwise
/** * Returns if this class has methods which should be compiled. * * @return true if this class contains methods which should be compiled, false otherwise */
public boolean hasMethods() { return !methods.isEmpty(); }
Add a method to the list of compiled methods. This method needs to be thread-safe.
/** * Add a method to the list of compiled methods. This method needs to be thread-safe. */
public synchronized boolean addCompiledMethod(CompiledMethodInfo cm) { return compiledMethods.add(cm); }
Return the array list of compiled class methods.
Returns:array list of compiled methods
/** * Return the array list of compiled class methods. * * @return array list of compiled methods */
public ArrayList<CompiledMethodInfo> getCompiledMethods() { return compiledMethods; }
Returns if this class has successfully compiled methods.
Returns:true if methods were compiled, false otherwise
/** * Returns if this class has successfully compiled methods. * * @return true if methods were compiled, false otherwise */
public boolean hasCompiledMethods() { return !compiledMethods.isEmpty(); }
Add a klass data.
/** * Add a klass data. */
public synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { String name = type.getName(); long fingerprint = type.getFingerprint(); AOTKlassData data = klassData.get(name); if (data != null) { assert data.getFingerprint() == fingerprint : "incorrect fingerprint data for klass: " + name; } else { data = new AOTKlassData(binaryContainer, name, fingerprint, classesCount++); klassData.put(name, data); } return data; } public synchronized static AOTKlassData getAOTKlassData(String name) { return klassData.get(name); } public synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) { return getAOTKlassData(type.getName()); } public void addAOTKlassData(BinaryContainer binaryContainer) { for (CompiledMethodInfo methodInfo : compiledMethods) { // Record methods holder methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType); // Record inlinee classes ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods(); if (inlinees != null) { for (ResolvedJavaMethod m : inlinees) { methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); } } // Record classes of fields that were accessed ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields(); if (fields != null) { for (ResolvedJavaField f : fields) { methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); } } } } public synchronized static AOTKlassData addFingerprintKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { if (type.isArray()) { return addAOTKlassData(binaryContainer, type); } assert type.getFingerprint() != 0 : "no fingerprint for " + type.getName(); AOTKlassData old = getAOTKlassData(type); if (old != null) { boolean assertsEnabled = false; assert assertsEnabled = true; if (assertsEnabled) { HotSpotResolvedObjectType s = type.getSuperclass(); if (s != null) { assert getAOTKlassData(s) != null : "fingerprint super " + s.getName() + " needed for " + type.getName(); } for (HotSpotResolvedObjectType i : type.getInterfaces()) { assert getAOTKlassData(i) != null : "fingerprint super " + i.getName() + " needed for " + type.getName(); } } return old; } // Fingerprinting requires super classes and super interfaces HotSpotResolvedObjectType s = type.getSuperclass(); if (s != null) { addFingerprintKlassData(binaryContainer, s); } for (HotSpotResolvedObjectType i : type.getInterfaces()) { addFingerprintKlassData(binaryContainer, i); } return addAOTKlassData(binaryContainer, type); } /* * Put methods data to contained. */ public void putMethodsData(BinaryContainer binaryContainer) { ReadOnlyDataContainer container = binaryContainer.getMethodsOffsetsContainer(); int cntMethods = compiledMethods.size(); int startMethods = binaryContainer.addMethodsCount(cntMethods, container); for (CompiledMethodInfo methodInfo : compiledMethods) { methodInfo.addMethodOffsets(binaryContainer, container); } String name = resolvedJavaType.getName(); AOTKlassData data = klassData.get(name); assert data != null : "missing data for klass: " + name; assert data.getFingerprint() == resolvedJavaType.getFingerprint() : "incorrect fingerprint for klass: " + name; int cntDepMethods = data.dependentMethods.size(); assert cntDepMethods > 0 : "no dependent methods for compiled klass: " + name; data.setCompiledMethodsOffset(startMethods); } public static void putAOTKlassData(BinaryContainer binaryContainer) { ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer(); for (AOTKlassData data : klassData.values()) { data.putAOTKlassData(binaryContainer, container); } } public boolean representsStubs() { return representsStubs; } public void clear() { for (CompiledMethodInfo c : compiledMethods) { c.clear(); } this.compiledMethods = null; this.methods = null; } }