<<

A Post-Apocalyptic sun.misc.Unsafe World http://www.superbwallpapers.com/fantasy/post-apocalyptic-tower-bridge-london-26546/ Chris Engelbert Twitter: @noctarius2k Jatumba!

2014, 2015, 2016, … Disclaimer This talk is not going to be negative! Disclaimer But certain things are highly speculative and or ideas might change by tomorrow! sun.misc.Scissors

http://www.underwhelmedcomic.com/wp-content/uploads/2012/03/runningdude.jpg sun.misc.Unsafe - What you (don’t) know sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE // Unsafe mechanics private static final sun.misc.Unsafe U; private static final long QBASE; private static final long QLOCK; private static final int ABASE; private static final int ASHIFT; static { try { U = sun.misc.Unsafe.getUnsafe(); Class k = WorkQueue.class; Class ak = ForkJoinTask[].class; example: QBASE = U.objectFieldOffset (k.getDeclaredField("base")); .util.concurrent.ForkJoinPool QLOCK = U.objectFieldOffset (k.getDeclaredField("qlock")); ABASE = U.arrayBaseOffset(ak); int scale = U.arrayIndexScale(ak); if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } } } sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE • Used outside as well sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE • Used outside as well (good

// Deserialization public Object readObject(InputStream is) { SomeType element = unsafe.allocateInstance(SomeType.class); element.deserializeValues(is); return element; } sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE • Used outside as well (good, bad)

# # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00000001067314b5, pid=25244, tid=5891 # # JRE version: Java(TM) SE Runtime Environment (8.0_05-b13) (build 1.8.0_05-b13) # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.5-b02 mixed mode bsd-amd64 compressed oops) # Problematic frame: # V [libjvm.dylib+0x5314b5] Unsafe_SetNativeAddress+0x36 # # An error report file with more information is saved as: # /Users/noctarius//hazelcast-only.idea/hs_err_pid25244.log # # If you would like to submit a bug report, please visit: # http://bugreport.sun.com/bugreport/crash.jsp # sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE • Used outside as well (good / bad) • Never intended for outside use sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE • Used outside as well (good / bad) • Never intended for outside use sun.misc.Unsafe - What you (don’t) know

• Internal class (sun.misc Package) • Used inside the JVM / JRE • Used outside as well (good / bad) • Never intended for outside use • Used by popular: • Applications • Frameworks • Libraries CapLogic ActivePivot Apache Ignite JRuby Liquibase Neo4j Presto Gson Disruptor Metrics (AOP) GWT Mockito Scala Robolectric OrientDB MapDB EasyMock XStream jol JMock Spock Ehcache Apache HBase Agrona Akka Hazelcast Kryo Zookeeper Cassandra XRebel LWJGL Chronicle Byte Buddy Aeron Simple Binary Encoding Apache Wink XAP Infinispan Dropwizard WildFly CapLogic ActivePivot Apache Ignite JRuby Liquibase Apache Spark Neo4j Presto Gson Disruptor Metrics (AOP) GWT Mockito Scala Robolectric Hibernate OrientDB MapDB EasyMock XStream jol Grails JMock Spock Ehcache Apache HBase Agrona Akka Netty Apache Continuum Apache Flink Hazelcast Kryo Zookeeper Cassandra XRebel LWJGL Apache Storm Apache Kafka Chronicle Byte Buddy Aeron Simple Binary Encoding Apache Wink XAP Infinispan Spring Framework Dropwizard Apache Hadoop WildFly sun.misc.Unsafe is only supported on HotSpot JVMs anyways, isn’t it? No! sun.misc.Unsafe is only supported on HotSpot JVMs anyways, isn’t it? Language URL sun.misc.Unsafe Avian ++ https://github.com/ReadyTalk/avian Yes BicaVM JavaScript https://github.com/nurv/BicaVM No Cacao C http://www.cacaojvm.org Yes Excelsior JVM C / C++ ? http://www.excelsiorjet.com Yes / ART / Android C / C++ https://source.android.com/source/index.html Yes Graal mainly Java http://openjdk.java.net/projects/graal Yes GCJ C / C++ https://gcc.gnu.org/java Yes HaikuVM C http://haiku-vm.sourceforge.net No IBM J9 C / C++ ? http://www.ibm.com/developerworks/java/jdk/index.html Yes IcedTea C / C++ http://icedtea.classpath.org/wiki/Main_Page Yes IKVM.NET C# http://www.ikvm.net Yes Jamiga C https://sourceforge.net/projects/jamiga2 No JamVM C http://jamvm.sourceforge.net Yes JatoVM C http://jatovm.org Yes JikesRVM C microkernel, Java http://www.jikesrvm.org Yes JNode C microkernel, Java http://www.jnode.org Yes JVM.go Go https://github.com/zxh0/jvm.go Yes JX C http://www4.cs.fau.de/Projects/JX/index.html No C https://github.com/kaffe/kaffe Yes NanoVM C http://harbaum.org/till/nanovm/index.shtml No OpenJDK / Oracle / Zulu C / C++ http://openjdk.java.net Yes RoboVM C / C++ / ObjC https://robovm.com Yes SAPJVM C / C++ ? http://help.sap.com/saphelp_nwce10/helpdata/en/47/ Yes Waratek Multitenant JVM C / C++ ? dc90b4ef17452289f9128b8c2bbd77/content.htmhttp://www.waratek.com Yes Zing JVM C / C++ ? https://www.azul.com/products/zing Yes Use Cases - The Good Ones! Use Cases - The Good Ones!

