EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.impl.services.bytecode]

COVERAGE SUMMARY FOR SOURCE FILE [CodeChunk.java]

nameclass, %method, %block, %line, %
CodeChunk.java100% (1/1)85%  (11/13)95%  (1307/1383)69%  (62/90)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class CodeChunk100% (1/1)85%  (11/13)95%  (1307/1383)69%  (62/90)
<static initializer> 100% (1/1)100% (1121/1121)100% (8/8)
CodeChunk (boolean): void 100% (1/1)96%  (26/27)90%  (9/10)
addChunk (CodeChunk): void 0%   (0/1)0%   (0/8)0%   (0/4)
addInstr (short): void 100% (1/1)86%  (6/7)75%  (3/4)
addInstrCPE (short, int): void 100% (1/1)96%  (25/26)88%  (7/8)
addInstrU1 (short, int): void 100% (1/1)91%  (10/11)80%  (4/5)
addInstrU2 (short, int): void 100% (1/1)91%  (10/11)80%  (4/5)
addInstrU2U1U1 (short, int, short, short): void 100% (1/1)95%  (18/19)86%  (6/7)
addInstrWide (short, int): void 0%   (0/1)0%   (0/27)0%   (0/9)
complete (ClassHolder, ClassMember, int, int): void 100% (1/1)43%  (26/61)50%  (9/18)
fixLengths (int, int, int): void 100% (1/1)100% (55/55)100% (10/10)
getCout (): ClassFormatOutput 100% (1/1)100% (3/3)100% (1/1)
getRelativePC (): int 100% (1/1)100% (7/7)100% (1/1)

