mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-29 04:28:30 +00:00
8245505: Prelink j.l.ref.Reference when loading AOT library
Reviewed-by: dlong, kvn
This commit is contained in:
parent
b189d0b918
commit
23ce03d2ca
@ -366,24 +366,30 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data
|
||||
}
|
||||
}
|
||||
|
||||
void AOTCodeHeap::link_primitive_array_klasses() {
|
||||
void AOTCodeHeap::link_klass(const Klass* klass) {
|
||||
ResourceMark rm;
|
||||
assert(klass != NULL, "Should be given a klass");
|
||||
AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), klass->signature_name());
|
||||
if (klass_data != NULL) {
|
||||
// Set both GOT cells, resolved and initialized klass pointers.
|
||||
// _got_index points to second cell - resolved klass pointer.
|
||||
_klasses_got[klass_data->_got_index-1] = (Metadata*)klass; // Initialized
|
||||
_klasses_got[klass_data->_got_index ] = (Metadata*)klass; // Resolved
|
||||
if (PrintAOT) {
|
||||
tty->print_cr("[Found %s in %s]", klass->internal_name(), _lib->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AOTCodeHeap::link_known_klasses() {
|
||||
for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
|
||||
BasicType t = (BasicType)i;
|
||||
if (is_java_primitive(t)) {
|
||||
const Klass* arr_klass = Universe::typeArrayKlassObj(t);
|
||||
AOTKlassData* klass_data = (AOTKlassData*) os::dll_lookup(_lib->dl_handle(), arr_klass->signature_name());
|
||||
if (klass_data != NULL) {
|
||||
// Set both GOT cells, resolved and initialized klass pointers.
|
||||
// _got_index points to second cell - resolved klass pointer.
|
||||
_klasses_got[klass_data->_got_index-1] = (Metadata*)arr_klass; // Initialized
|
||||
_klasses_got[klass_data->_got_index ] = (Metadata*)arr_klass; // Resolved
|
||||
if (PrintAOT) {
|
||||
tty->print_cr("[Found %s in %s]", arr_klass->internal_name(), _lib->name());
|
||||
}
|
||||
}
|
||||
link_klass(arr_klass);
|
||||
}
|
||||
}
|
||||
link_klass(SystemDictionary::Reference_klass());
|
||||
}
|
||||
|
||||
void AOTCodeHeap::register_stubs() {
|
||||
@ -590,9 +596,7 @@ void AOTCodeHeap::link_global_lib_symbols() {
|
||||
link_stub_routines_symbols();
|
||||
link_os_symbols();
|
||||
link_graal_runtime_symbols();
|
||||
|
||||
// Link primitive array klasses.
|
||||
link_primitive_array_klasses();
|
||||
link_known_klasses();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -217,7 +217,8 @@ class AOTCodeHeap : public CodeHeap {
|
||||
void link_graal_runtime_symbols();
|
||||
|
||||
void link_global_lib_symbols();
|
||||
void link_primitive_array_klasses();
|
||||
void link_klass(const Klass* klass);
|
||||
void link_known_klasses();
|
||||
void publish_aot(const methodHandle& mh, AOTMethodData* method_data, int code_id);
|
||||
|
||||
|
||||
|
||||
@ -121,7 +121,7 @@ public class ReplaceConstantNodesPhaseTest extends HotSpotGraalCompilerTest {
|
||||
new EliminateRedundantInitializationPhase().apply(graph, highTierContext);
|
||||
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
|
||||
new LoadJavaMirrorWithKlassPhase(config).apply(graph, highTierContext);
|
||||
new ReplaceConstantNodesPhase(false).apply(graph, highTierContext);
|
||||
new ReplaceConstantNodesPhase(true, false).apply(graph, highTierContext);
|
||||
Assert.assertEquals(expectedInits, graph.getNodes().filter(InitializeKlassNode.class).count());
|
||||
Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveConstantNode.class).count());
|
||||
Assert.assertEquals(expectedLoads, graph.getNodes().filter(LoadConstantIndirectlyNode.class).count());
|
||||
|
||||
@ -59,6 +59,7 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.common.LoweringPhase;
|
||||
import org.graalvm.compiler.phases.common.inlining.InliningPhase;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.graalvm.compiler.phases.tiers.LowTierContext;
|
||||
import org.graalvm.compiler.phases.tiers.MidTierContext;
|
||||
import org.graalvm.compiler.phases.tiers.Suites;
|
||||
import org.graalvm.compiler.phases.tiers.SuitesCreator;
|
||||
@ -100,7 +101,11 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
|
||||
highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue(options)));
|
||||
}
|
||||
ListIterator<BasePhase<? super MidTierContext>> midTierLowering = ret.getMidTier().findPhase(LoweringPhase.class);
|
||||
midTierLowering.add(new ReplaceConstantNodesPhase());
|
||||
midTierLowering.add(new ReplaceConstantNodesPhase(true));
|
||||
|
||||
// Replace possible constants after GC barrier expansion.
|
||||
ListIterator<BasePhase<? super LowTierContext>> lowTierLowering = ret.getLowTier().findPhase(LoweringPhase.class);
|
||||
lowTierLowering.add(new ReplaceConstantNodesPhase(false));
|
||||
|
||||
// Replace inlining policy
|
||||
if (Inline.getValue(options)) {
|
||||
|
||||
@ -28,6 +28,7 @@ import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.stri
|
||||
import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes;
|
||||
import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@ -82,6 +83,7 @@ import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
|
||||
private final boolean verifyFingerprints;
|
||||
private final boolean allowResolution;
|
||||
|
||||
static Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
|
||||
static Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
|
||||
@ -92,6 +94,7 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
static class ClassInfo {
|
||||
|
||||
private ResolvedJavaType stringType;
|
||||
private ResolvedJavaType referenceType;
|
||||
private final HashSet<ResolvedJavaType> builtIns = new HashSet<>();
|
||||
|
||||
ClassInfo(MetaAccessProvider metaAccessProvider) {
|
||||
@ -113,6 +116,7 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
builtIns.add(metaAccessProvider.lookupJavaType(longCacheClass));
|
||||
|
||||
stringType = metaAccessProvider.lookupJavaType(String.class);
|
||||
referenceType = metaAccessProvider.lookupJavaType(Reference.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,8 +317,10 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
* @param graph
|
||||
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
|
||||
* resolution.
|
||||
* @return return true if all usages of the node have been replaced
|
||||
*/
|
||||
private static void tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) {
|
||||
private static boolean tryToReplaceWithExisting(StructuredGraph graph, ConstantNode node) {
|
||||
boolean allUsagesReplaced = true;
|
||||
ScheduleResult schedule = graph.getLastSchedule();
|
||||
NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
|
||||
BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
|
||||
@ -347,16 +353,20 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
for (Block d : blockToExisting.getKeys()) {
|
||||
if (strictlyDominates(d, b)) {
|
||||
use.replaceFirstInput(node, blockToExisting.get(d));
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!replaced && allUsagesReplaced) {
|
||||
allUsagesReplaced = false;
|
||||
}
|
||||
}
|
||||
return allUsagesReplaced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} or
|
||||
* {@link ResolveConstantNode}.
|
||||
* Replace the uses of a constant with {@link ResolveConstantNode}.
|
||||
*
|
||||
* @param graph
|
||||
* @param stateMapper
|
||||
@ -366,30 +376,63 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
private static void replaceWithResolution(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) {
|
||||
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
|
||||
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
|
||||
ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
|
||||
ValueNode replacement;
|
||||
|
||||
if (type.isArray() && type.getComponentType().isPrimitive()) {
|
||||
// Special case for primitive arrays. The AOT runtime pre-resolves them, so we may
|
||||
// omit the resolution call.
|
||||
FixedWithNextNode fixedReplacement;
|
||||
if (classInfo.builtIns.contains(type)) {
|
||||
// Special case of klass constants that come from {@link BoxingSnippets}.
|
||||
fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE));
|
||||
} else {
|
||||
fixedReplacement = graph.add(new ResolveConstantNode(node));
|
||||
}
|
||||
insertReplacement(graph, stateMapper, node, fixedReplacement);
|
||||
node.replaceAtUsages(fixedReplacement, n -> !isReplacementNode(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the uses of a constant with either {@link LoadConstantIndirectlyNode} if possible.
|
||||
*
|
||||
* @param graph
|
||||
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
|
||||
* resolution.
|
||||
* @return return true if all usages of the node have been replaced
|
||||
*/
|
||||
private static boolean replaceWithLoad(StructuredGraph graph, ConstantNode node, ClassInfo classInfo) {
|
||||
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
|
||||
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
|
||||
ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
|
||||
ValueNode replacement = null;
|
||||
if ((type.isArray() && type.getComponentType().isPrimitive()) || type.equals(classInfo.referenceType)) {
|
||||
// Special case for primitive arrays and j.l.ref.Reference.
|
||||
// The AOT runtime pre-resolves them, so we may omit the resolution call.
|
||||
replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node));
|
||||
} else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) {
|
||||
// If it's a supertype of or the same class that declares the top method, we are
|
||||
// guaranteed to have it resolved already. If it's an interface, we just test for
|
||||
// equality.
|
||||
replacement = graph.addOrUnique(new LoadConstantIndirectlyNode(node));
|
||||
} else {
|
||||
FixedWithNextNode fixedReplacement;
|
||||
if (classInfo.builtIns.contains(type)) {
|
||||
// Special case of klass constants that come from {@link BoxingSnippets}.
|
||||
fixedReplacement = graph.add(new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE));
|
||||
} else {
|
||||
fixedReplacement = graph.add(new ResolveConstantNode(node));
|
||||
}
|
||||
insertReplacement(graph, stateMapper, node, fixedReplacement);
|
||||
replacement = fixedReplacement;
|
||||
}
|
||||
node.replaceAtUsages(replacement, n -> !isReplacementNode(n));
|
||||
if (replacement != null) {
|
||||
node.replaceAtUsages(replacement, n -> !isReplacementNode(n));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} has a valid
|
||||
* fingerprint.
|
||||
*
|
||||
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType}.
|
||||
*/
|
||||
private void verifyFingerprint(ConstantNode node) {
|
||||
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
|
||||
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
|
||||
if (type != null) {
|
||||
assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
|
||||
if (verifyFingerprints && checkForBadFingerprint(type)) {
|
||||
throw new GraalError("Type with bad fingerprint: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -400,17 +443,11 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
|
||||
* resolution.
|
||||
*/
|
||||
private void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) {
|
||||
private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, FrameStateMapperClosure stateMapper, ConstantNode node, ClassInfo classInfo) {
|
||||
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
|
||||
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
|
||||
|
||||
if (type != null) {
|
||||
if (verifyFingerprints && checkForBadFingerprint(type)) {
|
||||
throw new GraalError("Type with bad fingerprint: " + type);
|
||||
}
|
||||
assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
|
||||
tryToReplaceWithExisting(graph, node);
|
||||
if (anyUsagesNeedReplacement(node)) {
|
||||
if (!tryToReplaceWithExisting(graph, node) && !replaceWithLoad(graph, node, classInfo)) {
|
||||
replaceWithResolution(graph, stateMapper, node, classInfo);
|
||||
}
|
||||
} else {
|
||||
@ -418,6 +455,24 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} with a load. This
|
||||
* variant handles only constants that don't require resolution.
|
||||
*
|
||||
* @param graph
|
||||
* @param node {@link ConstantNode} containing a {@link HotSpotResolvedJavaType} that needs
|
||||
* resolution.
|
||||
*/
|
||||
private static void handleHotSpotMetaspaceConstantWithoutResolution(StructuredGraph graph, ConstantNode node, ClassInfo classInfo) {
|
||||
HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
|
||||
HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
|
||||
if (type != null) {
|
||||
replaceWithLoad(graph, node, classInfo);
|
||||
} else {
|
||||
throw new GraalError("Unsupported metaspace constant type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace an object constant with an indirect load {@link ResolveConstantNode}. Currently we
|
||||
* support only strings.
|
||||
@ -482,6 +537,7 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
*
|
||||
* @param graph
|
||||
* @param stateMapper
|
||||
* @param classInfo
|
||||
*/
|
||||
private void replaceKlassesAndObjects(StructuredGraph graph, FrameStateMapperClosure stateMapper, ClassInfo classInfo) {
|
||||
new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
|
||||
@ -489,6 +545,7 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
for (ConstantNode node : getConstantNodes(graph)) {
|
||||
Constant constant = node.asConstant();
|
||||
if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) {
|
||||
verifyFingerprint(node);
|
||||
handleHotSpotMetaspaceConstant(graph, stateMapper, node, classInfo);
|
||||
} else if (constant instanceof HotSpotObjectConstant && anyUsagesNeedReplacement(node)) {
|
||||
handleHotSpotObjectConstant(graph, stateMapper, node, classInfo);
|
||||
@ -496,18 +553,37 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace well-known klass constants with indirect loads.
|
||||
*
|
||||
* @param graph
|
||||
* @param classInfo
|
||||
*/
|
||||
private static void replaceKlassesWithoutResolution(StructuredGraph graph, ClassInfo classInfo) {
|
||||
for (ConstantNode node : getConstantNodes(graph)) {
|
||||
Constant constant = node.asConstant();
|
||||
if (constant instanceof HotSpotMetaspaceConstant && anyUsagesNeedReplacement(node)) {
|
||||
handleHotSpotMetaspaceConstantWithoutResolution(graph, node, classInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(StructuredGraph graph, CoreProviders context) {
|
||||
FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph);
|
||||
ReentrantNodeIterator.apply(stateMapper, graph.start(), null);
|
||||
if (allowResolution) {
|
||||
FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph);
|
||||
ReentrantNodeIterator.apply(stateMapper, graph.start(), null);
|
||||
|
||||
// Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
|
||||
// constants.
|
||||
replaceLoadMethodCounters(graph, stateMapper, context);
|
||||
// Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
|
||||
// constants.
|
||||
replaceLoadMethodCounters(graph, stateMapper, context);
|
||||
|
||||
// Replace object and klass constants (including the ones added in the previous pass) with
|
||||
// resolution nodes.
|
||||
replaceKlassesAndObjects(graph, stateMapper, new ClassInfo(context.getMetaAccess()));
|
||||
// Replace object and klass constants (including the ones added in the previous pass)
|
||||
// with resolution nodes.
|
||||
replaceKlassesAndObjects(graph, stateMapper, new ClassInfo(context.getMetaAccess()));
|
||||
} else {
|
||||
replaceKlassesWithoutResolution(graph, new ClassInfo(context.getMetaAccess()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -515,11 +591,12 @@ public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public ReplaceConstantNodesPhase() {
|
||||
this(true);
|
||||
public ReplaceConstantNodesPhase(boolean allowResolution) {
|
||||
this(allowResolution, true);
|
||||
}
|
||||
|
||||
public ReplaceConstantNodesPhase(boolean verifyFingerprints) {
|
||||
public ReplaceConstantNodesPhase(boolean allowResolution, boolean verifyFingerprints) {
|
||||
this.allowResolution = allowResolution;
|
||||
this.verifyFingerprints = verifyFingerprints;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user