Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -1304,7 +1305,7 @@ public AnalysisMethod findConstructor(Signature signature) {
}

public Set<AnalysisMethod> getOpenTypeWorldDispatchTableMethods() {
AnalysisError.guarantee(dispatchTableMethods != null);
Objects.requireNonNull(dispatchTableMethods);
return dispatchTableMethods;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ public void persistMethodInfo(Collection<HostedMethod> methods) {
} else {
if (priorIdx != vTableIndex) {
if (generateErrorMessage()) {
String message = String.format("VTable Index Mismatch %s. prior: %s new: %s", method.format("%H.%n"), priorIdx, vTableIndex);
String message = String.format("VTable Index Mismatch %s. prior: %s new: %s", method.format("%H.%n(%p)"), priorIdx, vTableIndex);
if (logErrorMessages()) {
System.out.println(message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import com.oracle.svm.hosted.image.NativeImageHeap;
import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo;
import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo;
import com.oracle.svm.hosted.lambda.LambdaSubstitutionType;
import com.oracle.svm.hosted.lambda.StableLambdaProxyNameFeature;
import com.oracle.svm.hosted.meta.HostedField;
Expand Down Expand Up @@ -183,6 +184,14 @@ protected boolean shouldPersistMethod(AnalysisMethod method) {
return false;
}

@Override
public void persistMethod(AnalysisMethod method) {
super.persistMethod(method);

// register this method as persisted for name resolution
HostedDynamicLayerInfo.singleton().recordPersistedMethod(hUniverse.lookup(method));
}

@Override
protected void persistField(AnalysisField field, EconomicMap<String, Object> fieldMap) {
HostedField hostedField = hUniverse.lookup(field);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.word.PointerBase;
Expand All @@ -57,25 +59,29 @@
import com.oracle.svm.hosted.c.CGlobalDataFeature;
import com.oracle.svm.hosted.image.NativeImage;
import com.oracle.svm.hosted.meta.HostedMethod;
import com.oracle.svm.hosted.meta.HostedMethodNameFactory.MethodNameInfo;

import jdk.graal.compiler.debug.Assertions;

public class HostedDynamicLayerInfo extends DynamicImageLayerInfo implements LayeredImageSingleton {
private final Map<Integer, Integer> methodIdToOffsetMap;
private final ConcurrentHashMap<Integer, MethodNameInfo> methodIdToNameInfoMap;
private final CGlobalData<PointerBase> cGlobalData;
private final Set<HostedMethod> priorLayerHostedMethods = new HashSet<>();
private boolean persisted = false;

HostedDynamicLayerInfo() {
this(0, null, new HashMap<>());
this(0, null, new HashMap<>(), new ConcurrentHashMap<>());
}

public static HostedDynamicLayerInfo singleton() {
return (HostedDynamicLayerInfo) ImageSingletons.lookup(DynamicImageLayerInfo.class);
}

private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, Map<Integer, Integer> methodIdToOffsetMap) {
private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, Map<Integer, Integer> methodIdToOffsetMap, ConcurrentHashMap<Integer, MethodNameInfo> methodIdToNameInfoMap) {
super(layerNumber);
this.methodIdToOffsetMap = methodIdToOffsetMap;
this.methodIdToNameInfoMap = methodIdToNameInfoMap;
cGlobalData = codeSectionStartSymbol == null ? null : CGlobalDataFactory.forSymbol(codeSectionStartSymbol);
}

Expand All @@ -95,7 +101,23 @@ public boolean compiledInPriorLayer(AnalysisMethod aMethod) {
return methodIdToOffsetMap.containsKey(aMethod.getId());
}

void registerOffset(HostedMethod method) {
public MethodNameInfo loadMethodNameInfo(AnalysisMethod method) {
return methodIdToNameInfoMap.get(method.getId());
}

public void recordPersistedMethod(HostedMethod hMethod) {
assert !persisted : "Too late to record this information";
MethodNameInfo info = new MethodNameInfo(hMethod.getName(), hMethod.getUniqueShortName());
var prev = methodIdToNameInfoMap.put(hMethod.getWrapped().getId(), info);
// will have to change for multiple layers
assert prev == null : prev;
}

public Set<String> getReservedNames() {
return methodIdToNameInfoMap.values().stream().map(MethodNameInfo::uniqueShortName).collect(Collectors.toUnmodifiableSet());
}

void registerCompilation(HostedMethod method) {
assert BuildPhaseProvider.isCompileQueueFinished();
int offset = method.getCodeAddressOffset();
int methodID = method.getWrapped().getId();
Expand Down Expand Up @@ -143,6 +165,7 @@ boolean verifyUniqueOffsets(Collection<? extends SharedMethod> methods) {

@Override
public PersistFlags preparePersist(ImageSingletonWriter writer) {
persisted = true;
/*
* When there are multiple shared layers we will need to store the starting code offset of
* each layer.
Expand All @@ -163,20 +186,33 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) {
* Write out all method offsets.
*/
List<Integer> offsets = new ArrayList<>(methodIdToOffsetMap.size());
List<Integer> methodIDs = new ArrayList<>(methodIdToOffsetMap.size());
List<Integer> methodOffsetIds = new ArrayList<>(methodIdToOffsetMap.size());
methodIdToOffsetMap.forEach((key, value) -> {
methodIDs.add(key);
methodOffsetIds.add(key);
offsets.add(value);
});
writer.writeIntList("methodIDs", methodIDs);
writer.writeIntList("methodOffsetIDs", methodOffsetIds);
writer.writeIntList("offsets", offsets);

/*
* Write out all persisted method names
*/
List<Integer> methodNameIds = new ArrayList<>(methodIdToNameInfoMap.size());
List<String> names = new ArrayList<>(methodIdToNameInfoMap.size() * 2);
methodIdToNameInfoMap.forEach((key, value) -> {
methodNameIds.add(key);
names.add(value.name());
names.add(value.uniqueShortName());
});
writer.writeIntList("methodNameIDs", methodNameIds);
writer.writeStringList("names", names);

return PersistFlags.CREATE;
}

@SuppressWarnings("unused")
public static Object createFromLoader(ImageSingletonLoader loader) {
assert loader.readIntList("offsets").size() == loader.readIntList("methodIDs").size() : Assertions.errorMessage("Offsets and methodIDs are incompatible", loader.readIntList("offsets"),
assert loader.readIntList("offsets").size() == loader.readIntList("methodOffsetIDs").size() : Assertions.errorMessage("Offsets and methodIDs are incompatible", loader.readIntList("offsets"),
loader.readIntList("methodIDs"));

int layerNumber = loader.readInt("nextLayerNumber");
Expand All @@ -187,16 +223,32 @@ public static Object createFromLoader(ImageSingletonLoader loader) {
* Load the offsets of all methods in the prior layers.
*/
var offsets = loader.readIntList("offsets").iterator();
var methodIDs = loader.readIntList("methodIDs").iterator();
var methodOffsetIds = loader.readIntList("methodOffsetIDs").iterator();
Map<Integer, Integer> initialMethodIdToOffsetMap = new HashMap<>();

while (offsets.hasNext()) {
int methodId = methodIDs.next();
int methodId = methodOffsetIds.next();
int offset = offsets.next();
initialMethodIdToOffsetMap.put(methodId, offset);
var prev = initialMethodIdToOffsetMap.put(methodId, offset);
assert prev == null;
}

/*
* Load the names of all methods in the prior layers.
*/
var names = loader.readStringList("names").iterator();
var methodNameIds = loader.readIntList("methodNameIDs").iterator();
ConcurrentHashMap<Integer, MethodNameInfo> initialMethodIdToMethodNameMap = new ConcurrentHashMap<>();

while (methodNameIds.hasNext()) {
int methodId = methodNameIds.next();
String name = names.next();
String uniqueShortName = names.next();
var prev = initialMethodIdToMethodNameMap.put(methodId, new MethodNameInfo(name, uniqueShortName));
assert prev == null;
}

return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, initialMethodIdToOffsetMap);
return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, initialMethodIdToOffsetMap, initialMethodIdToMethodNameMap);
}
}

Expand Down Expand Up @@ -231,7 +283,7 @@ public void afterCompilation(AfterCompilationAccess access) {
assert HostedDynamicLayerInfo.singleton().verifyUniqueOffsets(config.getMethods());

for (var entry : config.getCodeCache().getOrderedCompilations()) {
HostedDynamicLayerInfo.singleton().registerOffset(entry.getLeft());
HostedDynamicLayerInfo.singleton().registerCompilation(entry.getLeft());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Function;

import org.graalvm.collections.Pair;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
import com.oracle.graal.pointsto.infrastructure.ResolvedSignature;
Expand All @@ -53,8 +47,6 @@
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.code.ImageCodeInfo;
import com.oracle.svm.core.deopt.Deoptimizer;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.graal.code.CustomCallingConventionMethod;
import com.oracle.svm.core.graal.code.ExplicitCallingConvention;
import com.oracle.svm.core.graal.code.StubCallingConvention;
Expand Down Expand Up @@ -155,7 +147,7 @@ static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, Host

private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, ResolvedSignature<HostedType> signature,
ConstantPool constantPool, ExceptionHandler[] handlers, MultiMethodKey key, Map<MultiMethodKey, MultiMethod> multiMethodMap, LocalVariableTable localVariableTable) {
Function<Integer, Pair<String, String>> nameGenerator = (collisionCount) -> {
Function<Integer, HostedMethodNameFactory.MethodNameInfo> nameGenerator = (collisionCount) -> {
String name = wrapped.wrapped.getName(); // want name w/o any multimethodkey suffix
if (key != ORIGINAL_METHOD) {
name += StableMethodNameFormatter.MULTI_METHOD_KEY_SEPARATOR + key;
Expand All @@ -165,12 +157,12 @@ private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, R
}
String uniqueShortName = SubstrateUtil.uniqueShortName(holder.getJavaClass().getClassLoader(), holder, name, signature, wrapped.isConstructor());

return Pair.create(name, uniqueShortName);
return new HostedMethodNameFactory.MethodNameInfo(name, uniqueShortName);
};

Pair<String, String> names = ImageSingletons.lookup(HostedMethodNameFactory.class).createNames(nameGenerator);
HostedMethodNameFactory.MethodNameInfo names = HostedMethodNameFactory.singleton().createNames(nameGenerator, wrapped);

return new HostedMethod(wrapped, holder, signature, constantPool, handlers, names.getLeft(), names.getRight(), localVariableTable, key, multiMethodMap);
return new HostedMethod(wrapped, holder, signature, constantPool, handlers, names.name(), names.uniqueShortName(), localVariableTable, key, multiMethodMap);
}

private static LocalVariableTable createLocalVariableTable(HostedUniverse universe, AnalysisMethod wrapped) {
Expand Down Expand Up @@ -627,31 +619,3 @@ public Collection<MultiMethod> getAllMultiMethods() {
}
}
}

@Platforms(Platform.HOSTED_ONLY.class)
@AutomaticallyRegisteredFeature
class HostedMethodNameFactory implements InternalFeature {
Map<String, Integer> methodNameCount = new ConcurrentHashMap<>();
Set<String> uniqueShortNames = ConcurrentHashMap.newKeySet();

Pair<String, String> createNames(Function<Integer, Pair<String, String>> nameGenerator) {
Pair<String, String> result = nameGenerator.apply(0);

int collisionCount = methodNameCount.merge(result.getRight(), 0, (oldValue, value) -> oldValue + 1);

if (collisionCount != 0) {
result = nameGenerator.apply(collisionCount);
}

boolean added = uniqueShortNames.add(result.getRight());
VMError.guarantee(added, "failed to generate uniqueShortName for HostedMethod: %s", result.getRight());

return result;
}

@Override
public void afterCompilation(AfterCompilationAccess access) {
methodNameCount = null;
uniqueShortNames = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024, 2024, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 com.oracle.svm.hosted.meta;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo;

@AutomaticallyRegisteredFeature
public class HostedMethodNameFactory implements InternalFeature {
private Map<String, Integer> methodNameCount = new ConcurrentHashMap<>();
private Set<String> uniqueShortNames = ConcurrentHashMap.newKeySet();
private final boolean buildingExtensionLayer = ImageLayerBuildingSupport.buildingExtensionLayer();
private Set<String> reservedUniqueShortNames = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().getReservedNames() : null;

public record MethodNameInfo(String name, String uniqueShortName) {
}

public static HostedMethodNameFactory singleton() {
return ImageSingletons.lookup(HostedMethodNameFactory.class);
}

MethodNameInfo createNames(Function<Integer, MethodNameInfo> nameGenerator, AnalysisMethod aMethod) {
MethodNameInfo result = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().loadMethodNameInfo(aMethod) : null;
if (result == null) {
MethodNameInfo initialName = nameGenerator.apply(0);
result = initialName;

do {
int collisionCount = methodNameCount.merge(initialName.uniqueShortName(), 0, (oldValue, value) -> oldValue + 1);
if (collisionCount != 0) {
result = nameGenerator.apply(collisionCount);
}
/*
* Redo if the short name is reserved.
*/
} while (buildingExtensionLayer && reservedUniqueShortNames.contains(result.uniqueShortName()));
} else {
assert reservedUniqueShortNames.contains(result.uniqueShortName()) : result;
}

boolean added = uniqueShortNames.add(result.uniqueShortName());
VMError.guarantee(added, "failed to generate uniqueShortName for HostedMethod: %s", result.uniqueShortName());

return result;
}

@Override
public void afterCompilation(AfterCompilationAccess access) {
methodNameCount = null;
uniqueShortNames = null;
reservedUniqueShortNames = null;
}
}
Loading