• Low Latency, GC Overhead Use Cases - The Good Ones!

• Low Latency, GC Overhead Unsafe unsafe = findUnsafe(); long baseAddress = unsafe.allocateMemory(8);

class Point { long offsetX = 0; long offsetY = 4;

int getX(long baseAddress) { return unsafe.getInt(baseAddress + offsetX); }

int getY(long baseAddress) { return unsafe.getInt(baseAddress + offsetY); } } Caution: Overly simplified! Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization

// Deserialization public Object readObject(InputStream is) { SomeType element = unsafe.allocateInstance(SomeType.class); element.deserializeValues(is); return element; } Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit regions Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions

long baseAddress = unsafe.allocateMemory(Long.MAX_VALUE); unsafe.putInt(baseAddress + Long.MAX_VALUE - 4, Integer.MAX_VALUE); Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations

unsafe.compareAndSwapInt(this, offsetField, oldValue, newValue); unsafe.compareAndSwapLong(this, offsetField, oldValue, newValue); unsafe.compareAndSwapObject(this, offsetField, oldObject, newObject); Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout Use Cases - The Good Ones!

Low Latency, GC Overhead class Point { • long offsetX = 0; • Fast (de-)serialization long offsetY = 4; • 64bit Memory regions } • Atomic memory operations • Efficient memory layout offsetX offsetY Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout • Fast field / memory access Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout • Fast field / memory access

long versionFieldOffset = unsafe.objectFieldOffset(versionField);

long version = unsafe.getLong(this, versionFieldOffset);

unsafe.putLong(this, versionFieldOffset, 10L); Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout • Fast field / memory access • Access to array with volatile semantics Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout • Fast field / memory access • Access to array with volatile semantics

long base = unsafe.arrayBaseOffset(int[].class); long index = unsafe.arrayIndexScale(int[].class);

unsafe.getIntVolatile(array, base + (index * 3)); Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout • Fast field / memory access • Access to array with volatile semantics • Custom memory fences Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization unsafe.fullFence(); 64bit Memory regions • unsafe.storeFence(); • Atomic memory operations • Efficient memory layout unsafe.loadFence(); • Fast field / memory access • Access to array with volatile semantics • Custom memory fences Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization • 64bit Memory regions • Atomic memory operations • Efficient memory layout • Fast field / memory access • Access to array with volatile semantics • Custom memory fences • Fast interaction with native code Use Cases - The Good Ones!

• Low Latency, GC Overhead • Fast (de-)serialization long addr = unsafe.allocateMemory(50); 64bit Memory regions copyBytes(addr, byteArray); • nativeCall(addr); • Atomic memory operations • Efficient memory layout • Fast field / memory access • Access to array with volatile semantics • Custom memory fences • Fast interaction with native code Get Access Get Access

Easy One (not working outside the JRE / JDK)

Unsafe unsafe = Unsafe.getUnsafe(); Get Access

