package jdk.tools.jaotc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
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.HotSpotResolvedJavaMethod;
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.tools.jaotc.AOTDynamicTypeStore.AdapterLocation;
import jdk.tools.jaotc.AOTDynamicTypeStore.AppendixLocation;
import jdk.tools.jaotc.AOTDynamicTypeStore.Location;
final class AOTCompiledClass {
private static AOTDynamicTypeStore dynoStore;
static void setDynamicTypeStore(AOTDynamicTypeStore s) {
dynoStore = s;
}
static class AOTKlassData {
private int gotIndex;
private int classId;
private int compiledMethodsOffset;
private int dependentMethodsOffset;
private final String metadataName;
HotSpotResolvedObjectType type;
private ArrayList<CompiledMethodInfo> dependentMethods;
AOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type, int classId) {
this.dependentMethods = new ArrayList<>();
this.classId = classId;
this.type = type;
this.metadataName = type.isAnonymous() ? "anon<"+ classId + ">": type.getName();
this.gotIndex = binaryContainer.addTwoSlotKlassSymbol(metadataName);
this.compiledMethodsOffset = -1;
this.dependentMethodsOffset = -1;
}
private String[] getMetaspaceNames() {
String name = metadataName;
Set<Location> locs = dynoStore.getDynamicClassLocationsForType(type);
if (locs == null) {
return new String[] {name};
} else {
ArrayList<String> names = new ArrayList<String>();
names.add(name);
for (Location l : locs) {
HotSpotResolvedObjectType cpType = l.getHolder();
AOTKlassData data = getAOTKlassData(cpType);
if (data == null) {
continue;
}
int cpi = l.getCpi();
String location = "<"+ data.classId + ":" + cpi + ">";
if (l instanceof AdapterLocation) {
names.add("adapter" + location);
AdapterLocation a = (AdapterLocation)l;
names.add("adapter:" + a.getMethodId() + location);
} else {
assert l instanceof AppendixLocation;
names.add("appendix" + location);
}
}
return names.toArray(new String[names.size()]);
}
}
HotSpotResolvedObjectType getType() {
return type;
}
String getMetadataName() {
return metadataName;
}
synchronized boolean addDependentMethod(CompiledMethodInfo cm) {
return dependentMethods.add(cm);
}
ArrayList<CompiledMethodInfo> getDependentMethods() {
return dependentMethods;
}
boolean hasDependentMethods() {
return !dependentMethods.isEmpty();
}
void setCompiledMethodsOffset(int offset) {
compiledMethodsOffset = offset;
}
protected void putAOTKlassData(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
int cntDepMethods = dependentMethods.size();
ReadOnlyDataContainer dependenciesContainer = binaryContainer.getKlassesDependenciesContainer();
this.dependentMethodsOffset = BinaryContainer.addMethodsCount(cntDepMethods, dependenciesContainer);
for (CompiledMethodInfo methodInfo : dependentMethods) {
dependenciesContainer.appendInt(methodInfo.getCodeId());
}
verify();
int offset = container.getByteStreamSize();
for (String name : getMetaspaceNames()) {
container.createSymbol(offset, Kind.OBJECT, Binding.GLOBAL, 0, name);
}
container.appendInt(gotIndex).
appendInt(classId).
appendInt(compiledMethodsOffset).
appendInt(dependentMethodsOffset).
appendLong(type.getFingerprint());
}
private void verify() {
String name = type.getName();
assert gotIndex > 0 : "incorrect gotIndex: " + gotIndex + " for klass: " + name;
long fingerprint = type.getFingerprint();
assert type.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;
private static HashMap<String, AOTKlassData> klassData = new HashMap<>();
private ArrayList<ResolvedJavaMethod> methods = new ArrayList<>();
private ArrayList<CompiledMethodInfo> compiledMethods;
private final boolean representsStubs;
private static int classesCount = 0;
AOTCompiledClass(ArrayList<CompiledMethodInfo> compiledMethods) {
this.resolvedJavaType = null;
this.compiledMethods = compiledMethods;
this.representsStubs = true;
}
AOTCompiledClass(ResolvedJavaType resolvedJavaType) {
this.resolvedJavaType = (HotSpotResolvedObjectType) resolvedJavaType;
this.compiledMethods = new ArrayList<>();
this.representsStubs = false;
}
ResolvedJavaType getResolvedJavaType() {
return resolvedJavaType;
}
ArrayList<ResolvedJavaMethod> getMethods() {
ArrayList<ResolvedJavaMethod> m = methods;
methods = null;
return m;
}
static int getClassesCount() {
return classesCount;
}
int getMethodCount() {
return methods.size();
}
void addMethod(ResolvedJavaMethod method) {
methods.add(method);
}
boolean hasMethods() {
return !methods.isEmpty();
}
synchronized boolean addCompiledMethod(CompiledMethodInfo cm) {
return compiledMethods.add(cm);
}
ArrayList<CompiledMethodInfo> getCompiledMethods() {
return compiledMethods;
}
boolean hasCompiledMethods() {
return !compiledMethods.isEmpty();
}
synchronized static AOTKlassData addAOTKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
String name = type.getName();
AOTKlassData data = klassData.get(name);
if (data != null) {
assert data.getType() == type : "duplicate classes for name " + name;
} else {
data = new AOTKlassData(binaryContainer, type, classesCount++);
klassData.put(name, data);
}
return data;
}
private synchronized static AOTKlassData getAOTKlassData(String name) {
return klassData.get(name);
}
synchronized static AOTKlassData getAOTKlassData(HotSpotResolvedObjectType type) {
String name = type.getName();
AOTKlassData data = getAOTKlassData(name);
assert data == null || data.getType() == type : "duplicate classes for name " + name;
return data;
}
void addAOTKlassData(BinaryContainer binaryContainer) {
for (CompiledMethodInfo methodInfo : compiledMethods) {
methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods();
if (inlinees != null) {
for (ResolvedJavaMethod m : inlinees) {
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
}
}
ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields();
if (fields != null) {
for (ResolvedJavaField f : fields) {
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
}
}
}
}
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 for super " + s.getName() + " needed for " + type.getName();
}
for (HotSpotResolvedObjectType i : type.getInterfaces()) {
assert getAOTKlassData(i) != null : "fingerprint for interface " + i.getName() + " needed for " + type.getName();
}
}
return old;
}
HotSpotResolvedObjectType s = type.getSuperclass();
if (s != null) {
addFingerprintKlassData(binaryContainer, s);
}
for (HotSpotResolvedObjectType i : type.getInterfaces()) {
addFingerprintKlassData(binaryContainer, i);
}
return addAOTKlassData(binaryContainer, type);
}
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 = getAOTKlassData(resolvedJavaType);
assert data != null : "missing data for klass: " + name;
int cntDepMethods = data.dependentMethods.size();
assert cntDepMethods > 0 : "no dependent methods for compiled klass: " + name;
data.setCompiledMethodsOffset(startMethods);
}
static void putAOTKlassData(BinaryContainer binaryContainer) {
Set<HotSpotResolvedObjectType> dynoTypes = dynoStore.getDynamicTypes();
if (dynoTypes != null) {
for (HotSpotResolvedObjectType dynoType : dynoTypes) {
addFingerprintKlassData(binaryContainer, dynoType);
}
}
ReadOnlyDataContainer container = binaryContainer.getKlassesOffsetsContainer();
for (AOTKlassData data : klassData.values()) {
data.putAOTKlassData(binaryContainer, container);
}
}
static HotSpotResolvedObjectType getType(Object ref) {
return (ref instanceof HotSpotResolvedObjectType) ?
(HotSpotResolvedObjectType)ref :
((HotSpotResolvedJavaMethod)ref).getDeclaringClass();
}
static String metadataName(HotSpotResolvedObjectType type) {
AOTKlassData data = getAOTKlassData(type);
assert data != null : "no data for " + type;
return getAOTKlassData(type).getMetadataName();
}
private static String metadataName(HotSpotResolvedJavaMethod m) {
return metadataName(m.getDeclaringClass()) + "." + m.getName() + m.getSignature().toMethodDescriptor();
}
static String metadataName(Object ref) {
if (ref instanceof HotSpotResolvedJavaMethod) {
HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod)ref;
return metadataName(m);
} else {
assert ref instanceof HotSpotResolvedObjectType : "unexpected object type " + ref.getClass().getName();
HotSpotResolvedObjectType type = (HotSpotResolvedObjectType)ref;
return metadataName(type);
}
}
boolean representsStubs() {
return representsStubs;
}
void clear() {
for (CompiledMethodInfo c : compiledMethods) {
c.clear();
}
this.compiledMethods = null;
this.methods = null;
}
}