I think this is an enormously bad idea. The whole point of using sun.misc.Unsafe is because you need to do something with basically no overhead, regardless of safety. In my opinion, they should just modularize it such that users must enable access to it explicitly. The MemorySegment API is nice, but sometimes you really want to skip bounds checking in a cross platform way.
The cost of bounds checks, which is already low, could be reduced further the vast majority of uses with even more enhancements to the compiler's inlining decisions, so we're talking about an API whose value is already small and constantly declining. However, those who think they absolutely need to avoid bounds checks could, indeed, use a flag to access the JDK's internals. We don't think that such a small benefit (especially when integrated over all users) merits a supported API.
You might be correct, but it's not obvious to me unsafe is really faster. I recall reading that using unsafe invalidates most of the other optimizations because it's opaque to the JIT what you are doing. Also, if there are BCE opportunities, I feel pretty confident OpenJDK will add them, rather than being unsympathetic.
> sometimes you really want to skip bounds checking in a cross platform way
What is a use case where this is crucial? Where the difference is not just to win a benchmark pissing contest, but where the delta is so large that it is a factor of the JVM being a valid platform or not, and where the JVM would still be the best overall solution?
Put differently: if you need extreme performance and full low-level control, what is a scenario where you still choose the JVM over eg Rust, and where bounds-checking elimination would be the deciding factor?
If you really insist on shooting yourself in the foot, you can do MemorySegment.ofAddress(0).reinterpret(Long.MAX_VALUE) to obtain a MemorySegment for the lower half of the address space of your process. Obviously, you set the address to Long.MAX_VALUE for the upper half.
<<
Over the past several years, we have introduced two standard APIs that are safe and performant replacements for the memory-access methods in sun.misc.Unsafe:
java.lang.invoke.VarHandle, introduced in JDK 9, provides methods to safely and efficiently manipulate on-heap memory: fields of objects, static fields of classes, and elements of arrays.
java.lang.foreign.MemorySegment, introduced in JDK 22, provides methods to safely and efficiently access off-heap memory (sometimes in cooperation with VarHandle).
These standard APIs guarantee no undefined behavior, promise long-term stability, and have high-quality integration with the tooling and documentation of the Java Platform (examples of their use are given below). Given the availability of these APIs, it is now appropriate to deprecate and eventually remove the memory-access methods in sun.misc.Unsafe.
>>
Once I did some experiments at programming in Java using only sun.misc.Unsafe for a memory access: https://github.com/xonixx/gc_less. I was able to implement this way basic data structures (array, array list, hash table). I even explicitely set a very small heap and used Epsilon GC to make sure I don't allocate in heap.
Just recently I decided to check if it still works in the latest Java (23) and to my surprise it appears - it is. Now, apparently, this is going to change.
The main sting here seems to be that MemorySegment when allocated from Java code requires bounds checks on all accesses, which the JVM cannot optimise away on random accesses.
However, MemorySegment itself already supports unbounded access when wrapping a native pointer. It’s necessary for even basic interactions with native code (e.g. reading a c-str).
It should be easy to “wash” an off-heap MemorySegment through native code to obtain an unbounded MemorySegment from it. Something like:
void *vanish_bounds(void *ptr) { return ptr; }
I think it would be nice if the FFI provided a way to get an unbounded MemorySegment without resorting to native code hacks though. It can obviously be made restricted like unbounded MemorySegment’s already are.
That should take most of the sting out of this proposal (although it still sounds like a painful transition for a very modest gain).
First, please clarify whether you are asking about performance impacts vs. no bounds checking or vs. bounds checking in software.
The "vs. no bounds checking" deals with the fact that the bounds must be stored somewhere, so you get an additional memory access, and that's slow (best case, puts some load on the caches).
The "vs. software" is more like RISC vs. CISC in general.
Most of sun.misc.Unsafe forwards to jdk.internal, which will still exist and be accessible via --add-exports on the command line. This is a good middle ground for strong encapsulation and making sure users know that they're using internal api's that could change.
[+] [-] slaymaker1907|2 years ago|reply
[+] [-] pron|2 years ago|reply
[+] [-] synthetigram|2 years ago|reply
[+] [-] MrBuddyCasino|2 years ago|reply
What is a use case where this is crucial? Where the difference is not just to win a benchmark pissing contest, but where the delta is so large that it is a factor of the JVM being a valid platform or not, and where the JVM would still be the best overall solution?
Put differently: if you need extreme performance and full low-level control, what is a scenario where you still choose the JVM over eg Rust, and where bounds-checking elimination would be the deciding factor?
[+] [-] grishka|2 years ago|reply
[+] [-] throwaway2037|2 years ago|reply
<< Over the past several years, we have introduced two standard APIs that are safe and performant replacements for the memory-access methods in sun.misc.Unsafe:
java.lang.invoke.VarHandle, introduced in JDK 9, provides methods to safely and efficiently manipulate on-heap memory: fields of objects, static fields of classes, and elements of arrays.
java.lang.foreign.MemorySegment, introduced in JDK 22, provides methods to safely and efficiently access off-heap memory (sometimes in cooperation with VarHandle).
These standard APIs guarantee no undefined behavior, promise long-term stability, and have high-quality integration with the tooling and documentation of the Java Platform (examples of their use are given below). Given the availability of these APIs, it is now appropriate to deprecate and eventually remove the memory-access methods in sun.misc.Unsafe. >>
[+] [-] xonix|2 years ago|reply
Once I did some experiments at programming in Java using only sun.misc.Unsafe for a memory access: https://github.com/xonixx/gc_less. I was able to implement this way basic data structures (array, array list, hash table). I even explicitely set a very small heap and used Epsilon GC to make sure I don't allocate in heap.
Just recently I decided to check if it still works in the latest Java (23) and to my surprise it appears - it is. Now, apparently, this is going to change.
[+] [-] kaba0|2 years ago|reply
[+] [-] jeeeb|2 years ago|reply
However, MemorySegment itself already supports unbounded access when wrapping a native pointer. It’s necessary for even basic interactions with native code (e.g. reading a c-str).
It should be easy to “wash” an off-heap MemorySegment through native code to obtain an unbounded MemorySegment from it. Something like:
I think it would be nice if the FFI provided a way to get an unbounded MemorySegment without resorting to native code hacks though. It can obviously be made restricted like unbounded MemorySegment’s already are.That should take most of the sting out of this proposal (although it still sounds like a painful transition for a very modest gain).
[+] [-] g-b-r|2 years ago|reply
Is it inherently difficult to do it without performance impacts? Or nobody cared too much for the prevalence of trust-the-developer c thinking?
I found some information at https://stackoverflow.com/questions/40752436/do-any-cpus-hav...
[+] [-] moring|2 years ago|reply
The "vs. no bounds checking" deals with the fact that the bounds must be stored somewhere, so you get an additional memory access, and that's slow (best case, puts some load on the caches).
The "vs. software" is more like RISC vs. CISC in general.
[+] [-] bhakunikaran|2 years ago|reply
[+] [-] vips7L|2 years ago|reply
[+] [-] vkaku|2 years ago|reply
Maybe, if the Devs can replicate the perf with VarHandle and MemorySegment, it could go away eventually.