KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > services > bytecode > CodeChunk


1 /*
2
3    Derby - Class org.apache.derby.impl.services.bytecode.CodeChunk
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.services.bytecode;
23
24 import org.apache.derby.iapi.services.classfile.CONSTANT_Index_info;
25 import org.apache.derby.iapi.services.classfile.CONSTANT_Utf8_info;
26 import org.apache.derby.iapi.services.classfile.ClassFormatOutput;
27 import org.apache.derby.iapi.services.classfile.ClassHolder;
28 import org.apache.derby.iapi.services.classfile.ClassMember;
29 import org.apache.derby.iapi.services.classfile.VMDescriptor;
30
31 import org.apache.derby.iapi.services.sanity.SanityManager;
32 import org.apache.derby.iapi.services.classfile.VMOpcode;
33 import org.apache.derby.iapi.services.io.ArrayOutputStream;
34
35 import java.io.IOException JavaDoc;
36 import java.lang.reflect.Modifier JavaDoc;
37 import java.util.Arrays JavaDoc;
38
39 /**
40  * This class represents a chunk of code in a CodeAttribute.
41  * Typically, a CodeAttribute represents the code in a method.
42  * If there is a try/catch block, each catch block will get its
43  * own code chunk. This allows the catch blocks to all be put at
44  * the end of the generated code for a method, which eliminates
45  * the need to generate a jump around each catch block, which
46  * would be a forward reference.
47  */

48 final class CodeChunk {
49     
50     /**
51      * Starting point of the byte code stream in the underlying stream/array.
52      */

53     private static final int CODE_OFFSET = 8;
54         
55     // The use of ILOAD for the non-integer types is correct.
56
// We have to assume that the appropriate checks/conversions
57
// are defined on math operation results to ensure that
58
// the type is preserved when/as needed.
59
static final short[] LOAD_VARIABLE = {
60         VMOpcode.ILOAD, /* vm_byte */
61         VMOpcode.ILOAD, /* vm_short */
62         VMOpcode.ILOAD, /* vm_int */
63         VMOpcode.LLOAD, /* vm_long */
64         VMOpcode.FLOAD, /* vm_float */
65         VMOpcode.DLOAD, /* vm_double */
66         VMOpcode.ILOAD, /* vm_char */
67         VMOpcode.ALOAD /* vm_reference */
68     };
69
70     static final short[] LOAD_VARIABLE_FAST = {
71         VMOpcode.ILOAD_0, /* vm_byte */
72         VMOpcode.ILOAD_0, /* vm_short */
73         VMOpcode.ILOAD_0, /* vm_int */
74         VMOpcode.LLOAD_0, /* vm_long */
75         VMOpcode.FLOAD_0, /* vm_float */
76         VMOpcode.DLOAD_0, /* vm_double */
77         VMOpcode.ILOAD_0, /* vm_char */
78         VMOpcode.ALOAD_0 /* vm_reference */
79     };
80
81     // The ISTOREs for non-int types are how things work.
82
// It assumes that the appropriate casts are done
83
// on operations on non-ints to ensure that the values
84
// remain in the valid ranges.
85
static final short[] STORE_VARIABLE = {
86         VMOpcode.ISTORE, /* vm_byte */
87         VMOpcode.ISTORE, /* vm_short */
88         VMOpcode.ISTORE, /* vm_int */
89         VMOpcode.LSTORE, /* vm_long */
90         VMOpcode.FSTORE, /* vm_float */
91         VMOpcode.DSTORE, /* vm_double */
92         VMOpcode.ISTORE, /* vm_char */
93         VMOpcode.ASTORE /* vm_reference */
94     };
95
96     static final short[] STORE_VARIABLE_FAST = {
97         VMOpcode.ISTORE_0, /* vm_byte */
98         VMOpcode.ISTORE_0, /* vm_short */
99         VMOpcode.ISTORE_0, /* vm_int */
100         VMOpcode.LSTORE_0, /* vm_long */
101         VMOpcode.FSTORE_0, /* vm_float */
102         VMOpcode.DSTORE_0, /* vm_double */
103         VMOpcode.ISTORE_0, /* vm_char */
104         VMOpcode.ASTORE_0 /* vm_reference */
105     };
106
107     static final short ARRAY_ACCESS[] = {
108         VMOpcode.BALOAD, /* vm_byte */
109         VMOpcode.SALOAD, /* vm_short */
110         VMOpcode.IALOAD, /* vm_int */
111         VMOpcode.LALOAD, /* vm_long */
112         VMOpcode.FALOAD, /* vm_float */
113         VMOpcode.DALOAD, /* vm_double */
114         VMOpcode.CALOAD, /* vm_char */
115         VMOpcode.AALOAD /* vm_reference */
116     };
117     static final short ARRAY_STORE[] = {
118         VMOpcode.BASTORE, /* vm_byte */
119         VMOpcode.SASTORE, /* vm_short */
120         VMOpcode.IASTORE, /* vm_int */
121         VMOpcode.LASTORE, /* vm_long */
122         VMOpcode.FASTORE, /* vm_float */
123         VMOpcode.DASTORE, /* vm_double */
124         VMOpcode.CASTORE, /* vm_char */
125         VMOpcode.AASTORE /* vm_reference */
126     };
127     static final short[] RETURN_OPCODE = {
128         VMOpcode.IRETURN, /* 0 = byte */
129         VMOpcode.IRETURN, /* 1 = short */
130         VMOpcode.IRETURN, /* 2 = int */
131         VMOpcode.LRETURN, /* 3 = long */
132         VMOpcode.FRETURN, /* 4 = float */
133         VMOpcode.DRETURN, /* 5 = double */
134         VMOpcode.IRETURN, /* 6 = char */
135         VMOpcode.ARETURN /* 7 = reference */
136         };
137
138     // the first dimension is the current vmTypeId
139
// the second dimension is the target vmTypeId
140
//
141
// the cells of the entry at [current,target] are:
142
// 0: operation
143
// 1: result type of operation
144
// if entry[1] = target, we are done. otherwise,
145
// you have to continue with entry[1] as the new current
146
// after generating the opcode listed (don't generate if it is NOP).
147
// if entry[0] = BAD, we can
148

149     static final short CAST_CONVERSION_INFO[][][] = {
150         /* current = vm_byte */
151         {
152         /* target = vm_byte */ { VMOpcode.NOP, BCExpr.vm_byte },
153         /* target = vm_short */ { VMOpcode.NOP, BCExpr.vm_short },
154         /* target = vm_int */ { VMOpcode.NOP, BCExpr.vm_int },
155         /* target = vm_long */ { VMOpcode.NOP, BCExpr.vm_int },
156         /* target = vm_float */ { VMOpcode.NOP, BCExpr.vm_int },
157         /* target = vm_double */ { VMOpcode.NOP, BCExpr.vm_int },
158         /* target = vm_char */ { VMOpcode.NOP, BCExpr.vm_char },
159         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
160         },
161         /* current = vm_short */
162         {
163         /* target = vm_byte */ { VMOpcode.NOP, BCExpr.vm_byte },
164         /* target = vm_short */ { VMOpcode.NOP, BCExpr.vm_short },
165         /* target = vm_int */ { VMOpcode.NOP, BCExpr.vm_int },
166         /* target = vm_long */ { VMOpcode.NOP, BCExpr.vm_int },
167         /* target = vm_float */ { VMOpcode.NOP, BCExpr.vm_int },
168         /* target = vm_double */ { VMOpcode.NOP, BCExpr.vm_int },
169         /* target = vm_char */ { VMOpcode.NOP, BCExpr.vm_char },
170         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
171         },
172         /* current = vm_int */
173         {
174         /* target = vm_byte */ { VMOpcode.I2B, BCExpr.vm_byte },
175         /* target = vm_short */ { VMOpcode.I2S, BCExpr.vm_short },
176         /* target = vm_int */ { VMOpcode.NOP, BCExpr.vm_int },
177         /* target = vm_long */ { VMOpcode.I2L, BCExpr.vm_long },
178         /* target = vm_float */ { VMOpcode.I2F, BCExpr.vm_float },
179         /* target = vm_double */ { VMOpcode.I2D, BCExpr.vm_double },
180         /* target = vm_char */ { VMOpcode.I2B, BCExpr.vm_char },
181         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
182         },
183         /* current = vm_long */
184         {
185         /* target = vm_byte */ { VMOpcode.L2I, BCExpr.vm_int },
186         /* target = vm_short */ { VMOpcode.L2I, BCExpr.vm_int },
187         /* target = vm_int */ { VMOpcode.L2I, BCExpr.vm_int },
188         /* target = vm_long */ { VMOpcode.NOP, BCExpr.vm_long },
189         /* target = vm_float */ { VMOpcode.L2F, BCExpr.vm_float },
190         /* target = vm_double */ { VMOpcode.L2D, BCExpr.vm_double },
191         /* target = vm_char */ { VMOpcode.L2I, BCExpr.vm_int },
192         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
193         },
194         /* current = vm_float */
195         {
196         /* target = vm_byte */ { VMOpcode.F2I, BCExpr.vm_int },
197         /* target = vm_short */ { VMOpcode.F2I, BCExpr.vm_int },
198         /* target = vm_int */ { VMOpcode.F2I, BCExpr.vm_int },
199         /* target = vm_long */ { VMOpcode.F2L, BCExpr.vm_long },
200         /* target = vm_float */ { VMOpcode.NOP, BCExpr.vm_float },
201         /* target = vm_double */ { VMOpcode.F2D, BCExpr.vm_double },
202         /* target = vm_char */ { VMOpcode.F2I, BCExpr.vm_int },
203         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
204         },
205         /* current = vm_double */
206         {
207         /* target = vm_byte */ { VMOpcode.D2I, BCExpr.vm_int },
208         /* target = vm_short */ { VMOpcode.D2I, BCExpr.vm_int },
209         /* target = vm_int */ { VMOpcode.D2I, BCExpr.vm_int },
210         /* target = vm_long */ { VMOpcode.D2L, BCExpr.vm_long },
211         /* target = vm_float */ { VMOpcode.D2F, BCExpr.vm_float },
212         /* target = vm_double */ { VMOpcode.NOP, BCExpr.vm_double },
213         /* target = vm_char */ { VMOpcode.D2I, BCExpr.vm_int },
214         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
215         },
216         /* current = vm_char */
217         {
218         /* target = vm_byte */ { VMOpcode.NOP, BCExpr.vm_byte },
219         /* target = vm_short */ { VMOpcode.NOP, BCExpr.vm_short },
220         /* target = vm_int */ { VMOpcode.NOP, BCExpr.vm_int },
221         /* target = vm_long */ { VMOpcode.NOP, BCExpr.vm_int },
222         /* target = vm_float */ { VMOpcode.NOP, BCExpr.vm_int },
223         /* target = vm_double */ { VMOpcode.NOP, BCExpr.vm_int },
224         /* target = vm_char */ { VMOpcode.NOP, BCExpr.vm_char },
225         /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }
226         },
227         /* current = vm_reference */
228         {
229         /* target = vm_byte */ { VMOpcode.BAD, BCExpr.vm_byte },
230         /* target = vm_short */ { VMOpcode.BAD, BCExpr.vm_short },
231         /* target = vm_int */ { VMOpcode.BAD, BCExpr.vm_int },
232         /* target = vm_long */ { VMOpcode.BAD, BCExpr.vm_long },
233         /* target = vm_float */ { VMOpcode.BAD, BCExpr.vm_float },
234         /* target = vm_double */ { VMOpcode.BAD, BCExpr.vm_double },
235         /* target = vm_char */ { VMOpcode.BAD, BCExpr.vm_char },
236         /* target = vm_reference */ { VMOpcode.NOP, BCExpr.vm_reference }
237         }
238     };
239     
240     /**
241      * Constant used by OPCODE_ACTION to represent the
242      * common action of push one word, 1 byte
243      * for the instruction.
244      */

