8336489: Track scoped accesses in JVMCI compiled code
Reviewed-by: dnsimon, never
This commit is contained in:
parent
7e925d727f
commit
c095c0e6a5
@ -722,6 +722,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
|
|||||||
jint entry_bci = -1;
|
jint entry_bci = -1;
|
||||||
JVMCICompileState* compile_state = nullptr;
|
JVMCICompileState* compile_state = nullptr;
|
||||||
bool has_unsafe_access = false;
|
bool has_unsafe_access = false;
|
||||||
|
bool has_scoped_access = false;
|
||||||
jint id = -1;
|
jint id = -1;
|
||||||
|
|
||||||
if (is_nmethod) {
|
if (is_nmethod) {
|
||||||
@ -729,6 +730,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
|
|||||||
entry_bci = is_nmethod ? stream->read_s4("entryBCI") : -1;
|
entry_bci = is_nmethod ? stream->read_s4("entryBCI") : -1;
|
||||||
compile_state = (JVMCICompileState*) stream->read_u8("compileState");
|
compile_state = (JVMCICompileState*) stream->read_u8("compileState");
|
||||||
has_unsafe_access = stream->read_bool("hasUnsafeAccess");
|
has_unsafe_access = stream->read_bool("hasUnsafeAccess");
|
||||||
|
has_scoped_access = stream->read_bool("hasScopedAccess");
|
||||||
id = stream->read_s4("id");
|
id = stream->read_s4("id");
|
||||||
}
|
}
|
||||||
stream->set_code_desc(name, method);
|
stream->set_code_desc(name, method);
|
||||||
@ -795,6 +797,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
|
|||||||
id,
|
id,
|
||||||
_has_monitors,
|
_has_monitors,
|
||||||
has_unsafe_access,
|
has_unsafe_access,
|
||||||
|
has_scoped_access,
|
||||||
_has_wide_vector,
|
_has_wide_vector,
|
||||||
compiled_code,
|
compiled_code,
|
||||||
mirror,
|
mirror,
|
||||||
|
@ -2078,6 +2078,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
|
|||||||
int compile_id,
|
int compile_id,
|
||||||
bool has_monitors,
|
bool has_monitors,
|
||||||
bool has_unsafe_access,
|
bool has_unsafe_access,
|
||||||
|
bool has_scoped_access,
|
||||||
bool has_wide_vector,
|
bool has_wide_vector,
|
||||||
JVMCIObject compiled_code,
|
JVMCIObject compiled_code,
|
||||||
JVMCIObject nmethod_mirror,
|
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_unsafe_access(has_unsafe_access);
|
||||||
nm->set_has_wide_vectors(has_wide_vector);
|
nm->set_has_wide_vectors(has_wide_vector);
|
||||||
nm->set_has_monitors(has_monitors);
|
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();
|
JVMCINMethodData* data = nm->jvmci_nmethod_data();
|
||||||
assert(data != nullptr, "must be");
|
assert(data != nullptr, "must be");
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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,
|
int compile_id,
|
||||||
bool has_monitors,
|
bool has_monitors,
|
||||||
bool has_unsafe_access,
|
bool has_unsafe_access,
|
||||||
|
bool has_scoped_access,
|
||||||
bool has_wide_vector,
|
bool has_wide_vector,
|
||||||
JVMCIObject compiled_code,
|
JVMCIObject compiled_code,
|
||||||
JVMCIObject nmethod_mirror,
|
JVMCIObject nmethod_mirror,
|
||||||
|
@ -655,6 +655,7 @@
|
|||||||
declare_constant(ConstMethodFlags::_misc_intrinsic_candidate) \
|
declare_constant(ConstMethodFlags::_misc_intrinsic_candidate) \
|
||||||
declare_constant(ConstMethodFlags::_misc_reserved_stack_access) \
|
declare_constant(ConstMethodFlags::_misc_reserved_stack_access) \
|
||||||
declare_constant(ConstMethodFlags::_misc_changes_current_thread) \
|
declare_constant(ConstMethodFlags::_misc_changes_current_thread) \
|
||||||
|
declare_constant(ConstMethodFlags::_misc_is_scoped) \
|
||||||
\
|
\
|
||||||
declare_constant(CounterData::count_off) \
|
declare_constant(CounterData::count_off) \
|
||||||
\
|
\
|
||||||
|
@ -563,6 +563,7 @@ final class HotSpotCompiledCodeStream implements AutoCloseable {
|
|||||||
writeInt("entryBCI", nmethod.entryBCI);
|
writeInt("entryBCI", nmethod.entryBCI);
|
||||||
writeLong("compileState", nmethod.compileState);
|
writeLong("compileState", nmethod.compileState);
|
||||||
writeBoolean("hasUnsafeAccess", nmethod.hasUnsafeAccess);
|
writeBoolean("hasUnsafeAccess", nmethod.hasUnsafeAccess);
|
||||||
|
writeBoolean("hasScopedAccess", nmethod.hasScopedAccess());
|
||||||
writeInt("id", nmethod.id);
|
writeInt("id", nmethod.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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() {
|
public String getInstallationFailureMessage() {
|
||||||
return installationFailureMessage;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
|||||||
* @return flags of this method
|
* @return flags of this method
|
||||||
*/
|
*/
|
||||||
private int getFlags() {
|
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
|
* @return flags of this method's ConstMethod
|
||||||
*/
|
*/
|
||||||
private int getConstMethodFlags() {
|
private int getConstMethodFlags() {
|
||||||
return UNSAFE.getChar(getConstMethod() + config().constMethodFlagsOffset);
|
return UNSAFE.getInt(getConstMethod() + config().constMethodFlagsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -324,6 +324,17 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
|||||||
return (getConstMethodFlags() & config().constMethodFlagsReservedStackAccess) != 0;
|
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
|
* Sets flags on {@code method} indicating that it should never be inlined or compiled by the
|
||||||
* VM.
|
* VM.
|
||||||
|
@ -194,6 +194,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
|
|||||||
final int constMethodFlagsReservedStackAccess = getConstant("ConstMethodFlags::_misc_reserved_stack_access", Integer.class);
|
final int constMethodFlagsReservedStackAccess = getConstant("ConstMethodFlags::_misc_reserved_stack_access", Integer.class);
|
||||||
final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class);
|
final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class);
|
||||||
final int constMethodFlagsIntrinsicCandidate = getConstant("ConstMethodFlags::_misc_intrinsic_candidate", 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 constMethodHasLineNumberTable = getConstant("ConstMethodFlags::_misc_has_linenumber_table", Integer.class);
|
||||||
final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_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);
|
final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class);
|
||||||
|
@ -463,6 +463,16 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
|
|||||||
return getDeclaringClass().isJavaLangObject() && getName().equals("<init>");
|
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
|
* 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
|
* and query previously failed speculations. The implementation may return a new
|
||||||
|
@ -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 static class UnlinkedType {
|
||||||
abstract void abstractMethod();
|
abstract void abstractMethod();
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ import java.util.stream.Collectors;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import jdk.internal.misc.Unsafe;
|
import jdk.internal.misc.Unsafe;
|
||||||
|
import jdk.internal.misc.ScopedMemoryAccess;
|
||||||
import jdk.vm.ci.meta.ConstantReflectionProvider;
|
import jdk.vm.ci.meta.ConstantReflectionProvider;
|
||||||
import jdk.vm.ci.meta.JavaConstant;
|
import jdk.vm.ci.meta.JavaConstant;
|
||||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
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,
|
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,
|
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,
|
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) {
|
for (Class<?> c : initialClasses) {
|
||||||
addClass(c);
|
addClass(c);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user