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;
|
||||
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,
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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) \
|
||||
\
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user