The Ugly One private static final Unsafe UNSAFE; static { try { Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafeField.setAccessible(true); UNSAFE = (Unsafe) theUnsafeField.get(Unsafe.class);

} catch (Exception e) { // We need you! =( throw new Error(e); } } Get Access private static Unsafe findUnsafe() { try { return Unsafe.getUnsafe(); } catch (SecurityException se) { return AccessController.doPrivileged(new PrivilegedAction() { @Override public Unsafe run() { try { Class type = Unsafe.class; try { Field field = type.getDeclaredField("theUnsafe"); field.setAccessible(true); return type.cast(field.get(type));

} catch (Exception e) { The Working One for (Field field : type.getDeclaredFields()) { if (type.isAssignableFrom(field.getType())) { (at least for more than just HotSpot) field.setAccessible(true); return type.cast(field.get(type)); } } } } catch (Exception e) { throw new RuntimeException("Unsafe unavailable", e); } throw new RuntimeException("Unsafe unavailable"); } }); } } Get Access

The Tricky One private static final Unsafe UNSAFE; static { try { Constructor constructor = Unsafe.class.getDeclaredConstructor();

constructor.setAccessible(true); UNSAFE = constructor.newInstance();

} catch (Exception e) { // We need you! =( throw new Error(e); } } Get Access

Does Any Of This Feel Right? No !

Weird! No !

WAAAAAT!?!? http://mail.openjdk.java.net/pipermail/openjfx-dev/2015-April/017028.html

Let me be blunt -- sun.misc.Unsafe must die in a fire. It is -- wait for it -- Unsafe. It must go. Ignore any kind of theoretical rope and start the path to righteousness _*/now/*_. It is still years until the end of public updates to JDK 8, so we have /*years */to work this out properly. But sticking our heads in the collective sands and hoping for trivial work arounds to Unsafe is not going to work. If you're using Unsafe, this is the year to explain where the API is broken and get it straight....

Please help us kill Unsafe, kill Unsafe dead, kill Unsafe right, and do so as quickly as possible to the ultimate benefit of everyone.

Wed Apr 8 19:15:42 UTC 2015, OpenJFX Mailinglist, Donald Smith, Oracle http://mail.openjdk.java.net/pipermail/openjfx-dev/2015-April/017028.html

Let me be blunt -- sun.misc.Unsafe must die in a fire. It is -- wait for it -- Unsafe. It must go. Ignore any kind of theoretical rope and start the path to righteousness _*/now/*_. It is still years until the end of public updates to JDK 8, so we have /*years */to work this out properly. But sticking our heads in the collective sands and hoping for trivial work arounds to Unsafe is not going to work. If you're using Unsafe, this is the year to explain where the API is broken and get it straight....

Please help us kill Unsafe, kill Unsafe dead, kill Unsafe right, and do so as quickly as possible to the ultimate benefit of everyone.

Wed Apr 8 19:15:42 UTC 2015, OpenJFX Mailinglist, Donald Smith, Oracle http://mail.openjdk.java.net/pipermail/openjfx-dev/2015-April/017028.html

Let me be blunt -- sun.misc.Unsafe must die in a fire. It is -- wait for it -- Unsafe. It must go. Ignore any kind of theoretical rope and start the path to righteousness _*/now/*_. It is still years until the end of public updates to JDK 8, so we have /*years */to work this out properly. But sticking our heads in the collective sands and hoping for trivial work arounds to Unsafe is not going to work. If you're using Unsafe, this is the year to explain where the API is broken and get it straight....

Please help us kill Unsafe, kill Unsafe dead, kill Unsafe right, and do so as quickly as possible to the ultimate benefit of everyone.

Wed Apr 8 19:15:42 UTC 2015, OpenJFX Mailinglist, Donald Smith, Oracle http://mail.openjdk.java.net/pipermail/openjfx-dev/2015-April/017028.html

Let me be blunt -- sun.misc.Unsafe must die in a fire. It is -- wait for it -- Unsafe. It must go. Ignore any kind of theoretical rope and start the path to righteousness _*/now/*_. It is still years until the end of public updates to JDK 8, so we have /*years */to work this out properly. But sticking our heads in the collective sands and hoping for trivial work arounds to Unsafe is not going to work. If you're using Unsafe, this is the year to explain where the API is broken and get it straight....

Please help us kill Unsafe, kill Unsafe dead, kill Unsafe right, and do so as quickly as possible to the ultimate benefit of everyone.

Wed Apr 8 19:15:42 UTC 2015, OpenJFX Mailinglist, Donald Smith, Oracle Oracle created a new Taskforce K.U.T.T. - Kill Unsafe To Total death

Oracle created a new Taskforce http://mail.openjdk.java.net/pipermail/openjfx-dev/2015-April/017028.html

Let me be blunt -- sun.misc.Unsafe must die in a fire. It is -- wait for it -- Unsafe. It must go. Ignore any kind of theoretical rope and start the path to righteousness _*/now/*_. It is still years until the end of public updates to JDK 8, so we have /*years */to work this out properly. But sticking our heads in the collective sands and hoping for trivial work arounds to Unsafe is not going to work. If you're using Unsafe, this is the year to explain where the API is broken and get it straight....

Please help us kill Unsafe, kill Unsafe dead, kill Unsafe right, and do so as quickly as possible to the ultimate benefit of everyone.

Wed Apr 8 19:15:42 UTC 2015, OpenJFX Mailinglist, Donald Smith, Oracle So What’s Coming? Atomic Updates private static final Unsafe UNSAFE = findUnsafe(); private static long VERSION_OFFSET = findVersionOffset();

// Updated through Unsafe only! private volatile long version = 0; public long increment() { while(true) { long version = this.version; long newVersion = version + 1; if (UNSAFE.compareAndSwapLong( this, VERSION_OFFSET, version, newVersion)) {

return newVersion; } } } Atomic Updates

