JDK-6908240 : javac should avoid generating same finally block several times
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P4
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2009-12-08
  • Updated: 2015-12-08
  • Resolved: 2015-12-08
Description
FULL PRODUCT VERSION :
All JDK 7

ADDITIONAL OS VERSION INFORMATION :
Windows XP SP-3

A DESCRIPTION OF THE PROBLEM :
Compile given source code below.
The finally block exists 6 times in resulting byte code for each return path.

This is memory wastage, especially if regarding code becomes JIT-compiled.

Note thread:
http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2009-November/002154.html

ACTUAL -
sun/nio/cs/ext/EUC_TW_C_d_b_codeToBuffer4$Decoder.decodeArrayLoop(Ljava/nio/ByteBuffer;Ljava/nio/CharBuffer;)Ljava/nio/charset/CoderResult;
  interpreter_invocation_count:        2
  invocation_counter:                  2
  backedge_counter:                 6024

0 aload_1
1 invokevirtual 12 <array> <()[B>
  0   bci: 1    VirtualCallData     count(1) entries(0)
4 astore_3
5 aload_1
6 invokevirtual 13 <arrayOffset> <()I>
  24  bci: 6    VirtualCallData     count(1) entries(0)
9 aload_1
10 invokevirtual 14 <position> <()I>
  48  bci: 10   VirtualCallData     count(1) entries(0)
13 iadd
14 istore #4
16 iload #4
18 aload_1
19 invokevirtual 15 <remaining> <()I>
  72  bci: 19   VirtualCallData     count(1) entries(0)
22 iadd
23 istore #5
25 aload_2
26 invokevirtual 16 <array> <()[C>
  96  bci: 26   VirtualCallData     count(1) entries(0)
29 astore #6
31 iconst_1
32 newarray int
34 astore #7
36 aload #7
38 iconst_0
39 aload_2
40 invokevirtual 17 <arrayOffset> <()I>
  120 bci: 40   VirtualCallData     count(1) entries(0)
43 aload_2
44 invokevirtual 18 <position> <()I>
  144 bci: 44   VirtualCallData     count(1) entries(0)
47 iadd
48 iastore
49 aload #7
51 iconst_0
52 iaload
53 aload_2
54 invokevirtual 19 <remaining> <()I>
  168 bci: 54   VirtualCallData     count(1) entries(0)
57 iadd
58 istore #8
60 iload #4
62 iload #5
64 if_icmpge 366
  192 bci: 64   BranchData          taken(0) displacement(612)
                                    not taken(12288)
67 aload_3
68 iload #4
70 baload
71 istore #10
73 iload #10
75 iflt 146
  208 bci: 75   BranchData          taken(1024) displacement(140)
                                    not taken(11264)
78 aload #7
80 iconst_0
81 iaload
82 iload #8
84 if_icmpne 121
  224 bci: 84   BranchData          taken(11264) displacement(112)
                                    not taken(0)
87 getstatic 20 <OVERFLOW> <Ljava/nio/charset/CoderResult;>
********************* 1st copy of finally block >>>>>>>>>>>>>>>>>>>>>>>>>>
90 astore #11
92 aload_1
93 iload #4
95 aload_1
96 invokevirtual 13 <arrayOffset> <()I>
  240 bci: 96   VirtualCallData     count(0) entries(0)
99 isub
100 invokevirtual 21 <position> <(I)Ljava/nio/Buffer;>
  264 bci: 100  VirtualCallData     count(0) entries(0)
103 pop
104 aload_2
105 aload #7
107 iconst_0
108 iaload
109 aload_2
110 invokevirtual 17 <arrayOffset> <()I>
  288 bci: 110  VirtualCallData     count(0) entries(0)
113 isub
114 invokevirtual 22 <position> <(I)Ljava/nio/Buffer;>
  312 bci: 114  VirtualCallData     count(0) entries(0)
117 pop
118 aload #11
120 areturn
********************* end of finally block <<<<<<<<<<<<<<<<<<<<<<<<<<
121 aload #6
123 aload #7
125 iconst_0
126 dup2
127 iaload
128 dup_x2
129 iconst_1
130 iadd
131 iastore
132 iload #10
134 sipush 255
137 iand
138 i2c
139 castore
140 iinc #4 1
143 goto 363
  336 bci: 143  JumpData            taken(11264) displacement(456)
146 iload #10
148 bipush -114
150 if_icmpeq 229
  348 bci: 150  BranchData          taken(0) displacement(176)
                                    not taken(1024)
153 iload #4
155 iconst_1
156 iadd
157 iload #5
159 if_icmpne 165
  364 bci: 159  BranchData          taken(1024) displacement(28)
                                    not taken(0)
162 goto 366
  380 bci: 162  JumpData            taken(0) displacement(424)
165 iload #10
167 aload_3
168 iload #4
170 iconst_1
171 iadd
172 baload
173 iconst_0
174 aload #6
176 aload #7
178 iload #8
180 invokestatic 23 <decode> <(BBI[C[II)Ljava/nio/charset/CoderResult;>
  392 bci: 180  CounterData         count(1024)
183 astore #9
185 aload #9
187 ifnull 223
  400 bci: 187  BranchData          taken(1024) displacement(112)
                                    not taken(0)
190 aload #9
********************* 2nd copy of finally block >>>>>>>>>>>>>>>>>>>>>>>>>>
192 astore #11
194 aload_1
195 iload #4
197 aload_1
198 invokevirtual 13 <arrayOffset> <()I>
  416 bci: 198  VirtualCallData     count(0) entries(0)
201 isub
202 invokevirtual 21 <position> <(I)Ljava/nio/Buffer;>
  440 bci: 202  VirtualCallData     count(0) entries(0)
205 pop
206 aload_2
207 aload #7
209 iconst_0
210 iaload
211 aload_2
212 invokevirtual 17 <arrayOffset> <()I>
  464 bci: 212  VirtualCallData     count(0) entries(0)
215 isub
216 invokevirtual 22 <position> <(I)Ljava/nio/Buffer;>
  488 bci: 216  VirtualCallData     count(0) entries(0)
219 pop
220 aload #11
222 areturn
********************* end of finally block <<<<<<<<<<<<<<<<<<<<<<<<<<
223 iinc #4 2
226 goto 363
  512 bci: 226  JumpData            taken(1024) displacement(280)
229 iload #4
231 iconst_4
232 iadd
233 iload #5
235 if_icmple 241
  524 bci: 235  BranchData          taken(0) displacement(28)
                                    not taken(0)
238 goto 366
  540 bci: 238  JumpData            taken(0) displacement(264)
241 getstatic 24 <cnspToIndex> <[B>
244 aload_3
245 iload #4
247 iconst_1
248 iadd
249 baload
250 sipush 255
253 iand
254 baload
255 istore #11
257 iload #11
259 ifge 297
  552 bci: 259  BranchData          taken(0) displacement(120)
                                    not taken(0)
262 iconst_2
263 invokestatic 25 <malformedForLength> <(I)Ljava/nio/charset/CoderResult;>
  568 bci: 263  CounterData         count(0)
********************* 3rd copy of finally block >>>>>>>>>>>>>>>>>>>>>>>>>>
266 astore #12
268 aload_1
269 iload #4
271 aload_1
272 invokevirtual 13 <arrayOffset> <()I>
  576 bci: 272  VirtualCallData     count(0) entries(0)
275 isub
276 invokevirtual 21 <position> <(I)Ljava/nio/Buffer;>
  600 bci: 276  VirtualCallData     count(0) entries(0)
279 pop
280 aload_2
281 aload #7
283 iconst_0
284 iaload
285 aload_2
286 invokevirtual 17 <arrayOffset> <()I>
  624 bci: 286  VirtualCallData     count(0) entries(0)
289 isub
290 invokevirtual 22 <position> <(I)Ljava/nio/Buffer;>
  648 bci: 290  VirtualCallData     count(0) entries(0)
293 pop
294 aload #12
296 areturn
********************* end of finally block <<<<<<<<<<<<<<<<<<<<<<<<<<
297 aload_3
298 iload #4
300 iconst_2
301 iadd
302 baload
303 aload_3
304 iload #4
306 iconst_3
307 iadd
308 baload
309 iload #11
311 aload #6
313 aload #7
315 iload #8
317 invokestatic 23 <decode> <(BBI[C[II)Ljava/nio/charset/CoderResult;>
  672 bci: 317  CounterData         count(0)
320 astore #9
322 aload #9
324 ifnull 360
  680 bci: 324  BranchData          taken(0) displacement(112)
                                    not taken(0)
327 aload #9
********************* 4th copy of finally block >>>>>>>>>>>>>>>>>>>>>>>>>>
329 astore #12
331 aload_1
332 iload #4
334 aload_1
335 invokevirtual 13 <arrayOffset> <()I>
  696 bci: 335  VirtualCallData     count(0) entries(0)
338 isub
339 invokevirtual 21 <position> <(I)Ljava/nio/Buffer;>
  720 bci: 339  VirtualCallData     count(0) entries(0)
342 pop
343 aload_2
344 aload #7
346 iconst_0
347 iaload
348 aload_2
349 invokevirtual 17 <arrayOffset> <()I>
  744 bci: 349  VirtualCallData     count(0) entries(0)
352 isub
353 invokevirtual 22 <position> <(I)Ljava/nio/Buffer;>
  768 bci: 353  VirtualCallData     count(0) entries(0)
356 pop
357 aload #12
359 areturn
********************* end of finally block <<<<<<<<<<<<<<<<<<<<<<<<<<
360 iinc #4 4
363 goto 60
  792 bci: 363  JumpData            taken(12288) displacement(-600)
366 getstatic 26 <UNDERFLOW> <Ljava/nio/charset/CoderResult;>
********************* 5th copy of finally block >>>>>>>>>>>>>>>>>>>>>>>>>>
369 astore #9
371 aload_1
372 iload #4
374 aload_1
375 invokevirtual 13 <arrayOffset> <()I>
  804 bci: 375  VirtualCallData     count(0) entries(0)
378 isub
379 invokevirtual 21 <position> <(I)Ljava/nio/Buffer;>
  828 bci: 379  VirtualCallData     count(0) entries(0)
382 pop
383 aload_2
384 aload #7
386 iconst_0
387 iaload
388 aload_2
389 invokevirtual 17 <arrayOffset> <()I>
  852 bci: 389  VirtualCallData     count(0) entries(0)
392 isub
393 invokevirtual 22 <position> <(I)Ljava/nio/Buffer;>
  876 bci: 393  VirtualCallData     count(0) entries(0)
396 pop
397 aload #9
399 areturn
********************* end of finally block <<<<<<<<<<<<<<<<<<<<<<<<<<
********************* 6th copy of finally block >>>>>>>>>>>>>>>>>>>>>>>>>>
400 astore #13
402 aload_1
403 iload #4
405 aload_1
406 invokevirtual 13 <arrayOffset> <()I>
  900 bci: 406  VirtualCallData     count(0) entries(0)
409 isub
410 invokevirtual 21 <position> <(I)Ljava/nio/Buffer;>
  924 bci: 410  VirtualCallData     count(0) entries(0)
413 pop
414 aload_2
415 aload #7
417 iconst_0
418 iaload
419 aload_2
420 invokevirtual 17 <arrayOffset> <()I>
  948 bci: 420  VirtualCallData     count(0) entries(0)
423 isub
424 invokevirtual 22 <position> <(I)Ljava/nio/Buffer;>
  972 bci: 424  VirtualCallData     count(0) entries(0)
427 pop
428 aload #13
430 athrow
********************* end of finally block <<<<<<<<<<<<<<<<<<<<<<<<<<


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
        private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {

            byte[] sa = src.array();
            int sp = src.arrayOffset() + src.position();
            int sl = sp + src.remaining();

            char[] da = dst.array();
            int [] dp = new int[1];
            dp[0] = dst.arrayOffset() + dst.position();
            int dl = dp[0] + dst.remaining();
            try {
                while (sp < sl) {
                    CoderResult result;
                    byte byte1 = sa[sp];
                    if (byte1 >= 0) {               // ASCII      G0
                        if (dp[0] == dl)
                            return CoderResult.OVERFLOW;
                        da[dp[0]++] = (char)(byte1 & 0xff);
                        sp++;
                    } else if (byte1 != SS2) {      // Codeset 1  G1
                        if (sp + 1 == sl)
                            break;
                        result = decode(byte1, sa[sp+1], 0, da, dp, dl);
                        if (result != null)
                            return result;
                        sp += 2;
                    } else {                        // Codeset 2  G2
                        if (sp + 4 > sl)
                            break;
                        int cnsPlane = cnspToIndex[sa[sp+1] & 0xff];
                        if (cnsPlane < 0)
                            return CoderResult.malformedForLength(2);
                        result = decode(sa[sp+2], sa[sp+3], cnsPlane, da, dp, dl);
                        if (result != null)
                            return result;
                        sp += 4;
                    }
                }
                return CoderResult.UNDERFLOW;
            } finally {
                src.position(sp - src.arrayOffset());
                dst.position(dp[0] - dst.arrayOffset());
            }
        }

---------- END SOURCE ----------

Comments
This is a consequence of removing jsr/ret instructions, plus we won't change a pattern that is already expected by hotspot
08-12-2015

EVALUATION This is a consequence of removing jsr/ret instructions, and would be very hard to fix.
05-01-2010