Source Code Cross Referenced for CodeChunk.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » services » bytecode » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.services.bytecode 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.services.bytecode.CodeChunk
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.services.bytecode;
0023:
0024:        import org.apache.derby.iapi.services.classfile.CONSTANT_Index_info;
0025:        import org.apache.derby.iapi.services.classfile.CONSTANT_Utf8_info;
0026:        import org.apache.derby.iapi.services.classfile.ClassFormatOutput;
0027:        import org.apache.derby.iapi.services.classfile.ClassHolder;
0028:        import org.apache.derby.iapi.services.classfile.ClassMember;
0029:        import org.apache.derby.iapi.services.classfile.VMDescriptor;
0030:
0031:        import org.apache.derby.iapi.services.sanity.SanityManager;
0032:        import org.apache.derby.iapi.services.classfile.VMOpcode;
0033:        import org.apache.derby.iapi.services.io.ArrayOutputStream;
0034:
0035:        import java.io.IOException;
0036:        import java.lang.reflect.Modifier;
0037:        import java.util.Arrays;
0038:
0039:        /**
0040:         * This class represents a chunk of code in a CodeAttribute.
0041:         * Typically, a CodeAttribute represents the code in a method.
0042:         * If there is a try/catch block, each catch block will get its
0043:         * own code chunk.  This allows the catch blocks to all be put at
0044:         * the end of the generated code for a method, which eliminates
0045:         * the need to generate a jump around each catch block, which
0046:         * would be a forward reference.
0047:         */
0048:        final class CodeChunk {
0049:
0050:            /**
0051:             * Starting point of the byte code stream in the underlying stream/array.
0052:             */
0053:            private static final int CODE_OFFSET = 8;
0054:
0055:            // The use of ILOAD for the non-integer types is correct.
0056:            // We have to assume that the appropriate checks/conversions
0057:            // are defined on math operation results to ensure that
0058:            // the type is preserved when/as needed.
0059:            static final short[] LOAD_VARIABLE = { VMOpcode.ILOAD, /* vm_byte */
0060:            VMOpcode.ILOAD, /* vm_short */
0061:            VMOpcode.ILOAD, /* vm_int */
0062:            VMOpcode.LLOAD, /* vm_long */
0063:            VMOpcode.FLOAD, /* vm_float */
0064:            VMOpcode.DLOAD, /* vm_double */
0065:            VMOpcode.ILOAD, /* vm_char */
0066:            VMOpcode.ALOAD /* vm_reference */
0067:            };
0068:
0069:            static final short[] LOAD_VARIABLE_FAST = { VMOpcode.ILOAD_0, /* vm_byte */
0070:            VMOpcode.ILOAD_0, /* vm_short */
0071:            VMOpcode.ILOAD_0, /* vm_int */
0072:            VMOpcode.LLOAD_0, /* vm_long */
0073:            VMOpcode.FLOAD_0, /* vm_float */
0074:            VMOpcode.DLOAD_0, /* vm_double */
0075:            VMOpcode.ILOAD_0, /* vm_char */
0076:            VMOpcode.ALOAD_0 /* vm_reference */
0077:            };
0078:
0079:            // The ISTOREs for non-int types are how things work.
0080:            // It assumes that the appropriate casts are done
0081:            // on operations on non-ints to ensure that the values
0082:            // remain in the valid ranges.
0083:            static final short[] STORE_VARIABLE = { VMOpcode.ISTORE, /* vm_byte */
0084:            VMOpcode.ISTORE, /* vm_short */
0085:            VMOpcode.ISTORE, /* vm_int */
0086:            VMOpcode.LSTORE, /* vm_long */
0087:            VMOpcode.FSTORE, /* vm_float */
0088:            VMOpcode.DSTORE, /* vm_double */
0089:            VMOpcode.ISTORE, /* vm_char */
0090:            VMOpcode.ASTORE /* vm_reference */
0091:            };
0092:
0093:            static final short[] STORE_VARIABLE_FAST = { VMOpcode.ISTORE_0, /* vm_byte */
0094:            VMOpcode.ISTORE_0, /* vm_short */
0095:            VMOpcode.ISTORE_0, /* vm_int */
0096:            VMOpcode.LSTORE_0, /* vm_long */
0097:            VMOpcode.FSTORE_0, /* vm_float */
0098:            VMOpcode.DSTORE_0, /* vm_double */
0099:            VMOpcode.ISTORE_0, /* vm_char */
0100:            VMOpcode.ASTORE_0 /* vm_reference */
0101:            };
0102:
0103:            static final short ARRAY_ACCESS[] = { VMOpcode.BALOAD, /* vm_byte */
0104:            VMOpcode.SALOAD, /* vm_short */
0105:            VMOpcode.IALOAD, /* vm_int */
0106:            VMOpcode.LALOAD, /* vm_long */
0107:            VMOpcode.FALOAD, /* vm_float */
0108:            VMOpcode.DALOAD, /* vm_double */
0109:            VMOpcode.CALOAD, /* vm_char */
0110:            VMOpcode.AALOAD /* vm_reference */
0111:            };
0112:            static final short ARRAY_STORE[] = { VMOpcode.BASTORE, /* vm_byte */
0113:            VMOpcode.SASTORE, /* vm_short */
0114:            VMOpcode.IASTORE, /* vm_int */
0115:            VMOpcode.LASTORE, /* vm_long */
0116:            VMOpcode.FASTORE, /* vm_float */
0117:            VMOpcode.DASTORE, /* vm_double */
0118:            VMOpcode.CASTORE, /* vm_char */
0119:            VMOpcode.AASTORE /* vm_reference */
0120:            };
0121:            static final short[] RETURN_OPCODE = { VMOpcode.IRETURN, /* 0 = byte      */
0122:            VMOpcode.IRETURN, /* 1 = short     */
0123:            VMOpcode.IRETURN, /* 2 = int       */
0124:            VMOpcode.LRETURN, /* 3 = long      */
0125:            VMOpcode.FRETURN, /* 4 = float     */
0126:            VMOpcode.DRETURN, /* 5 = double    */
0127:            VMOpcode.IRETURN, /* 6 = char      */
0128:            VMOpcode.ARETURN /* 7 = reference */
0129:            };
0130:
0131:            // the first dimension is the current vmTypeId
0132:            // the second dimension is the target vmTypeId
0133:            //
0134:            // the cells of the entry at [current,target] are:
0135:            // 0: operation
0136:            // 1: result type of operation
0137:            // if entry[1] = target, we are done. otherwise,
0138:            // you have to continue with entry[1] as the new current
0139:            // after generating the opcode listed (don't generate if it is NOP).
0140:            // if entry[0] = BAD, we can
0141:
0142:            static final short CAST_CONVERSION_INFO[][][] = {
0143:                    /* current = vm_byte */
0144:                    {
0145:                            /* target = vm_byte      */{ VMOpcode.NOP,
0146:                                    BCExpr.vm_byte },
0147:                            /* target = vm_short     */{ VMOpcode.NOP,
0148:                                    BCExpr.vm_short },
0149:                            /* target = vm_int       */{ VMOpcode.NOP,
0150:                                    BCExpr.vm_int },
0151:                            /* target = vm_long      */{ VMOpcode.NOP,
0152:                                    BCExpr.vm_int },
0153:                            /* target = vm_float     */{ VMOpcode.NOP,
0154:                                    BCExpr.vm_int },
0155:                            /* target = vm_double    */{ VMOpcode.NOP,
0156:                                    BCExpr.vm_int },
0157:                            /* target = vm_char      */{ VMOpcode.NOP,
0158:                                    BCExpr.vm_char },
0159:                            /* target = vm_reference */{ VMOpcode.BAD,
0160:                                    BCExpr.vm_reference } },
0161:                    /* current = vm_short */
0162:                    {
0163:                            /* target = vm_byte      */{ VMOpcode.NOP,
0164:                                    BCExpr.vm_byte },
0165:                            /* target = vm_short     */{ VMOpcode.NOP,
0166:                                    BCExpr.vm_short },
0167:                            /* target = vm_int       */{ VMOpcode.NOP,
0168:                                    BCExpr.vm_int },
0169:                            /* target = vm_long      */{ VMOpcode.NOP,
0170:                                    BCExpr.vm_int },
0171:                            /* target = vm_float     */{ VMOpcode.NOP,
0172:                                    BCExpr.vm_int },
0173:                            /* target = vm_double    */{ VMOpcode.NOP,
0174:                                    BCExpr.vm_int },
0175:                            /* target = vm_char      */{ VMOpcode.NOP,
0176:                                    BCExpr.vm_char },
0177:                            /* target = vm_reference */{ VMOpcode.BAD,
0178:                                    BCExpr.vm_reference } },
0179:                    /* current = vm_int */
0180:                    {
0181:                            /* target = vm_byte      */{ VMOpcode.I2B,
0182:                                    BCExpr.vm_byte },
0183:                            /* target = vm_short     */{ VMOpcode.I2S,
0184:                                    BCExpr.vm_short },
0185:                            /* target = vm_int       */{ VMOpcode.NOP,
0186:                                    BCExpr.vm_int },
0187:                            /* target = vm_long      */{ VMOpcode.I2L,
0188:                                    BCExpr.vm_long },
0189:                            /* target = vm_float     */{ VMOpcode.I2F,
0190:                                    BCExpr.vm_float },
0191:                            /* target = vm_double    */{ VMOpcode.I2D,
0192:                                    BCExpr.vm_double },
0193:                            /* target = vm_char      */{ VMOpcode.I2B,
0194:                                    BCExpr.vm_char },
0195:                            /* target = vm_reference */{ VMOpcode.BAD,
0196:                                    BCExpr.vm_reference } },
0197:                    /* current = vm_long */
0198:                    {
0199:                            /* target = vm_byte      */{ VMOpcode.L2I,
0200:                                    BCExpr.vm_int },
0201:                            /* target = vm_short     */{ VMOpcode.L2I,
0202:                                    BCExpr.vm_int },
0203:                            /* target = vm_int       */{ VMOpcode.L2I,
0204:                                    BCExpr.vm_int },
0205:                            /* target = vm_long      */{ VMOpcode.NOP,
0206:                                    BCExpr.vm_long },
0207:                            /* target = vm_float     */{ VMOpcode.L2F,
0208:                                    BCExpr.vm_float },
0209:                            /* target = vm_double    */{ VMOpcode.L2D,
0210:                                    BCExpr.vm_double },
0211:                            /* target = vm_char      */{ VMOpcode.L2I,
0212:                                    BCExpr.vm_int },
0213:                            /* target = vm_reference */{ VMOpcode.BAD,
0214:                                    BCExpr.vm_reference } },
0215:                    /* current = vm_float */
0216:                    {
0217:                            /* target = vm_byte      */{ VMOpcode.F2I,
0218:                                    BCExpr.vm_int },
0219:                            /* target = vm_short     */{ VMOpcode.F2I,
0220:                                    BCExpr.vm_int },
0221:                            /* target = vm_int       */{ VMOpcode.F2I,
0222:                                    BCExpr.vm_int },
0223:                            /* target = vm_long      */{ VMOpcode.F2L,
0224:                                    BCExpr.vm_long },
0225:                            /* target = vm_float     */{ VMOpcode.NOP,
0226:                                    BCExpr.vm_float },
0227:                            /* target = vm_double    */{ VMOpcode.F2D,
0228:                                    BCExpr.vm_double },
0229:                            /* target = vm_char      */{ VMOpcode.F2I,
0230:                                    BCExpr.vm_int },
0231:                            /* target = vm_reference */{ VMOpcode.BAD,
0232:                                    BCExpr.vm_reference } },
0233:                    /* current = vm_double */
0234:                    {
0235:                            /* target = vm_byte      */{ VMOpcode.D2I,
0236:                                    BCExpr.vm_int },
0237:                            /* target = vm_short     */{ VMOpcode.D2I,
0238:                                    BCExpr.vm_int },
0239:                            /* target = vm_int       */{ VMOpcode.D2I,
0240:                                    BCExpr.vm_int },
0241:                            /* target = vm_long      */{ VMOpcode.D2L,
0242:                                    BCExpr.vm_long },
0243:                            /* target = vm_float     */{ VMOpcode.D2F,
0244:                                    BCExpr.vm_float },
0245:                            /* target = vm_double    */{ VMOpcode.NOP,
0246:                                    BCExpr.vm_double },
0247:                            /* target = vm_char      */{ VMOpcode.D2I,
0248:                                    BCExpr.vm_int },
0249:                            /* target = vm_reference */{ VMOpcode.BAD,
0250:                                    BCExpr.vm_reference } },
0251:                    /* current = vm_char */
0252:                    {
0253:                            /* target = vm_byte      */{ VMOpcode.NOP,
0254:                                    BCExpr.vm_byte },
0255:                            /* target = vm_short     */{ VMOpcode.NOP,
0256:                                    BCExpr.vm_short },
0257:                            /* target = vm_int       */{ VMOpcode.NOP,
0258:                                    BCExpr.vm_int },
0259:                            /* target = vm_long      */{ VMOpcode.NOP,
0260:                                    BCExpr.vm_int },
0261:                            /* target = vm_float     */{ VMOpcode.NOP,
0262:                                    BCExpr.vm_int },
0263:                            /* target = vm_double    */{ VMOpcode.NOP,
0264:                                    BCExpr.vm_int },
0265:                            /* target = vm_char      */{ VMOpcode.NOP,
0266:                                    BCExpr.vm_char },
0267:                            /* target = vm_reference */{ VMOpcode.BAD,
0268:                                    BCExpr.vm_reference } },
0269:                    /* current = vm_reference */
0270:                    {
0271:                            /* target = vm_byte      */{ VMOpcode.BAD,
0272:                                    BCExpr.vm_byte },
0273:                            /* target = vm_short     */{ VMOpcode.BAD,
0274:                                    BCExpr.vm_short },
0275:                            /* target = vm_int       */{ VMOpcode.BAD,
0276:                                    BCExpr.vm_int },
0277:                            /* target = vm_long      */{ VMOpcode.BAD,
0278:                                    BCExpr.vm_long },
0279:                            /* target = vm_float     */{ VMOpcode.BAD,
0280:                                    BCExpr.vm_float },
0281:                            /* target = vm_double    */{ VMOpcode.BAD,
0282:                                    BCExpr.vm_double },
0283:                            /* target = vm_char      */{ VMOpcode.BAD,
0284:                                    BCExpr.vm_char },
0285:                            /* target = vm_reference */{ VMOpcode.NOP,
0286:                                    BCExpr.vm_reference } } };
0287:
0288:            /**
0289:             * Constant used by OPCODE_ACTION to represent the
0290:             * common action of push one word, 1 byte
0291:             * for the instruction.
0292:             */
0293:            private static final byte[] push1_1i = { 1, 1 };
0294:
0295:            /**
0296:             * Constant used by OPCODE_ACTION to represent the
0297:             * common action of push two words, 1 byte
0298:             * for the instruction.
0299:             */
0300:            private static final byte[] push2_1i = { 2, 1 };
0301:            /**
0302:             * Constant used by OPCODE_ACTION to the opcode is
0303:             * not yet supported.
0304:             */
0305:            private static final byte[] NS = { 0, -1 };
0306:
0307:            /**
0308:             * Value for OPCODE_ACTION[opcode][0] to represent
0309:             * the number of words popped or pushed in variable.
0310:             */
0311:            private static final byte VARIABLE_STACK = -128;
0312:
0313:            /**
0314:             * Array that provides two pieces of information about
0315:             * each VM opcode. Each opcode has a two byte array.
0316:             * <P>
0317:             * The first element in the array [0] is the number of
0318:             * stack words (double/long count as two) pushed by the opcode.
0319:             * Will be negative if the opcode pops values.
0320:             * 
0321:             * <P>
0322:             * The second element in the array [1] is the number of bytes
0323:             * in the instruction stream that this opcode's instruction
0324:             * takes up, including the opocode.
0325:             */
0326:            private static final byte[][] OPCODE_ACTION = {
0327:
0328:            /* NOP  0 */{ 0, 1 },
0329:
0330:            /* ACONST_NULL  1 */push1_1i,
0331:            /* ICONST_M1  2 */push1_1i,
0332:            /* ICONST_0  3 */push1_1i,
0333:            /* ICONST_1  4 */push1_1i,
0334:            /* ICONST_2  5 */push1_1i,
0335:            /* ICONST_3  6 */push1_1i,
0336:            /* ICONST_4  7 */push1_1i,
0337:            /* ICONST_5  8 */push1_1i,
0338:            /* LCONST_0  9 */push2_1i,
0339:            /* LCONST_1  10 */push2_1i,
0340:            /* FCONST_0  11 */push1_1i,
0341:            /* FCONST_1  12 */push1_1i,
0342:            /* FCONST_2  13 */push1_1i,
0343:            /* DCONST_0  14 */push2_1i,
0344:            /* DCONST_1  15 */push2_1i,
0345:
0346:            /* BIPUSH  16 */{ 1, 2 },
0347:            /* SIPUSH  17 */{ 1, 3 },
0348:            /* LDC  18 */{ 1, 2 },
0349:            /* LDC_W  19 */{ 1, 3 },
0350:            /* LDC2_W  20 */{ 2, 3 },
0351:
0352:            /* ILOAD  21 */{ 1, 2 },
0353:            /* LLOAD  22 */{ 2, 2 },
0354:            /* FLOAD  23 */{ 1, 2 },
0355:            /* DLOAD  24 */{ 2, 2 },
0356:            /* ALOAD  25 */{ 1, 2 },
0357:            /* ILOAD_0  26 */push1_1i,
0358:            /* ILOAD_1  27 */push1_1i,
0359:            /* ILOAD_2  28 */push1_1i,
0360:            /* ILOAD_3  29 */push1_1i,
0361:            /* LLOAD_0  30 */push2_1i,
0362:            /* LLOAD_1  31 */push2_1i,
0363:            /* LLOAD_2  32 */push2_1i,
0364:            /* LLOAD_3  33 */push2_1i,
0365:            /* FLOAD_0  34 */push1_1i,
0366:            /* FLOAD_1  35 */push1_1i,
0367:            /* FLOAD_2  36 */push1_1i,
0368:            /* FLOAD_3  37 */push1_1i,
0369:            /* DLOAD_0  38 */push2_1i,
0370:            /* DLOAD_1  39 */push2_1i,
0371:            /* DLOAD_2  40 */push2_1i,
0372:            /* DLOAD_3  41 */push2_1i,
0373:            /* ALOAD_0  42 */push1_1i,
0374:            /* ALOAD_1  43 */push1_1i,
0375:            /* ALOAD_2  44 */push1_1i,
0376:            /* ALOAD_3  45 */push1_1i,
0377:            /* IALOAD  46 */{ -1, 1 },
0378:            /* LALOAD  47 */{ 0, 1 },
0379:            /* FALOAD  48 */{ -1, 1 },
0380:            /* DALOAD  49 */{ 0, 1 },
0381:            /* AALOAD  50 */{ -1, 1 },
0382:            /* BALOAD  51 */{ -1, 1 },
0383:            /* CALOAD  52 */{ -1, 1 },
0384:
0385:            /* SALOAD  53 */{ -1, 1 },
0386:            /* ISTORE  54 */{ -1, 2 },
0387:            /* LSTORE  55 */{ -2, 2 },
0388:            /* FSTORE  56 */{ -1, 2 },
0389:            /* DSTORE  57 */{ -2, 2 },
0390:            /* ASTORE  58 */{ -1, 2 },
0391:            /* ISTORE_0  59 */{ -1, 1 },
0392:            /* ISTORE_1  60 */{ -1, 1 },
0393:            /* ISTORE_2  61 */{ -1, 1 },
0394:            /* ISTORE_3  62 */{ -1, 1 },
0395:            /* LSTORE_0  63 */{ -2, 1 },
0396:            /* LSTORE_1  64 */{ -2, 1 },
0397:            /* LSTORE_2  65 */{ -2, 1 },
0398:            /* LSTORE_3  66 */{ -2, 1 },
0399:            /* FSTORE_0  67 */{ -1, 1 },
0400:            /* FSTORE_1  68 */{ -1, 1 },
0401:            /* FSTORE_2  69 */{ -1, 1 },
0402:            /* FSTORE_3  70 */{ -1, 1 },
0403:            /* DSTORE_0  71 */{ -2, 1 },
0404:            /* DSTORE_1  72 */{ -2, 1 },
0405:            /* DSTORE_2  73 */{ -2, 1 },
0406:            /* DSTORE_3  74 */{ -2, 1 },
0407:            /* ASTORE_0  75 */{ -1, 1 },
0408:            /* ASTORE_1  76 */{ -1, 1 },
0409:            /* ASTORE_2  77 */{ -1, 1 },
0410:            /* ASTORE_3  78 */{ -1, 1 },
0411:            /* IASTORE  79 */{ -3, 1 },
0412:            /* LASTORE  80 */{ -4, 1 },
0413:            /* FASTORE  81 */{ -3, 1 },
0414:            /* DASTORE  82 */{ -4, 1 },
0415:            /* AASTORE  83 */{ -3, 1 },
0416:            /* BASTORE  84 */{ -3, 1 },
0417:            /* CASTORE  85 */{ -3, 1 },
0418:            /* SASTORE  86 */{ -3, 1 },
0419:
0420:            /* POP  87 */{ -1, 1 },
0421:            /* POP2  88 */{ -2, 1 },
0422:            /* DUP  89 */push1_1i,
0423:            /* DUP_X1  90 */push1_1i,
0424:            /* DUP_X2  91 */push1_1i,
0425:            /* DUP2  92 */push2_1i,
0426:            /* DUP2_X1  93 */push2_1i,
0427:            /* DUP2_X2  94 */push2_1i,
0428:            /* SWAP  95 */{ 0, 1 },
0429:
0430:            /* IADD  96 */NS,
0431:            /* LADD  97 */NS,
0432:            /* FADD  98 */{ -1, 1 },
0433:            /* DADD  99 */{ -2, 1 },
0434:            /* ISUB  100 */NS,
0435:            /* LSUB  101 */NS,
0436:            /* FSUB  102 */{ -1, 1 },
0437:            /* DSUB  103 */{ -2, 1 },
0438:            /* IMUL  104 */NS,
0439:            /* LMUL  105 */NS,
0440:            /* FMUL  106 */{ -1, 1 },
0441:            /* DMUL  107 */{ -2, 1 },
0442:            /* IDIV  108 */NS,
0443:            /* LDIV  109 */NS,
0444:            /* FDIV  110 */{ -1, 1 },
0445:            /* DDIV  111 */{ -2, 1 },
0446:            /* IREM  112 */{ -1, 1 },
0447:            /* LREM  113 */{ -2, 1 },
0448:            /* FREM  114 */{ -1, 1 },
0449:            /* DREM  115 */{ -2, 1 },
0450:            /* INEG  116 */{ 0, 1 },
0451:            /* LNEG  117 */{ 0, 1 },
0452:            /* FNEG  118 */{ 0, 1 },
0453:            /* DNEG  119 */{ 0, 1 },
0454:            /* ISHL  120 */{ -1, 1 },
0455:            /* LSHL  121 */NS,
0456:            /* ISHR  122 */NS,
0457:            /* LSHR  123 */NS,
0458:            /* IUSHR  124 */NS,
0459:            /* LUSHR  125 */NS,
0460:
0461:            /* IAND  126 */{ -1, 1 },
0462:            /* LAND  127 */NS,
0463:            /* IOR  128 */{ -1, 1 },
0464:            /* LOR  129 */NS,
0465:            /* IXOR  130 */NS,
0466:            /* LXOR  131 */NS,
0467:            /* IINC  132 */NS,
0468:
0469:            /* I2L  133 */push1_1i,
0470:            /* I2F  134 */{ 0, 1 },
0471:            /* I2D  135 */push1_1i,
0472:            /* L2I  136 */{ -1, 1 },
0473:            /* L2F  137 */{ -1, 1 },
0474:            /* L2D  138 */{ 0, 1 },
0475:            /* F2I  139 */{ 0, 1 },
0476:            /* F2L  140 */push2_1i,
0477:            /* F2D  141 */push1_1i,
0478:            /* D2I  142 */{ -1, 1 },
0479:            /* D2L  143 */{ 0, 1 },
0480:            /* D2F  144 */{ -1, 1 },
0481:            /* I2B  145 */{ 0, 1 },
0482:            /* I2C  146 */{ 0, 1 },
0483:            /* I2S  147 */{ 0, 1 },
0484:
0485:            /* LCMP  148 */NS,
0486:            /* FCMPL  149 */{ -1, 1 },
0487:            /* FCMPG  150 */{ -1, 1 },
0488:            /* DCMPL  151 */{ -3, 1 },
0489:            /* DCMPG  152 */{ -3, 1 },
0490:            /* IFEQ  153 */{ -1, VMOpcode.IF_INS_LENGTH },
0491:            /* IFNE  154 */{ -1, VMOpcode.IF_INS_LENGTH },
0492:            /* IFLT  155 */{ -1, VMOpcode.IF_INS_LENGTH },
0493:            /* IFGE  156 */{ -1, VMOpcode.IF_INS_LENGTH },
0494:            /* IFGT  157 */{ -1, VMOpcode.IF_INS_LENGTH },
0495:            /* IFLE  158 */{ -1, VMOpcode.IF_INS_LENGTH },
0496:            /* IF_ICMPEQ  159 */NS,
0497:            /* IF_ICMPNE  160 */NS,
0498:            /* IF_ICMPLT  161 */NS,
0499:            /* IF_ICMPGE  162 */NS,
0500:            /* IF_ICMPGT  163 */NS,
0501:            /* IF_ICMPLE  164 */NS,
0502:            /* IF_ACMPEQ  165 */NS,
0503:            /* IF_ACMPNE  166 */NS,
0504:            /* GOTO  167 */{ 0, VMOpcode.GOTO_INS_LENGTH },
0505:            /* JSR  168 */NS,
0506:            /* RET  169 */NS,
0507:            /* TABLESWITCH  170 */NS,
0508:            /* LOOKUPSWITCH  171 */NS,
0509:
0510:            /* IRETURN  172 */{ -1, 1 }, // strictly speaking all words on the stack are popped.
0511:                    /* LRETURN  173 */{ -2, 1 }, // strictly speaking all words on the stack are popped.
0512:                    /* FRETURN  174 */{ -1, 1 }, // strictly speaking all words on the stack are popped.
0513:                    /* DRETURN  175 */{ -2, 1 }, // strictly speaking all words on the stack are popped.
0514:                    /* ARETURN  176 */{ -1, 1 }, // strictly speaking all words on the stack are popped.
0515:                    /* RETURN  177 */{ 0, 1 }, // strictly speaking all words on the stack are popped.
0516:
0517:                    /* GETSTATIC  178 */{ VARIABLE_STACK, 3 },
0518:                    /* PUTSTATIC  179 */{ VARIABLE_STACK, 3 },
0519:                    /* GETFIELD  180 */{ VARIABLE_STACK, 3 },
0520:                    /* PUTFIELD  181 */{ VARIABLE_STACK, 3 },
0521:                    /* INVOKEVIRTUAL  182 */{ VARIABLE_STACK, 3 },
0522:                    /* INVOKESPECIAL  183 */{ VARIABLE_STACK, 3 },
0523:                    /* INVOKESTATIC  184 */{ VARIABLE_STACK, 3 },
0524:                    /* INVOKEINTERFACE  185 */{ VARIABLE_STACK, 5 },
0525:
0526:                    /* XXXUNUSEDXXX  186 */NS,
0527:
0528:                    /* NEW  187 */{ 1, 3 },
0529:                    /* NEWARRAY  188 */{ 0, 2 },
0530:                    /* ANEWARRAY  189 */{ 0, 3 },
0531:                    /* ARRAYLENGTH  190 */{ 0, 1 },
0532:                    /* ATHROW  191 */NS,
0533:                    /* CHECKCAST  192 */{ 0, 3 },
0534:                    /* INSTANCEOF  193 */{ 0, 3 },
0535:                    /* MONITORENTER  194 */NS,
0536:                    /* MONITOREXIT  195 */NS,
0537:                    /* WIDE  196 */NS,
0538:                    /* MULTIANEWARRAY  197 */NS,
0539:                    /* IFNULL  198 */{ -1, VMOpcode.IF_INS_LENGTH },
0540:                    /* IFNONNULL  199 */{ -1, VMOpcode.IF_INS_LENGTH },
0541:                    /* GOTO_W  200 */{ 0, VMOpcode.GOTO_W_INS_LENGTH },
0542:                    /* JSR_W  201 */NS,
0543:                    /* BREAKPOINT  202 */NS,
0544:
0545:            };
0546:
0547:            /**
0548:             * Assume an IOException means some limit of the class file
0549:             * format was hit
0550:             * 
0551:             */
0552:            private void limitHit(IOException ioe) {
0553:                cb.addLimitExceeded(ioe.toString());
0554:            }
0555:
0556:            /**
0557:             * Add an instruction that has no operand.
0558:             * All opcodes are 1 byte large.
0559:             */
0560:            void addInstr(short opcode) {
0561:                try {
0562:                    cout.putU1(opcode);
0563:                } catch (IOException ioe) {
0564:                    limitHit(ioe);
0565:                }
0566:
0567:                if (SanityManager.DEBUG) {
0568:                    if (OPCODE_ACTION[opcode][1] != 1)
0569:                        SanityManager.THROWASSERT("Opcode " + opcode
0570:                                + " incorrect entry in OPCODE_ACTION -"
0571:                                + " writing 1 byte - set as "
0572:                                + OPCODE_ACTION[opcode][1]);
0573:                }
0574:            }
0575:
0576:            /**
0577:             * Add an instruction that has a 16 bit operand.
0578:             */
0579:            void addInstrU2(short opcode, int operand) {
0580:
0581:                try {
0582:                    cout.putU1(opcode);
0583:                    cout.putU2(operand);
0584:                } catch (IOException ioe) {
0585:                    limitHit(ioe);
0586:                }
0587:
0588:                if (SanityManager.DEBUG) {
0589:                    if (OPCODE_ACTION[opcode][1] != 3)
0590:                        SanityManager.THROWASSERT("Opcode " + opcode
0591:                                + " incorrect entry in OPCODE_ACTION -"
0592:                                + " writing 3 bytes - set as "
0593:                                + OPCODE_ACTION[opcode][1]);
0594:                }
0595:            }
0596:
0597:            /**
0598:             * Add an instruction that has a 32 bit operand.
0599:             */
0600:            void addInstrU4(short opcode, int operand) {
0601:                try {
0602:                    cout.putU1(opcode);
0603:                    cout.putU4(operand);
0604:                } catch (IOException ioe) {
0605:                    limitHit(ioe);
0606:                }
0607:                if (SanityManager.DEBUG) {
0608:                    if (OPCODE_ACTION[opcode][1] != 5)
0609:                        SanityManager.THROWASSERT("Opcode " + opcode
0610:                                + " incorrect entry in OPCODE_ACTION -"
0611:                                + " writing 5 bytes - set as "
0612:                                + OPCODE_ACTION[opcode][1]);
0613:                }
0614:            }
0615:
0616:            /**
0617:             * Add an instruction that has an 8 bit operand.
0618:             */
0619:            void addInstrU1(short opcode, int operand) {
0620:                try {
0621:                    cout.putU1(opcode);
0622:                    cout.putU1(operand);
0623:                } catch (IOException ioe) {
0624:                    limitHit(ioe);
0625:                }
0626:
0627:                // Only debug code from here.
0628:                if (SanityManager.DEBUG) {
0629:
0630:                    if (OPCODE_ACTION[opcode][1] != 2)
0631:                        SanityManager.THROWASSERT("Opcode " + opcode
0632:                                + " incorrect entry in OPCODE_ACTION -"
0633:                                + " writing 2 bytes - set as "
0634:                                + OPCODE_ACTION[opcode][1]);
0635:
0636:                }
0637:            }
0638:
0639:            /**
0640:             * This takes an instruction that has a narrow
0641:             * and a wide form for CPE access, and
0642:             * generates accordingly the right one.
0643:             * We assume the narrow instruction is what
0644:             * we were given, and that the wide form is
0645:             * the next possible instruction.
0646:             */
0647:            void addInstrCPE(short opcode, int cpeNum) {
0648:                if (cpeNum < 256) {
0649:                    addInstrU1(opcode, cpeNum);
0650:                } else {
0651:                    addInstrU2((short) (opcode + 1), cpeNum);
0652:                }
0653:            }
0654:
0655:            /**
0656:             * This takes an instruction that can be wrapped in
0657:             * a wide for large variable #s and does so.
0658:             */
0659:            void addInstrWide(short opcode, int varNum) {
0660:                if (varNum < 256) {
0661:                    addInstrU1(opcode, varNum);
0662:                } else {
0663:                    addInstr(VMOpcode.WIDE);
0664:                    addInstrU2(opcode, varNum);
0665:                }
0666:            }
0667:
0668:            /**
0669:             * For adding an instruction with 3 operands, a U2 and two U1's.
0670:             * So far, this is used by VMOpcode.INVOKEINTERFACE.
0671:             */
0672:            void addInstrU2U1U1(short opcode, int operand1, short operand2,
0673:                    short operand3) {
0674:                try {
0675:                    cout.putU1(opcode);
0676:                    cout.putU2(operand1);
0677:                    cout.putU1(operand2);
0678:                    cout.putU1(operand3);
0679:                } catch (IOException ioe) {
0680:                    limitHit(ioe);
0681:                }
0682:                if (SanityManager.DEBUG) {
0683:                    if (OPCODE_ACTION[opcode][1] != 5)
0684:                        SanityManager.THROWASSERT("Opcode " + opcode
0685:                                + " incorrect entry in OPCODE_ACTION -"
0686:                                + " writing 5 bytes - set as "
0687:                                + OPCODE_ACTION[opcode][1]);
0688:                }
0689:            }
0690:
0691:            /** Get the current program counter */
0692:            int getPC() {
0693:                return cout.size() + pcDelta;
0694:            }
0695:
0696:            /**
0697:             * Return the complete instruction length for the
0698:             * passed in opcode. This will include the space for
0699:             * the opcode and its operand.
0700:             */
0701:            private static int instructionLength(short opcode) {
0702:                int instructionLength = OPCODE_ACTION[opcode][1];
0703:
0704:                if (SanityManager.DEBUG) {
0705:                    if (instructionLength < 0)
0706:                        SanityManager
0707:                                .THROWASSERT("Opcode without instruction length "
0708:                                        + opcode);
0709:                }
0710:
0711:                return instructionLength;
0712:            }
0713:
0714:            /**
0715:             * The delta between cout.size() and the pc.
0716:             * For an initial code chunk this is -8 (CODE_OFFSET)
0717:             * since 8 bytes are written.
0718:             * For a nested CodeChunk return by insertCodeSpace the delta
0719:             * corresponds to the original starting pc.
0720:             * @see #insertCodeSpace
0721:             */
0722:            private final int pcDelta;
0723:
0724:            /**
0725:             * The class we are generating code for, used to indicate that
0726:             * some limit was hit during code generation.
0727:             */
0728:            final BCClass cb;
0729:
0730:            CodeChunk(BCClass cb) {
0731:                this .cb = cb;
0732:                cout = new ClassFormatOutput();
0733:                try {
0734:                    cout.putU2(0); // max_stack, placeholder for now
0735:                    cout.putU2(0); // max_locals, placeholder for now
0736:                    cout.putU4(0); // code_length, placeholder 4 now
0737:                } catch (IOException ioe) {
0738:                    limitHit(ioe);
0739:                }
0740:                pcDelta = -CodeChunk.CODE_OFFSET;
0741:            }
0742:
0743:            /**
0744:             * Return a CodeChunk that has limited visibility into
0745:             * this CodeChunk. Used when a caller needs to insert instructions
0746:             * into an existing stream.
0747:             * @param pc
0748:             * @param byteCount
0749:             */
0750:            private CodeChunk(CodeChunk main, int pc, int byteCount) {
0751:                this .cb = main.cb;
0752:                ArrayOutputStream aos = new ArrayOutputStream(main.cout
0753:                        .getData());
0754:
0755:                try {
0756:                    aos.setPosition(CODE_OFFSET + pc);
0757:                    aos.setLimit(byteCount);
0758:                } catch (IOException e) {
0759:                    limitHit(e);
0760:                }
0761:
0762:                cout = new ClassFormatOutput(aos);
0763:                pcDelta = pc;
0764:            }
0765:
0766:            private final ClassFormatOutput cout;
0767:
0768:            /**
0769:             * now that we have codeBytes, fix the lengths fields in it
0770:             * to reflect what was stored.
0771:             * Limits checked here are from these sections of the JVM spec.
0772:             * <UL>
0773:             * <LI> 4.7.3 The Code Attribute
0774:             * <LI> 4.10 Limitations of the Java Virtual Machine 
0775:             * </UL>
0776:             */
0777:            private void fixLengths(BCMethod mb, int maxStack, int maxLocals,
0778:                    int codeLength) {
0779:
0780:                byte[] codeBytes = cout.getData();
0781:
0782:                // max_stack is in bytes 0-1
0783:                if (mb != null && maxStack > 65535)
0784:                    cb.addLimitExceeded(mb, "max_stack", 65535, maxStack);
0785:
0786:                codeBytes[0] = (byte) (maxStack >> 8);
0787:                codeBytes[1] = (byte) (maxStack);
0788:
0789:                // max_locals is in bytes 2-3
0790:                if (mb != null && maxLocals > 65535)
0791:                    cb.addLimitExceeded(mb, "max_locals", 65535, maxLocals);
0792:                codeBytes[2] = (byte) (maxLocals >> 8);
0793:                codeBytes[3] = (byte) (maxLocals);
0794:
0795:                // code_length is in bytes 4-7
0796:                if (mb != null && codeLength > VMOpcode.MAX_CODE_LENGTH)
0797:                    cb.addLimitExceeded(mb, "code_length",
0798:                            VMOpcode.MAX_CODE_LENGTH, codeLength);
0799:                codeBytes[4] = (byte) (codeLength >> 24);
0800:                codeBytes[5] = (byte) (codeLength >> 16);
0801:                codeBytes[6] = (byte) (codeLength >> 8);
0802:                codeBytes[7] = (byte) (codeLength);
0803:            }
0804:
0805:            /**
0806:             * wrap up the entry and stuff it in the class,
0807:             * now that it holds all of the instructions and
0808:             * the exception table.
0809:             */
0810:            void complete(BCMethod mb, ClassHolder ch, ClassMember method,
0811:                    int maxStack, int maxLocals) {
0812:
0813:                int codeLength = getPC();
0814:
0815:                ClassFormatOutput out = cout;
0816:
0817:                try {
0818:
0819:                    out.putU2(0); // exception_table_length
0820:
0821:                    if (SanityManager.DEBUG) {
0822:                        if (SanityManager.DEBUG_ON("ClassLineNumbers")) {
0823:                            // Add a single attribute - LineNumberTable
0824:                            // This add fake line numbers that are the pc offset in the method.
0825:                            out.putU2(1); // attributes_count
0826:
0827:                            int cpiUTF = ch.addUtf8("LineNumberTable");
0828:
0829:                            out.putU2(cpiUTF);
0830:                            out.putU4((codeLength * 4) + 2);
0831:                            out.putU2(codeLength);
0832:                            for (int i = 0; i < codeLength; i++) {
0833:                                out.putU2(i);
0834:                                out.putU2(i);
0835:                            }
0836:                        } else {
0837:                            out.putU2(0); // attributes_count
0838:                        }
0839:
0840:                    } else {
0841:                        out.putU2(0); // attributes_count
0842:                        // attributes is empty, a 0-element array.
0843:                    }
0844:                } catch (IOException ioe) {
0845:                    limitHit(ioe);
0846:                }
0847:
0848:                fixLengths(mb, maxStack, maxLocals, codeLength);
0849:                method.addAttribute("Code", out);
0850:
0851:                if (SanityManager.DEBUG) {
0852:                    // Only validate if the class file format is valid.
0853:                    // Ok code length and guaranteed no errors building the class.
0854:                    if ((codeLength <= VMOpcode.MAX_CODE_LENGTH)
0855:                            && (mb != null && mb.cb.limitMsg == null)) {
0856:                        // Validate the alternate way to calculate the
0857:                        // max stack agrees with the dynamic as the code
0858:                        // is built way.
0859:                        int walkedMaxStack = findMaxStack(ch, 0, codeLength);
0860:                        if (walkedMaxStack != maxStack) {
0861:                            SanityManager.THROWASSERT("MAX STACK MISMATCH!! "
0862:                                    + maxStack + " <> " + walkedMaxStack);
0863:                        }
0864:                    }
0865:                }
0866:
0867:            }
0868:
0869:            /**
0870:             * Return the opcode at the given pc.
0871:             */
0872:            short getOpcode(int pc) {
0873:                return (short) (cout.getData()[CODE_OFFSET + pc] & 0xff);
0874:            }
0875:
0876:            /**
0877:             * Get the unsigned short value for the opcode at the program
0878:             * counter pc.
0879:             */
0880:            private int getU2(int pc) {
0881:                byte[] codeBytes = cout.getData();
0882:
0883:                int u2p = CODE_OFFSET + pc + 1;
0884:
0885:                return ((codeBytes[u2p] & 0xff) << 8)
0886:                        | (codeBytes[u2p + 1] & 0xff);
0887:            }
0888:
0889:            /**
0890:             * Get the unsigned 32 bit value for the opcode at the program
0891:             * counter pc.
0892:             */
0893:            private int getU4(int pc) {
0894:                byte[] codeBytes = cout.getData();
0895:
0896:                int u4p = CODE_OFFSET + pc + 1;
0897:
0898:                return (((codeBytes[u4p] & 0xff) << 24)
0899:                        | ((codeBytes[u4p + 1] & 0xff) << 16)
0900:                        | ((codeBytes[u4p + 2] & 0xff) << 8) | ((codeBytes[u4p + 3] & 0xff)));
0901:            }
0902:
0903:            /**
0904:             * Insert room for byteCount bytes after the instruction at pc
0905:             * and prepare to replace the instruction at pc. The instruction
0906:             * at pc is not modified by this call, space is allocated after it.
0907:             * The newly inserted space will be filled with NOP instructions.
0908:             * 
0909:             * Returns a CodeChunk positioned at pc and available to write
0910:             * instructions upto (byteCode + length(existing instruction at pc) bytes.
0911:             * 
0912:             * This chunk is left correctly positioned at the end of the code
0913:             * stream, ready to accept more code. Its pc will have increased by
0914:             * additionalBytes.
0915:             * 
0916:             * It is the responsibility of the caller to patch up any
0917:             * branches or gotos.
0918:             * 
0919:             * @param pc
0920:             * @param additionalBytes
0921:             */
0922:            CodeChunk insertCodeSpace(int pc, int additionalBytes) {
0923:                short existingOpcode = getOpcode(pc);
0924:
0925:                int lengthOfExistingInstruction = instructionLength(existingOpcode);
0926:
0927:                if (additionalBytes > 0) {
0928:                    // Size of the current code after this pc.
0929:                    int sizeToMove = (getPC() - pc)
0930:                            - lengthOfExistingInstruction;
0931:
0932:                    // Increase the code by the number of bytes to be
0933:                    // inserted. These NOPs will be overwritten by the
0934:                    // moved code by the System.arraycopy below.
0935:                    // It's assumed that the number of inserted bytes
0936:                    // is small, one or two instructions worth, so it
0937:                    // won't be a performance issue.
0938:                    for (int i = 0; i < additionalBytes; i++)
0939:                        addInstr(VMOpcode.NOP);
0940:
0941:                    // Must get codeBytes here as the array might have re-sized.
0942:                    byte[] codeBytes = cout.getData();
0943:
0944:                    int byteOffset = CODE_OFFSET + pc
0945:                            + lengthOfExistingInstruction;
0946:
0947:                    // Shift the existing code stream down
0948:                    System.arraycopy(codeBytes, byteOffset, codeBytes,
0949:                            byteOffset + additionalBytes, sizeToMove);
0950:
0951:                    // Place NOPs in the space just freed by the move.
0952:                    // This is not required, it ias assumed the caller
0953:                    // will overwrite all the bytes they requested, but
0954:                    // to be safe fill in with NOPs rather than leaving code
0955:                    // that could break the verifier.
0956:                    Arrays.fill(codeBytes, byteOffset, byteOffset
0957:                            + additionalBytes, (byte) VMOpcode.NOP);
0958:                }
0959:
0960:                // The caller must overwrite the original instruction
0961:                // at pc, thus increase the range of the limit stream
0962:                // created to include those bytes.
0963:                additionalBytes += lengthOfExistingInstruction;
0964:
0965:                // Now the caller needs to fill in the instructions
0966:                // that make up the modified byteCount bytes of bytecode stream.
0967:                // Return a CodeChunk that can be used for this and
0968:                // is limited to only those bytes.
0969:                // The pc of the original code chunk is left unchanged.
0970:
0971:                return new CodeChunk(this , pc, additionalBytes);
0972:
0973:            }
0974:
0975:            /*
0976:             * * Methods related to splitting the byte code chunks into sections that
0977:             * fit in the JVM's limits for a single method.
0978:             */
0979:
0980:            /**
0981:             * For a block of byte code starting at program counter pc for codeLength
0982:             * bytes return the maximum stack value, assuming a initial stack depth of
0983:             * zero.
0984:             */
0985:            private int findMaxStack(ClassHolder ch, int pc, int codeLength) {
0986:
0987:                final int endPc = pc + codeLength;
0988:                int stack = 0;
0989:                int maxStack = 0;
0990:
0991:                for (; pc < endPc;) {
0992:
0993:                    short opcode = getOpcode(pc);
0994:
0995:                    int stackDelta = stackWordDelta(ch, pc, opcode);
0996:
0997:                    stack += stackDelta;
0998:                    if (stack > maxStack)
0999:                        maxStack = stack;
1000:
1001:                    int[] cond_pcs = findConditionalPCs(pc, opcode);
1002:                    if (cond_pcs != null) {
1003:                        // an else block exists.
1004:                        if (cond_pcs[3] != -1) {
1005:                            int blockMaxStack = findMaxStack(ch, cond_pcs[1],
1006:                                    cond_pcs[2]);
1007:                            if ((stack + blockMaxStack) > maxStack)
1008:                                maxStack = stack + blockMaxStack;
1009:
1010:                            pc = cond_pcs[3];
1011:                            continue;
1012:                        }
1013:                    }
1014:
1015:                    pc += instructionLength(opcode);
1016:                }
1017:
1018:                return maxStack;
1019:            }
1020:
1021:            /**
1022:             * Return the number of stack words pushed (positive) or popped (negative)
1023:             * by this instruction.
1024:             */
1025:            private int stackWordDelta(ClassHolder ch, int pc, short opcode) {
1026:                if (SanityManager.DEBUG) {
1027:                    // this validates the OPCODE_ACTION entry
1028:                    instructionLength(opcode);
1029:                }
1030:
1031:                int stackDelta = OPCODE_ACTION[opcode][0];
1032:                if (stackDelta == VARIABLE_STACK) {
1033:                    stackDelta = getVariableStackDelta(ch, pc, opcode);
1034:                }
1035:
1036:                return stackDelta;
1037:            }
1038:
1039:            /**
1040:             * Get the type descriptor in the virtual machine format for the type
1041:             * defined by the constant pool index for the instruction at pc.
1042:             */
1043:            private String getTypeDescriptor(ClassHolder ch, int pc) {
1044:                int cpi = getU2(pc);
1045:
1046:                // Field reference or method reference
1047:                CONSTANT_Index_info cii = (CONSTANT_Index_info) ch
1048:                        .getEntry(cpi);
1049:
1050:                // NameAndType reference
1051:                int nameAndType = cii.getI2();
1052:                cii = (CONSTANT_Index_info) ch.getEntry(nameAndType);
1053:
1054:                // UTF8 descriptor
1055:                int descriptor = cii.getI2();
1056:                CONSTANT_Utf8_info type = (CONSTANT_Utf8_info) ch
1057:                        .getEntry(descriptor);
1058:
1059:                String vmDescriptor = type.toString();
1060:
1061:                return vmDescriptor;
1062:            }
1063:
1064:            /**
1065:             * Get the word count for a type descriptor in the format of the virual
1066:             * machine. For a method this returns the the word count for the return
1067:             * type.
1068:             */
1069:            private static int getDescriptorWordCount(String vmDescriptor) {
1070:
1071:                int width;
1072:                if (VMDescriptor.DOUBLE.equals(vmDescriptor))
1073:                    width = 2;
1074:                else if (VMDescriptor.LONG.equals(vmDescriptor))
1075:                    width = 2;
1076:                else if (vmDescriptor.charAt(0) == VMDescriptor.C_METHOD) {
1077:                    switch (vmDescriptor.charAt(vmDescriptor.length() - 1)) {
1078:                    case VMDescriptor.C_DOUBLE:
1079:                    case VMDescriptor.C_LONG:
1080:                        width = 2;
1081:                        break;
1082:                    case VMDescriptor.C_VOID:
1083:                        width = 0;
1084:                        break;
1085:                    default:
1086:                        width = 1;
1087:                        break;
1088:                    }
1089:                } else
1090:                    width = 1;
1091:
1092:                return width;
1093:            }
1094:
1095:            /**
1096:             * Get the number of words pushed (positive) or popped (negative) by this
1097:             * instruction. The instruction is a get/put field or a method call, thus
1098:             * the size of the words is defined by the field or method being access.
1099:             */
1100:            private int getVariableStackDelta(ClassHolder ch, int pc, int opcode) {
1101:                String vmDescriptor = getTypeDescriptor(ch, pc);
1102:                int width = CodeChunk.getDescriptorWordCount(vmDescriptor);
1103:
1104:                int stackDelta = 0;
1105:                // Stack delta depends on context.
1106:                switch (opcode) {
1107:                case VMOpcode.GETSTATIC:
1108:                    stackDelta = width;
1109:                    break;
1110:
1111:                case VMOpcode.GETFIELD:
1112:                    stackDelta = width - 1; // one for popped object ref
1113:                    break;
1114:
1115:                case VMOpcode.PUTSTATIC:
1116:                    stackDelta = -width;
1117:                    break;
1118:
1119:                case VMOpcode.PUTFIELD:
1120:                    stackDelta = -width - 1; // one for pop object ref
1121:                    break;
1122:
1123:                case VMOpcode.INVOKEVIRTUAL:
1124:                case VMOpcode.INVOKESPECIAL:
1125:                    stackDelta = -1; // for instance reference for method call.
1126:                case VMOpcode.INVOKESTATIC:
1127:                    stackDelta += (width - CodeChunk
1128:                            .parameterWordCount(vmDescriptor));
1129:                    // System.out.println("invoked non-interface " + stackDelta);
1130:                    break;
1131:
1132:                case VMOpcode.INVOKEINTERFACE:
1133:                    // third byte contains the number of arguments to be popped
1134:                    stackDelta = width - getOpcode(pc + 3);
1135:                    // System.out.println("invoked interface " + stackDelta);
1136:                    break;
1137:                default:
1138:                    System.out.println("WHO IS THIS ");
1139:                    break;
1140:
1141:                }
1142:
1143:                return stackDelta;
1144:            }
1145:
1146:            /**
1147:             * Calculate the number of stack words in the arguments pushed for this
1148:             * method descriptor.
1149:             */
1150:            private static int parameterWordCount(String methodDescriptor) {
1151:                int wordCount = 0;
1152:                for (int i = 1;; i++) {
1153:                    switch (methodDescriptor.charAt(i)) {
1154:                    case VMDescriptor.C_ENDMETHOD:
1155:                        return wordCount;
1156:                    case VMDescriptor.C_DOUBLE:
1157:                    case VMDescriptor.C_LONG:
1158:                        wordCount += 2;
1159:                        break;
1160:                    case VMDescriptor.C_ARRAY:
1161:                        // skip while there are array symbols.
1162:                        do {
1163:                            i++;
1164:                        } while (methodDescriptor.charAt(i) == VMDescriptor.C_ARRAY);
1165:                        if (methodDescriptor.charAt(i) != VMDescriptor.C_CLASS) {
1166:                            // an array is a reference, even an array of doubles.
1167:                            wordCount += 1;
1168:                            break;
1169:                        }
1170:
1171:                        // fall through to skip the Lclassname; after the array.
1172:
1173:                    case VMDescriptor.C_CLASS:
1174:                        // skip until ;
1175:                        do {
1176:                            i++;
1177:                        } while (methodDescriptor.charAt(i) != VMDescriptor.C_ENDCLASS);
1178:                        wordCount += 1;
1179:                        break;
1180:                    default:
1181:                        wordCount += 1;
1182:                        break;
1183:                    }
1184:                }
1185:            }
1186:
1187:            /**
1188:             * Find the limits of a conditional block starting at the instruction with
1189:             * the given opcode at the program counter pc.
1190:             * <P>
1191:             * Returns a six element integer array of program counters and lengths.
1192:             * <code. [0] - program counter of the IF opcode (passed in as pc) [1] -
1193:             * program counter of the start of the then block [2] - length of the then
1194:             * block [3] - program counter of the else block, -1 if no else block
1195:             * exists. [4] - length of of the else block, -1 if no else block exists.
1196:             * [5] - program counter of the common end point. </code>
1197:             * 
1198:             * Looks for and handles conditionals that are written by the Conditional
1199:             * class.
1200:             * 
1201:             * @return Null if the opcode is not the start of a conditional otherwise
1202:             *         the array of values.
1203:             */
1204:            private int[] findConditionalPCs(int pc, short opcode) {
1205:                switch (opcode) {
1206:                default:
1207:                    return null;
1208:                case VMOpcode.IFNONNULL:
1209:                case VMOpcode.IFNULL:
1210:                case VMOpcode.IFEQ:
1211:                case VMOpcode.IFNE:
1212:                    break;
1213:                }
1214:
1215:                int then_pc;
1216:                int else_pc;
1217:                int if_off = getU2(pc);
1218:
1219:                if ((if_off == 8)
1220:                        && (getOpcode(pc + VMOpcode.IF_INS_LENGTH) == VMOpcode.GOTO_W)) {
1221:                    // 32 bit branch
1222:                    then_pc = pc + VMOpcode.IF_INS_LENGTH
1223:                            + VMOpcode.GOTO_W_INS_LENGTH;
1224:
1225:                    // Get else PC from the 32 bit offset within the GOTO_W
1226:                    // instruction remembering to add it to the pc of that
1227:                    // instruction, not the original IF.
1228:                    else_pc = pc + VMOpcode.IF_INS_LENGTH
1229:                            + getU4(pc + VMOpcode.IF_INS_LENGTH);
1230:
1231:                } else {
1232:                    then_pc = pc + VMOpcode.IF_INS_LENGTH;
1233:                    else_pc = pc + if_off;
1234:                }
1235:
1236:                // Need to look for the goto or goto_w at the
1237:                // end of the then block. There might not be
1238:                // one for the case when there is no else block.
1239:                // In that case the then block will just run into
1240:                // what we currently think the else pc.
1241:
1242:                int end_pc = -1;
1243:                for (int tpc = then_pc; tpc < else_pc;) {
1244:                    short opc = getOpcode(tpc);
1245:
1246:                    // need to handle conditionals
1247:                    int[] innerCond = findConditionalPCs(tpc, opc);
1248:                    if (innerCond != null) {
1249:                        // skip to the end of this conditional
1250:                        tpc = innerCond[5]; // end_pc
1251:                        continue;
1252:                    }
1253:
1254:                    if (opc == VMOpcode.GOTO) {
1255:                        // not at the end of the then block
1256:                        // so not our goto. Shouldn't see this
1257:                        // with the current code due to the
1258:                        // skipping of the conditional above.
1259:                        // But safe defensive programming.
1260:                        if (tpc != (else_pc - VMOpcode.GOTO_INS_LENGTH))
1261:                            continue;
1262:
1263:                        end_pc = tpc + getU2(tpc);
1264:                        break;
1265:                    } else if (opc == VMOpcode.GOTO_W) {
1266:                        // not at the end of the then block
1267:                        // so not our goto. SHouldn't see this
1268:                        // with the current code due to the
1269:                        // skipping of the conditional above.
1270:                        // But safe defensive programming.
1271:                        if (tpc != (else_pc - VMOpcode.GOTO_W_INS_LENGTH))
1272:                            continue;
1273:
1274:                        end_pc = tpc + getU4(tpc);
1275:                        break;
1276:
1277:                    }
1278:                    tpc += instructionLength(opc);
1279:                }
1280:
1281:                int else_len;
1282:                int then_len;
1283:                if (end_pc == -1) {
1284:                    // no else block;
1285:                    end_pc = else_pc;
1286:                    else_pc = -1;
1287:
1288:                    then_len = end_pc - then_pc;
1289:                    else_len = -1;
1290:                } else {
1291:                    then_len = else_pc - then_pc;
1292:                    else_len = end_pc - else_pc;
1293:                }
1294:
1295:                int[] ret = new int[6];
1296:
1297:                ret[0] = pc;
1298:                ret[1] = then_pc;
1299:                ret[2] = then_len;
1300:                ret[3] = else_pc;
1301:                ret[4] = else_len;
1302:                ret[5] = end_pc;
1303:
1304:                return ret;
1305:            }
1306:
1307:            /**
1308:             * Attempt to split the current method by pushing a chunk of
1309:             * its code into a sub-method. The starting point of the split
1310:             * (split_pc) must correspond to a stack depth of zero. It is the
1311:             * reponsibility of the caller to ensure this.
1312:             * Split is only made if there exists a chunk of code starting at
1313:             * pc=split_pc, whose stack depth upon termination is zero.
1314:             * The method will try to split a code section greater than
1315:             * optimalMinLength but may split earlier if no such block exists.
1316:             * <P>
1317:             * The method is aimed at splitting methods that contain
1318:             * many independent statements.
1319:             * <P>
1320:             * If a split is possible this method will perform the split and
1321:             * create a void sub method, and move the code into the sub-method
1322:             * and setup this method to call the sub-method before continuing.
1323:             * This method's max stack and current pc will be correctly set
1324:             * as though the method had just been created.
1325:             * 
1326:             * @param mb Method for this chunk.
1327:             * @param ch Class definition
1328:             * @param optimalMinLength minimum length required for split
1329:             */
1330:            final int splitZeroStack(BCMethod mb, ClassHolder ch,
1331:                    final int split_pc, final int optimalMinLength) {
1332:
1333:                int splitMinLength = splitMinLength(mb);
1334:
1335:                int stack = 0;
1336:
1337:                // maximum possible split seen that is less than
1338:                // the minimum.
1339:                int possibleSplitLength = -1;
1340:
1341:                // do not split until at least this point (inclusive)
1342:                // used to ensure no split occurs in the middle of
1343:                // a conditional.
1344:                int outerConditionalEnd_pc = -1;
1345:
1346:                int end_pc = getPC(); // pc will be positioned at the end.
1347:                for (int pc = split_pc; pc < end_pc;) {
1348:
1349:                    short opcode = getOpcode(pc);
1350:
1351:                    int stackDelta = stackWordDelta(ch, pc, opcode);
1352:
1353:                    stack += stackDelta;
1354:
1355:                    // Cannot split a conditional but need to calculate
1356:                    // the stack depth at the end of the conditional.
1357:                    // Each path through the conditional will have the
1358:                    // same stack depth.
1359:                    int[] cond_pcs = findConditionalPCs(pc, opcode);
1360:                    if (cond_pcs != null) {
1361:                        // an else block exists, skip the then block.
1362:                        if (cond_pcs[3] != -1) {
1363:                            pc = cond_pcs[3];
1364:                            continue;
1365:                        }
1366:
1367:                        if (SanityManager.DEBUG) {
1368:                            if (outerConditionalEnd_pc != -1) {
1369:                                if (cond_pcs[5] >= outerConditionalEnd_pc)
1370:                                    SanityManager
1371:                                            .THROWASSERT("NESTED CONDITIONALS!");
1372:                            }
1373:                        }
1374:
1375:                        if (outerConditionalEnd_pc == -1) {
1376:                            outerConditionalEnd_pc = cond_pcs[5];
1377:                        }
1378:                    }
1379:
1380:                    pc += instructionLength(opcode);
1381:
1382:                    // Don't split in the middle of a conditional
1383:                    if (outerConditionalEnd_pc != -1) {
1384:                        if (pc > outerConditionalEnd_pc) {
1385:                            // passed the outermost conditional
1386:                            outerConditionalEnd_pc = -1;
1387:                        }
1388:                        continue;
1389:                    }
1390:
1391:                    if (stack != 0)
1392:                        continue;
1393:
1394:                    int splitLength = pc - split_pc;
1395:
1396:                    if (splitLength < optimalMinLength) {
1397:                        // record we do have a possible split.
1398:                        possibleSplitLength = splitLength;
1399:                        continue;
1400:                    }
1401:
1402:                    // no point splitting to a method bigger
1403:                    // than the VM can handle. Save one for
1404:                    // return instruction.
1405:                    if (splitLength > BCMethod.CODE_SPLIT_LENGTH - 1) {
1406:                        splitLength = -1;
1407:                    } else if (CodeChunk.isReturn(opcode)) {
1408:                        // Don't handle a return in the middle of
1409:                        // an instruction stream. Don't think this
1410:                        // is generated, but be safe.           
1411:                        splitLength = -1;
1412:                    }
1413:
1414:                    // if splitLenth was set to -1 above then there
1415:                    // is no possible split at this instruction.
1416:                    if (splitLength == -1) {
1417:                        // no earlier split at all
1418:                        if (possibleSplitLength == -1)
1419:                            return -1;
1420:
1421:                        // Decide if the earlier possible split is
1422:                        // worth it.
1423:                        if (possibleSplitLength <= splitMinLength)
1424:                            return -1;
1425:
1426:                        // OK go with the earlier split
1427:                        splitLength = possibleSplitLength;
1428:
1429:                    }
1430:
1431:                    // Yes, we can split this big method into a smaller method!!
1432:
1433:                    BCMethod subMethod = startSubMethod(mb, "void", split_pc,
1434:                            splitLength);
1435:
1436:                    return splitCodeIntoSubMethod(mb, ch, subMethod, split_pc,
1437:                            splitLength);
1438:                }
1439:                return -1;
1440:            }
1441:
1442:            /**
1443:             * Start a sub method that we will split the portion of our current code to,
1444:             * starting from start_pc and including codeLength bytes of code.
1445:             * 
1446:             * Return a BCMethod obtained from BCMethod.getNewSubMethod with the passed
1447:             * in return type and same parameters as mb if the code block to be moved
1448:             * uses parameters.
1449:             */
1450:            private BCMethod startSubMethod(BCMethod mb, String returnType,
1451:                    int split_pc, int blockLength) {
1452:
1453:                boolean needParameters = usesParameters(mb, split_pc,
1454:                        blockLength);
1455:
1456:                return mb.getNewSubMethod(returnType, needParameters);
1457:            }
1458:
1459:            /**
1460:             * Does a section of code use parameters.
1461:             * Any load, exception ALOAD_0 in an instance method, is
1462:             * seen as using parameters, as this complete byte code
1463:             * implementation does not use local variables.
1464:             * 
1465:             */
1466:            private boolean usesParameters(BCMethod mb, int pc, int codeLength) {
1467:
1468:                // does the method even have parameters?
1469:                if (mb.parameters == null)
1470:                    return false;
1471:
1472:                boolean isStatic = (mb.myEntry.getModifier() & Modifier.STATIC) != 0;
1473:
1474:                int endPc = pc + codeLength;
1475:
1476:                for (; pc < endPc;) {
1477:                    short opcode = getOpcode(pc);
1478:                    switch (opcode) {
1479:                    case VMOpcode.ILOAD_0:
1480:                    case VMOpcode.LLOAD_0:
1481:                    case VMOpcode.FLOAD_0:
1482:                    case VMOpcode.DLOAD_0:
1483:                        return true;
1484:
1485:                    case VMOpcode.ALOAD_0:
1486:                        if (isStatic)
1487:                            return true;
1488:                        break;
1489:
1490:                    case VMOpcode.ILOAD_1:
1491:                    case VMOpcode.LLOAD_1:
1492:                    case VMOpcode.FLOAD_1:
1493:                    case VMOpcode.DLOAD_1:
1494:                    case VMOpcode.ALOAD_1:
1495:                        return true;
1496:
1497:                    case VMOpcode.ILOAD_2:
1498:                    case VMOpcode.LLOAD_2:
1499:                    case VMOpcode.FLOAD_2:
1500:                    case VMOpcode.DLOAD_2:
1501:                    case VMOpcode.ALOAD_2:
1502:                        return true;
1503:
1504:                    case VMOpcode.ILOAD_3:
1505:                    case VMOpcode.LLOAD_3:
1506:                    case VMOpcode.FLOAD_3:
1507:                    case VMOpcode.DLOAD_3:
1508:                    case VMOpcode.ALOAD_3:
1509:                        return true;
1510:
1511:                    case VMOpcode.ILOAD:
1512:                    case VMOpcode.LLOAD:
1513:                    case VMOpcode.FLOAD:
1514:                    case VMOpcode.DLOAD:
1515:                    case VMOpcode.ALOAD:
1516:                        return true;
1517:                    default:
1518:                        break;
1519:
1520:                    }
1521:                    pc += instructionLength(opcode);
1522:                }
1523:                return false;
1524:            }
1525:
1526:            /**
1527:             * Split a block of code from this method into a sub-method
1528:             * and call it.
1529:             * 
1530:             * Returns the pc of this method just after the call
1531:             * to the sub-method.
1532:             
1533:             * @param mb My method
1534:             * @param ch My class
1535:             * @param subMethod Sub-method code was pushed into
1536:             * @param split_pc Program counter the split started at
1537:             * @param splitLength Length of code split
1538:             */
1539:            private int splitCodeIntoSubMethod(BCMethod mb, ClassHolder ch,
1540:                    BCMethod subMethod, final int split_pc,
1541:                    final int splitLength) {
1542:                CodeChunk subChunk = subMethod.myCode;
1543:
1544:                byte[] codeBytes = cout.getData();
1545:
1546:                // the code to be moved into the sub method
1547:                // as a block. This will correctly increase the
1548:                // program counter.
1549:                try {
1550:                    subChunk.cout.write(codeBytes, CODE_OFFSET + split_pc,
1551:                            splitLength);
1552:                } catch (IOException ioe) {
1553:                    limitHit(ioe);
1554:                }
1555:
1556:                // Just cause the sub-method to return,
1557:                // fix up its maxStack and then complete it.
1558:                if (subMethod.myReturnType.equals("void"))
1559:                    subChunk.addInstr(VMOpcode.RETURN);
1560:                else
1561:                    subChunk.addInstr(VMOpcode.ARETURN);
1562:
1563:                // Finding the max stack requires the class format to
1564:                // still be valid. If we have blown the number of constant
1565:                // pool entries then we can no longer guarantee that indexes
1566:                // into the constant pool in the code stream are valid.
1567:                if (cb.limitMsg != null)
1568:                    return -1;
1569:
1570:                subMethod.maxStack = subChunk.findMaxStack(ch, 0, subChunk
1571:                        .getPC());
1572:                subMethod.complete();
1573:
1574:                return removePushedCode(mb, ch, subMethod, split_pc,
1575:                        splitLength);
1576:            }
1577:
1578:            /**
1579:             * Remove a block of code from this method that was pushed into a sub-method
1580:             * and call the sub-method.
1581:             * 
1582:             * Returns the pc of this method just after the call to the sub-method.
1583:             * 
1584:             * @param mb
1585:             *            My method
1586:             * @param ch
1587:             *            My class
1588:             * @param subMethod
1589:             *            Sub-method code was pushed into
1590:             * @param split_pc
1591:             *            Program counter the split started at
1592:             * @param splitLength
1593:             *            Length of code split
1594:             */
1595:            private int removePushedCode(BCMethod mb, ClassHolder ch,
1596:                    BCMethod subMethod, final int split_pc,
1597:                    final int splitLength) {
1598:                // now need to fix up this method, create
1599:                // a new CodeChunk just to be clearer than
1600:                // trying to modify this chunk directly.
1601:
1602:                // total length of the code for this method before split
1603:                final int codeLength = getPC();
1604:
1605:                CodeChunk replaceChunk = new CodeChunk(mb.cb);
1606:                mb.myCode = replaceChunk;
1607:                mb.maxStack = 0;
1608:
1609:                byte[] codeBytes = cout.getData();
1610:
1611:                // write any existing code before the split point
1612:                // into the replacement chunk.
1613:                if (split_pc != 0) {
1614:                    try {
1615:                        replaceChunk.cout.write(codeBytes, CODE_OFFSET,
1616:                                split_pc);
1617:                    } catch (IOException ioe) {
1618:                        limitHit(ioe);
1619:                    }
1620:                }
1621:
1622:                // Call the sub method, will write into replaceChunk.
1623:                mb.callSubMethod(subMethod);
1624:
1625:                int postSplit_pc = replaceChunk.getPC();
1626:
1627:                // Write the code remaining in this method into the replacement chunk
1628:
1629:                int remainingCodePC = split_pc + splitLength;
1630:                int remainingCodeLength = codeLength - splitLength - split_pc;
1631:
1632:                try {
1633:                    replaceChunk.cout.write(codeBytes, CODE_OFFSET
1634:                            + remainingCodePC, remainingCodeLength);
1635:                } catch (IOException ioe) {
1636:                    limitHit(ioe);
1637:                }
1638:
1639:                // Finding the max stack requires the class format to
1640:                // still be valid. If we have blown the number of constant
1641:                // pool entries then we can no longer guarantee that indexes
1642:                // into the constant pool in the code stream are valid.
1643:                if (cb.limitMsg != null)
1644:                    return -1;
1645:
1646:                mb.maxStack = replaceChunk.findMaxStack(ch, 0, replaceChunk
1647:                        .getPC());
1648:
1649:                return postSplit_pc;
1650:            }
1651:
1652:            /**
1653:             * Split an expression out of a large method into its own
1654:             * sub-method.
1655:             * <P>
1656:             * Method call expressions are of the form:
1657:             * <UL>
1658:             * <LI> expr.method(args) -- instance method call
1659:             * <LI> method(args) -- static method call
1660:             * </UL>
1661:             * Two special cases of instance method calls will be handled
1662:             * by the first incarnation of splitExpressionOut. 
1663:             * three categories:
1664:             * <UL>
1665:             * <LI>this.method(args)
1666:             * <LI>this.getter().method(args)
1667:             * </UL>
1668:             * These calls are choosen as they are easier sub-cases
1669:             * and map to the code generated for SQL statements.
1670:             * Future coders can expand the method to cover more cases.
1671:             * <P>
1672:             * This method will split out such expressions in sub-methods
1673:             * and replace the original code with a call to that submethod.
1674:             * <UL>
1675:             * <LI>this.method(args) ->> this.sub1([parameters])
1676:             * <LI>this.getter().method(args) ->> this.sub1([parameters])
1677:             * </UL>
1678:             * The assumption is of course that the call to the sub-method
1679:             * is much smaller than the code it replaces.
1680:             * <P>
1681:             * Looking at the byte code for such calls they would look like
1682:             * (for an example three argument method):
1683:             * <code>
1684:             * this arg1 arg2 arg3 INVOKE // this.method(args)
1685:             * this INVOKE arg1 arg2 arg3 INVOKE // this.getter().metod(args)
1686:             * </code>
1687:             * The bytecode for the arguments can be arbitary long and
1688:             * consist of expressions, typical Derby code for generated
1689:             * queries is deeply nested method calls.
1690:             * <BR>
1691:             * If none of the arguments requred the parameters passed into
1692:             * the method, then in both cases the replacement bytecode
1693:             * would look like:
1694:             * <code>
1695:             * this.sub1();
1696:             * </code>
1697:             * Parameter handling is just as in the method splitZeroStack().
1698:             * <P>
1699:             * Because the VM is a stack machine the original byte code
1700:             * sequences are self contained. The stack at the start of
1701:             * is sequence is N and at the end (after the method call) will
1702:             * be:
1703:             * <UL>
1704:             * <LI> N - void method
1705:             * <LI> N + 1 - method returning a single word
1706:             * <LI> N + 2 - method returning a double word (java long or double)
1707:             * </UL>
1708:             * This code will handle the N+1 where the word is a reference,
1709:             * the typical case for generated code.
1710:             * <BR>
1711:             * The code is self contained because in general the byte code
1712:             * for the arguments will push and pop values but never drop
1713:             * below the stack value at the start of the byte code sequence.
1714:             * E.g. in the examples the stack before the first arg will be
1715:             * N+1 (the objectref for the method call) and at the end of the
1716:             * byte code for arg1 will be N+2 or N+3 depending on if arg1 is
1717:             * a single or double word argument. During the execution of
1718:             * the byte code the stack may have had many arguments pushed
1719:             * and popped, but will never have dropped below N+1. Thus the
1720:             * code for arg1 is independent of the stack's previous values
1721:             * and is self contained. This self-containment then extends to
1722:             * all the arguements, the method call itself and pushing the
1723:             * objectref for the method call, thus the complete
1724:             * sequence is self-contained.
1725:             * <BR>
1726:             * The self-containment breaks in a few cases, take the simple
1727:             * method call this.method(3), the byte code for this could be:
1728:             * <code>
1729:             * push3 this swap invoke
1730:             * </code>
1731:             * In this case the byte code for arg1 (swap) is not self-contained
1732:             * and relies on earlier stack values.
1733:             * <P>
1734:             * How to identify "self-contained blocks of code".
1735:             * <BR>
1736:             * We walk through the byte code and maintain a history of
1737:             * the program counter that indicates the start of the
1738:             * independent sequence each stack word depends on.
1739:             * Thus for a ALOAD_0 instruction which pushes 'this' the
1740:             * dependent pc is that of the this. If a DUP instruction followed
1741:             * then the top-word is now dependent on the previous word (this)
1742:             * and thus the dependence of it is equal to the dependence of
1743:             * the previous word. This information is kept in earliestIndepPC
1744:             * array as we process the instruction stream.
1745:             * <BR>
1746:             * When a INVOKE instruction is seen for an instance method
1747:             * that returns a single or double word, the dependence of
1748:             * the returned value is the dependence of the word in the
1749:             * stack that is the objectref for the call. This complete
1750:             * sequence from the pc the objectref depended on to the
1751:             * INVOKE instruction is then a self contained sequence
1752:             * and can be split into a sub-method.
1753:
1754:             * <BR>
1755:             * If the block is self-contained then it can be split, following
1756:             * similar logic to splitZeroStack().
1757:             *  
1758:             *  <P>
1759:             *  WORK IN PROGRESS - Incremental development
1760:             *  <BR>
1761:             *  Currently walks the method maintaining the
1762:             *  earliestIndepPC array and identifies potential blocks
1763:             *  to splt, performs splits as required.
1764:             *  Called by BCMethod but commented out in submitted code.
1765:             *  Tested with local changes from calls in BCMethod.
1766:             *  Splits generally work, though largeCodeGen shows
1767:             *  a problem that will be fixed before the code in
1768:             *  enabled for real.
1769:             *  
1770:             */
1771:
1772:            final int splitExpressionOut(final BCMethod mb,
1773:                    final ClassHolder ch, final int optimalMinLength,
1774:                    final int maxStack) {
1775:                // Save the best block we have seen for splitting out.
1776:                int bestSplitPC = -1;
1777:                int bestSplitBlockLength = -1;
1778:                String bestSplitRT = null;
1779:
1780:                int splitMinLength = splitMinLength(mb);
1781:
1782:                // Program counter of the earliest instruction
1783:                // that the word in the current active stack
1784:                // at the given depth depends on.
1785:                //
1786:                // Some examples, N is the stack depth *after*
1787:                // the instruction.
1788:                // E.g. 
1789:                // ALOAD_0 - pushes this, is an instruction that
1790:                // pushes an independent value, so the current
1791:                // stack word depends on the pc of current instruction.
1792:                // earliestIndepPC[N] = pc (that pushed the value).
1793:                //
1794:                // DUP - duplicates the top word, so the duplicated
1795:                // top word will depend on the same pc as the word
1796:                // it was duplicated from.
1797:                // I.e. earliestIndepPC[N]
1798:                //            = earliestIndepPC[N-1];
1799:                //
1800:                // instance method call returning single word value.
1801:                // The top word will depend on the same pc as the
1802:                // objectref for the method call, which was at the
1803:                // same depth in this case.
1804:                // earliestIndepPC[N] unchanged
1805:                //
1806:                // at any time earliestIndepPC is only valid
1807:                // from 1 to N where N is the depth of the stack.
1808:                int[] earliestIndepPC = new int[maxStack + 1];
1809:
1810:                int stack = 0;
1811:
1812:                //TODO: this conditional handling is copied from
1813:                //the splitZeroStack code, need to check to see
1814:                // how it fits with the expression logic.
1815:                // do not split until at least this point (inclusive)
1816:                // used to ensure no split occurs in the middle of
1817:                // a conditional.
1818:                int outerConditionalEnd_pc = -1;
1819:
1820:                int end_pc = getPC();
1821:
1822:                for (int pc = 0; pc < end_pc;) {
1823:
1824:                    short opcode = getOpcode(pc);
1825:
1826:                    int stackDelta = stackWordDelta(ch, pc, opcode);
1827:
1828:                    stack += stackDelta;
1829:
1830:                    // Cannot split a conditional but need to calculate
1831:                    // the stack depth at the end of the conditional.
1832:                    // Each path through the conditional will have the
1833:                    // same stack depth.
1834:                    int[] cond_pcs = findConditionalPCs(pc, opcode);
1835:                    if (cond_pcs != null) {
1836:
1837:                        // TODO: This conditional handling was copied
1838:                        // from splitZeroStack, haven't looked in detail
1839:                        // to see how a conditional should be handled
1840:                        // with an expression split. So for the time
1841:                        // being just bail.
1842:                        if (true)
1843:                            return -1;
1844:
1845:                        // an else block exists, skip the then block.
1846:                        if (cond_pcs[3] != -1) {
1847:                            pc = cond_pcs[3];
1848:                            continue;
1849:                        }
1850:
1851:                        if (SanityManager.DEBUG) {
1852:                            if (outerConditionalEnd_pc != -1) {
1853:                                if (cond_pcs[5] >= outerConditionalEnd_pc)
1854:                                    SanityManager
1855:                                            .THROWASSERT("NESTED CONDITIONALS!");
1856:                            }
1857:                        }
1858:
1859:                        if (outerConditionalEnd_pc == -1) {
1860:                            outerConditionalEnd_pc = cond_pcs[5];
1861:                        }
1862:                    }
1863:
1864:                    pc += instructionLength(opcode);
1865:
1866:                    // Don't split in the middle of a conditional
1867:                    if (outerConditionalEnd_pc != -1) {
1868:                        if (pc > outerConditionalEnd_pc) {
1869:                            // passed the outermost conditional
1870:                            outerConditionalEnd_pc = -1;
1871:                        }
1872:                        continue;
1873:                    }
1874:
1875:                    int opcode_pc = pc - instructionLength(opcode);
1876:                    switch (opcode) {
1877:                    // Any instruction we don't have any information
1878:                    // on, we simply clear all evidence of independent
1879:                    // starting points, and start again.
1880:                    default:
1881:                        Arrays.fill(earliestIndepPC, 0, stack + 1, -1);
1882:                        break;
1883:
1884:                    // Independent instructions do not change the stack depth
1885:                    // and the independence of the top word picks up
1886:                    // the independence of the previous word at the same
1887:                    // position. Ie. no change!
1888:                    case VMOpcode.ARRAYLENGTH:
1889:                    case VMOpcode.NOP:
1890:                    case VMOpcode.CHECKCAST:
1891:                    case VMOpcode.D2L:
1892:                    case VMOpcode.DNEG:
1893:                    case VMOpcode.F2I:
1894:                        break;
1895:
1896:                    // Independent instructions that push one word
1897:                    case VMOpcode.ALOAD_0:
1898:                    case VMOpcode.ALOAD_1:
1899:                    case VMOpcode.ALOAD_2:
1900:                    case VMOpcode.ALOAD_3:
1901:                    case VMOpcode.ALOAD:
1902:                    case VMOpcode.ACONST_NULL:
1903:                    case VMOpcode.BIPUSH:
1904:                    case VMOpcode.FCONST_0:
1905:                    case VMOpcode.FCONST_1:
1906:                    case VMOpcode.FCONST_2:
1907:                    case VMOpcode.FLOAD:
1908:                    case VMOpcode.ICONST_0:
1909:                    case VMOpcode.ICONST_1:
1910:                    case VMOpcode.ICONST_2:
1911:                    case VMOpcode.ICONST_3:
1912:                    case VMOpcode.ICONST_4:
1913:                    case VMOpcode.ICONST_5:
1914:                    case VMOpcode.ICONST_M1:
1915:                    case VMOpcode.LDC:
1916:                    case VMOpcode.LDC_W:
1917:                    case VMOpcode.SIPUSH:
1918:                        earliestIndepPC[stack] = opcode_pc;
1919:                        break;
1920:
1921:                    // Independent instructions that push two words
1922:                    case VMOpcode.DCONST_0:
1923:                    case VMOpcode.DCONST_1:
1924:                    case VMOpcode.LCONST_0:
1925:                    case VMOpcode.LCONST_1:
1926:                    case VMOpcode.LDC2_W:
1927:                    case VMOpcode.LLOAD:
1928:                    case VMOpcode.LLOAD_0:
1929:                    case VMOpcode.LLOAD_1:
1930:                    case VMOpcode.LLOAD_2:
1931:                    case VMOpcode.LLOAD_3:
1932:                        earliestIndepPC[stack - 1] = earliestIndepPC[stack] = opcode_pc;
1933:                        break;
1934:
1935:                    // nothing to do for pop, obviously no
1936:                    // code will be dependent on the popped words.
1937:                    case VMOpcode.POP:
1938:                    case VMOpcode.POP2:
1939:                        break;
1940:
1941:                    case VMOpcode.SWAP:
1942:                        earliestIndepPC[stack] = earliestIndepPC[stack - 1];
1943:                        break;
1944:
1945:                    // push a value that depends on the previous value
1946:                    case VMOpcode.I2L:
1947:                        earliestIndepPC[stack] = earliestIndepPC[stack - 1];
1948:                        break;
1949:
1950:                    case VMOpcode.GETFIELD: {
1951:                        String vmDescriptor = getTypeDescriptor(ch, opcode_pc);
1952:                        int width = CodeChunk
1953:                                .getDescriptorWordCount(vmDescriptor);
1954:                        if (width == 2)
1955:                            earliestIndepPC[stack] = earliestIndepPC[stack - 1];
1956:
1957:                        break;
1958:                    }
1959:
1960:                    case VMOpcode.INVOKEINTERFACE:
1961:                    case VMOpcode.INVOKEVIRTUAL: {
1962:                        //   ...,objectref[,word]*
1963:                        //   
1964:                        // => ...
1965:                        // => ...,word
1966:                        // => ...,word1,word2
1967:
1968:                        // Width of the value returned by the method call.
1969:                        String vmDescriptor = getTypeDescriptor(ch, opcode_pc);
1970:                        int width = CodeChunk
1971:                                .getDescriptorWordCount(vmDescriptor);
1972:
1973:                        // Independence of this block is the independence
1974:                        // of the objectref that invokved the method.
1975:                        int selfContainedBlockStart;
1976:                        if (width == 0) {
1977:                            // objectref was at one more than the current depth
1978:                            // no plan to split here though, as we are only
1979:                            // splitting methods that return a reference.
1980:                            selfContainedBlockStart = -1;
1981:                            // earliestIndepPC[stack + 1];
1982:                        } else if (width == 1) {
1983:                            // stack is unchanged, objectref was at
1984:                            // the current stack depth
1985:                            selfContainedBlockStart = earliestIndepPC[stack];
1986:                        } else {
1987:                            // width == 2, objectref was one below the
1988:                            // current stack depth.
1989:                            // no plan to split here though, as we are only
1990:                            // splitting methods that return a reference.
1991:                            selfContainedBlockStart = -1;
1992:
1993:                            // top two words depend on the objectref
1994:                            // which was at the same depth of the first word
1995:                            // of the 64 bit value.
1996:                            earliestIndepPC[stack] = earliestIndepPC[stack - 1];
1997:                        }
1998:
1999:                        if (selfContainedBlockStart != -1) {
2000:                            int blockLength = pc - selfContainedBlockStart;
2001:
2002:                            if (blockLength <= splitMinLength) {
2003:                                // No point splitting, too small
2004:                            } else if (blockLength > (VMOpcode.MAX_CODE_LENGTH - 1)) {
2005:                                // too big to split into a single method
2006:                                // (one for the return opcode)
2007:                            } else {
2008:                                // Only split for a method that returns
2009:                                // an class reference.
2010:                                int me = vmDescriptor.lastIndexOf(')');
2011:
2012:                                if (vmDescriptor.charAt(me + 1) == 'L') {
2013:                                    String rt = vmDescriptor.substring(me + 2,
2014:                                            vmDescriptor.length() - 1);
2015:
2016:                                    // convert to external format.
2017:                                    rt = rt.replace('/', '.');
2018:
2019:                                    if (blockLength >= optimalMinLength) {
2020:                                        // Split now!
2021:                                        BCMethod subMethod = startSubMethod(mb,
2022:                                                rt, selfContainedBlockStart,
2023:                                                blockLength);
2024:
2025:                                        return splitCodeIntoSubMethod(mb, ch,
2026:                                                subMethod,
2027:                                                selfContainedBlockStart,
2028:                                                blockLength);
2029:                                    } else if (blockLength > bestSplitBlockLength) {
2030:                                        // Save it, may split at this point
2031:                                        // if nothing better seen.
2032:                                        bestSplitPC = selfContainedBlockStart;
2033:                                        bestSplitBlockLength = blockLength;
2034:                                        bestSplitRT = rt;
2035:                                    }
2036:                                }
2037:                            }
2038:                        }
2039:                        break;
2040:                    }
2041:                    }
2042:
2043:                }
2044:
2045:                if (bestSplitBlockLength != -1) {
2046:                    BCMethod subMethod = startSubMethod(mb, bestSplitRT,
2047:                            bestSplitPC, bestSplitBlockLength);
2048:
2049:                    return splitCodeIntoSubMethod(mb, ch, subMethod,
2050:                            bestSplitPC, bestSplitBlockLength);
2051:                }
2052:
2053:                return -1;
2054:            }
2055:
2056:            /**
2057:             * See if the opcode is a return instruction.
2058:             * @param opcode opcode to be checked
2059:             * @return true for is a return instruction, false otherwise.
2060:             */
2061:            private static boolean isReturn(short opcode) {
2062:                switch (opcode) {
2063:                case VMOpcode.RETURN:
2064:                case VMOpcode.ARETURN:
2065:                case VMOpcode.IRETURN:
2066:                case VMOpcode.FRETURN:
2067:                case VMOpcode.DRETURN:
2068:                case VMOpcode.LRETURN:
2069:                    return true;
2070:                default:
2071:                    return false;
2072:                }
2073:            }
2074:
2075:            /**
2076:             * Minimum split length for a sub-method. If the number of
2077:             * instructions to call the sub-method exceeds the length
2078:             * of the sub-method, then there's no point splitting.
2079:             * The number of bytes in the code stream to call
2080:             * a generated sub-method can take is based upon the number of method args.
2081:             * A method can have maximum of 255 words of arguments (section 4.10 JVM spec)
2082:             * which in the worst case would be 254 (one-word) parameters
2083:             * and this. For a sub-method the arguments will come from the
2084:             * parameters to the method, i.e. ALOAD, ILOAD etc.
2085:             * <BR>
2086:             * This leads to this number of instructions.
2087:             * <UL>
2088:             * <LI> 4 - 'this' and first 3 parameters have single byte instructions
2089:             * <LI> (N-4)*2 - Remaining parameters have two byte instructions
2090:             * <LI> 3 for the invoke instruction.
2091:             * </UL>
2092:             */
2093:            private static int splitMinLength(BCMethod mb) {
2094:                int min = 1 + 3; // For ALOAD_0 (this) and invoke instruction
2095:
2096:                if (mb.parameters != null) {
2097:                    int paramCount = mb.parameters.length;
2098:
2099:                    min += paramCount;
2100:
2101:                    if (paramCount > 3)
2102:                        min += (paramCount - 3);
2103:                }
2104:
2105:                return min;
2106:            }
2107:            /*
2108:            final int splitNonZeroStack(BCMethod mb, ClassHolder ch,
2109:                    final int codeLength, final int optimalMinLength,
2110:                    int maxStack) {
2111:                
2112:                // program counter for the instruction that
2113:                // made the stack reach the given stack depth.
2114:                int[] stack_pcs = new int[maxStack+1];
2115:                Arrays.fill(stack_pcs, -1);
2116:                
2117:                int stack = 0;
2118:                
2119:                // maximum possible split seen that is less than
2120:                // the minimum.
2121:                int possibleSplitLength = -1;
2122:                
2123:                System.out.println("NZ SPLIT + " + mb.getName());
2124:
2125:                // do not split until at least this point (inclusive)
2126:                // used to ensure no split occurs in the middle of
2127:                // a conditional.
2128:                int outerConditionalEnd_pc = -1;
2129:
2130:                int end_pc = 0 + codeLength;
2131:                for (int pc = 0; pc < end_pc;) {
2132:
2133:                    short opcode = getOpcode(pc);
2134:
2135:                    int stackDelta = stackWordDelta(ch, pc, opcode);
2136:                    
2137:                    stack += stackDelta;
2138:                    
2139:                    // Cannot split a conditional but need to calculate
2140:                    // the stack depth at the end of the conditional.
2141:                    // Each path through the conditional will have the
2142:                    // same stack depth.
2143:                    int[] cond_pcs = findConditionalPCs(pc, opcode);
2144:                    if (cond_pcs != null) {
2145:                        // an else block exists, skip the then block.
2146:                        if (cond_pcs[3] != -1) {
2147:                            pc = cond_pcs[3];
2148:                            continue;
2149:                        }
2150:                        
2151:                        if (SanityManager.DEBUG)
2152:                        {
2153:                            if (outerConditionalEnd_pc != -1)
2154:                            {
2155:                                if (cond_pcs[5] >= outerConditionalEnd_pc)
2156:                                    SanityManager.THROWASSERT("NESTED CONDITIONALS!");
2157:                            }
2158:                        }
2159:
2160:                        if (outerConditionalEnd_pc == -1)
2161:                        {
2162:                            outerConditionalEnd_pc = cond_pcs[5];
2163:                        }
2164:                    }
2165:                               
2166:                    pc += instructionLength(opcode);
2167:                    
2168:                    // Don't split in the middle of a conditional
2169:                    if (outerConditionalEnd_pc != -1) {
2170:                        if (pc > outerConditionalEnd_pc) {
2171:                            // passed the outermost conditional
2172:                            outerConditionalEnd_pc = -1;
2173:                        }
2174:                        continue;
2175:                    }
2176:                    
2177:                    if (stackDelta == 0)
2178:                        continue;
2179:
2180:                    // Only split when the stack is having items popped
2181:                    if (stackDelta > 0)
2182:                    {
2183:                        // pushing double word, clear out a
2184:                        if (stackDelta == 2)
2185:                            stack_pcs[stack - 1] = pc;
2186:                        stack_pcs[stack] = pc;
2187:                        continue;
2188:                    }
2189:                    
2190:                    int opcode_pc = pc - instructionLength(opcode);
2191:                    
2192:                    // Look for specific opcodes that have the capability
2193:                    // of having a significant amount of code in a self
2194:                    // contained block.
2195:                    switch (opcode)
2196:                    {
2197:                    // this.method(A) construct
2198:                    //  ...         -- stack N
2199:                    //  push this -- stack N+1
2200:                    //  push args -- stack N+1+A
2201:                    //  call method -- stack N+R (R=0,1,2)
2202:                    //
2203:                    //  stackDelta = (N+R) - (N+1+A) = R-(1+A)
2204:                    //  stack = N+R
2205:                    //  Need to determine N+1
2206:                    //  
2207:                    //  
2208:                    //
2209:                    //  this.a(<i2>, <i2>, <i3>)
2210:                    //  returning int
2211:                    //
2212:                    //  stackDelta = -3 (this & 3 args popped, ret pushed)
2213:                    //  initial depth N = 10
2214:                    //  pc        - stack
2215:                    //  100 ...       - stack 10
2216:                    //  101 push this - stack 11
2217:                    //  109 push i1   - stack 12
2218:                    //  125 push i2   - stack 13
2219:                    //  156 push i3   - stack 14
2220:                    //  157 call      - stack 11
2221:                    //  
2222:                    //  need stack_pcs[11] = stack_pcs[11 + -3]
2223:                    //
2224:                    // ref.method(args).method(args) ... method(args)
2225:                    // 
2226:                    case VMOpcode.INVOKEINTERFACE:
2227:                    case VMOpcode.INVOKESPECIAL:
2228:                    case VMOpcode.INVOKEVIRTUAL:
2229:                    {
2230:                        String vmDescriptor = getTypeDescriptor(ch, opcode_pc);
2231:                        int r = CodeChunk.getDescriptorWordCount(vmDescriptor);
2232:                     
2233:                        // PC of the opcode that pushed the reference for
2234:                        // this method call.
2235:                        int ref_pc = stack_pcs[stack - r + 1];
2236:                       if (getOpcode(ref_pc) == VMOpcode.ALOAD_0) {
2237:                            System.out.println("POSS SPLIT " + (pc - ref_pc) + " @ " + ref_pc);
2238:                        }
2239:                       break;
2240:                    }
2241:                    case VMOpcode.INVOKESTATIC:
2242:                        String vmDescriptor = getTypeDescriptor(ch, opcode_pc);
2243:                        int r = CodeChunk.getDescriptorWordCount(vmDescriptor);
2244:                        int p1_pc = stack_pcs[stack - r + 1];
2245:                        System.out.println("POSS STATIC SPLIT " + (pc - p1_pc) + " @ " + p1_pc);
2246:                        
2247:                    }
2248:                    stack_pcs[stack] = opcode_pc;
2249:                }
2250:                return -1;
2251:            }*/
2252:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.