private final AtomicLong version = new AtomicLong(0); public long increment() { return version.incrementAndGet(); } Atomic Updates

private static final AtomicLongFieldUpdater VERSION = AtomicLongFieldUpdater.newUpdater(Record, "version");

// Updated through atomic field updater only! private volatile long version = 0; public long increment() { return VERSION.incrementAndGet(this); } Atomic Updates

private static final VarHandle VERSION = findVersionVarHandle();

// Updated through VarHandle only! private volatile long version = 0; public long increment() { return (long) VERSION.addAndGet(this, 1); } Atomic Updates

public static VarHandle findVersionVarHandle() { try { return MethodHandles.lookup(). findFieldVarHandle(Record.class, "version", long.class);

} catch (Exception e) { throw new Error(e); } } Memory Management

public long memory() { long address = UNSAFE.allocateMemory(8);

UNSAFE.putLong(address, Long.MAX_VALUE);

return UNSAFE.getLong(address); } Memory Management

public long memory() { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8);

byteBuffer.putLong(0, Long.MAX_VALUE);

return byteBuffer.getLong(0); } Memory Management

public long memory() { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8);

VarHandle bufferView = MethodHandles.byteBufferViewVarHandle(long[].class, true);

bufferView.set(byteBuffer, 0, Long.MAX_VALUE);

return bufferView.get(byteBuffer, 0); } Memory Management

public long memory() { MemoryRegion region = MemoryRegion.allocateNative ("myname", MemoryRegion.UNALIGNED, Long.MAX_VALUE);

VarHandle regionView = MethodHandles. memoryRegionViewVarHandle(long[].class, true);

regionView.set(region, 0, Long.MAX_VALUE);

return regionView.get(region, 0); } Deserialization

private static final Unsafe UNSAFE = findUnsafe(); private static final long VALUE_OFFSET = findValueOffset(); public String deserializeString() throws Exception { char[] chars = readCharsFromStream(); String allocated = (String) UNSAFE.allocateInstance(String.class); UNSAFE.putObjectVolatile(allocated, VALUE_OFFSET, chars); return allocated; } Deserialization

public String deserializeString() throws Exception { char[] chars = readCharsFromStream().freeze();

ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();

Constructor constructor = reflectionFactory .newConstructorForSerialization(String.class, char[].class);

return constructor.newInstance(chars); } Interoperability extern c { JNIEXPORT int JNICALL Java_ProcessIdentifier_getProcessId(JNIEnv *, jobject); }

JNIEXPORT int JNICALL Java_ProcessIdentifier_getProcessId(JNIEnv *env, jobject thisObj) { return getpid(); } public class ProcessIdentifier { static { System.loadLibrary("processidentifier"); }

public native void talk(); } Interoperability

interface LibC { void getpid(); } public int call() { LibC c = LibraryLoader.create(LibC.class).load("c"); return c.getpid(); } Interoperability

public void call() { MethodType intType = MethodType.methodType(int.class);

MethodHandle handle = MethodHandles .findNative(null, “getpid”, intType);

return (int) handle.invokeExact(); } Value Types

value class Point { final int x; final int y; }

// Create a Point instance Point point = makeValue(1, 2); Value Types

