New posts
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import java.util.Comparator;
|
||||
|
||||
/** Three Guava features whose implementations have an Unsafe fast path (see output/11): hashing, byte comparison, futures. Needs guava on the class path. */
|
||||
public class GuavaProbe {
|
||||
public static void main(String[] args) throws Exception {
|
||||
byte[] data = "unsafe-migration".getBytes();
|
||||
System.out.println("murmur3_128 = " + Hashing.murmur3_128().hashBytes(data));
|
||||
Comparator<byte[]> cmp = UnsignedBytes.lexicographicalComparator();
|
||||
System.out.println("comparator = " + cmp.getClass().getName());
|
||||
System.out.println("compare = " + Integer.signum(cmp.compare(new byte[] {1, 2, 3}, new byte[] {1, 2, 4})));
|
||||
SettableFuture<String> f = SettableFuture.create();
|
||||
f.set("ok");
|
||||
System.out.println("future = " + f.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/** Asks the running JDK which public sun.misc.Unsafe methods are deprecated for removal. Run: java tools/ListUnsafe.java */
|
||||
public class ListUnsafe {
|
||||
public static void main(String[] args) throws Exception {
|
||||
List<String> kept = new ArrayList<>();
|
||||
int removal = 0, total = 0;
|
||||
for (Method m : Class.forName("sun.misc.Unsafe").getDeclaredMethods()) {
|
||||
if (!Modifier.isPublic(m.getModifiers())) continue;
|
||||
total++;
|
||||
Deprecated d = m.getAnnotation(Deprecated.class);
|
||||
if (d != null && d.forRemoval()) removal++;
|
||||
else kept.add(m.getName() + (d != null ? " (deprecated, not for removal)" : ""));
|
||||
}
|
||||
Collections.sort(kept);
|
||||
System.out.println("java.version=" + System.getProperty("java.version"));
|
||||
System.out.println("public methods declared by sun.misc.Unsafe: " + total);
|
||||
System.out.println("deprecated for removal: " + removal);
|
||||
System.out.println("not deprecated for removal: " + kept.size());
|
||||
kept.forEach(k -> System.out.println(" " + k));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
/** A real third-party library that uses Unsafe: allocate one direct Netty buffer and use it. Compile and run with netty-common + netty-buffer on the class path. */
|
||||
public class NettyProbe {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("netty sees Unsafe: " + PlatformDependent.hasUnsafe());
|
||||
ByteBuf buf = UnpooledByteBufAllocator.DEFAULT.directBuffer(16);
|
||||
buf.writeLong(0xCAFEBABEL);
|
||||
System.out.println("direct=" + buf.isDirect() + " hasMemoryAddress=" + buf.hasMemoryAddress() + " readLong=" + Long.toHexString(buf.readLong()));
|
||||
buf.release();
|
||||
System.out.println("done");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
/** Prints the system property the JVM sets from --sun-misc-unsafe-memory-access (libraries can read it). */
|
||||
public class Prop { public static void main(String[] a){ System.out.println("sun.misc.unsafe.memory.access=" + System.getProperty("sun.misc.unsafe.memory.access")); } }
|
||||
@@ -0,0 +1,97 @@
|
||||
import java.io.InputStream;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.CodeModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.lang.classfile.instruction.ConstantInstruction;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Static scan of jars for call sites of the sun.misc.Unsafe methods that are deprecated for removal (JEP 471).
|
||||
*
|
||||
* It reads bytecode with the java.lang.classfile API (final in JDK 24). It does NOT run anything, so it reports
|
||||
* "this jar contains a call to X", never "this call is reached at run time". Which methods count as
|
||||
* "memory-access" is decided by asking the running JDK: a method is counted when its own Unsafe overload carries
|
||||
* @Deprecated(forRemoval = true).
|
||||
*
|
||||
* usage: java ScanJar.java [--classes] jar [jar ...]
|
||||
*/
|
||||
public class ScanJar {
|
||||
static final String UNSAFE = "sun/misc/Unsafe";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean perClass = false;
|
||||
List<String> jars = new ArrayList<>();
|
||||
for (String a : args) { if (a.equals("--classes")) perClass = true; else jars.add(a); }
|
||||
|
||||
Set<String> removal = new HashSet<>(); // name + descriptor of every forRemoval overload
|
||||
int total = 0;
|
||||
for (Method m : Class.forName("sun.misc.Unsafe").getDeclaredMethods()) {
|
||||
if (!java.lang.reflect.Modifier.isPublic(m.getModifiers())) continue;
|
||||
total++;
|
||||
Deprecated d = m.getAnnotation(Deprecated.class);
|
||||
if (d != null && d.forRemoval()) {
|
||||
removal.add(m.getName() + MethodType.methodType(m.getReturnType(), m.getParameterTypes()).descriptorString());
|
||||
}
|
||||
}
|
||||
System.out.println("this JDK: sun.misc.Unsafe has " + total + " public methods, " + removal.size() + " deprecated for removal");
|
||||
|
||||
for (String jar : jars) scan(jar, removal, perClass);
|
||||
}
|
||||
|
||||
static void scan(String jar, Set<String> removal, boolean perClass) throws Exception {
|
||||
int classes = 0, refClasses = 0, callSites = 0, mrClasses = 0, stringRefs = 0;
|
||||
Map<String, Integer> methods = new TreeMap<>();
|
||||
Map<String, Integer> perClassCalls = new TreeMap<>();
|
||||
Set<String> otherUnsafeCalls = new TreeSet<>();
|
||||
Set<String> mrCallers = new TreeSet<>();
|
||||
try (JarFile jf = new JarFile(jar)) {
|
||||
for (JarEntry e : Collections.list(jf.entries())) {
|
||||
String n = e.getName();
|
||||
if (!n.endsWith(".class") || n.endsWith("module-info.class")) continue;
|
||||
boolean mr = n.startsWith("META-INF/versions/");
|
||||
byte[] bytes;
|
||||
try (InputStream in = jf.getInputStream(e)) { bytes = in.readAllBytes(); }
|
||||
var cm = ClassFile.of().parse(bytes);
|
||||
classes++;
|
||||
boolean ref = false; int calls = 0;
|
||||
for (MethodModel mm : cm.methods()) {
|
||||
CodeModel code = mm.code().orElse(null);
|
||||
if (code == null) continue;
|
||||
for (var el : code) {
|
||||
if (el instanceof InvokeInstruction ii && ii.owner().asInternalName().equals(UNSAFE)) {
|
||||
ref = true;
|
||||
String key = ii.name().stringValue() + ii.typeSymbol().descriptorString();
|
||||
if (removal.contains(key)) { calls++; methods.merge(ii.name().stringValue(), 1, Integer::sum); }
|
||||
else otherUnsafeCalls.add(ii.name().stringValue());
|
||||
} else if (el instanceof ConstantInstruction.LoadConstantInstruction lc
|
||||
&& lc.constantEntry().constantValue() instanceof String s
|
||||
&& (s.equals("sun.misc.Unsafe") || s.equals("theUnsafe"))) {
|
||||
stringRefs++; ref = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ref) refClasses++;
|
||||
if (calls > 0) {
|
||||
callSites += calls;
|
||||
String cn = n.substring(0, n.length() - 6).replace('/', '.');
|
||||
perClassCalls.put(cn, calls);
|
||||
if (mr) { mrClasses++; mrCallers.add(cn); }
|
||||
}
|
||||
}
|
||||
}
|
||||
String name = jar.substring(jar.lastIndexOf('/') + 1);
|
||||
System.out.println();
|
||||
System.out.println(name + ": " + classes + " classes scanned");
|
||||
System.out.println(" classes touching sun.misc.Unsafe (call, or the strings 'sun.misc.Unsafe'/'theUnsafe'): " + refClasses);
|
||||
System.out.println(" classes calling a removal-deprecated Unsafe method: " + perClassCalls.size() + " (" + callSites + " call sites, " + methods.size() + " distinct methods)");
|
||||
if (!methods.isEmpty()) System.out.println(" methods: " + methods);
|
||||
if (!otherUnsafeCalls.isEmpty()) System.out.println(" other (not deprecated for removal) Unsafe methods called: " + otherUnsafeCalls);
|
||||
if (!mrCallers.isEmpty()) System.out.println(" of those classes, under META-INF/versions: " + mrCallers.size());
|
||||
if (perClass) perClassCalls.forEach((k, v) -> System.out.println(" " + k + " " + v));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user