1/*
2 
3   Derby - Class org.apache.derby.impl.services.bytecode.CodeChunk
4 
5   Copyright 1998, 2006 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.impl.services.bytecode;
22 
23import org.apache.derby.iapi.services.classfile.CONSTANT_Index_info;
24import org.apache.derby.iapi.services.classfile.CONSTANT_Utf8_info;
25import org.apache.derby.iapi.services.classfile.ClassFormatOutput;
26import org.apache.derby.iapi.services.classfile.ClassHolder;
27import org.apache.derby.iapi.services.classfile.ClassMember;
28import org.apache.derby.iapi.services.classfile.VMDescriptor;
29 
30import org.apache.derby.iapi.services.sanity.SanityManager;
31import org.apache.derby.iapi.services.classfile.VMOpcode;
32import org.apache.derby.iapi.services.io.ArrayOutputStream;
33 
34import java.io.IOException;
35import java.lang.reflect.Modifier;
36import java.util.Arrays;
37 
38/**
39 * This class represents a chunk of code in a CodeAttribute.
40 * Typically, a CodeAttribute represents the code in a method.
41 * If there is a try/catch block, each catch block will get its
42 * own code chunk.  This allows the catch blocks to all be put at
43 * the end of the generated code for a method, which eliminates
44 * the need to generate a jump around each catch block, which
45 * would be a forward reference.
46 */
47final class CodeChunk {
48        
49        /**
50         * Starting point of the byte code stream in the underlying stream/array.
51         */
52        private static final int CODE_OFFSET = 8;
53                
54        // The use of ILOAD for the non-integer types is correct.
55        // We have to assume that the appropriate checks/conversions
56        // are defined on math operation results to ensure that
57        // the type is preserved when/as needed.
58        static final short[] LOAD_VARIABLE = {
59                VMOpcode.ILOAD,        /* vm_byte */
60                VMOpcode.ILOAD,        /* vm_short */
61                VMOpcode.ILOAD,        /* vm_int */
62                VMOpcode.LLOAD,        /* vm_long */
63                VMOpcode.FLOAD,        /* vm_float */
64                VMOpcode.DLOAD,        /* vm_double */
65                VMOpcode.ILOAD,        /* vm_char */
66                VMOpcode.ALOAD        /* vm_reference */
67        };
68 
69        static final short[] LOAD_VARIABLE_FAST = {
70                VMOpcode.ILOAD_0,        /* vm_byte */
71                VMOpcode.ILOAD_0,        /* vm_short */
72                VMOpcode.ILOAD_0,        /* vm_int */
73                VMOpcode.LLOAD_0,        /* vm_long */
74                VMOpcode.FLOAD_0,        /* vm_float */
75                VMOpcode.DLOAD_0,        /* vm_double */
76                VMOpcode.ILOAD_0,        /* vm_char */
77                VMOpcode.ALOAD_0        /* vm_reference */
78        };
79 
80        // The ISTOREs for non-int types are how things work.
81        // It assumes that the appropriate casts are done
82        // on operations on non-ints to ensure that the values
83        // remain in the valid ranges.
84        static final short[] STORE_VARIABLE = {
85                VMOpcode.ISTORE,        /* vm_byte */
86                VMOpcode.ISTORE,        /* vm_short */
87                VMOpcode.ISTORE,        /* vm_int */
88                VMOpcode.LSTORE,        /* vm_long */
89                VMOpcode.FSTORE,        /* vm_float */
90                VMOpcode.DSTORE,        /* vm_double */
91                VMOpcode.ISTORE,        /* vm_char */
92                VMOpcode.ASTORE        /* vm_reference */
93        };
94 
95        static final short[] STORE_VARIABLE_FAST = {
96                VMOpcode.ISTORE_0,        /* vm_byte */
97                VMOpcode.ISTORE_0,        /* vm_short */
98                VMOpcode.ISTORE_0,        /* vm_int */
99                VMOpcode.LSTORE_0,        /* vm_long */
100                VMOpcode.FSTORE_0,        /* vm_float */
101                VMOpcode.DSTORE_0,        /* vm_double */
102                VMOpcode.ISTORE_0,        /* vm_char */
103                VMOpcode.ASTORE_0        /* vm_reference */
104        };
105 
106        static final short ARRAY_ACCESS[] = {
107                VMOpcode.BALOAD,        /* vm_byte */
108                VMOpcode.SALOAD,        /* vm_short */
109                VMOpcode.IALOAD,        /* vm_int */
110                VMOpcode.LALOAD,        /* vm_long */
111                VMOpcode.FALOAD,        /* vm_float */
112                VMOpcode.DALOAD,        /* vm_double */
113                VMOpcode.CALOAD,        /* vm_char */
114                VMOpcode.AALOAD        /* vm_reference */
115        };
116        static final short ARRAY_STORE[] = {
117                VMOpcode.BASTORE,        /* vm_byte */
118                VMOpcode.SASTORE,        /* vm_short */
119                VMOpcode.IASTORE,        /* vm_int */
120                VMOpcode.LASTORE,        /* vm_long */
121                VMOpcode.FASTORE,        /* vm_float */
122                VMOpcode.DASTORE,        /* vm_double */
123                VMOpcode.CASTORE,        /* vm_char */
124                VMOpcode.AASTORE        /* vm_reference */
125        };        
126        static final short[] RETURN_OPCODE = {
127                VMOpcode.IRETURN,  /* 0 = byte      */
128                VMOpcode.IRETURN,  /* 1 = short     */
129                VMOpcode.IRETURN,  /* 2 = int       */
130                VMOpcode.LRETURN,  /* 3 = long      */
131                VMOpcode.FRETURN,  /* 4 = float     */
132                VMOpcode.DRETURN,  /* 5 = double    */
133                VMOpcode.IRETURN,  /* 6 = char      */
134                VMOpcode.ARETURN   /* 7 = reference */
135                };
136 
137        // the first dimension is the current vmTypeId
138        // the second dimension is the target vmTypeId
139        //
140        // the cells of the entry at [current,target] are:
141        // 0: operation
142        // 1: result type of operation
143        // if entry[1] = target, we are done. otherwise,
144        // you have to continue with entry[1] as the new current
145        // after generating the opcode listed (don't generate if it is NOP).
146        // if entry[0] = BAD, we can
147        
148        static final short CAST_CONVERSION_INFO[][][] = {
149                /* current = vm_byte */
150                {
151                /* target = vm_byte      */ { VMOpcode.NOP, BCExpr.vm_byte },
152                /* target = vm_short     */ { VMOpcode.NOP, BCExpr.vm_short },
153                /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },
154                /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_int },
155                /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_int },
156                /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_int },
157                /* target = vm_char      */ { VMOpcode.NOP, BCExpr.vm_char }, 
158                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
159                },
160                /* current = vm_short */
161                {
162                /* target = vm_byte      */ { VMOpcode.NOP, BCExpr.vm_byte },
163                /* target = vm_short     */ { VMOpcode.NOP, BCExpr.vm_short },
164                /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },
165                /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_int },
166                /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_int },
167                /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_int },
168                /* target = vm_char      */ { VMOpcode.NOP, BCExpr.vm_char }, 
169                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
170                },
171                /* current = vm_int */
172                {
173                /* target = vm_byte      */ { VMOpcode.I2B, BCExpr.vm_byte },
174                /* target = vm_short     */ { VMOpcode.I2S, BCExpr.vm_short },
175                /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },
176                /* target = vm_long      */ { VMOpcode.I2L, BCExpr.vm_long },
177                /* target = vm_float     */ { VMOpcode.I2F, BCExpr.vm_float },
178                /* target = vm_double    */ { VMOpcode.I2D, BCExpr.vm_double },
179                /* target = vm_char      */ { VMOpcode.I2B, BCExpr.vm_char }, 
180                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
181                },
182                /* current = vm_long */
183                {
184                /* target = vm_byte      */ { VMOpcode.L2I, BCExpr.vm_int },
185                /* target = vm_short     */ { VMOpcode.L2I, BCExpr.vm_int },
186                /* target = vm_int       */ { VMOpcode.L2I, BCExpr.vm_int },
187                /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_long },
188                /* target = vm_float     */ { VMOpcode.L2F, BCExpr.vm_float },
189                /* target = vm_double    */ { VMOpcode.L2D, BCExpr.vm_double },
190                /* target = vm_char      */ { VMOpcode.L2I, BCExpr.vm_int }, 
191                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
192                },
193                /* current = vm_float */
194                {
195                /* target = vm_byte      */ { VMOpcode.F2I, BCExpr.vm_int },
196                /* target = vm_short     */ { VMOpcode.F2I, BCExpr.vm_int },
197                /* target = vm_int       */ { VMOpcode.F2I, BCExpr.vm_int },
198                /* target = vm_long      */ { VMOpcode.F2L, BCExpr.vm_long },
199                /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_float },
200                /* target = vm_double    */ { VMOpcode.F2D, BCExpr.vm_double },
201                /* target = vm_char      */ { VMOpcode.F2I, BCExpr.vm_int }, 
202                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
203                },
204                /* current = vm_double */
205                {
206                /* target = vm_byte      */ { VMOpcode.D2I, BCExpr.vm_int },
207                /* target = vm_short     */ { VMOpcode.D2I, BCExpr.vm_int },
208                /* target = vm_int       */ { VMOpcode.D2I, BCExpr.vm_int },
209                /* target = vm_long      */ { VMOpcode.D2L, BCExpr.vm_long },
210                /* target = vm_float     */ { VMOpcode.D2F, BCExpr.vm_float },
211                /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_double },
212                /* target = vm_char      */ { VMOpcode.D2I, BCExpr.vm_int }, 
213                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
214                },
215                /* current = vm_char */
216                {
217                /* target = vm_byte      */ { VMOpcode.NOP, BCExpr.vm_byte },
218                /* target = vm_short     */ { VMOpcode.NOP, BCExpr.vm_short },
219                /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },
220                /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_int },
221                /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_int },
222                /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_int },
223                /* target = vm_char      */ { VMOpcode.NOP, BCExpr.vm_char },
224                /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
225                },
226                /* current = vm_reference */
227                {
228                /* target = vm_byte      */ { VMOpcode.BAD, BCExpr.vm_byte },
229                /* target = vm_short     */ { VMOpcode.BAD, BCExpr.vm_short },
230                /* target = vm_int       */ { VMOpcode.BAD, BCExpr.vm_int },
231                /* target = vm_long      */ { VMOpcode.BAD, BCExpr.vm_long },
232                /* target = vm_float     */ { VMOpcode.BAD, BCExpr.vm_float },
233                /* target = vm_double    */ { VMOpcode.BAD, BCExpr.vm_double },
234                /* target = vm_char      */ { VMOpcode.BAD, BCExpr.vm_char },
235                /* target = vm_reference */ { VMOpcode.NOP, BCExpr.vm_reference }
236                }
237        };
238        
239        /**
240         * Constant used by OPCODE_ACTION to represent the
241         * common action of push one word, 1 byte
242         * for the instruction.
243         */
244        private static final byte[] push1_1i = {1, 1};
245 
246        /**
247         * Constant used by OPCODE_ACTION to represent the
248         * common action of push two words, 1 byte
249         * for the instruction.
250         */
251        private static final byte[] push2_1i = {2, 1};        
252        /**
253         * Constant used by OPCODE_ACTION to the opcode is
254         * not yet supported.
255         */
256        private static final byte[] NS = {0, -1};
257        
258        
259        /**
260         * Value for OPCODE_ACTION[opcode][0] to represent
261         * the number of words popped or pushed in variable.
262         */
263        private static final byte VARIABLE_STACK = -128;
264        
265        /**
266         * Array that provides two pieces of information about
267         * each VM opcode. Each opcode has a two byte array.
268         * <P>
269         * The first element in the array [0] is the number of
270         * stack words (double/long count as two) pushed by the opcode.
271         * Will be negative if the opcode pops values.
272         * 
273         * <P>
274         * The second element in the array [1] is the number of bytes
275         * in the instruction stream that this opcode's instruction
276         * takes up, including the opocode.
277         */
278        private static final byte[][] OPCODE_ACTION =
279        {
280        
281    /* NOP  0 */           { 0, 1 },
282    
283    /* ACONST_NULL  1 */  push1_1i,
284    /* ICONST_M1  2 */    push1_1i,
285    /* ICONST_0  3 */     push1_1i,
286    /* ICONST_1  4 */     push1_1i,
287    /* ICONST_2  5 */     push1_1i,
288    /* ICONST_3  6 */     push1_1i,
289    /* ICONST_4  7 */     push1_1i,
290    /* ICONST_5  8 */     push1_1i,
291    /* LCONST_0  9 */     push2_1i,
292    /* LCONST_1  10 */    push2_1i,
293    /* FCONST_0  11 */    push1_1i,
294    /* FCONST_1  12 */    push1_1i,
295    /* FCONST_2  13 */    push1_1i,
296    /* DCONST_0  14 */    push2_1i,
297    /* DCONST_1  15 */    push2_1i,
298    
299    /* BIPUSH  16 */     {1, 2},
300    /* SIPUSH  17 */     {1, 3},
301    /* LDC  18 */        {1, 2},
302    /* LDC_W  19 */      {1, 3},
303    /* LDC2_W  20 */     {2, 3},
304    
305    /* ILOAD  21 */     { 1, 2 },
306    /* LLOAD  22 */     { 2, 2 },
307    /* FLOAD  23 */     { 1, 2 },
308    /* DLOAD  24 */     { 2, 2 },
309    /* ALOAD  25 */     { 1, 2 },
310    /* ILOAD_0  26 */   push1_1i,
311    /* ILOAD_1  27 */   push1_1i,
312    /* ILOAD_2  28 */   push1_1i,
313    /* ILOAD_3  29 */   push1_1i,
314    /* LLOAD_0  30 */   push2_1i,
315    /* LLOAD_1  31 */   push2_1i,
316    /* LLOAD_2  32 */   push2_1i,
317    /* LLOAD_3  33 */   push2_1i,
318    /* FLOAD_0  34 */   push1_1i,
319    /* FLOAD_1  35 */   push1_1i,
320    /* FLOAD_2  36 */   push1_1i,
321    /* FLOAD_3  37 */   push1_1i,
322    /* DLOAD_0  38 */   push2_1i,
323    /* DLOAD_1  39 */   push2_1i,
324    /* DLOAD_2  40 */   push2_1i,
325    /* DLOAD_3  41 */   push2_1i,
326    /* ALOAD_0  42 */   push1_1i,
327    /* ALOAD_1  43 */   push1_1i,
328    /* ALOAD_2  44 */   push1_1i,
329    /* ALOAD_3  45 */   push1_1i,
330    /* IALOAD  46 */    { -1, 1 },
331    /* LALOAD  47 */    { 0, 1 },
332    /* FALOAD  48 */    { -1, 1 },
333    /* DALOAD  49 */    { 0, 1 },
334    /* AALOAD  50 */    { -1, 1 },
335    /* BALOAD  51 */    { -1, 1 },
336    /* CALOAD  52 */    { -1, 1 },
337    
338    /* SALOAD  53 */       { -1, 1 },
339    /* ISTORE  54 */       { -1, 2 },
340    /* LSTORE  55 */       { -2, 2 },
341    /* FSTORE  56 */       { -1, 2 },
342    /* DSTORE  57 */       { -2, 2 },
343    /* ASTORE  58 */       { -1, 2 },
344    /* ISTORE_0  59 */     { -1, 1 },
345    /* ISTORE_1  60 */     { -1, 1 },
346    /* ISTORE_2  61 */     { -1, 1 },
347    /* ISTORE_3  62 */     { -1, 1 },
348    /* LSTORE_0  63 */     { -2, 1 },
349    /* LSTORE_1  64 */     { -2, 1 },
350    /* LSTORE_2  65 */     { -2, 1 },
351    /* LSTORE_3  66 */     { -2, 1 },
352    /* FSTORE_0  67 */     { -1, 1 },
353    /* FSTORE_1  68 */     { -1, 1 },
354    /* FSTORE_2  69 */     { -1, 1 },
355    /* FSTORE_3  70 */     { -1, 1 },
356    /* DSTORE_0  71 */     { -2, 1 },
357    /* DSTORE_1  72 */     { -2, 1 },
358    /* DSTORE_2  73 */     { -2, 1 },
359    /* DSTORE_3  74 */     { -2, 1 },
360    /* ASTORE_0  75 */     { -1, 1 },
361    /* ASTORE_1  76 */     { -1, 1 },
362    /* ASTORE_2  77 */     { -1, 1 },
363    /* ASTORE_3  78 */     { -1, 1 },
364    /* IASTORE  79 */      { -3, 1 },
365    /* LASTORE  80 */      { -4, 1 },
366    /* FASTORE  81 */      { -3, 1 },
367    /* DASTORE  82 */      { -4, 1 },
368    /* AASTORE  83 */      { -3, 1 },
369    /* BASTORE  84 */      { -3, 1 },
370    /* CASTORE  85 */      { -3, 1 },
371    /* SASTORE  86 */      { -3, 1 },
372    
373    /* POP  87 */      { -1, 1 },
374    /* POP2  88 */     { -2, 1 },
375    /* DUP  89 */      push1_1i,
376    /* DUP_X1  90 */   push1_1i,
377    /* DUP_X2  91 */   push1_1i,
378    /* DUP2  92 */     push2_1i,
379    /* DUP2_X1  93 */  push2_1i,
380    /* DUP2_X2  94 */  push2_1i,
381    /* SWAP  95 */     { 0, 1 },
382    
383    /* IADD  96 */     NS,
384    /* LADD  97 */     NS,
385    /* FADD  98 */     { -1, 1 },
386    /* DADD  99 */     { -2, 1 },
387    /* ISUB  100 */     NS,
388    /* LSUB  101 */     NS,
389    /* FSUB  102 */     { -1, 1 },
390    /* DSUB  103 */     { -2, 1 },
391    /* IMUL  104 */     NS,
392    /* LMUL  105 */     NS,
393    /* FMUL  106 */     { -1, 1 },
394    /* DMUL  107 */     { -2, 1 },
395    /* IDIV  108 */     NS,
396    /* LDIV  109 */     NS,
397    /* FDIV  110 */     { -1, 1 },
398    /* DDIV  111 */     { -2, 1 },
399    /* IREM  112 */     { -1, 1 },
400    /* LREM  113 */     { -2, 1 },
401    /* FREM  114 */     { -1, 1 },
402    /* DREM  115 */     { -2, 1 },
403    /* INEG  116 */     { 0, 1 },
404    /* LNEG  117 */     { 0, 1 },
405    /* FNEG  118 */     { 0, 1 },
406    /* DNEG  119 */     { 0, 1 },
407    /* ISHL  120 */     { -1, 1 },
408    /* LSHL  121 */     NS,
409    /* ISHR  122 */     NS,
410    /* LSHR  123 */     NS,
411    /* IUSHR  124 */     NS,
412    /* LUSHR  125 */     NS,
413    
414    /* IAND  126 */     { -1, 1 },
415    /* LAND  127 */     NS,
416    /* IOR  128 */      { -1, 1 },
417    /* LOR  129 */      NS,
418    /* IXOR  130 */     NS,
419    /* LXOR  131 */     NS,
420    /* IINC  132 */     NS,
421    
422    /* I2L  133 */     push1_1i,
423    /* I2F  134 */     { 0, 1 },
424    /* I2D  135 */     push1_1i,
425    /* L2I  136 */     { -1, 1 },
426    /* L2F  137 */     { -1, 1 },
427    /* L2D  138 */     { 0, 1 },
428    /* F2I  139 */     { 0, 1 },
429    /* F2L  140 */     push2_1i,
430    /* F2D  141 */     push1_1i,
431    /* D2I  142 */     { -1, 1 },
432    /* D2L  143 */     { 0, 1 },
433    /* D2F  144 */     { -1, 1 },
434    /* I2B  145 */     { 0, 1 },
435    /* I2C  146 */     { 0, 1 },
436    /* I2S  147 */     { 0, 1 },
437    
438    /* LCMP  148 */        NS,
439    /* FCMPL  149 */       { -1, 1 },
440    /* FCMPG  150 */       { -1, 1 },
441    /* DCMPL  151 */       { -3, 1 },
442    /* DCMPG  152 */       { -3, 1 },
443    /* IFEQ  153 */        { -1, VMOpcode.IF_INS_LENGTH },
444    /* IFNE  154 */        { -1, VMOpcode.IF_INS_LENGTH },
445    /* IFLT  155 */        { -1, VMOpcode.IF_INS_LENGTH },
446    /* IFGE  156 */        { -1, VMOpcode.IF_INS_LENGTH },
447    /* IFGT  157 */        { -1, VMOpcode.IF_INS_LENGTH },
448    /* IFLE  158 */        { -1, VMOpcode.IF_INS_LENGTH },
449    /* IF_ICMPEQ  159 */   NS,
450    /* IF_ICMPNE  160 */   NS,
451    /* IF_ICMPLT  161 */   NS,
452    /* IF_ICMPGE  162 */   NS,
453    /* IF_ICMPGT  163 */   NS,
454    /* IF_ICMPLE  164 */   NS,
455    /* IF_ACMPEQ  165 */   NS,
456    /* IF_ACMPNE  166 */   NS,
457    /* GOTO  167 */        { 0, VMOpcode.GOTO_INS_LENGTH },
458    /* JSR  168 */         NS,
459    /* RET  169 */         NS,
460    /* TABLESWITCH  170 */ NS,
461    /* LOOKUPSWITCH  171 */NS,
462    
463    /* IRETURN  172 */     { -1, 1 }, // strictly speaking all words on the stack are popped.
464    /* LRETURN  173 */     { -2, 1 }, // strictly speaking all words on the stack are popped.
465    /* FRETURN  174 */     { -1, 1 }, // strictly speaking all words on the stack are popped.
466    /* DRETURN  175 */     { -2, 1 }, // strictly speaking all words on the stack are popped.
467    /* ARETURN  176 */     { -1, 1 }, // strictly speaking all words on the stack are popped.
468    /* RETURN  177 */      { 0, 1 }, // strictly speaking all words on the stack are popped.
469 
470    /* GETSTATIC  178 */           {VARIABLE_STACK, 3 },
471    /* PUTSTATIC  179 */           {VARIABLE_STACK, 3 },
472    /* GETFIELD  180 */            {VARIABLE_STACK, 3 },
473    /* PUTFIELD  181 */            {VARIABLE_STACK, 3 },
474    /* INVOKEVIRTUAL  182 */       {VARIABLE_STACK, 3 },
475    /* INVOKESPECIAL  183 */       {VARIABLE_STACK, 3 },
476    /* INVOKESTATIC  184 */        {VARIABLE_STACK, 3 },
477    /* INVOKEINTERFACE  185 */     {VARIABLE_STACK, 5 },
478    
479    /* XXXUNUSEDXXX  186 */        NS,
480 
481    /* NEW  187 */                 { 1, 3 },
482    /* NEWARRAY  188 */            { 0, 2 },
483    /* ANEWARRAY  189 */           { 0, 3 },
484    /* ARRAYLENGTH  190 */         { 0, 1 },
485    /* ATHROW  191 */              NS,
486    /* CHECKCAST  192 */           { 0, 3},
487    /* INSTANCEOF  193 */          { 0, 3 },
488    /* MONITORENTER  194 */        NS,
489    /* MONITOREXIT  195 */         NS,
490    /* WIDE  196 */                NS,
491    /* MULTIANEWARRAY  197 */      NS,
492    /* IFNULL  198 */              { -1, VMOpcode.IF_INS_LENGTH },
493    /* IFNONNULL  199 */           { -1, VMOpcode.IF_INS_LENGTH },
494    /* GOTO_W  200 */              {0, VMOpcode.GOTO_W_INS_LENGTH },
495    /* JSR_W  201 */               NS,
496    /* BREAKPOINT  202 */          NS,
497        
498        };
499        
500        
501        
502        /**
503         * Add an instruction that has no operand.
504         * All opcodes are 1 byte large.
505         */
506        void addInstr(short opcode) {
507                try {
508                cout.putU1(opcode);
509                } catch (IOException ioe) {
510                }
511 
512                if (SanityManager.DEBUG) {                        
513                        if (OPCODE_ACTION[opcode][1] != 1)
514                                SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
515                                                " writing 1 byte - set as " + OPCODE_ACTION[opcode][1]);                
516                }
517        }
518 
519        /**
520         * Add an instruction that has a 16 bit operand.
521         */
522        void addInstrU2(short opcode, int operand) {
523                try {
524                cout.putU1(opcode);
525                cout.putU2(operand);
526                } catch (IOException ioe) {
527                }
528 
529                if (SanityManager.DEBUG) {                        
530                        if (OPCODE_ACTION[opcode][1] != 3)
531                                SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
532                                                " writing 3 bytes - set as " + OPCODE_ACTION[opcode][1]);                
533                }
534        }
535 
536        /**
537         * Add an instruction that has a 32 bit operand.
538         */
539     void addInstrU4(short opcode, int operand) {
540                try {
541                cout.putU1(opcode);
542                cout.putU4(operand);
543                } catch (IOException ioe) {
544                }
545                if (SanityManager.DEBUG) {                        
546                        if (OPCODE_ACTION[opcode][1] != 5)
547                                SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
548                                                " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]);                
549                }
550        }
551 
552     
553         /**
554          * Add an instruction that has an 8 bit operand.
555          */
556     void addInstrU1(short opcode, int operand) {
557                try {
558                cout.putU1(opcode);
559                cout.putU1(operand);
560                } catch (IOException ioe) {
561                }
562 
563                // Only debug code from here.
564                if (SanityManager.DEBUG) {
565                        
566                        if (OPCODE_ACTION[opcode][1] != 2)
567                                SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
568                                                " writing 2 bytes - set as " + OPCODE_ACTION[opcode][1]);
569                
570                }
571        }
572 
573        /**
574         * This takes an instruction that has a narrow
575         * and a wide form for CPE access, and
576         * generates accordingly the right one.
577         * We assume the narrow instruction is what
578         * we were given, and that the wide form is
579         * the next possible instruction.
580         */
581        void addInstrCPE(short opcode, int cpeNum) {
582                if (cpeNum < 256) {
583                        addInstrU1(opcode, cpeNum);
584                }
585                else {
586                        addInstrU2((short) (opcode+1), cpeNum);
587                }
588        }
589 
590        /**
591         * This takes an instruction that can be wrapped in
592         * a wide for large variable #s and does so.
593         */
594        void addInstrWide(short opcode, int varNum) {
595                if (varNum < 256) {
596                        addInstrU1(opcode, varNum);
597                }
598                else {
599                        addInstr(VMOpcode.WIDE);
600                        addInstrU2(opcode, varNum);
601                }
602        }
603 
604        /**
605         * For adding an instruction with 3 operands, a U2 and two U1's.
606         * So far, this is used by VMOpcode.INVOKEINTERFACE.
607         */
608        void addInstrU2U1U1(short opcode, int operand1, short operand2,
609                short operand3) {
610                try {
611                cout.putU1(opcode);
612                cout.putU2(operand1);
613                cout.putU1(operand2);
614                cout.putU1(operand3);
615                } catch (IOException ioe) {
616                }
617                if (SanityManager.DEBUG) {                        
618                        if (OPCODE_ACTION[opcode][1] != 5)
619                                SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
620                                                " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]);                
621                }
622        }
623 
624        /** Get the current program counter */
625        int getPC() {
626                return cout.size() + pcDelta;
627        }
628        
629        /**
630         * Return the complete instruction length for the
631         * passed in opcode. This will include the space for
632         * the opcode and its operand.
633         */
634        private static int instructionLength(short opcode)
635        {
636                int instructionLength = OPCODE_ACTION[opcode][1];
637                
638                if (SanityManager.DEBUG)
639                {
640                        if (instructionLength < 0)
641                                SanityManager.THROWASSERT("Opcode without instruction length " + opcode);
642                }
643                
644                return instructionLength;
645        }
646        
647        /**
648         * The delta between cout.size() and the pc.
649         * For an initial code chunk this is -8 (CODE_OFFSET)
650         * since 8 bytes are written.
651         * For a nested CodeChunk return by insertCodeSpace the delta
652         * corresponds to the original starting pc.
653         * @see #insertCodeSpace
654         */
655        private final int pcDelta;
656 
657        CodeChunk() {
658        cout = new ClassFormatOutput();
659                try {
660                        cout.putU2(0); // max_stack, placeholder for now
661                        cout.putU2(0); // max_locals, placeholder for now
662                        cout.putU4(0); // code_length, placeholder 4 now
663                } catch (IOException ioe) {
664                }
665                pcDelta = - CodeChunk.CODE_OFFSET;
666        }
667        
668        /**
669         * Return a CodeChunk that has limited visibility into
670         * this CodeChunk. Used when a caller needs to insert instructions
671         * into an existing stream.
672         * @param pc
673         * @param byteCount
674         * @throws IOException 
675         */
676        private CodeChunk(CodeChunk main, int pc, int byteCount)
677        {
678                ArrayOutputStream aos =
679                        new ArrayOutputStream(main.cout.getData());
680                
681                try {
682                        aos.setPosition(CODE_OFFSET + pc);
683                        aos.setLimit(byteCount);
684                } catch (IOException e) {
685                }
686                
687                cout = new ClassFormatOutput(aos);
688                pcDelta = pc;
689        }
690 
691        private final ClassFormatOutput cout;
692 
693        /**
694         * now that we have codeBytes, fix the lengths fields in it
695         * to reflect what was stored.
696         * Limits checked here are from these sections of the JVM spec.
697         * <UL>
698         * <LI> 4.7.3 The Code Attribute
699         * <LI> 4.10 Limitations of the Java Virtual Machine 
700         * </UL>
701         */
702        private void fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength) {
703 
704                byte[] codeBytes = cout.getData();
705 
706                // max_stack is in bytes 0-1
707                if (mb != null && maxStack > 65535)
708                        mb.cb.addLimitExceeded(mb, "max_stack", 65535, maxStack);
709                        
710                codeBytes[0] = (byte)(maxStack >> 8 );
711                codeBytes[1] = (byte)(maxStack );
712 
713                // max_locals is in bytes 2-3
714                if (mb != null && maxLocals > 65535)
715                        mb.cb.addLimitExceeded(mb, "max_locals", 65535, maxLocals);
716                codeBytes[2] = (byte)(maxLocals >> 8 );
717                codeBytes[3] = (byte)(maxLocals );
718 
719                // code_length is in bytes 4-7
720                if (mb != null && codeLength > VMOpcode.MAX_CODE_LENGTH)
721                        mb.cb.addLimitExceeded(mb, "code_length",
722                                        VMOpcode.MAX_CODE_LENGTH, codeLength);
723                codeBytes[4] = (byte)(codeLength >> 24 );
724                codeBytes[5] = (byte)(codeLength >> 16 );
725                codeBytes[6] = (byte)(codeLength >> 8 );
726                codeBytes[7] = (byte)(codeLength );                        
727        }
728 
729        /**
730         * wrap up the entry and stuff it in the class,
731         * now that it holds all of the instructions and
732         * the exception table.
733         */
734        void complete(BCMethod mb, ClassHolder ch,
735                        ClassMember method, int maxStack, int maxLocals) {
736 
737        int codeLength =  getPC();
738 
739                ClassFormatOutput out = cout;
740                
741                try {
742 
743                        out.putU2(0); // exception_table_length
744 
745                        if (SanityManager.DEBUG) {
746                          if (SanityManager.DEBUG_ON("ClassLineNumbers")) {
747                                // Add a single attribute - LineNumberTable
748                                // This add fake line numbers that are the pc offset in the method.
749                                out.putU2(1); // attributes_count
750 
751                                int cpiUTF = ch.addUtf8("LineNumberTable");
752 
753                                out.putU2(cpiUTF);
754                                out.putU4((codeLength * 4) + 2);
755                                out.putU2(codeLength);
756                                for (int i = 0; i < codeLength; i++) {
757                                        out.putU2(i);
758                                        out.putU2(i);
759                                }
760                          } else {
761                                  out.putU2(0); // attributes_count
762                          }
763 
764                        } else {
765                                out.putU2(0); // attributes_count
766                                // attributes is empty, a 0-element array.
767                        }
768                } catch (IOException ioe) {
769                }
770 
771                fixLengths(mb, maxStack, maxLocals, codeLength);
772                method.addAttribute("Code", out);
773                
774                if (SanityManager.DEBUG)
775                {
776            // Only validate if the class file format is valid.
777            // Ok code length and guaranteed no errors building the class.
778            if ((codeLength <= VMOpcode.MAX_CODE_LENGTH)
779                && (mb != null && mb.cb.limitMsg == null))
780            {              
781                                // Validate the alternate way to calculate the
782                                // max stack agrees with the dynamic as the code
783                                // is built way.
784                                int walkedMaxStack = findMaxStack(ch, 0, codeLength);
785                                if (walkedMaxStack != maxStack)
786                                {
787                                        SanityManager.THROWASSERT("MAX STACK MISMATCH!! " +
788                                                        maxStack + " <> " + walkedMaxStack);
789                                }
790                        }
791                }
792 
793        }
794        /**
795         * Return the opcode at the given pc.
796         */
797        short getOpcode(int pc)
798        {
799                return (short) (cout.getData()[CODE_OFFSET + pc] & 0xff);
800        }
801        
802        /**
803         * Get the unsigned short value for the opcode at the program
804         * counter pc.
805         */
806        private int getU2(int pc)
807        {
808                byte[] codeBytes = cout.getData();
809                
810                int u2p = CODE_OFFSET + pc + 1;
811                
812                return ((codeBytes[u2p] & 0xff) << 8) | (codeBytes[u2p+1] & 0xff);
813        }
814 
815        /**
816         * Get the unsigned 32 bit value for the opcode at the program
817         * counter pc.
818         */
819        private int getU4(int pc)
820        {
821                byte[] codeBytes = cout.getData();
822                
823                int u4p = CODE_OFFSET + pc + 1;
824                
825                return (((codeBytes[u4p] & 0xff) << 24) |
826                        ((codeBytes[u4p+1] & 0xff) << 16) |
827                        ((codeBytes[u4p+2] & 0xff) << 8) |
828                        ((codeBytes[u4p+3] & 0xff)));
829        }        
830        /**
831         * Insert room for byteCount bytes after the instruction at pc
832         * and prepare to replace the instruction at pc. The instruction
833         * at pc is not modified by this call, space is allocated after it.
834         * The newly inserted space will be filled with NOP instructions.
835         * 
836         * Returns a CodeChunk positioned at pc and available to write
837         * instructions upto (byteCode + length(existing instruction at pc) bytes.
838         * 
839         * This chunk is left correctly positioned at the end of the code
840         * stream, ready to accept more code. Its pc will have increased by
841         * additionalBytes.
842         * 
843         * It is the responsibility of the caller to patch up any
844         * branches or gotos.
845         * 
846         * @param pc
847         * @param additionalBytes
848         */
849        CodeChunk insertCodeSpace(int pc, int additionalBytes)
850        {
851                short existingOpcode = getOpcode(pc);
852 
853                int lengthOfExistingInstruction
854                    = instructionLength(existingOpcode);
855                        
856                
857                if (additionalBytes > 0)
858                {
859                        // Size of the current code after this pc.
860                        int sizeToMove = (getPC() - pc) - lengthOfExistingInstruction;
861 
862                        // Increase the code by the number of bytes to be
863                        // inserted. These NOPs will be overwritten by the
864                        // moved code by the System.arraycopy below.
865                        // It's assumed that the number of inserted bytes
866                        // is small, one or two instructions worth, so it
867                        // won't be a performance issue.
868                        for (int i = 0; i < additionalBytes; i++)
869                                addInstr(VMOpcode.NOP);
870                
871                        // Must get codeBytes here as the array might have re-sized.
872                        byte[] codeBytes = cout.getData();
873                        
874                        int byteOffset = CODE_OFFSET + pc + lengthOfExistingInstruction;
875                                        
876                        
877                        // Shift the existing code stream down
878                        System.arraycopy(
879                                        codeBytes, byteOffset,
880                                        codeBytes, byteOffset + additionalBytes,
881                                        sizeToMove);
882                        
883                        // Place NOPs in the space just freed by the move.
884                        // This is not required, it ias assumed the caller
885                        // will overwrite all the bytes they requested, but
886                        // to be safe fill in with NOPs rather than leaving code
887                        // that could break the verifier.
888                        Arrays.fill(codeBytes, byteOffset, byteOffset + additionalBytes,
889                                        (byte) VMOpcode.NOP);
890                }
891                
892                // The caller must overwrite the original instruction
893                // at pc, thus increase the range of the limit stream
894                // created to include those bytes.
895                additionalBytes += lengthOfExistingInstruction;
896                
897                // Now the caller needs to fill in the instructions
898                // that make up the modified byteCount bytes of bytecode stream.
899                // Return a CodeChunk that can be used for this and
900                // is limited to only those bytes.
901                // The pc of the original code chunk is left unchanged.
902                
903                return new CodeChunk(this, pc, additionalBytes);
904                                                
905        }
906        
907        /*
908     * * Methods related to splitting the byte code chunks into sections that
909     * fit in the JVM's limits for a single method.
910     */
911 
912    /**
913     * For a block of byte code starting at program counter pc for codeLength
914     * bytes return the maximum stack value, assuming a initial stack depth of
915     * zero.
916     */
917    private int findMaxStack(ClassHolder ch, int pc, int codeLength) {
918 
919        int endPc = pc + codeLength;
920        int stack = 0;
921        int maxStack = 0;
922 
923        for (; pc < endPc;) {
924 
925            short opcode = getOpcode(pc);
926            
927 
928            int stackDelta = stackWordDelta(ch, pc, opcode);
929 
930            stack += stackDelta;
931            if (stack > maxStack)
932                maxStack = stack;
933 
934            int[] cond_pcs = findConditionalPCs(pc, opcode);
935            if (cond_pcs != null) {
936                // an else block exists.
937                if (cond_pcs[3] != -1) {
938                    int blockMaxStack = findMaxStack(ch, cond_pcs[1],
939                            cond_pcs[2]);
940                    if ((stack + blockMaxStack) > maxStack)
941                        maxStack = stack + blockMaxStack;
942 
943                    pc = cond_pcs[3];
944                    continue;
945                }
946            }
947 
948            pc += instructionLength(opcode);
949        }
950 
951        return maxStack;
952    }
953 
954    /**
955     * Return the number of stack words pushed (positive) or popped (negative)
956     * by this instruction.
957     */
958    private int stackWordDelta(ClassHolder ch, int pc, short opcode) {
959        if (SanityManager.DEBUG) {
960            // this validates the OPCODE_ACTION entry
961            instructionLength(opcode);
962        }
963 
964        int stackDelta = OPCODE_ACTION[opcode][0];
965        if (stackDelta == VARIABLE_STACK) {
966            stackDelta = getVariableStackDelta(ch, pc, opcode);
967        }
968 
969        return stackDelta;
970    }
971 
972    /**
973     * Get the type descriptor in the virtual machine format for the type
974     * defined by the constant pool index for the instruction at pc.
975     */
976    private String getTypeDescriptor(ClassHolder ch, int pc) {
977        int cpi = getU2(pc);
978 
979        // Field reference or method reference
980        CONSTANT_Index_info cii = (CONSTANT_Index_info) ch.getEntry(cpi);
981 
982        // NameAndType reference
983        int nameAndType = cii.getI2();
984        cii = (CONSTANT_Index_info) ch.getEntry(nameAndType);
985 
986        // UTF8 descriptor
987        int descriptor = cii.getI2();
988        CONSTANT_Utf8_info type = (CONSTANT_Utf8_info) ch.getEntry(descriptor);
989 
990        String vmDescriptor = type.toString();
991 
992        return vmDescriptor;
993    }
994 
995    /**
996     * Get the word count for a type descriptor in the format of the virual
997     * machine. For a method this returns the the word count for the return
998     * type.
999     */
1000    private static int getDescriptorWordCount(String vmDescriptor) {
1001 
1002        int width;
1003        if (VMDescriptor.DOUBLE.equals(vmDescriptor))
1004            width = 2;
1005        else if (VMDescriptor.LONG.equals(vmDescriptor))
1006            width = 2;
1007        else if (vmDescriptor.charAt(0) == VMDescriptor.C_METHOD) {
1008            switch (vmDescriptor.charAt(vmDescriptor.length() - 1)) {
1009            case VMDescriptor.C_DOUBLE:
1010            case VMDescriptor.C_LONG:
1011                width = 2;
1012                break;
1013            case VMDescriptor.C_VOID:
1014                width = 0;
1015                break;
1016            default:
1017                width = 1;
1018                break;
1019            }
1020        } else
1021            width = 1;
1022 
1023        return width;
1024    }
1025 
1026    /**
1027     * Get the number of words pushed (positive) or popped (negative) by this
1028     * instruction. The instruction is a get/put field or a method call, thus
1029     * the size of the words is defined by the field or method being access.
1030     */
1031    private int getVariableStackDelta(ClassHolder ch, int pc, int opcode) {
1032        String vmDescriptor = getTypeDescriptor(ch, pc);
1033        int width = CodeChunk.getDescriptorWordCount(vmDescriptor);
1034 
1035        int stackDelta = 0;
1036        // Stack delta depends on context.
1037        switch (opcode) {
1038        case VMOpcode.GETSTATIC:
1039            stackDelta = width;
1040            break;
1041 
1042        case VMOpcode.GETFIELD:
1043            stackDelta = width - 1; // one for popped object ref
1044            break;
1045 
1046        case VMOpcode.PUTSTATIC:
1047            stackDelta = -width;
1048            break;
1049 
1050        case VMOpcode.PUTFIELD:
1051            stackDelta = -width - 1; // one for pop object ref
1052            break;
1053 
1054        case VMOpcode.INVOKEVIRTUAL:
1055        case VMOpcode.INVOKESPECIAL:
1056            stackDelta = -1; // for instance reference for method call.
1057        case VMOpcode.INVOKESTATIC:
1058            stackDelta += (width - CodeChunk.parameterWordCount(vmDescriptor));
1059            // System.out.println("invoked non-interface " + stackDelta);
1060            break;
1061 
1062        case VMOpcode.INVOKEINTERFACE:
1063            // third byte contains the number of arguments to be popped
1064            stackDelta = width - getOpcode(pc + 3);
1065            // System.out.println("invoked interface " + stackDelta);
1066            break;
1067        default:
1068            System.out.println("WHO IS THIS ");
1069            break;
1070 
1071        }
1072 
1073        return stackDelta;
1074    }
1075 
1076    /**
1077     * Calculate the number of stack words in the arguments pushed for this
1078     * method descriptor.
1079     */
1080    private static int parameterWordCount(String methodDescriptor) {
1081        int wordCount = 0;
1082        for (int i = 1;; i++) {
1083            switch (methodDescriptor.charAt(i)) {
1084            case VMDescriptor.C_ENDMETHOD:
1085                return wordCount;
1086            case VMDescriptor.C_DOUBLE:
1087            case VMDescriptor.C_LONG:
1088                wordCount += 2;
1089                break;
1090            case VMDescriptor.C_ARRAY:
1091                // skip while there are array symbols.
1092                do {
1093                    i++;
1094                } while (methodDescriptor.charAt(i) == VMDescriptor.C_ARRAY);
1095                if (methodDescriptor.charAt(i) != VMDescriptor.C_CLASS) {
1096                    // an array is a reference, even an array of doubles.
1097                    wordCount += 1;
1098                    break;
1099                }
1100 
1101            // fall through to skip the Lclassname; after the array.
1102 
1103            case VMDescriptor.C_CLASS:
1104                // skip until ;
1105                do {
1106                    i++;
1107                } while (methodDescriptor.charAt(i) != VMDescriptor.C_ENDCLASS);
1108                wordCount += 1;
1109                break;
1110            default:
1111                wordCount += 1;
1112                break;
1113            }
1114        }
1115    }
1116 
1117    /**
1118     * Find the limits of a conditional block starting at the instruction with
1119     * the given opcode at the program counter pc.
1120     * <P>
1121     * Returns a six element integer array of program counters and lengths.
1122     * <code. [0] - program counter of the IF opcode (passed in as pc) [1] -
1123     * program counter of the start of the then block [2] - length of the then
1124     * block [3] - program counter of the else block, -1 if no else block
1125     * exists. [4] - length of of the else block, -1 if no else block exists.
1126     * [5] - program counter of the common end point. </code>
1127     * 
1128     * Looks for and handles conditionals that are written by the Conditional
1129     * class.
1130     * 
1131     * @return Null if the opcode is not the start of a conditional otherwise
1132     *         the array of values.
1133     */
1134    private int[] findConditionalPCs(int pc, short opcode) {
1135        switch (opcode) {
1136        default:
1137            return null;
1138        case VMOpcode.IFNONNULL:
1139        case VMOpcode.IFNULL:
1140        case VMOpcode.IFEQ:
1141        case VMOpcode.IFNE:
1142            break;
1143        }
1144 
1145        int then_pc;
1146        int else_pc;
1147        int if_off = getU2(pc);
1148 
1149        if ((if_off == 8)
1150                && (getOpcode(pc + VMOpcode.IF_INS_LENGTH) == VMOpcode.GOTO_W)) {
1151            // 32 bit branch
1152            then_pc = pc + VMOpcode.IF_INS_LENGTH + VMOpcode.GOTO_W_INS_LENGTH;
1153 
1154            // Get else PC from the 32 bit offset within the GOTO_W
1155            // instruction remembering to add it to the pc of that
1156            // instruction, not the original IF.
1157            else_pc = pc + VMOpcode.IF_INS_LENGTH
1158                    + getU4(pc + VMOpcode.IF_INS_LENGTH);
1159 
1160        } else {
1161            then_pc = pc + VMOpcode.IF_INS_LENGTH;
1162            else_pc = pc + if_off;
1163        }
1164 
1165        // Need to look for the goto or goto_w at the
1166        // end of the then block. There might not be
1167        // one for the case when there is no else block.
1168        // In that case the then block will just run into
1169        // what we currently think the else pc.
1170 
1171        int end_pc = -1;
1172        for (int tpc = then_pc; tpc < else_pc;) {
1173            short opc = getOpcode(tpc);
1174 
1175            // need to handle conditionals
1176            int[] innerCond = findConditionalPCs(tpc, opc);
1177            if (innerCond != null) {
1178                // skip to the end of this conditional
1179                tpc = innerCond[5]; // end_pc
1180                continue;
1181            }
1182 
1183            if (opc == VMOpcode.GOTO) {
1184                // not at the end of the then block
1185                // so not our goto. Shouldn't see this
1186                // with the current code due to the
1187                // skipping of the conditional above.
1188                // But safe defensive programming.
1189                if (tpc != (else_pc - VMOpcode.GOTO_INS_LENGTH))
1190                    continue;
1191 
1192                end_pc = tpc + getU2(tpc);
1193                break;
1194            } else if (opc == VMOpcode.GOTO_W) {
1195                // not at the end of the then block
1196                // so not our goto. SHouldn't see this
1197                // with the current code due to the
1198                // skipping of the conditional above.
1199                // But safe defensive programming.
1200                if (tpc != (else_pc - VMOpcode.GOTO_W_INS_LENGTH))
1201                    continue;
1202 
1203                end_pc = tpc + getU4(tpc);
1204                break;
1205 
1206            }
1207            tpc += instructionLength(opc);
1208        }
1209 
1210        int else_len;
1211        int then_len;
1212        if (end_pc == -1) {
1213            // no else block;
1214            end_pc = else_pc;
1215            else_pc = -1;
1216 
1217            then_len = end_pc - then_pc;
1218            else_len = -1;
1219        } else {
1220            then_len = else_pc - then_pc;
1221            else_len = end_pc - else_pc;
1222        }
1223 
1224        int[] ret = new int[6];
1225 
1226        ret[0] = pc;
1227        ret[1] = then_pc;
1228        ret[2] = then_len;
1229        ret[3] = else_pc;
1230        ret[4] = else_len;
1231        ret[5] = end_pc;
1232 
1233        return ret;
1234    }
1235    
1236    /**
1237     * Attempt to split the current method by pushing a chunk of
1238     * its code into a sub-method. The starting point of the split
1239     * (split_pc) must correspond to a stack depth of zero. It is the
1240     * reponsibility of the caller to ensure this.
1241     * Split is only made if there exists a chunk of code starting at
1242     * pc=split_pc, whose stack depth upon termination is zero.
1243     * The method will try to split a code section greater than
1244     * optimalMinLength but may split earlier if no such block exists.
1245     * <P>
1246     * The method is aimed at splitting methods that contain
1247     * many independent statements.
1248     * <P>
1249     * If a split is possible this method will perform the split and
1250     * create a void sub method, and move the code into the sub-method
1251     * and setup this method to call the sub-method before continuing.
1252     * This method's max stack and current pc will be correctly set
1253     * as though the method had just been created.
1254     * 
1255     * @param mb Method for this chunk.
1256     * @param ch Class definition
1257     * @param codeLength codeLength to check
1258     * @param optimalMinLength minimum length required for split
1259     */
1260    final int splitZeroStack(BCMethod mb, ClassHolder ch, final int split_pc,
1261            final int codeLength, final int optimalMinLength) {
1262        int stack = 0;
1263 
1264        // maximum possible split seen that is less than
1265        // the minimum.
1266        int possibleSplitLength = -1;
1267 
1268        // do not split until at least this point (inclusive)
1269        // used to ensure no split occurs in the middle of
1270        // a conditional.
1271        int outerConditionalEnd_pc = -1;
1272 
1273        int end_pc = split_pc + codeLength;
1274        for (int pc = split_pc; pc < end_pc;) {
1275 
1276            short opcode = getOpcode(pc);
1277 
1278            int stackDelta = stackWordDelta(ch, pc, opcode);
1279 
1280            stack += stackDelta;
1281 
1282            // Cannot split a conditional but need to calculate
1283            // the stack depth at the end of the conditional.
1284            // Each path through the conditional will have the
1285            // same stack depth.
1286            int[] cond_pcs = findConditionalPCs(pc, opcode);
1287            if (cond_pcs != null) {
1288                // an else block exists, skip the then block.
1289                if (cond_pcs[3] != -1) {
1290                    pc = cond_pcs[3];
1291                    continue;
1292                }
1293 
1294                if (SanityManager.DEBUG) {
1295                    if (outerConditionalEnd_pc != -1) {
1296                        if (cond_pcs[5] >= outerConditionalEnd_pc)
1297                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");
1298                    }
1299                }
1300 
1301                if (outerConditionalEnd_pc == -1) {
1302                    outerConditionalEnd_pc = cond_pcs[5];
1303                }
1304            }
1305 
1306            pc += instructionLength(opcode);
1307 
1308            // Don't split in the middle of a conditional
1309            if (outerConditionalEnd_pc != -1) {
1310                if (pc > outerConditionalEnd_pc) {
1311                    // passed the outermost conditional
1312                    outerConditionalEnd_pc = -1;
1313                }
1314                continue;
1315            }
1316 
1317            if (stack != 0)
1318                continue;
1319 
1320            int splitLength = pc - split_pc;
1321 
1322            if (splitLength < optimalMinLength) {
1323                // record we do have a possible split.
1324                possibleSplitLength = splitLength;
1325                continue;
1326            }
1327 
1328            // no point splitting to a method bigger
1329            // than the VM can handle. Save one for
1330            // return instruction.
1331            if (splitLength > BCMethod.CODE_SPLIT_LENGTH - 1) {
1332                if (possibleSplitLength == -1)
1333                    return -1;
1334 
1335                // Decide if the earlier possible split is
1336                // worth it. 100 is an arbitary number,
1337                // a real low limit would be the number of
1338                // bytes of instructions required to call
1339                // the sub-method, four I think.
1340                if (possibleSplitLength < 100)
1341                    return -1;
1342 
1343                // OK go with the earlier split
1344                splitLength = possibleSplitLength;
1345 
1346            }
1347 
1348            // Yes, we can split this big method into a smaller method!!
1349 
1350            BCMethod subMethod = startSubMethod(mb, "void", split_pc,
1351                    splitLength);
1352 
1353            CodeChunk subChunk = subMethod.myCode;
1354 
1355            byte[] codeBytes = cout.getData();
1356 
1357            // the code to be moved into the sub method
1358            // as a block. This will correctly increase the
1359            // program counter.
1360            try {
1361                subChunk.cout.write(codeBytes, CODE_OFFSET + split_pc,
1362                        splitLength);
1363            } catch (IOException ioe) {
1364                // writing to a byte array
1365            }
1366 
1367            // Just cause the sub-method to return,
1368            // fix up its maxStack and then complete it.
1369            subChunk.addInstr(VMOpcode.RETURN);
1370            subMethod.maxStack = subChunk.findMaxStack(ch, 0, subChunk.getPC());
1371            subMethod.complete();
1372 
1373            return removePushedCode(mb, ch, subMethod, split_pc, splitLength,
1374                    codeLength);
1375        }
1376        return -1;
1377    }
1378 
1379    /**
1380     * Start a sub method that we will split the portion of our current code to,
1381     * starting from start_pc and including codeLength bytes of code.
1382     * 
1383     * Return a BCMethod obtained from BCMethod.getNewSubMethod with the passed
1384     * in return type and same parameters as mb if the code block to be moved
1385     * uses parameters.
1386     */
1387    private BCMethod startSubMethod(BCMethod mb, String returnType,
1388            int split_pc, int codeLength) {
1389 
1390        boolean needParameters = usesParameters(mb, split_pc, codeLength);
1391 
1392        return mb.getNewSubMethod(returnType, needParameters);
1393    }
1394 
1395    /**
1396     * Does a section of code use parameters.
1397     * Any load, exception ALOAD_0 in an instance method, is
1398     * seen as using parameters, as this complete byte code
1399     * implementation does not use local variables.
1400     * 
1401     */
1402    private boolean usesParameters(BCMethod mb, int pc, int codeLength) {
1403 
1404        // does the method even have parameters?
1405        if (mb.parameters == null)
1406            return false;
1407 
1408        boolean isStatic = (mb.myEntry.getModifier() & Modifier.STATIC) != 0;
1409 
1410        int endPc = pc + codeLength;
1411 
1412        for (; pc < endPc;) {
1413            short opcode = getOpcode(pc);
1414            switch (opcode) {
1415            case VMOpcode.ILOAD_0:
1416            case VMOpcode.LLOAD_0:
1417            case VMOpcode.FLOAD_0:
1418            case VMOpcode.DLOAD_0:
1419                return true;
1420 
1421            case VMOpcode.ALOAD_0:
1422                if (isStatic)
1423                    return true;
1424                break;
1425 
1426            case VMOpcode.ILOAD_1:
1427            case VMOpcode.LLOAD_1:
1428            case VMOpcode.FLOAD_1:
1429            case VMOpcode.DLOAD_1:
1430            case VMOpcode.ALOAD_1:
1431                return true;
1432 
1433            case VMOpcode.ILOAD_2:
1434            case VMOpcode.LLOAD_2:
1435            case VMOpcode.FLOAD_2:
1436            case VMOpcode.DLOAD_2:
1437            case VMOpcode.ALOAD_2:
1438                return true;
1439 
1440            case VMOpcode.ILOAD_3:
1441            case VMOpcode.LLOAD_3:
1442            case VMOpcode.FLOAD_3:
1443            case VMOpcode.DLOAD_3:
1444            case VMOpcode.ALOAD_3:
1445                return true;
1446 
1447            case VMOpcode.ILOAD:
1448            case VMOpcode.LLOAD:
1449            case VMOpcode.FLOAD:
1450            case VMOpcode.DLOAD:
1451            case VMOpcode.ALOAD:
1452                return true;
1453            default:
1454                break;
1455 
1456            }
1457            pc += instructionLength(opcode);
1458        }
1459        return false;
1460    }
1461 
1462    /**
1463     * Remove a block of code from this method that was
1464     * pushed into a sub-method and call the sub-method.
1465     * 
1466     * Returns the pc of this method just after the call
1467     * to the sub-method.
1468     
1469     * @param mb My method
1470     * @param ch My class
1471     * @param subMethod Sub-method code was pushed into
1472     * @param split_pc Program counter the split started at
1473     * @param splitLength Length of code split
1474     * @param codeLength Length of code before split
1475     */
1476    private int removePushedCode(BCMethod mb, ClassHolder ch,
1477            BCMethod subMethod, int split_pc, int splitLength, int codeLength) {
1478        // now need to fix up this method, create
1479        // a new CodeChunk just to be clearer than
1480        // trying to modify this chunk directly.
1481        CodeChunk replaceChunk = new CodeChunk();
1482        mb.myCode = replaceChunk;
1483        mb.maxStack = 0;
1484 
1485        byte[] codeBytes = cout.getData();
1486 
1487        // write any existing code before the split point
1488        // into the replacement chunk.
1489        if (split_pc != 0) {
1490            try {
1491                replaceChunk.cout.write(codeBytes, CODE_OFFSET, split_pc);
1492            } catch (IOException ioe) {
1493                // writing to a byte array
1494            }
1495        }
1496 
1497        // Call the sub method, will write into replaceChunk.
1498        mb.callSubMethod(subMethod);
1499 
1500        int postSplit_pc = replaceChunk.getPC();
1501 
1502        // Write the code remaining in this method into the replacement chunk
1503 
1504        int remainingCodeLength = codeLength - splitLength;
1505        try {
1506            replaceChunk.cout.write(codeBytes, CODE_OFFSET + split_pc
1507                    + splitLength, remainingCodeLength);
1508        } catch (IOException ioe) {
1509            // writing to a byte array
1510        }
1511 
1512        mb.maxStack = replaceChunk.findMaxStack(ch, 0, replaceChunk.getPC());
1513 
1514        return postSplit_pc;
1515    }
1516}

[all classes][org.apache.derby.impl.services.bytecode]
EMMA 2.0.5312 (C) Vladimir Roubtsov