int[] values = new int[2]; int x = values[0]; int y = values[1]; Value Types

int[] values = new int[2]; int x = values[0]; int y = values[1];

Stack var X var Y Value Types

int[] values = new int[2]; int x = values[0]; int y = values[1]; Stack Allocation!

Stack var X var Y Specialized Generics

class Box { void set(T element) { ... };

T get() { ... }; } Specialized Generics

class Box { void set(T element) { ... };

T get() { ... }; }

Box Box${T=int}.class Box Box${T=java.lang.String}.class Box Box${T=RandomClass}.class Specialized Generics public void generics() { Box intBox = new Box<>(); intBox.set(1); int intValue = intBox.get();

Box stringBox = new Box<>(); stringBox.set("hello"); String stringValue = stringBox.get();

Box box = new Box<>(); box.set(new RandomClass()); RandomClass value = box.get(); } Arrays 2.0 int[] values = new int[Long.MAX_VALUE]; Arrays 2.0 int[] values = new int[Long.MAX_VALUE];

Arrays.chop(T[] a, int newlength); Arrays 2.0 int[] values = new int[Long.MAX_VALUE];

Arrays.chop(T[] a, int newlength);

Box[] ... = new Box[]; Arrays 2.0 int[] values = new int[Long.MAX_VALUE];

Arrays.chop(T[] a, int newlength);

Box[] ... = new Box[]; char[] frozen = new char[20L].freeze(); Arrays 2.0 int[] values = new int[Long.MAX_VALUE];

Arrays.chop(T[] a, int newlength);

Box[] ... = new Box[]; char[] frozen = new char[20L].freeze();

Point[] points = new Point[3]; Stack var X points[0] var Y

var X points[1] var Y

var X points[2] var Y Class Dynamic Class Dynamic

•Templating functionality Class Dynamic

•Templating functionality •Aspect-like approach Class Dynamic

•Templating functionality •Aspect-like approach •Group common functionality Class Dynamic

•Templating functionality •Aspect-like approach •Group common functionality •Enhanced Proxies Class Dynamic

•Templating functionality •Aspect-like approach •Group common functionality •Enhanced Proxies

R methodName(ARGS) { synchronized (this) { Collections::sychronizedMap underlying.methodName(ARGS); } } Class Dynamic

•Templating functionality •Aspect-like approach •Group common functionality •Enhanced Proxies

R methodName(ARGS) { logger.trace("Before methodname X"); Logging / Tracing underlying.methodName(ARGS); logger.trace("After methodname X"); } Class Dynamic

•Templating functionality •Aspect-like approach •Group common functionality •Enhanced Proxies

Your Use Case! SpinWait Hints SpinWait Hints

Hints the JVM that a busy spin’s upcoming SpinWait Hints

Hints the JVM that a busy spin’s upcoming

JVM CAN intrinsify to use a WAIT opcode for the specific platform / CPU SpinWait Hints

Hints the JVM that a busy spin’s upcoming

JVM CAN intrinsify to use a WAIT opcode for the specific platform / CPU

No-Op implementation for non supported CPUs SpinWait Hints

Hints the JVM that a busy spin’s upcoming

JVM CAN intrinsify to use a WAIT opcode for the specific platform / CPU

No-Op implementation for non supported CPUs

while (!shutdown) { while (queue.length == 0) { // Hint the JVM to intrinsify wait // opcode otherwise busy spin Thread.onSpinWait(); } consume(queue); } What Else?

No idea!

A lot is changing now. Java / JVM will be different. What Else?

No idea!

A lot is changing now. Java / JVM will be different.

Don’t forget about Jigsaw, test your application with Java 9 EA builds!

https://jdk9.java.net/jigsaw/ Questions? github.com/noctarius @noctarius2k

More information: • http://openjdk.java.net/jeps/193 • http://openjdk.java.net/jeps/254 • http://openjdk.java.net/jeps/285 • http://openjdk.java.net/projects/valhalla/ • http://cr.openjdk.java.net/~jrose/arrays/frozen-array-value-rules.html • https://twitter.com/PaulSandoz/status/623891528432394240 • http://openjdk.java.net/projects/panama/ • http://cr.openjdk.java.net/~jrose/values/values-0.html • http://cr.openjdk.java.net/~briangoetz/valhalla/spec-classdyn.html • http://blog.codefx.org/java/dev/the-road-to-valhalla/