245     private static final byte[] push1_1i = {1, 1};
246
247     /**
248      * Constant used by OPCODE_ACTION to represent the
249      * common action of push two words, 1 byte
250      * for the instruction.
251      */

252     private static final byte[] push2_1i = {2, 1};
253     /**
254      * Constant used by OPCODE_ACTION to the opcode is
255      * not yet supported.
256      */

257     private static final byte[] NS = {0, -1};
258     
259     
260     /**
261      * Value for OPCODE_ACTION[opcode][0] to represent
262      * the number of words popped or pushed in variable.
263      */

264     private static final byte VARIABLE_STACK = -128;
265     
266     /**
267      * Array that provides two pieces of information about
268      * each VM opcode. Each opcode has a two byte array.
269      * <P>
270      * The first element in the array [0] is the number of
271      * stack words (double/long count as two) pushed by the opcode.
272      * Will be negative if the opcode pops values.
273      *
274      * <P>
275      * The second element in the array [1] is the number of bytes
276      * in the instruction stream that this opcode's instruction
277      * takes up, including the opocode.
278      */

279     private static final byte[][] OPCODE_ACTION =
280     {
281     
282     /* NOP 0 */ { 0, 1 },
283     
284     /* ACONST_NULL 1 */ push1_1i,
285     /* ICONST_M1 2 */ push1_1i,
286     /* ICONST_0 3 */ push1_1i,
287     /* ICONST_1 4 */ push1_1i,
288     /* ICONST_2 5 */ push1_1i,
289     /* ICONST_3 6 */ push1_1i,
290     /* ICONST_4 7 */ push1_1i,
291     /* ICONST_5 8 */ push1_1i,
292     /* LCONST_0 9 */ push2_1i,
293     /* LCONST_1 10 */ push2_1i,
294     /* FCONST_0 11 */ push1_1i,
295     /* FCONST_1 12 */ push1_1i,
296     /* FCONST_2 13 */ push1_1i,
297     /* DCONST_0 14 */ push2_1i,
298     /* DCONST_1 15 */ push2_1i,
299     
300     /* BIPUSH 16 */ {1, 2},
301     /* SIPUSH 17 */ {1, 3},
302     /* LDC 18 */ {1, 2},
303     /* LDC_W 19 */ {1, 3},
304     /* LDC2_W 20 */ {2, 3},
305     
306     /* ILOAD 21 */ { 1, 2 },
307     /* LLOAD 22 */ { 2, 2 },
308     /* FLOAD 23 */ { 1, 2 },
309     /* DLOAD 24 */ { 2, 2 },
310     /* ALOAD 25 */ { 1, 2 },
311     /* ILOAD_0 26 */ push1_1i,
312     /* ILOAD_1 27 */ push1_1i,
313     /* ILOAD_2 28 */ push1_1i,
314     /* ILOAD_3 29 */ push1_1i,
315     /* LLOAD_0 30 */ push2_1i,
316     /* LLOAD_1 31 */ push2_1i,
317     /* LLOAD_2 32 */ push2_1i,
318     /* LLOAD_3 33 */ push2_1i,
319     /* FLOAD_0 34 */ push1_1i,
320     /* FLOAD_1 35 */ push1_1i,
321     /* FLOAD_2 36 */ push1_1i,
322     /* FLOAD_3 37 */ push1_1i,
323     /* DLOAD_0 38 */ push2_1i,
324     /* DLOAD_1 39 */ push2_1i,
325     /* DLOAD_2 40 */ push2_1i,
326     /* DLOAD_3 41 */ push2_1i,
327     /* ALOAD_0 42 */ push1_1i,
328     /* ALOAD_1 43 */ push1_1i,
329     /* ALOAD_2 44 */ push1_1i,
330     /* ALOAD_3 45 */ push1_1i,
331     /* IALOAD 46 */ { -1, 1 },
332     /* LALOAD 47 */ { 0, 1 },
333     /* FALOAD 48 */ { -1, 1 },
334     /* DALOAD 49 */ { 0, 1 },
335     /* AALOAD 50 */ { -1, 1 },
336     /* BALOAD 51 */ { -1, 1 },
337     /* CALOAD 52 */ { -1, 1 },
338     
339     /* SALOAD 53 */ { -1, 1 },
340     /* ISTORE 54 */ { -1, 2 },
341     /* LSTORE 55 */ { -2, 2 },
342     /* FSTORE 56 */ { -1, 2 },
343     /* DSTORE 57 */ { -2, 2 },
344     /* ASTORE 58 */ { -1, 2 },
345     /* ISTORE_0 59 */ { -1, 1 },
346     /* ISTORE_1 60 */ { -1, 1 },
347     /* ISTORE_2 61 */ { -1, 1 },
348     /* ISTORE_3 62 */ { -1, 1 },
349     /* LSTORE_0 63 */ { -2, 1 },
350     /* LSTORE_1 64 */ { -2, 1 },
351     /* LSTORE_2 65 */ { -2, 1 },
352     /* LSTORE_3 66 */ { -2, 1 },
353     /* FSTORE_0 67 */ { -1, 1 },
354     /* FSTORE_1 68 */ { -1, 1 },
355     /* FSTORE_2 69 */ { -1, 1 },
356     /* FSTORE_3 70 */ { -1, 1 },
357     /* DSTORE_0 71 */ { -2, 1 },
358     /* DSTORE_1 72 */ { -2, 1 },
359     /* DSTORE_2 73 */ { -2, 1 },
360     /* DSTORE_3 74 */ { -2, 1 },
361     /* ASTORE_0 75 */ { -1, 1 },
362     /* ASTORE_1 76 */ { -1, 1 },
363     /* ASTORE_2 77 */ { -1, 1 },
364     /* ASTORE_3 78 */ { -1, 1 },
365     /* IASTORE 79 */ { -3, 1 },
366     /* LASTORE 80 */ { -4, 1 },
367     /* FASTORE 81 */ { -3, 1 },
368     /* DASTORE 82 */ { -4, 1 },
369     /* AASTORE 83 */ { -3, 1 },
370     /* BASTORE 84 */ { -3, 1 },
371     /* CASTORE 85 */ { -3, 1 },
372     /* SASTORE 86 */ { -3, 1 },
373     
374     /* POP 87 */ { -1, 1 },
375     /* POP2 88 */ { -2, 1 },
376     /* DUP 89 */ push1_1i,
377     /* DUP_X1 90 */ push1_1i,
378     /* DUP_X2 91 */ push1_1i,
379     /* DUP2 92 */ push2_1i,
380     /* DUP2_X1 93 */ push2_1i,
381     /* DUP2_X2 94 */ push2_1i,
382     /* SWAP 95 */ { 0, 1 },
383     
384     /* IADD 96 */ NS,
385     /* LADD 97 */ NS,
386     /* FADD 98 */ { -1, 1 },
387     /* DADD 99 */ { -2, 1 },
388     /* ISUB 100 */ NS,
389     /* LSUB 101 */ NS,
390     /* FSUB 102 */ { -1, 1 },
391     /* DSUB 103 */ { -2, 1 },
392     /* IMUL 104 */ NS,
393     /* LMUL 105 */ NS,
394     /* FMUL 106 */ { -1, 1 },
395     /* DMUL 107 */ { -2, 1 },
396     /* IDIV 108 */ NS,
397     /* LDIV 109 */ NS,
398     /* FDIV 110 */ { -1, 1 },
399     /* DDIV 111 */ { -2, 1 },
400     /* IREM 112 */ { -1, 1 },
401     /* LREM 113 */ { -2, 1 },
402     /* FREM 114 */ { -1, 1 },
403     /* DREM 115 */ { -2, 1 },
404     /* INEG 116 */ { 0, 1 },
405     /* LNEG 117 */ { 0, 1 },
406     /* FNEG 118 */ { 0, 1 },
407     /* DNEG 119 */ { 0, 1 },
408     /* ISHL 120 */ { -1, 1 },
409     /* LSHL 121 */ NS,
410     /* ISHR 122 */ NS,
411     /* LSHR 123 */ NS,
412     /* IUSHR 124 */ NS,
413     /* LUSHR 125 */ NS,
414     
415     /* IAND 126 */ { -1, 1 },
416     /* LAND 127 */ NS,
417     /* IOR 128 */ { -1, 1 },
418     /* LOR 129 */ NS,
419     /* IXOR 130 */ NS,
420     /* LXOR 131 */ NS,
421     /* IINC 132 */ NS,
422     
423     /* I2L 133 */ push1_1i,
424     /* I2F 134 */ { 0, 1 },
425     /* I2D 135 */ push1_1i,
426     /* L2I 136 */ { -1, 1 },
427     /* L2F 137 */ { -1, 1 },
428     /* L2D 138 */ { 0, 1 },
429     /* F2I 139 */ { 0, 1 },
430     /* F2L 140 */ push2_1i,
431     /* F2D 141 */ push1_1i,
432     /* D2I 142 */ { -1, 1 },
433     /* D2L 143 */ { 0, 1 },
434     /* D2F 144 */ { -1, 1 },
435     /* I2B 145 */ { 0, 1 },
436     /* I2C 146 */ { 0, 1 },
437     /* I2S 147 */ { 0, 1 },
438     
439     /* LCMP 148 */ NS,
440     /* FCMPL 149 */ { -1, 1 },
441     /* FCMPG 150 */ { -1, 1 },
442     /* DCMPL 151 */ { -3, 1 },
443     /* DCMPG 152 */ { -3, 1 },
444     /* IFEQ 153 */ { -1, VMOpcode.IF_INS_LENGTH },
445     /* IFNE 154 */ { -1, VMOpcode.IF_INS_LENGTH },
446     /* IFLT 155 */ { -1, VMOpcode.IF_INS_LENGTH },
447     /* IFGE 156 */ { -1, VMOpcode.IF_INS_LENGTH },
448     /* IFGT 157 */ { -1, VMOpcode.IF_INS_LENGTH },
449     /* IFLE 158 */ { -1, VMOpcode.IF_INS_LENGTH },
450     /* IF_ICMPEQ 159 */ NS,
451     /* IF_ICMPNE 160 */ NS,
452     /* IF_ICMPLT 161 */ NS,
453     /* IF_ICMPGE 162 */ NS,
454     /* IF_ICMPGT 163 */ NS,
455     /* IF_ICMPLE 164 */ NS,
456     /* IF_ACMPEQ 165 */ NS,
457     /* IF_ACMPNE 166 */ NS,
458     /* GOTO 167 */ { 0, VMOpcode.GOTO_INS_LENGTH },
459     /* JSR 168 */ NS,
460     /* RET 169 */ NS,
461     /* TABLESWITCH 170 */ NS,
462     /* LOOKUPSWITCH 171 */NS,
463     
464     /* IRETURN 172 */ { -1, 1 }, // strictly speaking all words on the stack are popped.
465
/* LRETURN 173 */ { -2, 1 }, // strictly speaking all words on the stack are popped.
466
/* FRETURN 174 */ { -1, 1 }, // strictly speaking all words on the stack are popped.
467
/* DRETURN 175 */ { -2, 1 }, // strictly speaking all words on the stack are popped.
468
/* ARETURN 176 */ { -1, 1 }, // strictly speaking all words on the stack are popped.
469
/* RETURN 177 */ { 0, 1 }, // strictly speaking all words on the stack are popped.
470

471     /* GETSTATIC 178 */ {VARIABLE_STACK, 3 },
472     /* PUTSTATIC 179 */ {VARIABLE_STACK, 3 },
473     /* GETFIELD 180 */ {VARIABLE_STACK, 3 },
474     /* PUTFIELD 181 */ {VARIABLE_STACK, 3 },
475     /* INVOKEVIRTUAL 182 */ {VARIABLE_STACK, 3 },
476     /* INVOKESPECIAL 183 */ {VARIABLE_STACK, 3 },
477     /* INVOKESTATIC 184 */ {VARIABLE_STACK, 3 },
478     /* INVOKEINTERFACE 185 */ {VARIABLE_STACK, 5 },
479     
480     /* XXXUNUSEDXXX 186 */ NS,
481
482     /* NEW 187 */ { 1, 3 },
483     /* NEWARRAY 188 */ { 0, 2 },
484     /* ANEWARRAY 189 */ { 0, 3 },
485     /* ARRAYLENGTH 190 */ { 0, 1 },
486     /* ATHROW 191 */ NS,
487     /* CHECKCAST 192 */ { 0, 3},
488     /* INSTANCEOF 193 */ { 0, 3 },
489     /* MONITORENTER 194 */ NS,
490     /* MONITOREXIT 195 */ NS,
491     /* WIDE 196 */ NS,
492     /* MULTIANEWARRAY 197 */ NS,
493     /* IFNULL 198 */ { -1, VMOpcode.IF_INS_LENGTH },
494     /* IFNONNULL 199 */ { -1, VMOpcode.IF_INS_LENGTH },
495     /* GOTO_W 200 */ {0, VMOpcode.GOTO_W_INS_LENGTH },
496     /* JSR_W 201 */ NS,
497     /* BREAKPOINT 202 */ NS,
498     
499     };
500     
501     /**
502      * Assume an IOException means some limit of the class file
503      * format was hit
504      *
505      */

506     private void limitHit(IOException JavaDoc ioe)
507     {
508         cb.addLimitExceeded(ioe.toString());
509     }
510     
511     
512     /**
513      * Add an instruction that has no operand.
514      * All opcodes are 1 byte large.
515      */

516     void addInstr(short opcode) {
517         try {
518         cout.putU1(opcode);
519         } catch (IOException JavaDoc ioe) {
520             limitHit(ioe);
521         }
522
523         if (SanityManager.DEBUG) {
524             if (OPCODE_ACTION[opcode][1] != 1)
525                 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
526                         " writing 1 byte - set as " + OPCODE_ACTION[opcode][1]);
527         }
528     }
529
530     /**
531      * Add an instruction that has a 16 bit operand.
532      */

533     void addInstrU2(short opcode, int operand) {
534         
535         try {
536         cout.putU1(opcode);
537         cout.putU2(operand);
538         } catch (IOException JavaDoc ioe) {
539             limitHit(ioe);
540         }
541
542         if (SanityManager.DEBUG) {
543             if (OPCODE_ACTION[opcode][1] != 3)
544                 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
545                         " writing 3 bytes - set as " + OPCODE_ACTION[opcode][1]);
546         }
547     }
548
549     /**
550      * Add an instruction that has a 32 bit operand.
551      */

552      void addInstrU4(short opcode, int operand) {
553         try {
554         cout.putU1(opcode);
555         cout.putU4(operand);
556         } catch (IOException JavaDoc ioe) {
557             limitHit(ioe);
558         }
559         if (SanityManager.DEBUG) {
560             if (OPCODE_ACTION[opcode][1] != 5)
561                 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
562                         " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]);
563         }
564     }
565
566      
567     /**
568      * Add an instruction that has an 8 bit operand.
569      */

570      void addInstrU1(short opcode, int operand) {
571         try {
572         cout.putU1(opcode);
573         cout.putU1(operand);
574         } catch (IOException JavaDoc ioe) {
575             limitHit(ioe);
576         }
577
578         // Only debug code from here.
579
if (SanityManager.DEBUG) {
580             
581             if (OPCODE_ACTION[opcode][1] != 2)
582                 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
583                         " writing 2 bytes - set as " + OPCODE_ACTION[opcode][1]);
584         
585         }
586     }
587
588     /**
589      * This takes an instruction that has a narrow
590      * and a wide form for CPE access, and
591      * generates accordingly the right one.
592      * We assume the narrow instruction is what
593      * we were given, and that the wide form is
594      * the next possible instruction.
595      */

596     void addInstrCPE(short opcode, int cpeNum) {
597         if (cpeNum < 256) {
598             addInstrU1(opcode, cpeNum);
599         }
600         else {
601             addInstrU2((short) (opcode+1), cpeNum);
602         }
603     }
604
605     /**
606      * This takes an instruction that can be wrapped in
607      * a wide for large variable #s and does so.
608      */

609     void addInstrWide(short opcode, int varNum) {
610         if (varNum < 256) {
611             addInstrU1(opcode, varNum);
612         }
613         else {
614             addInstr(VMOpcode.WIDE);
615             addInstrU2(opcode, varNum);
616         }
617     }
618
619     /**
620      * For adding an instruction with 3 operands, a U2 and two U1's.
621      * So far, this is used by VMOpcode.INVOKEINTERFACE.
622      */

623     void addInstrU2U1U1(short opcode, int operand1, short operand2,
624         short operand3) {
625         try {
626         cout.putU1(opcode);
627         cout.putU2(operand1);
628         cout.putU1(operand2);
629         cout.putU1(operand3);
630         } catch (IOException JavaDoc ioe) {
631             limitHit(ioe);
632         }
633         if (SanityManager.DEBUG) {
634             if (OPCODE_ACTION[opcode][1] != 5)
635                 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +
636                         " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]);
637         }
638     }
639
640     /** Get the current program counter */
641     int getPC() {
642         return cout.size() + pcDelta;
643     }
644     
645     /**
646      * Return the complete instruction length for the
647      * passed in opcode. This will include the space for
648      * the opcode and its operand.
649      */

650     private static int instructionLength(short opcode)
651     {
652         int instructionLength = OPCODE_ACTION[opcode][1];
653         
654         if (SanityManager.DEBUG)
655         {
656             if (instructionLength < 0)
657                 SanityManager.THROWASSERT("Opcode without instruction length " + opcode);
658         }
659         
660         return instructionLength;
661     }
662     
663     /**
664      * The delta between cout.size() and the pc.
665      * For an initial code chunk this is -8 (CODE_OFFSET)
666      * since 8 bytes are written.
667      * For a nested CodeChunk return by insertCodeSpace the delta
668      * corresponds to the original starting pc.
669      * @see #insertCodeSpace
670      */

671     private final int pcDelta;
672     
673     /**
674      * The class we are generating code for, used to indicate that
675      * some limit was hit during code generation.
676      */

677     final BCClass cb;
678
679     CodeChunk(BCClass cb) {
680         this.cb = cb;
681         cout = new ClassFormatOutput();
682         try {
683             cout.putU2(0); // max_stack, placeholder for now
684
cout.putU2(0); // max_locals, placeholder for now
685
cout.putU4(0); // code_length, placeholder 4 now
686
} catch (IOException JavaDoc ioe) {
687             limitHit(ioe);
688         }
689         pcDelta = - CodeChunk.CODE_OFFSET;
690     }
691     
692     /**
693      * Return a CodeChunk that has limited visibility into
694      * this CodeChunk. Used when a caller needs to insert instructions
695      * into an existing stream.
696      * @param pc
697      * @param byteCount
698      */

699     private CodeChunk(CodeChunk main, int pc, int byteCount)
700     {
701         this.cb = main.cb;
702         ArrayOutputStream aos =
703             new ArrayOutputStream(main.cout.getData());
704         
705         try {
706             aos.setPosition(CODE_OFFSET + pc);
707             aos.setLimit(byteCount);
708         } catch (IOException JavaDoc e) {
709             limitHit(e);
710         }
711         
712         cout = new ClassFormatOutput(aos);
713         pcDelta = pc;
714     }
715
716     private final ClassFormatOutput cout;
717
718     /**
719      * now that we have codeBytes, fix the lengths fields in it
720      * to reflect what was stored.
721      * Limits checked here are from these sections of the JVM spec.
722      * <UL>
723      * <LI> 4.7.3 The Code Attribute
724      * <LI> 4.10 Limitations of the Java Virtual Machine
725      * </UL>
726      */

727     private void fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength) {
728
729         byte[] codeBytes = cout.getData();
730
731         // max_stack is in bytes 0-1
732
if (mb != null && maxStack > 65535)
733             cb.addLimitExceeded(mb, "max_stack", 65535, maxStack);
734             
735         codeBytes[0] = (byte)(maxStack >> 8 );
736         codeBytes[1] = (byte)(maxStack );
737
738         // max_locals is in bytes 2-3
739
if (mb != null && maxLocals > 65535)
740             cb.addLimitExceeded(mb, "max_locals", 65535, maxLocals);
741         codeBytes[2] = (byte)(maxLocals >> 8 );
742         codeBytes[3] = (byte)(maxLocals );
743
744         // code_length is in bytes 4-7
745
if (mb != null && codeLength > VMOpcode.MAX_CODE_LENGTH)
746             cb.addLimitExceeded(mb, "code_length",
747                     VMOpcode.MAX_CODE_LENGTH, codeLength);
748         codeBytes[4] = (byte)(codeLength >> 24 );
749         codeBytes[5] = (byte)(codeLength >> 16 );
750         codeBytes[6] = (byte)(codeLength >> 8 );
751         codeBytes[7] = (byte)(codeLength );
752     }
753
754     /**
755      * wrap up the entry and stuff it in the class,
756      * now that it holds all of the instructions and
757      * the exception table.
758      */

759     void complete(BCMethod mb, ClassHolder ch,
760             ClassMember method, int maxStack, int maxLocals) {
761
762         int codeLength = getPC();
763
764         ClassFormatOutput out = cout;
765         
766         try {
767
768             out.putU2(0); // exception_table_length
769

770             if (SanityManager.DEBUG) {
771               if (SanityManager.DEBUG_ON("ClassLineNumbers")) {
772                 // Add a single attribute - LineNumberTable
773
// This add fake line numbers that are the pc offset in the method.
774
out.putU2(1); // attributes_count
775

776                 int cpiUTF = ch.addUtf8("LineNumberTable");
777
778                 out.putU2(cpiUTF);
779                 out.putU4((codeLength * 4) + 2);
780                 out.putU2(codeLength);
781                 for (int i = 0; i < codeLength; i++) {
782                     out.putU2(i);
783                     out.putU2(i);
784                 }
785               } else {
786                   out.putU2(0); // attributes_count
787
}
788
789             } else {
790                 out.putU2(0); // attributes_count
791
// attributes is empty, a 0-element array.
792
}
793         } catch (IOException JavaDoc ioe) {
794             limitHit(ioe);
795         }
796
797         fixLengths(mb, maxStack, maxLocals, codeLength);
798         method.addAttribute("Code", out);
799         
800         if (SanityManager.DEBUG)
801         {
802             // Only validate if the class file format is valid.
803
// Ok code length and guaranteed no errors building the class.
804
if ((codeLength <= VMOpcode.MAX_CODE_LENGTH)
805                 && (mb != null && mb.cb.limitMsg == null))
806             {
807                 // Validate the alternate way to calculate the
808
// max stack agrees with the dynamic as the code
809
// is built way.
810
int walkedMaxStack = findMaxStack(ch, 0, codeLength);
811                 if (walkedMaxStack != maxStack)
812                 {
813                     SanityManager.THROWASSERT("MAX STACK MISMATCH!! " +
814                             maxStack + " <> " + walkedMaxStack);
815                 }
816             }
817         }
818
819     }
820     /**
821      * Return the opcode at the given pc.
822      */

823     short getOpcode(int pc)
824     {
825         return (short) (cout.getData()[CODE_OFFSET + pc] & 0xff);
826     }
827     
828     /**
829      * Get the unsigned short value for the opcode at the program
830      * counter pc.
831      */

832     private int getU2(int pc)
833     {
834         byte[] codeBytes = cout.getData();
835         
836         int u2p = CODE_OFFSET + pc + 1;
837                 
838         return ((codeBytes[u2p] & 0xff) << 8) | (codeBytes[u2p+1] & 0xff);
839     }
840
841     /**
842      * Get the unsigned 32 bit value for the opcode at the program
843      * counter pc.
844      */

845     private int getU4(int pc)
846     {
847         byte[] codeBytes = cout.getData();
848         
849         int u4p = CODE_OFFSET + pc + 1;
850         
851         return (((codeBytes[u4p] & 0xff) << 24) |
852                 ((codeBytes[u4p+1] & 0xff) << 16) |
853                 ((codeBytes[u4p+2] & 0xff) << 8) |
854                 ((codeBytes[u4p+3] & 0xff)));
855     }
856     /**
857      * Insert room for byteCount bytes after the instruction at pc
858      * and prepare to replace the instruction at pc. The instruction
859      * at pc is not modified by this call, space is allocated after it.
860      * The newly inserted space will be filled with NOP instructions.
861      *
862      * Returns a CodeChunk positioned at pc and available to write
863      * instructions upto (byteCode + length(existing instruction at pc) bytes.
864      *
865      * This chunk is left correctly positioned at the end of the code
866      * stream, ready to accept more code. Its pc will have increased by
867      * additionalBytes.
868      *
869      * It is the responsibility of the caller to patch up any
870      * branches or gotos.
871      *
872      * @param pc
873      * @param additionalBytes
874      */

875     CodeChunk insertCodeSpace(int pc, int additionalBytes)
876     {
877         short existingOpcode = getOpcode(pc);
878
879         int lengthOfExistingInstruction
880             = instructionLength(existingOpcode);
881             
882         
883         if (additionalBytes > 0)
884         {
885             // Size of the current code after this pc.
886
int sizeToMove = (getPC() - pc) - lengthOfExistingInstruction;
887
888             // Increase the code by the number of bytes to be
889
// inserted. These NOPs will be overwritten by the
890
// moved code by the System.arraycopy below.
891
// It's assumed that the number of inserted bytes
892
// is small, one or two instructions worth, so it
893
// won't be a performance issue.
894
for (int i = 0; i < additionalBytes; i++)
895                 addInstr(VMOpcode.NOP);
896         
897             // Must get codeBytes here as the array might have re-sized.
898
byte[] codeBytes = cout.getData();
899             
900             int byteOffset = CODE_OFFSET + pc + lengthOfExistingInstruction;
901                     
902             
903             // Shift the existing code stream down
904
System.arraycopy(
905                     codeBytes, byteOffset,
906                     codeBytes, byteOffset + additionalBytes,
907                     sizeToMove);
908             
909             // Place NOPs in the space just freed by the move.
910
// This is not required, it ias assumed the caller
911
// will overwrite all the bytes they requested, but
912
// to be safe fill in with NOPs rather than leaving code
913
// that could break the verifier.
914
Arrays.fill(codeBytes, byteOffset, byteOffset + additionalBytes,
915                     (byte) VMOpcode.NOP);
916         }
917         
918         // The caller must overwrite the original instruction
919
// at pc, thus increase the range of the limit stream
920
// created to include those bytes.
921
additionalBytes += lengthOfExistingInstruction;
922         
923         // Now the caller needs to fill in the instructions
924
// that make up the modified byteCount bytes of bytecode stream.
925
// Return a CodeChunk that can be used for this and
926
// is limited to only those bytes.
927
// The pc of the original code chunk is left unchanged.
928

929         return new CodeChunk(this, pc, additionalBytes);
930                         
931     }
932     
933     /*
934      * * Methods related to splitting the byte code chunks into sections that
935      * fit in the JVM's limits for a single method.
936      */

937
938     /**
939      * For a block of byte code starting at program counter pc for codeLength
940      * bytes return the maximum stack value, assuming a initial stack depth of
941      * zero.
942      */

943     private int findMaxStack(ClassHolder ch, int pc, int codeLength) {
944
945         final int endPc = pc + codeLength;
946         int stack = 0;
947         int maxStack = 0;
948
949         for (; pc < endPc;) {
950
951             short opcode = getOpcode(pc);
952             
953  
954             int stackDelta = stackWordDelta(ch, pc, opcode);
955
956             stack += stackDelta;
957             if (stack > maxStack)
958                 maxStack = stack;
959  
960             int[] cond_pcs = findConditionalPCs(pc, opcode);
961             if (cond_pcs != null) {
962                 // an else block exists.
963
if (cond_pcs[3] != -1) {
964                     int blockMaxStack = findMaxStack(ch, cond_pcs[1],
965                             cond_pcs[2]);
966                     if ((stack + blockMaxStack) > maxStack)
967                         maxStack = stack + blockMaxStack;
968
969                     pc = cond_pcs[3];
970                     continue;
971                 }
972             }
973
974             pc += instructionLength(opcode);
975         }
976
977         return maxStack;
978     }
979
980     /**
981      * Return the number of stack words pushed (positive) or popped (negative)
982      * by this instruction.
983      */

984     private int stackWordDelta(ClassHolder ch, int pc, short opcode) {
985         if (SanityManager.DEBUG) {
986             // this validates the OPCODE_ACTION entry
987
instructionLength(opcode);
988         }
989
990         int stackDelta = OPCODE_ACTION[opcode][0];
991         if (stackDelta == VARIABLE_STACK) {
992             stackDelta = getVariableStackDelta(ch, pc, opcode);
993         }
994
995         return stackDelta;
996     }
997
998     /**
999      * Get the type descriptor in the virtual machine format for the type
1000     * defined by the constant pool index for the instruction at pc.
1001     */

1002    private String JavaDoc getTypeDescriptor(ClassHolder ch, int pc) {
1003        int cpi = getU2(pc);
1004
1005
1006        // Field reference or method reference
1007
CONSTANT_Index_info cii = (CONSTANT_Index_info) ch.getEntry(cpi);
1008
1009        // NameAndType reference
1010
int nameAndType = cii.getI2();
1011        cii = (CONSTANT_Index_info) ch.getEntry(nameAndType);
1012
1013        // UTF8 descriptor
1014
int descriptor = cii.getI2();
1015        CONSTANT_Utf8_info type = (CONSTANT_Utf8_info) ch.getEntry(descriptor);
1016
1017        String JavaDoc vmDescriptor = type.toString();
1018
1019        return vmDescriptor;
1020    }
1021
1022    /**
1023     * Get the word count for a type descriptor in the format of the virual
1024     * machine. For a method this returns the the word count for the return
1025     * type.
1026     */

1027    private static int getDescriptorWordCount(String JavaDoc vmDescriptor) {
1028 
1029        int width;
1030        if (VMDescriptor.DOUBLE.equals(vmDescriptor))
1031            width = 2;
1032        else if (VMDescriptor.LONG.equals(vmDescriptor))
1033            width = 2;
1034        else if (vmDescriptor.charAt(0) == VMDescriptor.C_METHOD) {
1035            switch (vmDescriptor.charAt(vmDescriptor.length() - 1)) {
1036            case VMDescriptor.C_DOUBLE:
1037            case VMDescriptor.C_LONG:
1038                width = 2;
1039                break;
1040            case VMDescriptor.C_VOID:
1041                width = 0;
1042                break;
1043            default:
1044                width = 1;
1045                break;
1046            }
1047        } else
1048            width = 1;
1049
1050        return width;
1051    }
1052
1053    /**
1054     * Get the number of words pushed (positive) or popped (negative) by this
1055     * instruction. The instruction is a get/put field or a method call, thus
1056     * the size of the words is defined by the field or method being access.
1057     */

1058    private int getVariableStackDelta(ClassHolder ch, int pc, int opcode) {
1059        String JavaDoc vmDescriptor = getTypeDescriptor(ch, pc);
1060        int width = CodeChunk.getDescriptorWordCount(vmDescriptor);
1061
1062        int stackDelta = 0;
1063        // Stack delta depends on context.
1064
switch (opcode) {
1065        case VMOpcode.GETSTATIC:
1066            stackDelta = width;
1067            break;
1068
1069        case VMOpcode.GETFIELD:
1070            stackDelta = width - 1; // one for popped object ref
1071
break;
1072
1073        case VMOpcode.PUTSTATIC:
1074            stackDelta = -width;
1075            break;
1076
1077        case VMOpcode.PUTFIELD:
1078            stackDelta = -width - 1; // one for pop object ref
1079
break;
1080
1081        case VMOpcode.INVOKEVIRTUAL:
1082        case VMOpcode.INVOKESPECIAL:
1083            stackDelta = -1; // for instance reference for method call.
1084
case VMOpcode.INVOKESTATIC:
1085            stackDelta += (width - CodeChunk.parameterWordCount(vmDescriptor));
1086            // System.out.println("invoked non-interface " + stackDelta);
1087
break;
1088
1089        case VMOpcode.INVOKEINTERFACE:
1090            // third byte contains the number of arguments to be popped
1091
stackDelta = width - getOpcode(pc + 3);
1092            // System.out.println("invoked interface " + stackDelta);
1093
break;
1094        default:
1095            System.out.println("WHO IS THIS ");
1096            break;
1097
1098        }
1099
1100        return stackDelta;
1101    }
1102
1103    /**
1104     * Calculate the number of stack words in the arguments pushed for this
1105     * method descriptor.
1106     */

1107    private static int parameterWordCount(String JavaDoc methodDescriptor) {
1108        int wordCount = 0;
1109        for (int i = 1;; i++) {
1110            switch (methodDescriptor.charAt(i)) {
1111            case VMDescriptor.C_ENDMETHOD:
1112                return wordCount;
1113            case VMDescriptor.C_DOUBLE:
1114            case VMDescriptor.C_LONG:
1115                wordCount += 2;
1116                break;
1117            case VMDescriptor.C_ARRAY:
1118                // skip while there are array symbols.
1119
do {
1120                    i++;
1121                } while (methodDescriptor.charAt(i) == VMDescriptor.C_ARRAY);
1122                if (methodDescriptor.charAt(i) != VMDescriptor.C_CLASS) {
1123                    // an array is a reference, even an array of doubles.
1124
wordCount += 1;
1125                    break;
1126                }
1127
1128            // fall through to skip the Lclassname; after the array.
1129

1130            case VMDescriptor.C_CLASS:
1131                // skip until ;
1132
do {
1133                    i++;
1134                } while (methodDescriptor.charAt(i) != VMDescriptor.C_ENDCLASS);
1135                wordCount += 1;
1136                break;
1137            default:
1138                wordCount += 1;
1139                break;
1140            }
1141        }
1142    }
1143
1144    /**
1145     * Find the limits of a conditional block starting at the instruction with
1146     * the given opcode at the program counter pc.
1147     * <P>
1148     * Returns a six element integer array of program counters and lengths.
1149     * <code. [0] - program counter of the IF opcode (passed in as pc) [1] -
1150     * program counter of the start of the then block [2] - length of the then
1151     * block [3] - program counter of the else block, -1 if no else block
1152     * exists. [4] - length of of the else block, -1 if no else block exists.
1153     * [5] - program counter of the common end point. </code>
1154     *
1155     * Looks for and handles conditionals that are written by the Conditional
1156     * class.
1157     *
1158     * @return Null if the opcode is not the start of a conditional otherwise
1159     * the array of values.
1160     */

1161    private int[] findConditionalPCs(int pc, short opcode) {
1162        switch (opcode) {
1163        default:
1164            return null;
1165        case VMOpcode.IFNONNULL:
1166        case VMOpcode.IFNULL:
1167        case VMOpcode.IFEQ:
1168        case VMOpcode.IFNE:
1169            break;
1170        }
1171
1172        int then_pc;
1173        int else_pc;
1174        int if_off = getU2(pc);
1175
1176        if ((if_off == 8)
1177                && (getOpcode(pc + VMOpcode.IF_INS_LENGTH) == VMOpcode.GOTO_W)) {
1178            // 32 bit branch
1179
then_pc = pc + VMOpcode.IF_INS_LENGTH + VMOpcode.GOTO_W_INS_LENGTH;
1180
1181            // Get else PC from the 32 bit offset within the GOTO_W
1182
// instruction remembering to add it to the pc of that
1183
// instruction, not the original IF.
1184
else_pc = pc + VMOpcode.IF_INS_LENGTH
1185                    + getU4(pc + VMOpcode.IF_INS_LENGTH);
1186
1187        } else {
1188            then_pc = pc + VMOpcode.IF_INS_LENGTH;
1189            else_pc = pc + if_off;
1190        }
1191
1192        // Need to look for the goto or goto_w at the
1193
// end of the then block. There might not be
1194
// one for the case when there is no else block.
1195
// In that case the then block will just run into
1196
// what we currently think the else pc.
1197

1198        int end_pc = -1;
1199        for (int tpc = then_pc; tpc < else_pc;) {
1200            short opc = getOpcode(tpc);
1201
1202            // need to handle conditionals
1203
int[] innerCond = findConditionalPCs(tpc, opc);
1204            if (innerCond != null) {
1205                // skip to the end of this conditional
1206
tpc = innerCond[5]; // end_pc
1207
continue;
1208            }
1209
1210            if (opc == VMOpcode.GOTO) {
1211                // not at the end of the then block
1212
// so not our goto. Shouldn't see this
1213
// with the current code due to the
1214
// skipping of the conditional above.
1215
// But safe defensive programming.
1216
if (tpc != (else_pc - VMOpcode.GOTO_INS_LENGTH))
1217                    continue;
1218
1219                end_pc = tpc + getU2(tpc);
1220                break;
1221            } else if (opc == VMOpcode.GOTO_W) {
1222                // not at the end of the then block
1223
// so not our goto. SHouldn't see this
1224
// with the current code due to the
1225
// skipping of the conditional above.
1226
// But safe defensive programming.
1227
if (tpc != (else_pc - VMOpcode.GOTO_W_INS_LENGTH))
1228                    continue;
1229
1230                end_pc = tpc + getU4(tpc);
1231                break;
1232
1233            }
1234            tpc += instructionLength(opc);
1235        }
1236
1237        int else_len;
1238        int then_len;
1239        if (end_pc == -1) {
1240            // no else block;
1241
end_pc = else_pc;
1242            else_pc = -1;
1243
1244            then_len = end_pc - then_pc;
1245            else_len = -1;
1246        } else {
1247            then_len = else_pc - then_pc;
1248            else_len = end_pc - else_pc;
1249        }
1250
1251        int[] ret = new int[6];
1252
1253        ret[0] = pc;
1254        ret[1] = then_pc;
1255        ret[2] = then_len;
1256        ret[3] = else_pc;
1257        ret[4] = else_len;
1258        ret[5] = end_pc;
1259
1260        return ret;
1261    }
1262    
1263    /**
1264     * Attempt to split the current method by pushing a chunk of
1265     * its code into a sub-method. The starting point of the split
1266     * (split_pc) must correspond to a stack depth of zero. It is the
1267     * reponsibility of the caller to ensure this.
1268     * Split is only made if there exists a chunk of code starting at
1269     * pc=split_pc, whose stack depth upon termination is zero.
1270     * The method will try to split a code section greater than
1271     * optimalMinLength but may split earlier if no such block exists.
1272     * <P>
1273     * The method is aimed at splitting methods that contain
1274     * many independent statements.
1275     * <P>
1276     * If a split is possible this method will perform the split and
1277     * create a void sub method, and move the code into the sub-method
1278     * and setup this method to call the sub-method before continuing.
1279     * This method's max stack and current pc will be correctly set
1280     * as though the method had just been created.
1281     *
1282     * @param mb Method for this chunk.
1283     * @param ch Class definition
1284     * @param optimalMinLength minimum length required for split
1285     */

1286    final int splitZeroStack(BCMethod mb, ClassHolder ch, final int split_pc,
1287            final int optimalMinLength) {
1288        
1289        int splitMinLength = splitMinLength(mb);
1290        
1291        int stack = 0;
1292
1293        // maximum possible split seen that is less than
1294
// the minimum.
1295
int possibleSplitLength = -1;
1296
1297        // do not split until at least this point (inclusive)
1298
// used to ensure no split occurs in the middle of
1299
// a conditional.
1300
int outerConditionalEnd_pc = -1;
1301
1302        int end_pc = getPC(); // pc will be positioned at the end.
1303
for (int pc = split_pc; pc < end_pc;) {
1304
1305            short opcode = getOpcode(pc);
1306
1307            int stackDelta = stackWordDelta(ch, pc, opcode);
1308
1309            stack += stackDelta;
1310
1311            // Cannot split a conditional but need to calculate
1312
// the stack depth at the end of the conditional.
1313
// Each path through the conditional will have the
1314
// same stack depth.
1315
int[] cond_pcs = findConditionalPCs(pc, opcode);
1316            if (cond_pcs != null) {
1317                // an else block exists, skip the then block.
1318
if (cond_pcs[3] != -1) {
1319                    pc = cond_pcs[3];
1320                    continue;
1321                }
1322
1323                if (SanityManager.DEBUG) {
1324                    if (outerConditionalEnd_pc != -1) {
1325                        if (cond_pcs[5] >= outerConditionalEnd_pc)
1326                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");
1327                    }
1328                }
1329
1330                if (outerConditionalEnd_pc == -1) {
1331                    outerConditionalEnd_pc = cond_pcs[5];
1332                }
1333            }
1334
1335            pc += instructionLength(opcode);
1336
1337            // Don't split in the middle of a conditional
1338
if (outerConditionalEnd_pc != -1) {
1339                if (pc > outerConditionalEnd_pc) {
1340                    // passed the outermost conditional
1341
outerConditionalEnd_pc = -1;
1342                }
1343                continue;
1344            }
1345
1346            if (stack != 0)
1347                continue;
1348
1349            int splitLength = pc - split_pc;
1350
1351            if (splitLength < optimalMinLength) {
1352                // record we do have a possible split.
1353
possibleSplitLength = splitLength;
1354                continue;
1355            }
1356
1357            // no point splitting to a method bigger
1358
// than the VM can handle. Save one for
1359
// return instruction.
1360
if (splitLength > BCMethod.CODE_SPLIT_LENGTH - 1) {
1361                splitLength = -1;
1362            }
1363            else if (CodeChunk.isReturn(opcode))
1364            {
1365                // Don't handle a return in the middle of
1366
// an instruction stream. Don't think this
1367
// is generated, but be safe.
1368
splitLength = -1;
1369            }
1370            
1371            // if splitLenth was set to -1 above then there
1372
// is no possible split at this instruction.
1373
if (splitLength == -1)
1374            {
1375                // no earlier split at all
1376
if (possibleSplitLength == -1)
1377                    return -1;
1378 
1379                // Decide if the earlier possible split is
1380
// worth it.
1381
if (possibleSplitLength <= splitMinLength)
1382                    return -1;
1383
1384                // OK go with the earlier split
1385
splitLength = possibleSplitLength;
1386
1387            }
1388
1389            // Yes, we can split this big method into a smaller method!!
1390

1391            BCMethod subMethod = startSubMethod(mb, "void", split_pc,
1392                    splitLength);
1393
1394            return splitCodeIntoSubMethod(mb, ch, subMethod,
1395                    split_pc, splitLength);
1396        }
1397        return -1;
1398    }
1399
1400    /**
1401     * Start a sub method that we will split the portion of our current code to,
1402     * starting from start_pc and including codeLength bytes of code.
1403     *
1404     * Return a BCMethod obtained from BCMethod.getNewSubMethod with the passed
1405     * in return type and same parameters as mb if the code block to be moved
1406     * uses parameters.
1407     */

1408    private BCMethod startSubMethod(BCMethod mb, String JavaDoc returnType,
1409            int split_pc, int blockLength) {
1410
1411        boolean needParameters = usesParameters(mb, split_pc, blockLength);
1412
1413        return mb.getNewSubMethod(returnType, needParameters);
1414    }
1415
1416    /**
1417     * Does a section of code use parameters.
1418     * Any load, exception ALOAD_0 in an instance method, is
1419     * seen as using parameters, as this complete byte code
1420     * implementation does not use local variables.
1421     *
1422     */

1423    private boolean usesParameters(BCMethod mb, int pc, int codeLength) {
1424
1425        // does the method even have parameters?
1426
if (mb.parameters == null)
1427            return false;
1428
1429        boolean isStatic = (mb.myEntry.getModifier() & Modifier.STATIC) != 0;
1430
1431        int endPc = pc + codeLength;
1432
1433        for (; pc < endPc;) {
1434            short opcode = getOpcode(pc);
1435            switch (opcode) {
1436            case VMOpcode.ILOAD_0:
1437            case VMOpcode.LLOAD_0:
1438            case VMOpcode.FLOAD_0:
1439            case VMOpcode.DLOAD_0:
1440                return true;
1441
1442            case VMOpcode.ALOAD_0:
1443                if (isStatic)
1444                    return true;
1445                break;
1446
1447            case VMOpcode.ILOAD_1:
1448            case VMOpcode.LLOAD_1:
1449            case VMOpcode.FLOAD_1:
1450            case VMOpcode.DLOAD_1:
1451            case VMOpcode.ALOAD_1:
1452                return true;
1453
1454            case VMOpcode.ILOAD_2:
1455            case VMOpcode.LLOAD_2:
1456            case VMOpcode.FLOAD_2:
1457            case VMOpcode.DLOAD_2:
1458            case VMOpcode.ALOAD_2:
1459                return true;
1460
1461            case VMOpcode.ILOAD_3:
1462            case VMOpcode.LLOAD_3:
1463            case VMOpcode.FLOAD_3:
1464            case VMOpcode.DLOAD_3:
1465            case VMOpcode.ALOAD_3:
1466                return true;
1467
1468            case VMOpcode.ILOAD:
1469            case VMOpcode.LLOAD:
1470            case VMOpcode.FLOAD:
1471            case VMOpcode.DLOAD:
1472            case VMOpcode.ALOAD:
1473                return true;
1474            default:
1475                break;
1476
1477            }
1478            pc += instructionLength(opcode);
1479        }
1480        return false;
1481    }
1482    /**
1483     * Split a block of code from this method into a sub-method
1484     * and call it.
1485     *
1486     * Returns the pc of this method just after the call
1487     * to the sub-method.
1488     
1489     * @param mb My method
1490     * @param ch My class
1491     * @param subMethod Sub-method code was pushed into
1492     * @param split_pc Program counter the split started at
1493     * @param splitLength Length of code split
1494     */

1495    private int splitCodeIntoSubMethod(BCMethod mb, ClassHolder ch,
1496            BCMethod subMethod, final int split_pc, final int splitLength) {
1497        CodeChunk subChunk = subMethod.myCode;
1498
1499        byte[] codeBytes = cout.getData();
1500
1501        // the code to be moved into the sub method
1502
// as a block. This will correctly increase the
1503
// program counter.
1504
try {
1505            subChunk.cout.write(codeBytes, CODE_OFFSET + split_pc, splitLength);
1506        } catch (IOException JavaDoc ioe) {
1507            limitHit(ioe);
1508        }
1509
1510        // Just cause the sub-method to return,
1511
// fix up its maxStack and then complete it.
1512
if (subMethod.myReturnType.equals("void"))
1513            subChunk.addInstr(VMOpcode.RETURN);
1514        else
1515           subChunk.addInstr(VMOpcode.ARETURN);
1516        
1517        // Finding the max stack requires the class format to
1518
// still be valid. If we have blown the number of constant
1519
// pool entries then we can no longer guarantee that indexes
1520
// into the constant pool in the code stream are valid.
1521
if (cb.limitMsg != null)
1522            return -1;
1523        
1524        subMethod.maxStack = subChunk.findMaxStack(ch, 0, subChunk.getPC());
1525        subMethod.complete();
1526
1527        return removePushedCode(mb, ch, subMethod, split_pc, splitLength);
1528    }
1529
1530    /**
1531     * Remove a block of code from this method that was pushed into a sub-method
1532     * and call the sub-method.
1533     *
1534     * Returns the pc of this method just after the call to the sub-method.
1535     *
1536     * @param mb
1537     * My method
1538     * @param ch
1539     * My class
1540     * @param subMethod
1541     * Sub-method code was pushed into
1542     * @param split_pc
1543     * Program counter the split started at
1544     * @param splitLength
1545     * Length of code split
1546     */

1547    private int removePushedCode(BCMethod mb, ClassHolder ch,
1548            BCMethod subMethod, final int split_pc, final int splitLength) {
1549        // now need to fix up this method, create
1550
// a new CodeChunk just to be clearer than
1551
// trying to modify this chunk directly.
1552

1553        // total length of the code for this method before split
1554
final int codeLength = getPC();
1555        
1556        CodeChunk replaceChunk = new CodeChunk(mb.cb);
1557        mb.myCode = replaceChunk;
1558        mb.maxStack = 0;
1559
1560        byte[] codeBytes = cout.getData();
1561        
1562        // write any existing code before the split point
1563
// into the replacement chunk.
1564
if (split_pc != 0) {
1565            try {
1566                replaceChunk.cout.write(codeBytes, CODE_OFFSET, split_pc);
1567            } catch (IOException JavaDoc ioe) {
1568                limitHit(ioe);
1569            }
1570        }
1571
1572        // Call the sub method, will write into replaceChunk.
1573
mb.callSubMethod(subMethod);
1574
1575        int postSplit_pc = replaceChunk.getPC();
1576
1577        // Write the code remaining in this method into the replacement chunk
1578

1579        int remainingCodePC = split_pc + splitLength;
1580        int remainingCodeLength = codeLength - splitLength - split_pc;
1581        
1582       try {
1583            replaceChunk.cout.write(codeBytes, CODE_OFFSET + remainingCodePC,
1584                    remainingCodeLength);
1585        } catch (IOException JavaDoc ioe) {
1586            limitHit(ioe);
1587        }
1588
1589        // Finding the max stack requires the class format to
1590
// still be valid. If we have blown the number of constant
1591
// pool entries then we can no longer guarantee that indexes
1592
// into the constant pool in the code stream are valid.
1593
if (cb.limitMsg != null)
1594            return -1;
1595        
1596        mb.maxStack = replaceChunk.findMaxStack(ch, 0, replaceChunk.getPC());
1597
1598        return postSplit_pc;
1599    }
1600    
1601    /**
1602     * Split an expression out of a large method into its own
1603     * sub-method.
1604     * <P>
1605     * Method call expressions are of the form:
1606     * <UL>
1607     * <LI> expr.method(args) -- instance method call
1608     * <LI> method(args) -- static method call
1609     * </UL>
1610     * Two special cases of instance method calls will be handled
1611     * by the first incarnation of splitExpressionOut.
1612     * three categories:
1613     * <UL>
1614     * <LI>this.method(args)
1615     * <LI>this.getter().method(args)
1616     * </UL>
1617     * These calls are choosen as they are easier sub-cases
1618     * and map to the code generated for SQL statements.
1619     * Future coders can expand the method to cover more cases.
1620     * <P>
1621     * This method will split out such expressions in sub-methods
1622     * and replace the original code with a call to that submethod.
1623     * <UL>
1624     * <LI>this.method(args) ->> this.sub1([parameters])
1625     * <LI>this.getter().method(args) ->> this.sub1([parameters])
1626     * </UL>
1627     * The assumption is of course that the call to the sub-method
1628     * is much smaller than the code it replaces.
1629     * <P>
1630     * Looking at the byte code for such calls they would look like
1631     * (for an example three argument method):
1632     * <code>
1633     * this arg1 arg2 arg3 INVOKE // this.method(args)
1634     * this INVOKE arg1 arg2 arg3 INVOKE // this.getter().metod(args)
1635     * </code>
1636     * The bytecode for the arguments can be arbitary long and
1637     * consist of expressions, typical Derby code for generated
1638     * queries is deeply nested method calls.
1639     * <BR>
1640     * If none of the arguments requred the parameters passed into
1641     * the method, then in both cases the replacement bytecode
1642     * would look like:
1643     * <code>
1644     * this.sub1();
1645     * </code>
1646     * Parameter handling is just as in the method splitZeroStack().
1647     * <P>
1648     * Because the VM is a stack machine the original byte code
1649     * sequences are self contained. The stack at the start of
1650     * is sequence is N and at the end (after the method call) will
1651     * be:
1652     * <UL>
1653     * <LI> N - void method
1654     * <LI> N + 1 - method returning a single word
1655     * <LI> N + 2 - method returning a double word (java long or double)
1656     * </UL>
1657     * This code will handle the N+1 where the word is a reference,
1658     * the typical case for generated code.
1659     * <BR>
1660     * The code is self contained because in general the byte code
1661     * for the arguments will push and pop values but never drop
1662     * below the stack value at the start of the byte code sequence.
1663     * E.g. in the examples the stack before the first arg will be
1664     * N+1 (the objectref for the method call) and at the end of the
1665     * byte code for arg1 will be N+2 or N+3 depending on if arg1 is
1666     * a single or double word argument. During the execution of
1667     * the byte code the stack may have had many arguments pushed
1668     * and popped, but will never have dropped below N+1. Thus the
1669     * code for arg1 is independent of the stack's previous values
1670     * and is self contained. This self-containment then extends to
1671     * all the arguements, the method call itself and pushing the
1672     * objectref for the method call, thus the complete
1673     * sequence is self-contained.
1674     * <BR>
1675     * The self-containment breaks in a few cases, take the simple
1676     * method call this.method(3), the byte code for this could be:
1677     * <code>
1678     * push3 this swap invoke
1679     * </code>
1680     * In this case the byte code for arg1 (swap) is not self-contained
1681     * and relies on earlier stack values.
1682     * <P>
1683     * How to identify "self-contained blocks of code".
1684     * <BR>
1685     * We walk through the byte code and maintain a history of
1686     * the program counter that indicates the start of the
1687     * independent sequence each stack word depends on.
1688     * Thus for a ALOAD_0 instruction which pushes 'this' the
1689     * dependent pc is that of the this. If a DUP instruction followed
1690     * then the top-word is now dependent on the previous word (this)
1691     * and thus the dependence of it is equal to the dependence of
1692     * the previous word. This information is kept in earliestIndepPC
1693     * array as we process the instruction stream.
1694     * <BR>
1695     * When a INVOKE instruction is seen for an instance method
1696     * that returns a single or double word, the dependence of
1697     * the returned value is the dependence of the word in the
1698     * stack that is the objectref for the call. This complete
1699     * sequence from the pc the objectref depended on to the
1700     * INVOKE instruction is then a self contained sequence
1701     * and can be split into a sub-method.
1702
1703     * <BR>
1704     * If the block is self-contained then it can be split, following
1705     * similar logic to splitZeroStack().
1706     *
1707     * <P>
1708     * WORK IN PROGRESS - Incremental development
1709     * <BR>
1710     * Currently walks the method maintaining the
1711     * earliestIndepPC array and identifies potential blocks
1712     * to splt, performs splits as required.
1713     * Called by BCMethod but commented out in submitted code.
1714     * Tested with local changes from calls in BCMethod.
1715     * Splits generally work, though largeCodeGen shows
1716     * a problem that will be fixed before the code in
1717     * enabled for real.
1718     *
1719      */

1720
1721    final int splitExpressionOut(final BCMethod mb, final ClassHolder ch,
1722            final int optimalMinLength,
1723            final int maxStack)
1724    {
1725        // Save the best block we have seen for splitting out.
1726
int bestSplitPC = -1;
1727        int bestSplitBlockLength = -1;
1728        String JavaDoc bestSplitRT = null;
1729        
1730        int splitMinLength = splitMinLength(mb);
1731        
1732        // Program counter of the earliest instruction
1733
// that the word in the current active stack
1734
// at the given depth depends on.
1735
//
1736
// Some examples, N is the stack depth *after*
1737
// the instruction.
1738
// E.g.
1739
// ALOAD_0 - pushes this, is an instruction that
1740
// pushes an independent value, so the current
1741
// stack word depends on the pc of current instruction.
1742
// earliestIndepPC[N] = pc (that pushed the value).
1743
//
1744
// DUP - duplicates the top word, so the duplicated
1745
// top word will depend on the same pc as the word
1746
// it was duplicated from.
1747
// I.e. earliestIndepPC[N]
1748
// = earliestIndepPC[N-1];
1749
//
1750
// instance method call returning single word value.
1751
// The top word will depend on the same pc as the
1752
// objectref for the method call, which was at the
1753
// same depth in this case.
1754
// earliestIndepPC[N] unchanged
1755
//
1756
// at any time earliestIndepPC is only valid
1757
// from 1 to N where N is the depth of the stack.
1758
int[] earliestIndepPC = new int[maxStack+1];
1759       
1760        int stack = 0;
1761               
1762        //TODO: this conditional handling is copied from
1763
//the splitZeroStack code, need to check to see
1764
// how it fits with the expression logic.
1765
// do not split until at least this point (inclusive)
1766
// used to ensure no split occurs in the middle of
1767
// a conditional.
1768
int outerConditionalEnd_pc = -1;
1769
1770        int end_pc = getPC();
1771        
1772        for (int pc = 0; pc < end_pc;) {
1773
1774            short opcode = getOpcode(pc);
1775            
1776            int stackDelta = stackWordDelta(ch, pc, opcode);
1777            
1778            stack += stackDelta;
1779            
1780            // Cannot split a conditional but need to calculate
1781
// the stack depth at the end of the conditional.
1782
// Each path through the conditional will have the
1783
// same stack depth.
1784
int[] cond_pcs = findConditionalPCs(pc, opcode);
1785            if (cond_pcs != null) {
1786                
1787                // TODO: This conditional handling was copied
1788
// from splitZeroStack, haven't looked in detail
1789
// to see how a conditional should be handled
1790
// with an expression split. So for the time
1791
// being just bail.
1792
if (true)
1793                    return -1;
1794
1795                // an else block exists, skip the then block.
1796
if (cond_pcs[3] != -1) {
1797                    pc = cond_pcs[3];
1798                    continue;
1799                }
1800                
1801                if (SanityManager.DEBUG)
1802                {
1803                    if (outerConditionalEnd_pc != -1)
1804                    {
1805                        if (cond_pcs[5] >= outerConditionalEnd_pc)
1806                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");
1807                    }
1808                }
1809
1810                if (outerConditionalEnd_pc == -1)
1811                {
1812                    outerConditionalEnd_pc = cond_pcs[5];
1813                }
1814            }
1815                       
1816            pc += instructionLength(opcode);
1817            
1818            // Don't split in the middle of a conditional
1819
if (outerConditionalEnd_pc != -1) {
1820                if (pc > outerConditionalEnd_pc) {
1821                    // passed the outermost conditional
1822
outerConditionalEnd_pc = -1;
1823                }
1824                continue;
1825            }
1826            
1827            int opcode_pc = pc - instructionLength(opcode);
1828            switch (opcode)
1829            {
1830            // Any instruction we don't have any information
1831
// on, we simply clear all evidence of independent
1832
// starting points, and start again.
1833
default:
1834                Arrays.fill(earliestIndepPC,
1835                        0, stack + 1, -1);
1836                break;
1837            
1838            // Independent instructions do not change the stack depth
1839
// and the independence of the top word picks up
1840
// the independence of the previous word at the same
1841
// position. Ie. no change!
1842
case VMOpcode.ARRAYLENGTH:
1843            case VMOpcode.NOP:
1844            case VMOpcode.CHECKCAST:
1845            case VMOpcode.D2L:
1846            case VMOpcode.DNEG:
1847            case VMOpcode.F2I:
1848                break;
1849                
1850            // Independent instructions that push one word
1851
case VMOpcode.ALOAD_0:
1852            case VMOpcode.ALOAD_1:
1853            case VMOpcode.ALOAD_2:
1854            case VMOpcode.ALOAD_3:
1855            case VMOpcode.ALOAD:
1856            case VMOpcode.ACONST_NULL:
1857            case VMOpcode.BIPUSH:
1858            case VMOpcode.FCONST_0:
1859            case VMOpcode.FCONST_1:
1860            case VMOpcode.FCONST_2:
1861            case VMOpcode.FLOAD:
1862            case VMOpcode.ICONST_0:
1863            case VMOpcode.ICONST_1:
1864            case VMOpcode.ICONST_2:
1865            case VMOpcode.ICONST_3:
1866            case VMOpcode.ICONST_4:
1867            case VMOpcode.ICONST_5:
1868            case VMOpcode.ICONST_M1:
1869            case VMOpcode.LDC:
1870            case VMOpcode.LDC_W:
1871            case VMOpcode.SIPUSH:
1872                earliestIndepPC[stack] = opcode_pc;
1873                break;
1874            
1875            // Independent instructions that push two words
1876
case VMOpcode.DCONST_0:
1877            case VMOpcode.DCONST_1:
1878            case VMOpcode.LCONST_0:
1879            case VMOpcode.LCONST_1:
1880            case VMOpcode.LDC2_W:
1881            case VMOpcode.LLOAD:
1882            case VMOpcode.LLOAD_0:
1883            case VMOpcode.LLOAD_1:
1884            case VMOpcode.LLOAD_2:
1885            case VMOpcode.LLOAD_3:
1886                earliestIndepPC[stack - 1] =
1887                    earliestIndepPC[stack] = opcode_pc;
1888                break;
1889                
1890            // nothing to do for pop, obviously no
1891
// code will be dependent on the popped words.
1892
case VMOpcode.POP:
1893            case VMOpcode.POP2:
1894                break;
1895                
1896            case VMOpcode.SWAP:
1897                earliestIndepPC[stack] = earliestIndepPC[stack -1];
1898                break;
1899            
1900            // push a value that depends on the previous value
1901
case VMOpcode.I2L:
1902                earliestIndepPC[stack] = earliestIndepPC[stack -1];
1903                break;
1904                
1905            case VMOpcode.GETFIELD:
1906            {
1907                String JavaDoc vmDescriptor = getTypeDescriptor(ch, opcode_pc);
1908                int width = CodeChunk.getDescriptorWordCount(vmDescriptor);
1909                if (width == 2)
1910                    earliestIndepPC[stack] = earliestIndepPC[stack -1];
1911                    
1912                break;
1913            }
1914
1915            case VMOpcode.INVOKEINTERFACE:
1916            case VMOpcode.INVOKEVIRTUAL:
1917            {
1918                // ...,objectref[,word]*
1919
//
1920
// => ...
1921
// => ...,word
1922
// => ...,word1,word2
1923

1924                // Width of the value returned by the method call.
1925
String JavaDoc vmDescriptor = getTypeDescriptor(ch, opcode_pc);
1926                int width = CodeChunk.getDescriptorWordCount(vmDescriptor);
1927                
1928                // Independence of this block is the independence
1929
// of the objectref that invokved the method.
1930
int selfContainedBlockStart;
1931                if (width == 0)
1932                {
1933                    // objectref was at one more than the current depth
1934
// no plan to split here though, as we are only
1935
// splitting methods that return a reference.
1936
selfContainedBlockStart = -1;
1937                        // earliestIndepPC[stack + 1];
1938
}
1939                else if (width == 1)
1940                {
1941                    // stack is unchanged, objectref was at
1942
// the current stack depth
1943
selfContainedBlockStart = earliestIndepPC[stack];
1944               }
1945                else
1946                {
1947                    // width == 2, objectref was one below the
1948
// current stack depth.
1949
// no plan to split here though, as we are only
1950
// splitting methods that return a reference.
1951
selfContainedBlockStart = -1;
1952                        
1953                    // top two words depend on the objectref
1954
// which was at the same depth of the first word
1955
// of the 64 bit value.
1956
earliestIndepPC[stack] =
1957                        earliestIndepPC[stack - 1];
1958                 }
1959                
1960                if (selfContainedBlockStart != -1)
1961                {
1962                    int blockLength = pc - selfContainedBlockStart;
1963                    
1964                    if (blockLength <= splitMinLength)
1965                    {
1966                        // No point splitting, too small
1967
}
1968                    else if (blockLength > (VMOpcode.MAX_CODE_LENGTH - 1))
1969                    {
1970                        // too big to split into a single method
1971
// (one for the return opcode)
1972
}
1973                    else
1974                    {
1975                        // Only split for a method that returns
1976
// an class reference.
1977
int me = vmDescriptor.lastIndexOf(')');
1978                    
1979                        if (vmDescriptor.charAt(me+1) == 'L')
1980                        {
1981                            String JavaDoc rt = vmDescriptor.substring(me + 2,
1982                                    vmDescriptor.length() - 1);
1983                            
1984                            // convert to external format.
1985
rt = rt.replace('/', '.');
1986                            
1987                            if (blockLength >= optimalMinLength)
1988                            {
1989                                // Split now!
1990
BCMethod subMethod = startSubMethod(mb,
1991                                        rt, selfContainedBlockStart,
1992                                        blockLength);
1993    
1994                                return splitCodeIntoSubMethod(mb, ch, subMethod,
1995                                        selfContainedBlockStart, blockLength);
1996                            }
1997                            else if (blockLength > bestSplitBlockLength)
1998                            {
1999                                // Save it, may split at this point
2000
// if nothing better seen.
2001
bestSplitPC = selfContainedBlockStart;
2002                                bestSplitBlockLength = blockLength;
2003                                bestSplitRT = rt;
2004                            }
2005                        }
2006                    }
2007                }
2008                break;
2009              }
2010            }
2011            
2012       }
2013        
2014
2015        if (bestSplitBlockLength != -1) {
2016            BCMethod subMethod = startSubMethod(mb,
2017                    bestSplitRT, bestSplitPC,
2018                    bestSplitBlockLength);
2019    
2020            return splitCodeIntoSubMethod(mb, ch, subMethod,
2021                    bestSplitPC, bestSplitBlockLength);
2022        }
2023               
2024        return -1;
2025    }
2026    
2027    /**
2028     * See if the opcode is a return instruction.
2029     * @param opcode opcode to be checked
2030     * @return true for is a return instruction, false otherwise.
2031     */

2032    private static boolean isReturn(short opcode)
2033    {
2034        switch (opcode)
2035        {
2036        case VMOpcode.RETURN:
2037        case VMOpcode.ARETURN:
2038        case VMOpcode.IRETURN:
2039        case VMOpcode.FRETURN:
2040        case VMOpcode.DRETURN:
2041        case VMOpcode.LRETURN:
2042            return true;
2043         default:
2044            return false;
2045        }
2046    }
2047    
2048    /**
2049     * Minimum split length for a sub-method. If the number of
2050     * instructions to call the sub-method exceeds the length
2051     * of the sub-method, then there's no point splitting.
2052     * The number of bytes in the code stream to call
2053     * a generated sub-method can take is based upon the number of method args.
2054     * A method can have maximum of 255 words of arguments (section 4.10 JVM spec)
2055     * which in the worst case would be 254 (one-word) parameters
2056     * and this. For a sub-method the arguments will come from the
2057     * parameters to the method, i.e. ALOAD, ILOAD etc.
2058     * <BR>
2059     * This leads to this number of instructions.
2060     * <UL>
2061     * <LI> 4 - 'this' and first 3 parameters have single byte instructions
2062     * <LI> (N-4)*2 - Remaining parameters have two byte instructions
2063     * <LI> 3 for the invoke instruction.
2064     * </UL>
2065     */

2066    private static int splitMinLength(BCMethod mb) {
2067        int min = 1 + 3; // For ALOAD_0 (this) and invoke instruction
2068

2069        if (mb.parameters != null) {
2070            int paramCount = mb.parameters.length;
2071            
2072            min += paramCount;
2073            
2074            if (paramCount > 3)
2075                min += (paramCount - 3);
2076        }
2077        
2078        return min;
2079    }
2080    /*
2081    final int splitNonZeroStack(BCMethod mb, ClassHolder ch,
2082            final int codeLength, final int optimalMinLength,
2083            int maxStack) {
2084        
2085        // program counter for the instruction that
2086        // made the stack reach the given stack depth.
2087        int[] stack_pcs = new int[maxStack+1];
2088        Arrays.fill(stack_pcs, -1);
2089        
2090        int stack = 0;
2091        
2092        // maximum possible split seen that is less than
2093        // the minimum.
2094        int possibleSplitLength = -1;
2095        
2096        System.out.println("NZ SPLIT + " + mb.getName());
2097
2098        // do not split until at least this point (inclusive)
2099        // used to ensure no split occurs in the middle of
2100        // a conditional.
2101        int outerConditionalEnd_pc = -1;
2102
2103        int end_pc = 0 + codeLength;
2104        for (int pc = 0; pc < end_pc;) {
2105
2106            short opcode = getOpcode(pc);
2107
2108            int stackDelta = stackWordDelta(ch, pc, opcode);
2109            
2110            stack += stackDelta;
2111            
2112            // Cannot split a conditional but need to calculate
2113            // the stack depth at the end of the conditional.
2114            // Each path through the conditional will have the
2115            // same stack depth.
2116            int[] cond_pcs = findConditionalPCs(pc, opcode);
2117            if (cond_pcs != null) {
2118                // an else block exists, skip the then block.
2119                if (cond_pcs[3] != -1) {
2120                    pc = cond_pcs[3];
2121                    continue;
2122                }
2123                
2124                if (SanityManager.DEBUG)
2125                {
2126                    if (outerConditionalEnd_pc != -1)
2127                    {
2128                        if (cond_pcs[5] >= outerConditionalEnd_pc)
2129                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");
2130                    }
2131                }
2132
2133                if (outerConditionalEnd_pc == -1)
2134                {
2135                    outerConditionalEnd_pc = cond_pcs[5];
2136                }
2137            }
2138                       
2139            pc += instructionLength(opcode);
2140            
2141            // Don't split in the middle of a conditional
2142            if (outerConditionalEnd_pc != -1) {
2143                if (pc > outerConditionalEnd_pc) {
2144                    // passed the outermost conditional
2145                    outerConditionalEnd_pc = -1;
2146                }
2147                continue;
2148            }
2149            
2150            if (stackDelta == 0)
2151                continue;
2152
2153            // Only split when the stack is having items popped
2154            if (stackDelta > 0)
2155            {
2156                // pushing double word, clear out a
2157                if (stackDelta == 2)
2158                    stack_pcs[stack - 1] = pc;
2159                stack_pcs[stack] = pc;
2160                continue;
2161            }
2162            
2163            int opcode_pc = pc - instructionLength(opcode);
2164            
2165            // Look for specific opcodes that have the capability
2166            // of having a significant amount of code in a self
2167            // contained block.
2168            switch (opcode)
2169            {
2170            // this.method(A) construct
2171            // ... -- stack N
2172            // push this -- stack N+1
2173            // push args -- stack N+1+A
2174            // call method -- stack N+R (R=0,1,2)
2175            //
2176            // stackDelta = (N+R) - (N+1+A) = R-(1+A)
2177            // stack = N+R
2178            // Need to determine N+1
2179            //
2180            //
2181            //
2182            // this.a(<i2>, <i2>, <i3>)
2183            // returning int
2184            //
2185            // stackDelta = -3 (this & 3 args popped, ret pushed)
2186            // initial depth N = 10
2187            // pc - stack
2188            // 100 ... - stack 10
2189            // 101 push this - stack 11
2190            // 109 push i1 - stack 12
2191            // 125 push i2 - stack 13
2192            // 156 push i3 - stack 14
2193            // 157 call - stack 11
2194            //
2195            // need stack_pcs[11] = stack_pcs[11 + -3]
2196            //
2197            // ref.method(args).method(args) ... method(args)
2198            //
2199            case VMOpcode.INVOKEINTERFACE:
2200            case VMOpcode.INVOKESPECIAL:
2201            case VMOpcode.INVOKEVIRTUAL:
2202            {
2203                String vmDescriptor = getTypeDescriptor(ch, opcode_pc);
2204                int r = CodeChunk.getDescriptorWordCount(vmDescriptor);
2205             
2206                // PC of the opcode that pushed the reference for
2207                // this method call.
2208                int ref_pc = stack_pcs[stack - r + 1];
2209               if (getOpcode(ref_pc) == VMOpcode.ALOAD_0) {
2210                    System.out.println("POSS SPLIT " + (pc - ref_pc) + " @ " + ref_pc);
2211                }
2212               break;
2213            }
2214            case VMOpcode.INVOKESTATIC:
2215                String vmDescriptor = getTypeDescriptor(ch, opcode_pc);
2216                int r = CodeChunk.getDescriptorWordCount(vmDescriptor);
2217                int p1_pc = stack_pcs[stack - r + 1];
2218                System.out.println("POSS STATIC SPLIT " + (pc - p1_pc) + " @ " + p1_pc);
2219                
2220            }
2221            stack_pcs[stack] = opcode_pc;
2222        }
2223        return -1;
2224    }*/

2225}
2226
Popular Tags