Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

1) You catch the SEGV signal you get when failing to read the address, then it is complicated, but it is similar to the mechanism used to reach safe points (also does not use jumps).

2) If there are no nulls, it is faster not to do a branch.

https://shipilev.net/jvm/anatomy-quarks/25-implicit-null-che...



> Java specification says that NullPointerException would be thrown when we access the null object fields. Does this mean the JVM has to always employ runtime checks for nullity?

Once again, we're talking about how JIT can be faster than AOT, not how to reduce JIT overhead. Those are two different types of optimization. You will never be faster than AOT just by reducing JIT overhead. Both links that were provided talk about JIT overhead alone.

This one talks about internal JVM optimizations. Not about optimizations JIT is capable of doing for your code.

What exactly are we even comparing when talking about NullPointerException? To my knowledge, most AOT-compiled languages don't even have NPE (not in Java sense at least). It's apples to oranges comparison.


If we have the code "if (x != null) { x.foo = 42; }", then it can rewritten as x.foo = 42 (with some extra magic in the runtime). If x is not null it will be faster if the cost of a branch is higher than zero. If x is null, the (slow) trick with SEGV can be used.

The trick of catching the SEGV can also be used by an AOT compiler (https://llvm.org/docs/FaultMaps.html), but the AOT compiler would need profiling data to do this optimization that is more expensive to do if the variable x happens to be null often. Even if you have profile data for your application, and that profile data will correspond to your application profile of this particular run (on average), you can not handle the case when x != null for five hours and then is set to null for five hours. If you use an AOT compiler you would have exponential blow-up of code generations for combinations of variables that can be null (if you would try to compile all combinations), and you would basically reinvent a JIT compiler --- badly.

Theoretically, a JIT can do anything an AOT can do, but the reverse is not true.

The article is talking about optimizations the JIT is capable of doing for your code. It is well written, and although it is talking about code throwing a NullPointerException, I think you can see that the same optimization can be done for my example at the top (that is applicable to c++ as well). So my comparison is not apples to oranges.

But your observation that most compiled languages do not have NullPointerExceptions is interesting. It could very much be because that it is too expensive with an AOT, have you thought about that?


Also, in an AOT-way you couldn’t really play the same SEGFAULT trick multiple times without some expensive tracking of where did it come from, where to return to, etc, at which point you are doing borderline JIT compiler with precached method bodies.


Well I guess the point is that with JIT you can do a lot of tricks based on the fact that a function always gets passed a null (or anything relatively constant) in practice even if that wouldn't be statically probable.

If that assumption gets violated a JIT can deopt and adjust later. In AOT you can only make the assumptions based on what the code can statically tell you.


Feels like we're going in circles. I guess that's what you get for nitpicking :)

JIT can indeed do a lot of tricks to reduce JIT overhead. But you can't present that as a benefit of JIT over AOT: AOT doesn't have JIT overhead at all.

JIT can definitely trade space for time. I bet that JIT will inline/memoize certain calls based on call frequency.

The only thing I'm arguing against is that low call frequency (like zero branch executions) somehow provides room for optimization compared to AOT. The only optimizations you can do in this case are optimizations for JIT overhead itself.

Anything beyond that is simply not possible: you can't eliminate a branch and detect the fact that you were supposed to enter eliminated branch at the same time: the simplest mechanism that allows you to do that is branching!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: