8336489: Track scoped accesses in JVMCI compiled code

Reviewed-by: dnsimon, never
This commit is contained in:
Carlo Refice 2024-08-05 14:09:54 +00:00
parent 7e925d727f
commit c095c0e6a5
11 changed files with 72 additions and 6 deletions

View File

@ -722,6 +722,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
jint entry_bci = -1;
JVMCICompileState* compile_state = nullptr;
bool has_unsafe_access = false;
bool has_scoped_access = false;
jint id = -1;
if (is_nmethod) {
@ -729,6 +730,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
entry_bci = is_nmethod ? stream->read_s4("entryBCI") : -1;
compile_state = (JVMCICompileState*) stream->read_u8("compileState");
has_unsafe_access = stream->read_bool("hasUnsafeAccess");
has_scoped_access = stream->read_bool("hasScopedAccess");
id = stream->read_s4("id");
}
stream->set_code_desc(name, method);
@ -795,6 +797,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
id,
_has_monitors,
has_unsafe_access,
has_scoped_access,
_has_wide_vector,
compiled_code,
mirror,

View File

@ -2078,6 +2078,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
int compile_id,
bool has_monitors,
bool has_unsafe_access,
bool has_scoped_access,
bool has_wide_vector,
JVMCIObject compiled_code,
JVMCIObject nmethod_mirror,
@ -2183,7 +2184,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
nm->set_has_unsafe_access(has_unsafe_access);
nm->set_has_wide_vectors(has_wide_vector);
nm->set_has_monitors(has_monitors);
nm->set_has_scoped_access(true); // conservative
nm->set_has_scoped_access(has_scoped_access);
JVMCINMethodData* data = nm->jvmci_nmethod_data();
assert(data != nullptr, "must be");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -452,6 +452,7 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
int compile_id,
bool has_monitors,
bool has_unsafe_access,
bool has_scoped_access,
bool has_wide_vector,
JVMCIObject compiled_code,
JVMCIObject nmethod_mirror,

View File

@ -655,6 +655,7 @@
declare_constant(ConstMethodFlags::_misc_intrinsic_candidate) \
declare_constant(ConstMethodFlags::_misc_reserved_stack_access) \
declare_constant(ConstMethodFlags::_misc_changes_current_thread) \
declare_constant(ConstMethodFlags::_misc_is_scoped) \
\
declare_constant(CounterData::count_off) \
\

View File

@ -563,6 +563,7 @@ final class HotSpotCompiledCodeStream implements AutoCloseable {
writeInt("entryBCI", nmethod.entryBCI);
writeLong("compileState", nmethod.compileState);
writeBoolean("hasUnsafeAccess", nmethod.hasUnsafeAccess);
writeBoolean("hasScopedAccess", nmethod.hasScopedAccess());
writeInt("id", nmethod.id);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -100,4 +100,22 @@ public final class HotSpotCompiledNmethod extends HotSpotCompiledCode {
public String getInstallationFailureMessage() {
return installationFailureMessage;
}
/**
* Determines if {@code methods} contains at least one entry for which {@code HotSpotResolvedJavaMethod.isScoped()} returns true.
*/
public boolean hasScopedAccess() {
if (methods == null) {
return false;
}
for (ResolvedJavaMethod method : methods) {
if (method instanceof HotSpotResolvedJavaMethod hotSpotMethod) {
if (hotSpotMethod.isScoped()) {
return true;
}
}
}
return false;
}
}

View File

@ -170,7 +170,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
* @return flags of this method
*/
private int getFlags() {
return UNSAFE.getShort(getMethodPointer() + config().methodFlagsOffset);
return UNSAFE.getInt(getMethodPointer() + config().methodFlagsOffset);
}
/**
@ -179,7 +179,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
* @return flags of this method's ConstMethod
*/
private int getConstMethodFlags() {
return UNSAFE.getChar(getConstMethod() + config().constMethodFlagsOffset);
return UNSAFE.getInt(getConstMethod() + config().constMethodFlagsOffset);
}
@Override
@ -324,6 +324,17 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
return (getConstMethodFlags() & config().constMethodFlagsReservedStackAccess) != 0;
}
/**
* Returns true if this method has a
* {@code jdk.internal.misc.ScopedMemoryAccess.Scoped} annotation.
*
* @return true if Scoped annotation present, false otherwise
*/
@Override
public boolean isScoped() {
return (getConstMethodFlags() & config().constMethodFlagsIsScoped) != 0;
}
/**
* Sets flags on {@code method} indicating that it should never be inlined or compiled by the
* VM.

View File

@ -194,6 +194,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
final int constMethodFlagsReservedStackAccess = getConstant("ConstMethodFlags::_misc_reserved_stack_access", Integer.class);
final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class);
final int constMethodFlagsIntrinsicCandidate = getConstant("ConstMethodFlags::_misc_intrinsic_candidate", Integer.class);
final int constMethodFlagsIsScoped = getConstant("ConstMethodFlags::_misc_is_scoped", Integer.class);
final int constMethodHasLineNumberTable = getConstant("ConstMethodFlags::_misc_has_linenumber_table", Integer.class);
final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_table", Integer.class);
final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class);

View File

@ -463,6 +463,16 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
return getDeclaringClass().isJavaLangObject() && getName().equals("<init>");
}
/**
* Returns true if this method has a
* {@code jdk.internal.misc.ScopedMemoryAccess.Scoped} annotation.
*
* @return true if Scoped annotation present, false otherwise.
*/
default boolean isScoped() {
throw new UnsupportedOperationException();
}
/**
* Gets a speculation log that can be used when compiling this method to make new speculations
* and query previously failed speculations. The implementation may return a new

View File

@ -475,6 +475,24 @@ public class TestResolvedJavaMethod extends MethodUniverse {
}
}
@Test
public void isScopedTest() throws NoSuchMethodException, ClassNotFoundException {
// Must use reflection as ScopedMemoryAccess$Scoped is package-private
Class<? extends Annotation> scopedAnnotationClass = Class.forName("jdk.internal.misc.ScopedMemoryAccess$Scoped").asSubclass(Annotation.class);
boolean scopedMethodFound = false;
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
ResolvedJavaMethod m = e.getValue();
Method key = e.getKey();
boolean expect = key.isAnnotationPresent(scopedAnnotationClass);
boolean actual = m.isScoped();
assertEquals(m.toString(), expect, actual);
if (expect) {
scopedMethodFound = true;
}
}
assertTrue("At least one scoped method must be present", scopedMethodFound);
}
abstract static class UnlinkedType {
abstract void abstractMethod();

View File

@ -51,6 +51,7 @@ import java.util.stream.Collectors;
import org.junit.Test;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.MetaAccessProvider;
@ -115,7 +116,7 @@ public class TypeUniverse {
byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class,
ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class,
HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, InnerClass.class, InnerStaticClass.class,
InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class};
InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class, ScopedMemoryAccess.class};
for (Class<?> c : initialClasses) {
addClass(c);
}