Is the Java evaluation order guaranteed in this case the method call and arguments passed to

I read JLS 15.7.4 and 15.12.4.2 , but it doesn’t guarantee that there will be no compiler / runtime optimization that will change the order in which the method arguments are evaluated.

Assume the following code:

public static void main (String[] args) { MyObject obj = new MyObject(); methodRelyingOnEvalOrder(obj, obj.myMethod()); } public static Object methodRelyingOnEvalOrder(MyObject obj, Object input) { if (obj.myBoolean()) return null; else return input; } 

Is it guaranteed that the compiler or runtime will not perform false optimizations such as the following? This optimization may seem right, but it’s wrong when the order of evaluation makes sense.

In the event that calling obj.myMethod changes the value that obj.myBoolean will return, it is imperative that obj.myMethod be called first, since methodRelyingOnEvalOrder requires that this change occur first.

 //******************************* //Unwanted optimization possible: //******************************* public static void main (String[] args) { MyObject obj = new MyObject(); methodRelyingOnEvalOrder(obj); } public static Object methodRelyingOnEvalOrder(MyObject obj) { if (obj.myBoolean()) return null; else return obj.myMethod(); } //******************************* 

If possible, please show some sources or Java documentation that support your answer.

Note: Please do not ask to rewrite the code. This is a specific case when I ask a question about guaranteeing the evaluation order and guaranteeing compiler / runtime optimization. The execution of obj.myMethod must be executed in the main method.

+6
source share
2 answers

The JLS bit you refer to (15.7.4) ensures that:

Each argument expression appears to be fully evaluated before any part of any argument expression is on the right.

as well as in 15.12.4.2:

The evaluation then continues using the argument values ​​as described below.

The “appear” part allows you to use some optimization, but it should not be visible. The fact that all arguments are evaluated before the "evaluation then continues" shows that the arguments are indeed completely refuted before the method is executed. (Or at least that is the visible result.)

So, for example, if you have code:

 int x = 10; foo(x + 5, x + 20); 

one could optimize this for a parallel evaluation of both x + 5 and x + 20 : there is no way to detect this.

But in the case you pointed out, you will be able to detect the obj.myMethod call that occurred after the obj.myBoolean() call, so this will not be a real optimization at all.

In short: you can assume that everything will be done in an obvious way here.

+6
source

In addition to the order in which the argument is evaluated, an overview of the steps taken when the method was called and their order, described in section 15.12.4. Run-Time Evaluation of Invoice method , makes it clear that all evaluations of the arguments are performed before the method code is executed. Quote:

When you start a method call, five steps are required. First, the target link can be calculated. Secondly, the expression of the arguments was evaluated . Thirdly, the availability of the method for calling is verified. Fourth, the actual code for the method to be executed is located. Fifthly, a new activation frame is created, synchronization if necessary, and control is transferred to the method code .

The case that you presented when the argument is evaluated only after the control is transferred to the method code is out of the question.

+5
source

Source: https://habr.com/ru/post/951534/


All Articles