1 /*
  2  * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 import java.io.PrintStream;
 25 import jdk.incubator.code.Reflect;
 26 import java.util.Spliterator;
 27 import java.util.Spliterator.OfInt;
 28 
 29 import static java.lang.System.out;
 30 import static java.util.Spliterator.OfInt.*;
 31 
 32 /*
 33  * @test
 34  * @summary Smoke test for code reflection with field access.
 35  * @modules jdk.incubator.code
 36  * @build FieldAccessTest
 37  * @build CodeReflectionTester
 38  * @run main CodeReflectionTester FieldAccessTest
 39  */
 40 
 41 public class FieldAccessTest {
 42     static int s_f;
 43     int f;
 44 
 45     @Reflect
 46     @IR("""
 47             func @"test1" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
 48                 %1 : java.type:"int" = constant @1;
 49                 field.store %1 @java.ref:"FieldAccessTest::s_f:int";
 50                 %2 : java.type:"int" = constant @1;
 51                 field.store %0 %2 @java.ref:"FieldAccessTest::f:int";
 52                 return;
 53             };
 54             """)
 55     void test1() {
 56         s_f = 1;
 57         f = 1;
 58     }
 59 
 60     @Reflect
 61     @IR("""
 62             func @"test1_1" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
 63                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
 64                 %2 : java.type:"int" = constant @1;
 65                 %3 : java.type:"int" = add %1 %2;
 66                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
 67                 %4 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
 68                 %5 : java.type:"int" = constant @1;
 69                 %6 : java.type:"int" = add %4 %5;
 70                 field.store %6 @java.ref:"FieldAccessTest::s_f:int";
 71                 return;
 72             };
 73             """)
 74     void test1_1() {
 75         f += 1;
 76         s_f += 1;
 77     }
 78 
 79     @Reflect
 80     @IR("""
 81             func @"test2" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
 82                 %1 : java.type:"int" = constant @1;
 83                 field.store %0 %1 @java.ref:"FieldAccessTest::f:int";
 84                 field.store %1 @java.ref:"FieldAccessTest::s_f:int";
 85                 return;
 86             };
 87             """)
 88     void test2() {
 89         s_f = f = 1;
 90     }
 91 
 92     @Reflect
 93     @IR("""
 94             func @"test2_1" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
 95                 %1 : java.type:"int" = constant @1;
 96                 field.store %0 %1 @java.ref:"FieldAccessTest::f:int";
 97                 return;
 98             };
 99             """)
100     void test2_1() {
101         this.f = 1;
102     }
103 
104     @Reflect
105     @IR("""
106             func @"test2_2" (%0 : java.type:"FieldAccessTest")java.type:"int" -> {
107                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
108                 return %1;
109             };
110             """)
111     int test2_2() {
112         return this.f;
113     }
114 
115     @Reflect
116     @IR("""
117             func @"test2_3" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
118                 %1 : java.type:"int" = constant @1;
119                 field.store %0 %1 @java.ref:"FieldAccessTest::f:int";
120                 return;
121             };
122             """)
123     void test2_3() {
124         FieldAccessTest.this.f = 1;
125     }
126 
127     @Reflect
128     @IR("""
129             func @"test2_4" (%0 : java.type:"FieldAccessTest")java.type:"int" -> {
130                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
131                 return %1;
132             };
133             """)
134     int test2_4() {
135         return FieldAccessTest.this.f;
136     }
137 
138     @Reflect
139     @IR("""
140             func @"test3" (%0 : java.type:"FieldAccessTest")java.type:"int" -> {
141                 %1 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
142                 %2 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
143                 %3 : java.type:"int" = add %1 %2;
144                 return %3;
145             };
146             """)
147     int test3() {
148         return s_f + f;
149     }
150 
151     static class A {
152         B b;
153     }
154 
155     static class B {
156         C c;
157     }
158 
159     static class C {
160         int f;
161     }
162 
163     @Reflect
164     @IR("""
165             func @"test4" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$A")java.type:"void" -> {
166                 %2 : Var<java.type:"FieldAccessTest$A"> = var %1 @"a";
167                 %3 : java.type:"FieldAccessTest$A" = var.load %2;
168                 %4 : java.type:"FieldAccessTest$B" = field.load %3 @java.ref:"FieldAccessTest$A::b:FieldAccessTest$B";
169                 %5 : java.type:"FieldAccessTest$C" = field.load %4 @java.ref:"FieldAccessTest$B::c:FieldAccessTest$C";
170                 %6 : java.type:"int" = constant @1;
171                 field.store %5 %6 @java.ref:"FieldAccessTest$C::f:int";
172                 return;
173             };
174             """)
175     void test4(A a) {
176         a.b.c.f = 1;
177     }
178 
179     static class X {
180         int f;
181         static int s_f;
182     }
183 
184     @Reflect
185     @IR("""
186             func @"test5" (%0 : java.type:"FieldAccessTest")java.type:"int" -> {
187                 %1 : java.type:"int" = field.load @java.ref:"FieldAccessTest$X::s_f:int";
188                 return %1;
189             };
190             """)
191     int test5() {
192         return X.s_f;
193     }
194 
195     @Reflect
196     @IR("""
197             func @"test6" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
198                 %1 : java.type:"int" = constant @1;
199                 field.store %1 @java.ref:"FieldAccessTest$X::s_f:int";
200                 return;
201             };
202             """)
203     void test6() {
204         X.s_f = 1;
205     }
206 
207 
208     @Reflect
209     @IR("""
210             func @"test7" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
211                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
212                 %2 : java.type:"int" = constant @1;
213                 %3 : java.type:"int" = add %1 %2;
214                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
215                 %4 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
216                 %5 : java.type:"int" = constant @1;
217                 %6 : java.type:"int" = add %4 %5;
218                 field.store %6 @java.ref:"FieldAccessTest::s_f:int";
219                 return;
220             };
221             """)
222     void test7() {
223         f += 1;
224         s_f += 1;
225     }
226 
227     @Reflect
228     @IR("""
229             func @"test8" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
230                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
231                 %2 : java.type:"int" = constant @1;
232                 %3 : java.type:"int" = add %1 %2;
233                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
234                 %4 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
235                 %5 : java.type:"int" = constant @1;
236                 %6 : java.type:"int" = add %4 %5;
237                 field.store %6 @java.ref:"FieldAccessTest::s_f:int";
238                 return;
239             };
240             """)
241     void test8() {
242         this.f += 1;
243         this.s_f += 1;
244     }
245 
246     @Reflect
247     @IR("""
248             func @"test9" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
249                 %1 : java.type:"int" = field.load @java.ref:"FieldAccessTest$X::s_f:int";
250                 %2 : java.type:"int" = constant @1;
251                 %3 : java.type:"int" = add %1 %2;
252                 field.store %3 @java.ref:"FieldAccessTest$X::s_f:int";
253                 return;
254             };
255             """)
256     void test9() {
257         X.s_f += 1;
258     }
259 
260     @Reflect
261     @IR("""
262             func @"test10" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
263                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
264                 %2 : java.type:"int" = constant @1;
265                 %3 : java.type:"int" = add %1 %2;
266                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
267                 field.store %3 @java.ref:"FieldAccessTest::s_f:int";
268                 return;
269             };
270             """)
271     void test10() {
272         s_f = f += 1;
273     }
274 
275     @Reflect
276     @IR("""
277             func @"test11" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$A")java.type:"void" -> {
278                 %2 : Var<java.type:"FieldAccessTest$A"> = var %1 @"a";
279                 %3 : java.type:"FieldAccessTest$A" = var.load %2;
280                 %4 : java.type:"FieldAccessTest$B" = field.load %3 @java.ref:"FieldAccessTest$A::b:FieldAccessTest$B";
281                 %5 : java.type:"FieldAccessTest$C" = field.load %4 @java.ref:"FieldAccessTest$B::c:FieldAccessTest$C";
282                 %6 : java.type:"int" = field.load %5 @java.ref:"FieldAccessTest$C::f:int";
283                 %7 : java.type:"int" = constant @1;
284                 %8 : java.type:"int" = add %6 %7;
285                 field.store %5 %8 @java.ref:"FieldAccessTest$C::f:int";
286                 return;
287             };
288             """)
289     void test11(A a) {
290         a.b.c.f += 1;
291     }
292 
293     @Reflect
294     @IR("""
295             func @"test12" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
296                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
297                 %2 : java.type:"int" = constant @1;
298                 %3 : java.type:"int" = add %1 %2;
299                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
300                 %4 : Var<java.type:"int"> = var %1 @"x";
301                 %5 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
302                 %6 : java.type:"int" = constant @1;
303                 %7 : java.type:"int" = sub %5 %6;
304                 field.store %0 %7 @java.ref:"FieldAccessTest::f:int";
305                 %8 : Var<java.type:"int"> = var %5 @"y";
306                 return;
307             };
308             """)
309     void test12() {
310         int x = f++;
311         int y = f--;
312     }
313 
314     @Reflect
315     @IR("""
316             func @"test13" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
317                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
318                 %2 : java.type:"int" = constant @1;
319                 %3 : java.type:"int" = add %1 %2;
320                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
321                 %4 : Var<java.type:"int"> = var %1 @"x";
322                 %5 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
323                 %6 : java.type:"int" = constant @1;
324                 %7 : java.type:"int" = sub %5 %6;
325                 field.store %0 %7 @java.ref:"FieldAccessTest::f:int";
326                 %8 : Var<java.type:"int"> = var %5 @"y";
327                 return;
328             };
329             """)
330     void test13() {
331         int x = this.f++;
332         int y = this.f--;
333     }
334 
335     @Reflect
336     @IR("""
337             func @"test14" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
338                 %1 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
339                 %2 : java.type:"int" = constant @1;
340                 %3 : java.type:"int" = add %1 %2;
341                 field.store %3 @java.ref:"FieldAccessTest::s_f:int";
342                 %4 : Var<java.type:"int"> = var %1 @"x";
343                 %5 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
344                 %6 : java.type:"int" = constant @1;
345                 %7 : java.type:"int" = sub %5 %6;
346                 field.store %7 @java.ref:"FieldAccessTest::s_f:int";
347                 %8 : Var<java.type:"int"> = var %5 @"y";
348                 return;
349             };
350             """)
351     void test14() {
352         int x = s_f++;
353         int y = s_f--;
354     }
355 
356     @Reflect
357     @IR("""
358             func @"test15" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$X")java.type:"void" -> {
359                 %2 : Var<java.type:"FieldAccessTest$X"> = var %1 @"h";
360                 %3 : java.type:"FieldAccessTest$X" = var.load %2;
361                 %4 : java.type:"int" = field.load %3 @java.ref:"FieldAccessTest$X::f:int";
362                 %5 : java.type:"int" = constant @1;
363                 %6 : java.type:"int" = add %4 %5;
364                 field.store %3 %6 @java.ref:"FieldAccessTest$X::f:int";
365                 %7 : Var<java.type:"int"> = var %4 @"x";
366                 %8 : java.type:"FieldAccessTest$X" = var.load %2;
367                 %9 : java.type:"int" = field.load %8 @java.ref:"FieldAccessTest$X::f:int";
368                 %10 : java.type:"int" = constant @1;
369                 %11 : java.type:"int" = sub %9 %10;
370                 field.store %8 %11 @java.ref:"FieldAccessTest$X::f:int";
371                 %12 : Var<java.type:"int"> = var %9 @"y";
372                 return;
373             };
374             """)
375     void test15(X h) {
376         int x = h.f++;
377         int y = h.f--;
378     }
379 
380 
381 
382 
383     @Reflect
384     @IR("""
385             func @"test16" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
386                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
387                 %2 : java.type:"int" = constant @1;
388                 %3 : java.type:"int" = add %1 %2;
389                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
390                 %4 : Var<java.type:"int"> = var %3 @"x";
391                 %5 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
392                 %6 : java.type:"int" = constant @1;
393                 %7 : java.type:"int" = sub %5 %6;
394                 field.store %0 %7 @java.ref:"FieldAccessTest::f:int";
395                 %8 : Var<java.type:"int"> = var %7 @"y";
396                 return;
397             };
398             """)
399     void test16() {
400         int x = ++f;
401         int y = --f;
402     }
403 
404     @Reflect
405     @IR("""
406             func @"test17" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
407                 %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
408                 %2 : java.type:"int" = constant @1;
409                 %3 : java.type:"int" = add %1 %2;
410                 field.store %0 %3 @java.ref:"FieldAccessTest::f:int";
411                 %4 : Var<java.type:"int"> = var %3 @"x";
412                 %5 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest::f:int";
413                 %6 : java.type:"int" = constant @1;
414                 %7 : java.type:"int" = sub %5 %6;
415                 field.store %0 %7 @java.ref:"FieldAccessTest::f:int";
416                 %8 : Var<java.type:"int"> = var %7 @"y";
417                 return;
418             };
419             """)
420     void test17() {
421         int x = ++this.f;
422         int y = --this.f;
423     }
424 
425     @Reflect
426     @IR("""
427             func @"test18" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
428                 %1 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
429                 %2 : java.type:"int" = constant @1;
430                 %3 : java.type:"int" = add %1 %2;
431                 field.store %3 @java.ref:"FieldAccessTest::s_f:int";
432                 %4 : Var<java.type:"int"> = var %3 @"x";
433                 %5 : java.type:"int" = field.load @java.ref:"FieldAccessTest::s_f:int";
434                 %6 : java.type:"int" = constant @1;
435                 %7 : java.type:"int" = sub %5 %6;
436                 field.store %7 @java.ref:"FieldAccessTest::s_f:int";
437                 %8 : Var<java.type:"int"> = var %7 @"y";
438                 return;
439             };
440             """)
441     void test18() {
442         int x = ++s_f;
443         int y = --s_f;
444     }
445 
446     @Reflect
447     @IR("""
448             func @"test19" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$X")java.type:"void" -> {
449                 %2 : Var<java.type:"FieldAccessTest$X"> = var %1 @"h";
450                 %3 : java.type:"FieldAccessTest$X" = var.load %2;
451                 %4 : java.type:"int" = field.load %3 @java.ref:"FieldAccessTest$X::f:int";
452                 %5 : java.type:"int" = constant @1;
453                 %6 : java.type:"int" = add %4 %5;
454                 field.store %3 %6 @java.ref:"FieldAccessTest$X::f:int";
455                 %7 : Var<java.type:"int"> = var %6 @"x";
456                 %8 : java.type:"FieldAccessTest$X" = var.load %2;
457                 %9 : java.type:"int" = field.load %8 @java.ref:"FieldAccessTest$X::f:int";
458                 %10 : java.type:"int" = constant @1;
459                 %11 : java.type:"int" = sub %9 %10;
460                 field.store %8 %11 @java.ref:"FieldAccessTest$X::f:int";
461                 %12 : Var<java.type:"int"> = var %11 @"y";
462                 return;
463             };
464             """)
465     void test19(X h) {
466         int x = ++h.f;
467         int y = --h.f;
468     }
469 
470     static class Y extends X {
471         int yf;
472         static int s_yf;
473 
474         @Reflect
475         @IR("""
476                 func @"test" (%0 : java.type:"FieldAccessTest$Y")java.type:"void" -> {
477                     %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest$Y::f:int";
478                     %2 : Var<java.type:"int"> = var %1 @"x";
479                     %3 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_f:int";
480                     var.store %2 %3;
481                     return;
482                 };
483                 """)
484         void test() {
485             int x = f;
486             x = s_f;
487         }
488 
489         @Reflect
490         @IR("""
491                 func @"test2" (%0 : java.type:"FieldAccessTest$Y")java.type:"void" -> {
492                     %1 : java.type:"int" = constant @1;
493                     field.store %0 %1 @java.ref:"FieldAccessTest$Y::f:int";
494                     %2 : java.type:"int" = constant @1;
495                     field.store %2 @java.ref:"FieldAccessTest$Y::s_f:int";
496                     return;
497                 };
498                 """)
499         void test2() {
500             f = 1;
501             s_f = 1;
502         }
503 
504         @Reflect
505         @IR("""
506                 func @"test3" (%0 : java.type:"FieldAccessTest$Y")java.type:"void" -> {
507                     %1 : java.type:"int" = field.load %0 @java.ref:"FieldAccessTest$Y::f:int";
508                     %2 : java.type:"int" = constant @1;
509                     %3 : java.type:"int" = add %1 %2;
510                     field.store %0 %3 @java.ref:"FieldAccessTest$Y::f:int";
511                     %4 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_f:int";
512                     %5 : java.type:"int" = constant @1;
513                     %6 : java.type:"int" = add %4 %5;
514                     field.store %6 @java.ref:"FieldAccessTest$Y::s_f:int";
515                     return;
516                 };
517                 """)
518         void test3() {
519             f++;
520             s_f++;
521         }
522     }
523 
524     static class Z<T extends X> {
525         T x;
526     }
527 
528     static class ZZ extends Z<Y> {
529 
530         @IR("""
531                 func @"test1" (%0 : java.type:"FieldAccessTest$ZZ")java.type:"int" -> {
532                     %1 : java.type:"FieldAccessTest$Y" = field.load %0 @java.ref:"FieldAccessTest$ZZ::x:FieldAccessTest$X";
533                     %2 : java.type:"FieldAccessTest$Y" = cast %1 @java.type:"FieldAccessTest$Y";
534                     %3 : java.type:"int" = field.load %2 @java.ref:"FieldAccessTest$Y::yf:int";
535                     return %3;
536                 };
537                 """)
538         @Reflect
539         int test1() {
540             return x.yf;
541         }
542 
543         @IR("""
544                 func @"test2" (%0 : java.type:"FieldAccessTest$ZZ")java.type:"int" -> {
545                     %1 : Var<java.type:"FieldAccessTest$ZZ"> = var %0 @"zz";
546                     %2 : java.type:"FieldAccessTest$ZZ" = var.load %1;
547                     %3 : java.type:"FieldAccessTest$Y" = field.load %2 @java.ref:"FieldAccessTest$ZZ::x:FieldAccessTest$X";
548                     %4 : java.type:"FieldAccessTest$Y" = cast %3 @java.type:"FieldAccessTest$Y";
549                     %5 : java.type:"int" = field.load %4 @java.ref:"FieldAccessTest$Y::yf:int";
550                     return %5;
551                 };
552                 """)
553         @Reflect
554         static int test2(ZZ zz) {
555             return zz.x.yf;
556         }
557     }
558 
559     static class W<T extends Number> {
560         T n;
561     }
562 
563     static class WW extends W<Integer> {
564 
565         @IR("""
566                 func @"test1" (%0 : java.type:"FieldAccessTest$WW")java.type:"int" -> {
567                     %1 : java.type:"java.lang.Integer" = field.load %0 @java.ref:"FieldAccessTest$WW::n:java.lang.Number";
568                     %2 : java.type:"int" = invoke %1 @java.ref:"java.lang.Integer::intValue():int";
569                     %3 : java.type:"int" = constant @1;
570                     %4 : java.type:"int" = add %2 %3;
571                     %5 : java.type:"java.lang.Integer" = invoke %4 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
572                     field.store %0 %5 @java.ref:"FieldAccessTest$WW::n:java.lang.Number";
573                     %6 : java.type:"int" = constant @0;
574                     %7 : java.type:"java.lang.Integer" = invoke %6 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
575                     %8 : java.type:"int" = invoke %1 %7 @java.ref:"java.lang.Integer::compareTo(java.lang.Integer):int";
576                     return %8;
577                 };
578                 """)
579         @Reflect
580         int test1() {
581             return (n++).compareTo(0);
582         }
583 
584         @IR("""
585                 func @"test2" (%0 : java.type:"FieldAccessTest$WW")java.type:"int" -> {
586                     %1 : Var<java.type:"FieldAccessTest$WW"> = var %0 @"w";
587                     %2 : java.type:"FieldAccessTest$WW" = var.load %1;
588                     %3 : java.type:"java.lang.Integer" = field.load %2 @java.ref:"FieldAccessTest$WW::n:java.lang.Number";
589                     %4 : java.type:"int" = invoke %3 @java.ref:"java.lang.Integer::intValue():int";
590                     %5 : java.type:"int" = constant @1;
591                     %6 : java.type:"int" = add %4 %5;
592                     %7 : java.type:"java.lang.Integer" = invoke %6 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
593                     field.store %2 %7 @java.ref:"FieldAccessTest$WW::n:java.lang.Number";
594                     %8 : java.type:"int" = constant @0;
595                     %9 : java.type:"java.lang.Integer" = invoke %8 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
596                     %10 : java.type:"int" = invoke %3 %9 @java.ref:"java.lang.Integer::compareTo(java.lang.Integer):int";
597                     return %10;
598                 };
599                 """)
600         @Reflect
601         static int test2(WW w) {
602             return (w.n++).compareTo(0);
603         }
604     }
605 
606     @Reflect
607     @IR("""
608             func @"test20" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$Y")java.type:"void" -> {
609                 %2 : Var<java.type:"FieldAccessTest$Y"> = var %1 @"y";
610                 %3 : java.type:"FieldAccessTest$Y" = var.load %2;
611                 %4 : java.type:"int" = field.load %3 @java.ref:"FieldAccessTest$Y::f:int";
612                 %5 : Var<java.type:"int"> = var %4 @"x";
613                 %6 : java.type:"FieldAccessTest$Y" = var.load %2;
614                 %7 : java.type:"int" = field.load %6 @java.ref:"FieldAccessTest$Y::yf:int";
615                 var.store %5 %7;
616                 %8 : java.type:"FieldAccessTest$Y" = var.load %2;
617                 %9 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_yf:int";
618                 var.store %5 %9;
619                 %10 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_yf:int";
620                 var.store %5 %10;
621                 %11 : java.type:"FieldAccessTest$Y" = var.load %2;
622                 %12 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_f:int";
623                 var.store %5 %12;
624                 %13 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_f:int";
625                 var.store %5 %13;
626                 return;
627             };
628             """)
629     void test20(Y y) {
630         int x = y.f;
631         x = y.yf;
632         x = y.s_yf;
633         x = Y.s_yf;
634         x = y.s_f;
635         x = Y.s_f;
636     }
637 
638     @Reflect
639     @IR("""
640             func @"test21" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$Y")java.type:"void" -> {
641                 %2 : Var<java.type:"FieldAccessTest$Y"> = var %1 @"y";
642                 %3 : java.type:"FieldAccessTest$Y" = var.load %2;
643                 %4 : java.type:"int" = constant @1;
644                 field.store %3 %4 @java.ref:"FieldAccessTest$Y::f:int";
645                 %5 : java.type:"FieldAccessTest$Y" = var.load %2;
646                 %6 : java.type:"int" = constant @1;
647                 field.store %5 %6 @java.ref:"FieldAccessTest$Y::yf:int";
648                 %7 : java.type:"FieldAccessTest$Y" = var.load %2;
649                 %8 : java.type:"int" = constant @1;
650                 field.store %8 @java.ref:"FieldAccessTest$Y::s_yf:int";
651                 %9 : java.type:"int" = constant @1;
652                 field.store %9 @java.ref:"FieldAccessTest$Y::s_yf:int";
653                 %10 : java.type:"FieldAccessTest$Y" = var.load %2;
654                 %11 : java.type:"int" = constant @1;
655                 field.store %11 @java.ref:"FieldAccessTest$Y::s_f:int";
656                 %12 : java.type:"int" = constant @1;
657                 field.store %12 @java.ref:"FieldAccessTest$Y::s_f:int";
658                 return;
659             };
660             """)
661     void test21(Y y) {
662         y.f = 1;
663         y.yf = 1;
664         y.s_yf = 1;
665         Y.s_yf = 1;
666         y.s_f = 1;
667         Y.s_f = 1;
668     }
669 
670     @Reflect
671     @IR("""
672             func @"test22" (%0 : java.type:"FieldAccessTest", %1 : java.type:"FieldAccessTest$Y")java.type:"void" -> {
673                 %2 : Var<java.type:"FieldAccessTest$Y"> = var %1 @"y";
674                 %3 : java.type:"FieldAccessTest$Y" = var.load %2;
675                 %4 : java.type:"int" = field.load %3 @java.ref:"FieldAccessTest$Y::f:int";
676                 %5 : java.type:"int" = constant @1;
677                 %6 : java.type:"int" = add %4 %5;
678                 field.store %3 %6 @java.ref:"FieldAccessTest$Y::f:int";
679                 %7 : java.type:"FieldAccessTest$Y" = var.load %2;
680                 %8 : java.type:"int" = field.load %7 @java.ref:"FieldAccessTest$Y::yf:int";
681                 %9 : java.type:"int" = constant @1;
682                 %10 : java.type:"int" = add %8 %9;
683                 field.store %7 %10 @java.ref:"FieldAccessTest$Y::yf:int";
684                 %11 : java.type:"FieldAccessTest$Y" = var.load %2;
685                 %12 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_yf:int";
686                 %13 : java.type:"int" = constant @1;
687                 %14 : java.type:"int" = add %12 %13;
688                 field.store %14 @java.ref:"FieldAccessTest$Y::s_yf:int";
689                 %15 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_yf:int";
690                 %16 : java.type:"int" = constant @1;
691                 %17 : java.type:"int" = add %15 %16;
692                 field.store %17 @java.ref:"FieldAccessTest$Y::s_yf:int";
693                 %18 : java.type:"FieldAccessTest$Y" = var.load %2;
694                 %19 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_f:int";
695                 %20 : java.type:"int" = constant @1;
696                 %21 : java.type:"int" = add %19 %20;
697                 field.store %21 @java.ref:"FieldAccessTest$Y::s_f:int";
698                 %22 : java.type:"int" = field.load @java.ref:"FieldAccessTest$Y::s_f:int";
699                 %23 : java.type:"int" = constant @1;
700                 %24 : java.type:"int" = add %22 %23;
701                 field.store %24 @java.ref:"FieldAccessTest$Y::s_f:int";
702                 return;
703             };
704             """)
705     void test22(Y y) {
706         y.f++;
707         y.yf++;
708         y.s_yf++;
709         Y.s_yf++;
710         y.s_f++;
711         Y.s_f++;
712     }
713 
714     // @@@ Should propagate as constant value?
715     @Reflect
716     @IR("""
717             func @"test23" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
718                 %1 : java.type:"int" = field.load @java.ref:"java.util.Spliterator$OfInt::CONCURRENT:int";
719                 %2 : Var<java.type:"int"> = var %1 @"x";
720                 %3 : java.type:"int" = field.load @java.ref:"java.util.Spliterator$OfInt::CONCURRENT:int";
721                 var.store %2 %3;
722                 %4 : java.type:"int" = field.load @java.ref:"java.util.Spliterator$OfInt::CONCURRENT:int";
723                 var.store %2 %4;
724                 return;
725             };
726             """)
727     void test23() {
728         int x = Spliterator.OfInt.CONCURRENT;
729         x = OfInt.CONCURRENT;
730         x = CONCURRENT;
731     }
732 
733     @Reflect
734     @IR("""
735             func @"test24" (%0 : java.type:"FieldAccessTest")java.type:"void" -> {
736                 %1 : java.type:"java.io.PrintStream" = field.load @java.ref:"java.lang.System::out:java.io.PrintStream";
737                 %2 : Var<java.type:"java.io.PrintStream"> = var %1 @"ps";
738                 return;
739             };
740             """)
741     void test24() {
742         PrintStream ps = out;
743     }
744 
745     static class Box<T> {
746         public T v;
747 
748         public Box(T v) {
749             this.v = v;
750         }
751     }
752 
753     @Reflect
754     @IR("""
755             func @"test25" ()java.type:"void" -> {
756                 %0 : java.type:"java.lang.String" = constant @"abc";
757                 %1 : java.type:"FieldAccessTest$Box<java.lang.String>" = new %0 @java.ref:"FieldAccessTest$Box::(java.lang.Object)";
758                 %2 : Var<java.type:"FieldAccessTest$Box<java.lang.String>"> = var %1 @"b";
759                 %3 : java.type:"FieldAccessTest$Box<java.lang.String>" = var.load %2;
760                 %4 : java.type:"java.lang.String" = field.load %3 @java.ref:"FieldAccessTest$Box::v:java.lang.Object";
761                 %5 : java.type:"java.lang.String" = cast %4 @java.type:"java.lang.String";
762                 %6 : Var<java.type:"java.lang.String"> = var %5 @"s";
763                 return;
764             };
765             """)
766     static void test25() {
767         Box<String> b = new Box<>("abc");
768         String s = b.v;
769     }
770 
771     //@@@ unqualified access to field of generic type needs to be tested
772     // waiting for a new way of modeling types, so that type variables are captured in the IR
773 }